2

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.

3
  • 1
    This is not usually how to make a project "pluggable". Unless the plugins are installed while the Python process is already running. Is that your case? Commented May 17, 2021 at 19:42
  • Yes the plugins exist in a folder called plugins and I have the paths leading to each plugin. Commented May 17, 2021 at 22:36
  • Actually, could you clarify what you mean by installed? I don't have them pip installed, but they exist in a known directory. Commented May 17, 2021 at 23:27

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

I tried the same and it works - as long as there is only one plugin. Once you have two or more, it only loads the first. Neither the iter_modules or walk_packages work correctly.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.