[英]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
节点,则使returns
和decorator_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.