在Python中调试:显示最后N个执行行

gue*_*tli 14 python debugging pycharm

我很想看到在发生此异常之前由python解释器执行的最后10行:

test_has_perm_in_foobar.py F
Traceback (most recent call last):
  File "/.../test_has_perm_in_foobar.py", line 50, in test_has_perm
    self.assertFalse(check_perm(request, some_object))
  File "/usr/lib/python2.7/unittest/case.py", line 416, in assertFalse
    raise self.failureException(msg)
AssertionError: True is not false
Run Code Online (Sandbox Code Playgroud)

我想看看哪里check_perm()回来了True.

我知道我可以使用交互式调试来查找匹配的行,但我很懒,想要找到check_perm()返回返回值的行的更简单方法.

我使用pyCharm,但基于文本的工具,也将解决我的需求.

顺便说一下:请不要告诉我如何使用调试器进行步进和步入.我知道这个.

这是一些代码来说明它.

def check_perm(request, some_object):
    if condition_1:
        return True
    if condition_2:
        return sub_check(some_object)
    if condition_3:
        return sub_check2(some_object)
    ...
Run Code Online (Sandbox Code Playgroud)

有几种方法check_perm()可以返回True.如果True因为condition_1而返回,那么我想看到这样的东西

+         if condition_1:
+            return True
Run Code Online (Sandbox Code Playgroud)

我想到的输出就像set -x在shell上一样.

更新

cgitb,pytest和其他工具可以显示断言失败的行之前的行.但是,它们只显示当前python文件的行.这个问题是关于在断言发生之前执行的行,但覆盖了所有文件.在我的情况下,我想知道check_perm()创建返回值的位置.工具pytest,cgitb,...没有显示这个.

我在搜索的内容就像set -x在shell上一样:

帮助设定

-x在执行时打印命令及其参数.

gue*_*tli 1

由于找不到解决方案,我自己写了这个:

with trace_function_calls():    
    self.assertFalse(check_perm(request, some_object))
Run Code Online (Sandbox Code Playgroud)

trace_function_calls() 的实现:

class trace_function_calls(object):
    depth_symbol = '+'

    def __init__(self, write_method=None, log_lines=True):
        '''
        write_method: A method which gets called for every executed line. Defauls to logger.info

        # Simple example:

        with debugutils.trace_function_calls():
            method_you_want_to_trace()
        '''
        if write_method is None:
            write_method=logger.info
        self.write_method = write_method
        self.log_lines = log_lines

    def __enter__(self):
        self.old = sys.gettrace()
        self.depth = 0
        sys.settrace(self.trace_callback)

    def __exit__(self, type, value, traceback):
        sys.settrace(self.old)

    def trace_callback(self, frame, event, arg):
        # from http://pymotw.com/2/sys/tracing.html#tracing-function-calls
        if event == 'return':
            self.depth -= 1
            return self.trace_callback

        if event == 'line':
            if not self.log_lines:
                return self.trace_callback
        elif event == 'call':
            self.depth += 1
        else:
            # self.write_method('unknown: %s' % event)
            return self.trace_callback

        msg = []
        msg.append(self.depth_symbol * self.depth)

        co = frame.f_code
        func_name = co.co_name
        func_line_no = frame.f_lineno

        func_filename = co.co_filename
        if not is_python_file_from_my_codebase(func_filename):
            return self.trace_callback
        code_line = linecache.getline(func_filename, func_line_no).rstrip()
        msg.append('%s: %s %r on line %s of %s' % (
            event, func_name, code_line, func_line_no, func_filename))
        self.write_method(' '.join(msg))
        return self.trace_callback
Run Code Online (Sandbox Code Playgroud)

PS:这是开源软件。如果你想创建一个 python 包,那就去做吧,告诉我,这会让我很高兴。