Developing modules with ‘pkgutil’

Ben Finney ben+python at benfinney.id.au
Wed Apr 15 21:45:27 EDT 2009


Howdy all,

With all the current fuss about namespace packages, I'm dealing with a
similar goal that I hope is possible with stock Python 2.x.

When developing a module intended to be part of an existing package
installed on the system, I want to write programs that will import the
*in-development* module from my current working tree, but the
*system-installed* modules from the rest of the package.

The specific case is that of a new writer for Docutils. The module will
eventually be installed such that it is accessed via ‘import
docutils.writers.foo’, but while developing it I explicitly *don't* want
the module to come from the system-installed ‘docutils/writers/’
directory since that will fail to get the one I'm developing.

But the rest of the Docutils infrastructure I *need* to come from the
system-installed package when I do ‘docutils.bar.baz’. So I need to
somehow have a module in one location appear, for the purpose of
imports, as though it's part of a package defined in a different
location.

A naive first try would be:

    /usr/lib/python2.5/site-packages/
        docutils/
            __init__.py
            core.py
            …
            readers/
                __init__.py
                …
            transforms/
                __init__.py
                …
            writers/
                __init__.py
                …

    $HOME/projects/foo-writer/
        tools/
            rst2foo
        docutils/
            __init__.py
            writers/
                __init__.py
                foo.py

So, while developing the ‘foo.py’ module, I need to run ‘tools/rst2foo’
in order to make use of the module and exercise its in-development
functionality (and *not* whatever ‘foo.py’ might exist in the system
library location). But whenever I import anything *else* from the
‘docutils’ package, it's not going to find the system-installed package.

The ‘pkgutil’ module <URL:http://docs.python.org/library/pkgutil>, which
I only partly understand (with thanks to Doug Hellman for
<URL:http://blog.doughellmann.com/2008/02/pymotw-pkgutil.html>), appears
to offer a solution for this, by allowing my in-development ‘docutils’
shim package to also include the real one:

    $ cd $HOME/projects/foo-writer/
    $ cat docutils/__init__.py
    import pkgutil
    __path__ = pkgutil.extend_path(__path__, __name__)
    __path__.reverse()

Which, according to Doug, should allow me to have ‘tools/rst2foo’ say:

    from docutils.core import publish_cmdline, default_description
    from docutils.writers import foo

as it will look when installed for the end user; and the ‘docutils’
namespace will, because of the in-development shim package, be searched
both there and the system-installed directory, finding both the
system-installed ‘docutils.core’ and the in-development
‘docutils.writers.manpage’.

Then I should be able to run the program while developing, like this:

    $ PYTHONPATH=.  python ./tools/rst2foo

and it should find everything it needs.


However, this approach doesn't seem to be complete: there is code in the
system-installed ‘docutils/__init__.py’ that is not being found:

    Traceback (most recent call last):
      File "./tools/rst2foo", line 21, in <module>
        from docutils.core import publish_cmdline, default_description
      File "/usr/lib/python2.5/site-packages/docutils/core.py", line 20, in <module>
        from docutils import __version__, __version_details__, SettingsSpec
    ImportError: cannot import name __version__

What's happening, of course, is that the name ‘__version__’ is defined
in the system-installed ‘docutils/__init__.py’, but that's not being
found because the in-development ‘docutils/__init__.py’ is found first,
which doesn't have that name.

A simple ‘from docutils import *’ clearly doesn't work, for the same
reason. Catch-22.

At this point I'm stuck. I can't see how to have the
‘docutils/__init__.py’ stop shadowing the names in the system-installed
‘docutils/__init__.py’, while still doing the namespace shuffle
necessary to have my in-development module appear part of the wider
package namespace. What should I be doing instead?

-- 
 \         “Smoking cures weight problems. Eventually.” —Steven Wright |
  `\                                                                   |
_o__)                                                                  |
Ben Finney



More information about the Python-list mailing list