Модуль записи с оформленными функциями и импортом - PullRequest
0 голосов
/ 15 января 2020

у меня есть этот код в python файле:

from dec import my_decorator
import asyncio

@my_decorator
async def simple_method(bar):  # , x, plc_name, var_name):
    print("Henlo from simple_method\npartent:{}".format(parent))
    return


@my_decorator
async def other_simple_meth(bar, value):
    print("Henlo from other_simple_meth:\t Val:{}".format(value))
    return


async def main():
    print("Start Module-Export")
    open('module_functions.py', 'a').close()
    # Write all decorated functions to modue_functions.py
    print("Functions in module_functions.py exported")
    while True:
        asyncio.sleep(2)
        print("z...z...Z...")

Моя цель - записать все оформленные функции (в c. Зависимости импорта) во второй файл модуля (здесь "module_functions" .py "). Мой файл 'module_functions.py' должен выглядеть следующим образом:

from dec import my_decorator
import asyncio

@my_decorator
async def simple_method(bar):  # , x, plc_name, var_name):
    print("Henlo from simple_method\npartent:{}".format(parent))
    return


@my_decorator
async def other_simple_meth(bar, value):
    print("Henlo from other_simple_meth:\t Val:{}".format(value))
    return

Я знаю, как получить ссылки и имена функций, но не знаю, как "скопировать / вставить" код функции (включая декоратор и все зависимости) в отдельный файл. Возможно ли это вообще?

РЕДАКТИРОВАТЬ : Я знаю, что существуют маринад и укроп, но это может не полностью достичь цели. Проблема заключается в том, что кто-то еще может не знать порядок создания файла дампа, и загрузка их обратно может / вызовет проблему. Кроме того, кажется, что невозможно снова редактировать такие загруженные функции.

1 Ответ

1 голос
/ 16 января 2020

Я нашел (не идеальное, но нормальное) решение для своих проблем.

I) Поиск и запись функций, сопрограмм и т. Д. c. в файл ( работает ):

Как и подозревал @MisterMiyagi, модуль проверки - хороший способ go. Для обычных вещей можно с помощью inspect.getsource() получить код и записать их в файл:

# List of wanted stuff    
func_list = [simple_method, meth_with_input, meth_with_input_and_output, func_myself] 

    with open('module_functions.py', 'a') as module_file:
        for func in func_list:
            try:
                module_file.write(inspect.getsource(func))
                module_file.write("\n")
            except:
                print("Error :( ")

II) Но как насчет декорированных вещей (, кажется, работает ) ?

I) не будет работать для украшенных вещей, он просто игнорируется без исключения. Кажется, что используется from functools import wraps. Во многих примерах декоратор @wraps добавляется в класс декоратора. Это было невозможно для меня, но есть хороший обходной путь:

@wraps(lambda: simple_method) #<---add wraps-decorator here
@my_decorator
async def simple_method(parent):  # , x, plc_name, var_name):
    print("Henlo from simple_method\npartent:{}".format(parent))
    return

Оболочки могут быть помещены над оригинальным декорированным методом / классом / функцией, и кажется, что они ведут себя так, как я хочу. Теперь мы можем добавить simple_method в func_list из I).

III) А как насчет импорта?

Что ж, кажется довольно сложным / невозможным на самом деле прочитать зависимости функции. Мой обходной путь - отбросить все требуемые операции импорта в класс ( sigh ). Этот класс может быть брошен в func_list из I) и записан в файл.

РЕДАКТИРОВАТЬ: Существует более чистый способ, который может работать, после некоторой модификации, с I) и II). Модуль magi c имеет значение ast .

. Я переписал следующее:

class ImportVisitor(ast.NodeVisitor):

    def __init__(self, target):
        super().__init__()
        self.file_target = target

    "pick these special nodes via overwriting: visit_classname." \
    "classnames are listed in https://docs.python.org/3.6/library/ast.html#abstract-grammar"
    def visit_Import(self, node):
        "Overwrite func!"
        "Write all statements just with import like -  import ast into file_target"
        str = 'import '+', '.join(alias.name for alias in node.names)
        self.file_target.write(str+"\n")

    def visit_ImportFrom(self, node):
        "Overwrite func!"
        "Write all statements with from ... import (like - from os.path import basename) into file_tagrget"
        str = 'from '+ node.module+ ' import '+', '.join(alias.name for alias in node.names)
        self.file_target.write(str+"\n")

Теперь я могу проанализировать свое собственное имя сценария и заполнить файл module_file данными для импорта. и из ... import, которые он найдет при посещении всех узлов в этом дереве:

    with open('module_functions.py', 'a') as module_file:
        with open(basename(__file__), "rb") as f:
            tree = ast.parse(f.read(), basename(__file__))
            visitor = ImportVisitor(module_file)
            visitor.visit(tree)
            module_file.write("\n\n")
...