[Distutils] patches: ez_setup.py: don't import setuptools into your current address space in order to learn its version number

zooko zooko at zooko.com
Sat Sep 29 00:43:36 CEST 2007


On Sep 27, 2007, at 10:51 AM, Phillip J. Eby wrote:

> It won't work correctly.  First, pkg_resources is part of  
> setuptools, so if you install a new version of setuptools, you have  
> to reload() it too.
>
> Second, it's not *safe* to reload it, if it or setuptools were  
> already imported at the time the function is called.  That's  
> because easy_install runs the setup.py of a package it's building  
> from source.  So if you use easy_install to install a package that  
> needs a newer version, reloading pkg_resources or setuptools (and  
> note that setuptools is a package with lots of submodules!) will  
> break the host easy_install process.

Okay.  Attached is a patch that doesn't import pkg_resources and  
doesn't reload anything.  I haven't yet tested it -- I am submitting  
it only to inform the discussion and get any early feedback from you  
on whether the very idea is sound.

Regards,

Zooko

diff -rN -u old-up/setuptools-0.6c7/ez_setup.py new-up/ 
setuptools-0.6c7/ez_setup.py
--- old-up/setuptools-0.6c7/ez_setup.py	2007-09-28 16:41:24.000000000  
-0600
+++ new-up/setuptools-0.6c7/ez_setup.py	2007-09-28 16:41:25.000000000  
-0600
@@ -1,4 +1,4 @@
-#!python
+#!/usr/bin/env python
"""Bootstrap setuptools installation
If you want to use setuptools in your package's setup.py, just  
include this
@@ -13,7 +13,7 @@
This file can also be run as a script to install or upgrade setuptools.
"""
-import sys
+import os, re, subprocess, sys
DEFAULT_VERSION = "0.6c7"
DEFAULT_URL     = "http://pypi.python.org/packages/%s/s/setuptools/"  
% sys.version[:3]
@@ -44,8 +44,6 @@
      'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53',
}
-import sys, os
-
def _validate_md5(egg_name, data):
      if egg_name in md5_data:
          from md5 import md5
@@ -58,6 +56,42 @@
              sys.exit(2)
      return data
+# The following code to parse versions is copied from  
pkg_resources.py so that
+# we can parse versions without importing that module.
+component_re = re.compile(r'(\d+ | [a-z]+ | \.| -)', re.VERBOSE)
+replace = {'pre':'c',  
'preview':'c','-':'final-','rc':'c','dev':'@'}.get
+
+def _parse_version_parts(s):
+    for part in component_re.split(s):
+        part = replace(part,part)
+        if not part or part=='.':
+            continue
+        if part[:1] in '0123456789':
+            yield part.zfill(8)    # pad for numeric comparison
+        else:
+            yield '*'+part
+
+    yield '*final'  # ensure that alpha/beta/candidate are before final
+
+def parse_version(s):
+    parts = []
+    for part in _parse_version_parts(s.lower()):
+        if part.startswith('*'):
+            if part<'*final':   # remove '-' before a prerelease tag
+                while parts and parts[-1]=='*final-': parts.pop()
+            # remove trailing zeros from each series of numeric parts
+            while parts and parts[-1]=='00000000':
+                parts.pop()
+        parts.append(part)
+    return tuple(parts)
+
+def setuptools_is_new_enough(required_version):
+    """Return True if setuptools is already installed and has a version
+    number >= required_version."""
+    sub = subprocess.Popen([sys.executable, "-c", "import  
setuptools;print setuptools.__version__"], stdout=subprocess.PIPE)
+    verstr = sub.stdout.read().strip()
+    ver = parse_version(verstr)
+    return ver and ver >= parse_version(required_version)
def use_setuptools(
      version=DEFAULT_VERSION, download_base=DEFAULT_URL,  
to_dir=os.curdir,
@@ -74,32 +108,11 @@
      this routine will print a message to ``sys.stderr`` and raise  
SystemExit in
      an attempt to abort the calling script.
      """
-    try:
-        import setuptools
-        if setuptools.__version__ == '0.0.1':
-            print >>sys.stderr, (
-            "You have an obsolete version of setuptools installed.   
Please\n"
-            "remove it from your system entirely before rerunning  
this script."
-            )
-            sys.exit(2)
-    except ImportError:
+    if not setuptools_is_new_enough(version):
          egg = download_setuptools(version, download_base, to_dir,  
download_delay)
          sys.path.insert(0, egg)
          import setuptools; setuptools.bootstrap_install_from = egg
-    import pkg_resources
-    try:
-        pkg_resources.require("setuptools>="+version)
-
-    except pkg_resources.VersionConflict, e:
-        # XXX could we install in a subprocess here?
-        print >>sys.stderr, (
-            "The required version of setuptools (>=%s) is not  
available, and\n"
-            "can't be installed while this script is running. Please  
install\n"
-            " a more recent version first.\n\n(Currently using %r)"
-        ) % (version, e.args[0])
-        sys.exit(2)
-
def download_setuptools(
      version=DEFAULT_VERSION, download_base=DEFAULT_URL,  
to_dir=os.curdir,
      delay = 15
@@ -150,9 +163,14 @@
def main(argv, version=DEFAULT_VERSION):
      """Install or upgrade setuptools and EasyInstall"""
-    try:
-        import setuptools
-    except ImportError:
+    if setuptools_is_new_enough(version):
+        if argv:
+            from setuptools.command.easy_install import main
+            main(argv)
+        else:
+            print "Setuptools version",version,"or greater has been  
installed."
+            print '(Run "ez_setup.py -U setuptools" to reinstall or  
upgrade.)'
+    else:
          egg = None
          try:
              egg = download_setuptools(version, delay=0)
@@ -162,31 +180,6 @@
          finally:
              if egg and os.path.exists(egg):
                  os.unlink(egg)
-    else:
-        if setuptools.__version__ == '0.0.1':
-            # tell the user to uninstall obsolete version
-            use_setuptools(version)
-
-    req = "setuptools>="+version
-    import pkg_resources
-    try:
-        pkg_resources.require(req)
-    except pkg_resources.VersionConflict:
-        try:
-            from setuptools.command.easy_install import main
-        except ImportError:
-            from easy_install import main
-        main(list(argv)+[download_setuptools(delay=0)])
-        sys.exit(0) # try to force an exit
-    else:
-        if argv:
-            from setuptools.command.easy_install import main
-            main(argv)
-        else:
-            print "Setuptools version",version,"or greater has been  
installed."
-            print '(Run "ez_setup.py -U setuptools" to reinstall or  
upgrade.)'
-
-
def update_md5(filenames):
      """Update our built-in md5 registry"""

-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: ez_setup-subp.patch.txt
Url: http://mail.python.org/pipermail/distutils-sig/attachments/20070928/6555aa54/attachment.txt 


More information about the Distutils-SIG mailing list