Получить аргументы последнего вызова функции из traceback?

StackOverflow https://stackoverflow.com/questions/1650713

Вопрос

Могу ли я получить параметры последней функции, вызванной в traceback?Каким образом?

Я хочу создать средство поиска стандартных ошибок, чтобы сделать код читаемым, но при этом предоставить подробную информацию пользователю.

В следующем примере я хочу, чтобы GET_PARAMS вернул мне кортеж параметров, предоставленных os.chown.Изучая inspect модуль, рекомендованный Алексом Мартелли, я не смог найти.

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()

(Благодаря Джим Роберт для декоратора)

Это было полезно?

Решение

Проблема с использованием декоратора для того, чего вы пытаетесь достичь, состоит в том, что кадр, который получает обработчик исключений, это do_your_job () s, а не os.listdir () s, os.makedirs () s или os.chown () s. Таким образом, информация, которую вы будете печатать, является аргументами для do_your_job () . Чтобы получить поведение, которое, я думаю, вы намереваетесь, вам нужно украсить все библиотечные функции, которые вы вызываете.

Другие советы

При выполнении таких задач проверки всегда в первую очередь думайте о модуле inspect в стандартной библиотеке.Здесь, инспектировать.getargvalues выдает вам значения аргументов, заданные для фрейма, и inspect.getinnerframes проверять.getinnerframes выдает вам интересующие вас кадры из объекта обратной трассировки.

Вот пример такой функции и некоторые проблемы, которые вы не можете обойти:

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])

Вывод:

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

Я не использовал inspect.getinnerframes () , чтобы показать другой способ получить нужный кадр. Хотя он немного упрощается, он также выполняет некоторую дополнительную работу, которая вам не нужна, хотя и является относительно медленной ( inspect.getinnerframes () читает исходный файл для каждого модуля в трассировке; это не важно для одного вызов отладки, но может быть проблемой в других случаях).

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top