[Distutils] setuptools: namespace packages
Phillip J. Eby
pje at telecommunity.com
Fri Aug 19 19:54:01 CEST 2005
At 12:21 PM 8/19/2005 -0500, Ian Bicking wrote:
>When developing a namespace distribution, where should I put it? Should
>each such distribution be a separate project in the repository (e.g.,
>code goes in Paste/exceptions/trunk/paste/exceptions/)?
If you want to distribute them separately, they need to be separate
projects with their own setup.py and project name, like "Paste-Exceptions"
or whatever.
For example, let's say I made "peak.util" a namespace package. Then, I
could create separate projects like "PyUUID", "DynamicImports",
"IndentedStream", and so on, for the different modules in the "peak.util"
package. Each one would have to have its own, independently distributable
project, something like:
DynamicImports/
setup.py
peak/
__init__.py
util/
__init__.py
imports.py
With the setup.py listing 'peak.util' as a namespace package. The
__init__.py files will be empty.
The reason you need this layout is that you want "setup.py develop" to
still work, and for "develop" and "test" to work, they needs the
__init__.py files. If you are only using "install" or you always run from
built eggs, you can forego the __init__.py files and even the directory
tree, slapping the module directly into the project directory, and
setuptools will generate stub __init__.py's for you when it builds the
egg. (The livinglogic.de libraries like ll-color do this.)
But, if you want to be able to use the "develop" and "test" commands, you
need a source layout that includes the package tree.
Anyway, the idea behind a namespace package is that you get to claim a
package name like "paste", and then put all your modules and packages under
it, without forcing somebody to install a single mega-distribution. PEAK
right now has a huge array of functionality under "peak.*" packages, and
much of it could be used as independent pieces, if only you didn't have to
install all of PEAK. Over time (i.e. as soon as I have enough of
setuptools finished to have some spare time!), I intend to start breaking
out such pieces as separate distributions, but all the code that still
imports e.g. "peak.util.imports" will still work, even though it will be in
a different distribution.
It would be nice, by the way, if somebody who's new to this whole namespace
package idea would write up an introduction to this for the setuptools
docs, because the idea is so old hat to me that I doubt I can write a
really good introduction to it.
> Can (or should)
>I put them all together and let setuptools break them up when I
>distribute?
Setuptools actually can break them up, using the currently-undocumented
"feature" facility. It's undocumented because if you change feature
options between builds, you may not get what you expect. But I don't
really recommend this approach, because then you have to deal with
--with-X/--without-X options, and then the projects would have to have
different names, etc. I went through this thought process when thinking
about splitting PEAK, as it seemed like it would be easier to leave
everything together. But, it's hard to still be compatible with
EasyInstall that way. Ultimately I think the "feature" approach is a dead end.
>And will I have to move modules out of the namespace package and into
>subpackages?
No. A namespace package is a package that's a container. The container
can be added to by various distributions; each distribution can add
modules, resources, or subpackages. The only thing you shouldn't do is run
code in the __init__ module, because it will get run as soon as
pkg_resources is imported and any distribution for the package is on
sys.path. For normal site-packages installation, this means that as soon
as pkg_resources is imported, all declared namespace package __init__.py's
get run.
If you don't want them to get run right away, you can put this boilerplate
into all __init__.py files for the package:
__import__('pkg_resources').declare_namespace(__name__)
and then don't declare the namespace in setup.py. The problem with this
approach, however, is that you need to make absolutely certain you do it in
the mynamespacepackage/__init__.py file of *each* distribution. If you
miss even one, and that missed one gets imported first, then the others
will not get added to the namespace. This is why it's preferable to use
the documented approach of listing namespace packages in setup(), and
always using empty __init__.py files for namespace packages.
More information about the Distutils-SIG
mailing list