nutools/lib/nulib/python/nulib/control.py

87 lines
2.6 KiB
Python

# -*- coding: utf-8 -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
"""Contrôle d'exécution.
"""
__all__ = ('Status', 'OK_STATUS', 'ERROR_STATUS',
'Exit', 'exit', 'die')
import sys
from .base import isnum
from .output import eerror
class Status:
"""Un objet qui peut être utilisé pour retourner un status pour l'exécution
d'un programme ou d'une opération.
Le status peut être OK ou ERROR. La valeur booléenne de cet objet est True
ou False en fonction de la valeur du status. Un code de retour de programme
associé est disponible avec la propriété exitcode.
"""
ok = True
exitcode = 0
def __init__(self, ok=None, exitcode=None):
if ok is not None:
self.ok = ok
if exitcode is None:
if ok: exitcode = 0
else: exitcode = 1
self.exitcode = exitcode
elif exitcode is not None:
self.ok = exitcode == 0
self.exitcode = exitcode
def __nonzero__(self):
return self.ok
OK_STATUS = Status(True)
ERROR_STATUS = Status(False)
def ensure_status(status):
"""Retourner une instance de Status.
Si status est un entier, le prendre comme valeur de retour.
Sinon, le considérer comme une valeur booléenne indiquant le status: OK ou ERREUR.
"""
if isinstance(status, Status): return status
elif isnum(status): return Status(exitcode=int(status))
else: return Status(status)
class Exit(Exception):
"""Classe qui peut être utilisée pour propager un code de retour quand on
quitte l'application.
"""
def __init__(self, status):
self.exitcode = ensure_status(status).exitcode
def exit(status=OK_STATUS):
"""Quitter le programme avec l'exception Exit, en propageant par défaut le
status OK_STATUS.
"""
raise Exit(status)
def die(msg=None, status=ERROR_STATUS):
"""Quitter le programme en affichant un message d'erreur, en propageant
par défaut le status ERROR_STATUS.
Si msg==None, on prend le message de la dernière exception capturée.
"""
eerror(msg)
raise Exit(status)
def enable_exit_control():
"""Installer un excepthook qui appelle sys.exit() quand on lève l'exception
Exit.
"""
prev_excepthook = sys.excepthook
if prev_excepthook is sys.__excepthook__:
prev_excepthook = None
def exit(cls, obj, tb, prev_excepthook=prev_excepthook):
if issubclass(cls, Exit): sys.exit(obj.exitcode)
elif prev_excepthook is not None:
prev_excepthook(cls, obj, tb)
else: sys.__excepthook__(cls, obj, tb)
sys.excepthook = exit