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

Guido van Rossum guido@python.org
Mon, 16 Dec 2002 11:54:27 -0500


> At 10:47 AM 12/16/02 -0500, Guido van Rossum wrote:
> 
> >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__)
> 
> How would that work for say, 'zope.app'?

Good point.  Back to the drawing board; I'll have to turn dots in the
name into os.sep.

> >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
> 
> The 'isdir()' part isn't going to work on zipfiles...  unless os.path is 
> going to have zipfile support in 2.3.  :)

I tried putting Zope3 in a zipfile, and it's hopeless; lots and lots
of code expects to find data files (at least page templates and zcml
files; probably also style sheets and other stuff that I don't even
know about) by taking a module's __file__, stripping the filename to
get a directory, and concatenating the directory with the name of a
known data file.  Plus there's the issue of extension modules.

So I think the isdir() not working for zip files can be considered a
feature. :-)

BTW, here's a more recent draft, incorporating a search for .pth
files and with a different place for the isdir():

## pkgutil.py #################################################################
"""Utilities to support packages."""

import os
import sys

def extend_path(path, name):
    """Extend a package's path.

    Intended use is to place the following code in a package's __init__.py:

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

    This will add to the package's __path__ all subdirectories of
    directories on sys.path named after the package.  This is useful
    if one wants to distribute different parts of a single logical
    package as multiple directories.
    """
    path = path[:]
    for dir in sys.path:
        if isinstance(dir, (str, unicode)) and os.path.isdir(dir):
            subdir = os.path.join(dir, name)
            if subdir not in path and os.path.isdir(subdir):
                path.append(subdir)
            pthfile = os.path.join(dir, name + os.extsep + "pth")
            if os.path.isfile(pthfile):
                try:
                    f = open(pthfile)
                except IOError, msg:
                    sys.stderr.write("Can't open %s: %s\n" %
                                     (pthfile, msg))
                else:
                    for line in f:
                        line = line.strip()
                        if not line or line.startswith('#'):
                            continue
                        path.append(line) # Don't check for existence!
                    f.close()
    return path
###############################################################################

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