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 working 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.
sys. path is a built-in variable within the sys module. It contains a list of directories that the interpreter will search in for the required module.
To undo the sys. path. append , you just need to remove that line from your script. Since the path is only modified for your current script and not system wide until you edit the PYTHONPATH .
In Python, you use the import keyword to make code in one module available in another. Imports in Python are important for structuring your code effectively. Using imports properly will make you more productive, allowing you to reuse code while keeping your projects maintainable.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With