开发者

Telling __import__ where to look - am I stuck with sys.path?

开发者 https://www.devze.com 2023-03-31 11:41 出处:网络
I have a project in pure Python with a rudimentary plugin system: you write a module that defines a class with a specific interface and name, and the program imports the module and subsequently instan

I have a project in pure Python with a rudimentary plugin system: you write a module that defines a class with a specific interface and name, and the program imports the module and subsequently instantiates the class as needed.

Currently, the plugins all come from a specific folder (subdirectory of where the main .py file is located). I would like to be able to have them elsewhere on disk, and instruct the program to look for plugins in a specific place. Can I do this, for one-off dynamic imports, in a cleaner way than modifying sys.path? I don't want to pollute this global.

Related: can I count on sys.path[0] being the path to the script, even if that differs from the current worki开发者_开发问答ng directory (os.getcwd())?

EDIT: I forgot to mention - I want to be able to get plugins from several different folders, with the user specifying paths to plugin folders. Currently, each of these folders is set up as a package (with an __init__.py); I can trivially scrap this if it causes a problem.


This might seem weird, but you can modify a module's __path__ variable and then import from it. Then you're not messing with the global import space in sys.path.

Edit: If the directories are loaded at run time, then you don't need a plugins.py file to store them. You can create the module dynamically:

main.py:

#create the plugins module (pseudo-package)

import sys, os

sys.modules['plugins'] = plugins = type(sys)('plugins')

plugins.__path__ = []
for plugin_dir in ['plugins1', 'plugins2']:
    path = os.path.join(sys.path[0], 'addons', plugin_dir)
    plugins.__path__.append(path)

After creating the dynamic module, you can load the plugins as before, using either import_module or __import__:

from importlib import import_module

myplugins = []
for plugin in ['myplugin1', 'myplugin2']:
    myplugins.append(import_module('plugins.' + plugin))
    myplugins[-1].init()

##or using __import__:

myplugins = []
for plugin in ['myplugin1', 'myplugin2']:
    myplugins.append(getattr(__import__('plugins.' + plugin), plugin))
    myplugins[-1].init()

addons/plugins1/myplugin1.py:

def init():
    print('myplugin1')

addons/plugins2/myplugin2.py:

def init():
    print('myplugin2')

I've never used this, but it does work in both Python 2 & 3.

0

精彩评论

暂无评论...
验证码 换一张
取 消