Programmatically importing works on Windows, but not on Linux

Go To StackoverFlow.com

1

So I have a directory tree as follows:

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

And want to concatenate a similarly-named dictionary from each of plugin1, plugin2, etc.

The way I'm doing this is as follows (from 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

(The print commands there is for testing purposes)

Running that on Windows gives the proper commands dictionary, but running it on Linux (Ubuntu Server) gives an empty dictionary.

2012-04-04 02:41
by glittershark
Can't you use plugin_commands = getattr(plugin_mod, os.path.splitext(file)[0]) instead of exec - Blender 2012-04-04 02:53


0

Figured out my problem! The

os.path.isfile(file)

test wasn't working because Linux wanted an absolute path to the plugin file. So replacing all instances of file with

os.path.join(os.getcwd(), file)

Seems to fix everything.

2012-04-04 18:21
by glittershark


2

Try:

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)

When you call __import__('A.B'), the package A is returned. When you call __import__('A.B', fromlist = [True]), the module B is returned. It seems to me you want B. So on both Windows and Linux, you should need to set fromlist to some nonempty list.

2012-04-04 02:54
by unutbu
This wasn't the reason it was failing, but it still helped with doing things more idiomatically, so thank - glittershark 2012-04-04 18:22


0

Does your source code have Windows CRLF line endings? Try adding a print repr(firstline) to check that it doesn't end with \r\n instead of \n.

2012-04-04 02:58
by Baffe Boyois


0

I would put an else: branch on the if statement which prints a warning if a plugin is missing the identifier

Also, you probably don't care about the line endings, so calling firstline.strip() when checking may fix your problem

Finally, pedantically, you can just join file to the pluginFolderName path instead of using os.chdir()

Not tested:

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)
2012-04-04 03:24
by dbr