Можно ли заставить Python генерировать трассировку, аналогичную set -x bash? - PullRequest
6 голосов
/ 20 сентября 2010

Есть ли в Python аналогичный механизм, который set -x имеет в bash?

Вот несколько примеров вывода bash в этом режиме:

+ for src in cpfs.c log.c popcnt.c ssse3_popcount.c blkcache.c context.c types.c device.c
++ my_mktemp blkcache.c.o
+++ mktemp -t blkcache.c.o.2160.XXX
++ p=/tmp/blkcache.c.o.2160.IKA
++ test 0 -eq 0
++ echo /tmp/blkcache.c.o.2160.IKA
+ obj=/tmp/blkcache.c.o.2160.IKA

Я знаю о модуле Python trace, однако его вывод кажется очень многословным, а не высоким, как в bash.

Ответы [ 3 ]

7 голосов
/ 20 сентября 2010

Возможно использовать sys.settrace :

Используйте traceit() для включения трассировки, используйте traceit(False) для отключения трассировки.

import sys
import linecache

def _traceit(frame, event, arg):
    '''
    http://www.dalkescientific.com/writings/diary/archive/2005/04/20/tracing_python_code.html
    '''
    if event == "line":
        lineno = frame.f_lineno
        filename = frame.f_globals["__file__"]
        if (filename.endswith(".pyc") or
            filename.endswith(".pyo")):
            filename = filename[:-1]
        name = frame.f_globals["__name__"]
        line = linecache.getline(filename, lineno)
        print "%s  # %s:%s" % (line.rstrip(), name, lineno,)
    return _traceit

def _passit(frame, event, arg):
    return _passit

def traceit(on=True):
    if on: sys.settrace(_traceit)
    else: sys.settrace(_passit)

def mktemp(src):
    pass

def my_mktemp(src):
    mktemp(src)
    p=src

traceit()
for src in ('cpfs.c','log.c',):
    my_mktemp(src)
traceit(False)

1010 * выходы *

mktemp(src)  # __main__:33
pass  # __main__:30
p=src  # __main__:34
mktemp(src)  # __main__:33
pass  # __main__:30
p=src  # __main__:34
if on: sys.settrace(_traceit)  # __main__:26
else: sys.settrace(_passit)  # __main__:27
1 голос
/ 13 сентября 2012

Для отслеживания определенных вызовов вы можете обернуть каждую интересующую функцию своим собственным регистратором. Это приводит к тому, что аргументы расширяются до их значений, а не только имен аргументов в выводе.

Функции должны передаваться как строки, чтобы избежать проблем, когда модули перенаправляют на другие модули, такие как os.path / posixpath Я не думаю, что вы можете извлечь правильное имя модуля для патча только из объекта функции.

Код упаковки:

import importlib

def wrapper(ffull, f):
    def logger(*args, **kwargs):
        print "TRACE: %s (%s, %s)" % (ffull, args, kwargs)
        return f(*args, **kwargs)
    return logger

def log_execution(ffull):
    parts = ffull.split('.')
    mname = '.'.join(parts[:-1])
    fname = parts[-1]
    m = importlib.import_module(mname)
    f = getattr(m, fname)
    setattr(m, fname, wrapper(ffull, f))

Использование:

for f in ['os.path.join', 'os.listdir', 'sys.exit']:
    log_execution(f)

p = os.path.join('/usr', 'bin')
os.listdir(p)
sys.exit(0)

....

% ./a.py  
TRACE: os.path.join (('/usr', 'bin'), {})
TRACE: os.listdir (('/usr/bin',), {})
TRACE: sys.exit ((0,), {})
0 голосов
/ 20 сентября 2010

Вы должны попытаться использовать модуль трассировки, чтобы получить более высокий уровень детализации. Что именно вам нужно?

...