Question

Puis-je obtenir les paramètres de la dernière fonction appelée dans traceback? Comment?

Je souhaite créer un récupérateur des erreurs standard afin de rendre le code lisible, tout en fournissant des informations détaillées à l'utilisateur.

Dans l'exemple suivant, je souhaite que GET_PARAMS me renvoie un tuple de paramètres fournis à os.chown. En examinant le module inspect conseillé par Alex Martelli, je n’ai pas trouvé cela.

def catch_errors(fn):
    def decorator(*args, **kwargs):
        try:
            return fn(*args, **kwargs)
        except (IOError, OSError):
            msg = sys.exc_info()[2].tb_frame.f_locals['error_message']
            quit(msg.format(SEQUENCE_OF_PARAMETERS_OF_THE_LAST_FUNCTION_CALLED)\
            + '\nError #{0[0]}: {0[1]}'.format(sys.exc_info()[1].args), 1)
    return decorator

@catch_errors
def do_your_job():
    error_message = 'Can\'t change folder ownership \'{0}\' (uid:{1}, gid:{2})'
    os.chown('/root', 1000, 1000) # note that params aren't named vars.

if __name == '__main__' and os.getenv('USERNAME') != 'root':
    do_your_job()

(Merci à Jim Robert pour le décorateur)

Était-ce utile?

La solution

Le problème avec l'utilisation d'un décorateur pour ce que vous essayez d'obtenir est que le cadre obtenu par le gestionnaire d'exceptions est do_your_job () , et non os.listdir () s, os.makedirs () ou s os.chown () . Les informations que vous allez imprimer sont donc les arguments de do_your_job () . Pour obtenir le comportement que je pense que vous souhaitez, vous devez décorer toutes les fonctions de la bibliothèque que vous appelez.

Autres conseils

Pour ces tâches d’inspection, pensez toujours au module inspecter dans la bibliothèque standard. inspect.getargvalues ?? vous donne les valeurs d'argument données. un cadre et inspect.getinnerframes vous donne les cadres d'intérêt d'un objet de traçage.

Voici un exemple d'une telle fonction et de problèmes que vous ne pouvez pas contourner:

import sys

def get_params(tb):
    while tb.tb_next:
        tb = tb.tb_next
    frame = tb.tb_frame
    code = frame.f_code
    argcount = code.co_argcount
    if code.co_flags & 4: # *args
        argcount += 1
    if code.co_flags & 8: # **kwargs
        argcount += 1
    names = code.co_varnames[:argcount]
    params = {}
    for name in names:
        params[name] = frame.f_locals.get(name, '<deleted>')
    return params


def f(a, b=2, c=3, *d, **e):
    del c
    c = 4
    e['g'] = 6
    assert False

try:
    f(1, f=5)
except:
    print get_params(sys.exc_info()[2])

Le résultat est:

{'a': 1, 'c': 4, 'b': 2, 'e': {'g': 6, 'f': 5}, 'd': ()}

Je n'ai pas utilisé inspect.getinnerframes () pour indiquer un autre moyen d'obtenir l'image requise. Bien que cela simplifie un peu, il effectue également un travail supplémentaire qui n’est pas nécessaire mais qui est relativement lent ( inspect.getinnerframes () lit le fichier source pour chaque module de traceback; ce n’est pas important pour un appel de débogage, mais pourrait poser problème dans d’autres cas).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top