【问题标题】:Extracting "extra" docstrings from Python code?从 Python 代码中提取“额外”的文档字符串?
【发布时间】:2012-04-04 16:24:12
【问题描述】:

紧跟在类或函数声明之后的 Python 文档字符串被放置在 __doc__ 属性中。

问题:如何提取稍后在函数中出现的其他“内部”文档字符串?

更新:编译器省略了此类文字语句。我可以通过 AST 找到他们(以及他们的行号)吗?


我为什么要问?

我有一个(不完全成熟的)想法,使用这种“内部”文档字符串来描述敏捷场景的 Given/When/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

通过提取文档字符串,测试运行框架可以生成如下输出:

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

AssertionError   Traceback
...

我认为这比BehaveFreshenLettucePyCukes 中采用的方法更简洁,后者需要为每个步骤定义一个单独的函数。我不喜欢将步骤文本重复为函数名称 (@When("I add numbers") def add_numbers())。但与普通单元测试不同的是,文档字符串将添加打印出业务可读场景以供参考的能力。

【问题讨论】:

    标签: python docstring


    【解决方案1】:

    您可以使用 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 感兴趣。

    【讨论】:

    • 您可以使用inspect.getsource(module) 获取源代码。您不需要_ast 可以通过ast 获得名称。
    • 我不确定你应该走ast 路线,因为它本质上是为你的测试引入新的语法。如果有人忘记放绳子怎么办?等等。也许您可以使用with 语句指定上下文并使用它们来构建整体测试。
    • 我个人认为它相对无害,但它确实让我想起了提问者可能感兴趣的 konira。
    • 有价值的cmets。我想简单地打印出步骤可能会更好地通过函数调用来实现,甚至比 with-statement 更简单。
    【解决方案2】:

    你不能,因为编译器会省略文字语句。

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

    【讨论】:

    • 哦,好吧,回到绘图板。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-01-02
    • 2011-11-07
    • 1970-01-01
    • 2018-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多