Xantium
Xantium

Reputation: 11605

How to call a dynamically loaded module without raising NameError: name 'name' is not defined

I'm trying to create a 'plugin' system, where placing a python file (or package) inside a 'plugins' folder, and reloadings the script will dynamically call the functions inside those files.

I have the following file structure

main.py
plugins -
         |- test.py
         |- status.py

I import the test.py/status.py modules like so:

sys.path.append('plugins')

plugins_list = os.listdir('plugins')
plugins_list.remove('__pycache__') # prevenet error from being raised

for module in plugins_list:
    importlib.import_module('plugins.'+module[:-3])
    print("Imported {}".format('plugins.'+module[:-3]))

Script runs fine. I try print(sys.modules.keys()) and plugins.test and plugins.status have indeed been imported. However now when I attempt to call any functions inside, a name error is raised NameError: name 'plugins' is not defined

This takes me to Python custom module name not defined where they explain that plugins.status.get_status() will not work. I somehow have to import it differently. The issue is that I've used importlib so I'm not sure how to achieve that.

I've looked at the documentation page:

importlib.import_module(name, package=None)

Import a module. The name argument specifies what module to import in absolute or relative terms (e.g. either pkg.mod or ..mod). If the name is specified in relative terms, then the package argument must be set to the name of the package which is to act as the anchor for resolving the package name (e.g. import_module('..mod', 'pkg.subpkg') will import pkg.mod).

The import_module() function acts as a simplifying wrapper around importlib.__import__(). This means all semantics of the function are derived from importlib.__import__(). The most important difference between these two functions is that import_module() returns the specified package or module (e.g. pkg.mod), while __import__() returns the top-level package or module (e.g. pkg).

It seems as if __import__() would solve my problem, however it recommends I do not use that.

Additionally I feel like defining something as the second importlib arguement may sort the problem, however I'm not sure what

How do I make it so that the functions could be run?

Upvotes: 0

Views: 269

Answers (1)

user12842282
user12842282

Reputation:

When you are running importlib.import_module('plugins.'+module[:-3]) the value that is getting returned is the imported module. It's not being assigned to anything so it's getting cleaned up almost as soon as it's imported. You can dynamically add to the namespace, but it's not recommended.

Try something like this, where you're assigning the imported module to a dictionary, that you can then reference the module via the dictionary based on the module name:

plugin_dict = {}

for module in plugins_list:
    modname = module[:-3]
    plugin_dict[modname] = importlib.import_module('plugins.'+modname)
    print("Imported {}".format('plugins.'+module[:-3]))
    
    
    
plugin_dict['status'].get_status()

Upvotes: 2

Related Questions