Проблемы с импортом модуля, идущие от python 2 до python 3 - PullRequest
0 голосов
/ 06 марта 2020

Я пытаюсь обновить 10-летнего слушателя событий, который я не написал, с Python 2.7 до python 3.7. Основная проблема, с которой я столкнулся, заключается в том, как оригинальный скрипт импортировал свои плагины. Идея оригинального сценария заключалась в том, что любой файл python, помещенный в папку «plugins», с функцией «registerCallbacks» внутри, автоматически загружал себя в прослушиватель событий и запускался. Он отлично работал на многих стад ios в течение многих лет, но Python 3.7 это совсем не нравится.
Структура папок для исходного кода выглядит следующим образом:

EventListenerPackage
    src
        event_listener.py
    plugins
        plugin_1.py
        plugin_2.py

С Таким образом, вы можете видеть, что и прослушиватель событий, и плагины хранятся в папках, которые параллельны друг другу, а не вложены.
Исходный код читается так:

# Python 2.7 implementation

import imp

class Plugin(object):
    def __init__(self, path):
        self._path = 'c:/full/path/to/EventListenerPackage/plugins/plugin_1.py'
        self._pluginName = 'plugin_1'

    def load(self):
        try:
            plugin = imp.load_source(self._pluginName, self._path)
        except:
            self._active = False
            self.logger.error('Could not load the plugin at %s.\n\n%s', self._path, traceback.format_exc())
            return

        regFunc = getattr(plugin, 'registerCallbacks', None)

Из-за природы Из изменений (как я их понимаю) в том, как Python 3 импортируются модули, ни одна из других досок объявлений, похоже, не дает мне ответа.
Я пробовал несколько разных подходов, лучший на данный момент :
Как импортировать модуль по полному пути?
Я пробовал несколько разных методов, включая добавление полного пути к sys.path, но я всегда получаю «ModuleNotFoundError».
Вот где я сейчас нахожусь.

import importlib.util
import importlib.abc
import importlib

class Plugin(object):
    def __init__(self, path):
        self._path = 'c:/full/path/to/EventListenerPackage/plugins/plugin_1.py'
        self._pluginName = 'plugin_1'

    def load(self):
        try:
            spec = importlib.util.spec_from_file_location('plugins.%s' % self._pluginName, self._path)
            plugin = importlib.util.module_from_spec(spec)
            # OR I HAVE ALSO TRIED
            plugin = importlib.import_module(self._path)
        except:
            self._active = False
            self.logger.error('Could not load the plugin at %s.\n\n%s', self._path, traceback.format_exc())
            return

        regFunc = getattr(plugin, 'registerCallbacks', None)

Кто-нибудь знает, как я могу на самом деле импортировать эти модули с заданной структурой папок? Заранее спасибо.

1 Ответ

0 голосов
/ 06 марта 2020

Вы рассматриваете plugins, как будто это пакет. Это не. Это просто папка, в которой находится исходный код вашего плагина.

Вам нужно прекратить ставить plugins. перед аргументом имени модуля в spec_from_file_location:

spec = importlib.util.spec_from_file_location(self._pluginName, self._path)

В сторону Исходя из этого, вам также не хватает части, которая фактически выполняет код модуля:

spec.loader.exec_module(plugin)

В зависимости от того, как вы хотите, чтобы ваша система плагинов взаимодействовала с обычными модулями, вы могли бы просто вставить плагин каталог на путь импорта:

sys.path.append(plugin_directory)

, а затем импортируйте свои плагины с import или importlib.import_module. Вероятно, importlib.import_module, так как похоже на то, что загрузчик плагинов не будет заранее знать названия плагинов:

plugin = importlib.import_module(plugin_name)

Если вы сделаете это, плагины будут рассматриваться как обычные модули с последствиями, такими как невозможность смело выбирайте имя плагина, которое сталкивается с установленным модулем.


В качестве совершенно отдельной проблемы довольно странно, что ваш класс Plugin полностью игнорирует аргумент path.

...