I'm writing a python application that allows users to write their own plugins and extend the core functionality I provide -
$ tree project_dir/
.
├── application.py
├── plugins
│ ├── __init__.py
│ ├── example_plugin.py
│ ├── plugin1.py
│ ├── plugin2.py
│ └── plugin3
│ ├── sounds
│ │ └── test.wav
│ └── player.py
└── plugins_manager.py
plugins_manager.py -
class Manager(object):
def __init__(self):
self.plugins = {}
def register_plugin(self, name, plugin_func):
self.plugins[name] = plugin_func
application.py initializes Manager
instance globally -
manager = Manager()
def main():
print manager.plugins
main()
Each plugin is required to import the Manager
instance from application.py
and register itself like, plugin1.py -
from application import manager
PLUGIN_NAME = "AAC_Player"
def plugin_function(options):
# do something
manager.register_plugin(PLUGIN_NAME, plugin_function)
Now when I run application.py, obviously nothing gets printed. How do I make the plugins register themselves (call .register_plugin()
) at program startup?
So on that lines, a more generalised question would be - How can I make python execute a line of code that's global in a file without actually running the file?
Suggestions on improving the plugin architecture welcome!
You can use the __import__()
builtin to import the plugins, and then include the register_plugin()
call in either the plugin file example_plugin.py
or in __init__.py
if it's a directory.
For example, let's say this is your project structure:
./
application.py
plugins_manager.py
plugins/
__init__.py
plugin1.py
plugin2.py
plugin3/
__init__.py
Plugins have these contents:
$ cat plugins/plugin1.py
print 'Plugin 1'
$ cat plugins/plugin2.py
print 'Plugin 2'
$ cat plugins/plugin3/__init__.py
print 'Plugin 3'
In plugins_manager.py
, identify the plugins and import them in:
from os import listdir
from os.path import exists, isdir, basename, join, splitext
def is_plugin(filename):
filepath = join('plugins', filename)
_, ext = splitext(filepath)
# Ignore plugins/__init__.py
if filename == '__init__.py':
return False
# Find single file plugins
if ext == '.py':
return True
# Find plugins packaged in directories
if isdir(filepath) and exists(join(filepath, '__init__.py')):
return True
return False
plugin_names = [ splitext(p)[0] for p in listdir('plugins/') if is_plugin(p) ]
plugins = [ __import__('plugins.' + p) for p in plugin_names ]
Should get output similar to:
Plugin 1
Plugin 2
Plugin 3
Note that in this case the plugins
variable contains a list of the module objects imported.
Strictly speaking I'd say there is no way to run code without it being invoked somehow. To do this, the running program can use
import importlib
so that once you've found the file you can import it with:
mod = importlib.import_module(import_name, pkg_name)
and if that file provides a known function (Run in this case) you can call it with:
mod.Run(your_args)
This works for Python 2.7. Version 3 might be different.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.