On Tue, May 22, 2012 at 12:31 PM, Eric V. Smith <eric@trueblade.com> wrote:
On 05/22/2012 11:39 AM, Nick Coghlan wrote:
> Oops, I also meant to say that it's probably worth at least issuing
> ImportWarning if a new portion with an __init__.py gets added - it's
> going to block all future dynamic updates of that namespace package.

Right. That's on my list of things to clean up. It actually won't block
updates during this run of Python, though: once a namespace package,
always a namespace package. But if, on another run, that entry is on
sys.path, then yes, it will block all namespace package portions.

This discussion has gotten me thinking: should we expose a pkgutil.declare_namespace() API to allow such an __init__.py to turn itself back into a namespace?  (Per our previous discussion on transitioning existing namespace packages.)  It wouldn't need to do all the other stuff that the setuptools version does, it would just be a way to transition away from setuptools.

What it would do is:
1. Recursively invoke itself for parent packages
2. Create the module object if it doesn't already exist
3. Set the module __path__ to a _NamespacePath instance.

def declare_namespace(package_name):
     parent, dot, tail = package_name.rpartition('.')
     attr = '__path__'
     if dot:
        declare_namespace(parent)
     else:
        parent, attr = 'sys', 'path'
     with importlockcontext:
          module = sys.modules.get(package_name)
          if module is None:
              module = XXX new module here
          module.__path__ = _NamespacePath(...stuff involving 'parent' and 'attr')

It may be that this should complain under certain circumstances, or use the '__path__ = something' idiom, but the above approach would be (basically) API compatible with the standard usage of declare_namespace.

Obviously, this'll only be useful for people who are porting code going forward, but even if a different API is chosen, there still ought to be a way for people to do it.  Namespace packages are one of a handful of features that are still basically setuptools-only at this point (i.e. not yet provided by packaging/distutils2), but if it's the only setuptools-only feature a project is using, they'd be able to drop their dependency as of 3.3.

(Next up, I guess we'll need an entry-points PEP, but that'll be another discussion. ;-) )