PYTHONPATH issue with sibling package names

Stuart Moffatt stuartmoffatt at gmail.com
Thu Sep 10 13:14:23 EDT 2009


On Sep 10, 10:12 am, "Diez B. Roggisch" <de... at nospam.web.de> wrote:
> Stuart Moffatt wrote:
> > Environment: Eclipse 3.4.2, Windows XP Pro SP2, Pydev 1.4.4, python
> > 2.6
>
> > When I work in eclipse with java, I like to break up my client and
> > server packages, like this:
>
> > client-project/src/org/me/client
>
> > server-project/src/org/me/api
> > server-project/src/org/me/dao
> > server-project/src/org/me/entity
> > server-project/src/org/me/<etc>
>
> > Then, when I need to call API code from the client, I make sure the
> > API src is on the path.
>
> > I am trying setup pydev projects to do the same thing, but running
> > into an ImportError because my client code can't see the server src,
> > even though it is on the path.
>
> > Specifically, I am trying to import an entity from the server code
> > into the client, like this:
>
> >    from org.me.entity import MyEntity
>
> > If I do this from any module in the server project it is fine (because
> > the src path is in the same eclipse project). But if I do it from
> > anywhere in the client code I get the ImportError
>
> > From what I can tell, python asks for the "closest" module path, which
> > is the current project. It finds org.me, but there is only the client
> > sub-package. The org.me.entity sibling is in another eclipse project,
> > but even though that path is on the PYTHONPATH, python stopped looking
> > after it found a similarly named parent package.
>
> > Is there a trusted way to make sure python looks through all paths for
> > sibling packages? Can I load 'org.me.client' from one path in
> > PYTHONPATH and 'org.me.*' from another path in PYTHONPATH? I imagine
> > if I try to force python to load the second package first that the
> > same thing will happen in reverse.
>
> The solution you are searching for is called "namespace packages", and you
> can read more about it here:
>
>  http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages
>
> Do yourself a favor though, and don't use those several-steps-namespaces.
> This is Python, not Java - two levels at *most*, normally a
> project-namespace should be enough.
>
> Diez


Diez,

Thanks for the tips re: namespace packages. Yeah, I know this is
python, but for very large projects (or multiple projects for very
large clients) it is just more flexible to stick to the reverse-dot
java notation of "domain.organization.project.namespace".

All I had to do was make sure that top- and mid-level folders had an
__init__.py with this line:

__import__('pkg_resources').declare_namespace(__name__)

in it (and nothing else).

So, for my example, I had:

client-project/src/org/__init__.py
client-project/src/org/me/__init__.py
server-project/src/org/__init__.py
server-project/src/org/me/__init__.py

...all with the special namespace declaration line above.

Note that the lowest level folders in the package:

client-project/src/org/me/client
server-project/src/org/me/api
server-project/src/org/me/<etc>

...all have __init__.py files with actual module code, and therefore
do NOT have the namespace declaration line.

To expose the server code (org.me.api, org.me.dao, etc) I have a
setup.py in the server-project/src folder with:

from setuptools import setup
setup(name='myserver',
version='1.0',
namespace_packages = ['org','org.me'],
packages=['org.me.api','org.me.dao','org.me.entity'],
)

A similar setup.py can be created for the client library too. Notice
that the setup has every level (except the last) in the
namespace_packages list argument. This is how it walks down the tree
and builds the namespace properly.

With this setup file I can make an .egg or .zip distribution using:

  cd server-project/src
  python setup.py bdist

  or

  python setup.py bdist_egg

For my dev environment in eclipse I also wanted the convenience of
editing server code AND have the latest code on the path for my client
project (without rebuilding a dist). To do this I just:

  cd server-project/src
  python setup.py develop

...which puts a symlink (even does it properly in Windows) in my
python/lib/site-packages folder. Now in my client code I can do a
regular import, even though the code lives in another project, and
though portions of the code base are at different PYTHONPATHs:

  from org.me.entity import MyEntity # from server-project/src
  from org.me.api import MyAPI # from server-project/src
  from org.me.client import MyClient # from client-project/src

When my code is complete, the myserver-1.0-py2.6.egg and myclient-1.0-
py2.6.egg can be included in other python modules by loading compiled
source from inside the egg with:

  from pkg_resources import require
  require("myserver>=1.0")
  require("myclient>=1.0")

and then:

  from org.me.entity import MyEntity # from compiled code in
myserver-1.0-py2.6.egg
  from org.me.api import MyAPI # from compiled code in myserver-1.0-
py2.6.egg
  from org.me.client import MyClient # from compiled code in
myclient-1.0-py2.6.egg


Again, it might seem like a headache to some python developers, but it
replicates fairly well the java way of keeping code organized, but
"merging" it into a virtual namespace (encapsulated in an egg archive)
at run-time.

Hope that helps other java developers in packaging python code.

Stuart



More information about the Python-list mailing list