diff options
Diffstat (limited to 'setuptools/command')
| -rw-r--r-- | setuptools/command/__init__.py | 6 | ||||
| -rw-r--r-- | setuptools/command/build_py.py | 101 | ||||
| -rwxr-xr-x | setuptools/command/easy_install.py | 599 | ||||
| -rwxr-xr-x | setuptools/command/egg_info.py | 118 | ||||
| -rw-r--r-- | setuptools/command/install.py | 29 | ||||
| -rwxr-xr-x | setuptools/command/sdist.py | 48 | ||||
| -rwxr-xr-x | setuptools/command/upload.py | 184 | ||||
| -rw-r--r-- | setuptools/command/upload_docs.py | 24 |
8 files changed, 330 insertions, 779 deletions
diff --git a/setuptools/command/__init__.py b/setuptools/command/__init__.py index b063fa19..29c9d75a 100644 --- a/setuptools/command/__init__.py +++ b/setuptools/command/__init__.py @@ -1,17 +1,13 @@ __all__ = [ 'alias', 'bdist_egg', 'bdist_rpm', 'build_ext', 'build_py', 'develop', 'easy_install', 'egg_info', 'install', 'install_lib', 'rotate', 'saveopts', - 'sdist', 'setopt', 'test', 'upload', 'install_egg_info', 'install_scripts', + 'sdist', 'setopt', 'test', 'install_egg_info', 'install_scripts', 'register', 'bdist_wininst', 'upload_docs', ] from setuptools.command import install_scripts import sys -if sys.version>='2.5': - # In Python 2.5 and above, distutils includes its own upload command - __all__.remove('upload') - from distutils.command.bdist import bdist if 'egg' not in bdist.format_commands: diff --git a/setuptools/command/build_py.py b/setuptools/command/build_py.py index 8751acd4..090b44d2 100644 --- a/setuptools/command/build_py.py +++ b/setuptools/command/build_py.py @@ -1,64 +1,17 @@ -import os.path, sys, fnmatch +import os +import sys +import fnmatch +import textwrap from distutils.command.build_py import build_py as _build_py from distutils.util import convert_path from glob import glob try: - from distutils.util import Mixin2to3 as _Mixin2to3 - # add support for converting doctests that is missing in 3.1 distutils - from distutils import log - from lib2to3.refactor import RefactoringTool, get_fixers_from_package - import setuptools - class DistutilsRefactoringTool(RefactoringTool): - def log_error(self, msg, *args, **kw): - log.error(msg, *args) - - def log_message(self, msg, *args): - log.info(msg, *args) - - def log_debug(self, msg, *args): - log.debug(msg, *args) - - class Mixin2to3(_Mixin2to3): - def run_2to3(self, files, doctests = False): - # See of the distribution option has been set, otherwise check the - # setuptools default. - if self.distribution.use_2to3 is not True: - return - if not files: - return - log.info("Fixing "+" ".join(files)) - self.__build_fixer_names() - self.__exclude_fixers() - if doctests: - if setuptools.run_2to3_on_doctests: - r = DistutilsRefactoringTool(self.fixer_names) - r.refactor(files, write=True, doctests_only=True) - else: - _Mixin2to3.run_2to3(self, files) - - def __build_fixer_names(self): - if self.fixer_names: return - self.fixer_names = [] - for p in setuptools.lib2to3_fixer_packages: - self.fixer_names.extend(get_fixers_from_package(p)) - if self.distribution.use_2to3_fixers is not None: - for p in self.distribution.use_2to3_fixers: - self.fixer_names.extend(get_fixers_from_package(p)) - - def __exclude_fixers(self): - excluded_fixers = getattr(self, 'exclude_fixers', []) - if self.distribution.use_2to3_exclude_fixers is not None: - excluded_fixers.extend(self.distribution.use_2to3_exclude_fixers) - for fixer_name in excluded_fixers: - if fixer_name in self.fixer_names: - self.fixer_names.remove(fixer_name) - + from setuptools.lib2to3_ex import Mixin2to3 except ImportError: class Mixin2to3: def run_2to3(self, files, doctests=True): - # Nothing done in 2.x - pass + "do nothing" class build_py(_build_py, Mixin2to3): """Enhanced 'build_py' command that includes data files with packages @@ -97,9 +50,10 @@ class build_py(_build_py, Mixin2to3): # output files are. self.byte_compile(_build_py.get_outputs(self, include_bytecode=0)) - def __getattr__(self,attr): + def __getattr__(self, attr): if attr=='data_files': # lazily compute data files - self.data_files = files = self._get_data_files(); return files + self.data_files = files = self._get_data_files() + return files return _build_py.__getattr__(self,attr) def build_module(self, module, module_file, package): @@ -126,7 +80,7 @@ class build_py(_build_py, Mixin2to3): filenames = [ file[plen:] for file in self.find_data_files(package, src_dir) ] - data.append( (package, src_dir, build_dir, filenames) ) + data.append((package, src_dir, build_dir, filenames)) return data def find_data_files(self, package, src_dir): @@ -141,7 +95,6 @@ class build_py(_build_py, Mixin2to3): def build_package_data(self): """Copy data files into build directory""" - lastdir = None for package, src_dir, build_dir, filenames in self.data_files: for filename in filenames: target = os.path.join(build_dir, filename) @@ -152,7 +105,6 @@ class build_py(_build_py, Mixin2to3): if copied and srcfile in self.distribution.convert_2to3_doctests: self.__doctests_2to3.append(outf) - def analyze_manifest(self): self.manifest_files = mf = {} if not self.distribution.include_package_data: @@ -217,10 +169,10 @@ class build_py(_build_py, Mixin2to3): if 'declare_namespace'.encode() not in f.read(): from distutils import log log.warn( - "WARNING: %s is a namespace package, but its __init__.py does\n" - "not declare_namespace(); setuptools 0.7 will REQUIRE this!\n" - '(See the setuptools manual under "Namespace Packages" for ' - "details.)\n", package + "WARNING: %s is a namespace package, but its __init__.py does\n" + "not declare_namespace(); setuptools 0.7 will REQUIRE this!\n" + '(See the setuptools manual under "Namespace Packages" for ' + "details.)\n", package ) f.close() return init_py @@ -229,14 +181,12 @@ class build_py(_build_py, Mixin2to3): self.packages_checked={} _build_py.initialize_options(self) - def get_package_dir(self, package): res = _build_py.get_package_dir(self, package) if self.distribution.src_root is not None: return os.path.join(self.distribution.src_root, res) return res - def exclude_data_files(self, package, src_dir, files): """Filter filenames for package's data files in 'src_dir'""" globs = (self.exclude_package_data.get('', []) @@ -260,21 +210,12 @@ def assert_relative(path): if not os.path.isabs(path): return path from distutils.errors import DistutilsSetupError - raise DistutilsSetupError( -"""Error: setup script specifies an absolute path: - - %s - -setup() arguments must *always* be /-separated paths relative to the -setup.py directory, *never* absolute paths. -""" % path - ) - - - - - - - + msg = textwrap.dedent(""" + Error: setup script specifies an absolute path: + %s + setup() arguments must *always* be /-separated paths relative to the + setup.py directory, *never* absolute paths. + """).lstrip() % path + raise DistutilsSetupError(msg) diff --git a/setuptools/command/easy_install.py b/setuptools/command/easy_install.py index 3194644e..08ebf3e5 100755 --- a/setuptools/command/easy_install.py +++ b/setuptools/command/easy_install.py @@ -1,5 +1,6 @@ -#!python -"""\ +#!/usr/bin/env python + +""" Easy Install ------------ @@ -10,6 +11,7 @@ file, or visit the `EasyInstall home page`__. __ https://pythonhosted.org/setuptools/easy_install.html """ + import sys import os import zipimport @@ -20,24 +22,17 @@ import re import stat import random import platform +import textwrap +import warnings +import site +import struct from glob import glob +from distutils import log, dir_util + import pkg_resources from setuptools import Command, _dont_write_bytecode from setuptools.sandbox import run_setup -from distutils import log, dir_util -try: - # Python 2.7 or >=3.2 - from sysconfig import get_config_vars, get_path - def _get_platlib(): - return get_path("platlib") - def _get_purelib(): - return get_path("purelib") -except ImportError: - from distutils.sysconfig import get_config_vars, get_python_lib - def _get_platlib(): - return get_python_lib(True) - def _get_purelib(): - return get_python_lib(False) +from setuptools.py31compat import get_path, get_config_vars from distutils.util import get_platform from distutils.util import convert_path, subst_vars @@ -49,41 +44,34 @@ from setuptools.archive_util import unpack_archive from setuptools.package_index import PackageIndex from setuptools.package_index import URL_SCHEME from setuptools.command import bdist_egg, egg_info -from setuptools.compat import (iteritems, maxsize, xrange, basestring, unicode, +from setuptools.compat import (iteritems, maxsize, basestring, unicode, reraise) -from pkg_resources import yield_lines, normalize_path, resource_string, \ - ensure_directory, get_distribution, find_distributions, \ - Environment, Requirement, Distribution, \ - PathMetadata, EggMetadata, WorkingSet, \ - DistributionNotFound, VersionConflict, \ - DEVELOP_DIST - -if '__VENV_LAUNCHER__' in os.environ: - sys_executable = os.environ['__VENV_LAUNCHER__'] -else: - sys_executable = os.path.normpath(sys.executable) +from pkg_resources import ( + yield_lines, normalize_path, resource_string, ensure_directory, + get_distribution, find_distributions, Environment, Requirement, + Distribution, PathMetadata, EggMetadata, WorkingSet, DistributionNotFound, + VersionConflict, DEVELOP_DIST, +) + +sys_executable = os.environ.get('__VENV_LAUNCHER__', + os.path.normpath(sys.executable)) __all__ = [ 'samefile', 'easy_install', 'PthDistributions', 'extract_wininst_cfg', 'main', 'get_exe_prefixes', ] -import site -HAS_USER_SITE = not sys.version < "2.6" and site.ENABLE_USER_SITE - -import struct def is_64bit(): return struct.calcsize("P") == 8 -def samefile(p1,p2): - if hasattr(os.path,'samefile') and ( - os.path.exists(p1) and os.path.exists(p2) - ): - return os.path.samefile(p1,p2) - return ( - os.path.normpath(os.path.normcase(p1)) == - os.path.normpath(os.path.normcase(p2)) - ) +def samefile(p1, p2): + both_exist = os.path.exists(p1) and os.path.exists(p2) + use_samefile = hasattr(os.path, 'samefile') and both_exist + if use_samefile: + return os.path.samefile(p1, p2) + norm_p1 = os.path.normpath(os.path.normcase(p1)) + norm_p2 = os.path.normpath(os.path.normcase(p2)) + return norm_p1 == norm_p2 if sys.version_info <= (3,): def _to_ascii(s): @@ -120,43 +108,40 @@ 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", "no longer needed; don't use this"), - ("ignore-conflicts-at-my-risk", None, - "no longer needed; don't use this"), ("build-directory=", "b", "download/extract/build in DIR; keep the results"), ('optimize=', 'O', - "also compile with optimization: -O1 for \"python -O\", " - "-O2 for \"python -OO\", and -O0 to disable [default: -O0]"), + "also compile with optimization: -O1 for \"python -O\", " + "-O2 for \"python -OO\", and -O0 to disable [default: -O0]"), ('record=', None, - "filename in which to record list of installed files"), + "filename in which to record list of installed files"), ('always-unzip', 'Z', "don't install as a zipfile, no matter what"), ('site-dirs=','S',"list of directories where .pth files work"), ('editable', 'e', "Install specified packages in editable form"), ('no-deps', 'N', "don't install dependencies"), ('allow-hosts=', 'H', "pattern(s) that hostnames must match"), - ('local-snapshots-ok', 'l', "allow building eggs from local checkouts"), + ('local-snapshots-ok', 'l', + "allow building eggs from local checkouts"), ('version', None, "print version information and exit"), ('no-find-links', None, - "Don't load find-links defined in packages being installed") + "Don't load find-links defined in packages being installed") ] boolean_options = [ 'zip-ok', 'multi-version', 'exclude-scripts', 'upgrade', 'always-copy', - 'delete-conflicting', 'ignore-conflicts-at-my-risk', 'editable', + 'editable', 'no-deps', 'local-snapshots-ok', 'version' ] - if HAS_USER_SITE: - user_options.append(('user', None, - "install in user site-package '%s'" % site.USER_SITE)) + if site.ENABLE_USER_SITE: + help_msg = "install in user site-package '%s'" % site.USER_SITE + user_options.append(('user', None, help_msg)) boolean_options.append('user') - negative_opt = {'always-unzip': 'zip-ok'} create_index = PackageIndex def initialize_options(self): - if HAS_USER_SITE: + if site.ENABLE_USER_SITE: whereami = os.path.abspath(__file__) self.user = whereami.startswith(site.USER_SITE) else: @@ -181,7 +166,7 @@ class easy_install(Command): self.install_data = None self.install_base = None self.install_platbase = None - if HAS_USER_SITE: + if site.ENABLE_USER_SITE: self.install_userbase = site.USER_BASE self.install_usersite = site.USER_SITE else: @@ -192,8 +177,6 @@ class easy_install(Command): # Options not specifiable via command line self.package_index = None self.pth_file = self.always_copy_from = None - self.delete_conflicting = None - self.ignore_conflicts_at_my_risk = None self.site_dirs = None self.installed_projects = {} self.sitepy_installed = False @@ -226,27 +209,28 @@ class easy_install(Command): py_version = sys.version.split()[0] prefix, exec_prefix = get_config_vars('prefix', 'exec_prefix') - self.config_vars = {'dist_name': self.distribution.get_name(), - 'dist_version': self.distribution.get_version(), - 'dist_fullname': self.distribution.get_fullname(), - 'py_version': py_version, - 'py_version_short': py_version[0:3], - 'py_version_nodot': py_version[0] + py_version[2], - 'sys_prefix': prefix, - 'prefix': prefix, - 'sys_exec_prefix': exec_prefix, - 'exec_prefix': exec_prefix, - # Only python 3.2+ has abiflags - 'abiflags': getattr(sys, 'abiflags', ''), - } - - if HAS_USER_SITE: + self.config_vars = { + 'dist_name': self.distribution.get_name(), + 'dist_version': self.distribution.get_version(), + 'dist_fullname': self.distribution.get_fullname(), + 'py_version': py_version, + 'py_version_short': py_version[0:3], + 'py_version_nodot': py_version[0] + py_version[2], + 'sys_prefix': prefix, + 'prefix': prefix, + 'sys_exec_prefix': exec_prefix, + 'exec_prefix': exec_prefix, + # Only python 3.2+ has abiflags + 'abiflags': getattr(sys, 'abiflags', ''), + } + + if site.ENABLE_USER_SITE: self.config_vars['userbase'] = self.install_userbase self.config_vars['usersite'] = self.install_usersite # fix the install_dir if "--user" was used #XXX: duplicate of the code in the setup command - if self.user and HAS_USER_SITE: + if self.user and site.ENABLE_USER_SITE: self.create_home_path() if self.install_userbase is None: raise DistutilsPlatformError( @@ -336,11 +320,6 @@ 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 self.editable and not self.build_directory: raise DistutilsArgError( "Must specify a build directory (-b) when using --editable" @@ -351,7 +330,6 @@ class easy_install(Command): self.outputs = [] - def _expand_attrs(self, attrs): for attr in attrs: val = getattr(self, attr) @@ -382,7 +360,7 @@ class easy_install(Command): outputs = self.outputs if self.root: # strip any package prefix root_len = len(self.root) - for counter in xrange(len(outputs)): + for counter in range(len(outputs)): outputs[counter] = outputs[counter][root_len:] from distutils import file_util self.execute( @@ -406,12 +384,7 @@ class easy_install(Command): return os.path.join(self.install_dir, "test-easy-install-%s" % pid) def warn_deprecated_options(self): - if self.delete_conflicting or self.ignore_conflicts_at_my_risk: - log.warn( - "Note: The -D, --delete-conflicting and" - " --ignore-conflicts-at-my-risk no longer have any purpose" - " and should not be used." - ) + pass def check_site_dir(self): """Verify that self.install_dir is .pth-capable dir, if needed""" @@ -456,7 +429,7 @@ class easy_install(Command): self.install_dir = instdir def cant_write_to_target(self): - msg = """can't create or remove files in install directory + template = """can't create or remove files in install directory The following error occurred while trying to add or remove files in the installation directory: @@ -467,7 +440,8 @@ The installation directory you specified (via --install-dir, --prefix, or the distutils default setting) was: %s -""" % (sys.exc_info()[1], self.install_dir,) +""" + msg = template % (sys.exc_info()[1], self.install_dir,) if not os.path.exists(self.install_dir): msg += """ @@ -493,9 +467,6 @@ Please make the appropriate changes for your system and try again. """ raise DistutilsError(msg) - - - def check_pth_processing(self): """Empirically verify whether .pth files are supported in inst. dir""" instdir = self.install_dir @@ -514,7 +485,8 @@ Please make the appropriate changes for your system and try again. else: try: f.write("import os; f = open(%r, 'w'); f.write('OK'); f.close()\n" % (ok_file,)) - f.close(); f=None + f.close() + f=None executable = sys.executable if os.name=='nt': dirname,basename = os.path.split(executable) @@ -533,9 +505,12 @@ Please make the appropriate changes for your system and try again. ) return True finally: - if f: f.close() - if os.path.exists(ok_file): os.unlink(ok_file) - if os.path.exists(pth_file): os.unlink(pth_file) + if f: + f.close() + if os.path.exists(ok_file): + os.unlink(ok_file) + if os.path.exists(pth_file): + os.unlink(pth_file) if not self.multi_version: log.warn("TEST FAILED: %s does NOT support .pth files", instdir) return False @@ -580,11 +555,6 @@ Please make the appropriate changes for your system and try again. (spec.key, self.build_directory) ) - - - - - def easy_install(self, spec, deps=False): tmpdir = tempfile.mkdtemp(prefix="easy_install-") download = None @@ -654,7 +624,7 @@ Please make the appropriate changes for your system and try again. for dist in dists: self.process_distribution(spec, dist, deps) else: - dists = [self.check_conflicts(self.egg_distribution(download))] + dists = [self.egg_distribution(download)] self.process_distribution(spec, dists[0], deps, "Using") if spec is not None: @@ -662,8 +632,6 @@ Please make the appropriate changes for your system and try again. if dist in spec: return dist - - def select_scheme(self, name): """Sets the install directories by applying the install schemes.""" # it's the caller's problem if they supply a bad name! @@ -673,9 +641,6 @@ Please make the appropriate changes for your system and try again. if getattr(self, attrname) is None: setattr(self, attrname, scheme[key]) - - - def process_distribution(self, requirement, dist, deps=True, *info): self.update_pth(dist) self.package_index.add(dist) @@ -684,7 +649,7 @@ Please make the appropriate changes for your system and try again. self.installed_projects[dist.key] = dist log.info(self.installation_report(requirement, dist, *info)) if (dist.has_metadata('dependency_links.txt') and - not self.no_find_links): + not self.no_find_links): self.package_index.add_find_links( dist.get_metadata_lines('dependency_links.txt') ) @@ -735,10 +700,8 @@ Please make the appropriate changes for your system and try again. def maybe_move(self, spec, dist_filename, setup_base): dst = os.path.join(self.build_directory, spec.key) if os.path.exists(dst): - log.warn( - "%r already exists in %s; build directory %s will not be kept", - spec.key, self.build_directory, setup_base - ) + msg = "%r already exists in %s; build directory %s will not be kept" + log.warn(msg, spec.key, self.build_directory, setup_base) return setup_base if os.path.isdir(dist_filename): setup_base = dist_filename @@ -751,7 +714,8 @@ Please make the appropriate changes for your system and try again. if os.path.isdir(dist_filename): # if the only thing there is a directory, move it instead setup_base = dist_filename - ensure_directory(dst); shutil.move(setup_base, dst) + ensure_directory(dst) + shutil.move(setup_base, dst) return dst def install_wrapper_scripts(self, dist): @@ -759,8 +723,6 @@ Please make the appropriate changes for your system and try again. for args in get_script_args(dist): self.write_script(*args) - - def install_script(self, dist, script_name, script_text, dev_path=None): """Generate a legacy script wrapper and install it""" spec = str(dist.as_requirement()) @@ -799,14 +761,13 @@ Please make the appropriate changes for your system and try again. mask = current_umask() if not self.dry_run: ensure_directory(target) + if os.path.exists(target): + os.unlink(target) f = open(target,"w"+mode) f.write(contents) f.close() chmod(target, 0x1FF-mask) # 0777 - - - def install_eggs(self, spec, dist_filename, tmpdir): # .egg dirs or files are already built, so just return them if dist_filename.lower().endswith('.egg'): @@ -822,8 +783,7 @@ Please make the appropriate changes for your system and try again. setup_base = os.path.abspath(dist_filename) if (setup_base.startswith(tmpdir) # something we downloaded - and self.build_directory and spec is not None - ): + and self.build_directory and spec is not None): setup_base = self.maybe_move(spec, dist_filename, setup_base) # Find the setup.py file @@ -862,7 +822,6 @@ Please make the appropriate changes for your system and try again. ensure_directory(destination) dist = self.egg_distribution(egg_path) - self.check_conflicts(dist) if not samefile(egg_path, destination): if os.path.isdir(destination) and not os.path.islink(destination): dir_util.remove_tree(destination, dry_run=self.dry_run) @@ -897,18 +856,19 @@ Please make the appropriate changes for your system and try again. "%s is not a valid distutils Windows .exe" % dist_filename ) # Create a dummy distribution object until we build the real distro - dist = Distribution(None, + dist = Distribution( + None, project_name=cfg.get('metadata','name'), - version=cfg.get('metadata','version'), platform=get_platform() + version=cfg.get('metadata','version'), platform=get_platform(), ) # Convert the .exe to an unpacked egg egg_path = dist.location = os.path.join(tmpdir, dist.egg_name()+'.egg') - egg_tmp = egg_path+'.tmp' - egg_info = os.path.join(egg_tmp, 'EGG-INFO') - pkg_inf = os.path.join(egg_info, 'PKG-INFO') + egg_tmp = egg_path + '.tmp' + _egg_info = os.path.join(egg_tmp, 'EGG-INFO') + pkg_inf = os.path.join(_egg_info, 'PKG-INFO') ensure_directory(pkg_inf) # make sure EGG-INFO dir exists - dist._provider = PathMetadata(egg_tmp, egg_info) # XXX + dist._provider = PathMetadata(egg_tmp, _egg_info) # XXX self.exe_to_egg(dist_filename, egg_tmp) # Write EGG-INFO/PKG-INFO @@ -919,7 +879,7 @@ Please make the appropriate changes for your system and try again. if k != 'target_version': f.write('%s: %s\n' % (k.replace('_','-').title(), v)) f.close() - script_dir = os.path.join(egg_info,'scripts') + script_dir = os.path.join(_egg_info,'scripts') self.delete_blockers( # delete entry-point scripts to avoid duping [os.path.join(script_dir,args[0]) for args in get_script_args(dist)] ) @@ -965,7 +925,8 @@ Please make the appropriate changes for your system and try again. resource = parts[-1] parts[-1] = bdist_egg.strip_module(parts[-1])+'.py' pyfile = os.path.join(egg_tmp, *parts) - to_compile.append(pyfile); stubs.append(pyfile) + to_compile.append(pyfile) + stubs.append(pyfile) bdist_egg.write_stub(resource, pyfile) self.byte_compile(to_compile) # compile .py's bdist_egg.write_safety_flag(os.path.join(egg_tmp,'EGG-INFO'), @@ -979,82 +940,6 @@ Please make the appropriate changes for your system and try again. f.write('\n'.join(locals()[name])+'\n') f.close() - def check_conflicts(self, dist): - """Verify that there are no conflicting "old-style" packages""" - - return dist # XXX temporarily disable until new strategy is stable - 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]+self.all_site_dirs): - 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 and base!='site': # XXX ugh - 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.project_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, req, dist, what="Installed"): """Helpful installation message for display to package users""" msg = "\n%(what)s %(eggloc)s%(extras)s" @@ -1164,8 +1049,7 @@ See the setuptools documentation for the "develop" command for more info. cfg_filename = os.path.join(base, 'setup.cfg') setopt.edit_config(cfg_filename, settings) - - def update_pth(self,dist): + def update_pth(self, dist): if self.pth_file is None: return @@ -1207,9 +1091,10 @@ See the setuptools documentation for the "develop" command for more info. return dst # only unpack-and-compile skips files for dry run def unpack_and_compile(self, egg_path, destination): - to_compile = []; to_chmod = [] + to_compile = [] + to_chmod = [] - def pf(src,dst): + def pf(src, dst): if dst.endswith('.py') and not src.startswith('EGG-INFO/'): to_compile.append(dst) elif dst.endswith('.dll') or dst.endswith('.so'): @@ -1243,16 +1128,8 @@ See the setuptools documentation for the "develop" command for more info. finally: log.set_verbosity(self.verbose) # restore original verbosity - - - - - - - - def no_default_version_msg(self): - return """bad install directory or PYTHONPATH + template = """bad install directory or PYTHONPATH You are attempting to install a package to a directory that is not on PYTHONPATH and which Python does not read ".pth" files from. The @@ -1279,18 +1156,8 @@ Here are some of your options for correcting the problem: https://pythonhosted.org/setuptools/easy_install.html#custom-installation-locations -Please make the appropriate changes for your system and try again.""" % ( - self.install_dir, os.environ.get('PYTHONPATH','') - ) - - - - - - - - - +Please make the appropriate changes for your system and try again.""" + return template % (self.install_dir, os.environ.get('PYTHONPATH','')) def install_site_py(self): """Make sure there's a site.py in the target dir, if needed""" @@ -1328,9 +1195,6 @@ Please make the appropriate changes for your system and try again.""" % ( self.sitepy_installed = True - - - def create_home_path(self): """Create directories under ~.""" if not self.user: @@ -1341,22 +1205,16 @@ Please make the appropriate changes for your system and try again.""" % ( self.debug_print("os.makedirs('%s', 0700)" % path) os.makedirs(path, 0x1C0) # 0700 - - - - - - INSTALL_SCHEMES = dict( posix = dict( install_dir = '$base/lib/python$py_version_short/site-packages', - script_dir = '$base/bin', + script_dir = '$base/bin', ), ) DEFAULT_SCHEME = dict( install_dir = '$base/Lib/site-packages', - script_dir = '$base/Scripts', + script_dir = '$base/Scripts', ) def _expand(self, *attrs): @@ -1380,14 +1238,6 @@ Please make the appropriate changes for your system and try again.""" % ( val = os.path.expanduser(val) setattr(self, attr, val) - - - - - - - - def get_site_dirs(): # return a list of 'site' dirs sitedirs = [_f for _f in os.environ.get('PYTHONPATH', @@ -1422,10 +1272,11 @@ def get_site_dirs(): 'Python', sys.version[:3], 'site-packages')) - for site_lib in (_get_purelib(), _get_platlib()): + lib_paths = get_path('purelib'), get_path('platlib') + for site_lib in lib_paths: if site_lib not in sitedirs: sitedirs.append(site_lib) - if HAS_USER_SITE: + if site.ENABLE_USER_SITE: sitedirs.append(site.USER_SITE) sitedirs = list(map(normalize_path, sitedirs)) @@ -1507,10 +1358,9 @@ def extract_wininst_cfg(dist_filename): else: null_byte = chr(0) config = part.split(null_byte, 1)[0] - # Now the config is in bytes, but on Python 3, it must be - # unicode for the RawConfigParser, so decode it. Is this the - # right encoding? - config = config.decode('ascii') + # Now the config is in bytes, but for RawConfigParser, it should + # be text, so decode it. + config = config.decode(sys.getfilesystemencoding()) cfg.readfp(StringIO(config)) except ConfigParser.Error: return None @@ -1522,12 +1372,6 @@ def extract_wininst_cfg(dist_filename): f.close() - - - - - - def get_exe_prefixes(exe_filename): """Get exe->egg path translations for a given .exe file""" @@ -1561,7 +1405,8 @@ def get_exe_prefixes(exe_filename): finally: z.close() prefixes = [(x.lower(),y) for x, y in prefixes] - prefixes.sort(); prefixes.reverse() + prefixes.sort() + prefixes.reverse() return prefixes @@ -1582,7 +1427,8 @@ class PthDistributions(Environment): self.filename = filename self.sitedirs = list(map(normalize_path, sitedirs)) self.basedir = normalize_path(os.path.dirname(self.filename)) - self._load(); Environment.__init__(self, [], None, None) + self._load() + Environment.__init__(self, [], None, None) for path in yield_lines(self.paths): list(map(self.add, find_distributions(path, True))) @@ -1637,7 +1483,8 @@ class PthDistributions(Environment): if os.path.islink(self.filename): os.unlink(self.filename) f = open(self.filename,'wt') - f.write(data); f.close() + f.write(data) + f.close() elif os.path.exists(self.filename): log.debug("Deleting empty %s", self.filename) @@ -1645,22 +1492,22 @@ class PthDistributions(Environment): self.dirty = False - def add(self,dist): + def add(self, dist): """Add `dist` to the distribution map""" if (dist.location not in self.paths and ( dist.location not in self.sitedirs or - dist.location == os.getcwd() #account for '.' being in PYTHONPATH + dist.location == os.getcwd() # account for '.' being in PYTHONPATH )): self.paths.append(dist.location) self.dirty = True - Environment.add(self,dist) + Environment.add(self, dist) - def remove(self,dist): + def remove(self, dist): """Remove `dist` from the distribution map""" while dist.location in self.paths: - self.paths.remove(dist.location); self.dirty = True - Environment.remove(self,dist) - + self.paths.remove(dist.location) + self.dirty = True + Environment.remove(self, dist) def make_relative(self,path): npath, last = os.path.split(normalize_path(path)) @@ -1782,14 +1629,6 @@ def nt_quote_arg(arg): return ''.join(result) - - - - - - - - def is_python_script(script_text, filename): """Is this text, as a whole, a Python script? (as opposed to shell/bat/etc. """ @@ -1828,66 +1667,140 @@ def fix_jython_executable(executable, options): # shebang line interpreter) if options: # Can't apply the workaround, leave it broken - log.warn("WARNING: Unable to adapt shebang line for Jython," - " the following script is NOT executable\n" - " see http://bugs.jython.org/issue1112 for" - " more information.") + log.warn( + "WARNING: Unable to adapt shebang line for Jython," + " the following script is NOT executable\n" + " see http://bugs.jython.org/issue1112 for" + " more information.") else: return '/usr/bin/env %s' % executable return executable -def get_script_args(dist, executable=sys_executable, wininst=False): - """Yield write_script() argument tuples for a distribution's entrypoints""" - spec = str(dist.as_requirement()) - header = get_script_header("", executable, wininst) - for group in 'console_scripts', 'gui_scripts': - for name, ep in dist.get_entry_map(group).items(): - script_text = ( - "# EASY-INSTALL-ENTRY-SCRIPT: %(spec)r,%(group)r,%(name)r\n" - "__requires__ = %(spec)r\n" - "import sys\n" - "from pkg_resources import load_entry_point\n" - "\n" - "if __name__ == '__main__':" - "\n" - " sys.exit(\n" - " load_entry_point(%(spec)r, %(group)r, %(name)r)()\n" - " )\n" - ) % locals() - if sys.platform=='win32' or wininst: - # On Windows/wininst, add a .py extension and an .exe launcher - if group=='gui_scripts': - launcher_type = 'gui' - ext = '-script.pyw' - old = ['.pyw'] - new_header = re.sub('(?i)python.exe','pythonw.exe',header) - else: - launcher_type = 'cli' - ext = '-script.py' - old = ['.py','.pyc','.pyo'] - new_header = re.sub('(?i)pythonw.exe','python.exe',header) - if os.path.exists(new_header[2:-1].strip('"')) or sys.platform!='win32': - hdr = new_header - else: - hdr = header - yield (name+ext, hdr+script_text, 't', [name+x for x in old]) - yield ( - name+'.exe', get_win_launcher(launcher_type), - 'b' # write in binary mode - ) - if not is_64bit(): - # install a manifest for the launcher to prevent Windows - # from detecting it as an installer (which it will for - # launchers like easy_install.exe). Consider only - # adding a manifest for launchers detected as installers. - # See Distribute #143 for details. - m_name = name + '.exe.manifest' - yield (m_name, load_launcher_manifest(name), 't') - else: - # On other platforms, we assume the right thing to do is to - # just write the stub with no extension. - yield (name, header+script_text) +class ScriptWriter(object): + """ + Encapsulates behavior around writing entry point scripts for console and + gui apps. + """ + + template = textwrap.dedent(""" + # EASY-INSTALL-ENTRY-SCRIPT: %(spec)r,%(group)r,%(name)r + __requires__ = %(spec)r + import sys + from pkg_resources import load_entry_point + + if __name__ == '__main__': + sys.exit( + load_entry_point(%(spec)r, %(group)r, %(name)r)() + ) + """).lstrip() + + @classmethod + def get_script_args(cls, dist, executable=sys_executable, wininst=False): + """ + Yield write_script() argument tuples for a distribution's entrypoints + """ + gen_class = cls.get_writer(wininst) + spec = str(dist.as_requirement()) + header = get_script_header("", executable, wininst) + for type_ in 'console', 'gui': + group = type_ + '_scripts' + for name, ep in dist.get_entry_map(group).items(): + script_text = gen_class.template % locals() + for res in gen_class._get_script_args(type_, name, header, + script_text): + yield res + + @classmethod + def get_writer(cls, force_windows): + if force_windows or sys.platform=='win32': + return WindowsScriptWriter.get_writer() + return cls + + @classmethod + def _get_script_args(cls, type_, name, header, script_text): + # Simply write the stub with no extension. + yield (name, header+script_text) + + +class WindowsScriptWriter(ScriptWriter): + @classmethod + def get_writer(cls): + """ + Get a script writer suitable for Windows + """ + writer_lookup = dict( + executable=WindowsExecutableLauncherWriter, + natural=cls, + ) + # for compatibility, use the executable launcher by default + launcher = os.environ.get('SETUPTOOLS_LAUNCHER', 'executable') + return writer_lookup[launcher] + + @classmethod + def _get_script_args(cls, type_, name, header, script_text): + "For Windows, add a .py extension" + ext = dict(console='.pya', gui='.pyw')[type_] + if ext not in os.environ['PATHEXT'].lower().split(';'): + warnings.warn("%s not listed in PATHEXT; scripts will not be " + "recognized as executables." % ext, UserWarning) + old = ['.pya', '.py', '-script.py', '.pyc', '.pyo', '.pyw', '.exe'] + old.remove(ext) + header = cls._adjust_header(type_, header) + blockers = [name+x for x in old] + yield name+ext, header+script_text, 't', blockers + + @staticmethod + def _adjust_header(type_, orig_header): + """ + Make sure 'pythonw' is used for gui and and 'python' is used for + console (regardless of what sys.executable is). + """ + pattern = 'pythonw.exe' + repl = 'python.exe' + if type_ == 'gui': + pattern, repl = repl, pattern + pattern_ob = re.compile(re.escape(pattern), re.IGNORECASE) + new_header = pattern_ob.sub(string=orig_header, repl=repl) + clean_header = new_header[2:-1].strip('"') + if sys.platform == 'win32' and not os.path.exists(clean_header): + # the adjusted version doesn't exist, so return the original + return orig_header + return new_header + + +class WindowsExecutableLauncherWriter(WindowsScriptWriter): + @classmethod + def _get_script_args(cls, type_, name, header, script_text): + """ + For Windows, add a .py extension and an .exe launcher + """ + if type_=='gui': + launcher_type = 'gui' + ext = '-script.pyw' + old = ['.pyw'] + else: + launcher_type = 'cli' + ext = '-script.py' + old = ['.py','.pyc','.pyo'] + hdr = cls._adjust_header(type_, header) + blockers = [name+x for x in old] + yield (name+ext, hdr+script_text, 't', blockers) + yield ( + name+'.exe', get_win_launcher(launcher_type), + 'b' # write in binary mode + ) + if not is_64bit(): + # install a manifest for the launcher to prevent Windows + # from detecting it as an installer (which it will for + # launchers like easy_install.exe). Consider only + # adding a manifest for launchers detected as installers. + # See Distribute #143 for details. + m_name = name + '.exe.manifest' + yield (m_name, load_launcher_manifest(name), 't') + +# for backward-compatibility +get_script_args = ScriptWriter.get_script_args def get_win_launcher(type): """ @@ -1955,8 +1868,11 @@ def current_umask(): def bootstrap(): # This function is called when setuptools*.egg is run using /bin/sh - import setuptools; argv0 = os.path.dirname(setuptools.__path__[0]) - sys.argv[0] = argv0; sys.argv.append(argv0); main() + import setuptools + argv0 = os.path.dirname(setuptools.__path__[0]) + sys.argv[0] = argv0 + sys.argv.append(argv0) + main() def main(argv=None, **kw): from setuptools import setup @@ -1968,9 +1884,10 @@ usage: %(script)s [options] requirement_or_url ... or: %(script)s --help """ - def gen_usage (script_name): - script = os.path.basename(script_name) - return USAGE % vars() + def gen_usage(script_name): + return USAGE % dict( + script=os.path.basename(script_name), + ) def with_ei_usage(f): old_gen_usage = distutils.core.gen_usage @@ -1996,7 +1913,3 @@ usage: %(script)s [options] requirement_or_url ... distclass=DistributionWithoutHelpCommands, **kw ) ) - - - - diff --git a/setuptools/command/egg_info.py b/setuptools/command/egg_info.py index 31700648..5953aad4 100755 --- a/setuptools/command/egg_info.py +++ b/setuptools/command/egg_info.py @@ -2,22 +2,22 @@ Create a distribution's .egg-info directory and contents""" -# This module should be kept compatible with Python 2.3 -import os, re, sys +import os +import re +import sys + from setuptools import Command -from distutils.errors import * +import distutils.errors from distutils import log from setuptools.command.sdist import sdist from setuptools.compat import basestring from setuptools import svn_utils from distutils.util import convert_path from distutils.filelist import FileList as _FileList -from pkg_resources import parse_requirements, safe_name, parse_version, \ - safe_version, yield_lines, EntryPoint, iter_entry_points, to_filename +from pkg_resources import (parse_requirements, safe_name, parse_version, + safe_version, yield_lines, EntryPoint, iter_entry_points, to_filename) from setuptools.command.sdist import walk_revctrl -#requires python >= 2.4 -from subprocess import Popen as _Popen, PIPE as _PIPE class egg_info(Command): description = "create a distribution's .egg-info directory" @@ -38,12 +38,6 @@ class egg_info(Command): negative_opt = {'no-svn-revision': 'tag-svn-revision', 'no-date': 'tag-date'} - - - - - - def initialize_options(self): self.egg_name = None self.egg_version = None @@ -57,35 +51,16 @@ class egg_info(Command): def save_version_info(self, filename): from setuptools.command.setopt import edit_config - edit_config( - filename, - {'egg_info': - {'tag_svn_revision':0, 'tag_date': 0, 'tag_build': self.tags()} - } + values = dict( + egg_info=dict( + tag_svn_revision=0, + tag_date=0, + tag_build=self.tags(), + ) ) + edit_config(filename, values) - - - - - - - - - - - - - - - - - - - - - - def finalize_options (self): + def finalize_options(self): self.egg_name = safe_name(self.distribution.get_name()) self.vtags = self.tags() self.egg_version = self.tagged_version() @@ -95,7 +70,7 @@ class egg_info(Command): parse_requirements('%s==%s' % (self.egg_name,self.egg_version)) ) except ValueError: - raise DistutilsOptionError( + raise distutils.errors.DistutilsOptionError( "Invalid distribution name or version syntax: %s-%s" % (self.egg_name,self.egg_version) ) @@ -125,7 +100,6 @@ class egg_info(Command): pd._parsed_version = parse_version(self.egg_version) self.distribution._patched_dist = None - def write_or_delete_file(self, what, filename, data, force=False): """Write `data` to `filename` or delete if empty @@ -196,34 +170,14 @@ class egg_info(Command): os.path.exists('.svn') or os.path.exists('PKG-INFO') ): version += '-r%s' % self.get_svn_revision() if self.tag_date: - import time; version += time.strftime("-%Y%m%d") + import time + version += time.strftime("-%Y%m%d") return version - - - - - - - - - - - - - - - - @staticmethod def get_svn_revision(): return str(svn_utils.SvnInfo.load(os.curdir).get_revision()) - - - - - def find_sources(self): """Generate SOURCES.txt manifest file""" manifest_filename = os.path.join(self.egg_info,"SOURCES.txt") @@ -271,17 +225,11 @@ class FileList(_FileList): self.files.append(path) - - - - - - class manifest_maker(sdist): template = "MANIFEST.in" - def initialize_options (self): + def initialize_options(self): self.use_defaults = 1 self.prune = 1 self.manifest_only = 1 @@ -303,7 +251,7 @@ class manifest_maker(sdist): self.filelist.remove_duplicates() self.write_manifest() - def write_manifest (self): + def write_manifest(self): """Write the file list in 'self.filelist' (presumably as filled in by 'add_defaults()' and 'read_template()') to the manifest file named by 'self.manifest'. @@ -342,7 +290,7 @@ class manifest_maker(sdist): ei_cmd = self.get_finalized_command('egg_info') self.filelist.include_pattern("*", prefix=ei_cmd.egg_info) - def prune_file_list (self): + def prune_file_list(self): build = self.get_finalized_command('build') base_dir = self.distribution.get_fullname() self.filelist.exclude_pattern(None, prefix=build.build_base) @@ -351,7 +299,7 @@ class manifest_maker(sdist): self.filelist.exclude_pattern(sep+r'(RCS|CVS|\.svn)'+sep, is_regex=1) -def write_file (filename, contents): +def write_file(filename, contents): """Create a file with the specified name and write 'contents' (a sequence of strings without line terminators) to it. """ @@ -362,24 +310,12 @@ def write_file (filename, contents): f.write(contents) f.close() - - - - - - - - - - - - def write_pkg_info(cmd, basename, filename): log.info("writing %s", filename) if not cmd.dry_run: metadata = cmd.distribution.metadata metadata.version, oldver = cmd.egg_version, metadata.version - metadata.name, oldname = cmd.egg_name, metadata.name + metadata.name, oldname = cmd.egg_name, metadata.name try: # write unescaped data to PKG-INFO, so older pkg_resources # can still parse it @@ -408,14 +344,14 @@ def write_requirements(cmd, basename, filename): def write_toplevel_names(cmd, basename, filename): pkgs = dict.fromkeys( - [k.split('.',1)[0] + [ + k.split('.',1)[0] for k in cmd.distribution.iter_distribution_names() ] ) cmd.write_file("top-level names", filename, '\n'.join(pkgs)+'\n') - def overwrite_arg(cmd, basename, filename): write_arg(cmd, basename, filename, True) @@ -454,7 +390,3 @@ def get_pkg_info_revision(): return int(match.group(1)) f.close() return 0 - - - -# diff --git a/setuptools/command/install.py b/setuptools/command/install.py index 247c4f25..459cd3cd 100644 --- a/setuptools/command/install.py +++ b/setuptools/command/install.py @@ -1,4 +1,6 @@ -import setuptools, sys, glob +import setuptools +import sys +import glob from distutils.command.install import install as _install from distutils.errors import DistutilsArgError @@ -15,7 +17,7 @@ class install(_install): ] new_commands = [ ('install_egg_info', lambda self: True), - ('install_scripts', lambda self: True), + ('install_scripts', lambda self: True), ] _nc = dict(new_commands) @@ -46,7 +48,6 @@ class install(_install): self.path_file = None self.extra_dirs = '' - def run(self): # Explicit request for old-style install? Just do it if self.old_and_unmanageable or self.single_version_externally_managed: @@ -72,11 +73,6 @@ class install(_install): else: self.do_egg_install() - - - - - def do_egg_install(self): easy_install = self.distribution.get_command_class('easy_install') @@ -105,20 +101,3 @@ class install(_install): install.sub_commands = [ cmd for cmd in _install.sub_commands if cmd[0] not in install._nc ] + install.new_commands - - - - - - - - - - - - - - - - -# diff --git a/setuptools/command/sdist.py b/setuptools/command/sdist.py index 1bd07e65..04cbccdf 100755 --- a/setuptools/command/sdist.py +++ b/setuptools/command/sdist.py @@ -1,9 +1,12 @@ +import os +import re +import sys +from glob import glob + +import pkg_resources 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 -from glob import glob from setuptools import svn_utils READMES = ('README', 'README.rst', 'README.txt') @@ -19,7 +22,7 @@ def walk_revctrl(dirname=''): #TODO will need test case class re_finder(object): - def __init__(self, path, pattern, postproc=None): + def __init__(self, path, pattern, postproc=lambda x: x): self.pattern = pattern self.postproc = postproc self.path = convert_path(path) @@ -32,10 +35,9 @@ class re_finder(object): f.close() for match in self.pattern.finditer(data): path = match.group(1) - if postproc: - #postproc used to be used when the svn finder - #was an re_finder for calling unescape - path = postproc(path) + # postproc was formerly used when the svn finder + # was an re_finder for calling unescape + path = self.postproc(path) yield svn_utils.joinpath(dirname,path) def find(self, dirname=''): @@ -64,17 +66,6 @@ finders = [ ] - - - - - - - - - - - class sdist(_sdist): """Smart sdist that finds anything supported by revision control""" @@ -129,11 +120,12 @@ class sdist(_sdist): # Beginning with Python 2.7.2, 3.1.4, and 3.2.1, this leaky file handle # has been fixed, so only override the method if we're using an earlier # Python. - if ( - sys.version_info < (2,7,2) - or (3,0) <= sys.version_info < (3,1,4) - or (3,2) <= sys.version_info < (3,2,1) - ): + has_leaky_handle = ( + sys.version_info < (2,7,2) + or (3,0) <= sys.version_info < (3,1,4) + or (3,2) <= sys.version_info < (3,2,1) + ) + if has_leaky_handle: read_template = __read_template_hack def add_defaults(self): @@ -198,7 +190,6 @@ class sdist(_sdist): "standard file not found: should have one of " +', '.join(READMES) ) - def make_release_tree(self, base_dir, files): _sdist.make_release_tree(self, base_dir, files) @@ -245,10 +236,3 @@ class sdist(_sdist): continue self.filelist.append(line) manifest.close() - - - - - - -# diff --git a/setuptools/command/upload.py b/setuptools/command/upload.py deleted file mode 100755 index 02d955ed..00000000 --- a/setuptools/command/upload.py +++ /dev/null @@ -1,184 +0,0 @@ -"""distutils.command.upload - -Implements the Distutils 'upload' subcommand (upload package to PyPI).""" - -from distutils.errors import * -from distutils.core import Command -from distutils.spawn import spawn -from distutils import log -try: - from hashlib import md5 -except ImportError: - from md5 import md5 -import os -import sys -import socket -import platform -import base64 - -from setuptools.compat import urlparse, StringIO, httplib, ConfigParser - -class upload(Command): - - description = "upload binary package to PyPI" - - DEFAULT_REPOSITORY = 'https://pypi.python.org/pypi' - - user_options = [ - ('repository=', 'r', - "url of repository [default: %s]" % DEFAULT_REPOSITORY), - ('show-response', None, - 'display full response text from server'), - ('sign', 's', - 'sign files to upload using gpg'), - ('identity=', 'i', 'GPG identity used to sign files'), - ] - boolean_options = ['show-response', 'sign'] - - def initialize_options(self): - self.username = '' - self.password = '' - self.repository = '' - self.show_response = 0 - self.sign = False - self.identity = None - - def finalize_options(self): - if self.identity and not self.sign: - raise DistutilsOptionError( - "Must use --sign for --identity to have meaning" - ) - if 'HOME' in os.environ: - rc = os.path.join(os.environ['HOME'], '.pypirc') - if os.path.exists(rc): - self.announce('Using PyPI login from %s' % rc) - config = ConfigParser.ConfigParser({ - 'username':'', - 'password':'', - 'repository':''}) - config.read(rc) - if not self.repository: - self.repository = config.get('server-login', 'repository') - if not self.username: - self.username = config.get('server-login', 'username') - if not self.password: - self.password = config.get('server-login', 'password') - if not self.repository: - self.repository = self.DEFAULT_REPOSITORY - - def run(self): - if not self.distribution.dist_files: - raise DistutilsOptionError("No dist file created in earlier command") - for command, pyversion, filename in self.distribution.dist_files: - self.upload_file(command, pyversion, filename) - - def upload_file(self, command, pyversion, filename): - # Sign if requested - if self.sign: - gpg_args = ["gpg", "--detach-sign", "-a", filename] - if self.identity: - gpg_args[2:2] = ["--local-user", self.identity] - spawn(gpg_args, - dry_run=self.dry_run) - - # Fill in the data - f = open(filename,'rb') - content = f.read() - f.close() - basename = os.path.basename(filename) - comment = '' - if command=='bdist_egg' and self.distribution.has_ext_modules(): - comment = "built on %s" % platform.platform(terse=1) - data = { - ':action':'file_upload', - 'protocol_version':'1', - 'name':self.distribution.get_name(), - 'version':self.distribution.get_version(), - 'content':(basename,content), - 'filetype':command, - 'pyversion':pyversion, - 'md5_digest':md5(content).hexdigest(), - } - if command == 'bdist_rpm': - dist, version, id = platform.dist() - if dist: - comment = 'built for %s %s' % (dist, version) - elif command == 'bdist_dumb': - comment = 'built for %s' % platform.platform(terse=1) - data['comment'] = comment - - if self.sign: - asc_file = open(filename + ".asc") - data['gpg_signature'] = (os.path.basename(filename) + ".asc", asc_file.read()) - asc_file.close() - - # set up the authentication - auth = "Basic " + base64.encodestring(self.username + ":" + self.password).strip() - - # Build up the MIME payload for the POST data - boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254' - sep_boundary = '\n--' + boundary - end_boundary = sep_boundary + '--' - body = StringIO.StringIO() - for key, value in data.items(): - # handle multiple entries for the same name - if type(value) != type([]): - value = [value] - for value in value: - if type(value) is tuple: - fn = ';filename="%s"' % value[0] - value = value[1] - else: - fn = "" - value = str(value) - body.write(sep_boundary) - body.write('\nContent-Disposition: form-data; name="%s"'%key) - body.write(fn) - body.write("\n\n") - body.write(value) - if value and value[-1] == '\r': - body.write('\n') # write an extra newline (lurve Macs) - body.write(end_boundary) - body.write("\n") - body = body.getvalue() - - self.announce("Submitting %s to %s" % (filename, self.repository), log.INFO) - - # build the Request - # We can't use urllib2 since we need to send the Basic - # auth right with the first request - schema, netloc, url, params, query, fragments = \ - urlparse(self.repository) - assert not params and not query and not fragments - if schema == 'http': - http = httplib.HTTPConnection(netloc) - elif schema == 'https': - http = httplib.HTTPSConnection(netloc) - else: - raise AssertionError("unsupported schema " + schema) - - data = '' - loglevel = log.INFO - try: - http.connect() - http.putrequest("POST", url) - http.putheader('Content-type', - 'multipart/form-data; boundary=%s'%boundary) - http.putheader('Content-length', str(len(body))) - http.putheader('Authorization', auth) - http.endheaders() - http.send(body) - except socket.error: - e = sys.exc_info()[1] - self.announce(str(e), log.ERROR) - return - - r = http.getresponse() - if r.status == 200: - self.announce('Server response (%s): %s' % (r.status, r.reason), - log.INFO) - else: - self.announce('Upload failed (%s): %s' % (r.status, r.reason), - log.ERROR) - if self.show_response: - print('-'*75, r.read(), '-'*75) diff --git a/setuptools/command/upload_docs.py b/setuptools/command/upload_docs.py index 12bc916b..cad7a52d 100644 --- a/setuptools/command/upload_docs.py +++ b/setuptools/command/upload_docs.py @@ -17,20 +17,11 @@ from pkg_resources import iter_entry_points from distutils import log from distutils.errors import DistutilsOptionError +from distutils.command.upload import upload -try: - from distutils.command.upload import upload -except ImportError: - from setuptools.command.upload import upload +from setuptools.compat import httplib, urlparse, unicode, iteritems, PY3 -from setuptools.compat import httplib, urlparse, unicode, iteritems - -_IS_PYTHON3 = sys.version > '3' - -if _IS_PYTHON3: - errors = 'surrogateescape' -else: - errors = 'strict' +errors = 'surrogateescape' if PY3 else 'strict' # This is not just a replacement for byte literals @@ -124,7 +115,7 @@ class upload_docs(upload): # set up the authentication credentials = b(self.username + ':' + self.password) credentials = standard_b64encode(credentials) - if sys.version_info >= (3,): + if PY3: credentials = credentials.decode('ascii') auth = "Basic " + credentials @@ -136,7 +127,7 @@ class upload_docs(upload): for key, values in iteritems(data): title = '\nContent-Disposition: form-data; name="%s"' % key # handle multiple entries for the same name - if type(values) != type([]): + if not isinstance(values, list): values = [values] for value in values: if type(value) is tuple: @@ -171,12 +162,11 @@ class upload_docs(upload): raise AssertionError("unsupported schema "+schema) data = '' - loglevel = log.INFO try: conn.connect() conn.putrequest("POST", url) - conn.putheader('Content-type', - 'multipart/form-data; boundary=%s'%boundary) + content_type = 'multipart/form-data; boundary=%s' % boundary + conn.putheader('Content-type', content_type) conn.putheader('Content-length', str(len(body))) conn.putheader('Authorization', auth) conn.endheaders() |
