Skip to main content
 首页 » 编程设计

python之pdb 在 django doctests 中不起作用

2024年08月12日52lhb25

因此我创建了以下文件 (teSTLib.py) 以自动将所有 doctests(在我的嵌套项目目录中)加载到 tests.py 的 __tests__ 字典中:

# ./testlib.py 
import os, imp, re, inspect 
from django.contrib.admin import site 
 
def get_module_list(start): 
    all_files = os.walk(start) 
    file_list = [(i[0], (i[1], i[2])) for i in all_files] 
    file_dict = dict(file_list) 
 
    curr = start 
    modules = [] 
    pathlist = [] 
    pathstack = [[start]] 
 
    while pathstack is not None: 
 
        current_level = pathstack[len(pathstack)-1] 
        if len(current_level) == 0: 
            pathstack.pop() 
 
            if len(pathlist) == 0: 
                break 
            pathlist.pop() 
            continue 
        pathlist.append(current_level.pop()) 
        curr = os.sep.join(pathlist) 
 
        local_files = [] 
        for f in file_dict[curr][1]: 
            if f.endswith(".py") and os.path.basename(f) not in ('tests.py', 'models.py'): 
                local_file = re.sub('\.py$', '', f) 
                local_files.append(local_file) 
 
        for f in local_files: 
            # This is necessary because some of the imports are repopulating the registry, causing errors to be raised 
            site._registry.clear() 
            module = imp.load_module(f, *imp.find_module(f, [curr])) 
            modules.append(module) 
 
        pathstack.append([sub_dir for sub_dir in file_dict[curr][0] if sub_dir[0] != '.']) 
 
    return modules 
 
def get_doc_objs(module): 
    ret_val = [] 
    for obj_name in dir(module): 
        obj = getattr(module, obj_name) 
        if callable(obj): 
            ret_val.append(obj_name) 
        if inspect.isclass(obj): 
            ret_val.append(obj_name) 
 
    return ret_val 
 
def has_doctest(docstring): 
    return ">>>" in docstring 
 
def get_test_dict(package, locals): 
    test_dict = {} 
    for module in get_module_list(os.path.dirname(package.__file__)): 
        for method in get_doc_objs(module): 
            docstring = str(getattr(module, method).__doc__) 
            if has_doctest(docstring): 
 
                print "Found doctests(s) " + module.__name__ + '.' + method 
 
                # import the method itself, so doctest can find it 
                _temp = __import__(module.__name__, globals(), locals, [method]) 
                locals[method] = getattr(_temp, method) 
 
                # Django looks in __test__ for doctests to run. Some extra information is 
                # added to the dictionary key, because otherwise the info would be hidden. 
                test_dict[method + "@" + module.__file__] = getattr(module, method) 
 
    return test_dict 

为了在信用到期时给予信用,其中大部分来自 here

在我的 tests.py 文件中,我有以下代码:

# ./project/tests.py 
import testlib, project 
__test__ = testlib.get_test_dict(project, locals()) 

所有这些都可以很好地从我的所有文件和子目录中加载我的文档测试。 问题 是当我在任何地方 导入和调用 pdb.set_trace() 时,这就是我所看到的:

(Pdb) l 
(Pdb) args 
(Pdb) n 
(Pdb) n 
(Pdb) l 
(Pdb) cont 

doctest 显然正在捕获和调解输出本身,并在评估测试时使用输出。因此,当测试运行完成时,我在 doctest 的失败报告中看到了当我在 pdb shell 中时应该打印出来的所有内容。无论我是在 doctest 行内还是在被测试的函数或方法内调用 pdb.set_trace(),都会发生这种情况。

显然,这是一个很大的拖累。 Doctest 很棒,但如果没有交互式 pdb,我无法调试它们检测到的任何故障以修复它们。

我的想法是可能将 pdb 的输出流重定向到绕过 doctest 捕获输出的东西,但我需要一些帮助来弄清楚执行此操作所需的低级 io 内容。另外,我什至不知道这是否可能,而且我对 doctest 的内部结构太不熟悉了,不知道从哪里开始。有没有人有任何建议,或者更好的是一些可以完成这项工作的代码?

请您参考如下方法:

我能够通过调整获得 pdb。我只是将以下代码放在我的 teSTLib.py 文件的底部:

import sys, pdb 
class TestPdb(pdb.Pdb): 
    def __init__(self, *args, **kwargs): 
        self.__stdout_old = sys.stdout 
        sys.stdout = sys.__stdout__ 
        pdb.Pdb.__init__(self, *args, **kwargs) 
 
    def cmdloop(self, *args, **kwargs): 
        sys.stdout = sys.__stdout__ 
        retval = pdb.Pdb.cmdloop(self, *args, **kwargs) 
        sys.stdout = self.__stdout_old 
 
def pdb_trace(): 
    debugger = TestPdb() 
    debugger.set_trace(sys._getframe().f_back) 

为了使用调试器,我只是import teSTLib 并调用teSTLib.pdb_trace(),然后进入一个功能齐全的调试器。