[Zope3-dev] Zip import and sys.path manipulation (was Re: directory hierarchy proposal)

Guido van Rossum guido@python.org
Mon, 16 Dec 2002 10:47:14 -0500


> (CC'd to python-dev because of possible impact on zipimport
> implementation/API)
> 
> At 08:00 AM 12/16/02 -0500, Jim Fulton wrote:
> >Each zope package __init__ file would have a bit of boilerplate code
> >that would include all zope directories in sys.path:
> >
> >   # Boilerplate code that combines all zope directories in sys.path
> >   import sys, os
> >   __path__ = [os.path.join(p, 'zope') for p in sys.path]
> >
> >Jim
> 
> That should probably read:
> 
> __path__ = [os.path.join(p, 'zope') for p in sys.path if 
> isinstance(p,StringTypes)]
> 
> or else it could break in 2.3 if somebody's putting non-strings on
> sys.path.  I don't remember exactly how the python-dev discussion
> turned out, but I kind of got the impression that it was going to be
> allowable in 2.3.

Correct.  While the standard setup will still have only strings, we'll
support non-strings on sys.path and some users may want to use this.

> Also, I'm pretty sure it will not give the expected/desired results
> in conjunction with zipfile imports.

I think it will, actually; if /path/foo.zip is a zip file on sys.path,
/path/foo.zip/blah references a directory inside that zip file.

> For these and related reasons, I would suggest that a slightly
> different snippet be used instead (the names are lousy, improvements
> welcome):
> 
> from namespace_packages import makeNamespacePath
> __path__ = makeNamespacePath('zope')
> 
> And then make whatever carries "namespace_packages" be something
> that's distributed separately from Zope, preferably part of the
> standard library or distutils (and backported where possible).  If
> we can make it so that the __init__ code never *has* to change, that
> will minimize the likelihood of incompatible __init__.py's floating
> around.  Meanwhile, a module that actually *knows* something about
> what can be on sys.path (and how to interpret it) can do so.

This is not a bad idea: put the logic to add stuff to a package's
__path__ according to a certain policy in the standard library.

(Of course, getting it into Python 2.2 would require another release,
2.2.3 -- which may happen anyway.)

> In order to support something like this, importer objects would need
> to be able to return something that's the moral equivalent of
> "os.path.join" on an existing sys.path entry; either another
> importer object or a string that can be handled by one.  At this
> point, checking for a '.zip' extension at the end of a string isn't
> going to cut it any more.

As I said above, I think it will.

Time's running short (we're close to releasing Python 2.3 alpha 1);
we should decide on a name and a specific policy ASAP.  I propose the
following:

  from pkgutil import extended_path
  __path__ = extended_path(__path__, __name__)

Where pkgutil.py could be something like this:

  import sys.path

  def extended_path(path, name):
      """Extend a package's path.  (XXX more.)"""
      path = path[:]
      for dir in sys.path:
          if isinstance(dir, (str, unicode)):
              dir = os.path.join(dir, name)
              if dir not in path and os.path.isdir(dir):
                  path.append(dir)
      return path

--Guido van Rossum (home page: http://www.python.org/~guido/)