【问题标题】:Issues with module imports going from python 2 to python 3从 python 2 到 python 3 的模块导入问题
【发布时间】:2020-03-06 01:16:20
【问题描述】:

我正在尝试将我没有编写的 10 年历史的事件侦听器从 Python 2.7 升级到 python 3.7。我遇到的基本问题是原始脚本导入其插件的方式。原始脚本背后的想法是,任何放入“plugins”文件夹的python文件,带有其中的“registerCallbacks”函数会自动将自身加载到事件侦听器中并运行。多年来,它一直在许多工作室中运行良好,但 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 导入模块的方式发生了变化(据我所知),其他留言板似乎都没有让我找到答案。
我尝试了几种不同的方法,目前最好的是:
How to import a module given the full path?
我尝试了几种不同的方法,包括将完整路径添加到 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)

是否有人对我如何实际导入具有给定文件夹结构的这些模块有任何见解? 提前致谢。

【问题讨论】:

  • 查看了 importlib.machinery.SourceFileLoader?
  • 您确定这些模块对 Python3 有效吗?此外,还可以在此处找到其他一些提示和建议:stackoverflow.com/questions/43728431/…

标签: python python-importlib python-2to3 imp


【解决方案1】:

您将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)

然后使用importimportlib.import_module 导入您的插件。可能是importlib.import_module,因为听起来插件加载器不会提前知道插件名称:

plugin = importlib.import_module(plugin_name)

如果您这样做,插件将被视为普通模块,其后果是无法安全地选择与已安装模块冲突的插件名称。


作为一个完全独立的问题,您的 Plugin 类完全忽略了它的 path 参数,这很奇怪。

【讨论】:

  • 是的,我不确定为什么插件路径会被忽略。这令人沮丧,但到目前为止你们提供的信息非常有帮助。我现在添加了 spec.loader.exec_module(plugin),尽管我可能必须弄清楚这些东西在原始脚本中的执行位置。 spec.loader.exec_module(plugin) 是立即执行它,还是只是准备在其他地方使用它?再次感谢。这很有帮助
  • @AdamBenson: spec.loader.exec_module(plugin) 立即执行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-26
  • 1970-01-01
  • 2019-06-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多