One thing that can be a little confusing with Python is how packages work. Packages let you group your modules together and gives you a nice namespace. You can read all about them in the Python docs.
Now one thing that can be pretty confusing is that importing a package does not mean that any modules inside that package are loaded.
Imagine a very simple package called testing, with a single
foo module. E.g:
testing/
__init__.py
foo.py
The foo module might look something like:
def bar():
return 'bar'
Now, you might expect to be able to write code such as:
import testing print(testing.foo.bar())
However, trying this won’t work, you end up with an AttributeError:
Traceback (most recent call last): File "t.py", line 2, intesting.foo.bar() AttributeError: 'module' object has no attribute 'foo'
So, to fix this you need to actually import the module. There are at (at least) two ways you can do this:
import testing.foo from testing import foo
Either of these put testing.foo into
sys.modules, and testing.foo.bar() will work
fine.
But, what if you want to load all the modules in a package? Well, as far as I know there isn't any built-in approach to doing this, so what I’ve come up with is a pretty simple function that, given a package, will load all the modules in the package, and return them as a dictionary keyed by the module name.
def plugin_load(pkg):
"""Load all the plugin modules in a specific package.
A dictionary of modules is returned indexed by the module name.
Note: This assumes packages have a single path, and will only
find modules with a .py file extension.
"""
path = pkg.__path__[0]
pkg_name = pkg.__name__
module_names = [os.path.splitext(m)[0] for m in
os.listdir(path)
if os.path.splitext(m)[1] == '.py' and m != '__init__.py']
imported = __import__(pkg_name, fromlist=module_names)
return {m: getattr(imported, m) for m in module_names}
There are plenty of caveats to be aware of here. It only works with
modules ending in .py, which may miss out on some
cases. Also, at this point it doesn’t support packages that span
multiple directories (although that would be relatively simple to
add. Note: code testing on Python 3.2, probably needs
some modification to work on 2.x (in particular I don’t think dictionary
comprehensions in 2.x).
If you’ve got a better way for achieving this, please let me know in the comments.