[Python-ideas] Allow 'import star' with namespaces

Nick Coghlan ncoghlan at gmail.com
Mon May 9 16:04:16 CEST 2011


On Sat, May 7, 2011 at 6:52 AM, Eric Snow <ericsnowcurrently at gmail.com> wrote:

> If you have a list of the submodules you want imported then you can already
> accomplish this:
> import parent
> for mod in parent.__all_submodules__:
>     __import__("parent.{}".format(mod))

> Of course, this does not bind the submodules to the namespace of the package
> module

It actually does, as binding the submodule name in the parent package
namespace is part of the responsibility of __import__():

>>> import logging
>>> logging.handlers
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'handlers'
>>> __import__("logging.handlers")
<module 'logging' from '/usr/lib/python2.7/logging/__init__.pyc'>
>>> logging.handlers
<module 'logging.handlers' from '/usr/lib/python2.7/logging/handlers.pyc'>

This is one of the reasons circular imports are such a pain - we
pre-bind them in sys.modules, and remove them again if the import
fails, but we don't currently do that in the parent package namespace,
so circular imports sometimes work and sometime break depending not
only on which names are accessed but also *how* they're accessed (e.g.
in a/b/c.py, "import a.b.c" will work, "import a.b.c; c = a.b.c" will
fail with AttributeError and "from a.b import c" will fail with
ImportError).

> I am not sure
> of the specific import mechanism with regards to name binding, but that
> would seem to be a conflict with the way imported names for submodules are
> bound.

Nope, it's basically the same as what happens automatically when the
modules are imported normally. Indeed, as near as I can tell, this
request amounts to asking for syntactic sugar that does something
roughly along the lines of:

def _subnames(pkg_name, subnames):
    for subname in subnames:
        yield ".".join(pkg_name, subname)

def import_all(pkg):
    try:
        pkg_all = pkg.__all__
    except AttributeError:
        pass
    else:
        names = list(_subnames(pkg.__name__, pkg_all))
        for name in names:
            mod = importlib.import_module(name)
            try:
                mod_all = mod.__all__
            except AttributeError:
                pass
            else:
                names.extend(_subnames(mod.__name__, mod_all)

I can see a case being made to provide that as a function in pkgutil
(or perhaps importlib itself), but I don't see any reason to give it
dedicated syntax.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia



More information about the Python-ideas mailing list