2012-03-20 86 views
2

緊跟在類或函數聲明之後的Python docstrings被放置在__doc__屬性中。從Python代碼中提取「額外」docstrings?

問題:如何提取一個函數中稍後出現的額外「內部」文檔字符串?

更新:這樣的文字語句被編譯器忽略。我可以通過AST獲得他們(和他們的行號)嗎?


爲什麼要問?

我有一個(不完全成熟)主意,用這樣的「內部」文檔字符串劃定鑑於/時/然後敏捷方案的部分:

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 

通過提取文檔字符串,所述測試運行框架能夠產生輸出是這樣的:

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

AssertionError Traceback 
... 

我認爲這將是比Behave採取FreshenLettucePyCukes的方法,這需要定義一個組合通道更簡潔吃了每一步的功能。我不喜歡重複步驟的文本作爲函數名稱(@When("I add numbers") def add_numbers())。但是與普通的單元測試不同,文檔將增加打印商業可讀場景的能力以供參考。

回答

4

你可以使用ast模塊解析您的測試,並手動行走樹和安裝測試等有這樣做(你可以使用ast.NodeVisitorast.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 2012-03-20 09:20:29

+0

謝謝,更新! – zeekay 2012-03-20 09:25:58

+0

我不確定你應該走'ast'路線,因爲它本質上是爲你的測試引入新的語法。如果有人忘記放置字符串會怎麼樣?等 也許你可以指定使用'with'語句的上下文並使用它們來構建整體測試。 – 2012-03-20 09:56:49

2

由於編譯器忽略了字面語句,所以不能。

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

哦,回到製圖板。 – Graham 2012-03-20 07:29:11