Extrait les appels macOS derriere le contrat Systeme
- systeme/macos.py : SystemeMacOS (sons afplay, modificateurs Quartz, chemins, verrou d'instance fcntl) implementant le contrat Systeme. - systeme/__init__.py : choisir_systeme() fabrique selon sys.platform, refuse clairement une plateforme inconnue. - core.py : verrou d'instance (fcntl, LOCK_PATH, acquire_single_instance_lock) retire ; import os retire aussi, verifie inutilise ailleurs dans le fichier. - app.py : passe par choisir_systeme().acquerir_verrou_instance(dossier_donnees() + instance.lock) au lieu de core.acquire_single_instance_lock. Seul changement dans ce fichier, nom de fichier inchange. - tests/test_single_instance.py : reoriente vers choisir_systeme(), memes assertions et meme nombre de tests. - tests/test_systeme.py (nouveau) : verrou du test_le_verrou_refuse_une_seconde_prise garde desormais la reference au premier verrou — sans variable, CPython le garbage-collectait entre les deux assert (refcount 0 -> fermeture -> verrou relache), le test passait pour la mauvaise raison. 89 tests verts (84 + 5).
This commit is contained in:
@@ -3,8 +3,6 @@
|
||||
Tout ce qui est ici est testable sans micro, sans clavier, sans modèle.
|
||||
"""
|
||||
|
||||
import fcntl
|
||||
import os
|
||||
import re
|
||||
|
||||
CONFIG = {
|
||||
@@ -196,33 +194,4 @@ def clean_transcript(text):
|
||||
return re.sub(r"\s+", " ", text).strip()
|
||||
|
||||
|
||||
LOCK_PATH = os.path.expanduser("~/Library/Application Support/Zonza/instance.lock")
|
||||
|
||||
|
||||
def acquire_single_instance_lock(path=LOCK_PATH):
|
||||
"""Prend un verrou exclusif non bloquant ; renvoie le fichier, ou None si une
|
||||
autre instance le detient deja.
|
||||
|
||||
Pourquoi : deux bundles Zonza de meme identifiant (dont un fantome reste dans
|
||||
la Corbeille mais toujours enregistre aupres de LaunchServices) pouvaient
|
||||
tourner en meme temps. Chacun chargeait son propre modele MLX-Whisper et
|
||||
captait la MEME hotkey globale : un appui, deux transcriptions, machine
|
||||
saturee. Purger le fantome corrige l'incident ; ce verrou corrige la classe.
|
||||
|
||||
Le handle doit rester vivant tant que l'app tourne : le verrou tombe a la
|
||||
fermeture du fichier, et le noyau le libere si le processus meurt brutalement
|
||||
(donc pas de verrou orphelin apres un plantage).
|
||||
"""
|
||||
parent = os.path.dirname(path)
|
||||
if parent:
|
||||
os.makedirs(parent, exist_ok=True)
|
||||
handle = open(path, "a")
|
||||
try:
|
||||
fcntl.flock(handle, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
||||
except OSError:
|
||||
handle.close()
|
||||
return None
|
||||
return handle
|
||||
|
||||
|
||||
CONFIG["initial_prompt"] = build_initial_prompt()
|
||||
|
||||
Reference in New Issue
Block a user