[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