diff options
author | PJ Eby <distutils-sig@python.org> | 2005-10-17 02:26:39 +0000 |
---|---|---|
committer | PJ Eby <distutils-sig@python.org> | 2005-10-17 02:26:39 +0000 |
commit | 3df2aabcc056e6d001355d4cec780437387ac4fa (patch) | |
tree | e931e6f30fe51eb6ee968a008e9ac4c439249ea8 | |
parent | c23b0fb2bfbd8df35ebee9551458ed00e0f2095c (diff) | |
download | external_python_setuptools-3df2aabcc056e6d001355d4cec780437387ac4fa.tar.gz external_python_setuptools-3df2aabcc056e6d001355d4cec780437387ac4fa.tar.bz2 external_python_setuptools-3df2aabcc056e6d001355d4cec780437387ac4fa.zip |
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. :)
--HG--
branch : setuptools
extra : convert_revision : svn%3A6015fed2-1504-0410-9fe1-9d1591cc4771/sandbox/trunk/setuptools%4041262
-rwxr-xr-x | EasyInstall.txt | 96 | ||||
-rwxr-xr-x | api_tests.txt | 10 | ||||
-rw-r--r-- | pkg_resources.py | 61 | ||||
-rwxr-xr-x | pkg_resources.txt | 11 | ||||
-rwxr-xr-x | setup.py | 2 | ||||
-rwxr-xr-x | site.py | 408 | ||||
-rwxr-xr-x | virtual-python.py | 123 |
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. @@ -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() + |