【问题标题】:Programmatically importing works on Windows, but not on Linux以编程方式导入适用于 Windows,但不适用于 Linux
【发布时间】:2012-04-04 02:41:42
【问题描述】:

所以我有一个目录树如下:

pluginlist.py
plugins/
    __init__.py
    plugin1.py
    plugin2.py
    ...

并希望从 plugin1、plugin2 等中连接一个类似名称的字典。

我这样做的方式如下(来自pluginlist.py):

import os

pluginFolderName = "plugins"
pluginFlag = "##&plugin&##"

commands = {}

os.chdir(os.path.abspath(pluginFolderName))

for file in os.listdir(os.getcwd()):
    if os.path.isfile(file) and os.path.splitext(file)[1] == ".py":
        fileo = open(file, 'r')
        firstline = fileo.readline()
        if firstline == "##&plugin&##\n":
            plugin_mod = __import__("plugins.%s" % os.path.splitext(file)[0])
            import_command = "plugin_commands = plugin_mod.%s" %     os.path.splitext(file)[0]
            exec import_command
            commands = dict(commands.items() + plugin_commands.commands.items())
print commands

(打印命令用于测试目的)

在 Windows 上运行它会给出正确的命令字典,但在 Linux(Ubuntu 服务器)上运行它会给出一个空字典。

【问题讨论】:

  • 你不能用plugin_commands = getattr(plugin_mod, os.path.splitext(file)[0])代替exec吗?

标签: python plugins import


【解决方案1】:

试试:

for file in os.listdir(os.getcwd()):
    basename, ext = os.path.splitext(file)
    if os.path.isfile(file) and ext == ".py":
        with open(file, 'r') as fileo:
            firstline = fileo.readline()
            if firstline.startswith("##&plugin&##"):
                plugin_mod = __import__("plugins.%s" % basename, fromlist = [True])
                plugin_commands = getattr(plugin_mod, basename)
                commands.update(plugin_commands.commands)

当您调用__import__('A.B') 时,将返回包A。 当您调用__import__('A.B', fromlist = [True]) 时,将返回模块B。在我看来你想要B。因此,在 Windows 和 Linux 上,您都需要将 fromlist 设置为某个非空列表。

【讨论】:

  • 这不是它失败的原因,但它仍然有助于更惯用地做事,所以谢谢
【解决方案2】:

您的源代码是否有 Windows CRLF 行尾?尝试添加print repr(firstline) 以检查它是否以\r\n 而不是\n 结尾。

【讨论】:

    【解决方案3】:

    我会在if 语句上放置一个else: 分支,如果插件缺少标识符,则会打印警告

    另外,您可能并不关心行尾,因此在检查时调用firstline.strip() 可能会解决您的问题

    最后,学究式地,您可以将file 加入pluginFolderName 路径,而不是使用os.chdir()

    未测试:

    pluginFolderName = "plugins"
    pluginFlag = "##&plugin&##"
    
    pluginFolderName = os.path.abspath(pluginFolderName)
    
    commands = {}
    for file in os.listdir(pluginFolderName):
        # Construct path to file (instead of relying on the cwd)
        file = os.path.join(pluginFolderName, file)
    
        if os.path.isfile(file) and os.path.splitext(file)[1] == ".py":
            fileo = open(file, 'r')
            firstline = fileo.readline()
    
            if firstline.strip() == pluginFlag:
                # Strip firstline to ignore trailing whitespace
    
                plugin_mod = __import__("plugins.%s" % os.path.splitext(file)[0])
                plugin_cmds = getattr(plugin_mod, os.path.splitext(file)[0])
                commands.update(plugin_cmds)
             else:
                 print "Warning: %s is missing identifier %r, first line was %r" % (
                     file, PLUGIN_IDENTIFIER, firstline)
    

    【讨论】:

      【解决方案4】:

      找出我的问题!

      os.path.isfile(file)
      

      test 无法正常工作,因为 Linux 需要插件文件的绝对路径。所以用

      替换所有文件实例
      os.path.join(os.getcwd(), file)
      

      似乎可以解决所有问题。

      【讨论】:

        猜你喜欢
        • 2011-06-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-21
        • 2011-10-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多