[Python-checkins] python/nondist/sandbox/setuptools site.py, NONE, 1.1 virtual-python.py, NONE, 1.1 EasyInstall.txt, 1.64, 1.65 api_tests.txt, 1.6, 1.7 pkg_resources.py, 1.73, 1.74 pkg_resources.txt, 1.16, 1.17 setup.py, 1.44, 1.45
pje@users.sourceforge.net
pje at users.sourceforge.net
Mon Oct 17 04:26:44 CEST 2005
Update of /cvsroot/python/python/nondist/sandbox/setuptools
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv16625
Modified Files:
EasyInstall.txt api_tests.txt pkg_resources.py
pkg_resources.txt setup.py
Added Files:
site.py virtual-python.py
Log Message:
Significantly enhanced support and docs for "non-root" installation,
including both "virtual" and PYTHONPATH-based installs. The activation
precedence of distributions has also changed so that PYTHONPATH-based
non-root installs can include eggs that override system-defined packages
(whether managed or unmanaged). This version should eliminate most
common installation complaints from non-root Python users.
Note: this version includes a hacked 'site.py' to support processing
.pth files in directories that come *before* site-packages on sys.path.
However, because of its placement, it should only come into play when
a user puts the setuptools .egg file *directly* on PYTHONPATH, so it
doesn't affect "virtual" or "root" installations. It's strictly to
provide support for luddites who refuse to give up their
existing non-root PYTHONPATH setup unless you pry it from their cold,
dead hands. :)
--- NEW FILE: site.py ---
"""Append module search paths for third-party packages to sys.path.
****************************************************************
* This module is automatically imported during initialization, *
* if you add the setuptools egg to PYTHONPATH (to support the *
* simple non-root installation mode) *
****************************************************************
In earlier versions of Python (up to 1.5a3), scripts or modules that
needed to use site-specific modules would place ``import site''
somewhere near the top of their code. Because of the automatic
import, this is no longer necessary (but code that does it still
works).
This will append site-specific paths to the module search path. On
Unix, it starts with sys.prefix and sys.exec_prefix (if different) and
appends lib/python<version>/site-packages as well as lib/site-python.
On other platforms (mainly Mac and Windows), it uses just sys.prefix
(and sys.exec_prefix, if different, but this is unlikely). The
resulting directories, if they exist, are appended to sys.path, and
also inspected for path configuration files.
A path configuration file is a file whose name has the form
<package>.pth; its contents are additional directories (one per line)
to be added to sys.path. Non-existing directories (or
non-directories) are never added to sys.path; no directory is added to
sys.path more than once. Blank lines and lines beginning with
'#' are skipped. Lines starting with 'import' are executed.
For example, suppose sys.prefix and sys.exec_prefix are set to
/usr/local and there is a directory /usr/local/lib/python1.5/site-packages
with three subdirectories, foo, bar and spam, and two path
configuration files, foo.pth and bar.pth. Assume foo.pth contains the
following:
# foo package configuration
foo
bar
bletch
and bar.pth contains:
# bar package configuration
bar
Then the following directories are added to sys.path, in this order:
/usr/local/lib/python1.5/site-packages/bar
/usr/local/lib/python1.5/site-packages/foo
Note that bletch is omitted because it doesn't exist; bar precedes foo
because bar.pth comes alphabetically before foo.pth; and spam is
omitted because it is not mentioned in either path configuration file.
After these path manipulations, an attempt is made to import a module
named sitecustomize, which can perform arbitrary additional
site-specific customizations. If this import fails with an
ImportError exception, it is silently ignored.
"""
import sys
import os
import __builtin__
def makepath(*paths):
dir = os.path.abspath(os.path.join(*paths))
return dir, os.path.normcase(dir)
def abs__file__():
"""Set all module' __file__ attribute to an absolute path"""
for m in sys.modules.values():
try:
m.__file__ = os.path.abspath(m.__file__)
except AttributeError:
continue
def removeduppaths():
""" Remove duplicate entries from sys.path along with making them
absolute"""
# This ensures that the initial path provided by the interpreter contains
# only absolute pathnames, even if we're running from the build directory.
L = []
known_paths = {}
for dir in sys.path:
# Filter out duplicate paths (on case-insensitive file systems also
# if they only differ in case); turn relative paths into absolute
# paths.
dir, dircase = makepath(dir)
if not dircase in known_paths:
L.append(dir)
known_paths[dircase] = 1
sys.path[:] = L
return known_paths
# XXX This should not be part of site.py, since it is needed even when
# using the -S option for Python. See http://www.python.org/sf/586680
def addbuilddir():
"""Append ./build/lib.<platform> in case we're running in the build dir
(especially for Guido :-)"""
from distutils.util import get_platform
s = "build/lib.%s-%.3s" % (get_platform(), sys.version)
s = os.path.join(os.path.dirname(sys.path[-1]), s)
sys.path.append(s)
def _init_pathinfo():
"""Return a set containing all existing directory entries from sys.path"""
d = {}
for dir in sys.path:
try:
if os.path.isdir(dir):
dir, dircase = makepath(dir)
d[dircase] = 1
except TypeError:
continue
return d
def addpackage(sitedir, name, known_paths):
"""Add a new path to known_paths by combining sitedir and 'name' or execute
sitedir if it starts with 'import'"""
if known_paths is None:
known_paths = _init_pathinfo()
reset = 1
else:
reset = 0
fullname = os.path.join(sitedir, name)
try:
f = open(fullname, "rU")
except IOError:
return
try:
for line in f:
if line.startswith("#"):
continue
if line.startswith("import"):
exec line
continue
line = line.rstrip()
dir, dircase = makepath(sitedir, line)
if not dircase in known_paths and os.path.exists(dir):
sys.path.append(dir)
known_paths[dircase] = 1
finally:
f.close()
if reset:
known_paths = None
return known_paths
def addsitedir(sitedir, known_paths=None):
"""Add 'sitedir' argument to sys.path if missing and handle .pth files in
'sitedir'"""
if known_paths is None:
known_paths = _init_pathinfo()
reset = 1
else:
reset = 0
sitedir, sitedircase = makepath(sitedir)
if not sitedircase in known_paths:
sys.path.append(sitedir) # Add path component
try:
names = os.listdir(sitedir)
except os.error:
return
names.sort()
for name in names:
if name.endswith(os.extsep + "pth"):
addpackage(sitedir, name, known_paths)
if reset:
known_paths = None
return known_paths
def addsitepackages(known_paths):
"""Add site-packages (and possibly site-python) to sys.path"""
prefixes = [sys.prefix]
if sys.exec_prefix != sys.prefix:
prefixes.append(sys.exec_prefix)
for prefix in prefixes:
if prefix:
if sys.platform in ('os2emx', 'riscos'):
sitedirs = [os.path.join(prefix, "Lib", "site-packages")]
elif os.sep == '/':
sitedirs = [os.path.join(prefix,
"lib",
"python" + sys.version[:3],
"site-packages"),
os.path.join(prefix, "lib", "site-python")]
else:
sitedirs = [prefix, os.path.join(prefix, "lib", "site-packages")]
if sys.platform == 'darwin':
# for framework builds *only* we add the standard Apple
# locations. Currently only per-user, but /Library and
# /Network/Library could be added too
if 'Python.framework' in prefix:
home = os.environ.get('HOME')
if home:
sitedirs.append(
os.path.join(home,
'Library',
'Python',
sys.version[:3],
'site-packages'))
for sitedir in sys.path:
if sitedir and os.path.isdir(sitedir):
addsitedir(sitedir, known_paths)
return None
def setBEGINLIBPATH():
"""The OS/2 EMX port has optional extension modules that do double duty
as DLLs (and must use the .DLL file extension) for other extensions.
The library search path needs to be amended so these will be found
during module import. Use BEGINLIBPATH so that these are at the start
of the library search path.
"""
dllpath = os.path.join(sys.prefix, "Lib", "lib-dynload")
libpath = os.environ['BEGINLIBPATH'].split(';')
if libpath[-1]:
libpath.append(dllpath)
else:
libpath[-1] = dllpath
os.environ['BEGINLIBPATH'] = ';'.join(libpath)
def setquit():
"""Define new built-ins 'quit' and 'exit'.
These are simply strings that display a hint on how to exit.
"""
if os.sep == ':':
exit = 'Use Cmd-Q to quit.'
elif os.sep == '\\':
exit = 'Use Ctrl-Z plus Return to exit.'
else:
exit = 'Use Ctrl-D (i.e. EOF) to exit.'
__builtin__.quit = __builtin__.exit = exit
class _Printer(object):
"""interactive prompt objects for printing the license text, a list of
contributors and the copyright notice."""
MAXLINES = 23
def __init__(self, name, data, files=(), dirs=()):
self.__name = name
self.__data = data
self.__files = files
self.__dirs = dirs
self.__lines = None
def __setup(self):
if self.__lines:
return
data = None
for dir in self.__dirs:
for filename in self.__files:
filename = os.path.join(dir, filename)
try:
fp = file(filename, "rU")
data = fp.read()
fp.close()
break
except IOError:
pass
if data:
break
if not data:
data = self.__data
self.__lines = data.split('\n')
self.__linecnt = len(self.__lines)
def __repr__(self):
self.__setup()
if len(self.__lines) <= self.MAXLINES:
return "\n".join(self.__lines)
else:
return "Type %s() to see the full %s text" % ((self.__name,)*2)
def __call__(self):
self.__setup()
prompt = 'Hit Return for more, or q (and Return) to quit: '
lineno = 0
while 1:
try:
for i in range(lineno, lineno + self.MAXLINES):
print self.__lines[i]
except IndexError:
break
else:
lineno += self.MAXLINES
key = None
while key is None:
key = raw_input(prompt)
if key not in ('', 'q'):
key = None
if key == 'q':
break
def setcopyright():
"""Set 'copyright' and 'credits' in __builtin__"""
__builtin__.copyright = _Printer("copyright", sys.copyright)
if sys.platform[:4] == 'java':
__builtin__.credits = _Printer(
"credits",
"Jython is maintained by the Jython developers (www.jython.org).")
else:
__builtin__.credits = _Printer("credits", """\
Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands
for supporting Python development. See www.python.org for more information.""")
here = os.path.dirname(os.__file__)
__builtin__.license = _Printer(
"license", "See http://www.python.org/%.3s/license.html" % sys.version,
["LICENSE.txt", "LICENSE"],
[os.path.join(here, os.pardir), here, os.curdir])
class _Helper(object):
"""Define the built-in 'help'.
This is a wrapper around pydoc.help (with a twist).
"""
def __repr__(self):
return "Type help() for interactive help, " \
"or help(object) for help about object."
def __call__(self, *args, **kwds):
import pydoc
return pydoc.help(*args, **kwds)
def sethelper():
__builtin__.help = _Helper()
def aliasmbcs():
"""On Windows, some default encodings are not provided by Python,
while they are always available as "mbcs" in each locale. Make
them usable by aliasing to "mbcs" in such a case."""
if sys.platform == 'win32':
import locale, codecs
enc = locale.getdefaultlocale()[1]
if enc.startswith('cp'): # "cp***" ?
try:
codecs.lookup(enc)
except LookupError:
import encodings
encodings._cache[enc] = encodings._unknown
encodings.aliases.aliases[enc] = 'mbcs'
def setencoding():
"""Set the string encoding used by the Unicode implementation. The
default is 'ascii', but if you're willing to experiment, you can
change this."""
encoding = "ascii" # Default value set by _PyUnicode_Init()
if 0:
# Enable to support locale aware default string encodings.
import locale
loc = locale.getdefaultlocale()
if loc[1]:
encoding = loc[1]
if 0:
# Enable to switch off string to Unicode coercion and implicit
# Unicode to string conversion.
encoding = "undefined"
if encoding != "ascii":
# On Non-Unicode builds this will raise an AttributeError...
sys.setdefaultencoding(encoding) # Needs Python Unicode build !
def execsitecustomize():
"""Run custom site specific code, if available."""
try:
import sitecustomize
except ImportError:
pass
def main():
abs__file__()
paths_in_sys = removeduppaths()
if (os.name == "posix" and sys.path and
os.path.basename(sys.path[-1]) == "Modules"):
addbuilddir()
paths_in_sys = addsitepackages(paths_in_sys)
if sys.platform == 'os2emx':
setBEGINLIBPATH()
setquit()
setcopyright()
sethelper()
aliasmbcs()
setencoding()
execsitecustomize()
# Remove sys.setdefaultencoding() so that users cannot change the
# encoding after initialization. The test for presence is needed when
# this module is run as a script, because this code is executed twice.
if hasattr(sys, "setdefaultencoding"):
del sys.setdefaultencoding
main()
def _test():
print "sys.path = ["
for dir in sys.path:
print " %r," % (dir,)
print "]"
if __name__ == '__main__':
_test()
--- NEW FILE: virtual-python.py ---
"""Create a "virtual" Python installation
Based on a script created by Ian Bicking."""
import sys, os, optparse, shutil
join = os.path.join
py_version = 'python%s.%s' % (sys.version_info[0], sys.version_info[1])
def mkdir(path):
if not os.path.exists(path):
print 'Creating %s' % path
os.makedirs(path)
else:
if verbose:
print 'Directory %s already exists'
def symlink(src, dest):
if not os.path.exists(dest):
if verbose:
print 'Creating symlink %s' % dest
os.symlink(src, dest)
else:
print 'Symlink %s already exists' % dest
def rmtree(dir):
if os.path.exists(dir):
print 'Deleting tree %s' % dir
shutil.rmtree(dir)
else:
if verbose:
print 'Do not need to delete %s; already gone' % dir
def make_exe(fn):
if os.name == 'posix':
oldmode = os.stat(fn).st_mode & 07777
newmode = (oldmode | 0555) & 07777
os.chmod(fn, newmode)
if verbose:
print 'Changed mode of %s to %s' % (fn, oct(newmode))
def main():
if os.name != 'posix':
print "This script only works on Unix-like platforms, sorry."
return
parser = optparse.OptionParser()
parser.add_option('-v', '--verbose', action='count', dest='verbose',
default=0, help="Increase verbosity")
parser.add_option('--prefix', dest="prefix", default='~',
help="The base directory to install to (default ~)")
parser.add_option('--clear', dest='clear', action='store_true',
help="Clear out the non-root install and start from scratch")
parser.add_option('--no-site-packages', dest='no_site_packages',
action='store_true',
help="Don't copy the contents of the global site-packages dir to the "
"non-root site-packages")
options, args = parser.parse_args()
global verbose
home_dir = os.path.expanduser(options.prefix)
lib_dir = join(home_dir, 'lib', py_version)
inc_dir = join(home_dir, 'include', py_version)
bin_dir = join(home_dir, 'bin')
if sys.executable.startswith(bin_dir):
print 'Please use the *system* python to run this script'
return
verbose = options.verbose
assert not args, "No arguments allowed"
if options.clear:
rmtree(lib_dir)
rmtree(inc_dir)
print 'Not deleting', bin_dir
prefix = sys.prefix
mkdir(lib_dir)
stdlib_dir = join(prefix, 'lib', py_version)
for fn in os.listdir(stdlib_dir):
if fn != 'site-packages':
symlink(join(stdlib_dir, fn), join(lib_dir, fn))
mkdir(join(lib_dir, 'site-packages'))
if not options.no_site_packages:
for fn in os.listdir(join(stdlib_dir, 'site-packages')):
symlink(join(stdlib_dir, 'site-packages', fn),
join(lib_dir, 'site-packages', fn))
mkdir(inc_dir)
stdinc_dir = join(prefix, 'include', py_version)
for fn in os.listdir(stdinc_dir):
symlink(join(stdinc_dir, fn), join(inc_dir, fn))
if sys.exec_prefix != sys.prefix:
exec_dir = join(sys.exec_prefix, 'lib', py_version)
for fn in os.listdir(exec_dir):
symlink(join(exec_dir, fn), join(lib_dir, fn))
mkdir(bin_dir)
print 'Copying %s to %s' % (sys.executable, bin_dir)
py_executable = join(bin_dir, 'python')
if sys.executable != py_executable:
shutil.copyfile(sys.executable, py_executable)
make_exe(py_executable)
pydistutils = os.path.expanduser('~/.pydistutils.cfg')
if os.path.exists(pydistutils):
print 'Please make sure you remove any previous custom paths from'
print "your", pydistutils, "file."
print "You're now ready to download ez_setup.py, and run"
print py_executable, "ez_setup.py"
if __name__ == '__main__':
main()
Index: EasyInstall.txt
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/EasyInstall.txt,v
retrieving revision 1.64
retrieving revision 1.65
diff -u -d -r1.64 -r1.65
--- EasyInstall.txt 16 Oct 2005 20:45:28 -0000 1.64
+++ EasyInstall.txt 17 Oct 2005 02:26:39 -0000 1.65
@@ -25,6 +25,8 @@
====================
+.. _installation instructions:
+
Installing "Easy Install"
-------------------------
@@ -718,12 +720,46 @@
now or in the future.)
If you are on a Linux, BSD, Cygwin, or other similar Unix-like operating
-system, you should create a ``~/lib/python2.x/site-packages`` directory
-instead. (Note: Ian Bicking has created a script that can automate most of the
-process that follows; see http://svn.colorstudy.com/home/ianb/non_root_python.py
-for details.)
+system, you have a couple of different options. You can create a "virtual"
+Python installation, which uses its own library directories and some symlinks
+to the site-wide Python. Or, you can use a "traditional" ``PYTHONPATH``-based
+installation, which isn't as flexible, but which you may find more familiar,
+especially if you already have a custom ``PYTHONPATH`` set up.
-You will need to know your Python version's ``sys.prefix`` and
+
+Creating a "Virtual" Python
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In the simplest case, your virtual Python installation will live under the
+``~/lib/python2.x``, ``~/include/python2.x``, and ``~/bin`` directories. Just
+download `virtual-python.py`_ and run it using the site-wide Python. If you
+want to customize the location, you can use the ``--prefix`` option to specify
+an installation base directory in place of ``~``. (Use ``--help`` to get the
+complete list of options.)
+
+.. _virtual-python.py: http://peak.telecommunity.com/dist/virtual-python.py
+
+When you're done, you'll have a ``~/bin/python`` executable that's linked to
+the local Python installation and inherits all its current libraries, but which
+allows you to add as many new libraries as you want. Simply use this new
+Python in place of your system-defined one, and you can modify it as you like
+without breaking anything that relies on the system Python. You'll also still
+need to follow the standard `installation instructions`_ to install setuptools
+and EasyInstall, using your new ``~/bin/python`` executable in place of the
+system Python.
+
+Note that if you were previously setting a ``PYTHONPATH`` and/or had other
+special configuration options in your ``~/.pydistutils.cfg``, you may need to
+remove these settings *before* running ``virtual-python.py``. You should
+also make sure that the ``~/bin`` directory (or whatever directory you choose)
+is on your ``PATH``, because that is where EasyInstall will install new Python
+scripts.
+
+If you'd prefer to do the installation steps by hand, or just want to know what
+the script will do, here are the steps. (If you don't care how it works, you
+can just skip the rest of this section.)
+
+First, you will need to know your Python version's ``sys.prefix`` and
``sys.exec_prefix``, which you can find out by running::
python -c "import sys; print sys.prefix; print sys.exec_prefix"
@@ -761,13 +797,43 @@
Do NOT use a symlink! The Python binary must be copied or hardlinked,
otherwise it will use the system ``site-packages`` directory and not yours.
-Note that if you were previously setting a ``PYTHONPATH`` and/or had other
-special configuration options in your ``~/.pydistutils.cfg``, you may need to
-remove these settings and relocate any older installed modules to your
-new ``~/lib/python2.x/site-packages`` directory. Also note that you must now
-make sure to use the ``~/bin/python`` executable instead of the system Python,
-and ideally you should put the ``~/bin`` directory first on your ``PATH`` as
-well, because that is where EasyInstall will install new Python scripts.
+You can now proceed with the standard `installation instructions`_.
+
+
+"Traditional" ``PYTHONPATH``-based Installation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This installation method is not as robust or as flexible as `creating a
+"virtual" python`_ installation, as it uses various tricks to fool Python into
+processing ``.pth`` files where it normally wouldn't. We suggest you try the
+virtual Python approach first, as we are providing this method mainly for
+people who just can't get past their unshakeable belief that creating a virtual
+python is somehow "Not Right", or that putting stuff on ``PYTHONPATH`` "Should
+Just Work, Darnit." So, if you're not one of those people, you don't
+need these instructions. :-)
+
+Assuming that you want to install packages in a directory called ``~/py-lib``,
+and scripts in ``~/bin``, here's what you need to do:
+
+First, edit ``~/.pydistutils.cfg`` to include these settings::
+
+ [install]
+ install_lib = ~/py-lib
+ install_scripts = ~/bin
+
+ [easy_install]
+ site_dirs = ~/py_lib
+
+Be sure to do this *before* you try to run the ``ez_setup.py`` installation
+script. Then, follow the standard `installation instructions`_, but take
+careful note of the full pathname of the ``.egg`` file that gets installed, so
+that you can add it to your ``PYTHONPATH``, along with ``~/py_lib``.
+
+You *must* add the setuptools egg file to your ``PYTHONPATH`` manually, or it
+will not work, and neither will any other packages you install with
+EasyInstall. You will not, however, have to manually add any other
+packages to the ``PYTHONPATH``; EasyInstall will take care of them for you, as
+long as the setuptools egg is explicitly listed in ``PYTHONPATH``.
Release Notes/Change History
@@ -778,6 +844,12 @@
time out or be missing a file.
0.6a6
+ * Added support for "traditional" PYTHONPATH-based non-root installation, and
+ also the convenient ``virtual-python.py`` script, based on a contribution
+ by Ian Bicking. The setuptools egg now contains a hacked ``site`` module
+ that makes the PYTHONPATH-based approach work with .pth files, so that you
+ can get the full EasyInstall feature set on such installations.
+
* Added ``--no-deps`` option.
* Improved Windows ``.exe`` script wrappers so that the script can have the
Index: api_tests.txt
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/api_tests.txt,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- api_tests.txt 13 Aug 2005 23:04:08 -0000 1.6
+++ api_tests.txt 17 Oct 2005 02:26:39 -0000 1.7
@@ -182,12 +182,12 @@
['...example.com...', '...pkg_resources...', '...pkg_resources...']
And you can specify the path entry a distribution was found under, using the
-optional second parameter to ``add()``
+optional second parameter to ``add()``::
+ >>> ws = WorkingSet([])
>>> ws.add(dist,"foo")
- >>> ws.add(dist,"bar")
>>> ws.entries
- ['http://example.com/something', ..., 'foo', 'bar']
+ ['foo']
But even if a distribution is found under multiple path entries, it still only
shows up once when iterating the working set:
@@ -222,14 +222,14 @@
>>> def added(dist): print "Added", dist
>>> ws.subscribe(added)
Added Bar 0.9
- >>> foo12 = Distribution(project_name="Foo", version="1.2")
+ >>> foo12 = Distribution(project_name="Foo", version="1.2", location="f12")
>>> ws.add(foo12)
Added Foo 1.2
Note, however, that only the first distribution added for a given project name
will trigger a callback, even during the initial ``subscribe()`` callback::
- >>> foo14 = Distribution(project_name="Foo", version="1.4")
+ >>> foo14 = Distribution(project_name="Foo", version="1.4", location="f14")
>>> ws.add(foo14) # no callback, because Foo 1.2 is already active
>>> ws = WorkingSet([])
Index: pkg_resources.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/pkg_resources.py,v
retrieving revision 1.73
retrieving revision 1.74
diff -u -d -r1.73 -r1.74
--- pkg_resources.py 26 Sep 2005 00:35:35 -0000 1.73
+++ pkg_resources.py 17 Oct 2005 02:26:39 -0000 1.74
@@ -356,7 +356,7 @@
self.entry_keys.setdefault(entry, [])
self.entries.append(entry)
for dist in find_distributions(entry, True):
- self.add(dist, entry)
+ self.add(dist, entry, False)
def __contains__(self,dist):
@@ -421,7 +421,7 @@
seen[key]=1
yield self.by_key[key]
- def add(self, dist, entry=None):
+ def add(self, dist, entry=None, insert=True):
"""Add `dist` to working set, associated with `entry`
If `entry` is unspecified, it defaults to the ``.location`` of `dist`.
@@ -432,23 +432,23 @@
doesn't already have a distribution in the set. If it's added, any
callbacks registered with the ``subscribe()`` method will be called.
"""
+ if insert:
+ dist.insert_on(self.entries, entry)
+
if entry is None:
entry = dist.location
-
- if entry not in self.entry_keys:
- self.entries.append(entry)
- self.entry_keys[entry] = []
+ keys = self.entry_keys.setdefault(entry,[])
if dist.key in self.by_key:
return # ignore hidden distros
self.by_key[dist.key] = dist
- keys = self.entry_keys[entry]
if dist.key not in keys:
keys.append(dist.key)
self._added_new(dist)
+
def resolve(self, requirements, env=None, installer=None):
"""List all distributions needed to (recursively) meet `requirements`
@@ -1837,12 +1837,12 @@
def activate(self,path=None):
"""Ensure distribution is importable on `path` (default=sys.path)"""
if path is None: path = sys.path
- if self.location not in path:
- path.append(self.location)
+ self.insert_on(path)
if path is sys.path:
fixup_namespace_packages(self.location)
map(declare_namespace, self._get_metadata('namespace_packages.txt'))
+
def egg_name(self):
"""Return what this distribution's standard .egg filename should be"""
filename = "%s-%s-py%s" % (
@@ -1907,6 +1907,47 @@
"""Return the EntryPoint object for `group`+`name`, or ``None``"""
return self.get_entry_map(group).get(name)
+ def insert_on(self, path, loc = None):
+ """Insert self.location in path before its nearest parent directory"""
+ loc = loc or self.location
+ if not loc: return
+ if path is sys.path:
+ self.check_version_conflict()
+ best, pos = 0, -1
+ for p,item in enumerate(path):
+ if loc.startswith(item) and len(item)>best and loc<>item:
+ best, pos = len(item), p
+ if pos==-1:
+ if loc not in path: path.append(loc)
+ elif loc not in path[:pos+1]:
+ while loc in path: path.remove(loc)
+ path.insert(pos,loc)
+
+
+
+ def check_version_conflict(self):
+ if self.key=='setuptools':
+ return # ignore the inevitable setuptools self-conflicts :(
+
+ nsp = dict.fromkeys(self._get_metadata('namespace_packages.txt'))
+
+ for modname in self._get_metadata('top_level.txt'):
+ if modname not in sys.modules or modname in nsp:
+ continue
+
+ fn = getattr(sys.modules[modname], '__file__', None)
+ if fn and fn.startswith(self.location):
+ continue
+
+ from warnings import warn
+ warn(
+ "Module %s was already imported from %s, but %s is being added"
+ " to sys.path" % (modname, fn, self.location)
+ )
+
+
+
+
@@ -2165,9 +2206,9 @@
add_activation_listener = working_set.subscribe
run_script = working_set.run_script
run_main = run_script # backward compatibility
-
# Activate all distributions already on sys.path, and ensure that
# all distributions added to the working set in the future (e.g. by
# calling ``require()``) will get activated as well.
add_activation_listener(lambda dist: dist.activate())
+working_set.entries=[]; map(working_set.add_entry,sys.path) # match order
Index: pkg_resources.txt
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/pkg_resources.txt,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -d -r1.16 -r1.17
--- pkg_resources.txt 26 Sep 2005 00:35:35 -0000 1.16
+++ pkg_resources.txt 17 Oct 2005 02:26:39 -0000 1.17
@@ -1488,6 +1488,17 @@
Release Notes/Change History
----------------------------
+0.6a6
+ * Activated distributions are now inserted in ``sys.path`` (and the working
+ set) just before the directory that contains them, instead of at the end.
+ This allows e.g. eggs in ``site-packages`` to override unmanged modules in
+ the same location, and allows eggs found earlier on ``sys.path`` to override
+ ones found later.
+
+ * When a distribution is activated, it now checks whether any contained
+ non-namespace modules have already been imported and issues a warning if
+ a conflicting module has already been imported.
+
0.6a4
* Fix a bug in ``WorkingSet.resolve()`` that was introduced in 0.6a3.
Index: setup.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setup.py,v
retrieving revision 1.44
retrieving revision 1.45
diff -u -d -r1.44 -r1.45
--- setup.py 29 Sep 2005 17:05:43 -0000 1.44
+++ setup.py 17 Oct 2005 02:26:39 -0000 1.45
@@ -37,7 +37,7 @@
test_suite = 'setuptools.tests.test_suite',
packages = find_packages(),
package_data = {'setuptools': ['*.exe']},
- py_modules = ['pkg_resources', 'easy_install'],
+ py_modules = ['pkg_resources', 'easy_install', 'site'],
zip_safe = False, # We want 'python -m easy_install' to work, for now :(
entry_points = {
More information about the Python-checkins
mailing list