A prueba de fallos para los scripts de Python de larga duración.

Esta puede ser la pregunta más tonta, pero me gustaría saber si hay una manera de escribir una envoltura alrededor de una función (preferiblemente un decorador) para poder detectar el estado interno de las variables locales en caso de que haya una excepción. Criado en esa función. Atraparía a los locales a medida que se crearon, los escabullirían y luego los desecharían si no se generaban excepciones, o los escribirían en el archivo si se encontraban excepciones.

¿Es esto demasiado fantasioso, o alguien ha engañado con algo como esto?

Puede capturar la variable f_locals en un marco en el rastreo :

 import sys import functools def capturelocals(func): @functools.wraps(func) def wrapperfunc(*args, **kw): try: return func(*args, **kw) except Exception: _, _, tb = sys.exc_info() try: while tb.tb_next is not None: tb = tb.tb_next # find innermost frame locals = tb.tb_frame.f_locals print locals finally: del tb # prevent leaking tracebacks raise return wrapperfunc 

Para demostrar que funciona:

 >>> @capturelocals ... def foobar(): ... foo = 'bar' ... spam = 'eggs' ... raise ValueError('Bam!') ... >>> foobar() {'foo': 'bar', 'spam': 'eggs'} Traceback (most recent call last): File "", line 1, in  File "", line 5, in wrapperfunc File "", line 5, in foobar ValueError: Bam! 

Otra opción sería pasar como argumentos a la función solo aquellas variables que le interesa guardar en caso de algo catastrófico.

Un decorador que podría ayudarte a hacer esto:

 import os try: import cPickle as pickle except ImportError: import pickle def save_args_if_exception(pickle_folder): def real_decorator(function): def wrapper(*args, **kwargs): try: function(*args, **kwargs) except: print 'FAILING SAFE: Saving arguments to folder:' print pickle_folder for arg_position, arg in enumerate(args, start=1): arg_fname = os.path.join(pickle_folder, str(arg_position) + '.pickle') print 'Saving positional argument-{}'.format(arg_position) with open(arg_fname, mode='wb') as f: pickle.dump(arg, f) print 'Saving keyword arguments (kwargs)' with open(os.path.join(pickle_folder, 'kwargs.pickle'), mode='wb') as f: pickle.dump(kwargs, f) raise # re-raise original exception return wrapper return real_decorator @save_args_if_exception(os.getcwd()) def important_function(first_arg, second_arg=2, **kwargs): print 'About to raise an exception!' raise Exception important_function(3) 

Tenga en cuenta que en este ejemplo, second_arg no se guarda en un archivo, probablemente debido a la forma en que Python maneja los argumentos predeterminados. Dependiendo de su situación, esto puede ser o no un comportamiento útil.

Referencias: