add python3.6 modules
This commit is contained in:
parent
7080253073
commit
e9dacd2bf3
228 changed files with 10923 additions and 6804 deletions
|
|
@ -4,20 +4,20 @@ import os
|
|||
import functools
|
||||
import distutils.core
|
||||
import distutils.filelist
|
||||
from distutils.core import Command as _Command
|
||||
from distutils.util import convert_path
|
||||
from fnmatch import fnmatchcase
|
||||
|
||||
from setuptools.extern.six.moves import filterfalse, map
|
||||
from setuptools.extern.six.moves import filter, map
|
||||
|
||||
import setuptools.version
|
||||
from setuptools.extension import Extension
|
||||
from setuptools.dist import Distribution, Feature, _get_unpatched
|
||||
from setuptools.dist import Distribution, Feature
|
||||
from setuptools.depends import Require
|
||||
from . import monkey
|
||||
|
||||
__all__ = [
|
||||
'setup', 'Distribution', 'Feature', 'Command', 'Extension', 'Require',
|
||||
'find_packages'
|
||||
'find_packages',
|
||||
]
|
||||
|
||||
__version__ = setuptools.version.__version__
|
||||
|
|
@ -32,12 +32,18 @@ lib2to3_fixer_packages = ['lib2to3.fixes']
|
|||
|
||||
|
||||
class PackageFinder(object):
|
||||
"""
|
||||
Generate a list of all Python packages found within a directory
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def find(cls, where='.', exclude=(), include=('*',)):
|
||||
"""Return a list all Python packages found within directory 'where'
|
||||
|
||||
'where' should be supplied as a "cross-platform" (i.e. URL-style)
|
||||
path; it will be converted to the appropriate local path syntax.
|
||||
'where' is the root directory which will be searched for packages. It
|
||||
should be supplied as a "cross-platform" (i.e. URL-style) path; it will
|
||||
be converted to the appropriate local path syntax.
|
||||
|
||||
'exclude' is a sequence of package names to exclude; '*' can be used
|
||||
as a wildcard in the names, such that 'foo.*' will exclude all
|
||||
subpackages of 'foo' (but not 'foo' itself).
|
||||
|
|
@ -46,78 +52,67 @@ class PackageFinder(object):
|
|||
specified, only the named packages will be included. If it's not
|
||||
specified, all found packages will be included. 'include' can contain
|
||||
shell style wildcard patterns just like 'exclude'.
|
||||
"""
|
||||
|
||||
The list of included packages is built up first and then any
|
||||
explicitly excluded packages are removed from it.
|
||||
"""
|
||||
out = cls._find_packages_iter(convert_path(where))
|
||||
out = cls.require_parents(out)
|
||||
includes = cls._build_filter(*include)
|
||||
excludes = cls._build_filter('ez_setup', '*__pycache__', *exclude)
|
||||
out = filter(includes, out)
|
||||
out = filterfalse(excludes, out)
|
||||
return list(out)
|
||||
|
||||
@staticmethod
|
||||
def require_parents(packages):
|
||||
"""
|
||||
Exclude any apparent package that apparently doesn't include its
|
||||
parent.
|
||||
|
||||
For example, exclude 'foo.bar' if 'foo' is not present.
|
||||
"""
|
||||
found = []
|
||||
for pkg in packages:
|
||||
base, sep, child = pkg.rpartition('.')
|
||||
if base and base not in found:
|
||||
continue
|
||||
found.append(pkg)
|
||||
yield pkg
|
||||
|
||||
@staticmethod
|
||||
def _candidate_dirs(base_path):
|
||||
"""
|
||||
Return all dirs in base_path that might be packages.
|
||||
"""
|
||||
has_dot = lambda name: '.' in name
|
||||
for root, dirs, files in os.walk(base_path, followlinks=True):
|
||||
# Exclude directories that contain a period, as they cannot be
|
||||
# packages. Mutate the list to avoid traversal.
|
||||
dirs[:] = filterfalse(has_dot, dirs)
|
||||
for dir in dirs:
|
||||
yield os.path.relpath(os.path.join(root, dir), base_path)
|
||||
return list(cls._find_packages_iter(
|
||||
convert_path(where),
|
||||
cls._build_filter('ez_setup', '*__pycache__', *exclude),
|
||||
cls._build_filter(*include)))
|
||||
|
||||
@classmethod
|
||||
def _find_packages_iter(cls, base_path):
|
||||
candidates = cls._candidate_dirs(base_path)
|
||||
return (
|
||||
path.replace(os.path.sep, '.')
|
||||
for path in candidates
|
||||
if cls._looks_like_package(os.path.join(base_path, path))
|
||||
)
|
||||
def _find_packages_iter(cls, where, exclude, include):
|
||||
"""
|
||||
All the packages found in 'where' that pass the 'include' filter, but
|
||||
not the 'exclude' filter.
|
||||
"""
|
||||
for root, dirs, files in os.walk(where, followlinks=True):
|
||||
# Copy dirs to iterate over it, then empty dirs.
|
||||
all_dirs = dirs[:]
|
||||
dirs[:] = []
|
||||
|
||||
for dir in all_dirs:
|
||||
full_path = os.path.join(root, dir)
|
||||
rel_path = os.path.relpath(full_path, where)
|
||||
package = rel_path.replace(os.path.sep, '.')
|
||||
|
||||
# Skip directory trees that are not valid packages
|
||||
if ('.' in dir or not cls._looks_like_package(full_path)):
|
||||
continue
|
||||
|
||||
# Should this package be included?
|
||||
if include(package) and not exclude(package):
|
||||
yield package
|
||||
|
||||
# Keep searching subdirectories, as there may be more packages
|
||||
# down there, even if the parent was excluded.
|
||||
dirs.append(dir)
|
||||
|
||||
@staticmethod
|
||||
def _looks_like_package(path):
|
||||
"""Does a directory look like a package?"""
|
||||
return os.path.isfile(os.path.join(path, '__init__.py'))
|
||||
|
||||
@staticmethod
|
||||
def _build_filter(*patterns):
|
||||
"""
|
||||
Given a list of patterns, return a callable that will be true only if
|
||||
the input matches one of the patterns.
|
||||
the input matches at least one of the patterns.
|
||||
"""
|
||||
return lambda name: any(fnmatchcase(name, pat=pat) for pat in patterns)
|
||||
|
||||
|
||||
class PEP420PackageFinder(PackageFinder):
|
||||
@staticmethod
|
||||
def _looks_like_package(path):
|
||||
return True
|
||||
|
||||
|
||||
find_packages = PackageFinder.find
|
||||
|
||||
setup = distutils.core.setup
|
||||
|
||||
_Command = _get_unpatched(_Command)
|
||||
_Command = monkey.get_unpatched(distutils.core.Command)
|
||||
|
||||
|
||||
class Command(_Command):
|
||||
__doc__ = _Command.__doc__
|
||||
|
|
@ -137,9 +132,6 @@ class Command(_Command):
|
|||
vars(cmd).update(kw)
|
||||
return cmd
|
||||
|
||||
# we can't patch distutils.cmd, alas
|
||||
distutils.core.Command = Command
|
||||
|
||||
|
||||
def _find_all_simple(path):
|
||||
"""
|
||||
|
|
@ -165,5 +157,4 @@ def findall(dir=os.curdir):
|
|||
return list(files)
|
||||
|
||||
|
||||
# fix findall bug in distutils (http://bugs.python.org/issue12885)
|
||||
distutils.filelist.findall = findall
|
||||
monkey.patch_all()
|
||||
|
|
|
|||
|
|
@ -1,24 +1,26 @@
|
|||
"""Utilities for extracting common archive formats"""
|
||||
|
||||
|
||||
__all__ = [
|
||||
"unpack_archive", "unpack_zipfile", "unpack_tarfile", "default_filter",
|
||||
"UnrecognizedFormat", "extraction_drivers", "unpack_directory",
|
||||
]
|
||||
|
||||
import zipfile
|
||||
import tarfile
|
||||
import os
|
||||
import shutil
|
||||
import posixpath
|
||||
import contextlib
|
||||
from pkg_resources import ensure_directory, ContextualZipFile
|
||||
from distutils.errors import DistutilsError
|
||||
|
||||
from pkg_resources import ensure_directory, ContextualZipFile
|
||||
|
||||
__all__ = [
|
||||
"unpack_archive", "unpack_zipfile", "unpack_tarfile", "default_filter",
|
||||
"UnrecognizedFormat", "extraction_drivers", "unpack_directory",
|
||||
]
|
||||
|
||||
|
||||
class UnrecognizedFormat(DistutilsError):
|
||||
"""Couldn't recognize the archive type"""
|
||||
|
||||
def default_filter(src,dst):
|
||||
|
||||
def default_filter(src, dst):
|
||||
"""The default progress/filter callback; returns True for all files"""
|
||||
return dst
|
||||
|
||||
|
|
@ -167,4 +169,5 @@ def unpack_tarfile(filename, extract_dir, progress_filter=default_filter):
|
|||
pass
|
||||
return True
|
||||
|
||||
|
||||
extraction_drivers = unpack_directory, unpack_zipfile, unpack_tarfile
|
||||
|
|
|
|||
148
lib/python3.4/site-packages/setuptools/build_meta.py
Normal file
148
lib/python3.4/site-packages/setuptools/build_meta.py
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
"""A PEP 517 interface to setuptools
|
||||
|
||||
Previously, when a user or a command line tool (let's call it a "frontend")
|
||||
needed to make a request of setuptools to take a certain action, for
|
||||
example, generating a list of installation requirements, the frontend would
|
||||
would call "setup.py egg_info" or "setup.py bdist_wheel" on the command line.
|
||||
|
||||
PEP 517 defines a different method of interfacing with setuptools. Rather
|
||||
than calling "setup.py" directly, the frontend should:
|
||||
|
||||
1. Set the current directory to the directory with a setup.py file
|
||||
2. Import this module into a safe python interpreter (one in which
|
||||
setuptools can potentially set global variables or crash hard).
|
||||
3. Call one of the functions defined in PEP 517.
|
||||
|
||||
What each function does is defined in PEP 517. However, here is a "casual"
|
||||
definition of the functions (this definition should not be relied on for
|
||||
bug reports or API stability):
|
||||
|
||||
- `build_wheel`: build a wheel in the folder and return the basename
|
||||
- `get_requires_for_build_wheel`: get the `setup_requires` to build
|
||||
- `prepare_metadata_for_build_wheel`: get the `install_requires`
|
||||
- `build_sdist`: build an sdist in the folder and return the basename
|
||||
- `get_requires_for_build_sdist`: get the `setup_requires` to build
|
||||
|
||||
Again, this is not a formal definition! Just a "taste" of the module.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import tokenize
|
||||
import shutil
|
||||
import contextlib
|
||||
|
||||
import setuptools
|
||||
import distutils
|
||||
|
||||
|
||||
class SetupRequirementsError(BaseException):
|
||||
def __init__(self, specifiers):
|
||||
self.specifiers = specifiers
|
||||
|
||||
|
||||
class Distribution(setuptools.dist.Distribution):
|
||||
def fetch_build_eggs(self, specifiers):
|
||||
raise SetupRequirementsError(specifiers)
|
||||
|
||||
@classmethod
|
||||
@contextlib.contextmanager
|
||||
def patch(cls):
|
||||
"""
|
||||
Replace
|
||||
distutils.dist.Distribution with this class
|
||||
for the duration of this context.
|
||||
"""
|
||||
orig = distutils.core.Distribution
|
||||
distutils.core.Distribution = cls
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
distutils.core.Distribution = orig
|
||||
|
||||
|
||||
def _run_setup(setup_script='setup.py'):
|
||||
# Note that we can reuse our build directory between calls
|
||||
# Correctness comes first, then optimization later
|
||||
__file__ = setup_script
|
||||
f = getattr(tokenize, 'open', open)(__file__)
|
||||
code = f.read().replace('\\r\\n', '\\n')
|
||||
f.close()
|
||||
exec(compile(code, __file__, 'exec'))
|
||||
|
||||
|
||||
def _fix_config(config_settings):
|
||||
config_settings = config_settings or {}
|
||||
config_settings.setdefault('--global-option', [])
|
||||
return config_settings
|
||||
|
||||
|
||||
def _get_build_requires(config_settings):
|
||||
config_settings = _fix_config(config_settings)
|
||||
requirements = ['setuptools', 'wheel']
|
||||
|
||||
sys.argv = sys.argv[:1] + ['egg_info'] + \
|
||||
config_settings["--global-option"]
|
||||
try:
|
||||
with Distribution.patch():
|
||||
_run_setup()
|
||||
except SetupRequirementsError as e:
|
||||
requirements += e.specifiers
|
||||
|
||||
return requirements
|
||||
|
||||
|
||||
def get_requires_for_build_wheel(config_settings=None):
|
||||
config_settings = _fix_config(config_settings)
|
||||
return _get_build_requires(config_settings)
|
||||
|
||||
|
||||
def get_requires_for_build_sdist(config_settings=None):
|
||||
config_settings = _fix_config(config_settings)
|
||||
return _get_build_requires(config_settings)
|
||||
|
||||
|
||||
def prepare_metadata_for_build_wheel(metadata_directory, config_settings=None):
|
||||
sys.argv = sys.argv[:1] + ['dist_info', '--egg-base', metadata_directory]
|
||||
_run_setup()
|
||||
|
||||
dist_infos = [f for f in os.listdir(metadata_directory)
|
||||
if f.endswith('.dist-info')]
|
||||
|
||||
assert len(dist_infos) == 1
|
||||
return dist_infos[0]
|
||||
|
||||
|
||||
def build_wheel(wheel_directory, config_settings=None,
|
||||
metadata_directory=None):
|
||||
config_settings = _fix_config(config_settings)
|
||||
wheel_directory = os.path.abspath(wheel_directory)
|
||||
sys.argv = sys.argv[:1] + ['bdist_wheel'] + \
|
||||
config_settings["--global-option"]
|
||||
_run_setup()
|
||||
if wheel_directory != 'dist':
|
||||
shutil.rmtree(wheel_directory)
|
||||
shutil.copytree('dist', wheel_directory)
|
||||
|
||||
wheels = [f for f in os.listdir(wheel_directory)
|
||||
if f.endswith('.whl')]
|
||||
|
||||
assert len(wheels) == 1
|
||||
return wheels[0]
|
||||
|
||||
|
||||
def build_sdist(sdist_directory, config_settings=None):
|
||||
config_settings = _fix_config(config_settings)
|
||||
sdist_directory = os.path.abspath(sdist_directory)
|
||||
sys.argv = sys.argv[:1] + ['sdist'] + \
|
||||
config_settings["--global-option"]
|
||||
_run_setup()
|
||||
if sdist_directory != 'dist':
|
||||
shutil.rmtree(sdist_directory)
|
||||
shutil.copytree('dist', sdist_directory)
|
||||
|
||||
sdists = [f for f in os.listdir(sdist_directory)
|
||||
if f.endswith('.tar.gz')]
|
||||
|
||||
assert len(sdists) == 1
|
||||
return sdists[0]
|
||||
Binary file not shown.
|
|
@ -2,7 +2,7 @@ __all__ = [
|
|||
'alias', 'bdist_egg', 'bdist_rpm', 'build_ext', 'build_py', 'develop',
|
||||
'easy_install', 'egg_info', 'install', 'install_lib', 'rotate', 'saveopts',
|
||||
'sdist', 'setopt', 'test', 'install_egg_info', 'install_scripts',
|
||||
'register', 'bdist_wininst', 'upload_docs', 'upload',
|
||||
'register', 'bdist_wininst', 'upload_docs', 'upload', 'build_clib', 'dist_info',
|
||||
]
|
||||
|
||||
from distutils.command.bdist import bdist
|
||||
|
|
@ -10,7 +10,6 @@ import sys
|
|||
|
||||
from setuptools.command import install_scripts
|
||||
|
||||
|
||||
if 'egg' not in bdist.format_commands:
|
||||
bdist.format_command['egg'] = ('bdist_egg', "Python .egg file")
|
||||
bdist.format_commands.append('egg')
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ from distutils import log
|
|||
from types import CodeType
|
||||
import sys
|
||||
import os
|
||||
import marshal
|
||||
import textwrap
|
||||
import marshal
|
||||
|
||||
from setuptools.extern import six
|
||||
|
||||
|
|
@ -38,6 +38,14 @@ def strip_module(filename):
|
|||
filename = filename[:-6]
|
||||
return filename
|
||||
|
||||
def sorted_walk(dir):
|
||||
"""Do os.walk in a reproducible way,
|
||||
independent of indeterministic filesystem readdir order
|
||||
"""
|
||||
for base, dirs, files in os.walk(dir):
|
||||
dirs.sort()
|
||||
files.sort()
|
||||
yield base, dirs, files
|
||||
|
||||
def write_stub(resource, pyfile):
|
||||
_stub_template = textwrap.dedent("""
|
||||
|
|
@ -129,7 +137,7 @@ class bdist_egg(Command):
|
|||
self.distribution.data_files.append(item)
|
||||
|
||||
try:
|
||||
log.info("installing package data to %s" % self.bdist_dir)
|
||||
log.info("installing package data to %s", self.bdist_dir)
|
||||
self.call_command('install_data', force=0, root=None)
|
||||
finally:
|
||||
self.distribution.data_files = old
|
||||
|
|
@ -152,7 +160,7 @@ class bdist_egg(Command):
|
|||
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)
|
||||
log.info("installing library code to %s", self.bdist_dir)
|
||||
instcmd = self.get_finalized_command('install')
|
||||
old_root = instcmd.root
|
||||
instcmd.root = None
|
||||
|
|
@ -169,7 +177,7 @@ class bdist_egg(Command):
|
|||
pyfile = os.path.join(self.bdist_dir, strip_module(filename) +
|
||||
'.py')
|
||||
self.stubs.append(pyfile)
|
||||
log.info("creating stub loader for %s" % ext_name)
|
||||
log.info("creating stub loader for %s", ext_name)
|
||||
if not self.dry_run:
|
||||
write_stub(os.path.basename(ext_name), pyfile)
|
||||
to_compile.append(pyfile)
|
||||
|
|
@ -186,14 +194,14 @@ class bdist_egg(Command):
|
|||
self.mkpath(egg_info)
|
||||
if self.distribution.scripts:
|
||||
script_dir = os.path.join(egg_info, 'scripts')
|
||||
log.info("installing scripts to %s" % script_dir)
|
||||
log.info("installing scripts to %s", script_dir)
|
||||
self.call_command('install_scripts', install_dir=script_dir,
|
||||
no_ep=1)
|
||||
|
||||
self.copy_metadata_to(egg_info)
|
||||
native_libs = os.path.join(egg_info, "native_libs.txt")
|
||||
if all_outputs:
|
||||
log.info("writing %s" % native_libs)
|
||||
log.info("writing %s", native_libs)
|
||||
if not self.dry_run:
|
||||
ensure_directory(native_libs)
|
||||
libs_file = open(native_libs, 'wt')
|
||||
|
|
@ -201,7 +209,7 @@ class bdist_egg(Command):
|
|||
libs_file.write('\n')
|
||||
libs_file.close()
|
||||
elif os.path.isfile(native_libs):
|
||||
log.info("removing %s" % native_libs)
|
||||
log.info("removing %s", native_libs)
|
||||
if not self.dry_run:
|
||||
os.unlink(native_libs)
|
||||
|
||||
|
|
@ -302,7 +310,7 @@ class bdist_egg(Command):
|
|||
ext_outputs = []
|
||||
|
||||
paths = {self.bdist_dir: ''}
|
||||
for base, dirs, files in os.walk(self.bdist_dir):
|
||||
for base, dirs, files in sorted_walk(self.bdist_dir):
|
||||
for filename in files:
|
||||
if os.path.splitext(filename)[1].lower() in NATIVE_EXTENSIONS:
|
||||
all_outputs.append(paths[base] + filename)
|
||||
|
|
@ -329,7 +337,7 @@ NATIVE_EXTENSIONS = dict.fromkeys('.dll .so .dylib .pyd'.split())
|
|||
|
||||
def walk_egg(egg_dir):
|
||||
"""Walk an unpacked egg's contents, skipping the metadata directory"""
|
||||
walker = os.walk(egg_dir)
|
||||
walker = sorted_walk(egg_dir)
|
||||
base, dirs, files = next(walker)
|
||||
if 'EGG-INFO' in dirs:
|
||||
dirs.remove('EGG-INFO')
|
||||
|
|
@ -429,6 +437,7 @@ def can_scan():
|
|||
log.warn("Please ask the author to include a 'zip_safe'"
|
||||
" setting (either True or False) in the package's setup.py")
|
||||
|
||||
|
||||
# Attribute names of options for commands that might need to be convinced to
|
||||
# install to the egg build directory
|
||||
|
||||
|
|
@ -457,15 +466,15 @@ def make_zipfile(zip_filename, base_dir, verbose=0, dry_run=0, compress=True,
|
|||
p = path[len(base_dir) + 1:]
|
||||
if not dry_run:
|
||||
z.write(path, p)
|
||||
log.debug("adding '%s'" % p)
|
||||
log.debug("adding '%s'", p)
|
||||
|
||||
compression = zipfile.ZIP_DEFLATED if compress else zipfile.ZIP_STORED
|
||||
if not dry_run:
|
||||
z = zipfile.ZipFile(zip_filename, mode, compression=compression)
|
||||
for dirname, dirs, files in os.walk(base_dir):
|
||||
for dirname, dirs, files in sorted_walk(base_dir):
|
||||
visit(z, dirname, files)
|
||||
z.close()
|
||||
else:
|
||||
for dirname, dirs, files in os.walk(base_dir):
|
||||
for dirname, dirs, files in sorted_walk(base_dir):
|
||||
visit(None, dirname, files)
|
||||
return zip_filename
|
||||
|
|
|
|||
98
lib/python3.4/site-packages/setuptools/command/build_clib.py
Normal file
98
lib/python3.4/site-packages/setuptools/command/build_clib.py
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
import distutils.command.build_clib as orig
|
||||
from distutils.errors import DistutilsSetupError
|
||||
from distutils import log
|
||||
from setuptools.dep_util import newer_pairwise_group
|
||||
|
||||
|
||||
class build_clib(orig.build_clib):
|
||||
"""
|
||||
Override the default build_clib behaviour to do the following:
|
||||
|
||||
1. Implement a rudimentary timestamp-based dependency system
|
||||
so 'compile()' doesn't run every time.
|
||||
2. Add more keys to the 'build_info' dictionary:
|
||||
* obj_deps - specify dependencies for each object compiled.
|
||||
this should be a dictionary mapping a key
|
||||
with the source filename to a list of
|
||||
dependencies. Use an empty string for global
|
||||
dependencies.
|
||||
* cflags - specify a list of additional flags to pass to
|
||||
the compiler.
|
||||
"""
|
||||
|
||||
def build_libraries(self, libraries):
|
||||
for (lib_name, build_info) in libraries:
|
||||
sources = build_info.get('sources')
|
||||
if sources is None or not isinstance(sources, (list, tuple)):
|
||||
raise DistutilsSetupError(
|
||||
"in 'libraries' option (library '%s'), "
|
||||
"'sources' must be present and must be "
|
||||
"a list of source filenames" % lib_name)
|
||||
sources = list(sources)
|
||||
|
||||
log.info("building '%s' library", lib_name)
|
||||
|
||||
# Make sure everything is the correct type.
|
||||
# obj_deps should be a dictionary of keys as sources
|
||||
# and a list/tuple of files that are its dependencies.
|
||||
obj_deps = build_info.get('obj_deps', dict())
|
||||
if not isinstance(obj_deps, dict):
|
||||
raise DistutilsSetupError(
|
||||
"in 'libraries' option (library '%s'), "
|
||||
"'obj_deps' must be a dictionary of "
|
||||
"type 'source: list'" % lib_name)
|
||||
dependencies = []
|
||||
|
||||
# Get the global dependencies that are specified by the '' key.
|
||||
# These will go into every source's dependency list.
|
||||
global_deps = obj_deps.get('', list())
|
||||
if not isinstance(global_deps, (list, tuple)):
|
||||
raise DistutilsSetupError(
|
||||
"in 'libraries' option (library '%s'), "
|
||||
"'obj_deps' must be a dictionary of "
|
||||
"type 'source: list'" % lib_name)
|
||||
|
||||
# Build the list to be used by newer_pairwise_group
|
||||
# each source will be auto-added to its dependencies.
|
||||
for source in sources:
|
||||
src_deps = [source]
|
||||
src_deps.extend(global_deps)
|
||||
extra_deps = obj_deps.get(source, list())
|
||||
if not isinstance(extra_deps, (list, tuple)):
|
||||
raise DistutilsSetupError(
|
||||
"in 'libraries' option (library '%s'), "
|
||||
"'obj_deps' must be a dictionary of "
|
||||
"type 'source: list'" % lib_name)
|
||||
src_deps.extend(extra_deps)
|
||||
dependencies.append(src_deps)
|
||||
|
||||
expected_objects = self.compiler.object_filenames(
|
||||
sources,
|
||||
output_dir=self.build_temp
|
||||
)
|
||||
|
||||
if newer_pairwise_group(dependencies, expected_objects) != ([], []):
|
||||
# First, compile the source code to object files in the library
|
||||
# directory. (This should probably change to putting object
|
||||
# files in a temporary build directory.)
|
||||
macros = build_info.get('macros')
|
||||
include_dirs = build_info.get('include_dirs')
|
||||
cflags = build_info.get('cflags')
|
||||
objects = self.compiler.compile(
|
||||
sources,
|
||||
output_dir=self.build_temp,
|
||||
macros=macros,
|
||||
include_dirs=include_dirs,
|
||||
extra_postargs=cflags,
|
||||
debug=self.debug
|
||||
)
|
||||
|
||||
# Now "link" the object files together into a static library.
|
||||
# (On Unix at least, this isn't really linking -- it just
|
||||
# builds an archive. Whatever.)
|
||||
self.compiler.create_static_lib(
|
||||
expected_objects,
|
||||
lib_name,
|
||||
output_dir=self.build_clib,
|
||||
debug=self.debug
|
||||
)
|
||||
|
|
@ -1,14 +1,16 @@
|
|||
from distutils.command.build_ext import build_ext as _du_build_ext
|
||||
from distutils.file_util import copy_file
|
||||
from distutils.ccompiler import new_compiler
|
||||
from distutils.sysconfig import customize_compiler
|
||||
from distutils.errors import DistutilsError
|
||||
from distutils import log
|
||||
import os
|
||||
import sys
|
||||
import itertools
|
||||
import imp
|
||||
from distutils.command.build_ext import build_ext as _du_build_ext
|
||||
from distutils.file_util import copy_file
|
||||
from distutils.ccompiler import new_compiler
|
||||
from distutils.sysconfig import customize_compiler, get_config_var
|
||||
from distutils.errors import DistutilsError
|
||||
from distutils import log
|
||||
|
||||
from setuptools.extension import Library
|
||||
from setuptools.extern import six
|
||||
|
||||
try:
|
||||
# Attempt to use Cython for building extensions, if available
|
||||
|
|
@ -16,15 +18,30 @@ try:
|
|||
except ImportError:
|
||||
_build_ext = _du_build_ext
|
||||
|
||||
try:
|
||||
# Python 2.7 or >=3.2
|
||||
from sysconfig import _CONFIG_VARS
|
||||
except ImportError:
|
||||
from distutils.sysconfig import get_config_var
|
||||
# make sure _config_vars is initialized
|
||||
get_config_var("LDSHARED")
|
||||
from distutils.sysconfig import _config_vars as _CONFIG_VARS
|
||||
|
||||
|
||||
def _customize_compiler_for_shlib(compiler):
|
||||
if sys.platform == "darwin":
|
||||
# building .dylib requires additional compiler flags on OSX; here we
|
||||
# temporarily substitute the pyconfig.h variables so that distutils'
|
||||
# 'customize_compiler' uses them before we build the shared libraries.
|
||||
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"
|
||||
customize_compiler(compiler)
|
||||
finally:
|
||||
_CONFIG_VARS.clear()
|
||||
_CONFIG_VARS.update(tmp)
|
||||
else:
|
||||
customize_compiler(compiler)
|
||||
|
||||
get_config_var("LDSHARED") # make sure _config_vars is initialized
|
||||
del get_config_var
|
||||
from distutils.sysconfig import _config_vars as _CONFIG_VARS
|
||||
|
||||
have_rtld = False
|
||||
use_stubs = False
|
||||
|
|
@ -39,9 +56,18 @@ elif os.name != 'nt':
|
|||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
if_dl = lambda s: s if have_rtld else ''
|
||||
|
||||
|
||||
def get_abi3_suffix():
|
||||
"""Return the file extension for an abi3-compliant Extension()"""
|
||||
for suffix, _, _ in (s for s in imp.get_suffixes() if s[2] == imp.C_EXTENSION):
|
||||
if '.abi3' in suffix: # Unix
|
||||
return suffix
|
||||
elif suffix == '.pyd': # Windows
|
||||
return suffix
|
||||
|
||||
|
||||
class build_ext(_build_ext):
|
||||
def run(self):
|
||||
"""Build extensions in build directory, then copy if --inplace"""
|
||||
|
|
@ -77,6 +103,15 @@ class build_ext(_build_ext):
|
|||
filename = _build_ext.get_ext_filename(self, fullname)
|
||||
if fullname in self.ext_map:
|
||||
ext = self.ext_map[fullname]
|
||||
use_abi3 = (
|
||||
six.PY3
|
||||
and getattr(ext, 'py_limited_api')
|
||||
and get_abi3_suffix()
|
||||
)
|
||||
if use_abi3:
|
||||
so_ext = _get_config_var_837('EXT_SUFFIX')
|
||||
filename = filename[:-len(so_ext)]
|
||||
filename = filename + get_abi3_suffix()
|
||||
if isinstance(ext, Library):
|
||||
fn, ext = os.path.splitext(filename)
|
||||
return self.shlib_compiler.library_filename(fn, libtype)
|
||||
|
|
@ -124,20 +159,7 @@ class build_ext(_build_ext):
|
|||
compiler = self.shlib_compiler = new_compiler(
|
||||
compiler=self.compiler, dry_run=self.dry_run, force=self.force
|
||||
)
|
||||
if sys.platform == "darwin":
|
||||
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"
|
||||
customize_compiler(compiler)
|
||||
finally:
|
||||
_CONFIG_VARS.clear()
|
||||
_CONFIG_VARS.update(tmp)
|
||||
else:
|
||||
customize_compiler(compiler)
|
||||
_customize_compiler_for_shlib(compiler)
|
||||
|
||||
if self.include_dirs is not None:
|
||||
compiler.set_include_dirs(self.include_dirs)
|
||||
|
|
@ -294,3 +316,13 @@ else:
|
|||
self.create_static_lib(
|
||||
objects, basename, output_dir, debug, target_lang
|
||||
)
|
||||
|
||||
|
||||
def _get_config_var_837(name):
|
||||
"""
|
||||
In https://github.com/pypa/setuptools/pull/837, we discovered
|
||||
Python 3.3.0 exposes the extension suffix under the name 'SO'.
|
||||
"""
|
||||
if sys.version_info < (3, 3, 1):
|
||||
name = 'SO'
|
||||
return get_config_var(name)
|
||||
|
|
|
|||
|
|
@ -6,14 +6,15 @@ import fnmatch
|
|||
import textwrap
|
||||
import io
|
||||
import distutils.errors
|
||||
import collections
|
||||
import itertools
|
||||
|
||||
from setuptools.extern.six.moves import map
|
||||
from setuptools.extern import six
|
||||
from setuptools.extern.six.moves import map, filter, filterfalse
|
||||
|
||||
try:
|
||||
from setuptools.lib2to3_ex import Mixin2to3
|
||||
except ImportError:
|
||||
|
||||
class Mixin2to3:
|
||||
def run_2to3(self, files, doctests=True):
|
||||
"do nothing"
|
||||
|
|
@ -67,6 +68,9 @@ class build_py(orig.build_py, Mixin2to3):
|
|||
return orig.build_py.__getattr__(self, attr)
|
||||
|
||||
def build_module(self, module, module_file, package):
|
||||
if six.PY2 and isinstance(package, six.string_types):
|
||||
# avoid errors on Python 2 when unicode is passed (#190)
|
||||
package = package.split('.')
|
||||
outfile, copied = orig.build_py.build_module(self, module, module_file,
|
||||
package)
|
||||
if copied:
|
||||
|
|
@ -94,12 +98,19 @@ class build_py(orig.build_py, Mixin2to3):
|
|||
|
||||
def find_data_files(self, package, src_dir):
|
||||
"""Return filenames for package's data files in 'src_dir'"""
|
||||
globs = (self.package_data.get('', [])
|
||||
+ self.package_data.get(package, []))
|
||||
files = self.manifest_files.get(package, [])[:]
|
||||
for pattern in globs:
|
||||
# Each pattern has to be converted to a platform-specific path
|
||||
files.extend(glob(os.path.join(src_dir, convert_path(pattern))))
|
||||
patterns = self._get_platform_patterns(
|
||||
self.package_data,
|
||||
package,
|
||||
src_dir,
|
||||
)
|
||||
globs_expanded = map(glob, patterns)
|
||||
# flatten the expanded globs into an iterable of matches
|
||||
globs_matches = itertools.chain.from_iterable(globs_expanded)
|
||||
glob_files = filter(os.path.isfile, globs_matches)
|
||||
files = itertools.chain(
|
||||
self.manifest_files.get(package, []),
|
||||
glob_files,
|
||||
)
|
||||
return self.exclude_data_files(package, src_dir, files)
|
||||
|
||||
def build_package_data(self):
|
||||
|
|
@ -184,26 +195,63 @@ class build_py(orig.build_py, Mixin2to3):
|
|||
|
||||
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('', [])
|
||||
+ self.exclude_package_data.get(package, [])
|
||||
files = list(files)
|
||||
patterns = self._get_platform_patterns(
|
||||
self.exclude_package_data,
|
||||
package,
|
||||
src_dir,
|
||||
)
|
||||
bad = set(
|
||||
item
|
||||
for pattern in globs
|
||||
for item in fnmatch.filter(
|
||||
files,
|
||||
os.path.join(src_dir, convert_path(pattern)),
|
||||
)
|
||||
match_groups = (
|
||||
fnmatch.filter(files, pattern)
|
||||
for pattern in patterns
|
||||
)
|
||||
seen = collections.defaultdict(itertools.count)
|
||||
return [
|
||||
# flatten the groups of matches into an iterable of matches
|
||||
matches = itertools.chain.from_iterable(match_groups)
|
||||
bad = set(matches)
|
||||
keepers = (
|
||||
fn
|
||||
for fn in files
|
||||
if fn not in bad
|
||||
# ditch dupes
|
||||
and not next(seen[fn])
|
||||
]
|
||||
)
|
||||
# ditch dupes
|
||||
return list(_unique_everseen(keepers))
|
||||
|
||||
@staticmethod
|
||||
def _get_platform_patterns(spec, package, src_dir):
|
||||
"""
|
||||
yield platform-specific path patterns (suitable for glob
|
||||
or fn_match) from a glob-based spec (such as
|
||||
self.package_data or self.exclude_package_data)
|
||||
matching package in src_dir.
|
||||
"""
|
||||
raw_patterns = itertools.chain(
|
||||
spec.get('', []),
|
||||
spec.get(package, []),
|
||||
)
|
||||
return (
|
||||
# Each pattern has to be converted to a platform-specific path
|
||||
os.path.join(src_dir, convert_path(pattern))
|
||||
for pattern in raw_patterns
|
||||
)
|
||||
|
||||
|
||||
# from Python docs
|
||||
def _unique_everseen(iterable, key=None):
|
||||
"List unique elements, preserving order. Remember all elements ever seen."
|
||||
# unique_everseen('AAAABBBCCDAABBB') --> A B C D
|
||||
# unique_everseen('ABBCcAD', str.lower) --> A B C D
|
||||
seen = set()
|
||||
seen_add = seen.add
|
||||
if key is None:
|
||||
for element in filterfalse(seen.__contains__, iterable):
|
||||
seen_add(element)
|
||||
yield element
|
||||
else:
|
||||
for element in iterable:
|
||||
k = key(element)
|
||||
if k not in seen:
|
||||
seen_add(k)
|
||||
yield element
|
||||
|
||||
|
||||
def assert_relative(path):
|
||||
|
|
|
|||
|
|
@ -9,10 +9,11 @@ from setuptools.extern import six
|
|||
|
||||
from pkg_resources import Distribution, PathMetadata, normalize_path
|
||||
from setuptools.command.easy_install import easy_install
|
||||
from setuptools import namespaces
|
||||
import setuptools
|
||||
|
||||
|
||||
class develop(easy_install):
|
||||
class develop(namespaces.DevelopInstaller, easy_install):
|
||||
"""Set up package for development"""
|
||||
|
||||
description = "install package in 'development mode'"
|
||||
|
|
@ -30,6 +31,7 @@ class develop(easy_install):
|
|||
if self.uninstall:
|
||||
self.multi_version = True
|
||||
self.uninstall_link()
|
||||
self.uninstall_namespaces()
|
||||
else:
|
||||
self.install_for_development()
|
||||
self.warn_deprecated_options()
|
||||
|
|
@ -77,15 +79,28 @@ class develop(easy_install):
|
|||
project_name=ei.egg_name
|
||||
)
|
||||
|
||||
p = self.egg_base.replace(os.sep, '/')
|
||||
if p != os.curdir:
|
||||
p = '../' * (p.count('/') + 1)
|
||||
self.setup_path = p
|
||||
p = normalize_path(os.path.join(self.install_dir, self.egg_path, p))
|
||||
if p != normalize_path(os.curdir):
|
||||
self.setup_path = self._resolve_setup_path(
|
||||
self.egg_base,
|
||||
self.install_dir,
|
||||
self.egg_path,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _resolve_setup_path(egg_base, install_dir, egg_path):
|
||||
"""
|
||||
Generate a path from egg_base back to '.' where the
|
||||
setup script resides and ensure that path points to the
|
||||
setup path from $install_dir/$egg_path.
|
||||
"""
|
||||
path_to_setup = egg_base.replace(os.sep, '/').rstrip('/')
|
||||
if path_to_setup != os.curdir:
|
||||
path_to_setup = '../' * (path_to_setup.count('/') + 1)
|
||||
resolved = normalize_path(os.path.join(install_dir, egg_path, path_to_setup))
|
||||
if resolved != normalize_path(os.curdir):
|
||||
raise DistutilsOptionError(
|
||||
"Can't get a consistent path to setup script from"
|
||||
" installation directory", p, normalize_path(os.curdir))
|
||||
" installation directory", resolved, normalize_path(os.curdir))
|
||||
return path_to_setup
|
||||
|
||||
def install_for_development(self):
|
||||
if six.PY3 and getattr(self.distribution, 'use_2to3', False):
|
||||
|
|
@ -123,6 +138,8 @@ class develop(easy_install):
|
|||
self.easy_install(setuptools.bootstrap_install_from)
|
||||
setuptools.bootstrap_install_from = None
|
||||
|
||||
self.install_namespaces()
|
||||
|
||||
# create an .egg-link in the installation dir, pointing to our egg
|
||||
log.info("Creating %s (link to %s)", self.egg_link, self.egg_base)
|
||||
if not self.dry_run:
|
||||
|
|
@ -186,6 +203,7 @@ class VersionlessRequirement(object):
|
|||
>>> str(adapted_dist.as_requirement())
|
||||
'foo'
|
||||
"""
|
||||
|
||||
def __init__(self, dist):
|
||||
self.__dist = dist
|
||||
|
||||
|
|
|
|||
37
lib/python3.4/site-packages/setuptools/command/dist_info.py
Normal file
37
lib/python3.4/site-packages/setuptools/command/dist_info.py
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
"""
|
||||
Create a dist_info directory
|
||||
As defined in the wheel specification
|
||||
"""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
|
||||
from distutils.core import Command
|
||||
|
||||
|
||||
class dist_info(Command):
|
||||
|
||||
description = 'create a .dist-info directory'
|
||||
|
||||
user_options = [
|
||||
('egg-base=', 'e', "directory containing .egg-info directories"
|
||||
" (default: top of the source tree)"),
|
||||
]
|
||||
|
||||
def initialize_options(self):
|
||||
self.egg_base = None
|
||||
|
||||
def finalize_options(self):
|
||||
pass
|
||||
|
||||
def run(self):
|
||||
egg_info = self.get_finalized_command('egg_info')
|
||||
egg_info.run()
|
||||
dist_info_dir = egg_info.egg_info[:-len('.egg-info')] + '.dist-info'
|
||||
|
||||
bdist_wheel = self.get_finalized_command('bdist_wheel')
|
||||
bdist_wheel.egg2dist(egg_info.egg_info, dist_info_dir)
|
||||
|
||||
if self.egg_base:
|
||||
shutil.move(dist_info_dir, os.path.join(
|
||||
self.egg_base, dist_info_dir))
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Easy Install
|
||||
------------
|
||||
|
|
@ -8,15 +7,17 @@ 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`__.
|
||||
|
||||
__ https://pythonhosted.org/setuptools/easy_install.html
|
||||
__ https://setuptools.readthedocs.io/en/latest/easy_install.html
|
||||
|
||||
"""
|
||||
|
||||
from glob import glob
|
||||
from distutils.util import get_platform
|
||||
from distutils.util import convert_path, subst_vars
|
||||
from distutils.errors import DistutilsArgError, DistutilsOptionError, \
|
||||
DistutilsError, DistutilsPlatformError
|
||||
from distutils.errors import (
|
||||
DistutilsArgError, DistutilsOptionError,
|
||||
DistutilsError, DistutilsPlatformError,
|
||||
)
|
||||
from distutils.command.install import INSTALL_SCHEMES, SCHEME_KEYS
|
||||
from distutils import log, dir_util
|
||||
from distutils.command.build_scripts import first_line_re
|
||||
|
|
@ -30,7 +31,6 @@ import zipfile
|
|||
import re
|
||||
import stat
|
||||
import random
|
||||
import platform
|
||||
import textwrap
|
||||
import warnings
|
||||
import site
|
||||
|
|
@ -46,10 +46,12 @@ from setuptools.extern.six.moves import configparser, map
|
|||
from setuptools import Command
|
||||
from setuptools.sandbox import run_setup
|
||||
from setuptools.py31compat import get_path, get_config_vars
|
||||
from setuptools.py27compat import rmtree_safe
|
||||
from setuptools.command import setopt
|
||||
from setuptools.archive_util import unpack_archive
|
||||
from setuptools.package_index import PackageIndex
|
||||
from setuptools.package_index import URL_SCHEME
|
||||
from setuptools.package_index import (
|
||||
PackageIndex, parse_requirement_arg, URL_SCHEME,
|
||||
)
|
||||
from setuptools.command import bdist_egg, egg_info
|
||||
from pkg_resources import (
|
||||
yield_lines, normalize_path, resource_string, ensure_directory,
|
||||
|
|
@ -57,12 +59,11 @@ from pkg_resources import (
|
|||
Distribution, PathMetadata, EggMetadata, WorkingSet, DistributionNotFound,
|
||||
VersionConflict, DEVELOP_DIST,
|
||||
)
|
||||
import pkg_resources
|
||||
import pkg_resources.py31compat
|
||||
|
||||
# Turn on PEP440Warnings
|
||||
warnings.filterwarnings("default", category=pkg_resources.PEP440Warning)
|
||||
|
||||
|
||||
__all__ = [
|
||||
'samefile', 'easy_install', 'PthDistributions', 'extract_wininst_cfg',
|
||||
'main', 'get_exe_prefixes',
|
||||
|
|
@ -74,6 +75,12 @@ def is_64bit():
|
|||
|
||||
|
||||
def samefile(p1, p2):
|
||||
"""
|
||||
Determine if two paths reference the same file.
|
||||
|
||||
Augments os.path.samefile to work on Windows and
|
||||
suppresses errors if the path doesn't exist.
|
||||
"""
|
||||
both_exist = os.path.exists(p1) and os.path.exists(p2)
|
||||
use_samefile = hasattr(os.path, 'samefile') and both_exist
|
||||
if use_samefile:
|
||||
|
|
@ -84,6 +91,7 @@ def samefile(p1, p2):
|
|||
|
||||
|
||||
if six.PY2:
|
||||
|
||||
def _to_ascii(s):
|
||||
return s
|
||||
|
||||
|
|
@ -94,6 +102,7 @@ if six.PY2:
|
|||
except UnicodeError:
|
||||
return False
|
||||
else:
|
||||
|
||||
def _to_ascii(s):
|
||||
return s.encode('ascii')
|
||||
|
||||
|
|
@ -105,6 +114,9 @@ else:
|
|||
return False
|
||||
|
||||
|
||||
_one_liner = lambda text: textwrap.dedent(text).strip().replace('\n', '; ')
|
||||
|
||||
|
||||
class easy_install(Command):
|
||||
"""Manage a download/build/install process"""
|
||||
description = "Find/get/install Python packages"
|
||||
|
|
@ -136,15 +148,13 @@ class easy_install(Command):
|
|||
('local-snapshots-ok', 'l',
|
||||
"allow building eggs from local checkouts"),
|
||||
('version', None, "print version information and exit"),
|
||||
('install-layout=', None, "installation layout to choose (known values: deb)"),
|
||||
('force-installation-into-system-dir', '0', "force installation into /usr"),
|
||||
('no-find-links', None,
|
||||
"Don't load find-links defined in packages being installed")
|
||||
]
|
||||
boolean_options = [
|
||||
'zip-ok', 'multi-version', 'exclude-scripts', 'upgrade', 'always-copy',
|
||||
'editable',
|
||||
'no-deps', 'local-snapshots-ok', 'version', 'force-installation-into-system-dir'
|
||||
'no-deps', 'local-snapshots-ok', 'version'
|
||||
]
|
||||
|
||||
if site.ENABLE_USER_SITE:
|
||||
|
|
@ -192,11 +202,6 @@ class easy_install(Command):
|
|||
self.site_dirs = None
|
||||
self.installed_projects = {}
|
||||
self.sitepy_installed = False
|
||||
# enable custom installation, known values: deb
|
||||
self.install_layout = None
|
||||
self.force_installation_into_system_dir = None
|
||||
self.multiarch = None
|
||||
|
||||
# Always read easy_install options, even if we are subclassed, or have
|
||||
# an independent instance created. This ensures that defaults will
|
||||
# always come from the standard configuration file(s)' "easy_install"
|
||||
|
|
@ -265,15 +270,10 @@ class easy_install(Command):
|
|||
self.expand_basedirs()
|
||||
self.expand_dirs()
|
||||
|
||||
if self.install_layout:
|
||||
if not self.install_layout.lower() in ['deb']:
|
||||
raise DistutilsOptionError("unknown value for --install-layout")
|
||||
self.install_layout = self.install_layout.lower()
|
||||
import sysconfig
|
||||
if sys.version_info[:2] >= (3, 3):
|
||||
self.multiarch = sysconfig.get_config_var('MULTIARCH')
|
||||
self._expand('install_dir', 'script_dir', 'build_directory',
|
||||
'site_dirs')
|
||||
self._expand(
|
||||
'install_dir', 'script_dir', 'build_directory',
|
||||
'site_dirs',
|
||||
)
|
||||
# If a non-default installation directory was specified, default the
|
||||
# script directory to match it.
|
||||
if self.script_dir is None:
|
||||
|
|
@ -296,15 +296,6 @@ class easy_install(Command):
|
|||
if self.user and self.install_purelib:
|
||||
self.install_dir = self.install_purelib
|
||||
self.script_dir = self.install_scripts
|
||||
|
||||
if self.prefix == '/usr' and not self.force_installation_into_system_dir:
|
||||
raise DistutilsOptionError("""installation into /usr
|
||||
|
||||
Trying to install into the system managed parts of the file system. Please
|
||||
consider to install to another location, or use the option
|
||||
--force-installation-into-system-dir to overwrite this warning.
|
||||
""")
|
||||
|
||||
# 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
|
||||
|
|
@ -402,9 +393,15 @@ consider to install to another location, or use the option
|
|||
|
||||
def expand_dirs(self):
|
||||
"""Calls `os.path.expanduser` on install dirs."""
|
||||
self._expand_attrs(['install_purelib', 'install_platlib',
|
||||
'install_lib', 'install_headers',
|
||||
'install_scripts', 'install_data', ])
|
||||
dirs = [
|
||||
'install_purelib',
|
||||
'install_platlib',
|
||||
'install_lib',
|
||||
'install_headers',
|
||||
'install_scripts',
|
||||
'install_data',
|
||||
]
|
||||
self._expand_attrs(dirs)
|
||||
|
||||
def run(self):
|
||||
if self.verbose != self.distribution.verbose:
|
||||
|
|
@ -436,7 +433,7 @@ consider to install to another location, or use the option
|
|||
"""
|
||||
try:
|
||||
pid = os.getpid()
|
||||
except:
|
||||
except Exception:
|
||||
pid = random.randint(0, sys.maxsize)
|
||||
return os.path.join(self.install_dir, "test-easy-install-%s" % pid)
|
||||
|
||||
|
|
@ -477,8 +474,7 @@ consider to install to another location, or use the option
|
|||
else:
|
||||
self.pth_file = None
|
||||
|
||||
PYTHONPATH = os.environ.get('PYTHONPATH', '').split(os.pathsep)
|
||||
if instdir not in map(normalize_path, filter(None, PYTHONPATH)):
|
||||
if instdir not in map(normalize_path, _pythonpath()):
|
||||
# only PYTHONPATH dirs need a site.py, so pretend it's there
|
||||
self.sitepy_installed = True
|
||||
elif self.multi_version and not os.path.exists(pth_file):
|
||||
|
|
@ -517,7 +513,7 @@ consider to install to another location, or use the option
|
|||
For information on other options, you may wish to consult the
|
||||
documentation at:
|
||||
|
||||
https://pythonhosted.org/setuptools/easy_install.html
|
||||
https://setuptools.readthedocs.io/en/latest/easy_install.html
|
||||
|
||||
Please make the appropriate changes for your system and try again.
|
||||
""").lstrip()
|
||||
|
|
@ -538,27 +534,34 @@ consider to install to another location, or use the option
|
|||
pth_file = self.pseudo_tempname() + ".pth"
|
||||
ok_file = pth_file + '.ok'
|
||||
ok_exists = os.path.exists(ok_file)
|
||||
tmpl = _one_liner("""
|
||||
import os
|
||||
f = open({ok_file!r}, 'w')
|
||||
f.write('OK')
|
||||
f.close()
|
||||
""") + '\n'
|
||||
try:
|
||||
if ok_exists:
|
||||
os.unlink(ok_file)
|
||||
dirname = os.path.dirname(ok_file)
|
||||
if not os.path.exists(dirname):
|
||||
os.makedirs(dirname)
|
||||
pkg_resources.py31compat.makedirs(dirname, exist_ok=True)
|
||||
f = open(pth_file, 'w')
|
||||
except (OSError, IOError):
|
||||
self.cant_write_to_target()
|
||||
else:
|
||||
try:
|
||||
f.write("import os; f = open(%r, 'w'); f.write('OK'); "
|
||||
"f.close()\n" % (ok_file,))
|
||||
f.write(tmpl.format(**locals()))
|
||||
f.close()
|
||||
f = None
|
||||
executable = sys.executable
|
||||
if os.name == 'nt':
|
||||
dirname, basename = os.path.split(executable)
|
||||
alt = os.path.join(dirname, 'pythonw.exe')
|
||||
if (basename.lower() == 'python.exe' and
|
||||
os.path.exists(alt)):
|
||||
use_alt = (
|
||||
basename.lower() == 'python.exe' and
|
||||
os.path.exists(alt)
|
||||
)
|
||||
if use_alt:
|
||||
# use pythonw.exe to avoid opening a console window
|
||||
executable = alt
|
||||
|
||||
|
|
@ -623,20 +626,26 @@ consider to install to another location, or use the option
|
|||
(spec.key, self.build_directory)
|
||||
)
|
||||
|
||||
@contextlib.contextmanager
|
||||
def _tmpdir(self):
|
||||
tmpdir = tempfile.mkdtemp(prefix=six.u("easy_install-"))
|
||||
try:
|
||||
# cast to str as workaround for #709 and #710 and #712
|
||||
yield str(tmpdir)
|
||||
finally:
|
||||
os.path.exists(tmpdir) and rmtree(rmtree_safe(tmpdir))
|
||||
|
||||
def easy_install(self, spec, deps=False):
|
||||
tmpdir = tempfile.mkdtemp(prefix="easy_install-")
|
||||
download = None
|
||||
if not self.editable:
|
||||
self.install_site_py()
|
||||
|
||||
try:
|
||||
with self._tmpdir() as tmpdir:
|
||||
if not isinstance(spec, Requirement):
|
||||
if URL_SCHEME(spec):
|
||||
# It's a url, download it to tmpdir and process
|
||||
self.not_editable(spec)
|
||||
download = self.package_index.download(spec, tmpdir)
|
||||
return self.install_item(None, download, tmpdir, deps,
|
||||
True)
|
||||
dl = self.package_index.download(spec, tmpdir)
|
||||
return self.install_item(None, dl, tmpdir, deps, True)
|
||||
|
||||
elif os.path.exists(spec):
|
||||
# Existing file or directory, just process it directly
|
||||
|
|
@ -662,10 +671,6 @@ consider to install to another location, or use the option
|
|||
else:
|
||||
return self.install_item(spec, dist.location, tmpdir, deps)
|
||||
|
||||
finally:
|
||||
if os.path.exists(tmpdir):
|
||||
rmtree(tmpdir)
|
||||
|
||||
def install_item(self, spec, download, tmpdir, deps, install_needed=False):
|
||||
|
||||
# Installation is also needed if file in tmpdir or is not an egg
|
||||
|
|
@ -733,10 +738,7 @@ consider to install to another location, or use the option
|
|||
elif requirement is None or dist not in requirement:
|
||||
# if we wound up with a different version, resolve what we've got
|
||||
distreq = dist.as_requirement()
|
||||
requirement = requirement or distreq
|
||||
requirement = Requirement(
|
||||
distreq.project_name, distreq.specs, requirement.extras
|
||||
)
|
||||
requirement = Requirement(str(distreq))
|
||||
log.info("Processing dependencies for %s", requirement)
|
||||
try:
|
||||
distros = WorkingSet([]).resolve(
|
||||
|
|
@ -765,8 +767,9 @@ consider to install to another location, or use the option
|
|||
def maybe_move(self, spec, dist_filename, setup_base):
|
||||
dst = os.path.join(self.build_directory, spec.key)
|
||||
if os.path.exists(dst):
|
||||
msg = ("%r already exists in %s; build directory %s will not be "
|
||||
"kept")
|
||||
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):
|
||||
|
|
@ -806,7 +809,7 @@ consider to install to another location, or use the option
|
|||
There are a couple of template scripts in the package. This
|
||||
function loads one of them and prepares it for use.
|
||||
"""
|
||||
# See https://bitbucket.org/pypa/setuptools/issue/134 for info
|
||||
# See https://github.com/pypa/setuptools/issues/134 for info
|
||||
# on script file naming and downstream issues with SVR4
|
||||
name = 'script.tmpl'
|
||||
if dev_path:
|
||||
|
|
@ -884,8 +887,10 @@ consider to install to another location, or use the option
|
|||
return Distribution.from_filename(egg_path, metadata=metadata)
|
||||
|
||||
def install_egg(self, egg_path, tmpdir):
|
||||
destination = os.path.join(self.install_dir,
|
||||
os.path.basename(egg_path))
|
||||
destination = os.path.join(
|
||||
self.install_dir,
|
||||
os.path.basename(egg_path),
|
||||
)
|
||||
destination = os.path.abspath(destination)
|
||||
if not self.dry_run:
|
||||
ensure_directory(destination)
|
||||
|
|
@ -895,8 +900,11 @@ consider to install to another location, or use the option
|
|||
if os.path.isdir(destination) and not os.path.islink(destination):
|
||||
dir_util.remove_tree(destination, dry_run=self.dry_run)
|
||||
elif os.path.exists(destination):
|
||||
self.execute(os.unlink, (destination,), "Removing " +
|
||||
destination)
|
||||
self.execute(
|
||||
os.unlink,
|
||||
(destination,),
|
||||
"Removing " + destination,
|
||||
)
|
||||
try:
|
||||
new_dist_is_zipped = False
|
||||
if os.path.isdir(egg_path):
|
||||
|
|
@ -913,13 +921,19 @@ consider to install to another location, or use the option
|
|||
f, m = shutil.move, "Moving"
|
||||
else:
|
||||
f, m = shutil.copy2, "Copying"
|
||||
self.execute(f, (egg_path, destination),
|
||||
(m + " %s to %s") %
|
||||
(os.path.basename(egg_path),
|
||||
os.path.dirname(destination)))
|
||||
update_dist_caches(destination,
|
||||
fix_zipimporter_caches=new_dist_is_zipped)
|
||||
except:
|
||||
self.execute(
|
||||
f,
|
||||
(egg_path, destination),
|
||||
(m + " %s to %s") % (
|
||||
os.path.basename(egg_path),
|
||||
os.path.dirname(destination)
|
||||
),
|
||||
)
|
||||
update_dist_caches(
|
||||
destination,
|
||||
fix_zipimporter_caches=new_dist_is_zipped,
|
||||
)
|
||||
except Exception:
|
||||
update_dist_caches(destination, fix_zipimporter_caches=False)
|
||||
raise
|
||||
|
||||
|
|
@ -941,8 +955,8 @@ consider to install to another location, or use the option
|
|||
)
|
||||
|
||||
# Convert the .exe to an unpacked egg
|
||||
egg_path = dist.location = os.path.join(tmpdir, dist.egg_name() +
|
||||
'.egg')
|
||||
egg_path = os.path.join(tmpdir, dist.egg_name() + '.egg')
|
||||
dist.location = egg_path
|
||||
egg_tmp = egg_path + '.tmp'
|
||||
_egg_info = os.path.join(egg_tmp, 'EGG-INFO')
|
||||
pkg_inf = os.path.join(_egg_info, 'PKG-INFO')
|
||||
|
|
@ -960,13 +974,13 @@ consider to install to another location, or use the option
|
|||
f.close()
|
||||
script_dir = os.path.join(_egg_info, 'scripts')
|
||||
# delete entry-point scripts to avoid duping
|
||||
self.delete_blockers(
|
||||
[os.path.join(script_dir, args[0]) for args in
|
||||
ScriptWriter.get_args(dist)]
|
||||
)
|
||||
self.delete_blockers([
|
||||
os.path.join(script_dir, args[0])
|
||||
for args in ScriptWriter.get_args(dist)
|
||||
])
|
||||
# Build .egg file from tmpdir
|
||||
bdist_egg.make_zipfile(
|
||||
egg_path, egg_tmp, verbose=self.verbose, dry_run=self.dry_run
|
||||
egg_path, egg_tmp, verbose=self.verbose, dry_run=self.dry_run,
|
||||
)
|
||||
# install the .egg
|
||||
return self.install_egg(egg_path, tmpdir)
|
||||
|
|
@ -1154,7 +1168,7 @@ consider to install to another location, or use the option
|
|||
if dist.location in self.pth_file.paths:
|
||||
log.info(
|
||||
"%s is already the active version in easy-install.pth",
|
||||
dist
|
||||
dist,
|
||||
)
|
||||
else:
|
||||
log.info("Adding %s to easy-install.pth file", dist)
|
||||
|
|
@ -1215,7 +1229,7 @@ consider to install to another location, or use the option
|
|||
if self.optimize:
|
||||
byte_compile(
|
||||
to_compile, optimize=self.optimize, force=1,
|
||||
dry_run=self.dry_run
|
||||
dry_run=self.dry_run,
|
||||
)
|
||||
finally:
|
||||
log.set_verbosity(self.verbose) # restore original verbosity
|
||||
|
|
@ -1246,7 +1260,8 @@ consider to install to another location, or use the option
|
|||
* You can set up the installation directory to support ".pth" files by
|
||||
using one of the approaches described here:
|
||||
|
||||
https://pythonhosted.org/setuptools/easy_install.html#custom-installation-locations
|
||||
https://setuptools.readthedocs.io/en/latest/easy_install.html#custom-installation-locations
|
||||
|
||||
|
||||
Please make the appropriate changes for your system and try again.""").lstrip()
|
||||
|
||||
|
|
@ -1262,17 +1277,14 @@ consider to install to another location, or use the option
|
|||
|
||||
sitepy = os.path.join(self.install_dir, "site.py")
|
||||
source = resource_string("setuptools", "site-patch.py")
|
||||
source = source.decode('utf-8')
|
||||
current = ""
|
||||
|
||||
if os.path.exists(sitepy):
|
||||
log.debug("Checking existing site.py in %s", self.install_dir)
|
||||
f = open(sitepy, 'rb')
|
||||
current = f.read()
|
||||
# we want str, not bytes
|
||||
if six.PY3:
|
||||
current = current.decode()
|
||||
with io.open(sitepy) as strm:
|
||||
current = strm.read()
|
||||
|
||||
f.close()
|
||||
if not current.startswith('def __boot():'):
|
||||
raise DistutilsError(
|
||||
"%s is not a setuptools-generated site.py; please"
|
||||
|
|
@ -1283,9 +1295,8 @@ consider to install to another location, or use the option
|
|||
log.info("Creating %s", sitepy)
|
||||
if not self.dry_run:
|
||||
ensure_directory(sitepy)
|
||||
f = open(sitepy, 'wb')
|
||||
f.write(source)
|
||||
f.close()
|
||||
with io.open(sitepy, 'w', encoding='utf-8') as strm:
|
||||
strm.write(source)
|
||||
self.byte_compile([sitepy])
|
||||
|
||||
self.sitepy_installed = True
|
||||
|
|
@ -1300,28 +1311,11 @@ consider to install to another location, or use the option
|
|||
self.debug_print("os.makedirs('%s', 0o700)" % path)
|
||||
os.makedirs(path, 0o700)
|
||||
|
||||
if sys.version[:3] in ('2.3', '2.4', '2.5') or 'real_prefix' in sys.__dict__:
|
||||
sitedir_name = 'site-packages'
|
||||
else:
|
||||
sitedir_name = 'dist-packages'
|
||||
|
||||
INSTALL_SCHEMES = dict(
|
||||
posix=dict(
|
||||
install_dir='$base/lib/python$py_version_short/site-packages',
|
||||
script_dir='$base/bin',
|
||||
),
|
||||
unix_local = dict(
|
||||
install_dir = '$base/local/lib/python$py_version_short/%s' % sitedir_name,
|
||||
script_dir = '$base/local/bin',
|
||||
),
|
||||
posix_local = dict(
|
||||
install_dir = '$base/local/lib/python$py_version_short/%s' % sitedir_name,
|
||||
script_dir = '$base/local/bin',
|
||||
),
|
||||
deb_system = dict(
|
||||
install_dir = '$base/lib/python3/%s' % sitedir_name,
|
||||
script_dir = '$base/bin',
|
||||
),
|
||||
)
|
||||
|
||||
DEFAULT_SCHEME = dict(
|
||||
|
|
@ -1332,18 +1326,11 @@ consider to install to another location, or use the option
|
|||
def _expand(self, *attrs):
|
||||
config_vars = self.get_finalized_command('install').config_vars
|
||||
|
||||
if self.prefix or self.install_layout:
|
||||
if self.install_layout and self.install_layout in ['deb']:
|
||||
scheme_name = "deb_system"
|
||||
self.prefix = '/usr'
|
||||
elif self.prefix or 'real_prefix' in sys.__dict__:
|
||||
scheme_name = os.name
|
||||
else:
|
||||
scheme_name = "posix_local"
|
||||
if self.prefix:
|
||||
# Set default install_dir/scripts from --prefix
|
||||
config_vars = config_vars.copy()
|
||||
config_vars['base'] = self.prefix
|
||||
scheme = self.INSTALL_SCHEMES.get(scheme_name,self.DEFAULT_SCHEME)
|
||||
scheme = self.INSTALL_SCHEMES.get(os.name, self.DEFAULT_SCHEME)
|
||||
for attr, val in scheme.items():
|
||||
if getattr(self, attr, None) is None:
|
||||
setattr(self, attr, val)
|
||||
|
|
@ -1359,10 +1346,21 @@ consider to install to another location, or use the option
|
|||
setattr(self, attr, val)
|
||||
|
||||
|
||||
def _pythonpath():
|
||||
items = os.environ.get('PYTHONPATH', '').split(os.pathsep)
|
||||
return filter(None, items)
|
||||
|
||||
|
||||
def get_site_dirs():
|
||||
# return a list of 'site' dirs
|
||||
sitedirs = [_f for _f in os.environ.get('PYTHONPATH',
|
||||
'').split(os.pathsep) if _f]
|
||||
"""
|
||||
Return a list of 'site' dirs
|
||||
"""
|
||||
|
||||
sitedirs = []
|
||||
|
||||
# start with PYTHONPATH
|
||||
sitedirs.extend(_pythonpath())
|
||||
|
||||
prefixes = [sys.prefix]
|
||||
if sys.exec_prefix != sys.prefix:
|
||||
prefixes.append(sys.exec_prefix)
|
||||
|
|
@ -1371,20 +1369,20 @@ def get_site_dirs():
|
|||
if sys.platform in ('os2emx', 'riscos'):
|
||||
sitedirs.append(os.path.join(prefix, "Lib", "site-packages"))
|
||||
elif os.sep == '/':
|
||||
sitedirs.extend([os.path.join(prefix,
|
||||
"lib",
|
||||
"python" + sys.version[:3],
|
||||
"site-packages"),
|
||||
os.path.join(prefix, "lib", "site-python")])
|
||||
sitedirs.extend([
|
||||
os.path.join(
|
||||
prefix,
|
||||
"lib",
|
||||
"python" + sys.version[:3],
|
||||
"site-packages",
|
||||
),
|
||||
os.path.join(prefix, "lib", "site-python"),
|
||||
])
|
||||
else:
|
||||
if sys.version[:3] in ('2.3', '2.4', '2.5'):
|
||||
sdir = "site-packages"
|
||||
else:
|
||||
sdir = "dist-packages"
|
||||
sitedirs.extend(
|
||||
[os.path.join(prefix, "local/lib", "python" + sys.version[:3], sdir),
|
||||
os.path.join(prefix, "lib", "python" + sys.version[:3], sdir)]
|
||||
)
|
||||
sitedirs.extend([
|
||||
prefix,
|
||||
os.path.join(prefix, "lib", "site-packages"),
|
||||
])
|
||||
if sys.platform == 'darwin':
|
||||
# for framework builds *only* we add the standard Apple
|
||||
# locations. Currently only per-user, but /Library and
|
||||
|
|
@ -1392,12 +1390,14 @@ def get_site_dirs():
|
|||
if 'Python.framework' in prefix:
|
||||
home = os.environ.get('HOME')
|
||||
if home:
|
||||
sitedirs.append(
|
||||
os.path.join(home,
|
||||
'Library',
|
||||
'Python',
|
||||
sys.version[:3],
|
||||
'site-packages'))
|
||||
home_sp = os.path.join(
|
||||
home,
|
||||
'Library',
|
||||
'Python',
|
||||
sys.version[:3],
|
||||
'site-packages',
|
||||
)
|
||||
sitedirs.append(home_sp)
|
||||
lib_paths = get_path('purelib'), get_path('platlib')
|
||||
for site_lib in lib_paths:
|
||||
if site_lib not in sitedirs:
|
||||
|
|
@ -1406,6 +1406,11 @@ def get_site_dirs():
|
|||
if site.ENABLE_USER_SITE:
|
||||
sitedirs.append(site.USER_SITE)
|
||||
|
||||
try:
|
||||
sitedirs.extend(site.getsitepackages())
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
sitedirs = list(map(normalize_path, sitedirs))
|
||||
|
||||
return sitedirs
|
||||
|
|
@ -1473,8 +1478,8 @@ def extract_wininst_cfg(dist_filename):
|
|||
return None # not a valid tag
|
||||
|
||||
f.seek(prepended - (12 + cfglen))
|
||||
cfg = configparser.RawConfigParser(
|
||||
{'version': '', 'target_version': ''})
|
||||
init = {'version': '', 'target_version': ''}
|
||||
cfg = configparser.RawConfigParser(init)
|
||||
try:
|
||||
part = f.read(cfglen)
|
||||
# Read up to the first null byte.
|
||||
|
|
@ -1497,7 +1502,8 @@ def get_exe_prefixes(exe_filename):
|
|||
"""Get exe->egg path translations for a given .exe file"""
|
||||
|
||||
prefixes = [
|
||||
('PURELIB/', ''), ('PLATLIB/pywin32_system32', ''),
|
||||
('PURELIB/', ''),
|
||||
('PLATLIB/pywin32_system32', ''),
|
||||
('PLATLIB/', ''),
|
||||
('SCRIPTS/', 'EGG-INFO/scripts/'),
|
||||
('DATA/lib/site-packages', ''),
|
||||
|
|
@ -1531,15 +1537,6 @@ def get_exe_prefixes(exe_filename):
|
|||
return prefixes
|
||||
|
||||
|
||||
def parse_requirement_arg(spec):
|
||||
try:
|
||||
return Requirement.parse(spec)
|
||||
except ValueError:
|
||||
raise DistutilsError(
|
||||
"Not a URL, existing file, or requirement spec: %r" % (spec,)
|
||||
)
|
||||
|
||||
|
||||
class PthDistributions(Environment):
|
||||
"""A .pth file with Distribution paths in it"""
|
||||
|
||||
|
|
@ -1649,7 +1646,6 @@ class PthDistributions(Environment):
|
|||
|
||||
|
||||
class RewritePthDistributions(PthDistributions):
|
||||
|
||||
@classmethod
|
||||
def _wrap_lines(cls, lines):
|
||||
yield cls.prelude
|
||||
|
|
@ -1657,12 +1653,11 @@ class RewritePthDistributions(PthDistributions):
|
|||
yield line
|
||||
yield cls.postlude
|
||||
|
||||
_inline = lambda text: textwrap.dedent(text).strip().replace('\n', '; ')
|
||||
prelude = _inline("""
|
||||
prelude = _one_liner("""
|
||||
import sys
|
||||
sys.__plen = len(sys.path)
|
||||
""")
|
||||
postlude = _inline("""
|
||||
postlude = _one_liner("""
|
||||
import sys
|
||||
new = sys.path[sys.__plen:]
|
||||
del sys.path[sys.__plen:]
|
||||
|
|
@ -1672,7 +1667,7 @@ class RewritePthDistributions(PthDistributions):
|
|||
""")
|
||||
|
||||
|
||||
if os.environ.get('SETUPTOOLS_SYS_PATH_TECHNIQUE', 'rewrite') == 'rewrite':
|
||||
if os.environ.get('SETUPTOOLS_SYS_PATH_TECHNIQUE', 'raw') == 'rewrite':
|
||||
PthDistributions = RewritePthDistributions
|
||||
|
||||
|
||||
|
|
@ -1689,7 +1684,7 @@ def _first_line_re():
|
|||
|
||||
|
||||
def auto_chmod(func, arg, exc):
|
||||
if func is os.remove and os.name == 'nt':
|
||||
if func in [os.unlink, os.remove] and os.name == 'nt':
|
||||
chmod(arg, stat.S_IWRITE)
|
||||
return func(arg)
|
||||
et, ev, _ = sys.exc_info()
|
||||
|
|
@ -1821,7 +1816,7 @@ def _update_zipimporter_cache(normalized_path, cache, updater=None):
|
|||
# * Does not support the dict.pop() method, forcing us to use the
|
||||
# get/del patterns instead. For more detailed information see the
|
||||
# following links:
|
||||
# https://bitbucket.org/pypa/setuptools/issue/202/more-robust-zipimporter-cache-invalidation#comment-10495960
|
||||
# https://github.com/pypa/setuptools/issues/202#issuecomment-202913420
|
||||
# https://bitbucket.org/pypy/pypy/src/dd07756a34a41f674c0cacfbc8ae1d4cc9ea2ae4/pypy/module/zipimport/interp_zipimport.py#cl-99
|
||||
old_entry = cache[p]
|
||||
del cache[p]
|
||||
|
|
@ -1842,6 +1837,7 @@ def _remove_and_clear_zip_directory_cache_data(normalized_path):
|
|||
normalized_path, zipimport._zip_directory_cache,
|
||||
updater=clear_and_remove_cached_zip_archive_directory_data)
|
||||
|
||||
|
||||
# PyPy Python implementation does not allow directly writing to the
|
||||
# zipimport._zip_directory_cache and so prevents us from attempting to correct
|
||||
# its content. The best we can do there is clear the problematic cache content
|
||||
|
|
@ -1854,6 +1850,7 @@ if '__pypy__' in sys.builtin_module_names:
|
|||
_replace_zip_directory_cache_data = \
|
||||
_remove_and_clear_zip_directory_cache_data
|
||||
else:
|
||||
|
||||
def _replace_zip_directory_cache_data(normalized_path):
|
||||
def replace_cached_zip_archive_directory_data(path, old_entry):
|
||||
# N.B. In theory, we could load the zip directory information just
|
||||
|
|
@ -1996,11 +1993,21 @@ class CommandSpec(list):
|
|||
def as_header(self):
|
||||
return self._render(self + list(self.options))
|
||||
|
||||
@staticmethod
|
||||
def _strip_quotes(item):
|
||||
_QUOTES = '"\''
|
||||
for q in _QUOTES:
|
||||
if item.startswith(q) and item.endswith(q):
|
||||
return item[1:-1]
|
||||
return item
|
||||
|
||||
@staticmethod
|
||||
def _render(items):
|
||||
cmdline = subprocess.list2cmdline(items)
|
||||
cmdline = subprocess.list2cmdline(
|
||||
CommandSpec._strip_quotes(item.strip()) for item in items)
|
||||
return '#!' + cmdline + '\n'
|
||||
|
||||
|
||||
# For pbr compat; will be removed in a future version.
|
||||
sys_executable = CommandSpec._sys_executable()
|
||||
|
||||
|
|
@ -2015,13 +2022,15 @@ class ScriptWriter(object):
|
|||
gui apps.
|
||||
"""
|
||||
|
||||
template = textwrap.dedent("""
|
||||
template = textwrap.dedent(r"""
|
||||
# EASY-INSTALL-ENTRY-SCRIPT: %(spec)r,%(group)r,%(name)r
|
||||
__requires__ = %(spec)r
|
||||
import re
|
||||
import sys
|
||||
from pkg_resources import load_entry_point
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(
|
||||
load_entry_point(%(spec)r, %(group)r, %(name)r)()
|
||||
)
|
||||
|
|
@ -2130,8 +2139,11 @@ class WindowsScriptWriter(ScriptWriter):
|
|||
"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)
|
||||
msg = (
|
||||
"{ext} not listed in PATHEXT; scripts will not be "
|
||||
"recognized as executables."
|
||||
).format(**locals())
|
||||
warnings.warn(msg, UserWarning)
|
||||
old = ['.pya', '.py', '-script.py', '.pyc', '.pyo', '.pyw', '.exe']
|
||||
old.remove(ext)
|
||||
header = cls._adjust_header(type_, header)
|
||||
|
|
@ -2210,8 +2222,6 @@ def get_win_launcher(type):
|
|||
Returns the executable as a byte string.
|
||||
"""
|
||||
launcher_fn = '%s.exe' % type
|
||||
if platform.machine().lower() == 'arm':
|
||||
launcher_fn = launcher_fn.replace(".", "-arm.")
|
||||
if is_64bit():
|
||||
launcher_fn = launcher_fn.replace(".", "-64.")
|
||||
else:
|
||||
|
|
@ -2228,39 +2238,7 @@ def load_launcher_manifest(name):
|
|||
|
||||
|
||||
def rmtree(path, ignore_errors=False, onerror=auto_chmod):
|
||||
"""Recursively delete a directory tree.
|
||||
|
||||
This code is taken from the Python 2.4 version of 'shutil', because
|
||||
the 2.3 version doesn't really work right.
|
||||
"""
|
||||
if ignore_errors:
|
||||
def onerror(*args):
|
||||
pass
|
||||
elif onerror is None:
|
||||
def onerror(*args):
|
||||
raise
|
||||
names = []
|
||||
try:
|
||||
names = os.listdir(path)
|
||||
except os.error:
|
||||
onerror(os.listdir, path, sys.exc_info())
|
||||
for name in names:
|
||||
fullname = os.path.join(path, name)
|
||||
try:
|
||||
mode = os.lstat(fullname).st_mode
|
||||
except os.error:
|
||||
mode = 0
|
||||
if stat.S_ISDIR(mode):
|
||||
rmtree(fullname, ignore_errors, onerror)
|
||||
else:
|
||||
try:
|
||||
os.remove(fullname)
|
||||
except os.error:
|
||||
onerror(os.remove, fullname, sys.exc_info())
|
||||
try:
|
||||
os.rmdir(path)
|
||||
except os.error:
|
||||
onerror(os.rmdir, path, sys.exc_info())
|
||||
return shutil.rmtree(path, ignore_errors, onerror)
|
||||
|
||||
|
||||
def current_umask():
|
||||
|
|
@ -2297,7 +2275,8 @@ def main(argv=None, **kw):
|
|||
setup(
|
||||
script_args=['-q', 'easy_install', '-v'] + argv,
|
||||
script_name=sys.argv[0] or 'easy_install',
|
||||
distclass=DistributionWithoutHelpCommands, **kw
|
||||
distclass=DistributionWithoutHelpCommands,
|
||||
**kw
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
Create a distribution's .egg-info directory and contents"""
|
||||
|
||||
from distutils.filelist import FileList as _FileList
|
||||
from distutils.errors import DistutilsInternalError
|
||||
from distutils.util import convert_path
|
||||
from distutils import log
|
||||
import distutils.errors
|
||||
|
|
@ -13,6 +14,7 @@ import sys
|
|||
import io
|
||||
import warnings
|
||||
import time
|
||||
import collections
|
||||
|
||||
from setuptools.extern import six
|
||||
from setuptools.extern.six.moves import map
|
||||
|
|
@ -26,13 +28,92 @@ from pkg_resources import (
|
|||
parse_requirements, safe_name, parse_version,
|
||||
safe_version, yield_lines, EntryPoint, iter_entry_points, to_filename)
|
||||
import setuptools.unicode_utils as unicode_utils
|
||||
from setuptools.glob import glob
|
||||
|
||||
from pkg_resources.extern import packaging
|
||||
|
||||
try:
|
||||
from setuptools_svn import svn_utils
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
def translate_pattern(glob):
|
||||
"""
|
||||
Translate a file path glob like '*.txt' in to a regular expression.
|
||||
This differs from fnmatch.translate which allows wildcards to match
|
||||
directory separators. It also knows about '**/' which matches any number of
|
||||
directories.
|
||||
"""
|
||||
pat = ''
|
||||
|
||||
# This will split on '/' within [character classes]. This is deliberate.
|
||||
chunks = glob.split(os.path.sep)
|
||||
|
||||
sep = re.escape(os.sep)
|
||||
valid_char = '[^%s]' % (sep,)
|
||||
|
||||
for c, chunk in enumerate(chunks):
|
||||
last_chunk = c == len(chunks) - 1
|
||||
|
||||
# Chunks that are a literal ** are globstars. They match anything.
|
||||
if chunk == '**':
|
||||
if last_chunk:
|
||||
# Match anything if this is the last component
|
||||
pat += '.*'
|
||||
else:
|
||||
# Match '(name/)*'
|
||||
pat += '(?:%s+%s)*' % (valid_char, sep)
|
||||
continue # Break here as the whole path component has been handled
|
||||
|
||||
# Find any special characters in the remainder
|
||||
i = 0
|
||||
chunk_len = len(chunk)
|
||||
while i < chunk_len:
|
||||
char = chunk[i]
|
||||
if char == '*':
|
||||
# Match any number of name characters
|
||||
pat += valid_char + '*'
|
||||
elif char == '?':
|
||||
# Match a name character
|
||||
pat += valid_char
|
||||
elif char == '[':
|
||||
# Character class
|
||||
inner_i = i + 1
|
||||
# Skip initial !/] chars
|
||||
if inner_i < chunk_len and chunk[inner_i] == '!':
|
||||
inner_i = inner_i + 1
|
||||
if inner_i < chunk_len and chunk[inner_i] == ']':
|
||||
inner_i = inner_i + 1
|
||||
|
||||
# Loop till the closing ] is found
|
||||
while inner_i < chunk_len and chunk[inner_i] != ']':
|
||||
inner_i = inner_i + 1
|
||||
|
||||
if inner_i >= chunk_len:
|
||||
# Got to the end of the string without finding a closing ]
|
||||
# Do not treat this as a matching group, but as a literal [
|
||||
pat += re.escape(char)
|
||||
else:
|
||||
# Grab the insides of the [brackets]
|
||||
inner = chunk[i + 1:inner_i]
|
||||
char_class = ''
|
||||
|
||||
# Class negation
|
||||
if inner[0] == '!':
|
||||
char_class = '^'
|
||||
inner = inner[1:]
|
||||
|
||||
char_class += re.escape(inner)
|
||||
pat += '[%s]' % (char_class,)
|
||||
|
||||
# Skip to the end ]
|
||||
i = inner_i
|
||||
else:
|
||||
pat += re.escape(char)
|
||||
i += 1
|
||||
|
||||
# Join each chunk with the dir separator
|
||||
if not last_chunk:
|
||||
pat += sep
|
||||
|
||||
pat += r'\Z'
|
||||
return re.compile(pat, flags=re.MULTILINE|re.DOTALL)
|
||||
|
||||
|
||||
class egg_info(Command):
|
||||
|
|
@ -41,18 +122,15 @@ class egg_info(Command):
|
|||
user_options = [
|
||||
('egg-base=', 'e', "directory containing .egg-info directories"
|
||||
" (default: top of the source tree)"),
|
||||
('tag-svn-revision', 'r',
|
||||
"Add subversion revision ID to version number"),
|
||||
('tag-date', 'd', "Add date stamp (e.g. 20050528) to version number"),
|
||||
('tag-build=', 'b', "Specify explicit tag to add to version number"),
|
||||
('no-svn-revision', 'R',
|
||||
"Don't add subversion revision ID [default]"),
|
||||
('no-date', 'D', "Don't include date stamp [default]"),
|
||||
]
|
||||
|
||||
boolean_options = ['tag-date', 'tag-svn-revision']
|
||||
negative_opt = {'no-svn-revision': 'tag-svn-revision',
|
||||
'no-date': 'tag-date'}
|
||||
boolean_options = ['tag-date']
|
||||
negative_opt = {
|
||||
'no-date': 'tag-date',
|
||||
}
|
||||
|
||||
def initialize_options(self):
|
||||
self.egg_name = None
|
||||
|
|
@ -60,20 +138,36 @@ class egg_info(Command):
|
|||
self.egg_base = None
|
||||
self.egg_info = None
|
||||
self.tag_build = None
|
||||
self.tag_svn_revision = 0
|
||||
self.tag_date = 0
|
||||
self.broken_egg_info = False
|
||||
self.vtags = None
|
||||
|
||||
####################################
|
||||
# allow the 'tag_svn_revision' to be detected and
|
||||
# set, supporting sdists built on older Setuptools.
|
||||
@property
|
||||
def tag_svn_revision(self):
|
||||
pass
|
||||
|
||||
@tag_svn_revision.setter
|
||||
def tag_svn_revision(self, value):
|
||||
pass
|
||||
####################################
|
||||
|
||||
def save_version_info(self, filename):
|
||||
values = dict(
|
||||
egg_info=dict(
|
||||
tag_svn_revision=0,
|
||||
tag_date=0,
|
||||
tag_build=self.tags(),
|
||||
)
|
||||
)
|
||||
edit_config(filename, values)
|
||||
"""
|
||||
Materialize the value of date into the
|
||||
build tag. Install build keys in a deterministic order
|
||||
to avoid arbitrary reordering on subsequent builds.
|
||||
"""
|
||||
# python 2.6 compatibility
|
||||
odict = getattr(collections, 'OrderedDict', dict)
|
||||
egg_info = odict()
|
||||
# follow the order these keys would have been added
|
||||
# when PYTHONHASHSEED=0
|
||||
egg_info['tag_build'] = self.tags()
|
||||
egg_info['tag_date'] = 0
|
||||
edit_config(filename, dict(egg_info=egg_info))
|
||||
|
||||
def finalize_options(self):
|
||||
self.egg_name = safe_name(self.distribution.get_name())
|
||||
|
|
@ -189,18 +283,10 @@ class egg_info(Command):
|
|||
version = ''
|
||||
if self.tag_build:
|
||||
version += self.tag_build
|
||||
if self.tag_svn_revision:
|
||||
version += '-r%s' % self.get_svn_revision()
|
||||
if self.tag_date:
|
||||
version += time.strftime("-%Y%m%d")
|
||||
return version
|
||||
|
||||
@staticmethod
|
||||
def get_svn_revision():
|
||||
if 'svn_utils' not in globals():
|
||||
return "0"
|
||||
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")
|
||||
|
|
@ -226,7 +312,155 @@ class egg_info(Command):
|
|||
|
||||
|
||||
class FileList(_FileList):
|
||||
"""File list that accepts only existing, platform-independent paths"""
|
||||
# Implementations of the various MANIFEST.in commands
|
||||
|
||||
def process_template_line(self, line):
|
||||
# Parse the line: split it up, make sure the right number of words
|
||||
# is there, and return the relevant words. 'action' is always
|
||||
# defined: it's the first word of the line. Which of the other
|
||||
# three are defined depends on the action; it'll be either
|
||||
# patterns, (dir and patterns), or (dir_pattern).
|
||||
(action, patterns, dir, dir_pattern) = self._parse_template_line(line)
|
||||
|
||||
# OK, now we know that the action is valid and we have the
|
||||
# right number of words on the line for that action -- so we
|
||||
# can proceed with minimal error-checking.
|
||||
if action == 'include':
|
||||
self.debug_print("include " + ' '.join(patterns))
|
||||
for pattern in patterns:
|
||||
if not self.include(pattern):
|
||||
log.warn("warning: no files found matching '%s'", pattern)
|
||||
|
||||
elif action == 'exclude':
|
||||
self.debug_print("exclude " + ' '.join(patterns))
|
||||
for pattern in patterns:
|
||||
if not self.exclude(pattern):
|
||||
log.warn(("warning: no previously-included files "
|
||||
"found matching '%s'"), pattern)
|
||||
|
||||
elif action == 'global-include':
|
||||
self.debug_print("global-include " + ' '.join(patterns))
|
||||
for pattern in patterns:
|
||||
if not self.global_include(pattern):
|
||||
log.warn(("warning: no files found matching '%s' "
|
||||
"anywhere in distribution"), pattern)
|
||||
|
||||
elif action == 'global-exclude':
|
||||
self.debug_print("global-exclude " + ' '.join(patterns))
|
||||
for pattern in patterns:
|
||||
if not self.global_exclude(pattern):
|
||||
log.warn(("warning: no previously-included files matching "
|
||||
"'%s' found anywhere in distribution"),
|
||||
pattern)
|
||||
|
||||
elif action == 'recursive-include':
|
||||
self.debug_print("recursive-include %s %s" %
|
||||
(dir, ' '.join(patterns)))
|
||||
for pattern in patterns:
|
||||
if not self.recursive_include(dir, pattern):
|
||||
log.warn(("warning: no files found matching '%s' "
|
||||
"under directory '%s'"),
|
||||
pattern, dir)
|
||||
|
||||
elif action == 'recursive-exclude':
|
||||
self.debug_print("recursive-exclude %s %s" %
|
||||
(dir, ' '.join(patterns)))
|
||||
for pattern in patterns:
|
||||
if not self.recursive_exclude(dir, pattern):
|
||||
log.warn(("warning: no previously-included files matching "
|
||||
"'%s' found under directory '%s'"),
|
||||
pattern, dir)
|
||||
|
||||
elif action == 'graft':
|
||||
self.debug_print("graft " + dir_pattern)
|
||||
if not self.graft(dir_pattern):
|
||||
log.warn("warning: no directories found matching '%s'",
|
||||
dir_pattern)
|
||||
|
||||
elif action == 'prune':
|
||||
self.debug_print("prune " + dir_pattern)
|
||||
if not self.prune(dir_pattern):
|
||||
log.warn(("no previously-included directories found "
|
||||
"matching '%s'"), dir_pattern)
|
||||
|
||||
else:
|
||||
raise DistutilsInternalError(
|
||||
"this cannot happen: invalid action '%s'" % action)
|
||||
|
||||
def _remove_files(self, predicate):
|
||||
"""
|
||||
Remove all files from the file list that match the predicate.
|
||||
Return True if any matching files were removed
|
||||
"""
|
||||
found = False
|
||||
for i in range(len(self.files) - 1, -1, -1):
|
||||
if predicate(self.files[i]):
|
||||
self.debug_print(" removing " + self.files[i])
|
||||
del self.files[i]
|
||||
found = True
|
||||
return found
|
||||
|
||||
def include(self, pattern):
|
||||
"""Include files that match 'pattern'."""
|
||||
found = [f for f in glob(pattern) if not os.path.isdir(f)]
|
||||
self.extend(found)
|
||||
return bool(found)
|
||||
|
||||
def exclude(self, pattern):
|
||||
"""Exclude files that match 'pattern'."""
|
||||
match = translate_pattern(pattern)
|
||||
return self._remove_files(match.match)
|
||||
|
||||
def recursive_include(self, dir, pattern):
|
||||
"""
|
||||
Include all files anywhere in 'dir/' that match the pattern.
|
||||
"""
|
||||
full_pattern = os.path.join(dir, '**', pattern)
|
||||
found = [f for f in glob(full_pattern, recursive=True)
|
||||
if not os.path.isdir(f)]
|
||||
self.extend(found)
|
||||
return bool(found)
|
||||
|
||||
def recursive_exclude(self, dir, pattern):
|
||||
"""
|
||||
Exclude any file anywhere in 'dir/' that match the pattern.
|
||||
"""
|
||||
match = translate_pattern(os.path.join(dir, '**', pattern))
|
||||
return self._remove_files(match.match)
|
||||
|
||||
def graft(self, dir):
|
||||
"""Include all files from 'dir/'."""
|
||||
found = [
|
||||
item
|
||||
for match_dir in glob(dir)
|
||||
for item in distutils.filelist.findall(match_dir)
|
||||
]
|
||||
self.extend(found)
|
||||
return bool(found)
|
||||
|
||||
def prune(self, dir):
|
||||
"""Filter out files from 'dir/'."""
|
||||
match = translate_pattern(os.path.join(dir, '**'))
|
||||
return self._remove_files(match.match)
|
||||
|
||||
def global_include(self, pattern):
|
||||
"""
|
||||
Include all files anywhere in the current directory that match the
|
||||
pattern. This is very inefficient on large file trees.
|
||||
"""
|
||||
if self.allfiles is None:
|
||||
self.findall()
|
||||
match = translate_pattern(os.path.join('**', pattern))
|
||||
found = [f for f in self.allfiles if match.match(f)]
|
||||
self.extend(found)
|
||||
return bool(found)
|
||||
|
||||
def global_exclude(self, pattern):
|
||||
"""
|
||||
Exclude all files anywhere that match the pattern.
|
||||
"""
|
||||
match = translate_pattern(os.path.join('**', pattern))
|
||||
return self._remove_files(match.match)
|
||||
|
||||
def append(self, item):
|
||||
if item.endswith('\r'): # Fix older sdists built on Windows
|
||||
|
|
@ -289,7 +523,6 @@ class manifest_maker(sdist):
|
|||
self.filelist = FileList()
|
||||
if not os.path.exists(self.manifest):
|
||||
self.write_manifest() # it must exist so it'll get in the list
|
||||
self.filelist.findall()
|
||||
self.add_defaults()
|
||||
if os.path.exists(self.template):
|
||||
self.read_template()
|
||||
|
|
@ -314,10 +547,17 @@ class manifest_maker(sdist):
|
|||
msg = "writing manifest file '%s'" % self.manifest
|
||||
self.execute(write_file, (self.manifest, files), msg)
|
||||
|
||||
def warn(self, msg): # suppress missing-file warnings from sdist
|
||||
if not msg.startswith("standard file not found:"):
|
||||
def warn(self, msg):
|
||||
if not self._should_suppress_warning(msg):
|
||||
sdist.warn(self, msg)
|
||||
|
||||
@staticmethod
|
||||
def _should_suppress_warning(msg):
|
||||
"""
|
||||
suppress missing-file warnings from sdist
|
||||
"""
|
||||
return re.match(r"standard file .*not found", msg)
|
||||
|
||||
def add_defaults(self):
|
||||
sdist.add_defaults(self)
|
||||
self.filelist.append(self.template)
|
||||
|
|
@ -328,38 +568,13 @@ class manifest_maker(sdist):
|
|||
elif os.path.exists(self.manifest):
|
||||
self.read_manifest()
|
||||
ei_cmd = self.get_finalized_command('egg_info')
|
||||
self._add_egg_info(cmd=ei_cmd)
|
||||
self.filelist.include_pattern("*", prefix=ei_cmd.egg_info)
|
||||
|
||||
def _add_egg_info(self, cmd):
|
||||
"""
|
||||
Add paths for egg-info files for an external egg-base.
|
||||
|
||||
The egg-info files are written to egg-base. If egg-base is
|
||||
outside the current working directory, this method
|
||||
searchs the egg-base directory for files to include
|
||||
in the manifest. Uses distutils.filelist.findall (which is
|
||||
really the version monkeypatched in by setuptools/__init__.py)
|
||||
to perform the search.
|
||||
|
||||
Since findall records relative paths, prefix the returned
|
||||
paths with cmd.egg_base, so add_default's include_pattern call
|
||||
(which is looking for the absolute cmd.egg_info) will match
|
||||
them.
|
||||
"""
|
||||
if cmd.egg_base == os.curdir:
|
||||
# egg-info files were already added by something else
|
||||
return
|
||||
|
||||
discovered = distutils.filelist.findall(cmd.egg_base)
|
||||
resolved = (os.path.join(cmd.egg_base, path) for path in discovered)
|
||||
self.filelist.allfiles.extend(resolved)
|
||||
self.filelist.graft(ei_cmd.egg_info)
|
||||
|
||||
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)
|
||||
self.filelist.exclude_pattern(None, prefix=base_dir)
|
||||
self.filelist.prune(build.build_base)
|
||||
self.filelist.prune(base_dir)
|
||||
sep = re.escape(os.sep)
|
||||
self.filelist.exclude_pattern(r'(^|' + sep + r')(RCS|CVS|\.svn)' + sep,
|
||||
is_regex=1)
|
||||
|
|
@ -384,6 +599,10 @@ def write_pkg_info(cmd, basename, filename):
|
|||
metadata = cmd.distribution.metadata
|
||||
metadata.version, oldver = cmd.egg_version, metadata.version
|
||||
metadata.name, oldname = cmd.egg_name, metadata.name
|
||||
metadata.long_description_content_type = getattr(
|
||||
cmd.distribution,
|
||||
'long_description_content_type'
|
||||
)
|
||||
try:
|
||||
# write unescaped data to PKG-INFO, so older pkg_resources
|
||||
# can still parse it
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import distutils.command.install as orig
|
|||
import setuptools
|
||||
|
||||
# Prior to numpy 1.9, NumPy relies on the '_install' name, so provide it for
|
||||
# now. See https://bitbucket.org/pypa/setuptools/issue/199/
|
||||
# now. See https://github.com/pypa/setuptools/issues/199/
|
||||
_install = orig.install
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,13 @@
|
|||
from distutils import log, dir_util
|
||||
import os, sys
|
||||
|
||||
from setuptools.extern.six.moves import map
|
||||
import os
|
||||
|
||||
from setuptools import Command
|
||||
from setuptools import namespaces
|
||||
from setuptools.archive_util import unpack_archive
|
||||
import pkg_resources
|
||||
|
||||
|
||||
class install_egg_info(Command):
|
||||
class install_egg_info(namespaces.Installer, Command):
|
||||
"""Install an .egg-info directory for the package"""
|
||||
|
||||
description = "Install an .egg-info directory for the package"
|
||||
|
|
@ -19,31 +18,14 @@ class install_egg_info(Command):
|
|||
|
||||
def initialize_options(self):
|
||||
self.install_dir = None
|
||||
self.install_layout = None
|
||||
self.prefix_option = None
|
||||
|
||||
def finalize_options(self):
|
||||
self.set_undefined_options('install_lib',
|
||||
('install_dir', 'install_dir'))
|
||||
self.set_undefined_options('install',('install_layout','install_layout'))
|
||||
if sys.hexversion > 0x2060000:
|
||||
self.set_undefined_options('install',('prefix_option','prefix_option'))
|
||||
ei_cmd = self.get_finalized_command("egg_info")
|
||||
basename = pkg_resources.Distribution(
|
||||
None, None, ei_cmd.egg_name, ei_cmd.egg_version
|
||||
).egg_name() + '.egg-info'
|
||||
|
||||
if self.install_layout:
|
||||
if not self.install_layout.lower() in ['deb']:
|
||||
raise DistutilsOptionError("unknown value for --install-layout")
|
||||
self.install_layout = self.install_layout.lower()
|
||||
basename = basename.replace('-py%s' % pkg_resources.PY_MAJOR, '')
|
||||
elif self.prefix_option or 'real_prefix' in sys.__dict__:
|
||||
# don't modify for virtualenv
|
||||
pass
|
||||
else:
|
||||
basename = basename.replace('-py%s' % pkg_resources.PY_MAJOR, '')
|
||||
|
||||
self.source = ei_cmd.egg_info
|
||||
self.target = os.path.join(self.install_dir, basename)
|
||||
self.outputs = []
|
||||
|
|
@ -73,66 +55,8 @@ class install_egg_info(Command):
|
|||
for skip in '.svn/', 'CVS/':
|
||||
if src.startswith(skip) or '/' + skip in src:
|
||||
return None
|
||||
if self.install_layout and self.install_layout in ['deb'] and src.startswith('SOURCES.txt'):
|
||||
log.info("Skipping SOURCES.txt")
|
||||
return None
|
||||
self.outputs.append(dst)
|
||||
log.debug("Copying %s to %s", src, dst)
|
||||
return dst
|
||||
|
||||
unpack_archive(self.source, self.target, skimmer)
|
||||
|
||||
def install_namespaces(self):
|
||||
nsp = self._get_all_ns_packages()
|
||||
if not nsp:
|
||||
return
|
||||
filename, ext = os.path.splitext(self.target)
|
||||
filename += '-nspkg.pth'
|
||||
self.outputs.append(filename)
|
||||
log.info("Installing %s", filename)
|
||||
lines = map(self._gen_nspkg_line, nsp)
|
||||
|
||||
if self.dry_run:
|
||||
# always generate the lines, even in dry run
|
||||
list(lines)
|
||||
return
|
||||
|
||||
with open(filename, 'wt') as f:
|
||||
f.writelines(lines)
|
||||
|
||||
_nspkg_tmpl = (
|
||||
"import sys, types, os",
|
||||
"p = os.path.join(sys._getframe(1).f_locals['sitedir'], *%(pth)r)",
|
||||
"ie = os.path.exists(os.path.join(p,'__init__.py'))",
|
||||
"m = not ie and "
|
||||
"sys.modules.setdefault(%(pkg)r, types.ModuleType(%(pkg)r))",
|
||||
"mp = (m or []) and m.__dict__.setdefault('__path__',[])",
|
||||
"(p not in mp) and mp.append(p)",
|
||||
)
|
||||
"lines for the namespace installer"
|
||||
|
||||
_nspkg_tmpl_multi = (
|
||||
'm and setattr(sys.modules[%(parent)r], %(child)r, m)',
|
||||
)
|
||||
"additional line(s) when a parent package is indicated"
|
||||
|
||||
@classmethod
|
||||
def _gen_nspkg_line(cls, pkg):
|
||||
# ensure pkg is not a unicode string under Python 2.7
|
||||
pkg = str(pkg)
|
||||
pth = tuple(pkg.split('.'))
|
||||
tmpl_lines = cls._nspkg_tmpl
|
||||
parent, sep, child = pkg.rpartition('.')
|
||||
if parent:
|
||||
tmpl_lines += cls._nspkg_tmpl_multi
|
||||
return ';'.join(tmpl_lines) % locals() + '\n'
|
||||
|
||||
def _get_all_ns_packages(self):
|
||||
"""Return sorted list of all package namespaces"""
|
||||
nsp = set()
|
||||
for pkg in self.distribution.namespace_packages or []:
|
||||
pkg = pkg.split('.')
|
||||
while pkg:
|
||||
nsp.add('.'.join(pkg))
|
||||
pkg.pop()
|
||||
return sorted(nsp)
|
||||
|
|
|
|||
|
|
@ -1,24 +1,12 @@
|
|||
import os
|
||||
import sys
|
||||
import imp
|
||||
from itertools import product, starmap
|
||||
import distutils.command.install_lib as orig
|
||||
|
||||
|
||||
class install_lib(orig.install_lib):
|
||||
"""Don't add compiled flags to filenames of non-Python files"""
|
||||
|
||||
def initialize_options(self):
|
||||
orig.install_lib.initialize_options(self)
|
||||
self.multiarch = None
|
||||
self.install_layout = None
|
||||
|
||||
def finalize_options(self):
|
||||
orig.install_lib.finalize_options(self)
|
||||
self.set_undefined_options('install',('install_layout','install_layout'))
|
||||
if self.install_layout == 'deb' and sys.version_info[:2] >= (3, 3):
|
||||
import sysconfig
|
||||
self.multiarch = sysconfig.get_config_var('MULTIARCH')
|
||||
|
||||
def run(self):
|
||||
self.build()
|
||||
outfiles = self.install()
|
||||
|
|
@ -103,8 +91,6 @@ class install_lib(orig.install_lib):
|
|||
exclude = self.get_exclusions()
|
||||
|
||||
if not exclude:
|
||||
import distutils.dir_util
|
||||
distutils.dir_util._multiarch = self.multiarch
|
||||
return orig.install_lib.copy_tree(self, infile, outfile)
|
||||
|
||||
# Exclude namespace package __init__.py* files from the output
|
||||
|
|
@ -114,24 +100,12 @@ class install_lib(orig.install_lib):
|
|||
|
||||
outfiles = []
|
||||
|
||||
if self.multiarch:
|
||||
import sysconfig
|
||||
ext_suffix = sysconfig.get_config_var ('EXT_SUFFIX')
|
||||
if ext_suffix.endswith(self.multiarch + ext_suffix[-3:]):
|
||||
new_suffix = None
|
||||
else:
|
||||
new_suffix = "%s-%s%s" % (ext_suffix[:-3], self.multiarch, ext_suffix[-3:])
|
||||
|
||||
def pf(src, dst):
|
||||
if dst in exclude:
|
||||
log.warn("Skipping installation of %s (namespace package)",
|
||||
dst)
|
||||
return False
|
||||
|
||||
if self.multiarch and new_suffix and dst.endswith(ext_suffix) and not dst.endswith(new_suffix):
|
||||
dst = dst.replace(ext_suffix, new_suffix)
|
||||
log.info("renaming extension to %s", os.path.basename(dst))
|
||||
|
||||
log.info("copying %s -> %s", src, os.path.dirname(dst))
|
||||
outfiles.append(dst)
|
||||
return dst
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
from distutils import log
|
||||
import distutils.command.install_scripts as orig
|
||||
import os
|
||||
import sys
|
||||
|
||||
from pkg_resources import Distribution, PathMetadata, ensure_directory
|
||||
|
||||
|
|
@ -37,6 +38,10 @@ class install_scripts(orig.install_scripts):
|
|||
if is_wininst:
|
||||
exec_param = "python.exe"
|
||||
writer = ei.WindowsScriptWriter
|
||||
if exec_param == sys.executable:
|
||||
# In case the path to the Python executable contains a space, wrap
|
||||
# it so it's not split up.
|
||||
exec_param = [exec_param]
|
||||
# resolve the writer to the environment
|
||||
writer = writer.best()
|
||||
cmd = writer.command_spec_class.best().from_param(exec_param)
|
||||
|
|
|
|||
136
lib/python3.4/site-packages/setuptools/command/py36compat.py
Normal file
136
lib/python3.4/site-packages/setuptools/command/py36compat.py
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
import os
|
||||
from glob import glob
|
||||
from distutils.util import convert_path
|
||||
from distutils.command import sdist
|
||||
|
||||
from setuptools.extern.six.moves import filter
|
||||
|
||||
|
||||
class sdist_add_defaults:
|
||||
"""
|
||||
Mix-in providing forward-compatibility for functionality as found in
|
||||
distutils on Python 3.7.
|
||||
|
||||
Do not edit the code in this class except to update functionality
|
||||
as implemented in distutils. Instead, override in the subclass.
|
||||
"""
|
||||
|
||||
def add_defaults(self):
|
||||
"""Add all the default files to self.filelist:
|
||||
- README or README.txt
|
||||
- setup.py
|
||||
- test/test*.py
|
||||
- all pure Python modules mentioned in setup script
|
||||
- all files pointed by package_data (build_py)
|
||||
- all files defined in data_files.
|
||||
- all files defined as scripts.
|
||||
- all C sources listed as part of extensions or C libraries
|
||||
in the setup script (doesn't catch C headers!)
|
||||
Warns if (README or README.txt) or setup.py are missing; everything
|
||||
else is optional.
|
||||
"""
|
||||
self._add_defaults_standards()
|
||||
self._add_defaults_optional()
|
||||
self._add_defaults_python()
|
||||
self._add_defaults_data_files()
|
||||
self._add_defaults_ext()
|
||||
self._add_defaults_c_libs()
|
||||
self._add_defaults_scripts()
|
||||
|
||||
@staticmethod
|
||||
def _cs_path_exists(fspath):
|
||||
"""
|
||||
Case-sensitive path existence check
|
||||
|
||||
>>> sdist_add_defaults._cs_path_exists(__file__)
|
||||
True
|
||||
>>> sdist_add_defaults._cs_path_exists(__file__.upper())
|
||||
False
|
||||
"""
|
||||
if not os.path.exists(fspath):
|
||||
return False
|
||||
# make absolute so we always have a directory
|
||||
abspath = os.path.abspath(fspath)
|
||||
directory, filename = os.path.split(abspath)
|
||||
return filename in os.listdir(directory)
|
||||
|
||||
def _add_defaults_standards(self):
|
||||
standards = [self.READMES, self.distribution.script_name]
|
||||
for fn in standards:
|
||||
if isinstance(fn, tuple):
|
||||
alts = fn
|
||||
got_it = False
|
||||
for fn in alts:
|
||||
if self._cs_path_exists(fn):
|
||||
got_it = True
|
||||
self.filelist.append(fn)
|
||||
break
|
||||
|
||||
if not got_it:
|
||||
self.warn("standard file not found: should have one of " +
|
||||
', '.join(alts))
|
||||
else:
|
||||
if self._cs_path_exists(fn):
|
||||
self.filelist.append(fn)
|
||||
else:
|
||||
self.warn("standard file '%s' not found" % fn)
|
||||
|
||||
def _add_defaults_optional(self):
|
||||
optional = ['test/test*.py', 'setup.cfg']
|
||||
for pattern in optional:
|
||||
files = filter(os.path.isfile, glob(pattern))
|
||||
self.filelist.extend(files)
|
||||
|
||||
def _add_defaults_python(self):
|
||||
# build_py is used to get:
|
||||
# - python modules
|
||||
# - files defined in package_data
|
||||
build_py = self.get_finalized_command('build_py')
|
||||
|
||||
# getting python files
|
||||
if self.distribution.has_pure_modules():
|
||||
self.filelist.extend(build_py.get_source_files())
|
||||
|
||||
# getting package_data files
|
||||
# (computed in build_py.data_files by build_py.finalize_options)
|
||||
for pkg, src_dir, build_dir, filenames in build_py.data_files:
|
||||
for filename in filenames:
|
||||
self.filelist.append(os.path.join(src_dir, filename))
|
||||
|
||||
def _add_defaults_data_files(self):
|
||||
# getting distribution.data_files
|
||||
if self.distribution.has_data_files():
|
||||
for item in self.distribution.data_files:
|
||||
if isinstance(item, str):
|
||||
# plain file
|
||||
item = convert_path(item)
|
||||
if os.path.isfile(item):
|
||||
self.filelist.append(item)
|
||||
else:
|
||||
# a (dirname, filenames) tuple
|
||||
dirname, filenames = item
|
||||
for f in filenames:
|
||||
f = convert_path(f)
|
||||
if os.path.isfile(f):
|
||||
self.filelist.append(f)
|
||||
|
||||
def _add_defaults_ext(self):
|
||||
if self.distribution.has_ext_modules():
|
||||
build_ext = self.get_finalized_command('build_ext')
|
||||
self.filelist.extend(build_ext.get_source_files())
|
||||
|
||||
def _add_defaults_c_libs(self):
|
||||
if self.distribution.has_c_libraries():
|
||||
build_clib = self.get_finalized_command('build_clib')
|
||||
self.filelist.extend(build_clib.get_source_files())
|
||||
|
||||
def _add_defaults_scripts(self):
|
||||
if self.distribution.has_scripts():
|
||||
build_scripts = self.get_finalized_command('build_scripts')
|
||||
self.filelist.extend(build_scripts.get_source_files())
|
||||
|
||||
|
||||
if hasattr(sdist.sdist, '_add_defaults_standards'):
|
||||
# disable the functionality already available upstream
|
||||
class sdist_add_defaults:
|
||||
pass
|
||||
|
|
@ -2,6 +2,7 @@ from distutils.util import convert_path
|
|||
from distutils import log
|
||||
from distutils.errors import DistutilsOptionError
|
||||
import os
|
||||
import shutil
|
||||
|
||||
from setuptools.extern import six
|
||||
|
||||
|
|
@ -59,4 +60,7 @@ class rotate(Command):
|
|||
for (t, f) in files:
|
||||
log.info("Deleting %s", f)
|
||||
if not self.dry_run:
|
||||
os.unlink(f)
|
||||
if os.path.isdir(f):
|
||||
shutil.rmtree(f)
|
||||
else:
|
||||
os.unlink(f)
|
||||
|
|
|
|||
|
|
@ -1,20 +1,19 @@
|
|||
from glob import glob
|
||||
from distutils import log
|
||||
import distutils.command.sdist as orig
|
||||
import os
|
||||
import sys
|
||||
import io
|
||||
import contextlib
|
||||
|
||||
from setuptools.extern import six
|
||||
|
||||
from setuptools.utils import cs_path_exists
|
||||
from .py36compat import sdist_add_defaults
|
||||
|
||||
import pkg_resources
|
||||
|
||||
READMES = 'README', 'README.rst', 'README.txt'
|
||||
|
||||
_default_revctrl = list
|
||||
|
||||
|
||||
def walk_revctrl(dirname=''):
|
||||
"""Find all files under revision control"""
|
||||
for ep in pkg_resources.iter_entry_points('setuptools.file_finders'):
|
||||
|
|
@ -22,7 +21,7 @@ def walk_revctrl(dirname=''):
|
|||
yield item
|
||||
|
||||
|
||||
class sdist(orig.sdist):
|
||||
class sdist(sdist_add_defaults, orig.sdist):
|
||||
"""Smart sdist that finds anything supported by revision control"""
|
||||
|
||||
user_options = [
|
||||
|
|
@ -38,6 +37,9 @@ class sdist(orig.sdist):
|
|||
|
||||
negative_opt = {}
|
||||
|
||||
README_EXTENSIONS = ['', '.rst', '.txt', '.md']
|
||||
READMES = tuple('README{0}'.format(ext) for ext in README_EXTENSIONS)
|
||||
|
||||
def run(self):
|
||||
self.run_command('egg_info')
|
||||
ei_cmd = self.get_finalized_command('egg_info')
|
||||
|
|
@ -64,6 +66,45 @@ class sdist(orig.sdist):
|
|||
if data not in dist_files:
|
||||
dist_files.append(data)
|
||||
|
||||
def initialize_options(self):
|
||||
orig.sdist.initialize_options(self)
|
||||
|
||||
self._default_to_gztar()
|
||||
|
||||
def _default_to_gztar(self):
|
||||
# only needed on Python prior to 3.6.
|
||||
if sys.version_info >= (3, 6, 0, 'beta', 1):
|
||||
return
|
||||
self.formats = ['gztar']
|
||||
|
||||
def make_distribution(self):
|
||||
"""
|
||||
Workaround for #516
|
||||
"""
|
||||
with self._remove_os_link():
|
||||
orig.sdist.make_distribution(self)
|
||||
|
||||
@staticmethod
|
||||
@contextlib.contextmanager
|
||||
def _remove_os_link():
|
||||
"""
|
||||
In a context, remove and restore os.link if it exists
|
||||
"""
|
||||
|
||||
class NoValue:
|
||||
pass
|
||||
|
||||
orig_val = getattr(os, 'link', NoValue)
|
||||
try:
|
||||
del os.link
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
if orig_val is not NoValue:
|
||||
setattr(os, 'link', orig_val)
|
||||
|
||||
def __read_template_hack(self):
|
||||
# This grody hack closes the template file (MANIFEST.in) if an
|
||||
# exception occurs during read_template.
|
||||
|
|
@ -71,7 +112,7 @@ class sdist(orig.sdist):
|
|||
# file.
|
||||
try:
|
||||
orig.sdist.read_template(self)
|
||||
except:
|
||||
except Exception:
|
||||
_, _, tb = sys.exc_info()
|
||||
tb.tb_next.tb_frame.f_locals['template'].close()
|
||||
raise
|
||||
|
|
@ -87,35 +128,8 @@ class sdist(orig.sdist):
|
|||
if has_leaky_handle:
|
||||
read_template = __read_template_hack
|
||||
|
||||
def add_defaults(self):
|
||||
standards = [READMES,
|
||||
self.distribution.script_name]
|
||||
for fn in standards:
|
||||
if isinstance(fn, tuple):
|
||||
alts = fn
|
||||
got_it = 0
|
||||
for fn in alts:
|
||||
if cs_path_exists(fn):
|
||||
got_it = 1
|
||||
self.filelist.append(fn)
|
||||
break
|
||||
|
||||
if not got_it:
|
||||
self.warn("standard file not found: should have one of " +
|
||||
', '.join(alts))
|
||||
else:
|
||||
if cs_path_exists(fn):
|
||||
self.filelist.append(fn)
|
||||
else:
|
||||
self.warn("standard file '%s' not found" % fn)
|
||||
|
||||
optional = ['test/test*.py', 'setup.cfg']
|
||||
for pattern in optional:
|
||||
files = list(filter(cs_path_exists, glob(pattern)))
|
||||
if files:
|
||||
self.filelist.extend(files)
|
||||
|
||||
# getting python files
|
||||
def _add_defaults_python(self):
|
||||
"""getting python files"""
|
||||
if self.distribution.has_pure_modules():
|
||||
build_py = self.get_finalized_command('build_py')
|
||||
self.filelist.extend(build_py.get_source_files())
|
||||
|
|
@ -128,26 +142,23 @@ class sdist(orig.sdist):
|
|||
self.filelist.extend([os.path.join(src_dir, filename)
|
||||
for filename in filenames])
|
||||
|
||||
if self.distribution.has_ext_modules():
|
||||
build_ext = self.get_finalized_command('build_ext')
|
||||
self.filelist.extend(build_ext.get_source_files())
|
||||
|
||||
if self.distribution.has_c_libraries():
|
||||
build_clib = self.get_finalized_command('build_clib')
|
||||
self.filelist.extend(build_clib.get_source_files())
|
||||
|
||||
if self.distribution.has_scripts():
|
||||
build_scripts = self.get_finalized_command('build_scripts')
|
||||
self.filelist.extend(build_scripts.get_source_files())
|
||||
def _add_defaults_data_files(self):
|
||||
try:
|
||||
if six.PY2:
|
||||
sdist_add_defaults._add_defaults_data_files(self)
|
||||
else:
|
||||
super()._add_defaults_data_files()
|
||||
except TypeError:
|
||||
log.warn("data_files contains unexpected objects")
|
||||
|
||||
def check_readme(self):
|
||||
for f in READMES:
|
||||
for f in self.READMES:
|
||||
if os.path.exists(f):
|
||||
return
|
||||
else:
|
||||
self.warn(
|
||||
"standard file not found: should have one of " +
|
||||
', '.join(READMES)
|
||||
', '.join(self.READMES)
|
||||
)
|
||||
|
||||
def make_release_tree(self, base_dir, files):
|
||||
|
|
@ -179,7 +190,7 @@ class sdist(orig.sdist):
|
|||
distribution.
|
||||
"""
|
||||
log.info("reading manifest file '%s'", self.manifest)
|
||||
manifest = open(self.manifest, 'rbU')
|
||||
manifest = open(self.manifest, 'rb')
|
||||
for line in manifest:
|
||||
# The manifest must contain UTF-8. See #303.
|
||||
if six.PY3:
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ from setuptools.extern.six.moves import configparser
|
|||
|
||||
from setuptools import Command
|
||||
|
||||
|
||||
__all__ = ['config_file', 'edit_config', 'option_base', 'setopt']
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,17 @@
|
|||
from distutils.errors import DistutilsOptionError
|
||||
from unittest import TestLoader
|
||||
import os
|
||||
import operator
|
||||
import sys
|
||||
import contextlib
|
||||
import itertools
|
||||
from distutils.errors import DistutilsError, DistutilsOptionError
|
||||
from distutils import log
|
||||
from unittest import TestLoader
|
||||
|
||||
from setuptools.extern import six
|
||||
from setuptools.extern.six.moves import map
|
||||
from setuptools.extern.six.moves import map, filter
|
||||
|
||||
from pkg_resources import (resource_listdir, resource_exists, normalize_path,
|
||||
working_set, _namespace_packages,
|
||||
working_set, _namespace_packages, evaluate_marker,
|
||||
add_activation_listener, require, EntryPoint)
|
||||
from setuptools import Command
|
||||
from setuptools.py31compat import unittest_main
|
||||
|
|
@ -62,7 +67,7 @@ class test(Command):
|
|||
user_options = [
|
||||
('test-module=', 'm', "Run 'test_suite' in specified module"),
|
||||
('test-suite=', 's',
|
||||
"Test suite to run (e.g. 'some_module.test_suite')"),
|
||||
"Run single test, case or suite (e.g. 'module.test_suite')"),
|
||||
('test-runner=', 'r', "Test runner to use"),
|
||||
]
|
||||
|
||||
|
|
@ -102,6 +107,14 @@ class test(Command):
|
|||
yield self.test_suite
|
||||
|
||||
def with_project_on_sys_path(self, func):
|
||||
"""
|
||||
Backward compatibility for project_on_sys_path context.
|
||||
"""
|
||||
with self.project_on_sys_path():
|
||||
func()
|
||||
|
||||
@contextlib.contextmanager
|
||||
def project_on_sys_path(self, include_dists=[]):
|
||||
with_2to3 = six.PY3 and getattr(self.distribution, 'use_2to3', False)
|
||||
|
||||
if with_2to3:
|
||||
|
|
@ -133,30 +146,73 @@ class test(Command):
|
|||
old_modules = sys.modules.copy()
|
||||
|
||||
try:
|
||||
sys.path.insert(0, normalize_path(ei_cmd.egg_base))
|
||||
project_path = normalize_path(ei_cmd.egg_base)
|
||||
sys.path.insert(0, project_path)
|
||||
working_set.__init__()
|
||||
add_activation_listener(lambda dist: dist.activate())
|
||||
require('%s==%s' % (ei_cmd.egg_name, ei_cmd.egg_version))
|
||||
func()
|
||||
with self.paths_on_pythonpath([project_path]):
|
||||
yield
|
||||
finally:
|
||||
sys.path[:] = old_path
|
||||
sys.modules.clear()
|
||||
sys.modules.update(old_modules)
|
||||
working_set.__init__()
|
||||
|
||||
@staticmethod
|
||||
@contextlib.contextmanager
|
||||
def paths_on_pythonpath(paths):
|
||||
"""
|
||||
Add the indicated paths to the head of the PYTHONPATH environment
|
||||
variable so that subprocesses will also see the packages at
|
||||
these paths.
|
||||
|
||||
Do this in a context that restores the value on exit.
|
||||
"""
|
||||
nothing = object()
|
||||
orig_pythonpath = os.environ.get('PYTHONPATH', nothing)
|
||||
current_pythonpath = os.environ.get('PYTHONPATH', '')
|
||||
try:
|
||||
prefix = os.pathsep.join(paths)
|
||||
to_join = filter(None, [prefix, current_pythonpath])
|
||||
new_path = os.pathsep.join(to_join)
|
||||
if new_path:
|
||||
os.environ['PYTHONPATH'] = new_path
|
||||
yield
|
||||
finally:
|
||||
if orig_pythonpath is nothing:
|
||||
os.environ.pop('PYTHONPATH', None)
|
||||
else:
|
||||
os.environ['PYTHONPATH'] = orig_pythonpath
|
||||
|
||||
@staticmethod
|
||||
def install_dists(dist):
|
||||
"""
|
||||
Install the requirements indicated by self.distribution and
|
||||
return an iterable of the dists that were built.
|
||||
"""
|
||||
ir_d = dist.fetch_build_eggs(dist.install_requires)
|
||||
tr_d = dist.fetch_build_eggs(dist.tests_require or [])
|
||||
er_d = dist.fetch_build_eggs(
|
||||
v for k, v in dist.extras_require.items()
|
||||
if k.startswith(':') and evaluate_marker(k[1:])
|
||||
)
|
||||
return itertools.chain(ir_d, tr_d, er_d)
|
||||
|
||||
def run(self):
|
||||
if self.distribution.install_requires:
|
||||
self.distribution.fetch_build_eggs(
|
||||
self.distribution.install_requires)
|
||||
if self.distribution.tests_require:
|
||||
self.distribution.fetch_build_eggs(self.distribution.tests_require)
|
||||
installed_dists = self.install_dists(self.distribution)
|
||||
|
||||
cmd = ' '.join(self._argv)
|
||||
if self.dry_run:
|
||||
self.announce('skipping "%s" (dry run)' % cmd)
|
||||
else:
|
||||
self.announce('running "%s"' % cmd)
|
||||
self.with_project_on_sys_path(self.run_tests)
|
||||
return
|
||||
|
||||
self.announce('running "%s"' % cmd)
|
||||
|
||||
paths = map(operator.attrgetter('location'), installed_dists)
|
||||
with self.paths_on_pythonpath(paths):
|
||||
with self.project_on_sys_path():
|
||||
self.run_tests()
|
||||
|
||||
def run_tests(self):
|
||||
# Purge modules under test from sys.modules. The test loader will
|
||||
|
|
@ -174,11 +230,17 @@ class test(Command):
|
|||
del_modules.append(name)
|
||||
list(map(sys.modules.__delitem__, del_modules))
|
||||
|
||||
unittest_main(
|
||||
exit_kwarg = {} if sys.version_info < (2, 7) else {"exit": False}
|
||||
test = unittest_main(
|
||||
None, None, self._argv,
|
||||
testLoader=self._resolve_as_ep(self.test_loader),
|
||||
testRunner=self._resolve_as_ep(self.test_runner),
|
||||
**exit_kwarg
|
||||
)
|
||||
if not test.result.wasSuccessful():
|
||||
msg = 'Test failed: %s' % test.result
|
||||
self.announce(msg, log.ERROR)
|
||||
raise DistutilsError(msg)
|
||||
|
||||
@property
|
||||
def _argv(self):
|
||||
|
|
|
|||
|
|
@ -1,15 +1,26 @@
|
|||
import getpass
|
||||
from distutils.command import upload as orig
|
||||
|
||||
|
||||
class upload(orig.upload):
|
||||
"""
|
||||
Override default upload behavior to look up password
|
||||
in the keyring if available.
|
||||
Override default upload behavior to obtain password
|
||||
in a variety of different ways.
|
||||
"""
|
||||
|
||||
def finalize_options(self):
|
||||
orig.upload.finalize_options(self)
|
||||
self.password or self._load_password_from_keyring()
|
||||
self.username = (
|
||||
self.username or
|
||||
getpass.getuser()
|
||||
)
|
||||
# Attempt to obtain password. Short circuit evaluation at the first
|
||||
# sign of success.
|
||||
self.password = (
|
||||
self.password or
|
||||
self._load_password_from_keyring() or
|
||||
self._prompt_for_password()
|
||||
)
|
||||
|
||||
def _load_password_from_keyring(self):
|
||||
"""
|
||||
|
|
@ -17,7 +28,15 @@ class upload(orig.upload):
|
|||
"""
|
||||
try:
|
||||
keyring = __import__('keyring')
|
||||
self.password = keyring.get_password(self.repository,
|
||||
self.username)
|
||||
return keyring.get_password(self.repository, self.username)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _prompt_for_password(self):
|
||||
"""
|
||||
Prompt for a password on the tty. Suppress Exceptions.
|
||||
"""
|
||||
try:
|
||||
return getpass.getpass()
|
||||
except (Exception, KeyboardInterrupt):
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ import socket
|
|||
import zipfile
|
||||
import tempfile
|
||||
import shutil
|
||||
import itertools
|
||||
import functools
|
||||
|
||||
from setuptools.extern import six
|
||||
from setuptools.extern.six.moves import http_client, urllib
|
||||
|
|
@ -21,18 +23,16 @@ from pkg_resources import iter_entry_points
|
|||
from .upload import upload
|
||||
|
||||
|
||||
errors = 'surrogateescape' if six.PY3 else '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, six.text_type):
|
||||
return s.encode(encoding, errors)
|
||||
return s
|
||||
def _encode(s):
|
||||
errors = 'surrogateescape' if six.PY3 else 'strict'
|
||||
return s.encode('utf-8', errors)
|
||||
|
||||
|
||||
class upload_docs(upload):
|
||||
# override the default repository as upload_docs isn't
|
||||
# supported by Warehouse (and won't be).
|
||||
DEFAULT_REPOSITORY = 'https://pypi.python.org/pypi/'
|
||||
|
||||
description = 'Upload documentation to PyPI'
|
||||
|
||||
user_options = [
|
||||
|
|
@ -68,6 +68,8 @@ class upload_docs(upload):
|
|||
else:
|
||||
self.ensure_dirname('upload_dir')
|
||||
self.target_dir = self.upload_dir
|
||||
if 'pypi.python.org' in self.repository:
|
||||
log.warn("Upload_docs command is deprecated. Use RTD instead.")
|
||||
self.announce('Using upload directory %s' % self.target_dir)
|
||||
|
||||
def create_zipfile(self, filename):
|
||||
|
|
@ -76,9 +78,8 @@ class upload_docs(upload):
|
|||
self.mkpath(self.target_dir) # just in case
|
||||
for root, dirs, files in os.walk(self.target_dir):
|
||||
if root == self.target_dir and not files:
|
||||
raise DistutilsOptionError(
|
||||
"no files found in upload directory '%s'"
|
||||
% self.target_dir)
|
||||
tmpl = "no files found in upload directory '%s'"
|
||||
raise DistutilsOptionError(tmpl % self.target_dir)
|
||||
for name in files:
|
||||
full = os.path.join(root, name)
|
||||
relative = root[len(self.target_dir):].lstrip(os.path.sep)
|
||||
|
|
@ -101,10 +102,48 @@ class upload_docs(upload):
|
|||
finally:
|
||||
shutil.rmtree(tmp_dir)
|
||||
|
||||
@staticmethod
|
||||
def _build_part(item, sep_boundary):
|
||||
key, values = item
|
||||
title = '\nContent-Disposition: form-data; name="%s"' % key
|
||||
# handle multiple entries for the same name
|
||||
if not isinstance(values, list):
|
||||
values = [values]
|
||||
for value in values:
|
||||
if isinstance(value, tuple):
|
||||
title += '; filename="%s"' % value[0]
|
||||
value = value[1]
|
||||
else:
|
||||
value = _encode(value)
|
||||
yield sep_boundary
|
||||
yield _encode(title)
|
||||
yield b"\n\n"
|
||||
yield value
|
||||
if value and value[-1:] == b'\r':
|
||||
yield b'\n' # write an extra newline (lurve Macs)
|
||||
|
||||
@classmethod
|
||||
def _build_multipart(cls, data):
|
||||
"""
|
||||
Build up the MIME payload for the POST data
|
||||
"""
|
||||
boundary = b'--------------GHSKFJDLGDS7543FJKLFHRE75642756743254'
|
||||
sep_boundary = b'\n--' + boundary
|
||||
end_boundary = sep_boundary + b'--'
|
||||
end_items = end_boundary, b"\n",
|
||||
builder = functools.partial(
|
||||
cls._build_part,
|
||||
sep_boundary=sep_boundary,
|
||||
)
|
||||
part_groups = map(builder, data.items())
|
||||
parts = itertools.chain.from_iterable(part_groups)
|
||||
body_items = itertools.chain(parts, end_items)
|
||||
content_type = 'multipart/form-data; boundary=%s' % boundary.decode('ascii')
|
||||
return b''.join(body_items), content_type
|
||||
|
||||
def upload_file(self, filename):
|
||||
f = open(filename, 'rb')
|
||||
content = f.read()
|
||||
f.close()
|
||||
with open(filename, 'rb') as f:
|
||||
content = f.read()
|
||||
meta = self.distribution.metadata
|
||||
data = {
|
||||
':action': 'doc_upload',
|
||||
|
|
@ -112,40 +151,16 @@ class upload_docs(upload):
|
|||
'content': (os.path.basename(filename), content),
|
||||
}
|
||||
# set up the authentication
|
||||
credentials = b(self.username + ':' + self.password)
|
||||
credentials = _encode(self.username + ':' + self.password)
|
||||
credentials = standard_b64encode(credentials)
|
||||
if six.PY3:
|
||||
credentials = credentials.decode('ascii')
|
||||
auth = "Basic " + credentials
|
||||
|
||||
# Build up the MIME payload for the POST data
|
||||
boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254'
|
||||
sep_boundary = b('\n--') + b(boundary)
|
||||
end_boundary = sep_boundary + b('--')
|
||||
body = []
|
||||
for key, values in six.iteritems(data):
|
||||
title = '\nContent-Disposition: form-data; name="%s"' % key
|
||||
# handle multiple entries for the same name
|
||||
if not isinstance(values, list):
|
||||
values = [values]
|
||||
for value in values:
|
||||
if type(value) is tuple:
|
||||
title += '; filename="%s"' % value[0]
|
||||
value = value[1]
|
||||
else:
|
||||
value = b(value)
|
||||
body.append(sep_boundary)
|
||||
body.append(b(title))
|
||||
body.append(b("\n\n"))
|
||||
body.append(value)
|
||||
if value and value[-1:] == b('\r'):
|
||||
body.append(b('\n')) # write an extra newline (lurve Macs)
|
||||
body.append(end_boundary)
|
||||
body.append(b("\n"))
|
||||
body = b('').join(body)
|
||||
body, ct = self._build_multipart(data)
|
||||
|
||||
self.announce("Submitting documentation to %s" % (self.repository),
|
||||
log.INFO)
|
||||
msg = "Submitting documentation to %s" % (self.repository)
|
||||
self.announce(msg, log.INFO)
|
||||
|
||||
# build the Request
|
||||
# We can't use urllib2 since we need to send the Basic
|
||||
|
|
@ -164,7 +179,7 @@ class upload_docs(upload):
|
|||
try:
|
||||
conn.connect()
|
||||
conn.putrequest("POST", url)
|
||||
content_type = 'multipart/form-data; boundary=%s' % boundary
|
||||
content_type = ct
|
||||
conn.putheader('Content-type', content_type)
|
||||
conn.putheader('Content-length', str(len(body)))
|
||||
conn.putheader('Authorization', auth)
|
||||
|
|
@ -176,16 +191,16 @@ class upload_docs(upload):
|
|||
|
||||
r = conn.getresponse()
|
||||
if r.status == 200:
|
||||
self.announce('Server response (%s): %s' % (r.status, r.reason),
|
||||
log.INFO)
|
||||
msg = 'Server response (%s): %s' % (r.status, r.reason)
|
||||
self.announce(msg, log.INFO)
|
||||
elif r.status == 301:
|
||||
location = r.getheader('Location')
|
||||
if location is None:
|
||||
location = 'https://pythonhosted.org/%s/' % meta.get_name()
|
||||
self.announce('Upload successful. Visit %s' % location,
|
||||
log.INFO)
|
||||
msg = 'Upload successful. Visit %s' % location
|
||||
self.announce(msg, log.INFO)
|
||||
else:
|
||||
self.announce('Upload failed (%s): %s' % (r.status, r.reason),
|
||||
log.ERROR)
|
||||
msg = 'Upload failed (%s): %s' % (r.status, r.reason)
|
||||
self.announce(msg, log.ERROR)
|
||||
if self.show_response:
|
||||
print('-' * 75, r.read(), '-' * 75)
|
||||
|
|
|
|||
554
lib/python3.4/site-packages/setuptools/config.py
Normal file
554
lib/python3.4/site-packages/setuptools/config.py
Normal file
|
|
@ -0,0 +1,554 @@
|
|||
from __future__ import absolute_import, unicode_literals
|
||||
import io
|
||||
import os
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from functools import partial
|
||||
|
||||
from distutils.errors import DistutilsOptionError, DistutilsFileError
|
||||
from setuptools.py26compat import import_module
|
||||
from setuptools.extern.six import string_types
|
||||
|
||||
|
||||
def read_configuration(
|
||||
filepath, find_others=False, ignore_option_errors=False):
|
||||
"""Read given configuration file and returns options from it as a dict.
|
||||
|
||||
:param str|unicode filepath: Path to configuration file
|
||||
to get options from.
|
||||
|
||||
:param bool find_others: Whether to search for other configuration files
|
||||
which could be on in various places.
|
||||
|
||||
:param bool ignore_option_errors: Whether to silently ignore
|
||||
options, values of which could not be resolved (e.g. due to exceptions
|
||||
in directives such as file:, attr:, etc.).
|
||||
If False exceptions are propagated as expected.
|
||||
|
||||
:rtype: dict
|
||||
"""
|
||||
from setuptools.dist import Distribution, _Distribution
|
||||
|
||||
filepath = os.path.abspath(filepath)
|
||||
|
||||
if not os.path.isfile(filepath):
|
||||
raise DistutilsFileError(
|
||||
'Configuration file %s does not exist.' % filepath)
|
||||
|
||||
current_directory = os.getcwd()
|
||||
os.chdir(os.path.dirname(filepath))
|
||||
|
||||
try:
|
||||
dist = Distribution()
|
||||
|
||||
filenames = dist.find_config_files() if find_others else []
|
||||
if filepath not in filenames:
|
||||
filenames.append(filepath)
|
||||
|
||||
_Distribution.parse_config_files(dist, filenames=filenames)
|
||||
|
||||
handlers = parse_configuration(
|
||||
dist, dist.command_options,
|
||||
ignore_option_errors=ignore_option_errors)
|
||||
|
||||
finally:
|
||||
os.chdir(current_directory)
|
||||
|
||||
return configuration_to_dict(handlers)
|
||||
|
||||
|
||||
def configuration_to_dict(handlers):
|
||||
"""Returns configuration data gathered by given handlers as a dict.
|
||||
|
||||
:param list[ConfigHandler] handlers: Handlers list,
|
||||
usually from parse_configuration()
|
||||
|
||||
:rtype: dict
|
||||
"""
|
||||
config_dict = defaultdict(dict)
|
||||
|
||||
for handler in handlers:
|
||||
|
||||
obj_alias = handler.section_prefix
|
||||
target_obj = handler.target_obj
|
||||
|
||||
for option in handler.set_options:
|
||||
getter = getattr(target_obj, 'get_%s' % option, None)
|
||||
|
||||
if getter is None:
|
||||
value = getattr(target_obj, option)
|
||||
|
||||
else:
|
||||
value = getter()
|
||||
|
||||
config_dict[obj_alias][option] = value
|
||||
|
||||
return config_dict
|
||||
|
||||
|
||||
def parse_configuration(
|
||||
distribution, command_options, ignore_option_errors=False):
|
||||
"""Performs additional parsing of configuration options
|
||||
for a distribution.
|
||||
|
||||
Returns a list of used option handlers.
|
||||
|
||||
:param Distribution distribution:
|
||||
:param dict command_options:
|
||||
:param bool ignore_option_errors: Whether to silently ignore
|
||||
options, values of which could not be resolved (e.g. due to exceptions
|
||||
in directives such as file:, attr:, etc.).
|
||||
If False exceptions are propagated as expected.
|
||||
:rtype: list
|
||||
"""
|
||||
meta = ConfigMetadataHandler(
|
||||
distribution.metadata, command_options, ignore_option_errors)
|
||||
meta.parse()
|
||||
|
||||
options = ConfigOptionsHandler(
|
||||
distribution, command_options, ignore_option_errors)
|
||||
options.parse()
|
||||
|
||||
return [meta, options]
|
||||
|
||||
|
||||
class ConfigHandler(object):
|
||||
"""Handles metadata supplied in configuration files."""
|
||||
|
||||
section_prefix = None
|
||||
"""Prefix for config sections handled by this handler.
|
||||
Must be provided by class heirs.
|
||||
|
||||
"""
|
||||
|
||||
aliases = {}
|
||||
"""Options aliases.
|
||||
For compatibility with various packages. E.g.: d2to1 and pbr.
|
||||
Note: `-` in keys is replaced with `_` by config parser.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, target_obj, options, ignore_option_errors=False):
|
||||
sections = {}
|
||||
|
||||
section_prefix = self.section_prefix
|
||||
for section_name, section_options in options.items():
|
||||
if not section_name.startswith(section_prefix):
|
||||
continue
|
||||
|
||||
section_name = section_name.replace(section_prefix, '').strip('.')
|
||||
sections[section_name] = section_options
|
||||
|
||||
self.ignore_option_errors = ignore_option_errors
|
||||
self.target_obj = target_obj
|
||||
self.sections = sections
|
||||
self.set_options = []
|
||||
|
||||
@property
|
||||
def parsers(self):
|
||||
"""Metadata item name to parser function mapping."""
|
||||
raise NotImplementedError(
|
||||
'%s must provide .parsers property' % self.__class__.__name__)
|
||||
|
||||
def __setitem__(self, option_name, value):
|
||||
unknown = tuple()
|
||||
target_obj = self.target_obj
|
||||
|
||||
# Translate alias into real name.
|
||||
option_name = self.aliases.get(option_name, option_name)
|
||||
|
||||
current_value = getattr(target_obj, option_name, unknown)
|
||||
|
||||
if current_value is unknown:
|
||||
raise KeyError(option_name)
|
||||
|
||||
if current_value:
|
||||
# Already inhabited. Skipping.
|
||||
return
|
||||
|
||||
skip_option = False
|
||||
parser = self.parsers.get(option_name)
|
||||
if parser:
|
||||
try:
|
||||
value = parser(value)
|
||||
|
||||
except Exception:
|
||||
skip_option = True
|
||||
if not self.ignore_option_errors:
|
||||
raise
|
||||
|
||||
if skip_option:
|
||||
return
|
||||
|
||||
setter = getattr(target_obj, 'set_%s' % option_name, None)
|
||||
if setter is None:
|
||||
setattr(target_obj, option_name, value)
|
||||
else:
|
||||
setter(value)
|
||||
|
||||
self.set_options.append(option_name)
|
||||
|
||||
@classmethod
|
||||
def _parse_list(cls, value, separator=','):
|
||||
"""Represents value as a list.
|
||||
|
||||
Value is split either by separator (defaults to comma) or by lines.
|
||||
|
||||
:param value:
|
||||
:param separator: List items separator character.
|
||||
:rtype: list
|
||||
"""
|
||||
if isinstance(value, list): # _get_parser_compound case
|
||||
return value
|
||||
|
||||
if '\n' in value:
|
||||
value = value.splitlines()
|
||||
else:
|
||||
value = value.split(separator)
|
||||
|
||||
return [chunk.strip() for chunk in value if chunk.strip()]
|
||||
|
||||
@classmethod
|
||||
def _parse_dict(cls, value):
|
||||
"""Represents value as a dict.
|
||||
|
||||
:param value:
|
||||
:rtype: dict
|
||||
"""
|
||||
separator = '='
|
||||
result = {}
|
||||
for line in cls._parse_list(value):
|
||||
key, sep, val = line.partition(separator)
|
||||
if sep != separator:
|
||||
raise DistutilsOptionError(
|
||||
'Unable to parse option value to dict: %s' % value)
|
||||
result[key.strip()] = val.strip()
|
||||
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
def _parse_bool(cls, value):
|
||||
"""Represents value as boolean.
|
||||
|
||||
:param value:
|
||||
:rtype: bool
|
||||
"""
|
||||
value = value.lower()
|
||||
return value in ('1', 'true', 'yes')
|
||||
|
||||
@classmethod
|
||||
def _parse_file(cls, value):
|
||||
"""Represents value as a string, allowing including text
|
||||
from nearest files using `file:` directive.
|
||||
|
||||
Directive is sandboxed and won't reach anything outside
|
||||
directory with setup.py.
|
||||
|
||||
Examples:
|
||||
file: LICENSE
|
||||
file: README.rst, CHANGELOG.md, src/file.txt
|
||||
|
||||
:param str value:
|
||||
:rtype: str
|
||||
"""
|
||||
include_directive = 'file:'
|
||||
|
||||
if not isinstance(value, string_types):
|
||||
return value
|
||||
|
||||
if not value.startswith(include_directive):
|
||||
return value
|
||||
|
||||
spec = value[len(include_directive):]
|
||||
filepaths = (os.path.abspath(path.strip()) for path in spec.split(','))
|
||||
return '\n'.join(
|
||||
cls._read_file(path)
|
||||
for path in filepaths
|
||||
if (cls._assert_local(path) or True)
|
||||
and os.path.isfile(path)
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _assert_local(filepath):
|
||||
if not filepath.startswith(os.getcwd()):
|
||||
raise DistutilsOptionError(
|
||||
'`file:` directive can not access %s' % filepath)
|
||||
|
||||
@staticmethod
|
||||
def _read_file(filepath):
|
||||
with io.open(filepath, encoding='utf-8') as f:
|
||||
return f.read()
|
||||
|
||||
@classmethod
|
||||
def _parse_attr(cls, value):
|
||||
"""Represents value as a module attribute.
|
||||
|
||||
Examples:
|
||||
attr: package.attr
|
||||
attr: package.module.attr
|
||||
|
||||
:param str value:
|
||||
:rtype: str
|
||||
"""
|
||||
attr_directive = 'attr:'
|
||||
if not value.startswith(attr_directive):
|
||||
return value
|
||||
|
||||
attrs_path = value.replace(attr_directive, '').strip().split('.')
|
||||
attr_name = attrs_path.pop()
|
||||
|
||||
module_name = '.'.join(attrs_path)
|
||||
module_name = module_name or '__init__'
|
||||
|
||||
sys.path.insert(0, os.getcwd())
|
||||
try:
|
||||
module = import_module(module_name)
|
||||
value = getattr(module, attr_name)
|
||||
|
||||
finally:
|
||||
sys.path = sys.path[1:]
|
||||
|
||||
return value
|
||||
|
||||
@classmethod
|
||||
def _get_parser_compound(cls, *parse_methods):
|
||||
"""Returns parser function to represents value as a list.
|
||||
|
||||
Parses a value applying given methods one after another.
|
||||
|
||||
:param parse_methods:
|
||||
:rtype: callable
|
||||
"""
|
||||
def parse(value):
|
||||
parsed = value
|
||||
|
||||
for method in parse_methods:
|
||||
parsed = method(parsed)
|
||||
|
||||
return parsed
|
||||
|
||||
return parse
|
||||
|
||||
@classmethod
|
||||
def _parse_section_to_dict(cls, section_options, values_parser=None):
|
||||
"""Parses section options into a dictionary.
|
||||
|
||||
Optionally applies a given parser to values.
|
||||
|
||||
:param dict section_options:
|
||||
:param callable values_parser:
|
||||
:rtype: dict
|
||||
"""
|
||||
value = {}
|
||||
values_parser = values_parser or (lambda val: val)
|
||||
for key, (_, val) in section_options.items():
|
||||
value[key] = values_parser(val)
|
||||
return value
|
||||
|
||||
def parse_section(self, section_options):
|
||||
"""Parses configuration file section.
|
||||
|
||||
:param dict section_options:
|
||||
"""
|
||||
for (name, (_, value)) in section_options.items():
|
||||
try:
|
||||
self[name] = value
|
||||
|
||||
except KeyError:
|
||||
pass # Keep silent for a new option may appear anytime.
|
||||
|
||||
def parse(self):
|
||||
"""Parses configuration file items from one
|
||||
or more related sections.
|
||||
|
||||
"""
|
||||
for section_name, section_options in self.sections.items():
|
||||
|
||||
method_postfix = ''
|
||||
if section_name: # [section.option] variant
|
||||
method_postfix = '_%s' % section_name
|
||||
|
||||
section_parser_method = getattr(
|
||||
self,
|
||||
# Dots in section names are tranlsated into dunderscores.
|
||||
('parse_section%s' % method_postfix).replace('.', '__'),
|
||||
None)
|
||||
|
||||
if section_parser_method is None:
|
||||
raise DistutilsOptionError(
|
||||
'Unsupported distribution option section: [%s.%s]' % (
|
||||
self.section_prefix, section_name))
|
||||
|
||||
section_parser_method(section_options)
|
||||
|
||||
|
||||
class ConfigMetadataHandler(ConfigHandler):
|
||||
|
||||
section_prefix = 'metadata'
|
||||
|
||||
aliases = {
|
||||
'home_page': 'url',
|
||||
'summary': 'description',
|
||||
'classifier': 'classifiers',
|
||||
'platform': 'platforms',
|
||||
}
|
||||
|
||||
strict_mode = False
|
||||
"""We need to keep it loose, to be partially compatible with
|
||||
`pbr` and `d2to1` packages which also uses `metadata` section.
|
||||
|
||||
"""
|
||||
|
||||
@property
|
||||
def parsers(self):
|
||||
"""Metadata item name to parser function mapping."""
|
||||
parse_list = self._parse_list
|
||||
parse_file = self._parse_file
|
||||
|
||||
return {
|
||||
'platforms': parse_list,
|
||||
'keywords': parse_list,
|
||||
'provides': parse_list,
|
||||
'requires': parse_list,
|
||||
'obsoletes': parse_list,
|
||||
'classifiers': self._get_parser_compound(parse_file, parse_list),
|
||||
'license': parse_file,
|
||||
'description': parse_file,
|
||||
'long_description': parse_file,
|
||||
'version': self._parse_version,
|
||||
}
|
||||
|
||||
def _parse_version(self, value):
|
||||
"""Parses `version` option value.
|
||||
|
||||
:param value:
|
||||
:rtype: str
|
||||
|
||||
"""
|
||||
version = self._parse_attr(value)
|
||||
|
||||
if callable(version):
|
||||
version = version()
|
||||
|
||||
if not isinstance(version, string_types):
|
||||
if hasattr(version, '__iter__'):
|
||||
version = '.'.join(map(str, version))
|
||||
else:
|
||||
version = '%s' % version
|
||||
|
||||
return version
|
||||
|
||||
|
||||
class ConfigOptionsHandler(ConfigHandler):
|
||||
|
||||
section_prefix = 'options'
|
||||
|
||||
@property
|
||||
def parsers(self):
|
||||
"""Metadata item name to parser function mapping."""
|
||||
parse_list = self._parse_list
|
||||
parse_list_semicolon = partial(self._parse_list, separator=';')
|
||||
parse_bool = self._parse_bool
|
||||
parse_dict = self._parse_dict
|
||||
|
||||
return {
|
||||
'zip_safe': parse_bool,
|
||||
'use_2to3': parse_bool,
|
||||
'include_package_data': parse_bool,
|
||||
'package_dir': parse_dict,
|
||||
'use_2to3_fixers': parse_list,
|
||||
'use_2to3_exclude_fixers': parse_list,
|
||||
'convert_2to3_doctests': parse_list,
|
||||
'scripts': parse_list,
|
||||
'eager_resources': parse_list,
|
||||
'dependency_links': parse_list,
|
||||
'namespace_packages': parse_list,
|
||||
'install_requires': parse_list_semicolon,
|
||||
'setup_requires': parse_list_semicolon,
|
||||
'tests_require': parse_list_semicolon,
|
||||
'packages': self._parse_packages,
|
||||
'entry_points': self._parse_file,
|
||||
'py_modules': parse_list,
|
||||
}
|
||||
|
||||
def _parse_packages(self, value):
|
||||
"""Parses `packages` option value.
|
||||
|
||||
:param value:
|
||||
:rtype: list
|
||||
"""
|
||||
find_directive = 'find:'
|
||||
|
||||
if not value.startswith(find_directive):
|
||||
return self._parse_list(value)
|
||||
|
||||
# Read function arguments from a dedicated section.
|
||||
find_kwargs = self.parse_section_packages__find(
|
||||
self.sections.get('packages.find', {}))
|
||||
|
||||
from setuptools import find_packages
|
||||
|
||||
return find_packages(**find_kwargs)
|
||||
|
||||
def parse_section_packages__find(self, section_options):
|
||||
"""Parses `packages.find` configuration file section.
|
||||
|
||||
To be used in conjunction with _parse_packages().
|
||||
|
||||
:param dict section_options:
|
||||
"""
|
||||
section_data = self._parse_section_to_dict(
|
||||
section_options, self._parse_list)
|
||||
|
||||
valid_keys = ['where', 'include', 'exclude']
|
||||
|
||||
find_kwargs = dict(
|
||||
[(k, v) for k, v in section_data.items() if k in valid_keys and v])
|
||||
|
||||
where = find_kwargs.get('where')
|
||||
if where is not None:
|
||||
find_kwargs['where'] = where[0] # cast list to single val
|
||||
|
||||
return find_kwargs
|
||||
|
||||
def parse_section_entry_points(self, section_options):
|
||||
"""Parses `entry_points` configuration file section.
|
||||
|
||||
:param dict section_options:
|
||||
"""
|
||||
parsed = self._parse_section_to_dict(section_options, self._parse_list)
|
||||
self['entry_points'] = parsed
|
||||
|
||||
def _parse_package_data(self, section_options):
|
||||
parsed = self._parse_section_to_dict(section_options, self._parse_list)
|
||||
|
||||
root = parsed.get('*')
|
||||
if root:
|
||||
parsed[''] = root
|
||||
del parsed['*']
|
||||
|
||||
return parsed
|
||||
|
||||
def parse_section_package_data(self, section_options):
|
||||
"""Parses `package_data` configuration file section.
|
||||
|
||||
:param dict section_options:
|
||||
"""
|
||||
self['package_data'] = self._parse_package_data(section_options)
|
||||
|
||||
def parse_section_exclude_package_data(self, section_options):
|
||||
"""Parses `exclude_package_data` configuration file section.
|
||||
|
||||
:param dict section_options:
|
||||
"""
|
||||
self['exclude_package_data'] = self._parse_package_data(
|
||||
section_options)
|
||||
|
||||
def parse_section_extras_require(self, section_options):
|
||||
"""Parses `extras_require` configuration file section.
|
||||
|
||||
:param dict section_options:
|
||||
"""
|
||||
parse_list = partial(self._parse_list, separator=';')
|
||||
self['extras_require'] = self._parse_section_to_dict(
|
||||
section_options, parse_list)
|
||||
23
lib/python3.4/site-packages/setuptools/dep_util.py
Normal file
23
lib/python3.4/site-packages/setuptools/dep_util.py
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
from distutils.dep_util import newer_group
|
||||
|
||||
# yes, this is was almost entirely copy-pasted from
|
||||
# 'newer_pairwise()', this is just another convenience
|
||||
# function.
|
||||
def newer_pairwise_group(sources_groups, targets):
|
||||
"""Walk both arguments in parallel, testing if each source group is newer
|
||||
than its corresponding target. Returns a pair of lists (sources_groups,
|
||||
targets) where sources is newer than target, according to the semantics
|
||||
of 'newer_group()'.
|
||||
"""
|
||||
if len(sources_groups) != len(targets):
|
||||
raise ValueError("'sources_group' and 'targets' must be the same length")
|
||||
|
||||
# build a pair of lists (sources_groups, targets) where source is newer
|
||||
n_sources = []
|
||||
n_targets = []
|
||||
for i in range(len(sources_groups)):
|
||||
if newer_group(sources_groups[i], targets[i]):
|
||||
n_sources.append(sources_groups[i])
|
||||
n_targets.append(targets[i])
|
||||
|
||||
return n_sources, n_targets
|
||||
|
|
@ -1,15 +1,17 @@
|
|||
import sys
|
||||
import imp
|
||||
import marshal
|
||||
from imp import PKG_DIRECTORY, PY_COMPILED, PY_SOURCE, PY_FROZEN
|
||||
from distutils.version import StrictVersion
|
||||
from imp import PKG_DIRECTORY, PY_COMPILED, PY_SOURCE, PY_FROZEN
|
||||
|
||||
from .py33compat import Bytecode
|
||||
|
||||
from setuptools.extern import six
|
||||
|
||||
__all__ = [
|
||||
'Require', 'find_module', 'get_module_constant', 'extract_constant'
|
||||
]
|
||||
|
||||
|
||||
class Require:
|
||||
"""A prerequisite to building or installing a distribution"""
|
||||
|
||||
|
|
@ -30,7 +32,7 @@ class Require:
|
|||
def full_name(self):
|
||||
"""Return full package/distribution name, w/version"""
|
||||
if self.requested_version is not None:
|
||||
return '%s-%s' % (self.name,self.requested_version)
|
||||
return '%s-%s' % (self.name, self.requested_version)
|
||||
return self.name
|
||||
|
||||
def version_ok(self, version):
|
||||
|
|
@ -39,7 +41,6 @@ class Require:
|
|||
str(version) != "unknown" and version >= self.requested_version
|
||||
|
||||
def get_version(self, paths=None, default="unknown"):
|
||||
|
||||
"""Get version number of installed module, 'None', or 'default'
|
||||
|
||||
Search 'paths' for module. If not found, return 'None'. If found,
|
||||
|
|
@ -52,8 +53,9 @@ class Require:
|
|||
|
||||
if self.attribute is None:
|
||||
try:
|
||||
f,p,i = find_module(self.module,paths)
|
||||
if f: f.close()
|
||||
f, p, i = find_module(self.module, paths)
|
||||
if f:
|
||||
f.close()
|
||||
return default
|
||||
except ImportError:
|
||||
return None
|
||||
|
|
@ -77,40 +79,6 @@ class Require:
|
|||
return self.version_ok(version)
|
||||
|
||||
|
||||
def _iter_code(code):
|
||||
|
||||
"""Yield '(op,arg)' pair for each operation in code object 'code'"""
|
||||
|
||||
from array import array
|
||||
from dis import HAVE_ARGUMENT, EXTENDED_ARG
|
||||
|
||||
bytes = array('b',code.co_code)
|
||||
eof = len(code.co_code)
|
||||
|
||||
ptr = 0
|
||||
extended_arg = 0
|
||||
|
||||
while ptr<eof:
|
||||
|
||||
op = bytes[ptr]
|
||||
|
||||
if op>=HAVE_ARGUMENT:
|
||||
|
||||
arg = bytes[ptr+1] + bytes[ptr+2]*256 + extended_arg
|
||||
ptr += 3
|
||||
|
||||
if op==EXTENDED_ARG:
|
||||
long_type = six.integer_types[-1]
|
||||
extended_arg = arg * long_type(65536)
|
||||
continue
|
||||
|
||||
else:
|
||||
arg = None
|
||||
ptr += 1
|
||||
|
||||
yield op,arg
|
||||
|
||||
|
||||
def find_module(module, paths=None):
|
||||
"""Just like 'imp.find_module()', but with package support"""
|
||||
|
||||
|
|
@ -118,20 +86,19 @@ def find_module(module, paths=None):
|
|||
|
||||
while parts:
|
||||
part = parts.pop(0)
|
||||
f, path, (suffix,mode,kind) = info = imp.find_module(part, paths)
|
||||
f, path, (suffix, mode, kind) = info = imp.find_module(part, paths)
|
||||
|
||||
if kind==PKG_DIRECTORY:
|
||||
if kind == PKG_DIRECTORY:
|
||||
parts = parts or ['__init__']
|
||||
paths = [path]
|
||||
|
||||
elif parts:
|
||||
raise ImportError("Can't find %r in %s" % (parts,module))
|
||||
raise ImportError("Can't find %r in %s" % (parts, module))
|
||||
|
||||
return info
|
||||
|
||||
|
||||
def get_module_constant(module, symbol, default=-1, paths=None):
|
||||
|
||||
"""Find 'module' by searching 'paths', and extract 'symbol'
|
||||
|
||||
Return 'None' if 'module' does not exist on 'paths', or it does not define
|
||||
|
|
@ -145,12 +112,12 @@ def get_module_constant(module, symbol, default=-1, paths=None):
|
|||
return None
|
||||
|
||||
try:
|
||||
if kind==PY_COMPILED:
|
||||
f.read(8) # skip magic & date
|
||||
if kind == PY_COMPILED:
|
||||
f.read(8) # skip magic & date
|
||||
code = marshal.load(f)
|
||||
elif kind==PY_FROZEN:
|
||||
elif kind == PY_FROZEN:
|
||||
code = imp.get_frozen_object(module)
|
||||
elif kind==PY_SOURCE:
|
||||
elif kind == PY_SOURCE:
|
||||
code = compile(f.read(), path, 'exec')
|
||||
else:
|
||||
# Not something we can parse; we'll have to import it. :(
|
||||
|
|
@ -177,9 +144,8 @@ def extract_constant(code, symbol, default=-1):
|
|||
only 'STORE_NAME' and 'STORE_GLOBAL' opcodes are checked, and 'symbol'
|
||||
must be present in 'code.co_names'.
|
||||
"""
|
||||
|
||||
if symbol not in code.co_names:
|
||||
# name's not there, can't possibly be an assigment
|
||||
# name's not there, can't possibly be an assignment
|
||||
return None
|
||||
|
||||
name_idx = list(code.co_names).index(symbol)
|
||||
|
|
@ -190,11 +156,13 @@ def extract_constant(code, symbol, default=-1):
|
|||
|
||||
const = default
|
||||
|
||||
for op, arg in _iter_code(code):
|
||||
for byte_code in Bytecode(code):
|
||||
op = byte_code.opcode
|
||||
arg = byte_code.arg
|
||||
|
||||
if op==LOAD_CONST:
|
||||
if op == LOAD_CONST:
|
||||
const = code.co_consts[arg]
|
||||
elif arg==name_idx and (op==STORE_NAME or op==STORE_GLOBAL):
|
||||
elif arg == name_idx and (op == STORE_NAME or op == STORE_GLOBAL):
|
||||
return const
|
||||
else:
|
||||
const = default
|
||||
|
|
@ -214,4 +182,5 @@ def _update_globals():
|
|||
del globals()[name]
|
||||
__all__.remove(name)
|
||||
|
||||
|
||||
_update_globals()
|
||||
|
|
|
|||
|
|
@ -2,117 +2,159 @@ __all__ = ['Distribution']
|
|||
|
||||
import re
|
||||
import os
|
||||
import sys
|
||||
import warnings
|
||||
import numbers
|
||||
import distutils.log
|
||||
import distutils.core
|
||||
import distutils.cmd
|
||||
import distutils.dist
|
||||
from distutils.core import Distribution as _Distribution
|
||||
from distutils.errors import (DistutilsOptionError, DistutilsPlatformError,
|
||||
DistutilsSetupError)
|
||||
import itertools
|
||||
from collections import defaultdict
|
||||
from distutils.errors import (
|
||||
DistutilsOptionError, DistutilsPlatformError, DistutilsSetupError,
|
||||
)
|
||||
from distutils.util import rfc822_escape
|
||||
|
||||
from setuptools.extern import six
|
||||
from setuptools.extern.six.moves import map
|
||||
from setuptools.extern.six.moves import map, filter, filterfalse
|
||||
from pkg_resources.extern import packaging
|
||||
|
||||
from setuptools.depends import Require
|
||||
from setuptools import windows_support
|
||||
from setuptools.monkey import get_unpatched
|
||||
from setuptools.config import parse_configuration
|
||||
import pkg_resources
|
||||
from .py36compat import Distribution_parse_config_files
|
||||
|
||||
__import__('pkg_resources.extern.packaging.specifiers')
|
||||
__import__('pkg_resources.extern.packaging.version')
|
||||
|
||||
|
||||
def _get_unpatched(cls):
|
||||
"""Protect against re-patching the distutils if reloaded
|
||||
warnings.warn("Do not call this function", DeprecationWarning)
|
||||
return get_unpatched(cls)
|
||||
|
||||
Also ensures that no other distutils extension monkeypatched the distutils
|
||||
first.
|
||||
|
||||
# Based on Python 3.5 version
|
||||
def write_pkg_file(self, file):
|
||||
"""Write the PKG-INFO format data to a file object.
|
||||
"""
|
||||
while cls.__module__.startswith('setuptools'):
|
||||
cls, = cls.__bases__
|
||||
if not cls.__module__.startswith('distutils'):
|
||||
raise AssertionError(
|
||||
"distutils has already been patched by %r" % cls
|
||||
)
|
||||
return cls
|
||||
version = '1.0'
|
||||
if (self.provides or self.requires or self.obsoletes or
|
||||
self.classifiers or self.download_url):
|
||||
version = '1.1'
|
||||
# Setuptools specific for PEP 345
|
||||
if hasattr(self, 'python_requires'):
|
||||
version = '1.2'
|
||||
|
||||
_Distribution = _get_unpatched(_Distribution)
|
||||
file.write('Metadata-Version: %s\n' % version)
|
||||
file.write('Name: %s\n' % self.get_name())
|
||||
file.write('Version: %s\n' % self.get_version())
|
||||
file.write('Summary: %s\n' % self.get_description())
|
||||
file.write('Home-page: %s\n' % self.get_url())
|
||||
file.write('Author: %s\n' % self.get_contact())
|
||||
file.write('Author-email: %s\n' % self.get_contact_email())
|
||||
file.write('License: %s\n' % self.get_license())
|
||||
if self.download_url:
|
||||
file.write('Download-URL: %s\n' % self.download_url)
|
||||
|
||||
def _patch_distribution_metadata_write_pkg_info():
|
||||
long_desc_content_type = getattr(
|
||||
self,
|
||||
'long_description_content_type',
|
||||
None
|
||||
) or 'UNKNOWN'
|
||||
file.write('Description-Content-Type: %s\n' % long_desc_content_type)
|
||||
|
||||
long_desc = rfc822_escape(self.get_long_description())
|
||||
file.write('Description: %s\n' % long_desc)
|
||||
|
||||
keywords = ','.join(self.get_keywords())
|
||||
if keywords:
|
||||
file.write('Keywords: %s\n' % keywords)
|
||||
|
||||
self._write_list(file, 'Platform', self.get_platforms())
|
||||
self._write_list(file, 'Classifier', self.get_classifiers())
|
||||
|
||||
# PEP 314
|
||||
self._write_list(file, 'Requires', self.get_requires())
|
||||
self._write_list(file, 'Provides', self.get_provides())
|
||||
self._write_list(file, 'Obsoletes', self.get_obsoletes())
|
||||
|
||||
# Setuptools specific for PEP 345
|
||||
if hasattr(self, 'python_requires'):
|
||||
file.write('Requires-Python: %s\n' % self.python_requires)
|
||||
|
||||
|
||||
# from Python 3.4
|
||||
def write_pkg_info(self, base_dir):
|
||||
"""Write the PKG-INFO file into the release tree.
|
||||
"""
|
||||
Workaround issue #197 - Python 3 prior to 3.2.2 uses an environment-local
|
||||
encoding to save the pkg_info. Monkey-patch its write_pkg_info method to
|
||||
correct this undesirable behavior.
|
||||
"""
|
||||
environment_local = (3,) <= sys.version_info[:3] < (3, 2, 2)
|
||||
if not environment_local:
|
||||
return
|
||||
with open(os.path.join(base_dir, 'PKG-INFO'), 'w',
|
||||
encoding='UTF-8') as pkg_info:
|
||||
self.write_pkg_file(pkg_info)
|
||||
|
||||
# from Python 3.4
|
||||
def write_pkg_info(self, base_dir):
|
||||
"""Write the PKG-INFO file into the release tree.
|
||||
"""
|
||||
with open(os.path.join(base_dir, 'PKG-INFO'), 'w',
|
||||
encoding='UTF-8') as pkg_info:
|
||||
self.write_pkg_file(pkg_info)
|
||||
|
||||
distutils.dist.DistributionMetadata.write_pkg_info = write_pkg_info
|
||||
_patch_distribution_metadata_write_pkg_info()
|
||||
|
||||
sequence = tuple, list
|
||||
|
||||
|
||||
def check_importable(dist, attr, value):
|
||||
try:
|
||||
ep = pkg_resources.EntryPoint.parse('x='+value)
|
||||
ep = pkg_resources.EntryPoint.parse('x=' + value)
|
||||
assert not ep.extras
|
||||
except (TypeError,ValueError,AttributeError,AssertionError):
|
||||
except (TypeError, ValueError, AttributeError, AssertionError):
|
||||
raise DistutilsSetupError(
|
||||
"%r must be importable 'module:attrs' string (got %r)"
|
||||
% (attr,value)
|
||||
% (attr, value)
|
||||
)
|
||||
|
||||
|
||||
def assert_string_list(dist, attr, value):
|
||||
"""Verify that value is a string list or None"""
|
||||
try:
|
||||
assert ''.join(value)!=value
|
||||
except (TypeError,ValueError,AttributeError,AssertionError):
|
||||
assert ''.join(value) != value
|
||||
except (TypeError, ValueError, AttributeError, AssertionError):
|
||||
raise DistutilsSetupError(
|
||||
"%r must be a list of strings (got %r)" % (attr,value)
|
||||
"%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)
|
||||
for nsp in value:
|
||||
ns_packages = value
|
||||
assert_string_list(dist, attr, ns_packages)
|
||||
for nsp in ns_packages:
|
||||
if not dist.has_contents_for(nsp):
|
||||
raise DistutilsSetupError(
|
||||
"Distribution contains no modules or packages for " +
|
||||
"namespace package %r" % nsp
|
||||
)
|
||||
if '.' in nsp:
|
||||
parent = '.'.join(nsp.split('.')[:-1])
|
||||
if parent not in value:
|
||||
distutils.log.warn(
|
||||
"WARNING: %r is declared as a package namespace, but %r"
|
||||
" is not: please correct this in setup.py", nsp, parent
|
||||
)
|
||||
parent, sep, child = nsp.rpartition('.')
|
||||
if parent and parent not in ns_packages:
|
||||
distutils.log.warn(
|
||||
"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):
|
||||
list(itertools.starmap(_check_extra, value.items()))
|
||||
except (TypeError, ValueError, AttributeError):
|
||||
raise DistutilsSetupError(
|
||||
"'extras_require' must be a dictionary whose values are "
|
||||
"strings or lists of strings containing valid project/version "
|
||||
"requirement specifiers."
|
||||
)
|
||||
|
||||
|
||||
def _check_extra(extra, reqs):
|
||||
name, sep, marker = extra.partition(':')
|
||||
if marker and pkg_resources.invalid_marker(marker):
|
||||
raise DistutilsSetupError("Invalid environment marker: " + marker)
|
||||
list(pkg_resources.parse_requirements(reqs))
|
||||
|
||||
|
||||
def assert_bool(dist, attr, value):
|
||||
"""Verify that value is True, False, 0, or 1"""
|
||||
if bool(value) != value:
|
||||
|
|
@ -131,6 +173,19 @@ def check_requirements(dist, attr, value):
|
|||
)
|
||||
raise DistutilsSetupError(tmpl.format(attr=attr, error=error))
|
||||
|
||||
|
||||
def check_specifier(dist, attr, value):
|
||||
"""Verify that value is a valid version specifier"""
|
||||
try:
|
||||
packaging.specifiers.SpecifierSet(value)
|
||||
except packaging.specifiers.InvalidSpecifier as error:
|
||||
tmpl = (
|
||||
"{attr!r} must be a string "
|
||||
"containing valid version specifiers; {error}"
|
||||
)
|
||||
raise DistutilsSetupError(tmpl.format(attr=attr, error=error))
|
||||
|
||||
|
||||
def check_entry_points(dist, attr, value):
|
||||
"""Verify that entry_points map is parseable"""
|
||||
try:
|
||||
|
|
@ -138,25 +193,30 @@ def check_entry_points(dist, attr, value):
|
|||
except ValueError as e:
|
||||
raise DistutilsSetupError(e)
|
||||
|
||||
|
||||
def check_test_suite(dist, attr, value):
|
||||
if not isinstance(value, six.string_types):
|
||||
raise DistutilsSetupError("test_suite must be a string")
|
||||
|
||||
|
||||
def check_package_data(dist, attr, value):
|
||||
"""Verify that value is a dictionary of package names to glob lists"""
|
||||
if isinstance(value,dict):
|
||||
for k,v in value.items():
|
||||
if not isinstance(k,str): break
|
||||
try: iter(v)
|
||||
if isinstance(value, dict):
|
||||
for k, v in value.items():
|
||||
if not isinstance(k, str):
|
||||
break
|
||||
try:
|
||||
iter(v)
|
||||
except TypeError:
|
||||
break
|
||||
else:
|
||||
return
|
||||
raise DistutilsSetupError(
|
||||
attr+" must be a dictionary mapping package names to lists of "
|
||||
attr + " must be a dictionary mapping package names to lists of "
|
||||
"wildcard patterns"
|
||||
)
|
||||
|
||||
|
||||
def check_packages(dist, attr, value):
|
||||
for pkgname in value:
|
||||
if not re.match(r'\w+(\.\w+)*', pkgname):
|
||||
|
|
@ -166,7 +226,10 @@ def check_packages(dist, attr, value):
|
|||
)
|
||||
|
||||
|
||||
class Distribution(_Distribution):
|
||||
_Distribution = get_unpatched(distutils.core.Distribution)
|
||||
|
||||
|
||||
class Distribution(Distribution_parse_config_files, _Distribution):
|
||||
"""Distribution with support for features, tests, and package data
|
||||
|
||||
This is an enhanced version of 'distutils.dist.Distribution' that
|
||||
|
|
@ -261,15 +324,18 @@ class Distribution(_Distribution):
|
|||
self.dist_files = []
|
||||
self.src_root = attrs and attrs.pop("src_root", None)
|
||||
self.patch_missing_pkg_info(attrs)
|
||||
self.long_description_content_type = _attrs_dict.get(
|
||||
'long_description_content_type'
|
||||
)
|
||||
# Make sure we have any eggs needed to interpret 'attrs'
|
||||
if attrs is not None:
|
||||
self.dependency_links = attrs.pop('dependency_links', [])
|
||||
assert_string_list(self,'dependency_links',self.dependency_links)
|
||||
assert_string_list(self, 'dependency_links', self.dependency_links)
|
||||
if attrs and 'setup_requires' in attrs:
|
||||
self.fetch_build_eggs(attrs['setup_requires'])
|
||||
for ep in pkg_resources.iter_entry_points('distutils.setup_keywords'):
|
||||
vars(self).setdefault(ep.name, None)
|
||||
_Distribution.__init__(self,attrs)
|
||||
_Distribution.__init__(self, attrs)
|
||||
if isinstance(self.metadata.version, numbers.Number):
|
||||
# Some people apparently take "version number" too literally :)
|
||||
self.metadata.version = str(self.metadata.version)
|
||||
|
|
@ -293,6 +359,83 @@ class Distribution(_Distribution):
|
|||
"setuptools, pip, and PyPI. Please see PEP 440 for more "
|
||||
"details." % self.metadata.version
|
||||
)
|
||||
self._finalize_requires()
|
||||
|
||||
def _finalize_requires(self):
|
||||
"""
|
||||
Set `metadata.python_requires` and fix environment markers
|
||||
in `install_requires` and `extras_require`.
|
||||
"""
|
||||
if getattr(self, 'python_requires', None):
|
||||
self.metadata.python_requires = self.python_requires
|
||||
self._convert_extras_requirements()
|
||||
self._move_install_requirements_markers()
|
||||
|
||||
def _convert_extras_requirements(self):
|
||||
"""
|
||||
Convert requirements in `extras_require` of the form
|
||||
`"extra": ["barbazquux; {marker}"]` to
|
||||
`"extra:{marker}": ["barbazquux"]`.
|
||||
"""
|
||||
spec_ext_reqs = getattr(self, 'extras_require', None) or {}
|
||||
self._tmp_extras_require = defaultdict(list)
|
||||
for section, v in spec_ext_reqs.items():
|
||||
# Do not strip empty sections.
|
||||
self._tmp_extras_require[section]
|
||||
for r in pkg_resources.parse_requirements(v):
|
||||
suffix = self._suffix_for(r)
|
||||
self._tmp_extras_require[section + suffix].append(r)
|
||||
|
||||
@staticmethod
|
||||
def _suffix_for(req):
|
||||
"""
|
||||
For a requirement, return the 'extras_require' suffix for
|
||||
that requirement.
|
||||
"""
|
||||
return ':' + str(req.marker) if req.marker else ''
|
||||
|
||||
def _move_install_requirements_markers(self):
|
||||
"""
|
||||
Move requirements in `install_requires` that are using environment
|
||||
markers `extras_require`.
|
||||
"""
|
||||
|
||||
# divide the install_requires into two sets, simple ones still
|
||||
# handled by install_requires and more complex ones handled
|
||||
# by extras_require.
|
||||
|
||||
def is_simple_req(req):
|
||||
return not req.marker
|
||||
|
||||
spec_inst_reqs = getattr(self, 'install_requires', None) or ()
|
||||
inst_reqs = list(pkg_resources.parse_requirements(spec_inst_reqs))
|
||||
simple_reqs = filter(is_simple_req, inst_reqs)
|
||||
complex_reqs = filterfalse(is_simple_req, inst_reqs)
|
||||
self.install_requires = list(map(str, simple_reqs))
|
||||
|
||||
for r in complex_reqs:
|
||||
self._tmp_extras_require[':' + str(r.marker)].append(r)
|
||||
self.extras_require = dict(
|
||||
(k, [str(r) for r in map(self._clean_req, v)])
|
||||
for k, v in self._tmp_extras_require.items()
|
||||
)
|
||||
|
||||
def _clean_req(self, req):
|
||||
"""
|
||||
Given a Requirement, remove environment markers and return it.
|
||||
"""
|
||||
req.marker = None
|
||||
return req
|
||||
|
||||
def parse_config_files(self, filenames=None):
|
||||
"""Parses configuration files from various levels
|
||||
and loads configuration.
|
||||
|
||||
"""
|
||||
_Distribution.parse_config_files(self, filenames=filenames)
|
||||
|
||||
parse_configuration(self, self.command_options)
|
||||
self._finalize_requires()
|
||||
|
||||
def parse_command_line(self):
|
||||
"""Process features after parsing command line options"""
|
||||
|
|
@ -301,9 +444,9 @@ class Distribution(_Distribution):
|
|||
self._finalize_features()
|
||||
return result
|
||||
|
||||
def _feature_attrname(self,name):
|
||||
def _feature_attrname(self, name):
|
||||
"""Convert feature name to corresponding option attribute name"""
|
||||
return 'with_'+name.replace('-','_')
|
||||
return 'with_' + name.replace('-', '_')
|
||||
|
||||
def fetch_build_eggs(self, requires):
|
||||
"""Resolve pre-setup requirements"""
|
||||
|
|
@ -314,6 +457,7 @@ class Distribution(_Distribution):
|
|||
)
|
||||
for dist in resolved_dists:
|
||||
pkg_resources.working_set.add(dist, replace=True)
|
||||
return resolved_dists
|
||||
|
||||
def finalize_options(self):
|
||||
_Distribution.finalize_options(self)
|
||||
|
|
@ -321,13 +465,16 @@ class Distribution(_Distribution):
|
|||
self._set_global_opts_from_features()
|
||||
|
||||
for ep in pkg_resources.iter_entry_points('distutils.setup_keywords'):
|
||||
value = getattr(self,ep.name,None)
|
||||
value = getattr(self, ep.name, None)
|
||||
if value is not None:
|
||||
ep.require(installer=self.fetch_build_egg)
|
||||
ep.load()(self, ep.name, value)
|
||||
if getattr(self, 'convert_2to3_doctests', None):
|
||||
# XXX may convert to set here when we can rely on set being builtin
|
||||
self.convert_2to3_doctests = [os.path.abspath(p) for p in self.convert_2to3_doctests]
|
||||
self.convert_2to3_doctests = [
|
||||
os.path.abspath(p)
|
||||
for p in self.convert_2to3_doctests
|
||||
]
|
||||
else:
|
||||
self.convert_2to3_doctests = []
|
||||
|
||||
|
|
@ -348,35 +495,30 @@ class Distribution(_Distribution):
|
|||
|
||||
def fetch_build_egg(self, req):
|
||||
"""Fetch an egg needed for building"""
|
||||
|
||||
try:
|
||||
cmd = self._egg_fetcher
|
||||
cmd.package_index.to_scan = []
|
||||
except AttributeError:
|
||||
from setuptools.command.easy_install import easy_install
|
||||
dist = self.__class__({'script_args':['easy_install']})
|
||||
dist.parse_config_files()
|
||||
opts = dist.get_option_dict('easy_install')
|
||||
keep = (
|
||||
'find_links', 'site_dirs', 'index_url', 'optimize',
|
||||
'site_dirs', 'allow_hosts'
|
||||
)
|
||||
for key in list(opts):
|
||||
if key not in keep:
|
||||
del opts[key] # don't use any other settings
|
||||
if self.dependency_links:
|
||||
links = self.dependency_links[:]
|
||||
if 'find_links' in opts:
|
||||
links = opts['find_links'][1].split() + links
|
||||
opts['find_links'] = ('setup', links)
|
||||
install_dir = self.get_egg_cache_dir()
|
||||
cmd = easy_install(
|
||||
dist, args=["x"], install_dir=install_dir, exclude_scripts=True,
|
||||
always_copy=False, build_directory=None, editable=False,
|
||||
upgrade=False, multi_version=True, no_report=True, user=False
|
||||
)
|
||||
cmd.ensure_finalized()
|
||||
self._egg_fetcher = cmd
|
||||
from setuptools.command.easy_install import easy_install
|
||||
dist = self.__class__({'script_args': ['easy_install']})
|
||||
dist.parse_config_files()
|
||||
opts = dist.get_option_dict('easy_install')
|
||||
keep = (
|
||||
'find_links', 'site_dirs', 'index_url', 'optimize',
|
||||
'site_dirs', 'allow_hosts'
|
||||
)
|
||||
for key in list(opts):
|
||||
if key not in keep:
|
||||
del opts[key] # don't use any other settings
|
||||
if self.dependency_links:
|
||||
links = self.dependency_links[:]
|
||||
if 'find_links' in opts:
|
||||
links = opts['find_links'][1].split() + links
|
||||
opts['find_links'] = ('setup', links)
|
||||
install_dir = self.get_egg_cache_dir()
|
||||
cmd = easy_install(
|
||||
dist, args=["x"], install_dir=install_dir,
|
||||
exclude_scripts=True,
|
||||
always_copy=False, build_directory=None, editable=False,
|
||||
upgrade=False, multi_version=True, no_report=True, user=False
|
||||
)
|
||||
cmd.ensure_finalized()
|
||||
return cmd.easy_install(req)
|
||||
|
||||
def _set_global_opts_from_features(self):
|
||||
|
|
@ -385,20 +527,23 @@ class Distribution(_Distribution):
|
|||
go = []
|
||||
no = self.negative_opt.copy()
|
||||
|
||||
for name,feature in self.features.items():
|
||||
self._set_feature(name,None)
|
||||
for name, feature in self.features.items():
|
||||
self._set_feature(name, None)
|
||||
feature.validate(self)
|
||||
|
||||
if feature.optional:
|
||||
descr = feature.description
|
||||
incdef = ' (default)'
|
||||
excdef=''
|
||||
excdef = ''
|
||||
if not feature.include_by_default():
|
||||
excdef, incdef = incdef, excdef
|
||||
|
||||
go.append(('with-'+name, None, 'include '+descr+incdef))
|
||||
go.append(('without-'+name, None, 'exclude '+descr+excdef))
|
||||
no['without-'+name] = 'with-'+name
|
||||
new = (
|
||||
('with-' + name, None, 'include ' + descr + incdef),
|
||||
('without-' + name, None, 'exclude ' + descr + excdef),
|
||||
)
|
||||
go.extend(new)
|
||||
no['without-' + name] = 'with-' + name
|
||||
|
||||
self.global_options = self.feature_options = go + self.global_options
|
||||
self.negative_opt = self.feature_negopt = no
|
||||
|
|
@ -407,25 +552,26 @@ class Distribution(_Distribution):
|
|||
"""Add/remove features and resolve dependencies between them"""
|
||||
|
||||
# First, flag all the enabled items (and thus their dependencies)
|
||||
for name,feature in self.features.items():
|
||||
for name, feature in self.features.items():
|
||||
enabled = self.feature_is_included(name)
|
||||
if enabled or (enabled is None and feature.include_by_default()):
|
||||
feature.include_in(self)
|
||||
self._set_feature(name,1)
|
||||
self._set_feature(name, 1)
|
||||
|
||||
# Then disable the rest, so that off-by-default features don't
|
||||
# get flagged as errors when they're required by an enabled feature
|
||||
for name,feature in self.features.items():
|
||||
for name, feature in self.features.items():
|
||||
if not self.feature_is_included(name):
|
||||
feature.exclude_from(self)
|
||||
self._set_feature(name,0)
|
||||
self._set_feature(name, 0)
|
||||
|
||||
def get_command_class(self, command):
|
||||
"""Pluggable version of get_command_class()"""
|
||||
if command in self.cmdclass:
|
||||
return self.cmdclass[command]
|
||||
|
||||
for ep in pkg_resources.iter_entry_points('distutils.commands',command):
|
||||
eps = pkg_resources.iter_entry_points('distutils.commands', command)
|
||||
for ep in eps:
|
||||
ep.require(installer=self.fetch_build_egg)
|
||||
self.cmdclass[command] = cmdclass = ep.load()
|
||||
return cmdclass
|
||||
|
|
@ -448,26 +594,26 @@ class Distribution(_Distribution):
|
|||
self.cmdclass[ep.name] = cmdclass
|
||||
return _Distribution.get_command_list(self)
|
||||
|
||||
def _set_feature(self,name,status):
|
||||
def _set_feature(self, name, status):
|
||||
"""Set feature's inclusion status"""
|
||||
setattr(self,self._feature_attrname(name),status)
|
||||
setattr(self, self._feature_attrname(name), status)
|
||||
|
||||
def feature_is_included(self,name):
|
||||
def feature_is_included(self, name):
|
||||
"""Return 1 if feature is included, 0 if excluded, 'None' if unknown"""
|
||||
return getattr(self,self._feature_attrname(name))
|
||||
return getattr(self, self._feature_attrname(name))
|
||||
|
||||
def include_feature(self,name):
|
||||
def include_feature(self, name):
|
||||
"""Request inclusion of feature named 'name'"""
|
||||
|
||||
if self.feature_is_included(name)==0:
|
||||
if self.feature_is_included(name) == 0:
|
||||
descr = self.features[name].description
|
||||
raise DistutilsOptionError(
|
||||
descr + " is required, but was excluded or is not available"
|
||||
)
|
||||
self.features[name].include_in(self)
|
||||
self._set_feature(name,1)
|
||||
self._set_feature(name, 1)
|
||||
|
||||
def include(self,**attrs):
|
||||
def include(self, **attrs):
|
||||
"""Add items to distribution that are named in keyword arguments
|
||||
|
||||
For example, 'dist.exclude(py_modules=["x"])' would add 'x' to
|
||||
|
|
@ -482,86 +628,87 @@ class Distribution(_Distribution):
|
|||
will try to call 'dist._include_foo({"bar":"baz"})', which can then
|
||||
handle whatever special inclusion logic is needed.
|
||||
"""
|
||||
for k,v in attrs.items():
|
||||
include = getattr(self, '_include_'+k, None)
|
||||
for k, v in attrs.items():
|
||||
include = getattr(self, '_include_' + k, None)
|
||||
if include:
|
||||
include(v)
|
||||
else:
|
||||
self._include_misc(k,v)
|
||||
self._include_misc(k, v)
|
||||
|
||||
def exclude_package(self,package):
|
||||
def exclude_package(self, package):
|
||||
"""Remove packages, modules, and extensions in named package"""
|
||||
|
||||
pfx = package+'.'
|
||||
pfx = package + '.'
|
||||
if self.packages:
|
||||
self.packages = [
|
||||
p for p in self.packages
|
||||
if p != package and not p.startswith(pfx)
|
||||
if p != package and not p.startswith(pfx)
|
||||
]
|
||||
|
||||
if self.py_modules:
|
||||
self.py_modules = [
|
||||
p for p in self.py_modules
|
||||
if p != package and not p.startswith(pfx)
|
||||
if p != package and not p.startswith(pfx)
|
||||
]
|
||||
|
||||
if self.ext_modules:
|
||||
self.ext_modules = [
|
||||
p for p in self.ext_modules
|
||||
if p.name != package and not p.name.startswith(pfx)
|
||||
if p.name != package and not p.name.startswith(pfx)
|
||||
]
|
||||
|
||||
def has_contents_for(self,package):
|
||||
def has_contents_for(self, package):
|
||||
"""Return true if 'exclude_package(package)' would do something"""
|
||||
|
||||
pfx = package+'.'
|
||||
pfx = package + '.'
|
||||
|
||||
for p in self.iter_distribution_names():
|
||||
if p==package or p.startswith(pfx):
|
||||
if p == package or p.startswith(pfx):
|
||||
return True
|
||||
|
||||
def _exclude_misc(self,name,value):
|
||||
def _exclude_misc(self, name, value):
|
||||
"""Handle 'exclude()' for list/tuple attrs without a special handler"""
|
||||
if not isinstance(value,sequence):
|
||||
if not isinstance(value, sequence):
|
||||
raise DistutilsSetupError(
|
||||
"%s: setting must be a list or tuple (%r)" % (name, value)
|
||||
)
|
||||
try:
|
||||
old = getattr(self,name)
|
||||
old = getattr(self, name)
|
||||
except AttributeError:
|
||||
raise DistutilsSetupError(
|
||||
"%s: No such distribution setting" % name
|
||||
)
|
||||
if old is not None and not isinstance(old,sequence):
|
||||
if old is not None and not isinstance(old, sequence):
|
||||
raise DistutilsSetupError(
|
||||
name+": this setting cannot be changed via include/exclude"
|
||||
name + ": this setting cannot be changed via include/exclude"
|
||||
)
|
||||
elif old:
|
||||
setattr(self,name,[item for item in old if item not in value])
|
||||
setattr(self, name, [item for item in old if item not in value])
|
||||
|
||||
def _include_misc(self,name,value):
|
||||
def _include_misc(self, name, value):
|
||||
"""Handle 'include()' for list/tuple attrs without a special handler"""
|
||||
|
||||
if not isinstance(value,sequence):
|
||||
if not isinstance(value, sequence):
|
||||
raise DistutilsSetupError(
|
||||
"%s: setting must be a list (%r)" % (name, value)
|
||||
)
|
||||
try:
|
||||
old = getattr(self,name)
|
||||
old = getattr(self, name)
|
||||
except AttributeError:
|
||||
raise DistutilsSetupError(
|
||||
"%s: No such distribution setting" % name
|
||||
)
|
||||
if old is None:
|
||||
setattr(self,name,value)
|
||||
elif not isinstance(old,sequence):
|
||||
setattr(self, name, value)
|
||||
elif not isinstance(old, sequence):
|
||||
raise DistutilsSetupError(
|
||||
name+": this setting cannot be changed via include/exclude"
|
||||
name + ": this setting cannot be changed via include/exclude"
|
||||
)
|
||||
else:
|
||||
setattr(self,name,old+[item for item in value if item not in old])
|
||||
new = [item for item in value if item not in old]
|
||||
setattr(self, name, old + new)
|
||||
|
||||
def exclude(self,**attrs):
|
||||
def exclude(self, **attrs):
|
||||
"""Remove items from distribution that are named in keyword arguments
|
||||
|
||||
For example, 'dist.exclude(py_modules=["x"])' would remove 'x' from
|
||||
|
|
@ -577,15 +724,15 @@ class Distribution(_Distribution):
|
|||
will try to call 'dist._exclude_foo({"bar":"baz"})', which can then
|
||||
handle whatever special exclusion logic is needed.
|
||||
"""
|
||||
for k,v in attrs.items():
|
||||
exclude = getattr(self, '_exclude_'+k, None)
|
||||
for k, v in attrs.items():
|
||||
exclude = getattr(self, '_exclude_' + k, None)
|
||||
if exclude:
|
||||
exclude(v)
|
||||
else:
|
||||
self._exclude_misc(k,v)
|
||||
self._exclude_misc(k, v)
|
||||
|
||||
def _exclude_packages(self,packages):
|
||||
if not isinstance(packages,sequence):
|
||||
def _exclude_packages(self, packages):
|
||||
if not isinstance(packages, sequence):
|
||||
raise DistutilsSetupError(
|
||||
"packages: setting must be a list or tuple (%r)" % (packages,)
|
||||
)
|
||||
|
|
@ -600,17 +747,17 @@ class Distribution(_Distribution):
|
|||
command = args[0]
|
||||
aliases = self.get_option_dict('aliases')
|
||||
while command in aliases:
|
||||
src,alias = aliases[command]
|
||||
del aliases[command] # ensure each alias can expand only once!
|
||||
src, alias = aliases[command]
|
||||
del aliases[command] # ensure each alias can expand only once!
|
||||
import shlex
|
||||
args[:1] = shlex.split(alias,True)
|
||||
args[:1] = shlex.split(alias, True)
|
||||
command = args[0]
|
||||
|
||||
nargs = _Distribution._parse_command_opts(self, parser, args)
|
||||
|
||||
# Handle commands that want to consume all remaining arguments
|
||||
cmd_class = self.get_command_class(command)
|
||||
if getattr(cmd_class,'command_consumes_arguments',None):
|
||||
if getattr(cmd_class, 'command_consumes_arguments', None):
|
||||
self.get_option_dict(command)['args'] = ("command line", nargs)
|
||||
if nargs is not None:
|
||||
return []
|
||||
|
|
@ -629,31 +776,31 @@ class Distribution(_Distribution):
|
|||
|
||||
d = {}
|
||||
|
||||
for cmd,opts in self.command_options.items():
|
||||
for cmd, opts in self.command_options.items():
|
||||
|
||||
for opt,(src,val) in opts.items():
|
||||
for opt, (src, val) in opts.items():
|
||||
|
||||
if src != "command line":
|
||||
continue
|
||||
|
||||
opt = opt.replace('_','-')
|
||||
opt = opt.replace('_', '-')
|
||||
|
||||
if val==0:
|
||||
if val == 0:
|
||||
cmdobj = self.get_command_obj(cmd)
|
||||
neg_opt = self.negative_opt.copy()
|
||||
neg_opt.update(getattr(cmdobj,'negative_opt',{}))
|
||||
for neg,pos in neg_opt.items():
|
||||
if pos==opt:
|
||||
opt=neg
|
||||
val=None
|
||||
neg_opt.update(getattr(cmdobj, 'negative_opt', {}))
|
||||
for neg, pos in neg_opt.items():
|
||||
if pos == opt:
|
||||
opt = neg
|
||||
val = None
|
||||
break
|
||||
else:
|
||||
raise AssertionError("Shouldn't be able to get here")
|
||||
|
||||
elif val==1:
|
||||
elif val == 1:
|
||||
val = None
|
||||
|
||||
d.setdefault(cmd,{})[opt] = val
|
||||
d.setdefault(cmd, {})[opt] = val
|
||||
|
||||
return d
|
||||
|
||||
|
|
@ -667,7 +814,7 @@ class Distribution(_Distribution):
|
|||
yield module
|
||||
|
||||
for ext in self.ext_modules or ():
|
||||
if isinstance(ext,tuple):
|
||||
if isinstance(ext, tuple):
|
||||
name, buildinfo = ext
|
||||
else:
|
||||
name = ext.name
|
||||
|
|
@ -711,16 +858,11 @@ class Distribution(_Distribution):
|
|||
sys.stdout.detach(), encoding, errors, newline, line_buffering)
|
||||
|
||||
|
||||
# Install it throughout the distutils
|
||||
for module in distutils.dist, distutils.core, distutils.cmd:
|
||||
module.Distribution = Distribution
|
||||
|
||||
|
||||
class Feature:
|
||||
"""
|
||||
**deprecated** -- The `Feature` facility was never completely implemented
|
||||
or supported, `has reported issues
|
||||
<https://bitbucket.org/pypa/setuptools/issue/58>`_ and will be removed in
|
||||
<https://github.com/pypa/setuptools/issues/58>`_ and will be removed in
|
||||
a future version.
|
||||
|
||||
A subset of the distribution that can be excluded if unneeded/wanted
|
||||
|
|
@ -775,14 +917,14 @@ class Feature:
|
|||
|
||||
@staticmethod
|
||||
def warn_deprecated():
|
||||
warnings.warn(
|
||||
msg = (
|
||||
"Features are deprecated and will be removed in a future "
|
||||
"version. See http://bitbucket.org/pypa/setuptools/65.",
|
||||
DeprecationWarning,
|
||||
stacklevel=3,
|
||||
"version. See https://github.com/pypa/setuptools/issues/65."
|
||||
)
|
||||
warnings.warn(msg, DeprecationWarning, stacklevel=3)
|
||||
|
||||
def __init__(self, description, standard=False, available=True,
|
||||
def __init__(
|
||||
self, description, standard=False, available=True,
|
||||
optional=True, require_features=(), remove=(), **extras):
|
||||
self.warn_deprecated()
|
||||
|
||||
|
|
@ -790,32 +932,32 @@ class Feature:
|
|||
self.standard = standard
|
||||
self.available = available
|
||||
self.optional = optional
|
||||
if isinstance(require_features,(str,Require)):
|
||||
if isinstance(require_features, (str, Require)):
|
||||
require_features = require_features,
|
||||
|
||||
self.require_features = [
|
||||
r for r in require_features if isinstance(r,str)
|
||||
r for r in require_features if isinstance(r, str)
|
||||
]
|
||||
er = [r for r in require_features if not isinstance(r,str)]
|
||||
if er: extras['require_features'] = er
|
||||
er = [r for r in require_features if not isinstance(r, str)]
|
||||
if er:
|
||||
extras['require_features'] = er
|
||||
|
||||
if isinstance(remove,str):
|
||||
if isinstance(remove, str):
|
||||
remove = remove,
|
||||
self.remove = remove
|
||||
self.extras = extras
|
||||
|
||||
if not remove and not require_features and not extras:
|
||||
raise DistutilsSetupError(
|
||||
"Feature %s: must define 'require_features', 'remove', or at least one"
|
||||
" of 'packages', 'py_modules', etc."
|
||||
"Feature %s: must define 'require_features', 'remove', or "
|
||||
"at least one of 'packages', 'py_modules', etc."
|
||||
)
|
||||
|
||||
def include_by_default(self):
|
||||
"""Should this feature be included by default?"""
|
||||
return self.available and self.standard
|
||||
|
||||
def include_in(self,dist):
|
||||
|
||||
def include_in(self, dist):
|
||||
"""Ensure feature and its requirements are included in distribution
|
||||
|
||||
You may override this in a subclass to perform additional operations on
|
||||
|
|
@ -826,7 +968,7 @@ class Feature:
|
|||
|
||||
if not self.available:
|
||||
raise DistutilsPlatformError(
|
||||
self.description+" is required, "
|
||||
self.description + " is required, "
|
||||
"but is not available on this platform"
|
||||
)
|
||||
|
||||
|
|
@ -835,8 +977,7 @@ class Feature:
|
|||
for f in self.require_features:
|
||||
dist.include_feature(f)
|
||||
|
||||
def exclude_from(self,dist):
|
||||
|
||||
def exclude_from(self, dist):
|
||||
"""Ensure feature is excluded from distribution
|
||||
|
||||
You may override this in a subclass to perform additional operations on
|
||||
|
|
@ -851,8 +992,7 @@ class Feature:
|
|||
for item in self.remove:
|
||||
dist.exclude_package(item)
|
||||
|
||||
def validate(self,dist):
|
||||
|
||||
def validate(self, dist):
|
||||
"""Verify that feature makes sense in context of distribution
|
||||
|
||||
This method is called by the distribution just before it parses its
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import sys
|
||||
import re
|
||||
import functools
|
||||
import distutils.core
|
||||
|
|
@ -7,18 +6,14 @@ import distutils.extension
|
|||
|
||||
from setuptools.extern.six.moves import map
|
||||
|
||||
from .dist import _get_unpatched
|
||||
from . import msvc9_support
|
||||
from .monkey import get_unpatched
|
||||
|
||||
_Extension = _get_unpatched(distutils.core.Extension)
|
||||
|
||||
msvc9_support.patch_for_specialized_compiler()
|
||||
|
||||
def _have_cython():
|
||||
"""
|
||||
Return True if Cython can be imported.
|
||||
"""
|
||||
cython_impl = 'Cython.Distutils.build_ext',
|
||||
cython_impl = 'Cython.Distutils.build_ext'
|
||||
try:
|
||||
# from (cython_impl) import build_ext
|
||||
__import__(cython_impl, fromlist=['build_ext']).build_ext
|
||||
|
|
@ -27,13 +22,22 @@ def _have_cython():
|
|||
pass
|
||||
return False
|
||||
|
||||
|
||||
# for compatibility
|
||||
have_pyrex = _have_cython
|
||||
|
||||
_Extension = get_unpatched(distutils.core.Extension)
|
||||
|
||||
|
||||
class Extension(_Extension):
|
||||
"""Extension that uses '.c' files in place of '.pyx' files"""
|
||||
|
||||
def __init__(self, name, sources, *args, **kw):
|
||||
# The *args is needed for compatibility as calls may use positional
|
||||
# arguments. py_limited_api may be set only via keyword.
|
||||
self.py_limited_api = kw.pop("py_limited_api", False)
|
||||
_Extension.__init__(self, name, sources, *args, **kw)
|
||||
|
||||
def _convert_pyx_sources_to_lang(self):
|
||||
"""
|
||||
Replace sources with .pyx extensions to sources with the target
|
||||
|
|
@ -48,10 +52,6 @@ class Extension(_Extension):
|
|||
sub = functools.partial(re.sub, '.pyx$', target_ext)
|
||||
self.sources = list(map(sub, self.sources))
|
||||
|
||||
|
||||
class Library(Extension):
|
||||
"""Just like a regular Extension, but built as a library instead"""
|
||||
|
||||
distutils.core.Extension = Extension
|
||||
distutils.extension.Extension = Extension
|
||||
if 'distutils.command.build_ext' in sys.modules:
|
||||
sys.modules['distutils.command.build_ext'].Extension = Extension
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
from pkg_resources.extern import VendorImporter
|
||||
|
||||
|
||||
names = 'six',
|
||||
VendorImporter(__name__, names, 'pkg_resources._vendor').install()
|
||||
|
|
|
|||
176
lib/python3.4/site-packages/setuptools/glob.py
Normal file
176
lib/python3.4/site-packages/setuptools/glob.py
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
"""
|
||||
Filename globbing utility. Mostly a copy of `glob` from Python 3.5.
|
||||
|
||||
Changes include:
|
||||
* `yield from` and PEP3102 `*` removed.
|
||||
* `bytes` changed to `six.binary_type`.
|
||||
* Hidden files are not ignored.
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import fnmatch
|
||||
from setuptools.extern.six import binary_type
|
||||
|
||||
__all__ = ["glob", "iglob", "escape"]
|
||||
|
||||
|
||||
def glob(pathname, recursive=False):
|
||||
"""Return a list of paths matching a pathname pattern.
|
||||
|
||||
The pattern may contain simple shell-style wildcards a la
|
||||
fnmatch. However, unlike fnmatch, filenames starting with a
|
||||
dot are special cases that are not matched by '*' and '?'
|
||||
patterns.
|
||||
|
||||
If recursive is true, the pattern '**' will match any files and
|
||||
zero or more directories and subdirectories.
|
||||
"""
|
||||
return list(iglob(pathname, recursive=recursive))
|
||||
|
||||
|
||||
def iglob(pathname, recursive=False):
|
||||
"""Return an iterator which yields the paths matching a pathname pattern.
|
||||
|
||||
The pattern may contain simple shell-style wildcards a la
|
||||
fnmatch. However, unlike fnmatch, filenames starting with a
|
||||
dot are special cases that are not matched by '*' and '?'
|
||||
patterns.
|
||||
|
||||
If recursive is true, the pattern '**' will match any files and
|
||||
zero or more directories and subdirectories.
|
||||
"""
|
||||
it = _iglob(pathname, recursive)
|
||||
if recursive and _isrecursive(pathname):
|
||||
s = next(it) # skip empty string
|
||||
assert not s
|
||||
return it
|
||||
|
||||
|
||||
def _iglob(pathname, recursive):
|
||||
dirname, basename = os.path.split(pathname)
|
||||
if not has_magic(pathname):
|
||||
if basename:
|
||||
if os.path.lexists(pathname):
|
||||
yield pathname
|
||||
else:
|
||||
# Patterns ending with a slash should match only directories
|
||||
if os.path.isdir(dirname):
|
||||
yield pathname
|
||||
return
|
||||
if not dirname:
|
||||
if recursive and _isrecursive(basename):
|
||||
for x in glob2(dirname, basename):
|
||||
yield x
|
||||
else:
|
||||
for x in glob1(dirname, basename):
|
||||
yield x
|
||||
return
|
||||
# `os.path.split()` returns the argument itself as a dirname if it is a
|
||||
# drive or UNC path. Prevent an infinite recursion if a drive or UNC path
|
||||
# contains magic characters (i.e. r'\\?\C:').
|
||||
if dirname != pathname and has_magic(dirname):
|
||||
dirs = _iglob(dirname, recursive)
|
||||
else:
|
||||
dirs = [dirname]
|
||||
if has_magic(basename):
|
||||
if recursive and _isrecursive(basename):
|
||||
glob_in_dir = glob2
|
||||
else:
|
||||
glob_in_dir = glob1
|
||||
else:
|
||||
glob_in_dir = glob0
|
||||
for dirname in dirs:
|
||||
for name in glob_in_dir(dirname, basename):
|
||||
yield os.path.join(dirname, name)
|
||||
|
||||
|
||||
# These 2 helper functions non-recursively glob inside a literal directory.
|
||||
# They return a list of basenames. `glob1` accepts a pattern while `glob0`
|
||||
# takes a literal basename (so it only has to check for its existence).
|
||||
|
||||
|
||||
def glob1(dirname, pattern):
|
||||
if not dirname:
|
||||
if isinstance(pattern, binary_type):
|
||||
dirname = os.curdir.encode('ASCII')
|
||||
else:
|
||||
dirname = os.curdir
|
||||
try:
|
||||
names = os.listdir(dirname)
|
||||
except OSError:
|
||||
return []
|
||||
return fnmatch.filter(names, pattern)
|
||||
|
||||
|
||||
def glob0(dirname, basename):
|
||||
if not basename:
|
||||
# `os.path.split()` returns an empty basename for paths ending with a
|
||||
# directory separator. 'q*x/' should match only directories.
|
||||
if os.path.isdir(dirname):
|
||||
return [basename]
|
||||
else:
|
||||
if os.path.lexists(os.path.join(dirname, basename)):
|
||||
return [basename]
|
||||
return []
|
||||
|
||||
|
||||
# This helper function recursively yields relative pathnames inside a literal
|
||||
# directory.
|
||||
|
||||
|
||||
def glob2(dirname, pattern):
|
||||
assert _isrecursive(pattern)
|
||||
yield pattern[:0]
|
||||
for x in _rlistdir(dirname):
|
||||
yield x
|
||||
|
||||
|
||||
# Recursively yields relative pathnames inside a literal directory.
|
||||
def _rlistdir(dirname):
|
||||
if not dirname:
|
||||
if isinstance(dirname, binary_type):
|
||||
dirname = binary_type(os.curdir, 'ASCII')
|
||||
else:
|
||||
dirname = os.curdir
|
||||
try:
|
||||
names = os.listdir(dirname)
|
||||
except os.error:
|
||||
return
|
||||
for x in names:
|
||||
yield x
|
||||
path = os.path.join(dirname, x) if dirname else x
|
||||
for y in _rlistdir(path):
|
||||
yield os.path.join(x, y)
|
||||
|
||||
|
||||
magic_check = re.compile('([*?[])')
|
||||
magic_check_bytes = re.compile(b'([*?[])')
|
||||
|
||||
|
||||
def has_magic(s):
|
||||
if isinstance(s, binary_type):
|
||||
match = magic_check_bytes.search(s)
|
||||
else:
|
||||
match = magic_check.search(s)
|
||||
return match is not None
|
||||
|
||||
|
||||
def _isrecursive(pattern):
|
||||
if isinstance(pattern, binary_type):
|
||||
return pattern == b'**'
|
||||
else:
|
||||
return pattern == '**'
|
||||
|
||||
|
||||
def escape(pathname):
|
||||
"""Escape all special characters.
|
||||
"""
|
||||
# Escaping is done by wrapping any of "*?[" between square brackets.
|
||||
# Metacharacters do not work in the drive part and shouldn't be escaped.
|
||||
drive, pathname = os.path.splitdrive(pathname)
|
||||
if isinstance(pathname, binary_type):
|
||||
pathname = magic_check_bytes.sub(br'[\1]', pathname)
|
||||
else:
|
||||
pathname = magic_check.sub(r'[\1]', pathname)
|
||||
return drive + pathname
|
||||
Binary file not shown.
|
|
@ -11,25 +11,25 @@ import sys
|
|||
|
||||
|
||||
def run():
|
||||
"""
|
||||
Run the script in sys.argv[1] as if it had
|
||||
been invoked naturally.
|
||||
"""
|
||||
__builtins__
|
||||
script_name = sys.argv[1]
|
||||
namespace = dict(
|
||||
__file__ = script_name,
|
||||
__name__ = '__main__',
|
||||
__doc__ = None,
|
||||
)
|
||||
sys.argv[:] = sys.argv[1:]
|
||||
"""
|
||||
Run the script in sys.argv[1] as if it had
|
||||
been invoked naturally.
|
||||
"""
|
||||
__builtins__
|
||||
script_name = sys.argv[1]
|
||||
namespace = dict(
|
||||
__file__=script_name,
|
||||
__name__='__main__',
|
||||
__doc__=None,
|
||||
)
|
||||
sys.argv[:] = sys.argv[1:]
|
||||
|
||||
open_ = getattr(tokenize, 'open', open)
|
||||
script = open_(script_name).read()
|
||||
norm_script = script.replace('\\r\\n', '\\n')
|
||||
code = compile(norm_script, script_name, 'exec')
|
||||
exec(code, namespace)
|
||||
open_ = getattr(tokenize, 'open', open)
|
||||
script = open_(script_name).read()
|
||||
norm_script = script.replace('\\r\\n', '\\n')
|
||||
code = compile(norm_script, script_name, 'exec')
|
||||
exec(code, namespace)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run()
|
||||
run()
|
||||
|
|
|
|||
|
|
@ -10,8 +10,10 @@ This module raises an ImportError on Python 2.
|
|||
from distutils.util import Mixin2to3 as _Mixin2to3
|
||||
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)
|
||||
|
|
@ -22,15 +24,16 @@ class DistutilsRefactoringTool(RefactoringTool):
|
|||
def log_debug(self, msg, *args):
|
||||
log.debug(msg, *args)
|
||||
|
||||
|
||||
class Mixin2to3(_Mixin2to3):
|
||||
def run_2to3(self, files, doctests = False):
|
||||
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))
|
||||
log.info("Fixing " + " ".join(files))
|
||||
self.__build_fixer_names()
|
||||
self.__exclude_fixers()
|
||||
if doctests:
|
||||
|
|
@ -41,7 +44,8 @@ class Mixin2to3(_Mixin2to3):
|
|||
_Mixin2to3.run_2to3(self, files)
|
||||
|
||||
def __build_fixer_names(self):
|
||||
if self.fixer_names: return
|
||||
if self.fixer_names:
|
||||
return
|
||||
self.fixer_names = []
|
||||
for p in setuptools.lib2to3_fixer_packages:
|
||||
self.fixer_names.extend(get_fixers_from_package(p))
|
||||
|
|
|
|||
197
lib/python3.4/site-packages/setuptools/monkey.py
Normal file
197
lib/python3.4/site-packages/setuptools/monkey.py
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
"""
|
||||
Monkey patching of distutils.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import distutils.filelist
|
||||
import platform
|
||||
import types
|
||||
import functools
|
||||
import inspect
|
||||
|
||||
from .py26compat import import_module
|
||||
from setuptools.extern import six
|
||||
|
||||
import setuptools
|
||||
|
||||
__all__ = []
|
||||
"""
|
||||
Everything is private. Contact the project team
|
||||
if you think you need this functionality.
|
||||
"""
|
||||
|
||||
|
||||
def _get_mro(cls):
|
||||
"""
|
||||
Returns the bases classes for cls sorted by the MRO.
|
||||
|
||||
Works around an issue on Jython where inspect.getmro will not return all
|
||||
base classes if multiple classes share the same name. Instead, this
|
||||
function will return a tuple containing the class itself, and the contents
|
||||
of cls.__bases__. See https://github.com/pypa/setuptools/issues/1024.
|
||||
"""
|
||||
if platform.python_implementation() == "Jython":
|
||||
return (cls,) + cls.__bases__
|
||||
return inspect.getmro(cls)
|
||||
|
||||
|
||||
def get_unpatched(item):
|
||||
lookup = (
|
||||
get_unpatched_class if isinstance(item, six.class_types) else
|
||||
get_unpatched_function if isinstance(item, types.FunctionType) else
|
||||
lambda item: None
|
||||
)
|
||||
return lookup(item)
|
||||
|
||||
|
||||
def get_unpatched_class(cls):
|
||||
"""Protect against re-patching the distutils if reloaded
|
||||
|
||||
Also ensures that no other distutils extension monkeypatched the distutils
|
||||
first.
|
||||
"""
|
||||
external_bases = (
|
||||
cls
|
||||
for cls in _get_mro(cls)
|
||||
if not cls.__module__.startswith('setuptools')
|
||||
)
|
||||
base = next(external_bases)
|
||||
if not base.__module__.startswith('distutils'):
|
||||
msg = "distutils has already been patched by %r" % cls
|
||||
raise AssertionError(msg)
|
||||
return base
|
||||
|
||||
|
||||
def patch_all():
|
||||
# we can't patch distutils.cmd, alas
|
||||
distutils.core.Command = setuptools.Command
|
||||
|
||||
has_issue_12885 = sys.version_info <= (3, 5, 3)
|
||||
|
||||
if has_issue_12885:
|
||||
# fix findall bug in distutils (http://bugs.python.org/issue12885)
|
||||
distutils.filelist.findall = setuptools.findall
|
||||
|
||||
needs_warehouse = (
|
||||
sys.version_info < (2, 7, 13)
|
||||
or
|
||||
(3, 0) < sys.version_info < (3, 3, 7)
|
||||
or
|
||||
(3, 4) < sys.version_info < (3, 4, 6)
|
||||
or
|
||||
(3, 5) < sys.version_info <= (3, 5, 3)
|
||||
)
|
||||
|
||||
if needs_warehouse:
|
||||
warehouse = 'https://upload.pypi.org/legacy/'
|
||||
distutils.config.PyPIRCCommand.DEFAULT_REPOSITORY = warehouse
|
||||
|
||||
_patch_distribution_metadata_write_pkg_file()
|
||||
_patch_distribution_metadata_write_pkg_info()
|
||||
|
||||
# Install Distribution throughout the distutils
|
||||
for module in distutils.dist, distutils.core, distutils.cmd:
|
||||
module.Distribution = setuptools.dist.Distribution
|
||||
|
||||
# Install the patched Extension
|
||||
distutils.core.Extension = setuptools.extension.Extension
|
||||
distutils.extension.Extension = setuptools.extension.Extension
|
||||
if 'distutils.command.build_ext' in sys.modules:
|
||||
sys.modules['distutils.command.build_ext'].Extension = (
|
||||
setuptools.extension.Extension
|
||||
)
|
||||
|
||||
patch_for_msvc_specialized_compiler()
|
||||
|
||||
|
||||
def _patch_distribution_metadata_write_pkg_file():
|
||||
"""Patch write_pkg_file to also write Requires-Python/Requires-External"""
|
||||
distutils.dist.DistributionMetadata.write_pkg_file = (
|
||||
setuptools.dist.write_pkg_file
|
||||
)
|
||||
|
||||
|
||||
def _patch_distribution_metadata_write_pkg_info():
|
||||
"""
|
||||
Workaround issue #197 - Python 3 prior to 3.2.2 uses an environment-local
|
||||
encoding to save the pkg_info. Monkey-patch its write_pkg_info method to
|
||||
correct this undesirable behavior.
|
||||
"""
|
||||
environment_local = (3,) <= sys.version_info[:3] < (3, 2, 2)
|
||||
if not environment_local:
|
||||
return
|
||||
|
||||
distutils.dist.DistributionMetadata.write_pkg_info = (
|
||||
setuptools.dist.write_pkg_info
|
||||
)
|
||||
|
||||
|
||||
def patch_func(replacement, target_mod, func_name):
|
||||
"""
|
||||
Patch func_name in target_mod with replacement
|
||||
|
||||
Important - original must be resolved by name to avoid
|
||||
patching an already patched function.
|
||||
"""
|
||||
original = getattr(target_mod, func_name)
|
||||
|
||||
# set the 'unpatched' attribute on the replacement to
|
||||
# point to the original.
|
||||
vars(replacement).setdefault('unpatched', original)
|
||||
|
||||
# replace the function in the original module
|
||||
setattr(target_mod, func_name, replacement)
|
||||
|
||||
|
||||
def get_unpatched_function(candidate):
|
||||
return getattr(candidate, 'unpatched')
|
||||
|
||||
|
||||
def patch_for_msvc_specialized_compiler():
|
||||
"""
|
||||
Patch functions in distutils to use standalone Microsoft Visual C++
|
||||
compilers.
|
||||
"""
|
||||
# import late to avoid circular imports on Python < 3.5
|
||||
msvc = import_module('setuptools.msvc')
|
||||
|
||||
if platform.system() != 'Windows':
|
||||
# Compilers only availables on Microsoft Windows
|
||||
return
|
||||
|
||||
def patch_params(mod_name, func_name):
|
||||
"""
|
||||
Prepare the parameters for patch_func to patch indicated function.
|
||||
"""
|
||||
repl_prefix = 'msvc9_' if 'msvc9' in mod_name else 'msvc14_'
|
||||
repl_name = repl_prefix + func_name.lstrip('_')
|
||||
repl = getattr(msvc, repl_name)
|
||||
mod = import_module(mod_name)
|
||||
if not hasattr(mod, func_name):
|
||||
raise ImportError(func_name)
|
||||
return repl, mod, func_name
|
||||
|
||||
# Python 2.7 to 3.4
|
||||
msvc9 = functools.partial(patch_params, 'distutils.msvc9compiler')
|
||||
|
||||
# Python 3.5+
|
||||
msvc14 = functools.partial(patch_params, 'distutils._msvccompiler')
|
||||
|
||||
try:
|
||||
# Patch distutils.msvc9compiler
|
||||
patch_func(*msvc9('find_vcvarsall'))
|
||||
patch_func(*msvc9('query_vcvarsall'))
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
try:
|
||||
# Patch distutils._msvccompiler._get_vc_env
|
||||
patch_func(*msvc14('_get_vc_env'))
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
try:
|
||||
# Patch distutils._msvccompiler.gen_lib_options for Numpy
|
||||
patch_func(*msvc14('gen_lib_options'))
|
||||
except ImportError:
|
||||
pass
|
||||
1302
lib/python3.4/site-packages/setuptools/msvc.py
Normal file
1302
lib/python3.4/site-packages/setuptools/msvc.py
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1,63 +0,0 @@
|
|||
try:
|
||||
import distutils.msvc9compiler
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
unpatched = dict()
|
||||
|
||||
def patch_for_specialized_compiler():
|
||||
"""
|
||||
Patch functions in distutils.msvc9compiler to use the standalone compiler
|
||||
build for Python (Windows only). Fall back to original behavior when the
|
||||
standalone compiler is not available.
|
||||
"""
|
||||
if 'distutils' not in globals():
|
||||
# The module isn't available to be patched
|
||||
return
|
||||
|
||||
if unpatched:
|
||||
# Already patched
|
||||
return
|
||||
|
||||
unpatched.update(vars(distutils.msvc9compiler))
|
||||
|
||||
distutils.msvc9compiler.find_vcvarsall = find_vcvarsall
|
||||
distutils.msvc9compiler.query_vcvarsall = query_vcvarsall
|
||||
|
||||
def find_vcvarsall(version):
|
||||
Reg = distutils.msvc9compiler.Reg
|
||||
VC_BASE = r'Software\%sMicrosoft\DevDiv\VCForPython\%0.1f'
|
||||
key = VC_BASE % ('', version)
|
||||
try:
|
||||
# Per-user installs register the compiler path here
|
||||
productdir = Reg.get_value(key, "installdir")
|
||||
except KeyError:
|
||||
try:
|
||||
# All-user installs on a 64-bit system register here
|
||||
key = VC_BASE % ('Wow6432Node\\', version)
|
||||
productdir = Reg.get_value(key, "installdir")
|
||||
except KeyError:
|
||||
productdir = None
|
||||
|
||||
if productdir:
|
||||
import os
|
||||
vcvarsall = os.path.join(productdir, "vcvarsall.bat")
|
||||
if os.path.isfile(vcvarsall):
|
||||
return vcvarsall
|
||||
|
||||
return unpatched['find_vcvarsall'](version)
|
||||
|
||||
def query_vcvarsall(version, *args, **kwargs):
|
||||
try:
|
||||
return unpatched['query_vcvarsall'](version, *args, **kwargs)
|
||||
except distutils.errors.DistutilsPlatformError as exc:
|
||||
if exc and "vcvarsall.bat" in exc.args[0]:
|
||||
message = 'Microsoft Visual C++ %0.1f is required (%s).' % (version, exc.args[0])
|
||||
if int(version) == 9:
|
||||
# This redirection link is maintained by Microsoft.
|
||||
# Contact vspython@microsoft.com if it needs updating.
|
||||
raise distutils.errors.DistutilsPlatformError(
|
||||
message + ' Get it from http://aka.ms/vcpython27'
|
||||
)
|
||||
raise distutils.errors.DistutilsPlatformError(message)
|
||||
raise
|
||||
107
lib/python3.4/site-packages/setuptools/namespaces.py
Normal file
107
lib/python3.4/site-packages/setuptools/namespaces.py
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
import os
|
||||
from distutils import log
|
||||
import itertools
|
||||
|
||||
from setuptools.extern.six.moves import map
|
||||
|
||||
|
||||
flatten = itertools.chain.from_iterable
|
||||
|
||||
|
||||
class Installer:
|
||||
|
||||
nspkg_ext = '-nspkg.pth'
|
||||
|
||||
def install_namespaces(self):
|
||||
nsp = self._get_all_ns_packages()
|
||||
if not nsp:
|
||||
return
|
||||
filename, ext = os.path.splitext(self._get_target())
|
||||
filename += self.nspkg_ext
|
||||
self.outputs.append(filename)
|
||||
log.info("Installing %s", filename)
|
||||
lines = map(self._gen_nspkg_line, nsp)
|
||||
|
||||
if self.dry_run:
|
||||
# always generate the lines, even in dry run
|
||||
list(lines)
|
||||
return
|
||||
|
||||
with open(filename, 'wt') as f:
|
||||
f.writelines(lines)
|
||||
|
||||
def uninstall_namespaces(self):
|
||||
filename, ext = os.path.splitext(self._get_target())
|
||||
filename += self.nspkg_ext
|
||||
if not os.path.exists(filename):
|
||||
return
|
||||
log.info("Removing %s", filename)
|
||||
os.remove(filename)
|
||||
|
||||
def _get_target(self):
|
||||
return self.target
|
||||
|
||||
_nspkg_tmpl = (
|
||||
"import sys, types, os",
|
||||
"has_mfs = sys.version_info > (3, 5)",
|
||||
"p = os.path.join(%(root)s, *%(pth)r)",
|
||||
"importlib = has_mfs and __import__('importlib.util')",
|
||||
"has_mfs and __import__('importlib.machinery')",
|
||||
"m = has_mfs and "
|
||||
"sys.modules.setdefault(%(pkg)r, "
|
||||
"importlib.util.module_from_spec("
|
||||
"importlib.machinery.PathFinder.find_spec(%(pkg)r, "
|
||||
"[os.path.dirname(p)])))",
|
||||
"m = m or "
|
||||
"sys.modules.setdefault(%(pkg)r, types.ModuleType(%(pkg)r))",
|
||||
"mp = (m or []) and m.__dict__.setdefault('__path__',[])",
|
||||
"(p not in mp) and mp.append(p)",
|
||||
)
|
||||
"lines for the namespace installer"
|
||||
|
||||
_nspkg_tmpl_multi = (
|
||||
'm and setattr(sys.modules[%(parent)r], %(child)r, m)',
|
||||
)
|
||||
"additional line(s) when a parent package is indicated"
|
||||
|
||||
def _get_root(self):
|
||||
return "sys._getframe(1).f_locals['sitedir']"
|
||||
|
||||
def _gen_nspkg_line(self, pkg):
|
||||
# ensure pkg is not a unicode string under Python 2.7
|
||||
pkg = str(pkg)
|
||||
pth = tuple(pkg.split('.'))
|
||||
root = self._get_root()
|
||||
tmpl_lines = self._nspkg_tmpl
|
||||
parent, sep, child = pkg.rpartition('.')
|
||||
if parent:
|
||||
tmpl_lines += self._nspkg_tmpl_multi
|
||||
return ';'.join(tmpl_lines) % locals() + '\n'
|
||||
|
||||
def _get_all_ns_packages(self):
|
||||
"""Return sorted list of all package namespaces"""
|
||||
pkgs = self.distribution.namespace_packages or []
|
||||
return sorted(flatten(map(self._pkg_names, pkgs)))
|
||||
|
||||
@staticmethod
|
||||
def _pkg_names(pkg):
|
||||
"""
|
||||
Given a namespace package, yield the components of that
|
||||
package.
|
||||
|
||||
>>> names = Installer._pkg_names('a.b.c')
|
||||
>>> set(names) == set(['a', 'a.b', 'a.b.c'])
|
||||
True
|
||||
"""
|
||||
parts = pkg.split('.')
|
||||
while parts:
|
||||
yield '.'.join(parts)
|
||||
parts.pop()
|
||||
|
||||
|
||||
class DevelopInstaller(Installer):
|
||||
def _get_root(self):
|
||||
return repr(str(self.egg_path))
|
||||
|
||||
def _get_target(self):
|
||||
return self.egg_link
|
||||
|
|
@ -17,9 +17,10 @@ except ImportError:
|
|||
from setuptools.extern import six
|
||||
from setuptools.extern.six.moves import urllib, http_client, configparser, map
|
||||
|
||||
import setuptools
|
||||
from pkg_resources import (
|
||||
CHECKOUT_DIST, Distribution, BINARY_DIST, normalize_path, SOURCE_DIST,
|
||||
require, Environment, find_distributions, safe_name, safe_version,
|
||||
Environment, find_distributions, safe_name, safe_version,
|
||||
to_filename, Requirement, DEVELOP_DIST,
|
||||
)
|
||||
from setuptools import ssl_support
|
||||
|
|
@ -29,14 +30,14 @@ from fnmatch import translate
|
|||
from setuptools.py26compat import strip_fragment
|
||||
from setuptools.py27compat import get_all_headers
|
||||
|
||||
EGG_FRAGMENT = re.compile(r'^egg=([-A-Za-z0-9_.]+)$')
|
||||
EGG_FRAGMENT = re.compile(r'^egg=([-A-Za-z0-9_.+!]+)$')
|
||||
HREF = re.compile("""href\\s*=\\s*['"]?([^'"> ]+)""", re.I)
|
||||
# this is here to fix emacs' cruddy broken syntax highlighting
|
||||
PYPI_MD5 = re.compile(
|
||||
'<a href="([^"#]+)">([^<]+)</a>\n\s+\\(<a (?:title="MD5 hash"\n\s+)'
|
||||
'href="[^?]+\?:action=show_md5&digest=([0-9a-f]{32})">md5</a>\\)'
|
||||
'<a href="([^"#]+)">([^<]+)</a>\n\\s+\\(<a (?:title="MD5 hash"\n\\s+)'
|
||||
'href="[^?]+\\?:action=show_md5&digest=([0-9a-f]{32})">md5</a>\\)'
|
||||
)
|
||||
URL_SCHEME = re.compile('([-+.a-z0-9]{2,}):',re.I).match
|
||||
URL_SCHEME = re.compile('([-+.a-z0-9]{2,}):', re.I).match
|
||||
EXTENSIONS = ".tar.gz .tar.bz2 .tar .zip .tgz".split()
|
||||
|
||||
__all__ = [
|
||||
|
|
@ -46,6 +47,19 @@ __all__ = [
|
|||
|
||||
_SOCKET_TIMEOUT = 15
|
||||
|
||||
_tmpl = "setuptools/{setuptools.__version__} Python-urllib/{py_major}"
|
||||
user_agent = _tmpl.format(py_major=sys.version[:3], setuptools=setuptools)
|
||||
|
||||
|
||||
def parse_requirement_arg(spec):
|
||||
try:
|
||||
return Requirement.parse(spec)
|
||||
except ValueError:
|
||||
raise DistutilsError(
|
||||
"Not a URL, existing file, or requirement spec: %r" % (spec,)
|
||||
)
|
||||
|
||||
|
||||
def parse_bdist_wininst(name):
|
||||
"""Return (base,pyversion) or (None,None) for possible .exe name"""
|
||||
|
||||
|
|
@ -56,45 +70,49 @@ def parse_bdist_wininst(name):
|
|||
if lower.endswith('.win32.exe'):
|
||||
base = name[:-10]
|
||||
plat = 'win32'
|
||||
elif lower.startswith('.win32-py',-16):
|
||||
elif lower.startswith('.win32-py', -16):
|
||||
py_ver = name[-7:-4]
|
||||
base = name[:-16]
|
||||
plat = 'win32'
|
||||
elif lower.endswith('.win-amd64.exe'):
|
||||
base = name[:-14]
|
||||
plat = 'win-amd64'
|
||||
elif lower.startswith('.win-amd64-py',-20):
|
||||
elif lower.startswith('.win-amd64-py', -20):
|
||||
py_ver = name[-7:-4]
|
||||
base = name[:-20]
|
||||
plat = 'win-amd64'
|
||||
return base,py_ver,plat
|
||||
return base, py_ver, plat
|
||||
|
||||
|
||||
def egg_info_for_url(url):
|
||||
parts = urllib.parse.urlparse(url)
|
||||
scheme, server, path, parameters, query, fragment = parts
|
||||
base = urllib.parse.unquote(path.split('/')[-1])
|
||||
if server=='sourceforge.net' and base=='download': # XXX Yuck
|
||||
if server == 'sourceforge.net' and base == 'download': # XXX Yuck
|
||||
base = urllib.parse.unquote(path.split('/')[-2])
|
||||
if '#' in base: base, fragment = base.split('#',1)
|
||||
return base,fragment
|
||||
if '#' in base:
|
||||
base, fragment = base.split('#', 1)
|
||||
return base, fragment
|
||||
|
||||
|
||||
def distros_for_url(url, metadata=None):
|
||||
"""Yield egg or source distribution objects that might be found at a URL"""
|
||||
base, fragment = egg_info_for_url(url)
|
||||
for dist in distros_for_location(url, base, metadata): yield dist
|
||||
for dist in distros_for_location(url, base, metadata):
|
||||
yield dist
|
||||
if fragment:
|
||||
match = EGG_FRAGMENT.match(fragment)
|
||||
if match:
|
||||
for dist in interpret_distro_name(
|
||||
url, match.group(1), metadata, precedence = CHECKOUT_DIST
|
||||
url, match.group(1), metadata, precedence=CHECKOUT_DIST
|
||||
):
|
||||
yield dist
|
||||
|
||||
|
||||
def distros_for_location(location, basename, metadata=None):
|
||||
"""Yield egg or source distribution objects based on basename"""
|
||||
if basename.endswith('.egg.zip'):
|
||||
basename = basename[:-4] # strip the .zip
|
||||
basename = basename[:-4] # strip the .zip
|
||||
if basename.endswith('.egg') and '-' in basename:
|
||||
# only one, unambiguous interpretation
|
||||
return [Distribution.from_location(location, basename, metadata)]
|
||||
|
|
@ -112,6 +130,7 @@ def distros_for_location(location, basename, metadata=None):
|
|||
return interpret_distro_name(location, basename, metadata)
|
||||
return [] # no extension matched
|
||||
|
||||
|
||||
def distros_for_filename(filename, metadata=None):
|
||||
"""Yield possible egg or source distribution objects based on a filename"""
|
||||
return distros_for_location(
|
||||
|
|
@ -142,17 +161,18 @@ def interpret_distro_name(
|
|||
# versions in distribution archive names (sdist and bdist).
|
||||
|
||||
parts = basename.split('-')
|
||||
if not py_version and any(re.match('py\d\.\d$', p) for p in parts[2:]):
|
||||
if not py_version and any(re.match(r'py\d\.\d$', p) for p in parts[2:]):
|
||||
# it is a bdist_dumb, not an sdist -- bail out
|
||||
return
|
||||
|
||||
for p in range(1,len(parts)+1):
|
||||
for p in range(1, len(parts) + 1):
|
||||
yield Distribution(
|
||||
location, metadata, '-'.join(parts[:p]), '-'.join(parts[p:]),
|
||||
py_version=py_version, precedence = precedence,
|
||||
platform = platform
|
||||
py_version=py_version, precedence=precedence,
|
||||
platform=platform
|
||||
)
|
||||
|
||||
|
||||
# From Python 2.7 docs
|
||||
def unique_everseen(iterable, key=None):
|
||||
"List unique elements, preserving order. Remember all elements ever seen."
|
||||
|
|
@ -171,19 +191,24 @@ def unique_everseen(iterable, key=None):
|
|||
seen_add(k)
|
||||
yield element
|
||||
|
||||
|
||||
def unique_values(func):
|
||||
"""
|
||||
Wrap a function returning an iterable such that the resulting iterable
|
||||
only ever yields unique items.
|
||||
"""
|
||||
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
return unique_everseen(func(*args, **kwargs))
|
||||
|
||||
return wrapper
|
||||
|
||||
REL = re.compile("""<([^>]*\srel\s*=\s*['"]?([^'">]+)[^>]*)>""", re.I)
|
||||
|
||||
REL = re.compile(r"""<([^>]*\srel\s*=\s*['"]?([^'">]+)[^>]*)>""", re.I)
|
||||
# this line is here to fix emacs' cruddy broken syntax highlighting
|
||||
|
||||
|
||||
@unique_values
|
||||
def find_external_links(url, page):
|
||||
"""Find rel="homepage" and rel="download" links in `page`, yielding URLs"""
|
||||
|
|
@ -197,19 +222,17 @@ def find_external_links(url, page):
|
|||
|
||||
for tag in ("<th>Home Page", "<th>Download URL"):
|
||||
pos = page.find(tag)
|
||||
if pos!=-1:
|
||||
match = HREF.search(page,pos)
|
||||
if pos != -1:
|
||||
match = HREF.search(page, pos)
|
||||
if match:
|
||||
yield urllib.parse.urljoin(url, htmldecode(match.group(1)))
|
||||
|
||||
user_agent = "Python-urllib/%s setuptools/%s" % (
|
||||
sys.version[:3], require('setuptools')[0].version
|
||||
)
|
||||
|
||||
class ContentChecker(object):
|
||||
"""
|
||||
A null content checker that defines the interface for checking content
|
||||
"""
|
||||
|
||||
def feed(self, block):
|
||||
"""
|
||||
Feed a block of data to the hash.
|
||||
|
|
@ -229,6 +252,7 @@ class ContentChecker(object):
|
|||
"""
|
||||
return
|
||||
|
||||
|
||||
class HashChecker(ContentChecker):
|
||||
pattern = re.compile(
|
||||
r'(?P<hash_name>sha1|sha224|sha384|sha256|sha512|md5)='
|
||||
|
|
@ -269,16 +293,22 @@ class PackageIndex(Environment):
|
|||
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('/')]
|
||||
Environment.__init__(self, *args, **kw)
|
||||
self.index_url = index_url + "/" [:not index_url.endswith('/')]
|
||||
self.scanned_urls = {}
|
||||
self.fetched_urls = {}
|
||||
self.package_pages = {}
|
||||
self.allows = re.compile('|'.join(map(translate,hosts))).match
|
||||
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()):
|
||||
use_ssl = (
|
||||
verify_ssl
|
||||
and ssl_support.is_available
|
||||
and (ca_bundle or ssl_support.find_ca_bundle())
|
||||
)
|
||||
if use_ssl:
|
||||
self.opener = ssl_support.opener_for(ca_bundle)
|
||||
else: self.opener = urllib.request.urlopen
|
||||
else:
|
||||
self.opener = urllib.request.urlopen
|
||||
|
||||
def process_url(self, url, retrieve=False):
|
||||
"""Evaluate a URL as a possible download, and maybe retrieve it"""
|
||||
|
|
@ -304,17 +334,19 @@ 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] = True # prevent multiple fetch attempts
|
||||
tmpl = "Download error on %s: %%s -- Some packages may not be found!"
|
||||
f = self.open_url(url, tmpl % url)
|
||||
if f is None:
|
||||
return
|
||||
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
|
||||
f.close() # not html, we can't process it
|
||||
return
|
||||
|
||||
base = f.url # handle redirects
|
||||
base = f.url # handle redirects
|
||||
page = f.read()
|
||||
if not isinstance(page, str): # We are in Python 3 and got bytes. We want str.
|
||||
if not isinstance(page, str): # We are in Python 3 and got bytes. We want str.
|
||||
if isinstance(f, urllib.error.HTTPError):
|
||||
# Errors have no charset, assume latin1:
|
||||
charset = 'latin-1'
|
||||
|
|
@ -325,7 +357,7 @@ class PackageIndex(Environment):
|
|||
for match in HREF.finditer(page):
|
||||
link = urllib.parse.urljoin(base, htmldecode(match.group(1)))
|
||||
self.process_url(link)
|
||||
if url.startswith(self.index_url) and getattr(f,'code',None)!=404:
|
||||
if url.startswith(self.index_url) and getattr(f, 'code', None) != 404:
|
||||
page = self.process_index(url, page)
|
||||
|
||||
def process_filename(self, fn, nested=False):
|
||||
|
|
@ -337,7 +369,7 @@ class PackageIndex(Environment):
|
|||
if os.path.isdir(fn) and not nested:
|
||||
path = os.path.realpath(fn)
|
||||
for item in os.listdir(path):
|
||||
self.process_filename(os.path.join(path,item), True)
|
||||
self.process_filename(os.path.join(path, item), True)
|
||||
|
||||
dists = distros_for_filename(fn)
|
||||
if dists:
|
||||
|
|
@ -346,7 +378,8 @@ class PackageIndex(Environment):
|
|||
|
||||
def url_ok(self, url, fatal=False):
|
||||
s = URL_SCHEME(url)
|
||||
if (s and s.group(1).lower()=='file') or self.allows(urllib.parse.urlparse(url)[1]):
|
||||
is_file = s and s.group(1).lower() == 'file'
|
||||
if is_file or self.allows(urllib.parse.urlparse(url)[1]):
|
||||
return True
|
||||
msg = ("\nNote: Bypassing %s (disallowed host; see "
|
||||
"http://bit.ly/1dg9ijs for details).\n")
|
||||
|
|
@ -381,19 +414,20 @@ class PackageIndex(Environment):
|
|||
dist.precedence = SOURCE_DIST
|
||||
self.add(dist)
|
||||
|
||||
def process_index(self,url,page):
|
||||
def process_index(self, url, page):
|
||||
"""Process the contents of a PyPI page"""
|
||||
|
||||
def scan(link):
|
||||
# Process a URL to see if it's for a package page
|
||||
if link.startswith(self.index_url):
|
||||
parts = list(map(
|
||||
urllib.parse.unquote, link[len(self.index_url):].split('/')
|
||||
))
|
||||
if len(parts)==2 and '#' not in parts[1]:
|
||||
if len(parts) == 2 and '#' not in parts[1]:
|
||||
# it's a package page, sanitize and index it
|
||||
pkg = safe_name(parts[0])
|
||||
ver = safe_version(parts[1])
|
||||
self.package_pages.setdefault(pkg.lower(),{})[link] = True
|
||||
self.package_pages.setdefault(pkg.lower(), {})[link] = True
|
||||
return to_filename(pkg), to_filename(ver)
|
||||
return None, None
|
||||
|
||||
|
|
@ -404,7 +438,7 @@ class PackageIndex(Environment):
|
|||
except ValueError:
|
||||
pass
|
||||
|
||||
pkg, ver = scan(url) # ensure this page is in the page index
|
||||
pkg, ver = scan(url) # ensure this page is in the page index
|
||||
if pkg:
|
||||
# process individual package page
|
||||
for new_url in find_external_links(url, page):
|
||||
|
|
@ -412,16 +446,16 @@ class PackageIndex(Environment):
|
|||
base, frag = egg_info_for_url(new_url)
|
||||
if base.endswith('.py') and not frag:
|
||||
if ver:
|
||||
new_url+='#egg=%s-%s' % (pkg,ver)
|
||||
new_url += '#egg=%s-%s' % (pkg, ver)
|
||||
else:
|
||||
self.need_version_info(url)
|
||||
self.scan_url(new_url)
|
||||
|
||||
return PYPI_MD5.sub(
|
||||
lambda m: '<a href="%s#md5=%s">%s</a>' % m.group(1,3,2), page
|
||||
lambda m: '<a href="%s#md5=%s">%s</a>' % m.group(1, 3, 2), page
|
||||
)
|
||||
else:
|
||||
return "" # no sense double-scanning non-package pages
|
||||
return "" # no sense double-scanning non-package pages
|
||||
|
||||
def need_version_info(self, url):
|
||||
self.scan_all(
|
||||
|
|
@ -431,24 +465,25 @@ class PackageIndex(Environment):
|
|||
|
||||
def scan_all(self, msg=None, *args):
|
||||
if self.index_url not in self.fetched_urls:
|
||||
if msg: self.warn(msg,*args)
|
||||
if msg:
|
||||
self.warn(msg, *args)
|
||||
self.info(
|
||||
"Scanning index of all packages (this may take a while)"
|
||||
)
|
||||
self.scan_url(self.index_url)
|
||||
|
||||
def find_packages(self, requirement):
|
||||
self.scan_url(self.index_url + requirement.unsafe_name+'/')
|
||||
self.scan_url(self.index_url + requirement.unsafe_name + '/')
|
||||
|
||||
if not self.package_pages.get(requirement.key):
|
||||
# Fall back to safe version of the name
|
||||
self.scan_url(self.index_url + requirement.project_name+'/')
|
||||
self.scan_url(self.index_url + requirement.project_name + '/')
|
||||
|
||||
if not self.package_pages.get(requirement.key):
|
||||
# We couldn't find the target package, so search the index page too
|
||||
self.not_found_in_index(requirement)
|
||||
|
||||
for url in list(self.package_pages.get(requirement.key,())):
|
||||
for url in list(self.package_pages.get(requirement.key, ())):
|
||||
# scan each page that might be related to the desired package
|
||||
self.scan_url(url)
|
||||
|
||||
|
|
@ -459,7 +494,7 @@ class PackageIndex(Environment):
|
|||
if dist in requirement:
|
||||
return dist
|
||||
self.debug("%s does not match %s", requirement, dist)
|
||||
return super(PackageIndex, self).obtain(requirement,installer)
|
||||
return super(PackageIndex, self).obtain(requirement, installer)
|
||||
|
||||
def check_hash(self, checker, filename, tfp):
|
||||
"""
|
||||
|
|
@ -480,10 +515,10 @@ class PackageIndex(Environment):
|
|||
"""Add `urls` to the list that will be prescanned for searches"""
|
||||
for url in urls:
|
||||
if (
|
||||
self.to_scan is None # if we have already "gone online"
|
||||
or not URL_SCHEME(url) # or it's a local file/directory
|
||||
self.to_scan is None # if we have already "gone online"
|
||||
or not URL_SCHEME(url) # or it's a local file/directory
|
||||
or url.startswith('file:')
|
||||
or list(distros_for_url(url)) # or a direct package link
|
||||
or list(distros_for_url(url)) # or a direct package link
|
||||
):
|
||||
# then go ahead and process it now
|
||||
self.scan_url(url)
|
||||
|
|
@ -495,12 +530,12 @@ class PackageIndex(Environment):
|
|||
"""Scan urls scheduled for prescanning (e.g. --find-links)"""
|
||||
if self.to_scan:
|
||||
list(map(self.scan_url, self.to_scan))
|
||||
self.to_scan = None # from now on, go ahead and process immediately
|
||||
self.to_scan = None # from now on, go ahead and process immediately
|
||||
|
||||
def not_found_in_index(self, requirement):
|
||||
if self[requirement.key]: # we've seen at least one distro
|
||||
if self[requirement.key]: # we've seen at least one distro
|
||||
meth, msg = self.info, "Couldn't retrieve index page for %r"
|
||||
else: # no distros seen for this name, might be misspelled
|
||||
else: # no distros seen for this name, might be misspelled
|
||||
meth, msg = (self.warn,
|
||||
"Couldn't find index page for %r (maybe misspelled?)")
|
||||
meth(msg, requirement.unsafe_name)
|
||||
|
|
@ -524,27 +559,21 @@ class PackageIndex(Environment):
|
|||
of `tmpdir`, and the local filename is returned. Various errors may be
|
||||
raised if a problem occurs during downloading.
|
||||
"""
|
||||
if not isinstance(spec,Requirement):
|
||||
if not isinstance(spec, Requirement):
|
||||
scheme = URL_SCHEME(spec)
|
||||
if scheme:
|
||||
# It's a url, download it to tmpdir
|
||||
found = self._download_url(scheme.group(1), spec, tmpdir)
|
||||
base, fragment = egg_info_for_url(spec)
|
||||
if base.endswith('.py'):
|
||||
found = self.gen_setup(found,fragment,tmpdir)
|
||||
found = self.gen_setup(found, fragment, tmpdir)
|
||||
return found
|
||||
elif os.path.exists(spec):
|
||||
# Existing file or directory, just return it
|
||||
return spec
|
||||
else:
|
||||
try:
|
||||
spec = Requirement.parse(spec)
|
||||
except ValueError:
|
||||
raise DistutilsError(
|
||||
"Not a URL, existing file, or requirement spec: %r" %
|
||||
(spec,)
|
||||
)
|
||||
return getattr(self.fetch_distribution(spec, tmpdir),'location',None)
|
||||
spec = parse_requirement_arg(spec)
|
||||
return getattr(self.fetch_distribution(spec, tmpdir), 'location', None)
|
||||
|
||||
def fetch_distribution(
|
||||
self, requirement, tmpdir, force_scan=False, source=False,
|
||||
|
|
@ -578,22 +607,24 @@ class PackageIndex(Environment):
|
|||
|
||||
for dist in env[req.key]:
|
||||
|
||||
if dist.precedence==DEVELOP_DIST and not develop_ok:
|
||||
if dist.precedence == DEVELOP_DIST and not develop_ok:
|
||||
if dist not in skipped:
|
||||
self.warn("Skipping development or system egg: %s",dist)
|
||||
self.warn("Skipping development or system egg: %s", dist)
|
||||
skipped[dist] = 1
|
||||
continue
|
||||
|
||||
if dist in req and (dist.precedence<=SOURCE_DIST or not source):
|
||||
return dist
|
||||
if dist in req and (dist.precedence <= SOURCE_DIST or not source):
|
||||
dist.download_location = self.download(dist.location, tmpdir)
|
||||
if os.path.exists(dist.download_location):
|
||||
return dist
|
||||
|
||||
if force_scan:
|
||||
self.prescan()
|
||||
self.find_packages(requirement)
|
||||
dist = find(requirement)
|
||||
|
||||
if local_index is not None:
|
||||
dist = dist or find(requirement, local_index)
|
||||
if not dist and local_index is not None:
|
||||
dist = find(requirement, local_index)
|
||||
|
||||
if dist is None:
|
||||
if self.to_scan is not None:
|
||||
|
|
@ -606,13 +637,13 @@ class PackageIndex(Environment):
|
|||
|
||||
if dist is None:
|
||||
self.warn(
|
||||
"No local packages or download links found for %s%s",
|
||||
"No local packages or working download links found for %s%s",
|
||||
(source and "a source distribution of " or ""),
|
||||
requirement,
|
||||
)
|
||||
else:
|
||||
self.info("Best match: %s", dist)
|
||||
return dist.clone(location=self.download(dist.location, tmpdir))
|
||||
return dist.clone(location=dist.download_location)
|
||||
|
||||
def fetch(self, requirement, tmpdir, force_scan=False, source=False):
|
||||
"""Obtain a file suitable for fulfilling `requirement`
|
||||
|
|
@ -622,7 +653,7 @@ class PackageIndex(Environment):
|
|||
``location`` of the downloaded distribution instead of a distribution
|
||||
object.
|
||||
"""
|
||||
dist = self.fetch_distribution(requirement,tmpdir,force_scan,source)
|
||||
dist = self.fetch_distribution(requirement, tmpdir, force_scan, source)
|
||||
if dist is not None:
|
||||
return dist.location
|
||||
return None
|
||||
|
|
@ -634,7 +665,7 @@ class PackageIndex(Environment):
|
|||
interpret_distro_name(filename, match.group(1), None) if d.version
|
||||
] or []
|
||||
|
||||
if len(dists)==1: # unambiguous ``#egg`` fragment
|
||||
if len(dists) == 1: # unambiguous ``#egg`` fragment
|
||||
basename = os.path.basename(filename)
|
||||
|
||||
# Make sure the file has been downloaded to the temp dir.
|
||||
|
|
@ -643,7 +674,7 @@ class PackageIndex(Environment):
|
|||
from setuptools.command.easy_install import samefile
|
||||
if not samefile(filename, dst):
|
||||
shutil.copy2(filename, dst)
|
||||
filename=dst
|
||||
filename = dst
|
||||
|
||||
with open(os.path.join(tmpdir, 'setup.py'), 'w') as file:
|
||||
file.write(
|
||||
|
|
@ -660,7 +691,7 @@ class PackageIndex(Environment):
|
|||
raise DistutilsError(
|
||||
"Can't unambiguously interpret project/version identifier %r; "
|
||||
"any dashes in the name or version should be escaped using "
|
||||
"underscores. %r" % (fragment,dists)
|
||||
"underscores. %r" % (fragment, dists)
|
||||
)
|
||||
else:
|
||||
raise DistutilsError(
|
||||
|
|
@ -669,6 +700,7 @@ class PackageIndex(Environment):
|
|||
)
|
||||
|
||||
dl_blocksize = 8192
|
||||
|
||||
def _download_to(self, url, filename):
|
||||
self.info("Downloading %s", url)
|
||||
# Download the file
|
||||
|
|
@ -678,7 +710,7 @@ class PackageIndex(Environment):
|
|||
fp = self.open_url(strip_fragment(url))
|
||||
if isinstance(fp, urllib.error.HTTPError):
|
||||
raise DistutilsError(
|
||||
"Can't download %s: %s %s" % (url, fp.code,fp.msg)
|
||||
"Can't download %s: %s %s" % (url, fp.code, fp.msg)
|
||||
)
|
||||
headers = fp.info()
|
||||
blocknum = 0
|
||||
|
|
@ -689,7 +721,7 @@ class PackageIndex(Environment):
|
|||
sizes = get_all_headers(headers, 'Content-Length')
|
||||
size = max(map(int, sizes))
|
||||
self.reporthook(url, filename, blocknum, bs, size)
|
||||
with open(filename,'wb') as tfp:
|
||||
with open(filename, 'wb') as tfp:
|
||||
while True:
|
||||
block = fp.read(bs)
|
||||
if block:
|
||||
|
|
@ -702,10 +734,11 @@ class PackageIndex(Environment):
|
|||
self.check_hash(checker, filename, tfp)
|
||||
return headers
|
||||
finally:
|
||||
if fp: fp.close()
|
||||
if fp:
|
||||
fp.close()
|
||||
|
||||
def reporthook(self, url, filename, blocknum, blksize, size):
|
||||
pass # no-op
|
||||
pass # no-op
|
||||
|
||||
def open_url(self, url, warning=None):
|
||||
if url.startswith('file:'):
|
||||
|
|
@ -735,7 +768,7 @@ class PackageIndex(Environment):
|
|||
'down, %s' %
|
||||
(url, v.line)
|
||||
)
|
||||
except http_client.HTTPException as v:
|
||||
except (http_client.HTTPException, socket.error) as v:
|
||||
if warning:
|
||||
self.warn(warning, v)
|
||||
else:
|
||||
|
|
@ -748,27 +781,27 @@ class PackageIndex(Environment):
|
|||
name, fragment = egg_info_for_url(url)
|
||||
if name:
|
||||
while '..' in name:
|
||||
name = name.replace('..','.').replace('\\','_')
|
||||
name = name.replace('..', '.').replace('\\', '_')
|
||||
else:
|
||||
name = "__downloaded__" # default if URL has no path contents
|
||||
name = "__downloaded__" # default if URL has no path contents
|
||||
|
||||
if name.endswith('.egg.zip'):
|
||||
name = name[:-4] # strip the extra .zip before download
|
||||
name = name[:-4] # strip the extra .zip before download
|
||||
|
||||
filename = os.path.join(tmpdir,name)
|
||||
filename = os.path.join(tmpdir, name)
|
||||
|
||||
# Download the file
|
||||
#
|
||||
if scheme=='svn' or scheme.startswith('svn+'):
|
||||
if scheme == 'svn' or scheme.startswith('svn+'):
|
||||
return self._download_svn(url, filename)
|
||||
elif scheme=='git' or scheme.startswith('git+'):
|
||||
elif scheme == 'git' or scheme.startswith('git+'):
|
||||
return self._download_git(url, filename)
|
||||
elif scheme.startswith('hg+'):
|
||||
return self._download_hg(url, filename)
|
||||
elif scheme=='file':
|
||||
elif scheme == 'file':
|
||||
return urllib.request.url2pathname(urllib.parse.urlparse(url)[2])
|
||||
else:
|
||||
self.url_ok(url, True) # raises error if not allowed
|
||||
self.url_ok(url, True) # raises error if not allowed
|
||||
return self._attempt_download(url, filename)
|
||||
|
||||
def scan_url(self, url):
|
||||
|
|
@ -776,7 +809,7 @@ class PackageIndex(Environment):
|
|||
|
||||
def _attempt_download(self, url, filename):
|
||||
headers = self._download_to(url, filename)
|
||||
if 'html' in headers.get('content-type','').lower():
|
||||
if 'html' in headers.get('content-type', '').lower():
|
||||
return self._download_html(url, headers, filename)
|
||||
else:
|
||||
return filename
|
||||
|
|
@ -791,25 +824,25 @@ class PackageIndex(Environment):
|
|||
file.close()
|
||||
os.unlink(filename)
|
||||
return self._download_svn(url, filename)
|
||||
break # not an index page
|
||||
break # not an index page
|
||||
file.close()
|
||||
os.unlink(filename)
|
||||
raise DistutilsError("Unexpected HTML page found at "+url)
|
||||
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
|
||||
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 = urllib.parse.urlparse(url)
|
||||
if not netloc and path.startswith('//') and '/' in path[2:]:
|
||||
netloc, path = path[2:].split('/',1)
|
||||
netloc, path = path[2:].split('/', 1)
|
||||
auth, host = splituser(netloc)
|
||||
if auth:
|
||||
if ':' in auth:
|
||||
user, pw = auth.split(':',1)
|
||||
user, pw = auth.split(':', 1)
|
||||
creds = " --username=%s --password=%s" % (user, pw)
|
||||
else:
|
||||
creds = " --username="+auth
|
||||
creds = " --username=" + auth
|
||||
netloc = host
|
||||
parts = scheme, netloc, url, p, q, f
|
||||
url = urllib.parse.urlunparse(parts)
|
||||
|
|
@ -824,7 +857,7 @@ class PackageIndex(Environment):
|
|||
scheme = scheme.split('+', 1)[-1]
|
||||
|
||||
# Some fragment identification fails
|
||||
path = path.split('#',1)[0]
|
||||
path = path.split('#', 1)[0]
|
||||
|
||||
rev = None
|
||||
if '@' in path:
|
||||
|
|
@ -836,7 +869,7 @@ class PackageIndex(Environment):
|
|||
return url, rev
|
||||
|
||||
def _download_git(self, url, filename):
|
||||
filename = filename.split('#',1)[0]
|
||||
filename = filename.split('#', 1)[0]
|
||||
url, rev = self._vcs_split_rev_from_url(url, pop_prefix=True)
|
||||
|
||||
self.info("Doing git clone from %s to %s", url, filename)
|
||||
|
|
@ -852,7 +885,7 @@ class PackageIndex(Environment):
|
|||
return filename
|
||||
|
||||
def _download_hg(self, url, filename):
|
||||
filename = filename.split('#',1)[0]
|
||||
filename = filename.split('#', 1)[0]
|
||||
url, rev = self._vcs_split_rev_from_url(url, pop_prefix=True)
|
||||
|
||||
self.info("Doing hg clone from %s to %s", url, filename)
|
||||
|
|
@ -860,7 +893,7 @@ class PackageIndex(Environment):
|
|||
|
||||
if rev is not None:
|
||||
self.info("Updating to %s", rev)
|
||||
os.system("(cd %s && hg up -C -r %s >&-)" % (
|
||||
os.system("(cd %s && hg up -C -r %s -q)" % (
|
||||
filename,
|
||||
rev,
|
||||
))
|
||||
|
|
@ -876,16 +909,20 @@ 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
|
||||
|
||||
|
||||
def uchr(c):
|
||||
if not isinstance(c, int):
|
||||
return c
|
||||
if c>255: return six.unichr(c)
|
||||
if c > 255:
|
||||
return six.unichr(c)
|
||||
return chr(c)
|
||||
|
||||
|
||||
def decode_entity(match):
|
||||
what = match.group(1)
|
||||
if what.startswith('#x'):
|
||||
|
|
@ -896,10 +933,12 @@ def decode_entity(match):
|
|||
what = six.moves.html_entities.name2codepoint.get(what, match.group(0))
|
||||
return uchr(what)
|
||||
|
||||
|
||||
def htmldecode(text):
|
||||
"""Decode HTML entities in the given text."""
|
||||
return entity_sub(decode_entity, text)
|
||||
|
||||
|
||||
def socket_timeout(timeout=15):
|
||||
def _socket_timeout(func):
|
||||
def _socket_timeout(*args, **kwargs):
|
||||
|
|
@ -909,9 +948,12 @@ def socket_timeout(timeout=15):
|
|||
return func(*args, **kwargs)
|
||||
finally:
|
||||
socket.setdefaulttimeout(old_timeout)
|
||||
|
||||
return _socket_timeout
|
||||
|
||||
return _socket_timeout
|
||||
|
||||
|
||||
def _encode_auth(auth):
|
||||
"""
|
||||
A function compatible with Python 2.3-3.3 that will encode
|
||||
|
|
@ -932,12 +974,14 @@ def _encode_auth(auth):
|
|||
# convert back to a string
|
||||
encoded = encoded_bytes.decode()
|
||||
# strip the trailing carriage return
|
||||
return encoded.replace('\n','')
|
||||
return encoded.replace('\n', '')
|
||||
|
||||
|
||||
class Credential(object):
|
||||
"""
|
||||
A username/password pair. Use like a namedtuple.
|
||||
"""
|
||||
|
||||
def __init__(self, username, password):
|
||||
self.username = username
|
||||
self.password = password
|
||||
|
|
@ -949,8 +993,8 @@ class Credential(object):
|
|||
def __str__(self):
|
||||
return '%(username)s:%(password)s' % vars(self)
|
||||
|
||||
class PyPIConfig(configparser.RawConfigParser):
|
||||
|
||||
class PyPIConfig(configparser.RawConfigParser):
|
||||
def __init__(self):
|
||||
"""
|
||||
Load from ~/.pypirc
|
||||
|
|
@ -1008,7 +1052,7 @@ def open_with_auth(url, opener=urllib.request.urlopen):
|
|||
if cred:
|
||||
auth = str(cred)
|
||||
info = cred.username, url
|
||||
log.info('Authenticating as %s for %s (from .pypirc)' % info)
|
||||
log.info('Authenticating as %s for %s (from .pypirc)', *info)
|
||||
|
||||
if auth:
|
||||
auth = "Basic " + _encode_auth(auth)
|
||||
|
|
@ -1026,18 +1070,20 @@ def open_with_auth(url, opener=urllib.request.urlopen):
|
|||
# Put authentication info back into request URL if same host,
|
||||
# so that links found on the page will work
|
||||
s2, h2, path2, param2, query2, frag2 = urllib.parse.urlparse(fp.url)
|
||||
if s2==scheme and h2==host:
|
||||
if s2 == scheme and h2 == host:
|
||||
parts = s2, netloc, path2, param2, query2, frag2
|
||||
fp.url = urllib.parse.urlunparse(parts)
|
||||
|
||||
return fp
|
||||
|
||||
|
||||
# adding a timeout to avoid freezing package_index
|
||||
open_with_auth = socket_timeout(_SOCKET_TIMEOUT)(open_with_auth)
|
||||
|
||||
|
||||
def fix_sf_url(url):
|
||||
return url # backward compatibility
|
||||
return url # backward compatibility
|
||||
|
||||
|
||||
def local_open(url):
|
||||
"""Read a local path, with special support for directories"""
|
||||
|
|
|
|||
|
|
@ -5,18 +5,27 @@ Compatibility Support for Python 2.6 and earlier
|
|||
import sys
|
||||
|
||||
try:
|
||||
from urllib.parse import splittag
|
||||
from urllib.parse import splittag
|
||||
except ImportError:
|
||||
from urllib import splittag
|
||||
from urllib import splittag
|
||||
|
||||
|
||||
def strip_fragment(url):
|
||||
"""
|
||||
In `Python 8280 <http://bugs.python.org/issue8280>`_, Python 2.7 and
|
||||
later was patched to disregard the fragment when making URL requests.
|
||||
Do the same for Python 2.6 and earlier.
|
||||
"""
|
||||
url, fragment = splittag(url)
|
||||
return url
|
||||
"""
|
||||
In `Python 8280 <http://bugs.python.org/issue8280>`_, Python 2.7 and
|
||||
later was patched to disregard the fragment when making URL requests.
|
||||
Do the same for Python 2.6 and earlier.
|
||||
"""
|
||||
url, fragment = splittag(url)
|
||||
return url
|
||||
|
||||
if sys.version_info >= (2,7):
|
||||
strip_fragment = lambda x: x
|
||||
|
||||
if sys.version_info >= (2, 7):
|
||||
strip_fragment = lambda x: x
|
||||
|
||||
try:
|
||||
from importlib import import_module
|
||||
except ImportError:
|
||||
|
||||
def import_module(module_name):
|
||||
return __import__(module_name, fromlist=['__name__'])
|
||||
|
|
|
|||
|
|
@ -2,14 +2,27 @@
|
|||
Compatibility Support for Python 2.7 and earlier
|
||||
"""
|
||||
|
||||
import sys
|
||||
import platform
|
||||
|
||||
from setuptools.extern import six
|
||||
|
||||
|
||||
def get_all_headers(message, key):
|
||||
"""
|
||||
Given an HTTPMessage, return all headers matching a given key.
|
||||
"""
|
||||
return message.get_all(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)
|
||||
|
||||
if six.PY2:
|
||||
def get_all_headers(message, key):
|
||||
return message.getheaders(key)
|
||||
|
||||
|
||||
linux_py2_ascii = (
|
||||
platform.system() == 'Linux' and
|
||||
six.PY2
|
||||
)
|
||||
|
||||
rmtree_safe = str if linux_py2_ascii else lambda x: x
|
||||
"""Workaround for http://bugs.python.org/issue24672"""
|
||||
|
|
|
|||
|
|
@ -8,10 +8,12 @@ try:
|
|||
from sysconfig import get_config_vars, get_path
|
||||
except ImportError:
|
||||
from distutils.sysconfig import get_config_vars, get_python_lib
|
||||
|
||||
def get_path(name):
|
||||
if name not in ('platlib', 'purelib'):
|
||||
raise ValueError("Name must be purelib or platlib")
|
||||
return get_python_lib(name=='platlib')
|
||||
return get_python_lib(name == 'platlib')
|
||||
|
||||
|
||||
try:
|
||||
# Python >=3.2
|
||||
|
|
@ -19,14 +21,16 @@ try:
|
|||
except ImportError:
|
||||
import shutil
|
||||
import tempfile
|
||||
|
||||
class TemporaryDirectory(object):
|
||||
"""
|
||||
Very simple temporary directory context manager.
|
||||
Will try to delete afterward, but will also ignore OS and similar
|
||||
errors on deletion.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.name = None # Handle mkdtemp raising an exception
|
||||
self.name = None # Handle mkdtemp raising an exception
|
||||
self.name = tempfile.mkdtemp()
|
||||
|
||||
def __enter__(self):
|
||||
|
|
@ -35,7 +39,7 @@ except ImportError:
|
|||
def __exit__(self, exctype, excvalue, exctrace):
|
||||
try:
|
||||
shutil.rmtree(self.name, True)
|
||||
except OSError: #removal errors are not the only possible
|
||||
except OSError: # removal errors are not the only possible
|
||||
pass
|
||||
self.name = None
|
||||
|
||||
|
|
|
|||
45
lib/python3.4/site-packages/setuptools/py33compat.py
Normal file
45
lib/python3.4/site-packages/setuptools/py33compat.py
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
import dis
|
||||
import array
|
||||
import collections
|
||||
|
||||
from setuptools.extern import six
|
||||
|
||||
|
||||
OpArg = collections.namedtuple('OpArg', 'opcode arg')
|
||||
|
||||
|
||||
class Bytecode_compat(object):
|
||||
def __init__(self, code):
|
||||
self.code = code
|
||||
|
||||
def __iter__(self):
|
||||
"""Yield '(op,arg)' pair for each operation in code object 'code'"""
|
||||
|
||||
bytes = array.array('b', self.code.co_code)
|
||||
eof = len(self.code.co_code)
|
||||
|
||||
ptr = 0
|
||||
extended_arg = 0
|
||||
|
||||
while ptr < eof:
|
||||
|
||||
op = bytes[ptr]
|
||||
|
||||
if op >= dis.HAVE_ARGUMENT:
|
||||
|
||||
arg = bytes[ptr + 1] + bytes[ptr + 2] * 256 + extended_arg
|
||||
ptr += 3
|
||||
|
||||
if op == dis.EXTENDED_ARG:
|
||||
long_type = six.integer_types[-1]
|
||||
extended_arg = arg * long_type(65536)
|
||||
continue
|
||||
|
||||
else:
|
||||
arg = None
|
||||
ptr += 1
|
||||
|
||||
yield OpArg(op, arg)
|
||||
|
||||
|
||||
Bytecode = getattr(dis, 'Bytecode', Bytecode_compat)
|
||||
82
lib/python3.4/site-packages/setuptools/py36compat.py
Normal file
82
lib/python3.4/site-packages/setuptools/py36compat.py
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
import sys
|
||||
from distutils.errors import DistutilsOptionError
|
||||
from distutils.util import strtobool
|
||||
from distutils.debug import DEBUG
|
||||
|
||||
|
||||
class Distribution_parse_config_files:
|
||||
"""
|
||||
Mix-in providing forward-compatibility for functionality to be
|
||||
included by default on Python 3.7.
|
||||
|
||||
Do not edit the code in this class except to update functionality
|
||||
as implemented in distutils.
|
||||
"""
|
||||
def parse_config_files(self, filenames=None):
|
||||
from configparser import ConfigParser
|
||||
|
||||
# Ignore install directory options if we have a venv
|
||||
if sys.prefix != sys.base_prefix:
|
||||
ignore_options = [
|
||||
'install-base', 'install-platbase', 'install-lib',
|
||||
'install-platlib', 'install-purelib', 'install-headers',
|
||||
'install-scripts', 'install-data', 'prefix', 'exec-prefix',
|
||||
'home', 'user', 'root']
|
||||
else:
|
||||
ignore_options = []
|
||||
|
||||
ignore_options = frozenset(ignore_options)
|
||||
|
||||
if filenames is None:
|
||||
filenames = self.find_config_files()
|
||||
|
||||
if DEBUG:
|
||||
self.announce("Distribution.parse_config_files():")
|
||||
|
||||
parser = ConfigParser(interpolation=None)
|
||||
for filename in filenames:
|
||||
if DEBUG:
|
||||
self.announce(" reading %s" % filename)
|
||||
parser.read(filename)
|
||||
for section in parser.sections():
|
||||
options = parser.options(section)
|
||||
opt_dict = self.get_option_dict(section)
|
||||
|
||||
for opt in options:
|
||||
if opt != '__name__' and opt not in ignore_options:
|
||||
val = parser.get(section,opt)
|
||||
opt = opt.replace('-', '_')
|
||||
opt_dict[opt] = (filename, val)
|
||||
|
||||
# Make the ConfigParser forget everything (so we retain
|
||||
# the original filenames that options come from)
|
||||
parser.__init__()
|
||||
|
||||
# If there was a "global" section in the config file, use it
|
||||
# to set Distribution options.
|
||||
|
||||
if 'global' in self.command_options:
|
||||
for (opt, (src, val)) in self.command_options['global'].items():
|
||||
alias = self.negative_opt.get(opt)
|
||||
try:
|
||||
if alias:
|
||||
setattr(self, alias, not strtobool(val))
|
||||
elif opt in ('verbose', 'dry_run'): # ugh!
|
||||
setattr(self, opt, strtobool(val))
|
||||
else:
|
||||
setattr(self, opt, val)
|
||||
except ValueError as msg:
|
||||
raise DistutilsOptionError(msg)
|
||||
|
||||
|
||||
if sys.version_info < (3,):
|
||||
# Python 2 behavior is sufficient
|
||||
class Distribution_parse_config_files:
|
||||
pass
|
||||
|
||||
|
||||
if False:
|
||||
# When updated behavior is available upstream,
|
||||
# disable override here.
|
||||
class Distribution_parse_config_files:
|
||||
pass
|
||||
|
|
@ -7,11 +7,12 @@ import itertools
|
|||
import re
|
||||
import contextlib
|
||||
import pickle
|
||||
import textwrap
|
||||
|
||||
from setuptools.extern import six
|
||||
from setuptools.extern.six.moves import builtins, map
|
||||
|
||||
import pkg_resources
|
||||
import pkg_resources.py31compat
|
||||
|
||||
if sys.platform.startswith('java'):
|
||||
import org.python.modules.posix.PosixModule as _os
|
||||
|
|
@ -25,10 +26,12 @@ _open = open
|
|||
from distutils.errors import DistutilsError
|
||||
from pkg_resources import working_set
|
||||
|
||||
|
||||
__all__ = [
|
||||
"AbstractSandbox", "DirectorySandbox", "SandboxViolation", "run_setup",
|
||||
]
|
||||
|
||||
|
||||
def _execfile(filename, globals, locals=None):
|
||||
"""
|
||||
Python 3 implementation of execfile.
|
||||
|
|
@ -71,8 +74,7 @@ def override_temp(replacement):
|
|||
"""
|
||||
Monkey-patch tempfile.tempdir with replacement, ensuring it exists
|
||||
"""
|
||||
if not os.path.isdir(replacement):
|
||||
os.makedirs(replacement)
|
||||
pkg_resources.py31compat.makedirs(replacement, exist_ok=True)
|
||||
|
||||
saved = tempfile.tempdir
|
||||
|
||||
|
|
@ -98,6 +100,7 @@ class UnpickleableException(Exception):
|
|||
"""
|
||||
An exception representing another Exception that could not be pickled.
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def dump(type, exc):
|
||||
"""
|
||||
|
|
@ -117,6 +120,7 @@ class ExceptionSaver:
|
|||
A Context Manager that will save an exception, serialized, and restore it
|
||||
later.
|
||||
"""
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
|
|
@ -212,7 +216,7 @@ def _needs_hiding(mod_name):
|
|||
>>> _needs_hiding('Cython')
|
||||
True
|
||||
"""
|
||||
pattern = re.compile('(setuptools|pkg_resources|distutils|Cython)(\.|$)')
|
||||
pattern = re.compile(r'(setuptools|pkg_resources|distutils|Cython)(\.|$)')
|
||||
return bool(pattern.match(mod_name))
|
||||
|
||||
|
||||
|
|
@ -232,15 +236,22 @@ def run_setup(setup_script, args):
|
|||
setup_dir = os.path.abspath(os.path.dirname(setup_script))
|
||||
with setup_context(setup_dir):
|
||||
try:
|
||||
sys.argv[:] = [setup_script]+list(args)
|
||||
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())
|
||||
def runner():
|
||||
ns = dict(__file__=setup_script, __name__='__main__')
|
||||
working_set.callbacks.append(lambda dist: dist.activate())
|
||||
|
||||
# __file__ should be a byte string on Python 2 (#712)
|
||||
dunder_file = (
|
||||
setup_script
|
||||
if isinstance(setup_script, str) else
|
||||
setup_script.encode(sys.getfilesystemencoding())
|
||||
)
|
||||
|
||||
with DirectorySandbox(setup_dir):
|
||||
ns = dict(__file__=dunder_file, __name__='__main__')
|
||||
_execfile(setup_script, ns)
|
||||
DirectorySandbox(setup_dir).run(runner)
|
||||
except SystemExit as v:
|
||||
if v.args and v.args[0]:
|
||||
raise
|
||||
|
|
@ -255,46 +266,54 @@ class AbstractSandbox:
|
|||
def __init__(self):
|
||||
self._attrs = [
|
||||
name for name in dir(_os)
|
||||
if not name.startswith('_') and hasattr(self,name)
|
||||
if not name.startswith('_') and hasattr(self, name)
|
||||
]
|
||||
|
||||
def _copy(self, source):
|
||||
for name in self._attrs:
|
||||
setattr(os, name, getattr(source,name))
|
||||
setattr(os, name, getattr(source, name))
|
||||
|
||||
def __enter__(self):
|
||||
self._copy(self)
|
||||
if _file:
|
||||
builtins.file = self._file
|
||||
builtins.open = self._open
|
||||
self._active = True
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
self._active = False
|
||||
if _file:
|
||||
builtins.file = _file
|
||||
builtins.open = _open
|
||||
self._copy(_os)
|
||||
|
||||
def run(self, func):
|
||||
"""Run 'func' under os sandboxing"""
|
||||
try:
|
||||
self._copy(self)
|
||||
if _file:
|
||||
builtins.file = self._file
|
||||
builtins.open = self._open
|
||||
self._active = True
|
||||
with self:
|
||||
return func()
|
||||
finally:
|
||||
self._active = False
|
||||
if _file:
|
||||
builtins.file = _file
|
||||
builtins.open = _open
|
||||
self._copy(_os)
|
||||
|
||||
def _mk_dual_path_wrapper(name):
|
||||
original = getattr(_os,name)
|
||||
def wrap(self,src,dst,*args,**kw):
|
||||
original = getattr(_os, name)
|
||||
|
||||
def wrap(self, src, dst, *args, **kw):
|
||||
if self._active:
|
||||
src,dst = self._remap_pair(name,src,dst,*args,**kw)
|
||||
return original(src,dst,*args,**kw)
|
||||
src, dst = self._remap_pair(name, src, dst, *args, **kw)
|
||||
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)
|
||||
if hasattr(_os, name):
|
||||
locals()[name] = _mk_dual_path_wrapper(name)
|
||||
|
||||
def _mk_single_path_wrapper(name, original=None):
|
||||
original = original or getattr(_os,name)
|
||||
def wrap(self,path,*args,**kw):
|
||||
original = original or getattr(_os, name)
|
||||
|
||||
def wrap(self, path, *args, **kw):
|
||||
if self._active:
|
||||
path = self._remap_input(name,path,*args,**kw)
|
||||
return original(path,*args,**kw)
|
||||
path = self._remap_input(name, path, *args, **kw)
|
||||
return original(path, *args, **kw)
|
||||
|
||||
return wrap
|
||||
|
||||
if _file:
|
||||
|
|
@ -305,49 +324,56 @@ class AbstractSandbox:
|
|||
"remove", "unlink", "rmdir", "utime", "lchown", "chroot", "lstat",
|
||||
"startfile", "mkfifo", "mknod", "pathconf", "access"
|
||||
]:
|
||||
if hasattr(_os,name): locals()[name] = _mk_single_path_wrapper(name)
|
||||
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):
|
||||
original = getattr(_os, name)
|
||||
|
||||
def wrap(self, path, *args, **kw):
|
||||
if self._active:
|
||||
path = self._remap_input(name,path,*args,**kw)
|
||||
return self._remap_output(name, original(path,*args,**kw))
|
||||
return original(path,*args,**kw)
|
||||
path = self._remap_input(name, path, *args, **kw)
|
||||
return self._remap_output(name, original(path, *args, **kw))
|
||||
return original(path, *args, **kw)
|
||||
|
||||
return wrap
|
||||
|
||||
for name in ['readlink', 'tempnam']:
|
||||
if hasattr(_os,name): locals()[name] = _mk_single_with_return(name)
|
||||
if hasattr(_os, name):
|
||||
locals()[name] = _mk_single_with_return(name)
|
||||
|
||||
def _mk_query(name):
|
||||
original = getattr(_os,name)
|
||||
def wrap(self,*args,**kw):
|
||||
retval = original(*args,**kw)
|
||||
original = getattr(_os, name)
|
||||
|
||||
def wrap(self, *args, **kw):
|
||||
retval = original(*args, **kw)
|
||||
if self._active:
|
||||
return self._remap_output(name, retval)
|
||||
return retval
|
||||
|
||||
return wrap
|
||||
|
||||
for name in ['getcwd', 'tmpnam']:
|
||||
if hasattr(_os,name): locals()[name] = _mk_query(name)
|
||||
if hasattr(_os, name):
|
||||
locals()[name] = _mk_query(name)
|
||||
|
||||
def _validate_path(self,path):
|
||||
def _validate_path(self, path):
|
||||
"""Called to remap or validate any path, whether input or output"""
|
||||
return path
|
||||
|
||||
def _remap_input(self,operation,path,*args,**kw):
|
||||
def _remap_input(self, operation, path, *args, **kw):
|
||||
"""Called for path inputs"""
|
||||
return self._validate_path(path)
|
||||
|
||||
def _remap_output(self,operation,path):
|
||||
def _remap_output(self, operation, path):
|
||||
"""Called for path outputs"""
|
||||
return self._validate_path(path)
|
||||
|
||||
def _remap_pair(self,operation,src,dst,*args,**kw):
|
||||
def _remap_pair(self, operation, src, dst, *args, **kw):
|
||||
"""Called for path pairs like rename, link, and symlink operations"""
|
||||
return (
|
||||
self._remap_input(operation+'-from',src,*args,**kw),
|
||||
self._remap_input(operation+'-to',dst,*args,**kw)
|
||||
self._remap_input(operation + '-from', src, *args, **kw),
|
||||
self._remap_input(operation + '-to', dst, *args, **kw)
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -356,13 +382,6 @@ if hasattr(os, 'devnull'):
|
|||
else:
|
||||
_EXCEPTIONS = []
|
||||
|
||||
try:
|
||||
from win32com.client.gencache import GetGeneratePath
|
||||
_EXCEPTIONS.append(GetGeneratePath())
|
||||
del GetGeneratePath
|
||||
except ImportError:
|
||||
# it appears pywin32 is not installed, so no need to exclude.
|
||||
pass
|
||||
|
||||
class DirectorySandbox(AbstractSandbox):
|
||||
"""Restrict operations to a single subdirectory - pseudo-chroot"""
|
||||
|
|
@ -374,13 +393,13 @@ class DirectorySandbox(AbstractSandbox):
|
|||
|
||||
_exception_patterns = [
|
||||
# Allow lib2to3 to attempt to save a pickled grammar object (#121)
|
||||
'.*lib2to3.*\.pickle$',
|
||||
r'.*lib2to3.*\.pickle$',
|
||||
]
|
||||
"exempt writing to paths that match the pattern"
|
||||
|
||||
def __init__(self, sandbox, exceptions=_EXCEPTIONS):
|
||||
self._sandbox = os.path.normcase(os.path.realpath(sandbox))
|
||||
self._prefix = os.path.join(self._sandbox,'')
|
||||
self._prefix = os.path.join(self._sandbox, '')
|
||||
self._exceptions = [
|
||||
os.path.normcase(os.path.realpath(path))
|
||||
for path in exceptions
|
||||
|
|
@ -392,15 +411,16 @@ class DirectorySandbox(AbstractSandbox):
|
|||
raise SandboxViolation(operation, args, kw)
|
||||
|
||||
if _file:
|
||||
|
||||
def _file(self, path, mode='r', *args, **kw):
|
||||
if mode not in ('r', 'rt', 'rb', 'rU', 'U') and not self._ok(path):
|
||||
self._violation("file", path, mode, *args, **kw)
|
||||
return _file(path,mode,*args,**kw)
|
||||
return _file(path, mode, *args, **kw)
|
||||
|
||||
def _open(self, path, mode='r', *args, **kw):
|
||||
if mode not in ('r', 'rt', 'rb', 'rU', 'U') and not self._ok(path):
|
||||
self._violation("open", path, mode, *args, **kw)
|
||||
return _open(path,mode,*args,**kw)
|
||||
return _open(path, mode, *args, **kw)
|
||||
|
||||
def tmpnam(self):
|
||||
self._violation("tmpnam")
|
||||
|
|
@ -440,57 +460,36 @@ class DirectorySandbox(AbstractSandbox):
|
|||
"""Called for path pairs like rename, link, and symlink operations"""
|
||||
if not self._ok(src) or not self._ok(dst):
|
||||
self._violation(operation, src, dst, *args, **kw)
|
||||
return (src,dst)
|
||||
return (src, dst)
|
||||
|
||||
def open(self, file, flags, mode=0o777, *args, **kw):
|
||||
"""Called for low-level os.open()"""
|
||||
if flags & WRITE_FLAGS and not self._ok(file):
|
||||
self._violation("os.open", file, flags, mode, *args, **kw)
|
||||
return _os.open(file,flags,mode, *args, **kw)
|
||||
return _os.open(file, flags, mode, *args, **kw)
|
||||
|
||||
|
||||
WRITE_FLAGS = functools.reduce(
|
||||
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"""
|
||||
|
||||
tmpl = textwrap.dedent("""
|
||||
SandboxViolation: {cmd}{args!r} {kwargs}
|
||||
|
||||
The package setup script has attempted to modify files on your system
|
||||
that are not within the EasyInstall build area, and has been aborted.
|
||||
|
||||
This package cannot be safely installed by EasyInstall, and may not
|
||||
support alternate installation locations even if you run its setup
|
||||
script by hand. Please inform the package's author and the EasyInstall
|
||||
maintainers to find out if a fix or workaround is available.
|
||||
""").lstrip()
|
||||
|
||||
def __str__(self):
|
||||
return """SandboxViolation: %s%r %s
|
||||
|
||||
The package setup script has attempted to modify files on your system
|
||||
that are not within the EasyInstall build area, and has been aborted.
|
||||
|
||||
This package cannot be safely installed by EasyInstall, and may not
|
||||
support alternate installation locations even if you run its setup
|
||||
script by hand. Please inform the package's author and the EasyInstall
|
||||
maintainers to find out if a fix or workaround is available.""" % self.args
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
cmd, args, kwargs = self.args
|
||||
return self.tmpl.format(**locals())
|
||||
|
|
|
|||
|
|
@ -2,19 +2,18 @@ def __boot():
|
|||
import sys
|
||||
import os
|
||||
PYTHONPATH = os.environ.get('PYTHONPATH')
|
||||
if PYTHONPATH is None or (sys.platform=='win32' and not PYTHONPATH):
|
||||
if PYTHONPATH is None or (sys.platform == 'win32' and not PYTHONPATH):
|
||||
PYTHONPATH = []
|
||||
else:
|
||||
PYTHONPATH = PYTHONPATH.split(os.pathsep)
|
||||
|
||||
pic = getattr(sys,'path_importer_cache',{})
|
||||
pic = getattr(sys, 'path_importer_cache', {})
|
||||
stdpath = sys.path[len(PYTHONPATH):]
|
||||
mydir = os.path.dirname(__file__)
|
||||
#print "searching",stdpath,sys.path
|
||||
|
||||
for item in stdpath:
|
||||
if item==mydir or not item:
|
||||
continue # skip if current dir. on Windows, or my own directory
|
||||
if item == mydir or not item:
|
||||
continue # skip if current dir. on Windows, or my own directory
|
||||
importer = pic.get(item)
|
||||
if importer is not None:
|
||||
loader = importer.find_module('site')
|
||||
|
|
@ -24,32 +23,30 @@ def __boot():
|
|||
break
|
||||
else:
|
||||
try:
|
||||
import imp # Avoid import loop in Python >= 3.3
|
||||
stream, path, descr = imp.find_module('site',[item])
|
||||
import imp # Avoid import loop in Python >= 3.3
|
||||
stream, path, descr = imp.find_module('site', [item])
|
||||
except ImportError:
|
||||
continue
|
||||
if stream is None:
|
||||
continue
|
||||
try:
|
||||
# This should actually reload the current module
|
||||
imp.load_module('site',stream,path,descr)
|
||||
imp.load_module('site', stream, path, descr)
|
||||
finally:
|
||||
stream.close()
|
||||
break
|
||||
else:
|
||||
raise ImportError("Couldn't find the real 'site' module")
|
||||
|
||||
#print "loaded", __file__
|
||||
known_paths = dict([(makepath(item)[1], 1) for item in sys.path]) # 2.2 comp
|
||||
|
||||
known_paths = dict([(makepath(item)[1],1) for item in sys.path]) # 2.2 comp
|
||||
|
||||
oldpos = getattr(sys,'__egginsert',0) # save old insertion position
|
||||
sys.__egginsert = 0 # and reset the current one
|
||||
oldpos = getattr(sys, '__egginsert', 0) # save old insertion position
|
||||
sys.__egginsert = 0 # and reset the current one
|
||||
|
||||
for item in PYTHONPATH:
|
||||
addsitedir(item)
|
||||
|
||||
sys.__egginsert += oldpos # restore effective old position
|
||||
sys.__egginsert += oldpos # restore effective old position
|
||||
|
||||
d, nd = makepath(stdpath[0])
|
||||
insert_at = None
|
||||
|
|
@ -58,7 +55,7 @@ def __boot():
|
|||
for item in sys.path:
|
||||
p, np = makepath(item)
|
||||
|
||||
if np==nd and insert_at is None:
|
||||
if np == nd and insert_at is None:
|
||||
# We've hit the first 'system' path entry, so added entries go here
|
||||
insert_at = len(new_path)
|
||||
|
||||
|
|
@ -71,6 +68,7 @@ def __boot():
|
|||
|
||||
sys.path[:] = new_path
|
||||
|
||||
if __name__=='site':
|
||||
|
||||
if __name__ == 'site':
|
||||
__boot()
|
||||
del __boot
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@ import os
|
|||
import socket
|
||||
import atexit
|
||||
import re
|
||||
import functools
|
||||
|
||||
from setuptools.extern.six.moves import urllib, http_client, map
|
||||
from setuptools.extern.six.moves import urllib, http_client, map, filter
|
||||
|
||||
import pkg_resources
|
||||
from pkg_resources import ResolutionError, ExtractionError
|
||||
|
||||
try:
|
||||
|
|
@ -26,9 +26,9 @@ cert_paths = """
|
|||
/etc/ssl/cert.pem
|
||||
/System/Library/OpenSSL/certs/cert.pem
|
||||
/usr/local/share/certs/ca-root-nss.crt
|
||||
/etc/ssl/ca-bundle.pem
|
||||
""".strip().split()
|
||||
|
||||
|
||||
try:
|
||||
HTTPSHandler = urllib.request.HTTPSHandler
|
||||
HTTPSConnection = http_client.HTTPSConnection
|
||||
|
|
@ -49,10 +49,13 @@ except ImportError:
|
|||
match_hostname = None
|
||||
|
||||
if not CertificateError:
|
||||
|
||||
class CertificateError(ValueError):
|
||||
pass
|
||||
|
||||
|
||||
if not match_hostname:
|
||||
|
||||
def _dnsname_match(dn, hostname, max_wildcards=1):
|
||||
"""Matching according to RFC 6125, section 6.4.3
|
||||
|
||||
|
|
@ -161,6 +164,7 @@ class VerifyingHTTPSHandler(HTTPSHandler):
|
|||
|
||||
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
|
||||
|
|
@ -192,6 +196,7 @@ class VerifyingHTTPSConn(HTTPSConnection):
|
|||
self.sock.close()
|
||||
raise
|
||||
|
||||
|
||||
def opener_for(ca_bundle=None):
|
||||
"""Get a urlopen() replacement that uses ca_bundle for verification"""
|
||||
return urllib.request.build_opener(
|
||||
|
|
@ -199,45 +204,52 @@ def opener_for(ca_bundle=None):
|
|||
).open
|
||||
|
||||
|
||||
_wincerts = None
|
||||
# from jaraco.functools
|
||||
def once(func):
|
||||
@functools.wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
if not hasattr(func, 'always_returns'):
|
||||
func.always_returns = func(*args, **kwargs)
|
||||
return func.always_returns
|
||||
return wrapper
|
||||
|
||||
|
||||
@once
|
||||
def get_win_certfile():
|
||||
global _wincerts
|
||||
if _wincerts is not None:
|
||||
return _wincerts.name
|
||||
|
||||
try:
|
||||
from wincertstore import CertFile
|
||||
import wincertstore
|
||||
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)
|
||||
class CertFile(wincertstore.CertFile):
|
||||
def __init__(self):
|
||||
super(CertFile, self).__init__()
|
||||
atexit.register(self.close)
|
||||
|
||||
def close(self):
|
||||
try:
|
||||
super(MyCertFile, self).close()
|
||||
super(CertFile, self).close()
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
_wincerts = MyCertFile(stores=['CA', 'ROOT'])
|
||||
_wincerts = CertFile()
|
||||
_wincerts.addstore('CA')
|
||||
_wincerts.addstore('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
|
||||
extant_cert_paths = filter(os.path.isfile, cert_paths)
|
||||
return (
|
||||
get_win_certfile()
|
||||
or next(extant_cert_paths, None)
|
||||
or _certifi_where()
|
||||
)
|
||||
|
||||
|
||||
def _certifi_where():
|
||||
try:
|
||||
return pkg_resources.resource_filename('certifi', 'cacert.pem')
|
||||
return __import__('certifi').where()
|
||||
except (ImportError, ResolutionError, ExtractionError):
|
||||
return None
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import sys
|
|||
|
||||
from setuptools.extern import six
|
||||
|
||||
|
||||
# HFS Plus uses decomposed UTF-8
|
||||
def decompose(path):
|
||||
if isinstance(path, six.text_type):
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
import os
|
||||
import os.path
|
||||
|
||||
|
||||
def cs_path_exists(fspath):
|
||||
if not os.path.exists(fspath):
|
||||
return False
|
||||
# make absolute so we always have a directory
|
||||
abspath = os.path.abspath(fspath)
|
||||
directory, filename = os.path.split(abspath)
|
||||
return filename in os.listdir(directory)
|
||||
|
|
@ -1 +1,6 @@
|
|||
__version__ = '20.1.1'
|
||||
import pkg_resources
|
||||
|
||||
try:
|
||||
__version__ = pkg_resources.get_distribution('setuptools').version
|
||||
except Exception:
|
||||
__version__ = 'unknown'
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue