zonza/systeme/macos.py
Ralph Mayola 5c4477fe1d 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).
2026-08-23 17:57:52 +02:00

55 lines
1.6 KiB
Python

"""Appels propres à macOS. Rien ici ne doit être importé directement par le noyau."""
import fcntl
import os
import subprocess
_SONS = {
"start": "/System/Library/Sounds/Pop.aiff",
"done": "/System/Library/Sounds/Glass.aiff",
"error": "/System/Library/Sounds/Basso.aiff",
}
# Masque des modificateurs (ctrl, shift, alt, cmd) dans les drapeaux Quartz.
_MASQUE_MODIFICATEURS = 0x000F0000
class SystemeMacOS:
"""Implémentation du contrat Systeme pour macOS."""
def jouer_son(self, nom):
chemin = _SONS.get(nom)
if not chemin:
return
try:
subprocess.Popen(["afplay", chemin])
except Exception:
pass # le son ne doit jamais casser la dictée
def modificateurs_enfonces(self):
try:
from Quartz import CGEventSourceFlagsState
return bool(CGEventSourceFlagsState(1) & _MASQUE_MODIFICATEURS)
except Exception:
return False # dans le doute, ne jamais bloquer le collage
def raccourci_defaut(self):
return "<cmd>+<ctrl>+d"
def chemin_log(self):
return os.path.expanduser("~/Library/Logs/Zonza.log")
def dossier_donnees(self):
return os.path.expanduser("~/Library/Application Support/Zonza")
def acquerir_verrou_instance(self, chemin):
parent = os.path.dirname(chemin)
if parent:
os.makedirs(parent, exist_ok=True)
fichier = open(chemin, "a")
try:
fcntl.flock(fichier, fcntl.LOCK_EX | fcntl.LOCK_NB)
except OSError:
fichier.close()
return None
return fichier