How to import members of all modules within a package?

I want the members of all modules in package to be in package’s
namespace, and I do not want the modules themselves to be in the
namespace.

I was able to do that by adapting something I’ve used in Python 2 to automatically import plug-ins to also work in Python 3.

In a nutshell, here’s how it works:

  1. The package’s __init__.py file imports all the other Python files in the same package directory except for those whose names start with an '_' (underscore) character.

  2. It then adds any names in the imported module’s namespace to that of __init__ module’s (which is also the package’s namespace). Note I had to make the example_module module explicitly import foo from the .foo_module.

One important aspect of doing things this way is realizing that it’s dynamic and doesn’t require the package module names to be hardcoded into the __init__.py file. Of course this requires more code to accomplish, but also makes it very generic and able to work with just about any (single-level) package — since it will automatically import new modules when they’re added and no longer attempt to import any removed from the directory.

test.py:

from package import *

print(example('derp'))

__init__.py:

def _import_all_modules():
    """ Dynamically imports all modules in this package. """
    import traceback
    import os
    global __all__
    __all__ = []
    globals_, locals_ = globals(), locals()

    # Dynamically import all the package modules in this file's directory.
    for filename in os.listdir(__name__):
        # Process all python files in directory that don't start
        # with underscore (which also prevents this module from
        # importing itself).
        if filename[0] != '_' and filename.split('.')[-1] in ('py', 'pyw'):
            modulename = filename.split('.')[0]  # Filename sans extension.
            package_module=".".join([__name__, modulename])
            try:
                module = __import__(package_module, globals_, locals_, [modulename])
            except:
                traceback.print_exc()
                raise
            for name in module.__dict__:
                if not name.startswith('_'):
                    globals_[name] = module.__dict__[name]
                    __all__.append(name)

_import_all_modules()

foo_module.py:

def foo(bar):
    return bar

example_module.py:

from .foo_module import foo  # added

def example(arg):
    return foo(arg)

Leave a Comment