[Python-checkins] r75384 - in sandbox/trunk/setuptools: EasyInstall.txt pkg_resources.py pkg_resources.txt setup.py setuptools.egg-info/entry_points.txt setuptools.txt setuptools/command/alias.py setuptools/command/bdist_egg.py setuptools/command/build_ext.py setuptools/command/easy_install.py setuptools/command/egg_info.py setuptools/command/sdist.py setuptools/command/test.py setuptools/depends.py setuptools/dist.py setuptools/package_index.py setuptools/sandbox.py setuptools/tests/api_tests.txt

phillip.eby python-checkins at python.org
Mon Oct 12 21:58:46 CEST 2009


Author: phillip.eby
Date: Mon Oct 12 21:58:46 2009
New Revision: 75384

Log:
Major updates and fixes include:

* Fix for the Python 2.6.3 build_ext API change
* Support for the most recent Sourceforge download link insanity
* Support for SVN 1.6
* Stop crashing on certain types of HTTP error
* Stop re-trying URLs that already failed retrieval once
* Fixes for various dependency management problems such as looping 
  builds, re-downloading packages already present on sys.path (but not 
  in a registered "site" directory), and randomly preferring local -f 
  packages over local installed packages
* Prevent lots of spurious "already imported from another path" warnings 
  (e.g. when pkg_resources is imported late)
* Ensure C libraries (as opposed to extensions) are also built when 
  doing bdist_egg
* Fixed running the "test" command under Python 2.6+

Other changes:
* Misc. documentation fixes
* Improved Jython support
* Fewer warnings under Python 2.6+
* Warn when 'packages' uses paths instead of package names (because it 
  causes other problems, like spurious "already imported" warnings)
* Stop using /usr/bin/sw_vers on Mac OS (replaced w/'platform' module 
  calls)

Note: This is NOT a merge from Distribute; upon review, many of the 
tracker-submitted patches used as a basis for forking were incorrect, 
incomplete, introduced new bugs, or were not addressing the root
causes.  (E.g., one of the changes in this patch fixes three superficially
unrelated issues in the setuptools bug tracker.)  Careful review will be
required if you  want to merge this work back into Distribute.


Modified:
   sandbox/trunk/setuptools/EasyInstall.txt
   sandbox/trunk/setuptools/pkg_resources.py
   sandbox/trunk/setuptools/pkg_resources.txt
   sandbox/trunk/setuptools/setup.py
   sandbox/trunk/setuptools/setuptools.egg-info/entry_points.txt
   sandbox/trunk/setuptools/setuptools.txt
   sandbox/trunk/setuptools/setuptools/command/alias.py
   sandbox/trunk/setuptools/setuptools/command/bdist_egg.py
   sandbox/trunk/setuptools/setuptools/command/build_ext.py
   sandbox/trunk/setuptools/setuptools/command/easy_install.py
   sandbox/trunk/setuptools/setuptools/command/egg_info.py
   sandbox/trunk/setuptools/setuptools/command/sdist.py
   sandbox/trunk/setuptools/setuptools/command/test.py
   sandbox/trunk/setuptools/setuptools/depends.py
   sandbox/trunk/setuptools/setuptools/dist.py
   sandbox/trunk/setuptools/setuptools/package_index.py
   sandbox/trunk/setuptools/setuptools/sandbox.py
   sandbox/trunk/setuptools/setuptools/tests/api_tests.txt

Modified: sandbox/trunk/setuptools/EasyInstall.txt
==============================================================================
--- sandbox/trunk/setuptools/EasyInstall.txt	(original)
+++ sandbox/trunk/setuptools/EasyInstall.txt	Mon Oct 12 21:58:46 2009
@@ -256,7 +256,7 @@
 If you want to delete the currently installed version of a package (or all
 versions of a package), you should first run::
 
-    easy_install -m PackageName
+    easy_install -mxN PackageName
 
 This will ensure that Python doesn't continue to search for a package you're
 planning to remove. After you've done this, you can safely delete the .egg
@@ -427,7 +427,7 @@
 
 
 Password-Protected Sites
-------------------------
+~~~~~~~~~~~~~~~~~~~~~~~~
 
 If a site you want to download from is password-protected using HTTP "Basic"
 authentication, you can specify your credentials in the URL, like so::

Modified: sandbox/trunk/setuptools/pkg_resources.py
==============================================================================
--- sandbox/trunk/setuptools/pkg_resources.py	(original)
+++ sandbox/trunk/setuptools/pkg_resources.py	Mon Oct 12 21:58:46 2009
@@ -13,7 +13,7 @@
 method.
 """
 
-import sys, os, zipimport, time, re, imp, new, pkgutil  # XXX
+import sys, os, zipimport, time, re, imp, pkgutil  # XXX
 
 try:
     frozenset
@@ -39,6 +39,47 @@
 
 
 
+_state_vars = {}
+
+def _declare_state(vartype, **kw):
+    g = globals()
+    for name, val in kw.iteritems():
+        g[name] = val
+        _state_vars[name] = vartype
+
+def __getstate__():
+    state = {}
+    g = globals()
+    for k, v in _state_vars.iteritems():
+        state[k] = g['_sget_'+v](g[k])
+    return state
+
+def __setstate__(state):
+    g = globals()
+    for k, v in state.iteritems():
+        g['_sset_'+_state_vars[k]](k, g[k], v)
+    return state
+
+def _sget_dict(val):
+    return val.copy()
+
+def _sset_dict(key, ob, state):
+    ob.clear()
+    ob.update(state)
+
+def _sget_object(val):
+    return val.__getstate__()
+
+def _sset_object(key, ob, state):
+    ob.__setstate__(state)
+
+_sget_none = _sset_none = lambda *args: None
+
+
+
+
+
+
 def get_supported_platform():
     """Return this platform's maximum compatible version.
 
