aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xEasyInstall.txt18
-rwxr-xr-xez_setup.py2
-rw-r--r--pkg_resources.py109
-rwxr-xr-xpkg_resources.txt20
-rwxr-xr-xrelease.sh2
-rwxr-xr-xsetup.py4
-rwxr-xr-xsetuptools.egg-info/entry_points.txt1
-rwxr-xr-xsetuptools.txt31
-rw-r--r--setuptools/__init__.py2
-rwxr-xr-xsetuptools/command/alias.py4
-rw-r--r--setuptools/command/bdist_egg.py6
-rw-r--r--setuptools/command/build_ext.py18
-rwxr-xr-xsetuptools/command/easy_install.py14
-rwxr-xr-xsetuptools/command/egg_info.py22
-rwxr-xr-xsetuptools/command/sdist.py83
-rw-r--r--setuptools/depends.py2
-rw-r--r--setuptools/dist.py53
-rwxr-xr-xsetuptools/package_index.py62
-rwxr-xr-xsetuptools/sandbox.py75
-rwxr-xr-xversion.dat2
20 files changed, 368 insertions, 162 deletions
diff --git a/EasyInstall.txt b/EasyInstall.txt
index b0341e88..20e2053a 100755
--- a/EasyInstall.txt
+++ b/EasyInstall.txt
@@ -256,7 +256,7 @@ or directory (found in the installation directory).
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 @@ below, and also the section on the `Package Index "API"`_.
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::
@@ -1217,7 +1217,19 @@ displayed MD5 info (broken onto two lines for readability)::
Release Notes/Change History
============================
-0.6final
+0.6c10
+ * Support for the most recent Sourceforge download link insanity
+
+ * 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 semi-randomly preferring local "-f" packages over
+ local installed packages
+
+0.6c9
* Fixed ``win32.exe`` support for .pth files, so unnecessary directory nesting
is flattened out in the resulting egg. (There was a case-sensitivity
problem that affected some distributions, notably ``pywin32``.)
diff --git a/ez_setup.py b/ez_setup.py
index d24e845e..f4de7e4b 100755
--- a/ez_setup.py
+++ b/ez_setup.py
@@ -14,7 +14,7 @@ the appropriate options to ``use_setuptools()``.
This file can also be run as a script to install or upgrade setuptools.
"""
import sys
-DEFAULT_VERSION = "0.6c9"
+DEFAULT_VERSION = "0.6c10"
DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3]
md5_data = {
diff --git a/pkg_resources.py b/pkg_resources.py
index 9edb6c0b..baff4225 100644
--- a/pkg_resources.py
+++ b/pkg_resources.py
@@ -13,7 +13,7 @@ The package resource API is designed to work with normal filesystem packages,
method.
"""
-import sys, os, zipimport, time, re, imp, new
+import sys, os, zipimport, time, re, imp
try:
frozenset
@@ -39,6 +39,47 @@ from os import open as os_open
+_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.
@@ -164,14 +205,8 @@ def get_provider(moduleOrReq):
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 @@ 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 @@ class WorkingSet(object):
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 @@ class WorkingSet(object):
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 @@ class WorkingSet(object):
return needed
-
def subscribe(self, callback):
"""Invoke `callback` for all distributions (including existing ones)"""
if callback in self.callbacks:
@@ -639,19 +678,21 @@ class WorkingSet(object):
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):
@@ -1597,7 +1638,7 @@ else:
-_distribution_finders = {}
+_declare_state('dict', _distribution_finders = {})
def register_finder(importer_type, distribution_finder):
"""Register `distribution_finder` to find distributions in sys.path items
@@ -1646,7 +1687,7 @@ def find_on_path(importer, path_item, only=False):
"""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(
@@ -1679,8 +1720,8 @@ def find_on_path(importer, path_item, only=False):
break
register_finder(ImpWrapper,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
@@ -1709,7 +1750,7 @@ def _handle_ns(packageName, path_item):
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)
@@ -2220,12 +2261,9 @@ class Distribution(object):
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):
@@ -2233,10 +2271,14 @@ class Distribution(object):
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
@@ -2253,7 +2295,6 @@ class Distribution(object):
return
-
def check_version_conflict(self):
if self.key=='setuptools':
return # ignore the inevitable setuptools self-conflicts :(
@@ -2267,7 +2308,7 @@ class Distribution(object):
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"
@@ -2444,7 +2485,7 @@ class Requirement:
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)
@@ -2541,7 +2582,7 @@ def _mkstemp(*args,**kw):
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):
@@ -2550,7 +2591,7 @@ def _initialize(g):
_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__
diff --git a/pkg_resources.txt b/pkg_resources.txt
index 7d8afd37..03793b62 100755
--- a/pkg_resources.txt
+++ b/pkg_resources.txt
@@ -269,7 +269,7 @@ instance:
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
@@ -1661,14 +1661,10 @@ PEP 302 Utilities
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.
-
- (Note: When run under Python 2.5, this function is simply an alias for
- ``pkgutil.get_importer()``, and instead of ``pkg_resources.ImpWrapper``
- instances, it may return ``pkgutil.ImpImporter`` instances.)
+ 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.
File/Path Utilities
@@ -1692,7 +1688,11 @@ File/Path Utilities
Release Notes/Change History
----------------------------
-0.6final
+0.6c10
+ * Prevent lots of spurious "already imported from another path" warnings (e.g.
+ when pkg_resources is imported late).
+
+0.6c9
* Fix ``resource_listdir('')`` always returning an empty list for zipped eggs.
0.6c7
diff --git a/release.sh b/release.sh
index c53357d9..2d2da5eb 100755
--- a/release.sh
+++ b/release.sh
@@ -7,7 +7,7 @@
# If your initials aren't PJE, don't run it. :)
#
-export VERSION="0.6c9"
+export VERSION="0.6c10"
python2.3 setup.py -q release source --target-version=2.3 upload && \
python2.4 setup.py -q release binary --target-version=2.4 upload && \
diff --git a/setup.py b/setup.py
index b5da4183..198ae88d 100755
--- a/setup.py
+++ b/setup.py
@@ -7,7 +7,7 @@ d = {}
execfile(convert_path('setuptools/command/__init__.py'), d)
SETUP_COMMANDS = d['__all__']
-VERSION = "0.6c9"
+VERSION = "0.6c10"
from setuptools import setup, find_packages
import sys
@@ -53,8 +53,8 @@ setup(
"include_package_data = setuptools.dist:assert_bool",
"dependency_links = setuptools.dist:assert_string_list",
"test_loader = setuptools.dist:check_importable",
+ "packages = setuptools.dist:check_packages",
],
-
"egg_info.writers": [
"PKG-INFO = setuptools.command.egg_info:write_pkg_info",
"requires.txt = setuptools.command.egg_info:write_requirements",
diff --git a/setuptools.egg-info/entry_points.txt b/setuptools.egg-info/entry_points.txt
index f7367e0d..10f1da6c 100755
--- a/setuptools.egg-info/entry_points.txt
+++ b/setuptools.egg-info/entry_points.txt
@@ -49,6 +49,7 @@ test_suite = setuptools.dist:check_test_suite
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]
diff --git a/setuptools.txt b/setuptools.txt
index d1b25302..93940528 100755
--- a/setuptools.txt
+++ b/setuptools.txt
@@ -2569,6 +2569,27 @@ A few important points for writing revision control file finders:
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``
-----------------------
@@ -2611,7 +2632,15 @@ XXX
Release Notes/Change History
----------------------------
-0.6final
+0.6c10
+ * Fix for the Python 2.6.3 build_ext API change
+
+ * Ensure C libraries (as opposed to extensions) are also built when doing
+ bdist_egg
+
+ * Support for SVN 1.6
+
+0.6c9
* Fixed a missing files problem when using Windows source distributions on
non-Windows platforms, due to distutils not handling manifest file line
endings correctly.
diff --git a/setuptools/__init__.py b/setuptools/__init__.py
index 56cbf767..a9f6544d 100644
--- a/setuptools/__init__.py
+++ b/setuptools/__init__.py
@@ -7,7 +7,7 @@ from distutils.core import Command as _Command
from distutils.util import convert_path
import os.path
-__version__ = '0.6c9'
+__version__ = '0.6c10'
__all__ = [
'setup', 'Distribution', 'Feature', 'Command', 'Extension', 'Require',
'find_packages'
diff --git a/setuptools/command/alias.py b/setuptools/command/alias.py
index f5368b29..40c00b55 100755
--- a/setuptools/command/alias.py
+++ b/setuptools/command/alias.py
@@ -9,7 +9,7 @@ def shquote(arg):
"""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 @@ class alias(option_base):
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"
diff --git a/setuptools/command/bdist_egg.py b/setuptools/command/bdist_egg.py
index 9e852a3f..7e5a3799 100644
--- a/setuptools/command/bdist_egg.py
+++ b/setuptools/command/bdist_egg.py
@@ -165,12 +165,13 @@ class bdist_egg(Command):
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 @@ class bdist_egg(Command):
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 @@ def write_safety_flag(egg_dir, safe):
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()
diff --git a/setuptools/command/build_ext.py b/setuptools/command/build_ext.py
index c0aaa8e8..f6f3355d 100644
--- a/setuptools/command/build_ext.py
+++ b/setuptools/command/build_ext.py
@@ -82,15 +82,15 @@ class build_ext(_build_ext):
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)
diff --git a/setuptools/command/easy_install.py b/setuptools/command/easy_install.py
index f06b6ddd..a5a23ad4 100755
--- a/setuptools/command/easy_install.py
+++ b/setuptools/command/easy_install.py
@@ -204,7 +204,7 @@ class easy_install(Command):
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 @@ class easy_install(Command):
# 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 @@ Please make the appropriate changes for your system and try again.
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 @@ Please make the appropriate changes for your system and try again.
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 @@ See the setuptools documentation for the "develop" command for more info.
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 @@ See the setuptools documentation for the "develop" command for more info.
+
def no_default_version_msg(self):
return """bad install directory or PYTHONPATH
@@ -1286,7 +1286,7 @@ def get_exe_prefixes(exe_filename):
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
diff --git a/setuptools/command/egg_info.py b/setuptools/command/egg_info.py
index 9741e26a..5a8b2db8 100755
--- a/setuptools/command/egg_info.py
+++ b/setuptools/command/egg_info.py
@@ -217,18 +217,21 @@ class egg_info(Command):
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 @@ class egg_info(Command):
-
-
-
def find_sources(self):
"""Generate SOURCES.txt manifest file"""
manifest_filename = os.path.join(self.egg_info,"SOURCES.txt")
diff --git a/setuptools/command/sdist.py b/setuptools/command/sdist.py
index 5bd5ebd4..d5121de5 100755
--- a/setuptools/command/sdist.py
+++ b/setuptools/command/sdist.py
@@ -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 joinpath(prefix,suffix):
-
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 @@ def entries_finder(dirname, filename):
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 @@ finders = [
-
-
-
-
class sdist(_sdist):
"""Smart sdist that finds anything supported by revision control"""
@@ -162,6 +162,56 @@ class sdist(_sdist):
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 @@ class sdist(_sdist):
-
-
-
-
-
-
-
-
-
#
diff --git a/setuptools/depends.py b/setuptools/depends.py
index 4b7b3437..5fdf2d7e 100644
--- a/setuptools/depends.py
+++ b/setuptools/depends.py
@@ -36,7 +36,7 @@ class Require:
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"):
diff --git a/setuptools/dist.py b/setuptools/dist.py
index 30ff35e3..c1218ef2 100644
--- a/setuptools/dist.py
+++ b/setuptools/dist.py
@@ -8,7 +8,7 @@ from setuptools.command.install_lib import install_lib
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 @@ def check_nsp(dist, attr, value):
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 @@ def check_package_data(dist, attr, value):
"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 @@ class Distribution(_Distribution):
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)
]
diff --git a/setuptools/package_index.py b/setuptools/package_index.py
index da3fed12..70b75a6f 100755
--- a/setuptools/package_index.py
+++ b/setuptools/package_index.py
@@ -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 @@ try:
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 parse_bdist_wininst(name):
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 @@ def distros_for_location(location, basename, metadata=None):
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 @@ class PackageIndex(Environment):
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 @@ class PackageIndex(Environment):
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 @@ class PackageIndex(Environment):
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 @@ class PackageIndex(Environment):
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 @@ class PackageIndex(Environment):
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 @@ class PackageIndex(Environment):
(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 @@ class PackageIndex(Environment):
-
-
-
-
-
def gen_setup(self, filename, fragment, tmpdir):
match = EGG_FRAGMENT.match(fragment)
dists = match and [d for d in
@@ -573,17 +573,19 @@ class PackageIndex(Environment):
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 @@ class PackageIndex(Environment):
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)
diff --git a/setuptools/sandbox.py b/setuptools/sandbox.py
index 4db0dbdb..00eb0124 100755
--- a/setuptools/sandbox.py
+++ b/setuptools/sandbox.py
@@ -1,14 +1,46 @@
-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()
save_argv = sys.argv[:]
save_path = sys.path[:]
@@ -16,13 +48,16 @@ def run_setup(setup_script, args):
temp_dir = os.path.join(setup_dir,'temp')
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)
+ 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",
@@ -34,11 +69,17 @@ def run_setup(setup_script, args):
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]
os.chdir(old_dir)
sys.path[:] = save_path
sys.argv[:] = save_argv
tempfile.tempdir = save_tmp
+
+
class AbstractSandbox:
"""Wrap 'os' module and 'open()' builtin for virtualizing setup scripts"""
@@ -58,15 +99,16 @@ class AbstractSandbox:
"""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 @@ class AbstractSandbox:
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 @@ class AbstractSandbox:
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 @@ class AbstractSandbox:
]:
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 @@ class DirectorySandbox(AbstractSandbox):
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"""
diff --git a/version.dat b/version.dat
index 32144c8e..16ecd2aa 100755
--- a/version.dat
+++ b/version.dat
@@ -1,6 +1,6 @@
[setuptools]
status = 'release candidate'
major = 0
-build = 9
+build = 10
minor = 6