2012-03-20 3 views
2

Docstrings Python, который следует за объявлением класса или функции, помещается в атрибут __doc__.Извлечение «дополнительных» docstrings из кода Python?

Вопрос: Как извлечь дополнительные «внутренние» docstrings, которые происходят позже в функции?

Обновление: такие буквенные утверждения выдаются компилятором. Могу ли я добраться до них (и их номер строки) через АСТ?


Почему я спрашиваю?

У меня было (не полностью запеченная) идея использовать такую ​​«внутреннюю» строку документацию очертить Учитывая/Когда/Then разделы Проворной Сценарий:

def test_adding(): 
    """Scenario: Adding two numbers""" 
    adder = Adder() 
    """When I add 2 and 3""" 
    result = adder.add(2, 3) 
    """Then the result is 5""" 
    assert result == 5 

пути экстрагирования, в строках документации Test- работает структура может генерировать такой вывод:

Scenario: Adding two numbers 
    When I add 2 and 3 (PASS) 
    Then the result is 5 (FAIL) 

AssertionError Traceback 
... 

Я думаю, что это будет более кратким, чем подходом, принятым в Behave, Freshen, Lettuce, PyCukes, которые требуют определения SEPAR для каждого шага. Мне не нравится повторять текст шага как имя функции (@When("I add numbers") def add_numbers()). Но в отличие от простого модульного теста, docstrings добавят возможность распечатать бизнес-удобочитаемый сценарий для справки.

ответ

4

Вы можете разобрать тесты с помощью ast модуля, и вручную ходить дерева и настройки тестов и т.д. Есть, вероятно, более эффективные способы сделать это (вы можете использовать ast.NodeVisitor или ast.NodeTransfomer и шаблон посетителя может быть), но вот пример:

import ast, inspect 

def find_tests(module): 
    # generate AST from module's source 
    tree = ast.parse(inspect.getsource(module)) 
    # return tests in module, assuming they are top level function definitions 
    return [node for node in tree.body if isinstance(node, ast.FunctionDef)] 

def print_docstrings(test): 
    for node in test.body: 
     if isinstance(node, ast.Expr): 
      # print lineno and docstring 
      print node.value.lineno, node.value.s 

if __name__ == '__main__': 
    import test_adding 
    for test in find_tests(test_adding): 
     print_docstrings(test) 

Вы также можете быть заинтересованы в konira.

+0

вы можете использовать 'inspect.getsource (module)' для получения источника. вам не нужно '_ast', имена доступны через' ast'. – jfs

+0

Спасибо, обновлено! – zeekay

+0

Я не уверен, что вы должны идти по маршруту ast, поскольку он по сути представляет новый синтаксис для ваших тестов. Что делать, если кто-то забывает поставить строку? и т. д. Возможно, вы можете указать контексты, используя оператор 'with', и использовать их для создания общего теста. –

2

Вы не можете, так как компилятор выводит буквальные утверждения.

>>> def foo(): 
... 'docstring' 
... 3 
... 'bar' 
... 
>>> dis.dis(foo) 
    4   0 LOAD_CONST    1 (None) 
       3 RETURN_VALUE   
+0

Ну, хорошо, назад к чертежной доске. – Graham

Смежные вопросы