Trace Bug仅在CI中发生

gue*_*tli 7 python debugging trace

我在python代码中有一个奇怪的错误,有时只在CI中发生.

我们无法重现它.

测试代码在哪里:

response=self.admin_client.post(url, post)
self.assertEqual(200, response.status_code, response)
Run Code Online (Sandbox Code Playgroud)

有时我们会得到一个302,因为表单被保存了.

我想调试这个:

with some_magic_trace.trace() as trace:
    response=self.admin_client.post(url, post)
    self.assertEqual(200, response.status_code, trace)
Run Code Online (Sandbox Code Playgroud)

跟踪应包含由解释器执行的python行(文件名,行偏移,行作为字符串).

如何实施some_magic_trace.trace()

Ste*_*o M 8

跟踪模块为您提供了一个非常简单的解决方案(从不同的你所要求的,但也足够简单,有一个尝试.)

from trace import Trace

tracer = Trace()
response = tracer.runfunc(self.admin_client.post, url, post)
self.assertEqual(200, response.status_code, response)
Run Code Online (Sandbox Code Playgroud)

一个更复杂的解决方案需要创建一个上下文管理器来保存跟踪并仅在异常上打印它,这需要使用sys.settrace.只是您自己实现的模板可能是:

class MyTracer():

    def __init__(self):
        self.trace = None

    def newscope(self, frame, event, arg):
        ## real work should be done here, just minimal example
        self.trace.append((frame, event, arg))
        return None

    def pprint(self):
        ## real pretty printing of trace info should be done here
        print(self.trace)

    def __enter__(self):
        self.trace = []
        sys.settrace(self.newscope)
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        sys.settrace(None)
        if exc_type is not None:
            self.pprint()
            ## print some info gathered from exc_type, exc_val, exc_tb
Run Code Online (Sandbox Code Playgroud)

然后你可以:

with MyTracer():
    response=self.admin_client.post(url, post)
    self.assertEqual(200, response.status_code, response)
Run Code Online (Sandbox Code Playgroud)

我们的想法是MyTracer实例有一个跟踪方法newscope,可以保存一些有用的信息self.trace.在从上下文异常退出时pprint调用该方法; 在正常退出时,将丢弃跟踪信息.

大多数工作必须在跟踪方法中完成newscope.可以在此处找到跟踪函数的一些具体示例.


Tad*_*sen 5

注意:Stefano M因为完全符合StackOverflow标准,所以解决方案是正确的答案

对于那些不熟悉使用帧/追踪对象时我提供了一个工作Tracker,从内置Stefano MMyTracer模板:

import sys,traceback

def printf(*stuff,sep=" ",end="\n",file=sys.stdout):
    file.write(sep.join(stuff)+end)#for backward compatability with python2

class Tracker:
    def __init__(self,out_file = sys.stdout):
        assert out_file.writable(),"need to open a file for writing"
        self.out = out_file
        self.last_frame = None

    def __enter__(self):
        self.old_trace = sys.gettrace()
        sys.settrace(self.newscope)

    def __exit__(self,etype,value,tb):
        sys.settrace(self.old_trace)
        self.finish_previous()
        if tb:
            traceback.printf_exception(etype,value,tb,file=self.out)
        else:
            printf("exit status normal",file=self.out)


    def newscope(self,f,e,ar):
        self.finish_previous(f)

        global_vars = f.f_globals
        for name,module in sys.modules.items():
            if global_vars is vars(module):
                file_name = name
                break
        else:
            file_name = "??"
            module = None

        printf(self._format_module(file_name,f.f_lineno),file=self.out)

        if module:
            printf(self._read_line_of_file(module,f.f_lineno),file=self.out)


    @staticmethod
    def _format_module(file_name,line):
        return "{}, line:{}".format(file_name,line)

    @staticmethod
    def _read_line_of_file(module,line):
        try:
            with open(module.__file__,"r") as FILE:
                line = list(FILE)[line]
                return line
        except Exception as e:
            return "ERROR WHEN READING FILE: %r"%e

    @staticmethod
    def _local_vars(frame):
        return "locals:\n    "+"\n    ".join("{} = {!r}".format(*pair) for pair in frame.f_locals.items())

    def finish_previous(self,new_frame=None):
        if self.last_frame:
            printf(self._local_vars(self.last_frame),end="\n\n\n",file=self.out)
        self.last_frame = new_frame
Run Code Online (Sandbox Code Playgroud)

然后它可以像这样用于显示输出到标准输出:

with Tracker():
    response=self.admin_client.post(url, post)
    self.assertEqual(200, response.status_code, trace)
Run Code Online (Sandbox Code Playgroud)

或者将输出发送到文件,您可以这样做:

with open("log.txt","w") as f, Tracker(f):
    response=self.admin_client.post(url, post)
    self.assertEqual(200, response.status_code, trace)
Run Code Online (Sandbox Code Playgroud)

希望可以给你立竿见影的效果,但你仍然会好得多落实模板斯特凡中号你自己,因为你正在寻找的信息可能是不同的,那么我想显示的内容.