简体   繁体   English

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

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

Default values should remain.应保留默认值。

Decorators should also be removed, but it's less of a concern.装饰器也应该被移除,但这不是一个问题。

Original source:原始来源:

# 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'),
    ]
):
    ...

Desired source:所需来源:

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

I can get the source using inspect.getsource(my_func) , but I need to strip the annotations.我可以使用inspect.getsource(my_func)获取源代码,但我需要去除注释。 How can I do this?我怎样才能做到这一点? Preferably using the standard modules.最好使用标准模块。

You can use ast.parse to parse the source into an AST, and use ast.walk to traverse the tree to nullify annotation if it's an arg node and nullify returns and decorator_list if it's a FunctionDef node.您可以使用ast.parse将源解析为 AST,如果它是arg节点,则使用ast.walk遍历树以使annotation无效,如果它是FunctionDef节点,则使returnsdecorator_list无效。 Use astunparse to unparse the tree back to source code:使用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))

This outputs:这输出:

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

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

You can subclass lib2to3.refactor.RefactoringTool to refactor the code using a fixer that is a subclass of lib2to3.fixer_base.BaseFix with a pattern that looks for either a typed argument, a function declaration with an annotated returning value, or a decorated definition, and a transform method that removes the indices of the annotations and decorators from the child nodes:您可以将 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, []

so that:以便:

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), ''))

outputs:输出:

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

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

lib2to3 is round-trip stable so all comments and white spaces are preserved after the transformation. lib2to3是往返稳定的,因此在转换后会保留所有注释和空格。 You can find the definition of the Python grammar in Grammar.txt of the lib2to3 module.您可以在lib2to3模块的Grammar.txt中找到 Python 语法的定义。

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

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