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

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

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

Related: can I count on sys.path[0] path to the script, even if it differs from the current working directory ( os.getcwd() )?

EDIT: I forgot to mention - I want to be able to get plugins from several different folders, while the user indicates the paths to the plugin folders. Each of these folders is currently configured as a package (with __init__.py ); I can trivially refuse this if this causes a problem.

+6
source share
1 answer

This may seem odd, but you can change the __path__ module variable and then import from it. Then you do not bother with the global import space in sys.path.

Edit: if directories are loaded at run time, you do not need the plugins.py file to store them. A dynamic dynamic module can be created:

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 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 have never used this, but it works in both Python 2 and 3.

+6
source

Source: https://habr.com/ru/post/896058/


All Articles