繁体   English   中英

给定对 function 的引用,在签名中生成不带注释的源代码

[英]Given a reference to function, produce it's source code without annotations in the signature

应保留默认值。

装饰器也应该被移除,但这不是一个问题。

原始来源:

# Comments
@decorator1
@decorator2(
    a=1,
    b=1,
)
def my_func(
    a: typing.List = 14,
    b: 'CustomType' = None,
    c: Whatever('foo') = 42,
    d: Whatever('foo') = some_function,
) -> typing.NamedTuple(
    'Dummy',
    [
      ('r1': 'CustomType'),
      ('21': 'CustomType2'),
    ]
):
    ...

所需来源:

def my_func(
    a = 14,
    b = None,
    c = 42,
    d = some_function,
):
    ...

我可以使用inspect.getsource(my_func)获取源代码,但我需要去除注释。 我怎样才能做到这一点? 最好使用标准模块。

您可以使用ast.parse将源解析为 AST,如果它是arg节点,则使用ast.walk遍历树以使annotation无效,如果它是FunctionDef节点,则使returnsdecorator_list无效。 使用astunparse将树解解析回源代码:

import inspect
import ast
import typing
import astunparse
from unittest.mock import patch

@patch('builtins.print')
def my_func(
        a: int = 1,
        b: typing.List = []
) -> bool:
    pass

tree = ast.parse(inspect.getsource(my_func), '', 'exec')
for node in ast.walk(tree):
    if isinstance(node, ast.arg):
        node.annotation = None
    elif isinstance(node, ast.FunctionDef):
        node.returns = None
        node.decorator_list = []
print(astunparse.unparse(tree))

这输出:

def my_func(a=1, b=[]):
    pass

演示: https://repl.it/repls/WaterloggedFunnyQuotient

您可以将 lib2to3.refactor.RefactoringTool 子类化以使用作为lib2to3.refactor.RefactoringTool子类的修复程序重构代码,该lib2to3.fixer_base.BaseFix具有查找类型化参数、带有注释返回值的 function 声明或修饰定义的模式,以及从子节点中删除注释和装饰器索引的transform方法:

from lib2to3 import fixer_base, refactor

class FixParameterAnnotations(fixer_base.BaseFix):
    PATTERN = "name=tname | func=funcdef< any+ '->' any+ > | decorated"

    def transform(self, node, results):
        if 'name' in results:
            del node.children[1:] # delete annotation to typed argument
        elif 'func' in results:
            del node.children[-4:-2] # delete annotation to function declaration
        else:
            del node.children[0] # delete decorators
        return node

class Refactor(refactor.RefactoringTool):
    def __init__(self, fixers):
        self._fixers= [cls(None, None) for cls in fixers]
        super().__init__(None)

    def get_fixers(self):
        return self._fixers, []

以便:

import inspect
import typing
from unittest.mock import patch

@patch('builtins.print')
def my_func(
        a: int = 1, # some comment
        b: typing.List = []     # more comment
) -> bool:
    ''' some docstring'''
    pass

print(Refactor([FixParameterAnnotations]).refactor_string(inspect.getsource(my_func), ''))

输出:

def my_func(
        a = 1, # some comment
        b = []     # more comment
):
    ''' some docstring'''
    pass

演示: https://repl.it/@blhsing/BrightWhirlwindBoolean

lib2to3是往返稳定的,因此在转换后会保留所有注释和空格。 您可以在lib2to3模块的Grammar.txt中找到 Python 语法的定义。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM