Учитывая ссылку на функцию, создайте ее исходный код без аннотаций в подписи - PullRequest
0 голосов
/ 26 сентября 2019

Значения по умолчанию должны остаться.

Декораторы также должны быть удалены, но это не так важно.

Исходный источник:

# 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), но мне нужно удалить аннотации.Как я могу это сделать?Желательно использовать стандартные модули.

1 Ответ

0 голосов
/ 27 сентября 2019

Вы можете использовать ast.parse для разбора источника в AST и использовать ast.walk для обхода дерева, чтобы обнулить annotation, если это узел arg, и обнулить returns и decorator_list, если этоFunctionDef узел.Используйте 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

...