aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xEasyInstall.txt96
-rwxr-xr-xapi_tests.txt10
-rw-r--r--pkg_resources.py61
-rwxr-xr-xpkg_resources.txt11
-rwxr-xr-xsetup.py2
-rwxr-xr-xsite.py408
-rwxr-xr-xvirtual-python.py123
7 files changed, 683 insertions, 28 deletions
diff --git a/EasyInstall.txt b/EasyInstall.txt
index 7866ed2d..6fcbcd16 100755
--- a/EasyInstall.txt
+++ b/EasyInstall.txt
@@ -25,6 +25,8 @@ Using "Easy Install"
====================
+.. _installation instructions:
+
Installing "Easy Install"
-------------------------
@@ -718,12 +720,46 @@ configuration file will work correctly no matter what Python version you use,
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.
+
+
+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.)
-You will need to know your Python version's ``sys.prefix`` and
+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 @@ is on a different filesystem), you should use ``copy -p`` instead of ``ln``.
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 @@ Known Issues
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
diff --git a/api_tests.txt b/api_tests.txt
index ae5392ba..25f3193f 100755
--- a/api_tests.txt
+++ b/api_tests.txt
@@ -182,12 +182,12 @@ once)::
['...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 @@ again for new distributions added thereafter::
>>> 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([])
diff --git a/pkg_resources.py b/pkg_resources.py
index f946fc4e..6717c2ad 100644
--- a/pkg_resources.py
+++ b/pkg_resources.py
@@ -356,7 +356,7 @@ class WorkingSet(object):
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 @@ class WorkingSet(object):
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 @@ class WorkingSet(object):
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 @@ class Distribution(object):
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 @@ class Distribution(object):
"""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 @@ iter_entry_points = working_set.iter_entry_points
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
diff --git a/pkg_resources.txt b/pkg_resources.txt
index 62b57dc5..d8198f5f 100755
--- a/pkg_resources.txt
+++ b/pkg_resources.txt
@@ -1488,6 +1488,17 @@ File/Path Utilities
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.
diff --git a/setup.py b/setup.py
index eb826fa5..4a2d4c71 100755
--- a/setup.py
+++ b/setup.py
@@ -37,7 +37,7 @@ setup(
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 = {
diff --git a/site.py b/site.py
new file mode 100755
index 00000000..70ade781
--- /dev/null
+++ b/site.py
@@ -0,0 +1,408 @@
+"""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()
diff --git a/virtual-python.py b/virtual-python.py
new file mode 100755
index 00000000..8624f37d
--- /dev/null
+++ b/virtual-python.py
@@ -0,0 +1,123 @@
+"""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()
+