2010-05-21 8 views
2

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

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

Все Тзи s работает достаточно хорошо, чтобы загрузить мои досье из всех моих файлов и подкаталогов. проблема в том, что когда я импортировать и вызывать pdb.set_trace() везде, это все, что я вижу:

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

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

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

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

ответ

4

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

+0

Спасибо, что помогли мне – Goin