@@ -166,14 +207,8 @@
 
 def _macosx_vers(_cache=[]):
     if not _cache:
-        info = os.popen('/usr/bin/sw_vers').read().splitlines()
-        for line in info:
-            key, value = line.split(None, 1)
-            if key == 'ProductVersion:':
-                _cache.append(value.strip().split("."))
-                break
-        else:
-            raise ValueError, "What?!"
+        from platform import mac_ver
+        _cache.append(mac_ver()[0].split('.'))
     return _cache[0]
 
 def _macosx_arch(machine):
@@ -203,6 +238,12 @@
 darwinVersionString = re.compile(r"darwin-(\d+)\.(\d+)\.(\d+)-(.*)")
 get_platform = get_build_platform   # XXX backward compat
 
+
+
+
+
+
+
 def compatible_platforms(provided,required):
     """Can code for the `provided` platform run on the `required` platform?
 
@@ -387,7 +428,7 @@
     def add_entry(self, entry):
         """Add a path item to ``.entries``, finding any distributions on it
 
-        ``find_distributions(entry,False)`` is used to find distributions
+        ``find_distributions(entry, True)`` is used to find distributions
         corresponding to the path entry, and they are added.  `entry` is
         always appended to ``.entries``, even if it is already present.
         (This is because ``sys.path`` can contain the same value more than
@@ -622,7 +663,6 @@
         activated to fulfill the requirements; all relevant distributions are
         included, even if they were already activated in this working set.
         """
-
         needed = self.resolve(parse_requirements(requirements))
 
         for dist in needed:
@@ -630,7 +670,6 @@
 
         return needed
 
-
     def subscribe(self, callback):
         """Invoke `callback` for all distributions (including existing ones)"""
         if callback in self.callbacks:
@@ -639,19 +678,21 @@
         for dist in self:
             callback(dist)
 
-
     def _added_new(self, dist):
         for callback in self.callbacks:
             callback(dist)
 
+    def __getstate__(self):
+        return (
+            self.entries[:], self.entry_keys.copy(), self.by_key.copy(),
+            self.callbacks[:]
+        )
 
-
-
-
-
-
-
-
+    def __setstate__(self, (entries, keys, by_key, callbacks)):
+        self.entries = entries[:]
+        self.entry_keys = keys.copy()
+        self.by_key = by_key.copy()
+        self.callbacks = callbacks[:]
 
 
 class Environment(object):
@@ -1515,7 +1556,7 @@
 
 
 
-_distribution_finders = {}
+_declare_state('dict', _distribution_finders = {})
 
 def register_finder(importer_type, distribution_finder):
     """Register `distribution_finder` to find distributions in sys.path items
@@ -1564,7 +1605,7 @@
     """Yield distributions accessible on a sys.path directory"""
     path_item = _normalize_cached(path_item)
 
-    if os.path.isdir(path_item):
+    if os.path.isdir(path_item) and os.access(path_item, os.R_OK):
         if path_item.lower().endswith('.egg'):
             # unpacked egg
             yield Distribution.from_filename(
@@ -1597,8 +1638,8 @@
                         break
 register_finder(pkgutil.ImpImporter, find_on_path)
 
-_namespace_handlers = {}
-_namespace_packages = {}
+_declare_state('dict', _namespace_handlers = {})
+_declare_state('dict', _namespace_packages = {})
 
 def register_namespace_handler(importer_type, namespace_handler):
     """Register `namespace_handler` to declare namespace packages
@@ -1627,7 +1668,7 @@
         return None
     module = sys.modules.get(packageName)
     if module is None:
-        module = sys.modules[packageName] = new.module(packageName)
+        module = sys.modules[packageName] = imp.new_module(packageName)
         module.__path__ = []; _set_parent_ns(packageName)
     elif not hasattr(module,'__path__'):
         raise TypeError("Not a package:", packageName)
@@ -2138,12 +2179,9 @@
         if not loc:
             return
 
-        if path is sys.path:
-            self.check_version_conflict()
-
         nloc = _normalize_cached(loc)
         bdir = os.path.dirname(nloc)
-        npath= map(_normalize_cached, path)
+        npath= [(p and _normalize_cached(p) or p) for p in path]
 
         bp = None
         for p, item in enumerate(npath):
@@ -2151,10 +2189,14 @@
                 break
             elif item==bdir and self.precedence==EGG_DIST:
                 # if it's an .egg, give it precedence over its directory
+                if path is sys.path:
+                    self.check_version_conflict()
                 path.insert(p, loc)
                 npath.insert(p, nloc)
                 break
         else:
+            if path is sys.path:
+                self.check_version_conflict()
             path.append(loc)
             return
 
@@ -2171,7 +2213,6 @@
         return
 
 
-
     def check_version_conflict(self):
         if self.key=='setuptools':
             return      # ignore the inevitable setuptools self-conflicts  :(
@@ -2185,7 +2226,7 @@
                 continue
 
             fn = getattr(sys.modules[modname], '__file__', None)
-            if fn and normalize_path(fn).startswith(loc):
+            if fn and (normalize_path(fn).startswith(loc) or fn.startswith(loc)):
                 continue
             issue_warning(
                 "Module %s was already imported from %s, but %s is being added"
@@ -2362,7 +2403,7 @@
 
     def __contains__(self,item):
         if isinstance(item,Distribution):
-            if item.key <> self.key: return False
+            if item.key != self.key: return False
             if self.index: item = item.parsed_version  # only get if we need it
         elif isinstance(item,basestring):
             item = parse_version(item)
@@ -2459,7 +2500,7 @@
         os.open = old_open  # and then put it back
 
 
-# Set up global resource manager
+# Set up global resource manager (deliberately not state-saved)
 _manager = ResourceManager()
 def _initialize(g):
     for name in dir(_manager):
@@ -2468,7 +2509,7 @@
 _initialize(globals())
 
 # Prepare the master working set and make the ``require()`` API available
-working_set = WorkingSet()
+_declare_state('object', working_set = WorkingSet())
 try:
     # Does the main program list any requirements?
     from __main__ import __requires__

Modified: sandbox/trunk/setuptools/pkg_resources.txt
==============================================================================
--- sandbox/trunk/setuptools/pkg_resources.txt	(original)
+++ sandbox/trunk/setuptools/pkg_resources.txt	Mon Oct 12 21:58:46 2009
@@ -275,7 +275,7 @@
     the global ``working_set`` to reflect the change.  This method is also
     called by the ``WorkingSet()`` constructor during initialization.
 
-    This method uses ``find_distributions(entry,False)`` to find distributions
+    This method uses ``find_distributions(entry, True)`` to find distributions
     corresponding to the path entry, and then ``add()`` them.  `entry` is
     always appended to the ``entries`` attribute, even if it is already
     present, however. (This is because ``sys.path`` can contain the same value
@@ -1667,10 +1667,13 @@
     for obtaining an "importer" object.  It first checks for an importer for
     the path item in ``sys.path_importer_cache``, and if not found it calls
     each of the ``sys.path_hooks`` and caches the result if a good importer is
-    found.  If no importer is found, this routine returns an ``ImpWrapper``
-    instance that wraps the builtin import machinery as a PEP 302-compliant
-    "importer" object.  This ``ImpWrapper`` is *not* cached; instead a new
-    instance is returned each time.
+    found.  If no importer is found, this routine returns a wrapper object
+    that wraps the builtin import machinery as a PEP 302-compliant "importer"
+    object.  This wrapper object is *not* cached; instead a new instance is
+    returned each time.
+
+    (Note: When run under Python 2.5, this function is simply an alias for
+    ``pkgutil.get_importer()``.)
 
 
 File/Path Utilities

Modified: sandbox/trunk/setuptools/setup.py
==============================================================================
--- sandbox/trunk/setuptools/setup.py	(original)
+++ sandbox/trunk/setuptools/setup.py	Mon Oct 12 21:58:46 2009
@@ -54,6 +54,7 @@
             "dependency_links     = setuptools.dist:assert_string_list",
             "test_loader          = setuptools.dist:check_importable",
             "test_runner          = setuptools.dist:check_importable",
+            "packages             = setuptools.dist:check_packages",
         ],
         "egg_info.writers": [
             "PKG-INFO = setuptools.command.egg_info:write_pkg_info",
@@ -79,8 +80,6 @@
     },
 
 
-
-
     classifiers = [f.strip() for f in """
     Development Status :: 3 - Alpha
     Intended Audience :: Developers

Modified: sandbox/trunk/setuptools/setuptools.egg-info/entry_points.txt
==============================================================================
--- sandbox/trunk/setuptools/setuptools.egg-info/entry_points.txt	(original)
+++ sandbox/trunk/setuptools/setuptools.egg-info/entry_points.txt	Mon Oct 12 21:58:46 2009
@@ -50,6 +50,7 @@
 eager_resources = setuptools.dist:assert_string_list
 zip_safe = setuptools.dist:assert_bool
 test_loader = setuptools.dist:check_importable
+packages = setuptools.dist:check_packages
 tests_require = setuptools.dist:check_requirements
 
 [setuptools.installation]

Modified: sandbox/trunk/setuptools/setuptools.txt
==============================================================================
--- sandbox/trunk/setuptools/setuptools.txt	(original)
+++ sandbox/trunk/setuptools/setuptools.txt	Mon Oct 12 21:58:46 2009
@@ -2562,6 +2562,27 @@
   inform the user of the missing program(s).
 
 
+A Note Regarding Dependencies
+-----------------------------
+
+If the project *containing* your distutils/setuptools extension(s) depends on
+any projects other than setuptools, you *must* also declare those dependencies
+as part of your project's  ``setup_requires`` keyword, so that they will
+already be built (and at least temprorarily installed) before your extension
+project is built.
+
+So, if for example you create a project Foo that includes a new file finder
+plugin, and Foo depends on Bar, then you *must* list Bar in both the
+``install_requires`` **and** ``setup_requires`` arguments to ``setup()``.
+
+If you don't do this, then in certain edge cases you may cause setuptools to
+try to go into infinite recursion, trying to build your dependencies to resolve
+your dependencies, while still building your dependencies.  (It probably won't
+happen on your development machine, but it *will* happen in a full build
+pulling everything from revision control on a clean machine, and then you or
+your users will be scratching their heads trying to figure it out!)
+
+
 Subclassing ``Command``
 -----------------------
 

Modified: sandbox/trunk/setuptools/setuptools/command/alias.py
==============================================================================
--- sandbox/trunk/setuptools/setuptools/command/alias.py	(original)
+++ sandbox/trunk/setuptools/setuptools/command/alias.py	Mon Oct 12 21:58:46 2009
@@ -9,7 +9,7 @@
     """Quote an argument for later parsing by shlex.split()"""
     for c in '"', "'", "\\", "#":
         if c in arg: return repr(arg)
-    if arg.split()<>[arg]:
+    if arg.split()!=[arg]:
         return repr(arg)
     return arg
 
@@ -33,7 +33,7 @@
 
     def finalize_options(self):
         option_base.finalize_options(self)
-        if self.remove and len(self.args)<>1:
+        if self.remove and len(self.args)!=1:
             raise DistutilsOptionError(
                 "Must specify exactly one argument (the alias name) when "
                 "using --remove"

Modified: sandbox/trunk/setuptools/setuptools/command/bdist_egg.py
==============================================================================
--- sandbox/trunk/setuptools/setuptools/command/bdist_egg.py	(original)
+++ sandbox/trunk/setuptools/setuptools/command/bdist_egg.py	Mon Oct 12 21:58:46 2009
@@ -165,12 +165,13 @@
     def run(self):
         # Generate metadata first
         self.run_command("egg_info")
-
         # We run install_lib before install_data, because some data hacks
         # pull their data path from the install_lib command.
         log.info("installing library code to %s" % self.bdist_dir)
         instcmd = self.get_finalized_command('install')
         old_root = instcmd.root; instcmd.root = None
+        if self.distribution.has_c_libraries() and not self.skip_build:
+            self.run_command('build_clib')
         cmd = self.call_command('install_lib', warn_dir=0)
         instcmd.root = old_root
 
@@ -190,7 +191,6 @@
         to_compile.extend(self.make_init_files())
         if to_compile:
             cmd.byte_compile(to_compile)
-
         if self.distribution.data_files:
             self.do_install_data()
 
@@ -398,7 +398,7 @@
     for flag,fn in safety_flags.items():
         fn = os.path.join(egg_dir, fn)
         if os.path.exists(fn):
-            if safe is None or bool(safe)<>flag:
+            if safe is None or bool(safe)!=flag:
                 os.unlink(fn)
         elif safe is not None and bool(safe)==flag:
             f=open(fn,'wb'); f.write('\n'); f.close()

Modified: sandbox/trunk/setuptools/setuptools/command/build_ext.py
==============================================================================
--- sandbox/trunk/setuptools/setuptools/command/build_ext.py	(original)
+++ sandbox/trunk/setuptools/setuptools/command/build_ext.py	Mon Oct 12 21:58:46 2009
@@ -82,15 +82,15 @@
 
     def get_ext_filename(self, fullname):
         filename = _build_ext.get_ext_filename(self,fullname)
-        ext = self.ext_map[fullname]
-        if isinstance(ext,Library):
-            fn, ext = os.path.splitext(filename)
-            return self.shlib_compiler.library_filename(fn,libtype)
-        elif use_stubs and ext._links_to_dynamic:
-            d,fn = os.path.split(filename)
-            return os.path.join(d,'dl-'+fn)
-        else:
-            return filename
+        if fullname in self.ext_map:
+            ext = self.ext_map[fullname]
+            if isinstance(ext,Library):
+                fn, ext = os.path.splitext(filename)
+                return self.shlib_compiler.library_filename(fn,libtype)
+            elif use_stubs and ext._links_to_dynamic:
+                d,fn = os.path.split(filename)
+                return os.path.join(d,'dl-'+fn)
+        return filename
 
     def initialize_options(self):
         _build_ext.initialize_options(self)

Modified: sandbox/trunk/setuptools/setuptools/command/easy_install.py
==============================================================================
--- sandbox/trunk/setuptools/setuptools/command/easy_install.py	(original)
+++ sandbox/trunk/setuptools/setuptools/command/easy_install.py	Mon Oct 12 21:58:46 2009
@@ -204,7 +204,7 @@
         self.outputs = []
 
     def run(self):
-        if self.verbose<>self.distribution.verbose:
+        if self.verbose!=self.distribution.verbose:
             log.set_verbosity(self.verbose)
         try:
             for spec in self.args:
@@ -252,7 +252,7 @@
         # Is it a configured, PYTHONPATH, implicit, or explicit site dir?
         is_site_dir = instdir in self.all_site_dirs
 
-        if not is_site_dir:
+        if not is_site_dir and not self.multi_version:
             # No?  Then directly test whether it does .pth file processing
             is_site_dir = self.check_pth_processing()
         else:
@@ -430,9 +430,9 @@
 
             self.check_editable(spec)
             dist = self.package_index.fetch_distribution(
-                spec, tmpdir, self.upgrade, self.editable, not self.always_copy
+                spec, tmpdir, self.upgrade, self.editable, not self.always_copy,
+                self.local_index
             )
-
             if dist is None:
                 msg = "Could not find suitable distribution for %r" % spec
                 if self.always_copy:
@@ -722,7 +722,7 @@
             f = open(pkg_inf,'w')
             f.write('Metadata-Version: 1.0\n')
             for k,v in cfg.items('metadata'):
-                if k<>'target_version':
+                if k!='target_version':
                     f.write('%s: %s\n' % (k.replace('_','-').title(), v))
             f.close()
         script_dir = os.path.join(egg_info,'scripts')
@@ -988,7 +988,6 @@
         def pf(src,dst):
             if dst.endswith('.py') and not src.startswith('EGG-INFO/'):
                 to_compile.append(dst)
-                to_chmod.append(dst)
             elif dst.endswith('.dll') or dst.endswith('.so'):
                 to_chmod.append(dst)
             self.unpack_progress(src,dst)
@@ -1023,6 +1022,7 @@
 
 
 
+
     def no_default_version_msg(self):
         return """bad install directory or PYTHONPATH
 
@@ -1286,7 +1286,7 @@
                 if parts[1].endswith('.egg-info'):
                     prefixes.insert(0,('/'.join(parts[:2]), 'EGG-INFO/'))
                     break
-            if len(parts)<>2 or not name.endswith('.pth'):
+            if len(parts)!=2 or not name.endswith('.pth'):
                 continue
             if name.endswith('-nspkg.pth'):
                 continue

Modified: sandbox/trunk/setuptools/setuptools/command/egg_info.py
==============================================================================
--- sandbox/trunk/setuptools/setuptools/command/egg_info.py	(original)
+++ sandbox/trunk/setuptools/setuptools/command/egg_info.py	Mon Oct 12 21:58:46 2009
@@ -217,18 +217,21 @@
             data = f.read()
             f.close()
 
-            if data.startswith('9') or data.startswith('8'):
+            if data.startswith('<?xml'):
+                dirurl = urlre.search(data).group(1)    # get repository URL
+                localrev = max([int(m.group(1)) for m in revre.finditer(data)]+[0])
+            else:
+                try: svnver = int(data.splitlines()[0])
+                except: svnver=-1
+                if data<8:
+                    log.warn("unrecognized .svn/entries format; skipping %s", base)
+                    dirs[:] = []
+                    continue
+                   
                 data = map(str.splitlines,data.split('\n\x0c\n'))
                 del data[0][0]  # get rid of the '8' or '9'
                 dirurl = data[0][3]
                 localrev = max([int(d[9]) for d in data if len(d)>9 and d[9]]+[0])
-            elif data.startswith('<?xml'):
-                dirurl = urlre.search(data).group(1)    # get repository URL
-                localrev = max([int(m.group(1)) for m in revre.finditer(data)]+[0])
-            else:
-                log.warn("unrecognized .svn/entries format; skipping %s", base)
-                dirs[:] = []
-                continue
             if base==os.curdir:
                 base_url = dirurl+'/'   # save the root url
             elif not dirurl.startswith(base_url):
@@ -241,9 +244,6 @@
 
 
 
-
-
-
     def find_sources(self):
         """Generate SOURCES.txt manifest file"""
         manifest_filename = os.path.join(self.egg_info,"SOURCES.txt")

Modified: sandbox/trunk/setuptools/setuptools/command/sdist.py
==============================================================================
--- sandbox/trunk/setuptools/setuptools/command/sdist.py	(original)
+++ sandbox/trunk/setuptools/setuptools/command/sdist.py	Mon Oct 12 21:58:46 2009
@@ -1,6 +1,7 @@
 from distutils.command.sdist import sdist as _sdist
 from distutils.util import convert_path
 from distutils import log
+from glob import glob
 import os, re, sys, pkg_resources
 
 entities = [
@@ -38,7 +39,6 @@
 
 
 
-
 def walk_revctrl(dirname=''):
     """Find all files under revision control"""
     for ep in pkg_resources.iter_entry_points('setuptools.file_finders'):
@@ -86,17 +86,21 @@
     f = open(filename,'rU')
     data = f.read()
     f.close()
-    if data.startswith('9') or data.startswith('8'):    # subversion 1.5/1.4
+    if data.startswith('<?xml'):
+        for match in entries_pattern.finditer(data):
+            yield joinpath(dirname,unescape(match.group(1)))
+    else:
+        svnver=-1
+        try: svnver = int(data.splitlines()[0])
+        except: pass
+        if svnver<8:
+            log.warn("unrecognized .svn/entries format in %s", dirname)
+            return           
         for record in map(str.splitlines, data.split('\n\x0c\n')[1:]):
             if not record or len(record)>=6 and record[5]=="delete":
                 continue    # skip deleted
             yield joinpath(dirname, record[0])
-    elif data.startswith('<?xml'):
-        for match in entries_pattern.finditer(data):
-            yield joinpath(dirname,unescape(match.group(1)))
-    else:
-        log.warn("unrecognized .svn/entries format in %s", dirname)
-
+        
 
 finders = [
     (convert_path('CVS/Entries'),
@@ -117,10 +121,6 @@
 
 
 
-
-
-
-
 class sdist(_sdist):
     """Smart sdist that finds anything supported by revision control"""
 
@@ -162,6 +162,56 @@
             sys.exc_info()[2].tb_next.tb_frame.f_locals['template'].close()
             raise
 
+    # Cribbed from old distutils code, to work around new distutils code
+    # that tries to do some of the same stuff as we do, in a way that makes
+    # us loop.
+    
+    def add_defaults (self):
+        standards = [('README', 'README.txt'), self.distribution.script_name]
+
+        for fn in standards:
+            if type(fn) is tuple:
+                alts = fn
+                got_it = 0
+                for fn in alts:
+                    if os.path.exists(fn):
+                        got_it = 1
+                        self.filelist.append(fn)
+                        break
+
+                if not got_it:
+                    self.warn("standard file not found: should have one of " +
+                              string.join(alts, ', '))
+            else:
+                if os.path.exists(fn):
+                    self.filelist.append(fn)
+                else:
+                    self.warn("standard file '%s' not found" % fn)
+
+        optional = ['test/test*.py', 'setup.cfg']
+        
+        for pattern in optional:
+            files = filter(os.path.isfile, glob(pattern))
+            if files:
+                self.filelist.extend(files)
+
+        if self.distribution.has_pure_modules():
+            build_py = self.get_finalized_command('build_py')
+            self.filelist.extend(build_py.get_source_files())
+
+        if self.distribution.has_ext_modules():
+            build_ext = self.get_finalized_command('build_ext')
+            self.filelist.extend(build_ext.get_source_files())
+
+        if self.distribution.has_c_libraries():
+            build_clib = self.get_finalized_command('build_clib')
+            self.filelist.extend(build_clib.get_source_files())
+
+        if self.distribution.has_scripts():
+            build_scripts = self.get_finalized_command('build_scripts')
+            self.filelist.extend(build_scripts.get_source_files())
+
+
     def check_readme(self):
         alts = ("README", "README.txt")
         for f in alts:
@@ -193,13 +243,4 @@
 
 
 
-
-
-
-
-
-
-
-
-
 #

Modified: sandbox/trunk/setuptools/setuptools/command/test.py
==============================================================================
--- sandbox/trunk/setuptools/setuptools/command/test.py	(original)
+++ sandbox/trunk/setuptools/setuptools/command/test.py	Mon Oct 12 21:58:46 2009
@@ -125,14 +125,14 @@
         import unittest
         loader_ep = EntryPoint.parse("x="+self.test_loader)
         loader_class = loader_ep.load(require=False)
-        runner = None
+        kw = {}
         if self.test_runner is not None:
             runner_ep = EntryPoint.parse("x="+self.test_runner)
             runner_class = runner_ep.load(require=False)
-            runner = runner_class()
+            kw['runner'] = runner_class()
         unittest.main(
             None, None, [unittest.__file__]+self.test_args,
-            testRunner = runner, testLoader = loader_class()
+            testLoader = loader_class(), **kw
         )
 
 

Modified: sandbox/trunk/setuptools/setuptools/depends.py
==============================================================================
--- sandbox/trunk/setuptools/setuptools/depends.py	(original)
+++ sandbox/trunk/setuptools/setuptools/depends.py	Mon Oct 12 21:58:46 2009
@@ -36,7 +36,7 @@
     def version_ok(self,version):
         """Is 'version' sufficiently up-to-date?"""
         return self.attribute is None or self.format is None or \
-            str(version)<>"unknown" and version >= self.requested_version
+            str(version)!="unknown" and version >= self.requested_version
 
 
     def get_version(self, paths=None, default="unknown"):

Modified: sandbox/trunk/setuptools/setuptools/dist.py
==============================================================================
--- sandbox/trunk/setuptools/setuptools/dist.py	(original)
+++ sandbox/trunk/setuptools/setuptools/dist.py	Mon Oct 12 21:58:46 2009
@@ -8,7 +8,7 @@
 from distutils.errors import DistutilsOptionError, DistutilsPlatformError
 from distutils.errors import DistutilsSetupError
 import setuptools, pkg_resources, distutils.core, distutils.dist, distutils.cmd
-import os, distutils.log
+import os, distutils.log, re
 
 def _get_unpatched(cls):
     """Protect against re-patching the distutils if reloaded
@@ -61,8 +61,8 @@
             parent = '.'.join(nsp.split('.')[:-1])
             if parent not in value:
                 distutils.log.warn(
-                    "%r is declared as a package namespace, but %r is not:"
-                    " please correct this in setup.py", nsp, parent
+                    "WARNING: %r is declared as a package namespace, but %r"
+                    " is not: please correct this in setup.py", nsp, parent
                 )
 
 def check_extras(dist, attr, value):
@@ -121,6 +121,47 @@
         "wildcard patterns"
     )
 
+def check_packages(dist, attr, value):
+    for pkgname in value:
+        if not re.match(r'\w+(\.\w+)*', pkgname):
+            distutils.log.warn(
+                "WARNING: %r not a valid package name; please use only"
+                ".-separated package names in setup.py", pkgname
+            )
+            
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 class Distribution(_Distribution):
     """Distribution with support for features, tests, and package data
 
@@ -415,19 +456,19 @@
         if self.packages:
             self.packages = [
                 p for p in self.packages
-                    if p<>package and not p.startswith(pfx)
+                    if p!=package and not p.startswith(pfx)
             ]
 
         if self.py_modules:
             self.py_modules = [
                 p for p in self.py_modules
-                    if p<>package and not p.startswith(pfx)
+                    if p!=package and not p.startswith(pfx)
             ]
 
         if self.ext_modules:
             self.ext_modules = [
                 p for p in self.ext_modules
-                    if p.name<>package and not p.name.startswith(pfx)
+                    if p.name!=package and not p.name.startswith(pfx)
             ]
 
 
@@ -796,3 +837,25 @@
                     " doesn't contain any packages or modules under %s"
                     % (self.description, item, item)
                 )
+                
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

Modified: sandbox/trunk/setuptools/setuptools/package_index.py
==============================================================================
--- sandbox/trunk/setuptools/setuptools/package_index.py	(original)
+++ sandbox/trunk/setuptools/setuptools/package_index.py	Mon Oct 12 21:58:46 2009
@@ -1,5 +1,6 @@
 """PyPI and direct package downloading"""
 import sys, os.path, re, urlparse, urllib2, shutil, random, socket, cStringIO
+import httplib
 from pkg_resources import *
 from distutils import log
 from distutils.errors import DistutilsError
@@ -8,7 +9,6 @@
 except ImportError:
     from md5 import md5
 from fnmatch import translate
-
 EGG_FRAGMENT = re.compile(r'^egg=([-A-Za-z0-9_.]+)$')
 HREF = re.compile("""href\\s*=\\s*['"]?([^'"> ]+)""", re.I)
 # this is here to fix emacs' cruddy broken syntax highlighting
@@ -42,6 +42,8 @@
 def egg_info_for_url(url):
     scheme, server, path, parameters, query, fragment = urlparse.urlparse(url)
     base = urllib2.unquote(path.split('/')[-1])
+    if server=='sourceforge.net' and base=='download':    # XXX Yuck
+        base = urllib2.unquote(path.split('/')[-2])
     if '#' in base: base, fragment = base.split('#',1)
     return base,fragment
 
@@ -64,14 +66,12 @@
     if basename.endswith('.egg') and '-' in basename:
         # only one, unambiguous interpretation
         return [Distribution.from_location(location, basename, metadata)]
-
     if basename.endswith('.exe'):
         win_base, py_ver = parse_bdist_wininst(basename)
         if win_base is not None:
             return interpret_distro_name(
                 location, win_base, metadata, py_ver, BINARY_DIST, "win32"
             )
-
     # Try source distro extensions (.zip, .tgz, etc.)
     #
     for ext in EXTENSIONS:
@@ -186,10 +186,10 @@
             return
 
         self.info("Reading %s", url)
+        self.fetched_urls[url] = True   # prevent multiple fetch attempts
         f = self.open_url(url, "Download error: %s -- Some packages may not be found!")
         if f is None: return
-        self.fetched_urls[url] = self.fetched_urls[f.url] = True
-
+        self.fetched_urls[f.url] = True
         if 'html' not in f.headers.get('content-type', '').lower():
             f.close()   # not html, we can't process it
             return
@@ -329,7 +329,7 @@
     def check_md5(self, cs, info, filename, tfp):
         if re.match('md5=[0-9a-f]{32}$', info):
             self.debug("Validating md5 checksum for %s", filename)
-            if cs.hexdigest()<>info[4:]:
+            if cs.hexdigest()!=info[4:]:
                 tfp.close()
                 os.unlink(filename)
                 raise DistutilsError(
@@ -409,7 +409,8 @@
 
 
     def fetch_distribution(self,
-        requirement, tmpdir, force_scan=False, source=False, develop_ok=False
+        requirement, tmpdir, force_scan=False, source=False, develop_ok=False,
+        local_index=None, 
     ):
         """Obtain a distribution suitable for fulfilling `requirement`
 
@@ -427,15 +428,15 @@
         set, development and system eggs (i.e., those using the ``.egg-info``
         format) will be ignored.
         """
-
         # process a Requirement
         self.info("Searching for %s", requirement)
         skipped = {}
+        dist = None
 
-        def find(req):
+        def find(env, req):
             # Find a matching distribution; may be called more than once
 
-            for dist in self[req.key]:
+            for dist in env[req.key]:
 
                 if dist.precedence==DEVELOP_DIST and not develop_ok:
                     if dist not in skipped:
@@ -444,23 +445,25 @@
                     continue
 
                 if dist in req and (dist.precedence<=SOURCE_DIST or not source):
-                    self.info("Best match: %s", dist)
-                    return dist.clone(
-                        location=self.download(dist.location, tmpdir)
-                    )
+                    return dist
+
+
 
         if force_scan:
             self.prescan()
             self.find_packages(requirement)
+            dist = find(self, requirement)
+            
+        if local_index is not None:
+            dist = dist or find(local_index, requirement)
 
-        dist = find(requirement)
         if dist is None and self.to_scan is not None:
             self.prescan()
-            dist = find(requirement)
+            dist = find(self, requirement)
 
         if dist is None and not force_scan:
             self.find_packages(requirement)
-            dist = find(requirement)
+            dist = find(self, requirement)
 
         if dist is None:
             self.warn(
@@ -468,7 +471,9 @@
                 (source and "a source distribution of " or ""),
                 requirement,
             )
-        return dist
+        self.info("Best match: %s", dist)
+        return dist.clone(location=self.download(dist.location, tmpdir))
+
 
     def fetch(self, requirement, tmpdir, force_scan=False, source=False):
         """Obtain a file suitable for fulfilling `requirement`
@@ -485,11 +490,6 @@
 
 
 
-
-
-
-
-
     def gen_setup(self, filename, fragment, tmpdir):
         match = EGG_FRAGMENT.match(fragment)
         dists = match and [d for d in
@@ -573,17 +573,19 @@
 
 
     def open_url(self, url, warning=None):
-        if url.startswith('file:'):
-            return local_open(url)
+        if url.startswith('file:'): return local_open(url)
         try:
             return open_with_auth(url)
         except urllib2.HTTPError, v:
             return v
         except urllib2.URLError, v:
-            if warning: self.warn(warning, v.reason)
-            else:
-                raise DistutilsError("Download error for %s: %s"
-                                     % (url, v.reason))
+            reason = v.reason
+        except httplib.HTTPException, v: 
+            reason = "%s: %s" % (v.__doc__ or v.__class__.__name__, v)
+        if warning:
+            self.warn(warning, reason)
+        else:
+            raise DistutilsError("Download error for %s: %s" % (url, reason))
 
     def _download_url(self, scheme, url, tmpdir):
         # Determine download filename
@@ -611,8 +613,6 @@
             self.url_ok(url, True)   # raises error if not allowed
             return self._attempt_download(url, filename)
 
-
-
     def scan_url(self, url):
         self.process_url(url, True)
 

Modified: sandbox/trunk/setuptools/setuptools/sandbox.py
==============================================================================
--- sandbox/trunk/setuptools/setuptools/sandbox.py	(original)
+++ sandbox/trunk/setuptools/setuptools/sandbox.py	Mon Oct 12 21:58:46 2009
@@ -1,10 +1,44 @@
-import os, sys, __builtin__, tempfile, operator
+import os, sys, __builtin__, tempfile, operator, pkg_resources
 _os = sys.modules[os.name]
 _open = open
+_file = file
+
 from distutils.errors import DistutilsError
+from pkg_resources import working_set
+
 __all__ = [
     "AbstractSandbox", "DirectorySandbox", "SandboxViolation", "run_setup",
 ]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 def run_setup(setup_script, args):
     """Run a distutils setup script, sandboxed in its directory"""
     old_dir = os.getcwd()
@@ -15,11 +49,15 @@
     if not os.path.isdir(temp_dir): os.makedirs(temp_dir)
     save_tmp = tempfile.tempdir
     save_modules = sys.modules.copy()
+    pr_state = pkg_resources.__getstate__()
     try:
         tempfile.tempdir = temp_dir; os.chdir(setup_dir)
         try:
             sys.argv[:] = [setup_script]+list(args)
             sys.path.insert(0, setup_dir)
+            # reset to include setup dir, w/clean callback list
+            working_set.__init__()  
+            working_set.callbacks.append(lambda dist:dist.activate())
             DirectorySandbox(setup_dir).run(
                 lambda: execfile(
                     "setup.py",
@@ -31,6 +69,7 @@
                 raise
             # Normal exit, just return
     finally:
+        pkg_resources.__setstate__(pr_state)
         sys.modules.update(save_modules)
         for key in list(sys.modules):
             if key not in save_modules: del sys.modules[key]
@@ -39,6 +78,8 @@
         sys.argv[:] = save_argv
         tempfile.tempdir = save_tmp
 
+
+
 class AbstractSandbox:
     """Wrap 'os' module and 'open()' builtin for virtualizing setup scripts"""
 
@@ -58,15 +99,16 @@
         """Run 'func' under os sandboxing"""
         try:
             self._copy(self)
-            __builtin__.open = __builtin__.file = self._open
+            __builtin__.file = self._file
+            __builtin__.open = self._open
             self._active = True
             return func()
         finally:
             self._active = False
-            __builtin__.open = __builtin__.file = _open
+            __builtin__.open = _file
+            __builtin__.file = _open
             self._copy(_os)
 
-
     def _mk_dual_path_wrapper(name):
         original = getattr(_os,name)
         def wrap(self,src,dst,*args,**kw):
@@ -75,7 +117,6 @@
             return original(src,dst,*args,**kw)
         return wrap
 
-
     for name in ["rename", "link", "symlink"]:
         if hasattr(_os,name): locals()[name] = _mk_dual_path_wrapper(name)
 
@@ -88,7 +129,8 @@
             return original(path,*args,**kw)
         return wrap
 
-    _open = _mk_single_path_wrapper('file', _open)
+    _open = _mk_single_path_wrapper('open', _open)
+    _file = _mk_single_path_wrapper('file', _file)
     for name in [
         "stat", "listdir", "chdir", "open", "chmod", "chown", "mkdir",
         "remove", "unlink", "rmdir", "utime", "lchown", "chroot", "lstat",
@@ -96,7 +138,6 @@
     ]:
         if hasattr(_os,name): locals()[name] = _mk_single_path_wrapper(name)
 
-
     def _mk_single_with_return(name):
         original = getattr(_os,name)
         def wrap(self,path,*args,**kw):
@@ -187,22 +228,22 @@
             self._violation(operation, src, dst, *args, **kw)
         return (src,dst)
 
+    def _file(self, path, mode='r', *args, **kw):
+        if mode not in ('r', 'rt', 'rb', 'rU', 'U') and not self._ok(path):
+            self._violation("file", path, mode, *args, **kw)
+        return _file(path,mode,*args,**kw)
+
     def open(self, file, flags, mode=0777):
         """Called for low-level os.open()"""
         if flags & WRITE_FLAGS and not self._ok(file):
             self._violation("os.open", file, flags, mode)
         return _os.open(file,flags,mode)
 
-
 WRITE_FLAGS = reduce(
-    operator.or_,
-    [getattr(_os, a, 0) for a in
+    operator.or_, [getattr(_os, a, 0) for a in
         "O_WRONLY O_RDWR O_APPEND O_CREAT O_TRUNC O_TEMPORARY".split()]
 )
 
-
-
-
 class SandboxViolation(DistutilsError):
     """A setup script attempted to modify the filesystem outside the sandbox"""
 

Modified: sandbox/trunk/setuptools/setuptools/tests/api_tests.txt
==============================================================================
--- sandbox/trunk/setuptools/setuptools/tests/api_tests.txt	(original)
+++ sandbox/trunk/setuptools/setuptools/tests/api_tests.txt	Mon Oct 12 21:58:46 2009
@@ -170,8 +170,8 @@
     >>> ws.entries
     ['http://example.com/something']
     >>> ws.add_entry(pkg_resources.__file__)
-    >>> ws.entries
-    ['http://example.com/something', '...pkg_resources.py...']
+    >>> ws.entries == ['http://example.com/something', pkg_resources.__file__]
+    True
 
 Multiple additions result in multiple entries, even if the entry is already in
 the working set (because ``sys.path`` can contain the same entry more than


More information about the Python-checkins mailing list