mirror of
https://github.com/python/cpython.git
synced 2024-11-29 12:54:02 +08:00
a4deda0d11
Here's a draft. I have no immediate use for it, but I'd like this to be available for experimentation. I may withdraw it or change it radically up to and including the release of Python 2.3b1.
79 lines
3.0 KiB
Python
79 lines
3.0 KiB
Python
"""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.
|
|
|
|
It also looks for *.pkg files beginning where * matches the name
|
|
argument. This feature is similar to *.pth files (see site.py),
|
|
except that it doesn't special-case lines starting with 'import'.
|
|
A *.pkg file is trusted at face value: apart from checking for
|
|
duplicates, all entries found in a *.pkg file are added to the
|
|
path, regardless of whether they are exist the filesystem. (This
|
|
is a feature.)
|
|
|
|
If the input path is not a list (as is the case for frozen
|
|
packages) it is returned unchanged. The input path is not
|
|
modified; an extended copy is returned. Items are only appended
|
|
to the copy at the end.
|
|
|
|
It is assumed that sys.path is a sequence. Items of sys.path that
|
|
are not (unicode or 8-bit) strings referring to existing
|
|
directories are ignored. Unicode items of sys.path that cause
|
|
errors when used as filenames may cause this function to raise an
|
|
exception (in line with os.path.isdir() behavior).
|
|
"""
|
|
|
|
if not isinstance(path, list):
|
|
# This could happen e.g. when this is called from inside a
|
|
# frozen package. Return the path unchanged in that case.
|
|
return path
|
|
|
|
pname = os.path.join(*name.split('.')) # Reconstitute as relative path
|
|
# Just in case os.extsep != '.'
|
|
sname = os.extsep.join(name.split('.'))
|
|
sname_pkg = sname + os.extsep + "pkg"
|
|
init_py = "__init__" + os.extsep + "py"
|
|
|
|
path = path[:] # Start with a copy of the existing path
|
|
|
|
for dir in sys.path:
|
|
if not isinstance(dir, (str, unicode)) or not os.path.isdir(dir):
|
|
continue
|
|
subdir = os.path.join(dir, pname)
|
|
# XXX This may still add duplicate entries to path on
|
|
# case-insensitive filesystems
|
|
initfile = os.path.join(subdir, init_py)
|
|
if subdir not in path and os.path.isfile(initfile):
|
|
path.append(subdir)
|
|
# XXX Is this the right thing for subpackages like zope.app?
|
|
# It looks for a file named "zope.app.pkg"
|
|
pkgfile = os.path.join(dir, sname_pkg)
|
|
if os.path.isfile(pkgfile):
|
|
try:
|
|
f = open(pkgfile)
|
|
except IOError, msg:
|
|
sys.stderr.write("Can't open %s: %s\n" %
|
|
(pkgfile, msg))
|
|
else:
|
|
for line in f:
|
|
line = line.rstrip('\n')
|
|
if not line or line.startswith('#'):
|
|
continue
|
|
path.append(line) # Don't check for existence!
|
|
f.close()
|
|
|
|
return path
|