pdb не работает в django doctests - PullRequest
2 голосов
/ 21 мая 2010

Итак, я создал следующий файл (testlib.py) для автоматической загрузки всех документов (во всех моих вложенных каталогах проектов) в __tests__ словарь tests.py:

.
# ./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

Чтобы получить кредит там, где он нужен, большая часть этого пришла от здесь

В моем файле 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, по-видимому, захватывает и опосредует сам вывод и использует вывод при оценке тестов. Итак, когда тестовый запуск завершен, я вижу все, что должно было распечатать, когда я был в оболочке pdb в отчете об ошибках doctest. Это происходит независимо от того, вызываю ли я pdb.set_trace () внутри строки документа или внутри тестируемой функции или метода.

Очевидно, это большое сопротивление. Doctests - это здорово, но без интерактивной pdb я не могу отладить ни одну из обнаруженных ошибок, чтобы исправить их.

Мой мыслительный процесс заключается в том, чтобы, возможно, перенаправить выходной поток pdb во что-то, что обходит вывод doctest, но мне нужна помощь в выяснении низкоуровневого ввода-вывода, необходимого для этого. Кроме того, я даже не знаю, будет ли это возможно, и я слишком незнаком с внутренностями doctest, чтобы знать, с чего начать. У кого-нибудь есть какие-нибудь предложения, или, лучше, код, который может это сделать?

1 Ответ

4 голосов
/ 21 мая 2010

Я смог получить 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(), и меня переводят в полнофункциональный отладчик.

...