diff options
-rwxr-xr-x | EasyInstall.txt | 61 | ||||
-rwxr-xr-x | setuptools.txt | 36 | ||||
-rwxr-xr-x | setuptools/archive_util.py | 4 | ||||
-rw-r--r-- | setuptools/command/bdist_egg.py | 49 | ||||
-rwxr-xr-x | setuptools/command/easy_install.py | 218 | ||||
-rwxr-xr-x | setuptools/command/egg_info.py | 38 | ||||
-rw-r--r-- | setuptools/dist.py | 8 | ||||
-rwxr-xr-x | setuptools/package_index.py | 14 | ||||
-rwxr-xr-x | setuptools/sandbox.py | 4 |
9 files changed, 364 insertions, 68 deletions
diff --git a/EasyInstall.txt b/EasyInstall.txt index f3025f9f..c612c31b 100755 --- a/EasyInstall.txt +++ b/EasyInstall.txt @@ -268,6 +268,36 @@ below for a list of the standard configuration file locations, and links to more documentation on using distutils configuration files. +Dealing with Installation Conflicts +----------------------------------- + +EasyInstall installs distributions in a "managed" way, such that each +distribution can be independently activated or deactivated on ``sys.path``. +However, packages that were not installed by EasyInstall are "unmanaged", +in that they usually live all in one directory and cannot be independently +activated or deactivated. + +As a result, if you are using EasyInstall to upgrade an existing package, or +to install a package with the same name as an existing package, EasyInstall +will warn you of the conflict. (This is an improvement over ``setup.py +install``, becuase the ``distutils`` just install new packages on top of old +ones, possibly combining two unrelated packages or leaving behind modules that +have been deleted in the newer version of the package.) + +By default, EasyInstall will stop the installation if it detects a conflict +between an existing, "unmanaged" package, and a module or package in any of +the distributions you're installing. It will display a list of all of the +existing files and directories that would need to be deleted for the new +package to be able to function correctly. You can then either delete these +conflicting files and directories yourself and re-run EasyInstall, or you can +just use the ``--delete-conflicting`` or ``--ignore-conflicts-at-my-risk`` +options, as described under `Command-Line Options`_, below. + +Of course, once you've replaced all of your existing "unmanaged" packages with +versions managed by EasyInstall, you won't have any more conflicts to worry +about! + + Reference Manual ================ @@ -424,6 +454,23 @@ Command-Line Options every time you use EasyInstall (unless overridden on the command line) and thus may make startup slower. +``--delete-conflicting, -D`` (New in 0.5a9) + If you are replacing a package that was previously installed *without* + using EasyInstall, the old version may end up on ``sys.path`` before the + version being installed with EasyInstall. EasyInstall will normally abort + the installation of a package if it detects such a conflict, and ask you to + manually remove the conflicting files or directories. If you specify this + option, however, EasyInstall will attempt to delete the files or + directories itself, and then proceed with the installation. + +``--ignore-conflicts-at-my-risk`` (New in 0.5a9) + Ignore conflicting packages and proceed with installation anyway, even + though it means the package probably won't work properly. If the + conflicting package is in a directory you can't write to, this may be your + only option, but you will need to take more invasive measures to get the + installed package to work, like manually adding it to ``PYTHONPATH`` or to + ``sys.path`` at runtime. + ``--index-url=URL, -u URL`` (New in 0.4a1) Specifies the base URL of the Python Package Index. The default is http://www.python.org/pypi if not specified. When a package is requested @@ -495,6 +542,20 @@ Known Issues in Exemaker. So, don't use Exemaker to wrap ``easy_install.py``, or at any rate don't expect it to work with all packages. +0.5a9 + * EasyInstall now automatically detects when an "unmanaged" package or + module is going to be on ``sys.path`` ahead of a package you're installing, + thereby preventing the newer version from being imported. By default, it + will abort installation to alert you of the problem, but there are also + new options (``--delete-conflicting`` and ``--ignore-conflicts-at-my-risk``) + available to change the default behavior. (Note: this new feature doesn't + take effect for egg files that were built with older ``setuptools`` + versions, because they lack the new metadata file required to implement it.) + + * The ``easy_install`` distutils command now uses ``DistutilsError`` as its + base error type for errors that should just issue a message to stderr and + exit the program without a traceback. + 0.5a8 * There is now a separate documentation page for `setuptools`_; revision history that's not specific to EasyInstall has been moved to that page. diff --git a/setuptools.txt b/setuptools.txt index ae6a7c26..00affdbe 100755 --- a/setuptools.txt +++ b/setuptools.txt @@ -570,7 +570,7 @@ the new egg file's metadata directory, for use by the egg runtime system or by any applications or frameworks that use that metadata. You won't usually need to specify any special options for this command; just -use ``bdist_egg`` and you're done. But there are a couple of options that may +use ``bdist_egg`` and you're done. But there are a few options that may be occasionally useful: ``--dist-dir=DIR, -d DIR`` @@ -590,6 +590,19 @@ be occasionally useful: cross-compiling or doing some other unusual things, you might find a use for this option. +``--exclude-source-files`` + Don't include any modules' ``.py`` files in the egg, just compiled Python, + C, and data files. (Note that this doesn't affect any ``.py`` files in the + EGG-INFO directory or its subdirectories, since for example there may be + scripts with a ``.py`` extension which must still be retained.) We don't + recommend that you use this option except for packages that are being + bundled for proprietary end-user applications, or for "embedded" scenarios + where space is at an absolute premium. On the other hand, if your package + is going to be installed and used in compressed form, you might as well + exclude the source because Python's ``traceback`` module doesn't currently + understand how to display zipped source code anyway, or how to deal with + files that are in a different place from where their code was compiled. + There are also some options you will probably never need, but which are there because they were copied from similar ``bdist`` commands used as an example for creating this one. They may be useful for testing and debugging, however, @@ -726,8 +739,8 @@ to temporarily change the project's version string. The following options can be used to modify the project's version string for all remaining commands on the setup command line. The options are processed -in the order shown, so if you use more than one, the request tags will be added -in the following order: +in the order shown, so if you use more than one, the requested tags will be +added in the following order: ``--tag-build=NAME, -b NAME`` Append NAME to the project's version string. Due to the way setuptools @@ -1049,6 +1062,23 @@ Release Notes/Change History * Changed --tag-svn-revision to include an "r" in front of the revision number for better readability. + * Added ability to build eggs without including source files (except for any + scripts, of course), using the ``--exclude-source-files`` option to + ``bdist_egg``. + + * ``setup.py install`` now automatically detects when an "unmanaged" package + or module is going to be on ``sys.path`` ahead of a package being installed, + thereby preventing the newer version from being imported. If this occurs, + a warning message is output to ``sys.stderr``, but installation proceeds + anyway. The warning message informs the user what files or directories + need deleting, and advises them they can also use EasyInstall (with the + ``--delete-conflicting`` option) to do it automatically. + + * The ``egg_info`` command now adds a ``top_level.txt`` file to the metadata + directory that lists all top-level modules and packages in the distribution. + This is used by the ``easy_install`` command to find possibly-conflicting + "unmanaged" packages when installing the distribution. + 0.5a8 * The "egg_info" command now always sets the distribution metadata to "safe" forms of the distribution name and version, so that distribution files will diff --git a/setuptools/archive_util.py b/setuptools/archive_util.py index 4def0a70..d24c6c13 100755 --- a/setuptools/archive_util.py +++ b/setuptools/archive_util.py @@ -8,8 +8,9 @@ __all__ = [ import zipfile, tarfile, os from pkg_resources import ensure_directory +from distutils.errors import DistutilsError -class UnrecognizedFormat(RuntimeError): +class UnrecognizedFormat(DistutilsError): """Couldn't recognize the archive type""" def default_filter(src,dst): @@ -38,7 +39,6 @@ def default_filter(src,dst): - def unpack_archive(filename, extract_dir, progress_filter=default_filter, drivers=None ): diff --git a/setuptools/command/bdist_egg.py b/setuptools/command/bdist_egg.py index 74a2cd26..552bd7e8 100644 --- a/setuptools/command/bdist_egg.py +++ b/setuptools/command/bdist_egg.py @@ -49,6 +49,8 @@ class bdist_egg(Command): ('plat-name=', 'p', "platform name to embed in generated filenames " "(default: %s)" % get_platform()), + ('exclude-source-files', None, + "remove all .py files from the generated egg"), ('keep-temp', 'k', "keep the pseudo-installation tree around after " + "creating the distribution archive"), @@ -59,7 +61,7 @@ class bdist_egg(Command): ] boolean_options = [ - 'keep-temp', 'skip-build', + 'keep-temp', 'skip-build', 'exclude-source-files' ] @@ -78,8 +80,6 @@ class bdist_egg(Command): - - def initialize_options (self): self.bdist_dir = None self.plat_name = None @@ -87,7 +87,7 @@ class bdist_egg(Command): self.dist_dir = None self.skip_build = 0 self.egg_output = None - + self.exclude_source_files = None def finalize_options(self): @@ -227,6 +227,8 @@ class bdist_egg(Command): "Use the install_requires/extras_require setup() args instead." ) + if self.exclude_source_files: self.zap_pyfiles() + # Make the archive make_zipfile(self.egg_output, archive_root, verbose=self.verbose, dry_run=self.dry_run) @@ -242,6 +244,45 @@ class bdist_egg(Command): + def zap_pyfiles(self): + log.info("Removing .py files from temporary directory") + for base,dirs,files in os.walk(self.bdist_dir): + if 'EGG-INFO' in dirs: + dirs.remove('EGG-INFO') + for name in files: + if name.endswith('.py'): + path = os.path.join(base,name) + log.debug("Deleting %s", path) + os.unlink(path) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + # Attribute names of options for commands that might need to be convinced to diff --git a/setuptools/command/easy_install.py b/setuptools/command/easy_install.py index 9d61bb29..4ac6bac7 100755 --- a/setuptools/command/easy_install.py +++ b/setuptools/command/easy_install.py @@ -17,7 +17,7 @@ from setuptools import Command from setuptools.sandbox import run_setup from distutils import log, dir_util from distutils.sysconfig import get_python_lib -from distutils.errors import DistutilsArgError, DistutilsOptionError +from distutils.errors import DistutilsArgError, DistutilsOptionError, DistutilsError from setuptools.archive_util import unpack_archive from setuptools.package_index import PackageIndex, parse_bdist_wininst from setuptools.package_index import URL_SCHEME @@ -43,7 +43,9 @@ class easy_install(Command): """Manage a download/build/install process""" description = "Find/get/install Python packages" + command_consumes_arguments = True + user_options = [ ("zip-ok", "z", "install package as a zipfile"), ("multi-version", "m", "make apps have to require() a version"), @@ -54,6 +56,10 @@ class easy_install(Command): ("always-copy", "a", "Copy all needed packages to install dir"), ("index-url=", "i", "base URL of Python Package Index"), ("find-links=", "f", "additional URL(s) to search for packages"), + ("delete-conflicting", "D", "delete old packages that get in the way"), + ("ignore-conflicts-at-my-risk", None, + "install even if old packages are in the way, even though it " + "most likely means the new package won't work."), ("build-directory=", "b", "download/extract/build in DIR; keep the results"), ('optimize=', 'O', @@ -62,11 +68,18 @@ class easy_install(Command): ('record=', None, "filename in which to record list of installed files"), ] + boolean_options = [ - 'zip-ok', 'multi-version', 'exclude-scripts', 'upgrade', 'always-copy' + 'zip-ok', 'multi-version', 'exclude-scripts', 'upgrade', 'always-copy', + 'delete-conflicting', 'ignore-conflicts-at-my-risk', ] + create_index = PackageIndex + + + + def initialize_options(self): self.zip_ok = None self.install_dir = self.script_dir = self.exclude_scripts = None @@ -79,6 +92,34 @@ class easy_install(Command): # Options not specifiable via command line self.package_index = None self.pth_file = None + self.delete_conflicting = None + self.ignore_conflicts_at_my_risk = None + + + def delete_blockers(self, blockers): + for filename in blockers: + log.info("Deleting %s", filename) + if not self.dry_run: + if os.path.isdir(filename): + shutil.rmtree(filename) + else: + os.unlink(filename) + + + + + + + + + + + + + + + + def finalize_options(self): # If a non-default installation directory was specified, default the @@ -122,16 +163,13 @@ class easy_install(Command): self.index_url = self.index_url or "http://www.python.org/pypi" self.shadow_path = sys.path[:] - for path_item in self.install_dir, self.script_dir: if path_item not in self.shadow_path: self.shadow_path.insert(0, self.install_dir) - if self.package_index is None: self.package_index = self.create_index( self.index_url, search_path = self.shadow_path ) - self.local_index = AvailableDistributions(self.shadow_path) if self.find_links is not None: @@ -149,6 +187,11 @@ class easy_install(Command): except ValueError: raise DistutilsOptionError("--optimize must be 0, 1, or 2") + if self.delete_conflicting and self.ignore_conflicts_at_my_risk: + raise DistutilsOptionError( + "Can't use both --delete-conflicting and " + "--ignore-conflicts-at-my-risk at the same time" + ) if not self.args: raise DistutilsArgError( "No urls, filenames, or requirements specified (see --help)") @@ -160,8 +203,6 @@ class easy_install(Command): self.outputs = [] - - def alloc_tmp(self): if self.build_directory is None: return tempfile.mkdtemp(prefix="easy_install-") @@ -221,7 +262,7 @@ class easy_install(Command): try: spec = Requirement.parse(spec) except ValueError: - raise RuntimeError( + raise DistutilsError( "Not a URL, existing file, or requirement spec: %r" % (spec,) ) @@ -232,7 +273,7 @@ class easy_install(Command): spec = None if download is None: - raise RuntimeError( + raise DistutilsError( "Could not find distribution for %r" % spec ) @@ -254,7 +295,7 @@ class easy_install(Command): for dist in dists: self.process_distribution(spec, dist) else: - dists = [self.egg_distribution(download)] + dists = [self.check_conflicts(self.egg_distribution(download))] self.process_distribution(spec, dists[0], "Using") if spec is not None: for dist in dists: @@ -276,11 +317,11 @@ class easy_install(Command): [requirement], self.shadow_path, self.easy_install ) except DistributionNotFound, e: - raise RuntimeError( + raise DistutilsError( "Could not find required distribution %s" % e.args ) except VersionConflict, e: - raise RuntimeError( + raise DistutilsError( "Installed distribution %s conflicts with requirement %s" % e.args ) @@ -385,11 +426,11 @@ class easy_install(Command): if not os.path.exists(setup_script): setups = glob(os.path.join(tmpdir, '*', 'setup.py')) if not setups: - raise RuntimeError( + raise DistutilsError( "Couldn't find a setup script in %s" % dist_filename ) if len(setups)>1: - raise RuntimeError( + raise DistutilsError( "Multiple setup scripts in %s" % dist_filename ) setup_script = setups[0] @@ -418,10 +459,10 @@ class easy_install(Command): def install_egg(self, egg_path, zip_ok, tmpdir): destination = os.path.join(self.install_dir,os.path.basename(egg_path)) destination = os.path.abspath(destination) - if not self.dry_run: ensure_directory(destination) + self.check_conflicts(self.egg_distribution(egg_path)) if not samefile(egg_path, destination): if os.path.isdir(destination): dir_util.remove_tree(destination, dry_run=self.dry_run) @@ -453,7 +494,7 @@ class easy_install(Command): # See if it's valid, get data cfg = extract_wininst_cfg(dist_filename) if cfg is None: - raise RuntimeError( + raise DistutilsError( "%s is not a valid distutils Windows .exe" % dist_filename ) @@ -495,18 +536,23 @@ class easy_install(Command): # Check for .pth file and set up prefix translations prefixes = get_exe_prefixes(dist_filename) + to_compile = [] native_libs = [] + top_level = {} def process(src,dst): for old,new in prefixes: if src.startswith(old): src = new+src[len(old):] - dst = os.path.join(egg_tmp, *src.split('/')) + parts = src.split('/') + dst = os.path.join(egg_tmp, *parts) dl = dst.lower() if dl.endswith('.pyd') or dl.endswith('.dll'): + top_level[os.path.splitext(parts[0])[0]] = 1 native_libs.append(src) elif dl.endswith('.py') and old!='SCRIPTS/': + top_level[os.path.splitext(parts[0])[0]] = 1 to_compile.append(dst) return dst if not src.endswith('.pth'): @@ -526,10 +572,87 @@ class easy_install(Command): self.byte_compile(to_compile) # compile .py's - if native_libs: # write EGG-INFO/native_libs.txt - nl_txt = os.path.join(egg_tmp, 'EGG-INFO', 'native_libs.txt') - ensure_directory(nl_txt) - open(nl_txt,'w').write('\n'.join(native_libs)+'\n') + for name in 'top_level','native_libs': + if locals()[name]: + txt = os.path.join(egg_tmp, 'EGG-INFO', name+'.txt') + ensure_directory(txt) + open(txt,'w').write('\n'.join(locals()[name])+'\n') + + def check_conflicts(self, dist): + """Verify that there are no conflicting "old-style" packages""" + + from imp import find_module, get_suffixes + from glob import glob + + blockers = [] + names = dict.fromkeys(dist._get_metadata('top_level.txt')) # XXX private attr + + exts = {'.pyc':1, '.pyo':1} # get_suffixes() might leave one out + for ext,mode,typ in get_suffixes(): + exts[ext] = 1 + + for path,files in expand_paths([self.install_dir, get_python_lib()]): + for filename in files: + base,ext = os.path.splitext(filename) + if base in names: + if not ext: + # no extension, check for package + try: + f, filename, descr = find_module(base, [path]) + except ImportError: + continue + else: + if f: f.close() + if filename not in blockers: + blockers.append(filename) + elif ext in exts: + blockers.append(os.path.join(path,filename)) + + if blockers: + self.found_conflicts(dist, blockers) + + return dist + + def found_conflicts(self, dist, blockers): + if self.delete_conflicting: + log.warn("Attempting to delete conflicting packages:") + return self.delete_blockers(blockers) + + msg = """\ +------------------------------------------------------------------------- +CONFLICT WARNING: + +The following modules or packages have the same names as modules or +packages being installed, and will be *before* the installed packages in +Python's search path. You MUST remove all of the relevant files and +directories before you will be able to use the package(s) you are +installing: + + %s + +""" % '\n '.join(blockers) + + if self.ignore_conflicts_at_my_risk: + msg += """\ +(Note: you can run EasyInstall on '%s' with the +--delete-conflicting option to attempt deletion of the above files +and/or directories.) +""" % dist.name + else: + msg += """\ +Note: you can attempt this installation again with EasyInstall, and use +either the --delete-conflicting (-D) option or the +--ignore-conflicts-at-my-risk option, to either delete the above files +and directories, or to ignore the conflicts, respectively. Note that if +you ignore the conflicts, the installed package(s) may not work. +""" + msg += """\ +------------------------------------------------------------------------- +""" + sys.stderr.write(msg) + sys.stderr.flush() + if not self.ignore_conflicts_at_my_risk: + raise DistutilsError("Installation aborted due to conflicts") def installation_report(self, dist, what="Installed"): """Helpful installation message for display to package users""" @@ -589,7 +712,7 @@ PYTHONPATH, or by being added to sys.path by your code.) try: run_setup(setup_script, args) except SystemExit, v: - raise RuntimeError( + raise DistutilsError( "Setup script exited with %s" % (v.args[0],) ) finally: @@ -695,6 +818,47 @@ PYTHONPATH, or by being added to sys.path by your code.) +def expand_paths(inputs): + """Yield sys.path directories that might contain "old-style" packages""" + + seen = {} + + for dirname in inputs: + if dirname in seen: + continue + + seen[dirname] = 1 + if not os.path.isdir(dirname): + continue + + files = os.listdir(dirname) + yield dirname, files + + for name in files: + if not name.endswith('.pth'): + # We only care about the .pth files + continue + if name in ('easy-install.pth','setuptools.pth'): + # Ignore .pth files that we control + continue + + # Read the .pth file + f = open(os.path.join(dirname,name)) + lines = list(yield_lines(f)) + f.close() + + # Yield existing non-dupe, non-import directory lines from it + for line in lines: + if not line.startswith("import"): + line = line.rstrip() + if line not in seen: + seen[line] = 1 + if not os.path.isdir(line): + continue + yield line, os.listdir(line) + + + def extract_wininst_cfg(dist_filename): """Extract configuration data from a bdist_wininst .exe @@ -820,11 +984,11 @@ class PthDistributions(AvailableDistributions): def main(argv, **kw): from setuptools import setup - try: - setup(script_args = ['-q','easy_install', '-v']+argv, **kw) - except RuntimeError, v: - print >>sys.stderr,"error:",v - sys.exit(1) + setup(script_args = ['-q','easy_install', '-v']+argv, **kw) + + + + diff --git a/setuptools/command/egg_info.py b/setuptools/command/egg_info.py index 907e47fb..dca4e2a3 100755 --- a/setuptools/command/egg_info.py +++ b/setuptools/command/egg_info.py @@ -97,6 +97,7 @@ class egg_info(Command): metadata.name, metadata.version = oldname, oldver self.write_requirements() + self.write_toplevel_names() if os.path.exists(os.path.join(self.egg_info,'depends.txt')): log.warn( "WARNING: 'depends.txt' will not be used by setuptools 0.6!\n" @@ -106,7 +107,6 @@ class egg_info(Command): def write_requirements(self): dist = self.distribution - if not getattr(dist,'install_requires',None) and \ not getattr(dist,'extras_require',None): return @@ -125,14 +125,11 @@ class egg_info(Command): version = self.distribution.get_version() if self.tag_build: version+=self.tag_build - if self.tag_svn_revision and os.path.exists('.svn'): version += '-r%s' % self.get_svn_revision() - if self.tag_date: import time version += time.strftime("-%Y%m%d") - return safe_version(version) @@ -142,23 +139,26 @@ class egg_info(Command): import re match = re.search(r'Last Changed Rev: (\d+)', result) if not match: - raise RuntimeError("svn info error: %s" % result.strip()) + raise DistutilsError("svn info error: %s" % result.strip()) return match.group(1) - - - - - - - - - - - - - - + def write_toplevel_names(self): + pkgs = dict.fromkeys(self.distribution.packages or ()) + pkgs.update(dict.fromkeys(self.distribution.py_modules or ())) + for ext in self.distribution.ext_modules or (): + if isinstance(ext,tuple): + name,buildinfo = ext + else: + name = ext.name + pkgs[name]=1 + pkgs = dict.fromkeys([k.split('.',1)[0] for k in pkgs]) + toplevel = os.path.join(self.egg_info,"top_level.txt") + log.info("writing list of top-level names to %s" % toplevel) + if not self.dry_run: + f = open(toplevel, 'wt') + f.write('\n'.join(pkgs)) + f.write('\n') + f.close() diff --git a/setuptools/dist.py b/setuptools/dist.py index 8fcd19ea..4fef454f 100644 --- a/setuptools/dist.py +++ b/setuptools/dist.py @@ -420,13 +420,16 @@ class Distribution(_Distribution): def install_eggs(self): from setuptools.command.easy_install import easy_install - cmd = easy_install(self, args="x") + cmd = easy_install(self, args="x", ignore_conflicts_at_my_risk=1) cmd.ensure_finalized() # finalize before bdist_egg munges install cmd + self.run_command('bdist_egg') args = [self.get_command_obj('bdist_egg').egg_output] + if setuptools.bootstrap_install_from: # Bootstrap self-installation of setuptools args.insert(0, setuptools.bootstrap_install_from) + cmd.args = args cmd.run() self.have_run['install'] = 1 @@ -446,9 +449,6 @@ class Distribution(_Distribution): - - - def get_cmdline_options(self): """Return a '{cmd: {opt:val}}' map of all command-line options diff --git a/setuptools/package_index.py b/setuptools/package_index.py index 0a8ccddc..21d37cf9 100755 --- a/setuptools/package_index.py +++ b/setuptools/package_index.py @@ -3,6 +3,7 @@ import sys, os.path, re, urlparse, urllib2 from pkg_resources import * from distutils import log +from distutils.errors import DistutilsError HREF = re.compile(r"""href\s*=\s*['"]?([^'"> ]+)""", re.I) URL_SCHEME = re.compile('([-+.a-z0-9]{2,}):',re.I).match @@ -38,7 +39,6 @@ def parse_bdist_wininst(name): - def distros_for_url(url, metadata=None): """Yield egg or source distribution objects that might be found at a URL""" @@ -272,7 +272,7 @@ class PackageIndex(AvailableDistributions): try: spec = Requirement.parse(spec) except ValueError: - raise RuntimeError( + raise DistutilsError( "Not a URL, existing file, or requirement spec: %r" % (spec,) ) @@ -336,7 +336,7 @@ class PackageIndex(AvailableDistributions): try: fp = self.open_url(url) if isinstance(fp, urllib2.HTTPError): - raise RuntimeError( + raise DistutilsError( "Can't download %s: %s %s" % (url, fp.code,fp.msg) ) @@ -373,7 +373,7 @@ class PackageIndex(AvailableDistributions): except urllib2.HTTPError, v: return v except urllib2.URLError, v: - raise RuntimeError("Download error: %s" % v.reason) + raise DistutilsError("Download error: %s" % v.reason) def _download_url(self, scheme, url, tmpdir): @@ -432,7 +432,7 @@ class PackageIndex(AvailableDistributions): return self._download_sourceforge(url, page, tmpdir) break # not an index page file.close() - raise RuntimeError("Unexpected HTML page found at "+url) + raise DistutilsError("Unexpected HTML page found at "+url) def _download_svn(self, url, filename): @@ -457,7 +457,7 @@ class PackageIndex(AvailableDistributions): mirror_regex = re.compile(r'HREF=(/.*?\?use_mirror=[^>]*)') urls = [m.group(1) for m in mirror_regex.finditer(sf_page)] if not urls: - raise RuntimeError( + raise DistutilsError( "URL looks like a Sourceforge mirror page, but no URLs found" ) @@ -481,7 +481,7 @@ class PackageIndex(AvailableDistributions): scheme = URL_SCHEME(download_url) return self._download_url(scheme.group(1), download_url, tmpdir) else: - raise RuntimeError( + raise DistutilsError( 'No META HTTP-EQUIV="refresh" found in Sourceforge page at %s' % url ) diff --git a/setuptools/sandbox.py b/setuptools/sandbox.py index 8aa58f8d..f124289a 100755 --- a/setuptools/sandbox.py +++ b/setuptools/sandbox.py @@ -1,7 +1,7 @@ import os, sys, __builtin__, tempfile _os = sys.modules[os.name] _open = open - +from distutils.errors import DistutilsError __all__ = [ "AbstractSandbox", "DirectorySandbox", "SandboxViolation", "run_setup", ] @@ -188,7 +188,7 @@ class DirectorySandbox(AbstractSandbox): return (src,dst) -class SandboxViolation(RuntimeError): +class SandboxViolation(DistutilsError): """A setup script attempted to modify the filesystem outside the sandbox""" def __str__(self): |