How to perform dynamic Python imports with module names?

How can I perform a Python dynamic import given the module name as a string?

I’m developing a Python application that takes a command as an argument, for example:

$ python myapp.py command1

The goal is to make the application extensible, so I can add new modules for commands without modifying the main application’s source code. The directory structure looks like this:

myapp/
    __init__.py
    commands/
        __init__.py
        command1.py
        command2.py
    foo.py
    bar.py

I want the application to dynamically find available command modules and execute the corresponding one at runtime.

Python provides the __import__() function, which allows importing modules by name as a string:

__import__(name, globals=None, locals=None, fromlist=(), level=0)

This function imports the specified module, and you can customize the globals, locals, and other parameters.

Currently, I’m using something like this:

command = sys.argv[1]
try:
    command_module = __import__("myapp.commands.%s" % command, fromlist=["myapp.commands"])
except ImportError:
    # Display error message
command_module.run()

This works well, but I’m curious if there’s a more idiomatic or preferred way to handle this in Python, specifically with dynamic imports.

(Note: I am not looking to use eggs or plugins in this application, as it’s not open-source and doesn’t require external extensions.)

So, from my experience, using importlib.import_module is the go-to way for handling python dynamic import in Python versions 2.7 and newer. This method provides a clear and maintainable approach for importing modules dynamically by their names."

For example:

import importlib

command = sys.argv[1]
try:
    command_module = importlib.import_module(f"myapp.commands.{command}")
except ImportError:
    print(f"Error: The command '{command}' could not be found.")
else:
    command_module.run()

This ensures you’re following the more idiomatic and explicit approach when dealing with python dynamic import, which is helpful for keeping things clean and understandable in the long run.

Now, to build on @devan-skeem’s point, let’s talk about how we can scale this concept. If you’re looking to dynamically import multiple modules at once, then __import__ can be a more compact option for python dynamic import. This method shines when you have a list of module names that you want to load in one go."

Here’s how it would look:

module_names = ['command1', 'command2', 'command3']
modules = {}

for name in module_names:
    try:
        modules[name] = __import__(f"myapp.commands.{name}", fromlist=["myapp.commands"])
    except ImportError:
        print(f"Module '{name}' could not be imported.")

# Execute the run function of a specific module
command = 'command1'  # Example command
if command in modules:
    modules[command].run()

This method is quite useful when you know the modules in advance and want to load them dynamically while keeping the code more concise. You can dynamically import multiple modules in a single loop, which makes things a lot easier when managing numerous commands.

Building off both of the previous methods, there’s also the option to dynamically import modules and assign them as attributes in a custom namespace. This gives you even more flexibility when working with python dynamic import."

For instance:

import types

commands = types.SimpleNamespace()
module_names = ['command1', 'command2', 'command3']

for name in module_names:
    try:
        setattr(commands, name, __import__(f"myapp.commands.{name}", fromlist=["myapp.commands"]))
    except ImportError:
        print(f"Failed to import '{name}'.")

# Access the module and run the command dynamically
command = 'command1'
if hasattr(commands, command):
    getattr(commands, command).run()

In this case, you’re not only importing modules dynamically but also organizing them neatly within a namespace. It’s like having a clean, organized shelf for your commands, making it easy to reference them dynamically by name while keeping everything structured and manageable.