Функции модуля mypy importlib

Я использую importlib для импорта модулей во время выполнения. Эти модули являются плагинами для моего приложения и должны реализовывать 1 или несколько функций уровня модуля. Я начал добавлять аннотации типов в свои приложения и получаю сообщение об ошибке mypy, указывающее

Модуль не имеет атрибута generate_configuration.

где "generate_configuration" - одна из функций модуля.

В этом примере в модуле должна быть только функция generate_configuration. Функция принимает единственный аргумент dict.

def generate_configuration(data: Dict[str, DataFrame]) -> None: ...

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

Код, загружающий этот модуль, показан ниже. Ошибка генерируется последней строкой.

plugin_directory = os.path.join(os.path.abspath(directory), 'Configuration-Generation-Plugins')
plugins = (
    module_file
    for module_file in Path(plugin_directory).glob('*.py')
)
sys.path.insert(0, plugin_directory)
for plugin in plugins:
    plugin_module = import_module(plugin.stem)
    plugin_module.generate_configuration(directory, points_list)

person idahogray    schedule 25.02.2018    source источник
comment
не видя соответствующего кода, нам сложно понять, как вам помочь? Как выглядит подпись вашего типа функции и какие рядом расположены строки?   -  person Anthony Sottile    schedule 25.02.2018
comment
@AnthonySottile Я добавил немного деталей и подпись функции. Извините за то, что изначально не было более ясным.   -  person idahogray    schedule 26.02.2018
comment
Можете ли вы также добавить строку, на которую указывает ошибка?   -  person Anthony Sottile    schedule 26.02.2018
comment
Спасибо, что помогли мне пройти через это. Я добавил код, который генерирует ошибку.   -  person idahogray    schedule 26.02.2018


Ответы (2)



Я провел еще несколько исследований и в конце концов остановился на немного другом решении, в котором используется typing.cast.

В решении по-прежнему используется определение статического метода от Anthony Sottile.

from typing import Dict
from pandas import DataFrame

class ConfigurationGenerationPlugin(ModuleType):
@staticmethod
    def generate_configuration(directory: str, points_list: Dict[str, DataFrame]) -> None: ...

Код, который импортирует модуль, затем использует ввод .cast (), чтобы установить правильный тип.

plugin_directory = os.path.join(os.path.abspath(directory), 'Configuration-Generation-Plugins')
plugins = (
    module_file
    for module_file in Path(plugin_directory).glob('*.py')
    if not module_file.stem.startswith('lib')
)
sys.path.insert(0, plugin_directory)
for plugin in plugins:
    plugin_module = cast(ConfigurationGenerationPlugin, import_module(plugin.stem))
    plugin_module.generate_configuration(directory, points_list)

Я не уверен, как я отношусь к необходимости добавлять класс ConfigurationGenerationPlugin или вызов cast () в код только для того, чтобы осчастливить mypy. Однако пока я собираюсь придерживаться этого.

person idahogray    schedule 27.02.2018
comment
Вы не думаете, что добавление определения класса и явного приведения типов улучшает читаемость и прозрачность? Я уверен! - person GLRoman; 26.07.2021