Reputation: 55
I am trying to create a python application that can be extended with plugins.
For testing I've tried to create a plugin with the following structure:
plugin_name
├── __init__.py
├── utils.py
└── config.py
The plugin class that I need is located in plugin_name.__init__.py
, but ___init__.py
uses utils.py
.
I am using the following code to import __init__.py
:
import os
module_path = "path to __init__.py"
package_name = os.path.basename( os.path.dirname(path) )
spec = importlib.util.spec_from_file_location(package_name, path)
plugin_module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(plugin_module )
If __init__.py
imports utils.py
as such:
import utils.py
It throws ModuleNotFoundError: No module named 'utils'
If __init__.py
imports utils.py
as such:
import utils.py
It throws ImportError: attempted relative import with no known parent package
So it's obvious that the import code I'm using doesn't recognize the package and only imports the specific file I specify without any metadata of the folder it is in or the other files in the same directory.
Is there a way to import packages like this?
I'm looking into pkgutil
and I can see that using pkgutil.walk_modules
, I can identify all the packages in the plugin. I'm wondering if I can use this to import the plugins I want, but I can't find any examples or documentation that would suggest this.
Upvotes: 1
Views: 1465
Reputation: 55
If the plugin directory looks as such:
path_to_plugin
└── plugin_name
├── __init__.py
├── utils.py
└── config.py
import pkgutil
path = 'path_to_plugin'
modules = []
for package in pkgutil.iter_modules(path):
finder, name, ispkg = package
spec = finder.find_spec(name)
module = spec.loader.load_module(name)
modules.append(module)
This code loads packages dynamically inside a directory.
If there is a better answer, please share.
Upvotes: 1