Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recursively populating __all__ in __init__.py

Tags:

python

flask

I'm using the following code to populate __all__ in my module's __init__.py and I was wandering if there was a more efficient way. Any ideas?

import fnmatch
import os

__all__ = []
for root, dirnames, filenames in os.walk(os.path.dirname(__file__)):
    root = root[os.path.dirname(__file__).__len__():]
    for filename in fnmatch.filter(filenames, "*.py"):
        __all__.append(os.path.join(root, filename[:-3]))
like image 823
Duru Can Celasun Avatar asked Oct 26 '25 07:10

Duru Can Celasun


1 Answers

You probably shouldn't be doing this: The default behaviour of import is quite flexible. If you don't want a module (or any other variable) to be automatically exported, give it a name that starts with _ and python won't export it. That's the standard python way, and reinventing the wheel is considered unpythonic. Also, don't forget that other things besides modules may need exporting; once you set __all__, you'll need to find and export them as well.

Still, you ask how to best generate a list of your exportable modules. Since you can't export what's not present, I'd just check what modules of your own are known to your main module:

basedir = os.path.dirname(__file__)
for m in sys.modules:
    if m in locals() and not m.startswith('_'): # Only export regular names
        mod = locals()[m]
        if '__file__' in mod.__dict__  and mod.__file__.startswith(basedir):
            print m

sys.modules includes the names of every module that python has loaded, including many that have not been exported to your main module-- so we check if they're in locals().

This is faster than scanning your filesystem, and more robust than assuming that every .py file in your directory tree will somehow end up as a top-level submodule. Naturally you should run this code near the end of your __init__.py, when everything has been loaded.

like image 120
alexis Avatar answered Oct 28 '25 02:10

alexis