summaryrefslogtreecommitdiff
path: root/setuptools
diff options
context:
space:
mode:
Diffstat (limited to 'setuptools')
-rw-r--r--setuptools/__init__.py14
-rwxr-xr-xsetuptools/archive_util.py46
-rw-r--r--setuptools/command/bdist_egg.py16
-rwxr-xr-xsetuptools/command/bdist_wininst.py67
-rw-r--r--setuptools/command/build_ext.py44
-rwxr-xr-xsetuptools/command/easy_install.py58
-rwxr-xr-xsetuptools/command/egg_info.py25
-rwxr-xr-xsetuptools/command/sdist.py75
-rw-r--r--setuptools/command/test.py2
-rwxr-xr-xsetuptools/command/upload.py2
-rw-r--r--setuptools/command/upload_docs.py16
-rw-r--r--setuptools/dist.py60
-rw-r--r--setuptools/extension.py2
-rwxr-xr-xsetuptools/package_index.py112
-rw-r--r--setuptools/py27compat.py15
-rwxr-xr-xsetuptools/sandbox.py48
-rw-r--r--setuptools/script template (dev).py5
-rw-r--r--setuptools/ssl_support.py248
-rw-r--r--setuptools/tests/__init__.py3
-rw-r--r--setuptools/tests/entries-v10615
-rw-r--r--setuptools/tests/test_develop.py2
-rw-r--r--setuptools/tests/test_easy_install.py61
-rw-r--r--setuptools/tests/test_egg_info.py40
-rw-r--r--setuptools/tests/test_packageindex.py22
-rw-r--r--setuptools/tests/test_resources.py51
25 files changed, 1321 insertions, 328 deletions
diff --git a/setuptools/__init__.py b/setuptools/__init__.py
index 9de373f9..a8e7617a 100644
--- a/setuptools/__init__.py
+++ b/setuptools/__init__.py
@@ -8,22 +8,12 @@ from distutils.util import convert_path
import os
import sys
-__version__ = '0.6'
+__version__ = '0.8'
__all__ = [
'setup', 'Distribution', 'Feature', 'Command', 'Extension', 'Require',
'find_packages'
]
-# This marker is used to simplify the process that checks is the
-# setuptools package was installed by the Setuptools project
-# or by the Distribute project, in case Setuptools creates
-# a distribution with the same version.
-#
-# The distribute_setup script for instance, will check if this
-# attribute is present to decide whether to reinstall the package
-# or not.
-_distribute = True
-
bootstrap_install_from = None
# If we run 2to3 on .py files, should we also convert docstrings?
@@ -51,7 +41,7 @@ def find_packages(where='.', exclude=()):
os.path.isfile(os.path.join(fn,'__init__.py'))
):
out.append(prefix+name); stack.append((fn,prefix+name+'.'))
- for pat in list(exclude)+['ez_setup', 'distribute_setup']:
+ for pat in list(exclude)+['ez_setup']:
from fnmatch import fnmatchcase
out = [item for item in out if not fnmatchcase(item,pat)]
return out
diff --git a/setuptools/archive_util.py b/setuptools/archive_util.py
index e22b25c0..1109f346 100755
--- a/setuptools/archive_util.py
+++ b/setuptools/archive_util.py
@@ -6,7 +6,7 @@ __all__ = [
"UnrecognizedFormat", "extraction_drivers", "unpack_directory",
]
-import zipfile, tarfile, os, shutil
+import zipfile, tarfile, os, shutil, posixpath
from pkg_resources import ensure_directory
from distutils.errors import DistutilsError
@@ -138,7 +138,7 @@ def unpack_zipfile(filename, extract_dir, progress_filter=default_filter):
name = info.filename
# don't extract absolute paths or ones with .. in them
- if name.startswith('/') or '..' in name:
+ if name.startswith('/') or '..' in name.split('/'):
continue
target = os.path.join(extract_dir, *name.split('/'))
@@ -172,43 +172,39 @@ def unpack_tarfile(filename, extract_dir, progress_filter=default_filter):
by ``tarfile.open()``). See ``unpack_archive()`` for an explanation
of the `progress_filter` argument.
"""
-
try:
tarobj = tarfile.open(filename)
except tarfile.TarError:
raise UnrecognizedFormat(
"%s is not a compressed or uncompressed tar file" % (filename,)
)
-
try:
tarobj.chown = lambda *args: None # don't do any chowning!
for member in tarobj:
name = member.name
# don't extract absolute paths or ones with .. in them
- if not name.startswith('/') and '..' not in name:
+ if not name.startswith('/') and '..' not in name.split('/'):
prelim_dst = os.path.join(extract_dir, *name.split('/'))
- final_dst = progress_filter(name, prelim_dst)
- # If progress_filter returns None, then we do not extract
- # this file
- # TODO: Do we really need to limit to just these file types?
- # tarobj.extract() will handle all files on all platforms,
- # turning file types that aren't allowed on that platform into
- # regular files.
- if final_dst and (member.isfile() or member.isdir() or
- member.islnk() or member.issym()):
- tarobj.extract(member, extract_dir)
- if final_dst != prelim_dst:
- shutil.move(prelim_dst, final_dst)
+
+ # resolve any links and to extract the link targets as normal files
+ while member is not None and (member.islnk() or member.issym()):
+ linkpath = member.linkname
+ if member.issym():
+ linkpath = posixpath.join(posixpath.dirname(member.name), linkpath)
+ linkpath = posixpath.normpath(linkpath)
+ member = tarobj._getmember(linkpath)
+
+ if member is not None and (member.isfile() or member.isdir()):
+ final_dst = progress_filter(name, prelim_dst)
+ if final_dst:
+ if final_dst.endswith(os.sep):
+ final_dst = final_dst[:-1]
+ try:
+ tarobj._extract_member(member, final_dst) # XXX Ugh
+ except tarfile.ExtractError:
+ pass # chown/chmod/mkfifo/mknode/makedev failed
return True
finally:
tarobj.close()
-
-
-
extraction_drivers = unpack_directory, unpack_zipfile, unpack_tarfile
-
-
-
-
-
diff --git a/setuptools/command/bdist_egg.py b/setuptools/command/bdist_egg.py
index 875971f0..c5776158 100644
--- a/setuptools/command/bdist_egg.py
+++ b/setuptools/command/bdist_egg.py
@@ -7,10 +7,14 @@ import sys, os, marshal
from setuptools import Command
from distutils.dir_util import remove_tree, mkpath
try:
- from distutils.sysconfig import get_python_version, get_python_lib
+ # Python 2.7 or >=3.2
+ from sysconfig import get_path, get_python_version
+ def _get_purelib():
+ return get_path("purelib")
except ImportError:
- from sysconfig import get_python_version
- from distutils.sysconfig import get_python_lib
+ from distutils.sysconfig import get_python_lib, get_python_version
+ def _get_purelib():
+ return get_python_lib(False)
from distutils import log
from distutils.errors import DistutilsSetupError
@@ -131,7 +135,7 @@ class bdist_egg(Command):
# Hack for packages that install data to install's --install-lib
self.get_finalized_command('install').install_lib = self.bdist_dir
- site_packages = os.path.normcase(os.path.realpath(get_python_lib()))
+ site_packages = os.path.normcase(os.path.realpath(_get_purelib()))
old, self.distribution.data_files = self.distribution.data_files,[]
for item in old:
@@ -171,12 +175,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
@@ -196,7 +201,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()
diff --git a/setuptools/command/bdist_wininst.py b/setuptools/command/bdist_wininst.py
index 93e6846d..e8521f83 100755
--- a/setuptools/command/bdist_wininst.py
+++ b/setuptools/command/bdist_wininst.py
@@ -2,26 +2,24 @@ from distutils.command.bdist_wininst import bdist_wininst as _bdist_wininst
import os, sys
class bdist_wininst(_bdist_wininst):
+ _good_upload = _bad_upload = None
def create_exe(self, arcname, fullname, bitmap=None):
_bdist_wininst.create_exe(self, arcname, fullname, bitmap)
- dist_files = getattr(self.distribution, 'dist_files', [])
-
+ installer_name = self.get_installer_filename(fullname)
if self.target_version:
- installer_name = os.path.join(self.dist_dir,
- "%s.win32-py%s.exe" %
- (fullname, self.target_version))
pyversion = self.target_version
-
- # fix 2.5 bdist_wininst ignoring --target-version spec
- bad = ('bdist_wininst','any',installer_name)
- if bad in dist_files:
- dist_files.remove(bad)
+ # fix 2.5+ bdist_wininst ignoring --target-version spec
+ self._bad_upload = ('bdist_wininst', 'any', installer_name)
else:
- installer_name = os.path.join(self.dist_dir,
- "%s.win32.exe" % fullname)
pyversion = 'any'
- good = ('bdist_wininst', pyversion, installer_name)
+ self._good_upload = ('bdist_wininst', pyversion, installer_name)
+
+ def _fix_upload_names(self):
+ good, bad = self._good_upload, self._bad_upload
+ dist_files = getattr(self.distribution, 'dist_files', [])
+ if bad in dist_files:
+ dist_files.remove(bad)
if good not in dist_files:
dist_files.append(good)
@@ -36,6 +34,49 @@ class bdist_wininst(_bdist_wininst):
self._is_running = True
try:
_bdist_wininst.run(self)
+ self._fix_upload_names()
finally:
self._is_running = False
+
+ if not hasattr(_bdist_wininst, 'get_installer_filename'):
+ def get_installer_filename(self, fullname):
+ # Factored out to allow overriding in subclasses
+ if self.target_version:
+ # if we create an installer for a specific python version,
+ # it's better to include this in the name
+ installer_name = os.path.join(self.dist_dir,
+ "%s.win32-py%s.exe" %
+ (fullname, self.target_version))
+ else:
+ installer_name = os.path.join(self.dist_dir,
+ "%s.win32.exe" % fullname)
+ return installer_name
+ # get_installer_filename()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/setuptools/command/build_ext.py b/setuptools/command/build_ext.py
index 4a94572c..50a039ce 100644
--- a/setuptools/command/build_ext.py
+++ b/setuptools/command/build_ext.py
@@ -9,9 +9,15 @@ import os, sys
from distutils.file_util import copy_file
from setuptools.extension import Library
from distutils.ccompiler import new_compiler
-from distutils.sysconfig import customize_compiler, get_config_var
-get_config_var("LDSHARED") # make sure _config_vars is initialized
-from distutils.sysconfig import _config_vars
+from distutils.sysconfig import customize_compiler
+try:
+ # Python 2.7 or >=3.2
+ from sysconfig import _CONFIG_VARS
+except ImportError:
+ from distutils.sysconfig import get_config_var
+ get_config_var("LDSHARED") # make sure _config_vars is initialized
+ del get_config_var
+ from distutils.sysconfig import _config_vars as _CONFIG_VARS
from distutils import log
from distutils.errors import *
@@ -82,17 +88,15 @@ class build_ext(_build_ext):
def get_ext_filename(self, fullname):
filename = _build_ext.get_ext_filename(self,fullname)
- if fullname not in self.ext_map:
- return filename
- 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)
@@ -133,16 +137,16 @@ class build_ext(_build_ext):
compiler=self.compiler, dry_run=self.dry_run, force=self.force
)
if sys.platform == "darwin":
- tmp = _config_vars.copy()
+ tmp = _CONFIG_VARS.copy()
try:
# XXX Help! I don't have any idea whether these are right...
- _config_vars['LDSHARED'] = "gcc -Wl,-x -dynamiclib -undefined dynamic_lookup"
- _config_vars['CCSHARED'] = " -dynamiclib"
- _config_vars['SO'] = ".dylib"
+ _CONFIG_VARS['LDSHARED'] = "gcc -Wl,-x -dynamiclib -undefined dynamic_lookup"
+ _CONFIG_VARS['CCSHARED'] = " -dynamiclib"
+ _CONFIG_VARS['SO'] = ".dylib"
customize_compiler(compiler)
finally:
- _config_vars.clear()
- _config_vars.update(tmp)
+ _CONFIG_VARS.clear()
+ _CONFIG_VARS.update(tmp)
else:
customize_compiler(compiler)
diff --git a/setuptools/command/easy_install.py b/setuptools/command/easy_install.py
index 50339e8f..3194644e 100755
--- a/setuptools/command/easy_install.py
+++ b/setuptools/command/easy_install.py
@@ -7,7 +7,7 @@ A tool for doing automatic download/extract/build of distutils-based Python
packages. For detailed documentation, see the accompanying EasyInstall.txt
file, or visit the `EasyInstall home page`__.
-__ http://packages.python.org/distribute/easy_install.html
+__ https://pythonhosted.org/setuptools/easy_install.html
"""
import sys
@@ -25,9 +25,22 @@ 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 distutils.util import get_platform
from distutils.util import convert_path, subst_vars
-from distutils.sysconfig import get_python_lib, get_config_vars
from distutils.errors import DistutilsArgError, DistutilsOptionError, \
DistutilsError, DistutilsPlatformError
from distutils.command.install import INSTALL_SCHEMES, SCHEME_KEYS
@@ -45,7 +58,10 @@ from pkg_resources import yield_lines, normalize_path, resource_string, \
DistributionNotFound, VersionConflict, \
DEVELOP_DIST
-sys_executable = os.path.normpath(sys.executable)
+if '__VENV_LAUNCHER__' in os.environ:
+ sys_executable = os.environ['__VENV_LAUNCHER__']
+else:
+ sys_executable = os.path.normpath(sys.executable)
__all__ = [
'samefile', 'easy_install', 'PthDistributions', 'extract_wininst_cfg',
@@ -204,7 +220,7 @@ class easy_install(Command):
def finalize_options(self):
if self.version:
- print('distribute %s' % get_distribution('distribute').version)
+ print('setuptools %s' % get_distribution('setuptools').version)
sys.exit()
py_version = sys.version.split()[0]
@@ -269,6 +285,8 @@ class easy_install(Command):
self.script_dir = self.install_scripts
# default --record from the install command
self.set_undefined_options('install', ('record', 'record'))
+ # Should this be moved to the if statement below? It's not used
+ # elsewhere
normpath = map(normalize_path, sys.path)
self.all_site_dirs = get_site_dirs()
if self.site_dirs is not None:
@@ -285,7 +303,7 @@ class easy_install(Command):
else:
self.all_site_dirs.append(normalize_path(d))
if not self.editable: self.check_site_dir()
- self.index_url = self.index_url or "http://pypi.python.org/simple"
+ self.index_url = self.index_url or "https://pypi.python.org/simple"
self.shadow_path = self.all_site_dirs[:]
for path_item in self.install_dir, normalize_path(self.script_dir):
if path_item not in self.shadow_path:
@@ -404,7 +422,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:
@@ -469,7 +487,7 @@ variable.
For information on other options, you may wish to consult the
documentation at:
- http://packages.python.org/distribute/easy_install.html
+ https://pythonhosted.org/setuptools/easy_install.html
Please make the appropriate changes for your system and try again.
"""
@@ -592,7 +610,6 @@ Please make the appropriate changes for your system and try again.
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:
@@ -663,8 +680,7 @@ Please make the appropriate changes for your system and try again.
self.update_pth(dist)
self.package_index.add(dist)
self.local_index.add(dist)
- if not self.editable:
- self.install_egg_scripts(dist)
+ self.install_egg_scripts(dist)
self.installed_projects[dist.key] = dist
log.info(self.installation_report(requirement, dist, *info))
if (dist.has_metadata('dependency_links.txt') and
@@ -714,7 +730,7 @@ Please make the appropriate changes for your system and try again.
return True
if not dist.has_metadata('zip-safe'):
return True
- return True
+ return False
def maybe_move(self, spec, dist_filename, setup_base):
dst = os.path.join(self.build_directory, spec.key)
@@ -1175,7 +1191,8 @@ See the setuptools documentation for the "develop" command for more info.
if not self.dry_run:
self.pth_file.save()
- if dist.key=='distribute':
+
+ if dist.key=='setuptools':
# Ensure that setuptools itself never becomes unavailable!
# XXX should this check for latest version?
filename = os.path.join(self.install_dir,'setuptools.pth')
@@ -1195,7 +1212,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)
@@ -1234,6 +1250,7 @@ See the setuptools documentation for the "develop" command for more info.
+
def no_default_version_msg(self):
return """bad install directory or PYTHONPATH
@@ -1260,7 +1277,7 @@ Here are some of your options for correcting the problem:
* You can set up the installation directory to support ".pth" files by
using one of the approaches described here:
- http://packages.python.org/distribute/easy_install.html#custom-installation-locations
+ 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','')
@@ -1405,8 +1422,7 @@ def get_site_dirs():
'Python',
sys.version[:3],
'site-packages'))
- for plat_specific in (0,1):
- site_lib = get_python_lib(plat_specific)
+ for site_lib in (_get_purelib(), _get_platlib()):
if site_lib not in sitedirs: sitedirs.append(site_lib)
if HAS_USER_SITE:
@@ -1519,7 +1535,7 @@ def get_exe_prefixes(exe_filename):
('PURELIB/', ''), ('PLATLIB/pywin32_system32', ''),
('PLATLIB/', ''),
('SCRIPTS/', 'EGG-INFO/scripts/'),
- ('DATA/LIB/site-packages', ''),
+ ('DATA/lib/site-packages', ''),
]
z = zipfile.ZipFile(exe_filename)
try:
@@ -1851,7 +1867,7 @@ def get_script_args(dist, executable=sys_executable, wininst=False):
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]) or sys.platform!='win32':
+ if os.path.exists(new_header[2:-1].strip('"')) or sys.platform!='win32':
hdr = new_header
else:
hdr = header
@@ -1970,12 +1986,6 @@ usage: %(script)s [options] requirement_or_url ...
def _show_help(self,*args,**kw):
with_ei_usage(lambda: Distribution._show_help(self,*args,**kw))
- def find_config_files(self):
- files = Distribution.find_config_files(self)
- if 'setup.cfg' in files:
- files.remove('setup.cfg')
- return files
-
if argv is None:
argv = sys.argv[1:]
diff --git a/setuptools/command/egg_info.py b/setuptools/command/egg_info.py
index 12acc422..642687b2 100755
--- a/setuptools/command/egg_info.py
+++ b/setuptools/command/egg_info.py
@@ -211,7 +211,8 @@ class egg_info(Command):
- def get_svn_revision(self):
+ @staticmethod
+ def get_svn_revision():
revision = 0
urlre = re.compile('url="([^"]+)"')
revre = re.compile('committed-rev="(\d+)"')
@@ -225,18 +226,21 @@ class egg_info(Command):
data = f.read()
f.close()
- if data.startswith('10') or 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 svnver<8:
+ log.warn("unrecognized .svn/entries format; skipping %s", base)
+ dirs[:] = []
+ continue
+
data = list(map(str.splitlines,data.split('\n\x0c\n')))
del data[0][0] # get rid of the '8' or '9' or '10'
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):
@@ -249,9 +253,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 6f3f48c8..39cd6043 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
from glob import glob
@@ -41,7 +42,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'):
@@ -89,18 +89,22 @@ def entries_finder(dirname, filename):
f = open(filename,'rU')
data = f.read()
f.close()
- if data.startswith('10') or data.startswith('9') or data.startswith('8'):
+ 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", os.path.abspath(dirname))
+ return
for record in map(str.splitlines, data.split('\n\x0c\n')[1:]):
# subversion 1.6/1.5/1.4
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", os.path.abspath(dirname))
-
+
finders = [
(convert_path('CVS/Entries'),
@@ -121,10 +125,6 @@ finders = [
-
-
-
-
class sdist(_sdist):
"""Smart sdist that finds anything supported by revision control"""
@@ -157,7 +157,7 @@ class sdist(_sdist):
import distutils.command
if 'check' not in distutils.command.__all__:
self.check_metadata()
-
+
self.make_distribution()
dist_files = getattr(self.distribution,'dist_files',[])
@@ -166,6 +166,26 @@ class sdist(_sdist):
if data not in dist_files:
dist_files.append(data)
+ def __read_template_hack(self):
+ # This grody hack closes the template file (MANIFEST.in) if an
+ # exception occurs during read_template.
+ # Doing so prevents an error when easy_install attempts to delete the
+ # file.
+ try:
+ _sdist.read_template(self)
+ except:
+ sys.exc_info()[2].tb_next.tb_frame.f_locals['template'].close()
+ raise
+ # 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)
+ ):
+ read_template = __read_template_hack
+
def add_defaults(self):
standards = [READMES,
self.distribution.script_name]
@@ -219,26 +239,6 @@ class sdist(_sdist):
build_scripts = self.get_finalized_command('build_scripts')
self.filelist.extend(build_scripts.get_source_files())
- def __read_template_hack(self):
- # This grody hack closes the template file (MANIFEST.in) if an
- # exception occurs during read_template.
- # Doing so prevents an error when easy_install attempts to delete the
- # file.
- try:
- _sdist.read_template(self)
- except:
- sys.exc_info()[2].tb_next.tb_frame.f_locals['template'].close()
- raise
- # 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)
- ):
- read_template = __read_template_hack
-
def check_readme(self):
for f in READMES:
if os.path.exists(f):
@@ -301,13 +301,4 @@ class sdist(_sdist):
-
-
-
-
-
-
-
-
-
#
diff --git a/setuptools/command/test.py b/setuptools/command/test.py
index a02ac142..db2fc7b1 100644
--- a/setuptools/command/test.py
+++ b/setuptools/command/test.py
@@ -154,7 +154,7 @@ class test(Command):
for name in sys.modules:
if name.startswith(module):
del_modules.append(name)
- map(sys.modules.__delitem__, del_modules)
+ list(map(sys.modules.__delitem__, del_modules))
loader_ep = EntryPoint.parse("x="+self.test_loader)
loader_class = loader_ep.load(require=False)
diff --git a/setuptools/command/upload.py b/setuptools/command/upload.py
index 7edbf56a..02d955ed 100755
--- a/setuptools/command/upload.py
+++ b/setuptools/command/upload.py
@@ -22,7 +22,7 @@ class upload(Command):
description = "upload binary package to PyPI"
- DEFAULT_REPOSITORY = 'http://pypi.python.org/pypi'
+ DEFAULT_REPOSITORY = 'https://pypi.python.org/pypi'
user_options = [
('repository=', 'r',
diff --git a/setuptools/command/upload_docs.py b/setuptools/command/upload_docs.py
index 178a8793..12bc916b 100644
--- a/setuptools/command/upload_docs.py
+++ b/setuptools/command/upload_docs.py
@@ -2,7 +2,7 @@
"""upload_docs
Implements a Distutils 'upload_docs' subcommand (upload documentation to
-PyPI's packages.python.org).
+PyPI's pythonhosted.org).
"""
import os
@@ -23,15 +23,21 @@ try:
except ImportError:
from setuptools.command.upload import upload
-from setuptools.compat import httplib, urlparse
+from setuptools.compat import httplib, urlparse, unicode, iteritems
_IS_PYTHON3 = sys.version > '3'
+if _IS_PYTHON3:
+ errors = 'surrogateescape'
+else:
+ errors = 'strict'
+
+
# This is not just a replacement for byte literals
# but works as a general purpose encoder
def b(s, encoding='utf-8'):
if isinstance(s, unicode):
- return s.encode(encoding)
+ return s.encode(encoding, errors)
return s
@@ -127,7 +133,7 @@ class upload_docs(upload):
sep_boundary = b('\n--') + b(boundary)
end_boundary = sep_boundary + b('--')
body = []
- for key, values in data.iteritems():
+ 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([]):
@@ -187,7 +193,7 @@ class upload_docs(upload):
elif r.status == 301:
location = r.getheader('Location')
if location is None:
- location = 'http://packages.python.org/%s/' % meta.get_name()
+ location = 'https://pythonhosted.org/%s/' % meta.get_name()
self.announce('Upload successful. Visit %s' % location,
log.INFO)
else:
diff --git a/setuptools/dist.py b/setuptools/dist.py
index 62dd0eb2..01889215 100644
--- a/setuptools/dist.py
+++ b/setuptools/dist.py
@@ -50,7 +50,6 @@ def assert_string_list(dist, attr, value):
raise DistutilsSetupError(
"%r must be a list of strings (got %r)" % (attr,value)
)
-
def check_nsp(dist, attr, value):
"""Verify that namespace packages are valid"""
assert_string_list(dist,attr,value)
@@ -64,14 +63,18 @@ 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):
"""Verify that extras_require mapping is valid"""
try:
for k,v in value.items():
+ if ':' in k:
+ k,m = k.split(':',1)
+ if pkg_resources.invalid_marker(m):
+ raise DistutilsSetupError("Invalid environment marker: "+m)
list(pkg_resources.parse_requirements(v))
except (TypeError,ValueError,AttributeError):
raise DistutilsSetupError(
@@ -80,9 +83,6 @@ def check_extras(dist, attr, value):
"requirement specifiers."
)
-
-
-
def assert_bool(dist, attr, value):
"""Verify that value is True, False, 0, or 1"""
if bool(value) != value:
@@ -125,6 +125,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
@@ -848,11 +889,4 @@ class Feature:
-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
- )
diff --git a/setuptools/extension.py b/setuptools/extension.py
index eb8b836c..d7892d3d 100644
--- a/setuptools/extension.py
+++ b/setuptools/extension.py
@@ -35,7 +35,7 @@ class Extension(_Extension):
if source.endswith('.pyx'):
source = source[:-4] + '.c'
return source
- self.sources = map(pyx_to_c, self.sources)
+ self.sources = list(map(pyx_to_c, self.sources))
class Library(Extension):
"""Just like a regular Extension, but built as a library instead"""
diff --git a/setuptools/package_index.py b/setuptools/package_index.py
index 1e2a086d..61a66c6d 100755
--- a/setuptools/package_index.py
+++ b/setuptools/package_index.py
@@ -1,6 +1,8 @@
"""PyPI and direct package downloading"""
import sys, os.path, re, shutil, random, socket
+import itertools
import base64
+from setuptools import ssl_support
from pkg_resources import *
from distutils import log
from distutils.errors import DistutilsError
@@ -14,8 +16,8 @@ try:
except ImportError:
from md5 import md5
from fnmatch import translate
-
from setuptools.py24compat import wraps
+from setuptools.py27compat import get_all_headers
EGG_FRAGMENT = re.compile(r'^egg=([-A-Za-z0-9_.]+)$')
HREF = re.compile("""href\\s*=\\s*['"]?([^'"> ]+)""", re.I)
@@ -61,6 +63,8 @@ def parse_bdist_wininst(name):
def egg_info_for_url(url):
scheme, server, path, parameters, query, fragment = urlparse(url)
base = unquote(path.split('/')[-1])
+ if server=='sourceforge.net' and base=='download': # XXX Yuck
+ base = unquote(path.split('/')[-2])
if '#' in base: base, fragment = base.split('#',1)
return base,fragment
@@ -83,14 +87,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, platform = parse_bdist_wininst(basename)
if win_base is not None:
return interpret_distro_name(
location, win_base, metadata, py_ver, BINARY_DIST, platform
)
-
# Try source distro extensions (.zip, .tgz, etc.)
#
for ext in EXTENSIONS:
@@ -177,7 +179,7 @@ def find_external_links(url, page):
for match in REL.finditer(page):
tag, rel = match.groups()
- rels = map(str.strip, rel.lower().split(','))
+ rels = set(map(str.strip, rel.lower().split(',')))
if 'homepage' in rels or 'download' in rels:
for match in HREF.finditer(tag):
yield urljoin(url, htmldecode(match.group(1)))
@@ -189,17 +191,15 @@ def find_external_links(url, page):
if match:
yield urljoin(url, htmldecode(match.group(1)))
-
-user_agent = "Python-urllib/%s distribute/%s" % (
- sys.version[:3], require('distribute')[0].version
+user_agent = "Python-urllib/%s setuptools/%s" % (
+ sys.version[:3], require('setuptools')[0].version
)
-
class PackageIndex(Environment):
"""A distribution index that scans web pages for download URLs"""
- def __init__(self, index_url="http://pypi.python.org/simple", hosts=('*',),
- *args, **kw
+ def __init__(self, index_url="https://pypi.python.org/simple", hosts=('*',),
+ ca_bundle=None, verify_ssl=True, *args, **kw
):
Environment.__init__(self,*args,**kw)
self.index_url = index_url + "/"[:not index_url.endswith('/')]
@@ -208,8 +208,9 @@ class PackageIndex(Environment):
self.package_pages = {}
self.allows = re.compile('|'.join(map(translate,hosts))).match
self.to_scan = []
-
-
+ if verify_ssl and ssl_support.is_available and (ca_bundle or ssl_support.find_ca_bundle()):
+ self.opener = ssl_support.opener_for(ca_bundle)
+ else: self.opener = urllib2.urlopen
def process_url(self, url, retrieve=False):
"""Evaluate a URL as a possible download, and maybe retrieve it"""
@@ -235,10 +236,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 on %s: %%s -- Some packages may not be found!" % url)
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
@@ -488,7 +489,6 @@ 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 = {}
@@ -508,10 +508,9 @@ 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()
@@ -535,7 +534,10 @@ class PackageIndex(Environment):
(source and "a source distribution of " or ""),
requirement,
)
- return dist
+ else:
+ 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`
@@ -551,12 +553,6 @@ class PackageIndex(Environment):
return None
-
-
-
-
-
-
def gen_setup(self, filename, fragment, tmpdir):
match = EGG_FRAGMENT.match(fragment)
dists = match and [d for d in
@@ -618,8 +614,8 @@ class PackageIndex(Environment):
size = -1
if "content-length" in headers:
# Some servers return multiple Content-Length headers :(
- content_length = headers.get("Content-Length")
- size = int(content_length)
+ sizes = get_all_headers(headers, 'Content-Length')
+ size = max(map(int, sizes))
self.reporthook(url, filename, blocknum, bs, size)
tfp = open(filename,'wb')
while True:
@@ -645,7 +641,7 @@ class PackageIndex(Environment):
if url.startswith('file:'):
return local_open(url)
try:
- return open_with_auth(url)
+ return open_with_auth(url, self.opener)
except (ValueError, httplib.InvalidURL):
v = sys.exc_info()[1]
msg = ' '.join([str(arg) for arg in v.args])
@@ -682,9 +678,8 @@ class PackageIndex(Environment):
def _download_url(self, scheme, url, tmpdir):
# Determine download filename
#
- name = [_f for _f in urlparse(url)[2].split('/') if _f]
+ name, fragment = egg_info_for_url(url)
if name:
- name = name[-1]
while '..' in name:
name = name.replace('..','.').replace('\\','_')
else:
@@ -704,13 +699,11 @@ class PackageIndex(Environment):
elif scheme.startswith('hg+'):
return self._download_hg(url, filename)
elif scheme=='file':
- return url2pathname(urlparse.urlparse(url)[2])
+ return url2pathname(urlparse(url)[2])
else:
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)
@@ -737,14 +730,43 @@ class PackageIndex(Environment):
os.unlink(filename)
raise DistutilsError("Unexpected HTML page found at "+url)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
def _download_svn(self, url, filename):
url = url.split('#',1)[0] # remove any fragment for svn's sake
+ creds = ''
+ if url.lower().startswith('svn:') and '@' in url:
+ scheme, netloc, path, p, q, f = urlparse(url)
+ if not netloc and path.startswith('//') and '/' in path[2:]:
+ netloc, path = path[2:].split('/',1)
+ auth, host = splituser(netloc)
+ if auth:
+ if ':' in auth:
+ user, pw = auth.split(':',1)
+ creds = " --username=%s --password=%s" % (user, pw)
+ else:
+ creds = " --username="+auth
+ netloc = host
+ url = urlunparse((scheme, netloc, url, p, q, f))
self.info("Doing subversion checkout from %s to %s", url, filename)
- os.system("svn checkout -q %s %s" % (url, filename))
+ os.system("svn checkout%s -q %s %s" % (creds, url, filename))
return filename
def _vcs_split_rev_from_url(self, url, pop_prefix=False):
- scheme, netloc, path, query, frag = urlparse.urlsplit(url)
+ scheme, netloc, path, query, frag = urlsplit(url)
scheme = scheme.split('+', 1)[-1]
@@ -756,7 +778,7 @@ class PackageIndex(Environment):
path, rev = path.rsplit('@', 1)
# Also, discard fragment
- url = urlparse.urlunsplit((scheme, netloc, path, query, ''))
+ url = urlunsplit((scheme, netloc, path, query, ''))
return url, rev
@@ -801,6 +823,18 @@ class PackageIndex(Environment):
def warn(self, msg, *args):
log.warn(msg, *args)
+
+
+
+
+
+
+
+
+
+
+
+
# This pattern matches a character entity reference (a decimal numeric
# references, a hexadecimal numeric reference, or a named reference).
entity_sub = re.compile(r'&(#(\d+|x[\da-fA-F]+)|[\w.:-]+);?').sub
@@ -868,7 +902,7 @@ def _encode_auth(auth):
# strip the trailing carriage return
return encoded.rstrip()
-def open_with_auth(url):
+def open_with_auth(url, opener=urllib2.urlopen):
"""Open a urllib2 request, handling HTTP authentication"""
scheme, netloc, path, params, query, frag = urlparse(url)
@@ -892,7 +926,7 @@ def open_with_auth(url):
request = urllib2.Request(url)
request.add_header('User-Agent', user_agent)
- fp = urllib2.urlopen(request)
+ fp = opener(request)
if auth:
# Put authentication info back into request URL if same host,
diff --git a/setuptools/py27compat.py b/setuptools/py27compat.py
new file mode 100644
index 00000000..9d2886db
--- /dev/null
+++ b/setuptools/py27compat.py
@@ -0,0 +1,15 @@
+"""
+Compatibility Support for Python 2.7 and earlier
+"""
+
+import sys
+
+def get_all_headers(message, key):
+ """
+ Given an HTTPMessage, return all headers matching a given key.
+ """
+ return message.get_all(key)
+
+if sys.version_info < (3,):
+ def get_all_headers(message, key):
+ return message.getheaders(key)
diff --git a/setuptools/sandbox.py b/setuptools/sandbox.py
index 05b73d84..4e527446 100755
--- a/setuptools/sandbox.py
+++ b/setuptools/sandbox.py
@@ -9,11 +9,42 @@ except NameError:
_file = None
_open = open
from distutils.errors import DistutilsError
+from pkg_resources import working_set
+
from setuptools.compat import builtins, execfile, reduce
__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()
@@ -31,6 +62,9 @@ def run_setup(setup_script, args):
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",
@@ -52,12 +86,14 @@ def run_setup(setup_script, args):
# exclude any encodings modules. See #285
and not mod_name.startswith('encodings.')
]
- map(sys.modules.__delitem__, del_modules)
+ list(map(sys.modules.__delitem__, del_modules))
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"""
@@ -89,7 +125,6 @@ class AbstractSandbox:
builtins.open = _open
self._copy(_os)
-
def _mk_dual_path_wrapper(name):
original = getattr(_os,name)
def wrap(self,src,dst,*args,**kw):
@@ -98,7 +133,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)
@@ -121,7 +155,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):
@@ -243,16 +276,11 @@ class DirectorySandbox(AbstractSandbox):
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/setuptools/script template (dev).py b/setuptools/script template (dev).py
index 6dd9dd45..901790e7 100644
--- a/setuptools/script template (dev).py
+++ b/setuptools/script template (dev).py
@@ -3,4 +3,7 @@ __requires__ = """%(spec)r"""
from pkg_resources import require; require("""%(spec)r""")
del require
__file__ = """%(dev_path)r"""
-execfile(__file__)
+try:
+ execfile(__file__)
+except NameError:
+ exec(compile(open(__file__).read(), __file__, 'exec'))
diff --git a/setuptools/ssl_support.py b/setuptools/ssl_support.py
new file mode 100644
index 00000000..2aec655a
--- /dev/null
+++ b/setuptools/ssl_support.py
@@ -0,0 +1,248 @@
+import sys, os, socket, atexit, re
+import pkg_resources
+from pkg_resources import ResolutionError, ExtractionError
+from setuptools.compat import urllib2
+
+try:
+ import ssl
+except ImportError:
+ ssl = None
+
+__all__ = [
+ 'VerifyingHTTPSHandler', 'find_ca_bundle', 'is_available', 'cert_paths',
+ 'opener_for'
+]
+
+cert_paths = """
+/etc/pki/tls/certs/ca-bundle.crt
+/etc/ssl/certs/ca-certificates.crt
+/usr/share/ssl/certs/ca-bundle.crt
+/usr/local/share/certs/ca-root.crt
+/etc/ssl/cert.pem
+/System/Library/OpenSSL/certs/cert.pem
+""".strip().split()
+
+
+HTTPSHandler = HTTPSConnection = object
+
+for what, where in (
+ ('HTTPSHandler', ['urllib2','urllib.request']),
+ ('HTTPSConnection', ['httplib', 'http.client']),
+):
+ for module in where:
+ try:
+ exec("from %s import %s" % (module, what))
+ except ImportError:
+ pass
+
+is_available = ssl is not None and object not in (HTTPSHandler, HTTPSConnection)
+
+
+
+
+
+try:
+ from socket import create_connection
+except ImportError:
+ _GLOBAL_DEFAULT_TIMEOUT = getattr(socket, '_GLOBAL_DEFAULT_TIMEOUT', object())
+ def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT,
+ source_address=None):
+ """Connect to *address* and return the socket object.
+
+ Convenience function. Connect to *address* (a 2-tuple ``(host,
+ port)``) and return the socket object. Passing the optional
+ *timeout* parameter will set the timeout on the socket instance
+ before attempting to connect. If no *timeout* is supplied, the
+ global default timeout setting returned by :func:`getdefaulttimeout`
+ is used. If *source_address* is set it must be a tuple of (host, port)
+ for the socket to bind as a source address before making the connection.
+ An host of '' or port 0 tells the OS to use the default.
+ """
+ host, port = address
+ err = None
+ for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM):
+ af, socktype, proto, canonname, sa = res
+ sock = None
+ try:
+ sock = socket.socket(af, socktype, proto)
+ if timeout is not _GLOBAL_DEFAULT_TIMEOUT:
+ sock.settimeout(timeout)
+ if source_address:
+ sock.bind(source_address)
+ sock.connect(sa)
+ return sock
+
+ except error:
+ err = True
+ if sock is not None:
+ sock.close()
+ if err:
+ raise
+ else:
+ raise error("getaddrinfo returns an empty list")
+
+
+try:
+ from ssl import CertificateError, match_hostname
+except ImportError:
+ class CertificateError(ValueError):
+ pass
+
+ def _dnsname_to_pat(dn):
+ pats = []
+ for frag in dn.split(r'.'):
+ if frag == '*':
+ # When '*' is a fragment by itself, it matches a non-empty dotless
+ # fragment.
+ pats.append('[^.]+')
+ else:
+ # Otherwise, '*' matches any dotless fragment.
+ frag = re.escape(frag)
+ pats.append(frag.replace(r'\*', '[^.]*'))
+ return re.compile(r'\A' + r'\.'.join(pats) + r'\Z', re.IGNORECASE)
+
+ def match_hostname(cert, hostname):
+ """Verify that *cert* (in decoded format as returned by
+ SSLSocket.getpeercert()) matches the *hostname*. RFC 2818 rules
+ are mostly followed, but IP addresses are not accepted for *hostname*.
+
+ CertificateError is raised on failure. On success, the function
+ returns nothing.
+ """
+ if not cert:
+ raise ValueError("empty or no certificate")
+ dnsnames = []
+ san = cert.get('subjectAltName', ())
+ for key, value in san:
+ if key == 'DNS':
+ if _dnsname_to_pat(value).match(hostname):
+ return
+ dnsnames.append(value)
+ if not dnsnames:
+ # The subject is only checked when there is no dNSName entry
+ # in subjectAltName
+ for sub in cert.get('subject', ()):
+ for key, value in sub:
+ # XXX according to RFC 2818, the most specific Common Name
+ # must be used.
+ if key == 'commonName':
+ if _dnsname_to_pat(value).match(hostname):
+ return
+ dnsnames.append(value)
+ if len(dnsnames) > 1:
+ raise CertificateError("hostname %r "
+ "doesn't match either of %s"
+ % (hostname, ', '.join(map(repr, dnsnames))))
+ elif len(dnsnames) == 1:
+ raise CertificateError("hostname %r "
+ "doesn't match %r"
+ % (hostname, dnsnames[0]))
+ else:
+ raise CertificateError("no appropriate commonName or "
+ "subjectAltName fields were found")
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+class VerifyingHTTPSHandler(HTTPSHandler):
+ """Simple verifying handler: no auth, subclasses, timeouts, etc."""
+
+ def __init__(self, ca_bundle):
+ self.ca_bundle = ca_bundle
+ HTTPSHandler.__init__(self)
+
+ def https_open(self, req):
+ return self.do_open(
+ lambda host, **kw: VerifyingHTTPSConn(host, self.ca_bundle, **kw), req
+ )
+
+
+class VerifyingHTTPSConn(HTTPSConnection):
+ """Simple verifying connection: no auth, subclasses, timeouts, etc."""
+ def __init__(self, host, ca_bundle, **kw):
+ HTTPSConnection.__init__(self, host, **kw)
+ self.ca_bundle = ca_bundle
+
+ def connect(self):
+ sock = create_connection(
+ (self.host, self.port), getattr(self,'source_address',None)
+ )
+ self.sock = ssl.wrap_socket(
+ sock, cert_reqs=ssl.CERT_REQUIRED, ca_certs=self.ca_bundle
+ )
+ try:
+ match_hostname(self.sock.getpeercert(), self.host)
+ except CertificateError:
+ self.sock.shutdown(socket.SHUT_RDWR)
+ self.sock.close()
+ raise
+
+def opener_for(ca_bundle=None):
+ """Get a urlopen() replacement that uses ca_bundle for verification"""
+ return urllib2.build_opener(
+ VerifyingHTTPSHandler(ca_bundle or find_ca_bundle())
+ ).open
+
+
+
+_wincerts = None
+
+def get_win_certfile():
+ global _wincerts
+ if _wincerts is not None:
+ return _wincerts.name
+
+ try:
+ from wincertstore import CertFile
+ except ImportError:
+ return None
+
+ class MyCertFile(CertFile):
+ def __init__(self, stores=(), certs=()):
+ CertFile.__init__(self)
+ for store in stores:
+ self.addstore(store)
+ self.addcerts(certs)
+ atexit.register(self.close)
+
+ _wincerts = MyCertFile(stores=['CA', 'ROOT'])
+ return _wincerts.name
+
+
+def find_ca_bundle():
+ """Return an existing CA bundle path, or None"""
+ if os.name=='nt':
+ return get_win_certfile()
+ else:
+ for cert_path in cert_paths:
+ if os.path.isfile(cert_path):
+ return cert_path
+ try:
+ return pkg_resources.resource_filename('certifi', 'cacert.pem')
+ except (ImportError, ResolutionError, ExtractionError):
+ return None
+
+
+
+
+
diff --git a/setuptools/tests/__init__.py b/setuptools/tests/__init__.py
index 298141a7..b5328ce6 100644
--- a/setuptools/tests/__init__.py
+++ b/setuptools/tests/__init__.py
@@ -2,7 +2,7 @@
import sys
import os
import unittest
-import doctest
+from setuptools.tests import doctest
import distutils.core
import distutils.cmd
from distutils.errors import DistutilsOptionError, DistutilsPlatformError
@@ -11,6 +11,7 @@ from distutils.core import Extension
from distutils.version import LooseVersion
from setuptools.compat import func_code
+from setuptools.compat import func_code
import setuptools.dist
import setuptools.depends as dep
from setuptools import Feature
diff --git a/setuptools/tests/entries-v10 b/setuptools/tests/entries-v10
new file mode 100644
index 00000000..4446c501
--- /dev/null
+++ b/setuptools/tests/entries-v10
@@ -0,0 +1,615 @@
+10
+
+dir
+89001
+http://svn.python.org/projects/sandbox/branches/setuptools-0.6
+http://svn.python.org/projects
+
+
+
+2013-06-03T17:26:03.052972Z
+89000
+phillip.eby
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+6015fed2-1504-0410-9fe1-9d1591cc4771
+
+api_tests.txt
+file
+
+
+
+
+2013-06-19T13:20:47.948712Z
+dec366372ca14fbeaeb26f492bcf5725
+2013-05-15T22:04:59.389374Z
+88997
+phillip.eby
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+12312
+
+setuptools.egg-info
+dir
+
+README.txt
+file
+
+
+
+
+2013-06-19T13:20:47.948712Z
+26f0dd5d095522ba3ad999b6b6777b92
+2011-05-31T20:10:56.416725Z
+88846
+phillip.eby
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7615
+
+easy_install.py
+file
+
+
+
+
+2013-06-19T13:20:47.948712Z
+97b52fe7253bf4683f9f626f015eb72e
+2006-09-20T20:48:18.716070Z
+51935
+phillip.eby
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+126
+
+setuptools
+dir
+
+launcher.c
+file
+
+
+
+
+2013-06-19T13:20:47.924700Z
+e5a8e77de9022688b80f77fc6d742fee
+2009-10-19T21:03:29.785400Z
+75544
+phillip.eby
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7476
+
+ez_setup.py
+file
+
+
+
+
+2013-06-19T13:20:47.924700Z
+17e8ec5e08faccfcb08b5f8d5167ca14
+2011-01-20T18:50:00.815420Z
+88124
+phillip.eby
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+8350
+
+version
+file
+
+
+
+
+2013-06-19T13:20:47.924700Z
+e456da09e0c9e224a56302f8316b6dbf
+2007-01-09T19:21:05.921317Z
+53317
+phillip.eby
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1143
+
+setup.py
+file
+
+
+
+
+2013-06-19T13:20:47.924700Z
+d4e5b3c16bd61bfef6c0bb9377a3a3ea
+2013-05-15T22:04:59.389374Z
+88997
+phillip.eby
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+5228
+
+release.sh
+file
+
+
+
+
+2013-06-19T13:20:47.932704Z
+b1fd4054a1c107ff0f27baacd97be94c
+2009-10-28T17:12:45.227140Z
+75925
+phillip.eby
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1044
+
+pkg_resources.txt
+file
+
+
+
+
+2013-06-19T13:20:47.928702Z
+f497e7c92a4de207cbd9ab1943f93388
+2009-10-12T20:00:02.336146Z
+75385
+phillip.eby
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+94518
+
+site.py
+file
+
+
+
+
+2013-06-19T13:20:47.932704Z
+ebaac6fb6525f77ca950d22e6f8315df
+2006-03-11T00:39:09.666740Z
+42965
+phillip.eby
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2362
+
+version.dat
+file
+
+
+
+
+2013-06-19T13:20:47.932704Z
+8e14ecea32b9874cd7d29277494554c0
+2009-10-28T17:12:45.227140Z
+75925
+phillip.eby
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+80
+
+virtual-python.py
+file
+
+
+
+
+2013-06-19T13:20:47.932704Z
+aa857add3b5563238f0a904187f5ded9
+2005-10-17T02:26:39.000000Z
+41262
+pje
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3898
+
+setup.cfg
+file
+
+
+
+
+2013-06-19T13:20:47.932704Z
+eda883e744fce83f8107ad8dc8303536
+2006-09-21T22:26:48.050256Z
+51965
+phillip.eby
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+296
+
+setuptools.txt
+file
+
+
+
+
+2013-06-19T13:20:47.940708Z
+11926256f06046b196eaf814772504e7
+2013-05-15T22:04:59.389374Z
+88997
+phillip.eby
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+149832
+
+pkg_resources.py
+file
+
+
+
+
+2013-06-19T13:20:47.940708Z
+b63a30f5f0f0225a788c2c0e3430b3cf
+2013-05-15T22:04:59.389374Z
+88997
+phillip.eby
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+90397
+
+tests
+dir
+
+wikiup.cfg
+file
+
+
+
+
+2013-06-19T13:20:47.944710Z
+34ad845a5e0a0b46458557fa910bf429
+2008-08-21T17:23:50.797633Z
+65935
+phillip.eby
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+136
+
+EasyInstall.txt
+file
+
+
+
+
+2013-06-19T13:20:47.944710Z
+e97387c517f70fc18a377e42d19d64d4
+2013-05-15T22:04:59.389374Z
+88997
+phillip.eby
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+82495
+
diff --git a/setuptools/tests/test_develop.py b/setuptools/tests/test_develop.py
index 9d7ce711..7b90161a 100644
--- a/setuptools/tests/test_develop.py
+++ b/setuptools/tests/test_develop.py
@@ -51,7 +51,7 @@ class TestDevelopTest(unittest.TestCase):
site.USER_SITE = tempfile.mkdtemp()
def tearDown(self):
- if sys.version < "2.6" or hasattr(sys, 'real_prefix'):
+ if sys.version < "2.6" or hasattr(sys, 'real_prefix') or (hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix):
return
os.chdir(self.old_cwd)
diff --git a/setuptools/tests/test_easy_install.py b/setuptools/tests/test_easy_install.py
index d76025d2..2732bb3e 100644
--- a/setuptools/tests/test_easy_install.py
+++ b/setuptools/tests/test_easy_install.py
@@ -12,8 +12,9 @@ import textwrap
import tarfile
import distutils.core
+from setuptools.compat import StringIO, BytesIO, next, urlparse
from setuptools.sandbox import run_setup, SandboxViolation
-from setuptools.command.easy_install import easy_install, fix_jython_executable, get_script_args, main
+from setuptools.command.easy_install import easy_install, fix_jython_executable, get_script_args
from setuptools.command.easy_install import PthDistributions
from setuptools.command import easy_install as easy_install_pkg
from setuptools.dist import Distribution
@@ -84,41 +85,6 @@ class TestEasyInstallTest(unittest.TestCase):
self.assertEqual(script, WANTED)
- def test_no_setup_cfg(self):
- # makes sure easy_install as a command (main)
- # doesn't use a setup.cfg file that is located
- # in the current working directory
- dir = tempfile.mkdtemp()
- setup_cfg = open(os.path.join(dir, 'setup.cfg'), 'w')
- setup_cfg.write('[easy_install]\nfind_links = http://example.com')
- setup_cfg.close()
- setup_py = open(os.path.join(dir, 'setup.py'), 'w')
- setup_py.write(SETUP_PY)
- setup_py.close()
-
- from setuptools.dist import Distribution
-
- def _parse_command_line(self):
- msg = 'Error: a local setup.cfg was used'
- opts = self.command_options
- if 'easy_install' in opts:
- assert 'find_links' not in opts['easy_install'], msg
- return self._old_parse_command_line()
-
- Distribution._old_parse_command_line = Distribution.parse_command_line
- Distribution.parse_command_line = _parse_command_line
-
- old_wd = os.getcwd()
- try:
- os.chdir(dir)
- reset_setup_stop_context(
- lambda: self.assertRaises(SystemExit, main, [])
- )
- finally:
- os.chdir(old_wd)
- shutil.rmtree(dir)
- Distribution.parse_command_line = Distribution._old_parse_command_line
-
def test_no_find_links(self):
# new option '--no-find-links', that blocks find-links added at
# the project level
@@ -265,10 +231,10 @@ class TestUserInstallTest(unittest.TestCase):
del os.environ['PYTHONPATH']
def test_setup_requires(self):
- """Regression test for issue #318
+ """Regression test for Distribute issue #318
- Ensures that a package with setup_requires can be installed when
- distribute is installed in the user site-packages without causing a
+ Ensure that a package with setup_requires can be installed when
+ setuptools is installed in the user site-packages without causing a
SandboxViolation.
"""
@@ -306,11 +272,12 @@ class TestUserInstallTest(unittest.TestCase):
sys.stdout = StringIO()
sys.stderr = StringIO()
try:
- reset_setup_stop_context(
- lambda: run_setup(test_setup_py, ['install'])
- )
- except SandboxViolation:
- self.fail('Installation caused SandboxViolation')
+ try:
+ reset_setup_stop_context(
+ lambda: run_setup(test_setup_py, ['install'])
+ )
+ except SandboxViolation:
+ self.fail('Installation caused SandboxViolation')
finally:
sys.stdout = old_stdout
sys.stderr = old_stderr
@@ -372,13 +339,13 @@ class TestSetupRequires(unittest.TestCase):
doesn't exist) and invoke installer on it.
"""
def build_sdist(dir):
- dist_path = os.path.join(dir, 'distribute-test-fetcher-1.0.tar.gz')
+ dist_path = os.path.join(dir, 'setuptools-test-fetcher-1.0.tar.gz')
make_trivial_sdist(
dist_path,
textwrap.dedent("""
import setuptools
setuptools.setup(
- name="distribute-test-fetcher",
+ name="setuptools-test-fetcher",
version="1.0",
setup_requires = ['does-not-exist'],
)
@@ -446,7 +413,7 @@ def argv_context(f, repl):
def reset_setup_stop_context(f):
"""
- When the distribute tests are run using setup.py test, and then
+ When the setuptools tests are run using setup.py test, and then
one wants to invoke another setup() command (such as easy_install)
within those tests, it's necessary to reset the global variable
in distutils.core so that the setup() command will run naturally.
diff --git a/setuptools/tests/test_egg_info.py b/setuptools/tests/test_egg_info.py
new file mode 100644
index 00000000..f26a1f51
--- /dev/null
+++ b/setuptools/tests/test_egg_info.py
@@ -0,0 +1,40 @@
+import os
+import tempfile
+import shutil
+import unittest
+
+import pkg_resources
+from setuptools.command import egg_info
+
+ENTRIES_V10 = pkg_resources.resource_string(__name__, 'entries-v10')
+"An entries file generated with svn 1.6.17 against the legacy Setuptools repo"
+
+class TestEggInfo(unittest.TestCase):
+
+ def setUp(self):
+ self.test_dir = tempfile.mkdtemp()
+ os.mkdir(os.path.join(self.test_dir, '.svn'))
+
+ self.old_cwd = os.getcwd()
+ os.chdir(self.test_dir)
+
+ def tearDown(self):
+ os.chdir(self.old_cwd)
+ shutil.rmtree(self.test_dir)
+
+ def _write_entries(self, entries):
+ fn = os.path.join(self.test_dir, '.svn', 'entries')
+ entries_f = open(fn, 'wb')
+ entries_f.write(entries)
+ entries_f.close()
+
+ def test_version_10_format(self):
+ """
+ """
+ self._write_entries(ENTRIES_V10)
+ rev = egg_info.egg_info.get_svn_revision()
+ self.assertEqual(rev, '89000')
+
+
+def test_suite():
+ return unittest.defaultTestLoader.loadTestsFromName(__name__)
diff --git a/setuptools/tests/test_packageindex.py b/setuptools/tests/test_packageindex.py
index b596d37f..92d1e2e0 100644
--- a/setuptools/tests/test_packageindex.py
+++ b/setuptools/tests/test_packageindex.py
@@ -46,19 +46,15 @@ class TestPackageIndex(unittest.TestCase):
def _urlopen(*args):
raise httplib.BadStatusLine('line')
- old_urlopen = urllib2.urlopen
- urllib2.urlopen = _urlopen
+ index.opener = _urlopen
url = 'http://example.com'
try:
- try:
- v = index.open_url(url)
- except Exception:
- v = sys.exc_info()[1]
- self.assertTrue('line' in str(v))
- else:
- raise AssertionError('Should have raise here!')
- finally:
- urllib2.urlopen = old_urlopen
+ v = index.open_url(url)
+ except Exception:
+ v = sys.exc_info()[1]
+ self.assertTrue('line' in str(v))
+ else:
+ raise AssertionError('Should have raise here!')
def test_bad_url_double_scheme(self):
"""
@@ -103,7 +99,7 @@ class TestPackageIndex(unittest.TestCase):
"""
Download links from the pypi simple index should be used before
external download links.
- http://bitbucket.org/tarek/distribute/issue/163/md5-validation-error
+ https://bitbucket.org/tarek/distribute/issue/163
Usecase :
- someone uploads a package on pypi, a md5 is generated
@@ -112,7 +108,7 @@ class TestPackageIndex(unittest.TestCase):
- someone reuploads the package (with a different md5)
- while easy_installing, an MD5 error occurs because the external link
is used
- -> Distribute should use the link from pypi, not the external one.
+ -> Setuptools should use the link from pypi, not the external one.
"""
if sys.platform.startswith('java'):
# Skip this test on jython because binding to :0 fails
diff --git a/setuptools/tests/test_resources.py b/setuptools/tests/test_resources.py
index a2ec03c0..df5261d1 100644
--- a/setuptools/tests/test_resources.py
+++ b/setuptools/tests/test_resources.py
@@ -198,29 +198,6 @@ class DistroTests(TestCase):
)
self.assertRaises(UnknownExtra, d.requires, ["foo"])
- def testSetuptoolsDistributeCombination(self):
- # Ensure that installing a 0.7-series setuptools fails. PJE says that
- # it will not co-exist.
- ws = WorkingSet([])
- d = Distribution(
- "/some/path",
- project_name="setuptools",
- version="0.7a1")
- self.assertRaises(ValueError, ws.add, d)
- # A 0.6-series is no problem
- d2 = Distribution(
- "/some/path",
- project_name="setuptools",
- version="0.6c9")
- ws.add(d2)
-
- # a unexisting version needs to work
- ws = WorkingSet([])
- d3 = Distribution(
- "/some/path",
- project_name="setuptools")
- ws.add(d3)
-
class EntryPointTests(TestCase):
@@ -373,21 +350,13 @@ class RequirementsTests(TestCase):
self.assertTrue(d("foo-0.3a3.egg") in r2)
self.assertTrue(d("foo-0.3a5.egg") in r2)
- def testDistributeSetuptoolsOverride(self):
- # Plain setuptools or distribute mean we return distribute.
- self.assertEqual(
- Requirement.parse('setuptools').project_name, 'distribute')
- self.assertEqual(
- Requirement.parse('distribute').project_name, 'distribute')
- # setuptools lower than 0.7 means distribute
- self.assertEqual(
- Requirement.parse('setuptools==0.6c9').project_name, 'distribute')
- self.assertEqual(
- Requirement.parse('setuptools==0.6c10').project_name, 'distribute')
- self.assertEqual(
- Requirement.parse('setuptools>=0.6').project_name, 'distribute')
+ def testSetuptoolsProjectName(self):
+ """
+ The setuptools project should implement the setuptools package.
+ """
+
self.assertEqual(
- Requirement.parse('setuptools < 0.7').project_name, 'distribute')
+ Requirement.parse('setuptools').project_name, 'setuptools')
# setuptools 0.7 and higher means setuptools.
self.assertEqual(
Requirement.parse('setuptools == 0.7').project_name, 'setuptools')
@@ -559,7 +528,7 @@ class ScriptHeaderTests(TestCase):
platform = sys.platform
sys.platform = 'java1.5.0_13'
- stdout = sys.stdout
+ stdout, stderr = sys.stdout, sys.stderr
try:
# A mock sys.executable that uses a shebang line (this file)
exe = os.path.normpath(os.path.splitext(__file__)[0] + '.py')
@@ -582,7 +551,7 @@ class ScriptHeaderTests(TestCase):
finally:
del sys.modules["java"]
sys.platform = platform
- sys.stdout = stdout
+ sys.stdout, sys.stderr = stdout, stderr
@@ -591,7 +560,7 @@ class NamespaceTests(TestCase):
def setUp(self):
self._ns_pkgs = pkg_resources._namespace_packages.copy()
- self._tmpdir = tempfile.mkdtemp(prefix="tests-distribute-")
+ self._tmpdir = tempfile.mkdtemp(prefix="tests-setuptools-")
os.makedirs(os.path.join(self._tmpdir, "site-pkgs"))
self._prev_sys_path = sys.path[:]
sys.path.append(os.path.join(self._tmpdir, "site-pkgs"))
@@ -635,7 +604,7 @@ class NamespaceTests(TestCase):
try:
import pkg1.pkg2
except ImportError:
- self.fail("Distribute tried to import the parent namespace package")
+ self.fail("Setuptools tried to import the parent namespace package")
# check the _namespace_packages dict
self._assertIn("pkg1.pkg2", pkg_resources._namespace_packages.keys())
self.assertEqual(pkg_resources._namespace_packages["pkg1"], ["pkg1.pkg2"])