add python3.6 modules
This commit is contained in:
parent
7080253073
commit
e9dacd2bf3
228 changed files with 10923 additions and 6804 deletions
|
|
@ -10,6 +10,18 @@ import warnings
|
|||
import sys
|
||||
import re
|
||||
|
||||
# 2016-06-17 barry@debian.org: urllib3 1.14 added optional support for socks,
|
||||
# but if invoked (i.e. imported), it will issue a warning to stderr if socks
|
||||
# isn't available. requests unconditionally imports urllib3's socks contrib
|
||||
# module, triggering this warning. The warning breaks DEP-8 tests (because of
|
||||
# the stderr output) and is just plain annoying in normal usage. I don't want
|
||||
# to add socks as yet another dependency for pip, nor do I want to allow-stder
|
||||
# in the DEP-8 tests, so just suppress the warning. pdb tells me this has to
|
||||
# be done before the import of pip.vcs.
|
||||
from pip._vendor.requests.packages.urllib3.exceptions import DependencyWarning
|
||||
warnings.filterwarnings("ignore", category=DependencyWarning) # noqa
|
||||
|
||||
|
||||
from pip.exceptions import InstallationError, CommandError, PipError
|
||||
from pip.utils import get_installed_distributions, get_prog
|
||||
from pip.utils import deprecation, dist_is_editable
|
||||
|
|
@ -31,12 +43,12 @@ import pip.cmdoptions
|
|||
cmdoptions = pip.cmdoptions
|
||||
|
||||
# The version as used in the setup.py and the docs conf.py
|
||||
__version__ = "8.1.1"
|
||||
__version__ = "9.0.1"
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Hide the InsecureRequestWArning from urllib3
|
||||
# Hide the InsecureRequestWarning from urllib3
|
||||
warnings.filterwarnings("ignore", category=InsecureRequestWarning)
|
||||
|
||||
|
||||
|
|
@ -44,7 +56,7 @@ def autocomplete():
|
|||
"""Command and option completion for the main option parser (and options)
|
||||
and its subcommands (and options).
|
||||
|
||||
Enable by sourcing one of the completion shell scripts (bash or zsh).
|
||||
Enable by sourcing one of the completion shell scripts (bash, zsh or fish).
|
||||
"""
|
||||
# Don't complete if user hasn't sourced bash_completion file.
|
||||
if 'PIP_AUTO_COMPLETE' not in os.environ:
|
||||
|
|
@ -212,7 +224,11 @@ def main(args=None):
|
|||
|
||||
# Needed for locale.getpreferredencoding(False) to work
|
||||
# in pip.utils.encoding.auto_decode
|
||||
locale.setlocale(locale.LC_ALL, '')
|
||||
try:
|
||||
locale.setlocale(locale.LC_ALL, '')
|
||||
except locale.Error as e:
|
||||
# setlocale can apparently crash if locale are uninitialized
|
||||
logger.debug("Ignoring error %s when setting locale", e)
|
||||
command = commands_dict[cmd_name](isolated=check_isolated(cmd_args))
|
||||
return command.main(cmd_args)
|
||||
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ if DEBUNDLED:
|
|||
vendored("cachecontrol")
|
||||
vendored("colorama")
|
||||
vendored("distlib")
|
||||
vendored("distro")
|
||||
vendored("html5lib")
|
||||
vendored("lockfile")
|
||||
vendored("six")
|
||||
|
|
|
|||
|
|
@ -117,6 +117,12 @@ class Command(object):
|
|||
else:
|
||||
level = "INFO"
|
||||
|
||||
# The root logger should match the "console" level *unless* we
|
||||
# specified "--log" to send debug logs to a file.
|
||||
root_level = level
|
||||
if options.log:
|
||||
root_level = "DEBUG"
|
||||
|
||||
logging_dictConfig({
|
||||
"version": 1,
|
||||
"disable_existing_loggers": False,
|
||||
|
|
@ -155,7 +161,7 @@ class Command(object):
|
|||
},
|
||||
},
|
||||
"root": {
|
||||
"level": level,
|
||||
"level": root_level,
|
||||
"handlers": list(filter(None, [
|
||||
"console",
|
||||
"console_errors",
|
||||
|
|
@ -305,13 +311,15 @@ class RequirementCommand(Command):
|
|||
'to %(name)s (see "pip help %(name)s")' % opts)
|
||||
logger.warning(msg)
|
||||
|
||||
def _build_package_finder(self, options, session):
|
||||
def _build_package_finder(self, options, session,
|
||||
platform=None, python_versions=None,
|
||||
abi=None, implementation=None):
|
||||
"""
|
||||
Create a package finder appropriate to this requirement command.
|
||||
"""
|
||||
index_urls = [options.index_url] + options.extra_index_urls
|
||||
if options.no_index:
|
||||
logger.info('Ignoring indexes: %s', ','.join(index_urls))
|
||||
logger.debug('Ignoring indexes: %s', ','.join(index_urls))
|
||||
index_urls = []
|
||||
|
||||
return PackageFinder(
|
||||
|
|
@ -322,4 +330,8 @@ class RequirementCommand(Command):
|
|||
allow_all_prereleases=options.pre,
|
||||
process_dependency_links=options.process_dependency_links,
|
||||
session=session,
|
||||
platform=platform,
|
||||
versions=python_versions,
|
||||
abi=abi,
|
||||
implementation=implementation,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@ class UpdatingDefaultsHelpFormatter(PrettyHelpFormatter):
|
|||
|
||||
|
||||
class CustomOptionParser(optparse.OptionParser):
|
||||
|
||||
def insert_option_group(self, idx, *args, **kwargs):
|
||||
"""Insert an OptionGroup at a given position."""
|
||||
group = self.add_option_group(*args, **kwargs)
|
||||
|
|
@ -273,7 +274,7 @@ class ConfigOptionParser(CustomOptionParser):
|
|||
yield (_environ_prefix_re.sub("", key).lower(), val)
|
||||
|
||||
def get_default_values(self):
|
||||
"""Overridding to make updating the defaults after instantiation of
|
||||
"""Overriding to make updating the defaults after instantiation of
|
||||
the option parser possible, _update_defaults() does the dirty work."""
|
||||
if not self.process_default_values:
|
||||
# Old, pre-Optik 1.5 behaviour.
|
||||
|
|
|
|||
|
|
@ -114,7 +114,10 @@ quiet = partial(
|
|||
dest='quiet',
|
||||
action='count',
|
||||
default=0,
|
||||
help='Give less output.')
|
||||
help=('Give less output. Option is additive, and can be used up to 3'
|
||||
' times (corresponding to WARNING, ERROR, and CRITICAL logging'
|
||||
' levels).')
|
||||
)
|
||||
|
||||
log = partial(
|
||||
Option,
|
||||
|
|
@ -184,12 +187,12 @@ def exists_action():
|
|||
'--exists-action',
|
||||
dest='exists_action',
|
||||
type='choice',
|
||||
choices=['s', 'i', 'w', 'b'],
|
||||
choices=['s', 'i', 'w', 'b', 'a'],
|
||||
default=[],
|
||||
action='append',
|
||||
metavar='action',
|
||||
help="Default action when a path already exists: "
|
||||
"(s)witch, (i)gnore, (w)ipe, (b)ackup.")
|
||||
"(s)witch, (i)gnore, (w)ipe, (b)ackup, (a)bort.")
|
||||
|
||||
|
||||
cert = partial(
|
||||
|
|
@ -216,7 +219,10 @@ index_url = partial(
|
|||
dest='index_url',
|
||||
metavar='URL',
|
||||
default=PyPI.simple_url,
|
||||
help='Base URL of Python Package Index (default %default).')
|
||||
help="Base URL of Python Package Index (default %default). "
|
||||
"This should point to a repository compliant with PEP 503 "
|
||||
"(the simple repository API) or a local directory laid out "
|
||||
"in the same format.")
|
||||
|
||||
|
||||
def extra_index_url():
|
||||
|
|
@ -226,7 +232,9 @@ def extra_index_url():
|
|||
metavar='URL',
|
||||
action='append',
|
||||
default=[],
|
||||
help='Extra URLs of package indexes to use in addition to --index-url.'
|
||||
help="Extra URLs of package indexes to use in addition to "
|
||||
"--index-url. Should follow the same rules as "
|
||||
"--index-url."
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -469,6 +477,13 @@ build_dir = partial(
|
|||
help='Directory to unpack packages into and build in.'
|
||||
)
|
||||
|
||||
ignore_requires_python = partial(
|
||||
Option,
|
||||
'--ignore-requires-python',
|
||||
dest='ignore_requires_python',
|
||||
action='store_true',
|
||||
help='Ignore the Requires-Python information.')
|
||||
|
||||
install_options = partial(
|
||||
Option,
|
||||
'--install-option',
|
||||
|
|
@ -510,7 +525,7 @@ disable_pip_version_check = partial(
|
|||
"--disable-pip-version-check",
|
||||
dest="disable_pip_version_check",
|
||||
action="store_true",
|
||||
default=False,
|
||||
default=True,
|
||||
help="Don't periodically check PyPI to determine whether a new version "
|
||||
"of pip is available for download. Implied with --no-index.")
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ from pip.commands.freeze import FreezeCommand
|
|||
from pip.commands.hash import HashCommand
|
||||
from pip.commands.help import HelpCommand
|
||||
from pip.commands.list import ListCommand
|
||||
from pip.commands.check import CheckCommand
|
||||
from pip.commands.search import SearchCommand
|
||||
from pip.commands.show import ShowCommand
|
||||
from pip.commands.install import InstallCommand
|
||||
|
|
@ -27,6 +28,7 @@ commands_dict = {
|
|||
UninstallCommand.name: UninstallCommand,
|
||||
DownloadCommand.name: DownloadCommand,
|
||||
ListCommand.name: ListCommand,
|
||||
CheckCommand.name: CheckCommand,
|
||||
WheelCommand.name: WheelCommand,
|
||||
}
|
||||
|
||||
|
|
@ -38,6 +40,7 @@ commands_order = [
|
|||
FreezeCommand,
|
||||
ListCommand,
|
||||
ShowCommand,
|
||||
CheckCommand,
|
||||
SearchCommand,
|
||||
WheelCommand,
|
||||
HashCommand,
|
||||
|
|
|
|||
39
lib/python3.4/site-packages/pip/commands/check.py
Normal file
39
lib/python3.4/site-packages/pip/commands/check.py
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import logging
|
||||
|
||||
from pip.basecommand import Command
|
||||
from pip.operations.check import check_requirements
|
||||
from pip.utils import get_installed_distributions
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CheckCommand(Command):
|
||||
"""Verify installed packages have compatible dependencies."""
|
||||
name = 'check'
|
||||
usage = """
|
||||
%prog [options]"""
|
||||
summary = 'Verify installed packages have compatible dependencies.'
|
||||
|
||||
def run(self, options, args):
|
||||
dists = get_installed_distributions(local_only=False, skip=())
|
||||
missing_reqs_dict, incompatible_reqs_dict = check_requirements(dists)
|
||||
|
||||
for dist in dists:
|
||||
key = '%s==%s' % (dist.project_name, dist.version)
|
||||
|
||||
for requirement in missing_reqs_dict.get(key, []):
|
||||
logger.info(
|
||||
"%s %s requires %s, which is not installed.",
|
||||
dist.project_name, dist.version, requirement.project_name)
|
||||
|
||||
for requirement, actual in incompatible_reqs_dict.get(key, []):
|
||||
logger.info(
|
||||
"%s %s has requirement %s, but you have %s %s.",
|
||||
dist.project_name, dist.version, requirement,
|
||||
actual.project_name, actual.version)
|
||||
|
||||
if missing_reqs_dict or incompatible_reqs_dict:
|
||||
return 1
|
||||
else:
|
||||
logger.info("No broken requirements found.")
|
||||
|
|
@ -26,13 +26,21 @@ function _pip_completion {
|
|||
PIP_AUTO_COMPLETE=1 $words[1] ) )
|
||||
}
|
||||
compctl -K _pip_completion pip
|
||||
""", 'fish': """
|
||||
function __fish_complete_pip
|
||||
set -lx COMP_WORDS (commandline -o) ""
|
||||
set -lx COMP_CWORD (math (contains -i -- (commandline -t) $COMP_WORDS)-1)
|
||||
set -lx PIP_AUTO_COMPLETE 1
|
||||
string split \ -- (eval $COMP_WORDS[1])
|
||||
end
|
||||
complete -fa "(__fish_complete_pip)" -c pip
|
||||
"""}
|
||||
|
||||
|
||||
class CompletionCommand(Command):
|
||||
"""A helper command to be used for command completion."""
|
||||
name = 'completion'
|
||||
summary = 'A helper command used for command completion'
|
||||
summary = 'A helper command used for command completion.'
|
||||
|
||||
def __init__(self, *args, **kw):
|
||||
super(CompletionCommand, self).__init__(*args, **kw)
|
||||
|
|
@ -51,6 +59,12 @@ class CompletionCommand(Command):
|
|||
const='zsh',
|
||||
dest='shell',
|
||||
help='Emit completion code for zsh')
|
||||
cmd_opts.add_option(
|
||||
'--fish', '-f',
|
||||
action='store_const',
|
||||
const='fish',
|
||||
dest='shell',
|
||||
help='Emit completion code for fish')
|
||||
|
||||
self.parser.insert_option_group(0, cmd_opts)
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ from __future__ import absolute_import
|
|||
import logging
|
||||
import os
|
||||
|
||||
from pip.exceptions import CommandError
|
||||
from pip.index import FormatControl
|
||||
from pip.req import RequirementSet
|
||||
from pip.basecommand import RequirementCommand
|
||||
from pip import cmdoptions
|
||||
|
|
@ -63,6 +65,53 @@ class DownloadCommand(RequirementCommand):
|
|||
help=("Download packages into <dir>."),
|
||||
)
|
||||
|
||||
cmd_opts.add_option(
|
||||
'--platform',
|
||||
dest='platform',
|
||||
metavar='platform',
|
||||
default=None,
|
||||
help=("Only download wheels compatible with <platform>. "
|
||||
"Defaults to the platform of the running system."),
|
||||
)
|
||||
|
||||
cmd_opts.add_option(
|
||||
'--python-version',
|
||||
dest='python_version',
|
||||
metavar='python_version',
|
||||
default=None,
|
||||
help=("Only download wheels compatible with Python "
|
||||
"interpreter version <version>. If not specified, then the "
|
||||
"current system interpreter minor version is used. A major "
|
||||
"version (e.g. '2') can be specified to match all "
|
||||
"minor revs of that major version. A minor version "
|
||||
"(e.g. '34') can also be specified."),
|
||||
)
|
||||
|
||||
cmd_opts.add_option(
|
||||
'--implementation',
|
||||
dest='implementation',
|
||||
metavar='implementation',
|
||||
default=None,
|
||||
help=("Only download wheels compatible with Python "
|
||||
"implementation <implementation>, e.g. 'pp', 'jy', 'cp', "
|
||||
" or 'ip'. If not specified, then the current "
|
||||
"interpreter implementation is used. Use 'py' to force "
|
||||
"implementation-agnostic wheels."),
|
||||
)
|
||||
|
||||
cmd_opts.add_option(
|
||||
'--abi',
|
||||
dest='abi',
|
||||
metavar='abi',
|
||||
default=None,
|
||||
help=("Only download wheels compatible with Python "
|
||||
"abi <abi>, e.g. 'pypy_41'. If not specified, then the "
|
||||
"current interpreter abi tag is used. Generally "
|
||||
"you will need to specify --implementation, "
|
||||
"--platform, and --python-version when using "
|
||||
"this option."),
|
||||
)
|
||||
|
||||
index_opts = cmdoptions.make_option_group(
|
||||
cmdoptions.non_deprecated_index_group,
|
||||
self.parser,
|
||||
|
|
@ -73,14 +122,41 @@ class DownloadCommand(RequirementCommand):
|
|||
|
||||
def run(self, options, args):
|
||||
options.ignore_installed = True
|
||||
|
||||
if options.python_version:
|
||||
python_versions = [options.python_version]
|
||||
else:
|
||||
python_versions = None
|
||||
|
||||
dist_restriction_set = any([
|
||||
options.python_version,
|
||||
options.platform,
|
||||
options.abi,
|
||||
options.implementation,
|
||||
])
|
||||
binary_only = FormatControl(set(), set([':all:']))
|
||||
if dist_restriction_set and options.format_control != binary_only:
|
||||
raise CommandError(
|
||||
"--only-binary=:all: must be set and --no-binary must not "
|
||||
"be set (or must be set to :none:) when restricting platform "
|
||||
"and interpreter constraints using --python-version, "
|
||||
"--platform, --abi, or --implementation."
|
||||
)
|
||||
|
||||
options.src_dir = os.path.abspath(options.src_dir)
|
||||
options.download_dir = normalize_path(options.download_dir)
|
||||
|
||||
ensure_dir(options.download_dir)
|
||||
|
||||
with self._build_session(options) as session:
|
||||
|
||||
finder = self._build_package_finder(options, session)
|
||||
finder = self._build_package_finder(
|
||||
options=options,
|
||||
session=session,
|
||||
platform=options.platform,
|
||||
python_versions=python_versions,
|
||||
abi=options.abi,
|
||||
implementation=options.implementation,
|
||||
)
|
||||
build_delete = (not (options.no_clean or options.build_dir))
|
||||
if options.cache_dir and not check_path_owner(options.cache_dir):
|
||||
logger.warning(
|
||||
|
|
|
|||
|
|
@ -29,12 +29,13 @@ class FreezeCommand(Command):
|
|||
|
||||
self.cmd_opts.add_option(
|
||||
'-r', '--requirement',
|
||||
dest='requirement',
|
||||
action='store',
|
||||
default=None,
|
||||
dest='requirements',
|
||||
action='append',
|
||||
default=[],
|
||||
metavar='file',
|
||||
help="Use the order in the given requirements file and its "
|
||||
"comments when generating output.")
|
||||
"comments when generating output. This option can be "
|
||||
"used multiple times.")
|
||||
self.cmd_opts.add_option(
|
||||
'-f', '--find-links',
|
||||
dest='find_links',
|
||||
|
|
@ -73,7 +74,7 @@ class FreezeCommand(Command):
|
|||
skip.update(DEV_PKGS)
|
||||
|
||||
freeze_kwargs = dict(
|
||||
requirement=options.requirement,
|
||||
requirement=options.requirements,
|
||||
find_links=options.find_links,
|
||||
local_only=options.local,
|
||||
user_only=options.user,
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ from pip.exceptions import (
|
|||
InstallationError, CommandError, PreviousBuildDirError,
|
||||
)
|
||||
from pip import cmdoptions
|
||||
from pip.utils import ensure_dir
|
||||
from pip.utils import ensure_dir, get_installed_version
|
||||
from pip.utils.build import BuildDirectory
|
||||
from pip.utils.deprecation import RemovedInPip10Warning
|
||||
from pip.utils.filesystem import check_path_owner
|
||||
|
|
@ -95,8 +95,21 @@ class InstallCommand(RequirementCommand):
|
|||
dest='upgrade',
|
||||
action='store_true',
|
||||
help='Upgrade all specified packages to the newest available '
|
||||
'version. This process is recursive regardless of whether '
|
||||
'a dependency is already satisfied.'
|
||||
'version. The handling of dependencies depends on the '
|
||||
'upgrade-strategy used.'
|
||||
)
|
||||
|
||||
cmd_opts.add_option(
|
||||
'--upgrade-strategy',
|
||||
dest='upgrade_strategy',
|
||||
default='eager',
|
||||
choices=['only-if-needed', 'eager'],
|
||||
help='Determines how dependency upgrading should be handled. '
|
||||
'"eager" - dependencies are upgraded regardless of '
|
||||
'whether the currently installed version satisfies the '
|
||||
'requirements of the upgraded package(s). '
|
||||
'"only-if-needed" - are upgraded only when they do not '
|
||||
'satisfy the requirements of the upgraded package(s).'
|
||||
)
|
||||
|
||||
cmd_opts.add_option(
|
||||
|
|
@ -113,6 +126,7 @@ class InstallCommand(RequirementCommand):
|
|||
default=default_user,
|
||||
help='Ignore the installed packages (reinstalling instead).')
|
||||
|
||||
cmd_opts.add_option(cmdoptions.ignore_requires_python())
|
||||
cmd_opts.add_option(cmdoptions.no_deps())
|
||||
|
||||
cmd_opts.add_option(cmdoptions.install_options())
|
||||
|
|
@ -197,6 +211,15 @@ class InstallCommand(RequirementCommand):
|
|||
cmdoptions.resolve_wheel_no_use_binary(options)
|
||||
cmdoptions.check_install_build_global(options)
|
||||
|
||||
if options.as_egg:
|
||||
warnings.warn(
|
||||
"--egg has been deprecated and will be removed in the future. "
|
||||
"This flag is mutually exclusive with large parts of pip, and "
|
||||
"actually using it invalidates pip's ability to manage the "
|
||||
"installation process.",
|
||||
RemovedInPip10Warning,
|
||||
)
|
||||
|
||||
if options.allow_external:
|
||||
warnings.warn(
|
||||
"--allow-external has been deprecated and will be removed in "
|
||||
|
|
@ -287,9 +310,11 @@ class InstallCommand(RequirementCommand):
|
|||
src_dir=options.src_dir,
|
||||
download_dir=options.download_dir,
|
||||
upgrade=options.upgrade,
|
||||
upgrade_strategy=options.upgrade_strategy,
|
||||
as_egg=options.as_egg,
|
||||
ignore_installed=options.ignore_installed,
|
||||
ignore_dependencies=options.ignore_dependencies,
|
||||
ignore_requires_python=options.ignore_requires_python,
|
||||
force_reinstall=options.force_reinstall,
|
||||
use_user_site=options.use_user_site,
|
||||
target_dir=temp_target_dir,
|
||||
|
|
@ -334,6 +359,14 @@ class InstallCommand(RequirementCommand):
|
|||
root=options.root_path,
|
||||
prefix=options.prefix_path,
|
||||
)
|
||||
|
||||
possible_lib_locations = get_lib_location_guesses(
|
||||
user=options.use_user_site,
|
||||
home=temp_target_dir,
|
||||
root=options.root_path,
|
||||
prefix=options.prefix_path,
|
||||
isolated=options.isolated_mode,
|
||||
)
|
||||
reqs = sorted(
|
||||
requirement_set.successfully_installed,
|
||||
key=operator.attrgetter('name'))
|
||||
|
|
@ -341,9 +374,11 @@ class InstallCommand(RequirementCommand):
|
|||
for req in reqs:
|
||||
item = req.name
|
||||
try:
|
||||
if hasattr(req, 'installed_version'):
|
||||
if req.installed_version:
|
||||
item += '-' + req.installed_version
|
||||
installed_version = get_installed_version(
|
||||
req.name, possible_lib_locations
|
||||
)
|
||||
if installed_version:
|
||||
item += '-' + installed_version
|
||||
except Exception:
|
||||
pass
|
||||
items.append(item)
|
||||
|
|
@ -370,35 +405,51 @@ class InstallCommand(RequirementCommand):
|
|||
if options.target_dir:
|
||||
ensure_dir(options.target_dir)
|
||||
|
||||
lib_dir = distutils_scheme('', home=temp_target_dir)['purelib']
|
||||
# Checking both purelib and platlib directories for installed
|
||||
# packages to be moved to target directory
|
||||
lib_dir_list = []
|
||||
|
||||
for item in os.listdir(lib_dir):
|
||||
target_item_dir = os.path.join(options.target_dir, item)
|
||||
if os.path.exists(target_item_dir):
|
||||
if not options.upgrade:
|
||||
logger.warning(
|
||||
'Target directory %s already exists. Specify '
|
||||
'--upgrade to force replacement.',
|
||||
target_item_dir
|
||||
)
|
||||
continue
|
||||
if os.path.islink(target_item_dir):
|
||||
logger.warning(
|
||||
'Target directory %s already exists and is '
|
||||
'a link. Pip will not automatically replace '
|
||||
'links, please remove if replacement is '
|
||||
'desired.',
|
||||
target_item_dir
|
||||
)
|
||||
continue
|
||||
if os.path.isdir(target_item_dir):
|
||||
shutil.rmtree(target_item_dir)
|
||||
else:
|
||||
os.remove(target_item_dir)
|
||||
purelib_dir = distutils_scheme('', home=temp_target_dir)['purelib']
|
||||
platlib_dir = distutils_scheme('', home=temp_target_dir)['platlib']
|
||||
|
||||
shutil.move(
|
||||
os.path.join(lib_dir, item),
|
||||
target_item_dir
|
||||
)
|
||||
if os.path.exists(purelib_dir):
|
||||
lib_dir_list.append(purelib_dir)
|
||||
if os.path.exists(platlib_dir) and platlib_dir != purelib_dir:
|
||||
lib_dir_list.append(platlib_dir)
|
||||
|
||||
for lib_dir in lib_dir_list:
|
||||
for item in os.listdir(lib_dir):
|
||||
target_item_dir = os.path.join(options.target_dir, item)
|
||||
if os.path.exists(target_item_dir):
|
||||
if not options.upgrade:
|
||||
logger.warning(
|
||||
'Target directory %s already exists. Specify '
|
||||
'--upgrade to force replacement.',
|
||||
target_item_dir
|
||||
)
|
||||
continue
|
||||
if os.path.islink(target_item_dir):
|
||||
logger.warning(
|
||||
'Target directory %s already exists and is '
|
||||
'a link. Pip will not automatically replace '
|
||||
'links, please remove if replacement is '
|
||||
'desired.',
|
||||
target_item_dir
|
||||
)
|
||||
continue
|
||||
if os.path.isdir(target_item_dir):
|
||||
shutil.rmtree(target_item_dir)
|
||||
else:
|
||||
os.remove(target_item_dir)
|
||||
|
||||
shutil.move(
|
||||
os.path.join(lib_dir, item),
|
||||
target_item_dir
|
||||
)
|
||||
shutil.rmtree(temp_target_dir)
|
||||
return requirement_set
|
||||
|
||||
|
||||
def get_lib_location_guesses(*args, **kwargs):
|
||||
scheme = distutils_scheme('', *args, **kwargs)
|
||||
return [scheme['purelib'], scheme['platlib']]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,14 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
import json
|
||||
import logging
|
||||
import warnings
|
||||
try:
|
||||
from itertools import zip_longest
|
||||
except ImportError:
|
||||
from itertools import izip_longest as zip_longest
|
||||
|
||||
from pip._vendor import six
|
||||
|
||||
from pip.basecommand import Command
|
||||
from pip.exceptions import CommandError
|
||||
|
|
@ -11,7 +18,6 @@ from pip.utils import (
|
|||
from pip.utils.deprecation import RemovedInPip10Warning
|
||||
from pip.cmdoptions import make_option_group, index_group
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
|
@ -68,6 +74,23 @@ class ListCommand(Command):
|
|||
"pip only finds stable versions."),
|
||||
)
|
||||
|
||||
cmd_opts.add_option(
|
||||
'--format',
|
||||
action='store',
|
||||
dest='list_format',
|
||||
choices=('legacy', 'columns', 'freeze', 'json'),
|
||||
help="Select the output format among: legacy (default), columns, "
|
||||
"freeze or json.",
|
||||
)
|
||||
|
||||
cmd_opts.add_option(
|
||||
'--not-required',
|
||||
action='store_true',
|
||||
dest='not_required',
|
||||
help="List packages that are not dependencies of "
|
||||
"installed packages.",
|
||||
)
|
||||
|
||||
index_opts = make_option_group(index_group, self.parser)
|
||||
|
||||
self.parser.insert_option_group(0, index_opts)
|
||||
|
|
@ -110,38 +133,62 @@ class ListCommand(Command):
|
|||
"no longer has any effect.",
|
||||
RemovedInPip10Warning,
|
||||
)
|
||||
|
||||
if options.list_format is None:
|
||||
warnings.warn(
|
||||
"The default format will switch to columns in the future. "
|
||||
"You can use --format=(legacy|columns) (or define a "
|
||||
"format=(legacy|columns) in your pip.conf under the [list] "
|
||||
"section) to disable this warning.",
|
||||
RemovedInPip10Warning,
|
||||
)
|
||||
|
||||
if options.outdated and options.uptodate:
|
||||
raise CommandError(
|
||||
"Options --outdated and --uptodate cannot be combined.")
|
||||
|
||||
packages = get_installed_distributions(
|
||||
local_only=options.local,
|
||||
user_only=options.user,
|
||||
editables_only=options.editable,
|
||||
)
|
||||
|
||||
if options.outdated:
|
||||
self.run_outdated(options)
|
||||
packages = self.get_outdated(packages, options)
|
||||
elif options.uptodate:
|
||||
self.run_uptodate(options)
|
||||
else:
|
||||
self.run_listing(options)
|
||||
packages = self.get_uptodate(packages, options)
|
||||
|
||||
def run_outdated(self, options):
|
||||
for dist, latest_version, typ in sorted(
|
||||
self.find_packages_latest_versions(options),
|
||||
key=lambda p: p[0].project_name.lower()):
|
||||
if latest_version > dist.parsed_version:
|
||||
logger.info(
|
||||
'%s - Latest: %s [%s]',
|
||||
self.output_package(dist), latest_version, typ,
|
||||
)
|
||||
if options.not_required:
|
||||
packages = self.get_not_required(packages, options)
|
||||
|
||||
def find_packages_latest_versions(self, options):
|
||||
self.output_package_listing(packages, options)
|
||||
|
||||
def get_outdated(self, packages, options):
|
||||
return [
|
||||
dist for dist in self.iter_packages_latest_infos(packages, options)
|
||||
if dist.latest_version > dist.parsed_version
|
||||
]
|
||||
|
||||
def get_uptodate(self, packages, options):
|
||||
return [
|
||||
dist for dist in self.iter_packages_latest_infos(packages, options)
|
||||
if dist.latest_version == dist.parsed_version
|
||||
]
|
||||
|
||||
def get_not_required(self, packages, options):
|
||||
dep_keys = set()
|
||||
for dist in packages:
|
||||
dep_keys.update(requirement.key for requirement in dist.requires())
|
||||
return set(pkg for pkg in packages if pkg.key not in dep_keys)
|
||||
|
||||
def iter_packages_latest_infos(self, packages, options):
|
||||
index_urls = [options.index_url] + options.extra_index_urls
|
||||
if options.no_index:
|
||||
logger.info('Ignoring indexes: %s', ','.join(index_urls))
|
||||
logger.debug('Ignoring indexes: %s', ','.join(index_urls))
|
||||
index_urls = []
|
||||
|
||||
dependency_links = []
|
||||
for dist in get_installed_distributions(
|
||||
local_only=options.local,
|
||||
user_only=options.user,
|
||||
editables_only=options.editable):
|
||||
for dist in packages:
|
||||
if dist.has_metadata('dependency_links.txt'):
|
||||
dependency_links.extend(
|
||||
dist.get_metadata_lines('dependency_links.txt'),
|
||||
|
|
@ -151,12 +198,7 @@ class ListCommand(Command):
|
|||
finder = self._build_package_finder(options, index_urls, session)
|
||||
finder.add_dependency_links(dependency_links)
|
||||
|
||||
installed_packages = get_installed_distributions(
|
||||
local_only=options.local,
|
||||
user_only=options.user,
|
||||
editables_only=options.editable,
|
||||
)
|
||||
for dist in installed_packages:
|
||||
for dist in packages:
|
||||
typ = 'unknown'
|
||||
all_candidates = finder.find_all_candidates(dist.key)
|
||||
if not options.pre:
|
||||
|
|
@ -173,17 +215,12 @@ class ListCommand(Command):
|
|||
typ = 'wheel'
|
||||
else:
|
||||
typ = 'sdist'
|
||||
yield dist, remote_version, typ
|
||||
# This is dirty but makes the rest of the code much cleaner
|
||||
dist.latest_version = remote_version
|
||||
dist.latest_filetype = typ
|
||||
yield dist
|
||||
|
||||
def run_listing(self, options):
|
||||
installed_packages = get_installed_distributions(
|
||||
local_only=options.local,
|
||||
user_only=options.user,
|
||||
editables_only=options.editable,
|
||||
)
|
||||
self.output_package_listing(installed_packages)
|
||||
|
||||
def output_package(self, dist):
|
||||
def output_legacy(self, dist):
|
||||
if dist_is_editable(dist):
|
||||
return '%s (%s, %s)' % (
|
||||
dist.project_name,
|
||||
|
|
@ -193,17 +230,108 @@ class ListCommand(Command):
|
|||
else:
|
||||
return '%s (%s)' % (dist.project_name, dist.version)
|
||||
|
||||
def output_package_listing(self, installed_packages):
|
||||
installed_packages = sorted(
|
||||
installed_packages,
|
||||
def output_legacy_latest(self, dist):
|
||||
return '%s - Latest: %s [%s]' % (
|
||||
self.output_legacy(dist),
|
||||
dist.latest_version,
|
||||
dist.latest_filetype,
|
||||
)
|
||||
|
||||
def output_package_listing(self, packages, options):
|
||||
packages = sorted(
|
||||
packages,
|
||||
key=lambda dist: dist.project_name.lower(),
|
||||
)
|
||||
for dist in installed_packages:
|
||||
logger.info(self.output_package(dist))
|
||||
if options.list_format == 'columns' and packages:
|
||||
data, header = format_for_columns(packages, options)
|
||||
self.output_package_listing_columns(data, header)
|
||||
elif options.list_format == 'freeze':
|
||||
for dist in packages:
|
||||
logger.info("%s==%s", dist.project_name, dist.version)
|
||||
elif options.list_format == 'json':
|
||||
logger.info(format_for_json(packages, options))
|
||||
else: # legacy
|
||||
for dist in packages:
|
||||
if options.outdated:
|
||||
logger.info(self.output_legacy_latest(dist))
|
||||
else:
|
||||
logger.info(self.output_legacy(dist))
|
||||
|
||||
def run_uptodate(self, options):
|
||||
uptodate = []
|
||||
for dist, version, typ in self.find_packages_latest_versions(options):
|
||||
if dist.parsed_version == version:
|
||||
uptodate.append(dist)
|
||||
self.output_package_listing(uptodate)
|
||||
def output_package_listing_columns(self, data, header):
|
||||
# insert the header first: we need to know the size of column names
|
||||
if len(data) > 0:
|
||||
data.insert(0, header)
|
||||
|
||||
pkg_strings, sizes = tabulate(data)
|
||||
|
||||
# Create and add a separator.
|
||||
if len(data) > 0:
|
||||
pkg_strings.insert(1, " ".join(map(lambda x: '-' * x, sizes)))
|
||||
|
||||
for val in pkg_strings:
|
||||
logger.info(val)
|
||||
|
||||
|
||||
def tabulate(vals):
|
||||
# From pfmoore on GitHub:
|
||||
# https://github.com/pypa/pip/issues/3651#issuecomment-216932564
|
||||
assert len(vals) > 0
|
||||
|
||||
sizes = [0] * max(len(x) for x in vals)
|
||||
for row in vals:
|
||||
sizes = [max(s, len(str(c))) for s, c in zip_longest(sizes, row)]
|
||||
|
||||
result = []
|
||||
for row in vals:
|
||||
display = " ".join([str(c).ljust(s) if c is not None else ''
|
||||
for s, c in zip_longest(sizes, row)])
|
||||
result.append(display)
|
||||
|
||||
return result, sizes
|
||||
|
||||
|
||||
def format_for_columns(pkgs, options):
|
||||
"""
|
||||
Convert the package data into something usable
|
||||
by output_package_listing_columns.
|
||||
"""
|
||||
running_outdated = options.outdated
|
||||
# Adjust the header for the `pip list --outdated` case.
|
||||
if running_outdated:
|
||||
header = ["Package", "Version", "Latest", "Type"]
|
||||
else:
|
||||
header = ["Package", "Version"]
|
||||
|
||||
data = []
|
||||
if any(dist_is_editable(x) for x in pkgs):
|
||||
header.append("Location")
|
||||
|
||||
for proj in pkgs:
|
||||
# if we're working on the 'outdated' list, separate out the
|
||||
# latest_version and type
|
||||
row = [proj.project_name, proj.version]
|
||||
|
||||
if running_outdated:
|
||||
row.append(proj.latest_version)
|
||||
row.append(proj.latest_filetype)
|
||||
|
||||
if dist_is_editable(proj):
|
||||
row.append(proj.location)
|
||||
|
||||
data.append(row)
|
||||
|
||||
return data, header
|
||||
|
||||
|
||||
def format_for_json(packages, options):
|
||||
data = []
|
||||
for dist in packages:
|
||||
info = {
|
||||
'name': dist.project_name,
|
||||
'version': six.text_type(dist.version),
|
||||
}
|
||||
if options.outdated:
|
||||
info['latest_version'] = six.text_type(dist.latest_version)
|
||||
info['latest_filetype'] = dist.latest_filetype
|
||||
data.append(info)
|
||||
return json.dumps(data)
|
||||
|
|
|
|||
|
|
@ -5,12 +5,14 @@ import sys
|
|||
import textwrap
|
||||
|
||||
from pip.basecommand import Command, SUCCESS
|
||||
from pip.compat import OrderedDict
|
||||
from pip.download import PipXmlrpcTransport
|
||||
from pip.models import PyPI
|
||||
from pip.utils import get_terminal_size
|
||||
from pip.utils.logging import indent_log
|
||||
from pip.exceptions import CommandError
|
||||
from pip.status_codes import NO_MATCHES_FOUND
|
||||
from pip._vendor.packaging.version import parse as parse_version
|
||||
from pip._vendor import pkg_resources
|
||||
from pip._vendor.six.moves import xmlrpc_client
|
||||
|
||||
|
|
@ -28,7 +30,7 @@ class SearchCommand(Command):
|
|||
def __init__(self, *args, **kw):
|
||||
super(SearchCommand, self).__init__(*args, **kw)
|
||||
self.cmd_opts.add_option(
|
||||
'--index',
|
||||
'-i', '--index',
|
||||
dest='index',
|
||||
metavar='URL',
|
||||
default=PyPI.pypi_url,
|
||||
|
|
@ -67,21 +69,17 @@ def transform_hits(hits):
|
|||
packages with the list of versions stored inline. This converts the
|
||||
list from pypi into one we can use.
|
||||
"""
|
||||
packages = {}
|
||||
packages = OrderedDict()
|
||||
for hit in hits:
|
||||
name = hit['name']
|
||||
summary = hit['summary']
|
||||
version = hit['version']
|
||||
score = hit['_pypi_ordering']
|
||||
if score is None:
|
||||
score = 0
|
||||
|
||||
if name not in packages.keys():
|
||||
packages[name] = {
|
||||
'name': name,
|
||||
'summary': summary,
|
||||
'versions': [version],
|
||||
'score': score,
|
||||
}
|
||||
else:
|
||||
packages[name]['versions'].append(version)
|
||||
|
|
@ -89,16 +87,8 @@ def transform_hits(hits):
|
|||
# if this is the highest version, replace summary and score
|
||||
if version == highest_version(packages[name]['versions']):
|
||||
packages[name]['summary'] = summary
|
||||
packages[name]['score'] = score
|
||||
|
||||
# each record has a unique name now, so we will convert the dict into a
|
||||
# list sorted by score
|
||||
package_list = sorted(
|
||||
packages.values(),
|
||||
key=lambda x: x['score'],
|
||||
reverse=True,
|
||||
)
|
||||
return package_list
|
||||
return list(packages.values())
|
||||
|
||||
|
||||
def print_results(hits, name_column_width=None, terminal_width=None):
|
||||
|
|
@ -116,12 +106,11 @@ def print_results(hits, name_column_width=None, terminal_width=None):
|
|||
summary = hit['summary'] or ''
|
||||
version = hit.get('versions', ['-'])[-1]
|
||||
if terminal_width is not None:
|
||||
# wrap and indent summary to fit terminal
|
||||
summary = textwrap.wrap(
|
||||
summary,
|
||||
terminal_width - name_column_width - 5,
|
||||
)
|
||||
summary = ('\n' + ' ' * (name_column_width + 3)).join(summary)
|
||||
target_width = terminal_width - name_column_width - 5
|
||||
if target_width > 10:
|
||||
# wrap and indent summary to fit terminal
|
||||
summary = textwrap.wrap(summary, target_width)
|
||||
summary = ('\n' + ' ' * (name_column_width + 3)).join(summary)
|
||||
|
||||
line = '%-*s - %s' % (name_column_width,
|
||||
'%s (%s)' % (name, version), summary)
|
||||
|
|
@ -141,6 +130,4 @@ def print_results(hits, name_column_width=None, terminal_width=None):
|
|||
|
||||
|
||||
def highest_version(versions):
|
||||
return next(iter(
|
||||
sorted(versions, key=pkg_resources.parse_version, reverse=True)
|
||||
))
|
||||
return max(versions, key=parse_version)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import os
|
|||
from pip.basecommand import Command
|
||||
from pip.status_codes import SUCCESS, ERROR
|
||||
from pip._vendor import pkg_resources
|
||||
from pip._vendor.packaging.utils import canonicalize_name
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
|
@ -37,7 +38,8 @@ class ShowCommand(Command):
|
|||
query = args
|
||||
|
||||
results = search_packages_info(query)
|
||||
if not print_results(results, options.files):
|
||||
if not print_results(
|
||||
results, list_files=options.files, verbose=options.verbose):
|
||||
return ERROR
|
||||
return SUCCESS
|
||||
|
||||
|
|
@ -49,9 +51,12 @@ def search_packages_info(query):
|
|||
pip generated 'installed-files.txt' in the distributions '.egg-info'
|
||||
directory.
|
||||
"""
|
||||
installed = dict(
|
||||
[(p.project_name.lower(), p) for p in pkg_resources.working_set])
|
||||
query_names = [name.lower() for name in query]
|
||||
installed = {}
|
||||
for p in pkg_resources.working_set:
|
||||
installed[canonicalize_name(p.project_name)] = p
|
||||
|
||||
query_names = [canonicalize_name(name) for name in query]
|
||||
|
||||
for dist in [installed[pkg] for pkg in query_names if pkg in installed]:
|
||||
package = {
|
||||
'name': dist.project_name,
|
||||
|
|
@ -85,13 +90,11 @@ def search_packages_info(query):
|
|||
entry_points = dist.get_metadata_lines('entry_points.txt')
|
||||
package['entry_points'] = entry_points
|
||||
|
||||
installer = None
|
||||
if dist.has_metadata('INSTALLER'):
|
||||
for line in dist.get_metadata_lines('INSTALLER'):
|
||||
if line.strip():
|
||||
installer = line.strip()
|
||||
package['installer'] = line.strip()
|
||||
break
|
||||
package['installer'] = installer
|
||||
|
||||
# @todo: Should pkg_resources.Distribution have a
|
||||
# `get_pkg_info` method?
|
||||
|
|
@ -102,12 +105,9 @@ def search_packages_info(query):
|
|||
'home-page', 'author', 'author-email', 'license'):
|
||||
package[key] = pkg_info_dict.get(key)
|
||||
|
||||
# It looks like FeedParser can not deal with repeated headers
|
||||
# It looks like FeedParser cannot deal with repeated headers
|
||||
classifiers = []
|
||||
for line in metadata.splitlines():
|
||||
if not line:
|
||||
break
|
||||
# Classifier: License :: OSI Approved :: MIT License
|
||||
if line.startswith('Classifier: '):
|
||||
classifiers.append(line[len('Classifier: '):])
|
||||
package['classifiers'] = classifiers
|
||||
|
|
@ -117,38 +117,38 @@ def search_packages_info(query):
|
|||
yield package
|
||||
|
||||
|
||||
def print_results(distributions, list_all_files):
|
||||
def print_results(distributions, list_files=False, verbose=False):
|
||||
"""
|
||||
Print the informations from installed distributions found.
|
||||
"""
|
||||
results_printed = False
|
||||
for dist in distributions:
|
||||
for i, dist in enumerate(distributions):
|
||||
results_printed = True
|
||||
logger.info("---")
|
||||
logger.info("Metadata-Version: %s", dist.get('metadata-version'))
|
||||
logger.info("Name: %s", dist['name'])
|
||||
logger.info("Version: %s", dist['version'])
|
||||
logger.info("Summary: %s", dist.get('summary'))
|
||||
logger.info("Home-page: %s", dist.get('home-page'))
|
||||
logger.info("Author: %s", dist.get('author'))
|
||||
logger.info("Author-email: %s", dist.get('author-email'))
|
||||
if dist['installer'] is not None:
|
||||
logger.info("Installer: %s", dist['installer'])
|
||||
logger.info("License: %s", dist.get('license'))
|
||||
logger.info("Location: %s", dist['location'])
|
||||
logger.info("Requires: %s", ', '.join(dist['requires']))
|
||||
logger.info("Classifiers:")
|
||||
for classifier in dist['classifiers']:
|
||||
logger.info(" %s", classifier)
|
||||
if list_all_files:
|
||||
logger.info("Files:")
|
||||
if 'files' in dist:
|
||||
for line in dist['files']:
|
||||
logger.info(" %s", line.strip())
|
||||
else:
|
||||
logger.info("Cannot locate installed-files.txt")
|
||||
if 'entry_points' in dist:
|
||||
if i > 0:
|
||||
logger.info("---")
|
||||
logger.info("Name: %s", dist.get('name', ''))
|
||||
logger.info("Version: %s", dist.get('version', ''))
|
||||
logger.info("Summary: %s", dist.get('summary', ''))
|
||||
logger.info("Home-page: %s", dist.get('home-page', ''))
|
||||
logger.info("Author: %s", dist.get('author', ''))
|
||||
logger.info("Author-email: %s", dist.get('author-email', ''))
|
||||
logger.info("License: %s", dist.get('license', ''))
|
||||
logger.info("Location: %s", dist.get('location', ''))
|
||||
logger.info("Requires: %s", ', '.join(dist.get('requires', [])))
|
||||
if verbose:
|
||||
logger.info("Metadata-Version: %s",
|
||||
dist.get('metadata-version', ''))
|
||||
logger.info("Installer: %s", dist.get('installer', ''))
|
||||
logger.info("Classifiers:")
|
||||
for classifier in dist.get('classifiers', []):
|
||||
logger.info(" %s", classifier)
|
||||
logger.info("Entry-points:")
|
||||
for line in dist['entry_points']:
|
||||
for entry in dist.get('entry_points', []):
|
||||
logger.info(" %s", entry.strip())
|
||||
if list_files:
|
||||
logger.info("Files:")
|
||||
for line in dist.get('files', []):
|
||||
logger.info(" %s", line.strip())
|
||||
if "files" not in dist:
|
||||
logger.info("Cannot locate installed-files.txt")
|
||||
return results_printed
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ class WheelCommand(RequirementCommand):
|
|||
|
||||
Wheel is a built-package format, and offers the advantage of not
|
||||
recompiling your software during every install. For more details, see the
|
||||
wheel docs: http://wheel.readthedocs.org/en/latest.
|
||||
wheel docs: https://wheel.readthedocs.io/en/latest/
|
||||
|
||||
Requirements: setuptools>=0.8, and wheel.
|
||||
|
||||
|
|
@ -70,6 +70,7 @@ class WheelCommand(RequirementCommand):
|
|||
cmd_opts.add_option(cmdoptions.editable())
|
||||
cmd_opts.add_option(cmdoptions.requirements())
|
||||
cmd_opts.add_option(cmdoptions.src())
|
||||
cmd_opts.add_option(cmdoptions.ignore_requires_python())
|
||||
cmd_opts.add_option(cmdoptions.no_deps())
|
||||
cmd_opts.add_option(cmdoptions.build_dir())
|
||||
|
||||
|
|
@ -151,12 +152,14 @@ class WheelCommand(RequirementCommand):
|
|||
|
||||
index_urls = [options.index_url] + options.extra_index_urls
|
||||
if options.no_index:
|
||||
logger.info('Ignoring indexes: %s', ','.join(index_urls))
|
||||
logger.debug('Ignoring indexes: %s', ','.join(index_urls))
|
||||
index_urls = []
|
||||
|
||||
if options.build_dir:
|
||||
options.build_dir = os.path.abspath(options.build_dir)
|
||||
|
||||
options.src_dir = os.path.abspath(options.src_dir)
|
||||
|
||||
with self._build_session(options) as session:
|
||||
finder = self._build_package_finder(options, session)
|
||||
build_delete = (not (options.no_clean or options.build_dir))
|
||||
|
|
@ -169,6 +172,7 @@ class WheelCommand(RequirementCommand):
|
|||
download_dir=None,
|
||||
ignore_dependencies=options.ignore_dependencies,
|
||||
ignore_installed=True,
|
||||
ignore_requires_python=options.ignore_requires_python,
|
||||
isolated=options.isolated_mode,
|
||||
session=session,
|
||||
wheel_cache=wheel_cache,
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ except ImportError:
|
|||
try:
|
||||
from collections import OrderedDict
|
||||
except ImportError:
|
||||
from pip.compat.ordereddict import OrderedDict
|
||||
from pip._vendor.ordereddict import OrderedDict
|
||||
|
||||
try:
|
||||
import ipaddress
|
||||
|
|
@ -115,7 +115,7 @@ def get_path_uid(path):
|
|||
file_uid = os.fstat(fd).st_uid
|
||||
os.close(fd)
|
||||
else: # AIX and Jython
|
||||
# WARNING: time of check vulnerabity, but best we can do w/o NOFOLLOW
|
||||
# WARNING: time of check vulnerability, but best we can do w/o NOFOLLOW
|
||||
if not os.path.islink(path):
|
||||
# older versions of Jython don't have `os.fstat`
|
||||
file_uid = os.stat(path).st_uid
|
||||
|
|
|
|||
|
|
@ -1,129 +0,0 @@
|
|||
# Copyright (c) 2009 Raymond Hettinger
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person
|
||||
# obtaining a copy of this software and associated documentation files
|
||||
# (the "Software"), to deal in the Software without restriction,
|
||||
# including without limitation the rights to use, copy, modify, merge,
|
||||
# publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
# and to permit persons to whom the Software is furnished to do so,
|
||||
# subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be
|
||||
# included in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
# OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
# flake8: noqa
|
||||
|
||||
from UserDict import DictMixin
|
||||
|
||||
class OrderedDict(dict, DictMixin):
|
||||
|
||||
def __init__(self, *args, **kwds):
|
||||
if len(args) > 1:
|
||||
raise TypeError('expected at most 1 arguments, got %d' % len(args))
|
||||
try:
|
||||
self.__end
|
||||
except AttributeError:
|
||||
self.clear()
|
||||
self.update(*args, **kwds)
|
||||
|
||||
def clear(self):
|
||||
self.__end = end = []
|
||||
end += [None, end, end] # sentinel node for doubly linked list
|
||||
self.__map = {} # key --> [key, prev, next]
|
||||
dict.clear(self)
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
if key not in self:
|
||||
end = self.__end
|
||||
curr = end[1]
|
||||
curr[2] = end[1] = self.__map[key] = [key, curr, end]
|
||||
dict.__setitem__(self, key, value)
|
||||
|
||||
def __delitem__(self, key):
|
||||
dict.__delitem__(self, key)
|
||||
key, prev, next = self.__map.pop(key)
|
||||
prev[2] = next
|
||||
next[1] = prev
|
||||
|
||||
def __iter__(self):
|
||||
end = self.__end
|
||||
curr = end[2]
|
||||
while curr is not end:
|
||||
yield curr[0]
|
||||
curr = curr[2]
|
||||
|
||||
def __reversed__(self):
|
||||
end = self.__end
|
||||
curr = end[1]
|
||||
while curr is not end:
|
||||
yield curr[0]
|
||||
curr = curr[1]
|
||||
|
||||
def popitem(self, last=True):
|
||||
if not self:
|
||||
raise KeyError('dictionary is empty')
|
||||
if last:
|
||||
key = reversed(self).next()
|
||||
else:
|
||||
key = iter(self).next()
|
||||
value = self.pop(key)
|
||||
return key, value
|
||||
|
||||
def __reduce__(self):
|
||||
items = [[k, self[k]] for k in self]
|
||||
tmp = self.__map, self.__end
|
||||
del self.__map, self.__end
|
||||
inst_dict = vars(self).copy()
|
||||
self.__map, self.__end = tmp
|
||||
if inst_dict:
|
||||
return (self.__class__, (items,), inst_dict)
|
||||
return self.__class__, (items,)
|
||||
|
||||
def keys(self):
|
||||
return list(self)
|
||||
|
||||
setdefault = DictMixin.setdefault
|
||||
update = DictMixin.update
|
||||
pop = DictMixin.pop
|
||||
values = DictMixin.values
|
||||
items = DictMixin.items
|
||||
iterkeys = DictMixin.iterkeys
|
||||
itervalues = DictMixin.itervalues
|
||||
iteritems = DictMixin.iteritems
|
||||
|
||||
def __repr__(self):
|
||||
if not self:
|
||||
return '%s()' % (self.__class__.__name__,)
|
||||
return '%s(%r)' % (self.__class__.__name__, self.items())
|
||||
|
||||
def copy(self):
|
||||
return self.__class__(self)
|
||||
|
||||
@classmethod
|
||||
def fromkeys(cls, iterable, value=None):
|
||||
d = cls()
|
||||
for key in iterable:
|
||||
d[key] = value
|
||||
return d
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, OrderedDict):
|
||||
if len(self) != len(other):
|
||||
return False
|
||||
for p, q in zip(self.items(), other.items()):
|
||||
if p != q:
|
||||
return False
|
||||
return True
|
||||
return dict.__eq__(self, other)
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self == other
|
||||
|
|
@ -33,6 +33,7 @@ from pip.utils.encoding import auto_decode
|
|||
from pip.utils.filesystem import check_path_owner
|
||||
from pip.utils.logging import indent_log
|
||||
from pip.utils.setuptools_build import SETUPTOOLS_SHIM
|
||||
from pip.utils.glibc import libc_ver
|
||||
from pip.utils.ui import DownloadProgressBar, DownloadProgressSpinner
|
||||
from pip.locations import write_delete_marker_file
|
||||
from pip.vcs import vcs
|
||||
|
|
@ -40,6 +41,7 @@ from pip._vendor import requests, six
|
|||
from pip._vendor.requests.adapters import BaseAdapter, HTTPAdapter
|
||||
from pip._vendor.requests.auth import AuthBase, HTTPBasicAuth
|
||||
from pip._vendor.requests.models import CONTENT_CHUNK_SIZE, Response
|
||||
from pip._vendor.requests.utils import get_netrc_auth
|
||||
from pip._vendor.requests.structures import CaseInsensitiveDict
|
||||
from pip._vendor.requests.packages import urllib3
|
||||
from pip._vendor.cachecontrol import CacheControlAdapter
|
||||
|
|
@ -88,21 +90,22 @@ def user_agent():
|
|||
data["implementation"]["version"] = platform.python_version()
|
||||
|
||||
if sys.platform.startswith("linux"):
|
||||
distro = dict(filter(
|
||||
from pip._vendor import distro
|
||||
distro_infos = dict(filter(
|
||||
lambda x: x[1],
|
||||
zip(["name", "version", "id"], platform.linux_distribution()),
|
||||
zip(["name", "version", "id"], distro.linux_distribution()),
|
||||
))
|
||||
libc = dict(filter(
|
||||
lambda x: x[1],
|
||||
zip(["lib", "version"], platform.libc_ver()),
|
||||
zip(["lib", "version"], libc_ver()),
|
||||
))
|
||||
if libc:
|
||||
distro["libc"] = libc
|
||||
if distro:
|
||||
data["distro"] = distro
|
||||
distro_infos["libc"] = libc
|
||||
if distro_infos:
|
||||
data["distro"] = distro_infos
|
||||
|
||||
if sys.platform.startswith("darwin") and platform.mac_ver()[0]:
|
||||
data["distro"] = {"name": "OS X", "version": platform.mac_ver()[0]}
|
||||
data["distro"] = {"name": "macOS", "version": platform.mac_ver()[0]}
|
||||
|
||||
if platform.system():
|
||||
data.setdefault("system", {})["name"] = platform.system()
|
||||
|
|
@ -145,6 +148,11 @@ class MultiDomainBasicAuth(AuthBase):
|
|||
if username is None:
|
||||
username, password = self.parse_credentials(parsed.netloc)
|
||||
|
||||
# Get creds from netrc if we still don't have them
|
||||
if username is None and password is None:
|
||||
netrc_auth = get_netrc_auth(req.url)
|
||||
username, password = netrc_auth if netrc_auth else (None, None)
|
||||
|
||||
if username or password:
|
||||
# Store the username and password
|
||||
self.passwords[netloc] = (username, password)
|
||||
|
|
@ -163,7 +171,7 @@ class MultiDomainBasicAuth(AuthBase):
|
|||
if resp.status_code != 401:
|
||||
return resp
|
||||
|
||||
# We are not able to prompt the user so simple return the response
|
||||
# We are not able to prompt the user so simply return the response
|
||||
if not self.prompting:
|
||||
return resp
|
||||
|
||||
|
|
@ -331,7 +339,7 @@ class PipSession(requests.Session):
|
|||
total=retries,
|
||||
|
||||
# A 503 error from PyPI typically means that the Fastly -> Origin
|
||||
# connection got interupted in some way. A 503 error in general
|
||||
# connection got interrupted in some way. A 503 error in general
|
||||
# is typically considered a transient error so we'll go ahead and
|
||||
# retry it.
|
||||
status_forcelist=[503],
|
||||
|
|
@ -602,8 +610,8 @@ def _copy_file(filename, location, link):
|
|||
download_location = os.path.join(location, link.filename)
|
||||
if os.path.exists(download_location):
|
||||
response = ask_path_exists(
|
||||
'The file %s exists. (i)gnore, (w)ipe, (b)ackup ' %
|
||||
display_path(download_location), ('i', 'w', 'b'))
|
||||
'The file %s exists. (i)gnore, (w)ipe, (b)ackup, (a)abort' %
|
||||
display_path(download_location), ('i', 'w', 'b', 'a'))
|
||||
if response == 'i':
|
||||
copy = False
|
||||
elif response == 'w':
|
||||
|
|
@ -617,6 +625,8 @@ def _copy_file(filename, location, link):
|
|||
display_path(dest_file),
|
||||
)
|
||||
shutil.move(download_location, dest_file)
|
||||
elif response == 'a':
|
||||
sys.exit(-1)
|
||||
if copy:
|
||||
shutil.copy(filename, download_location)
|
||||
logger.info('Saved %s', display_path(download_location))
|
||||
|
|
@ -679,7 +689,7 @@ def unpack_file_url(link, location, download_dir=None, hashes=None):
|
|||
return
|
||||
|
||||
# If --require-hashes is off, `hashes` is either empty, the
|
||||
# link's embeddded hash, or MissingHashes; it is required to
|
||||
# link's embedded hash, or MissingHashes; it is required to
|
||||
# match. If --require-hashes is on, we are satisfied by any
|
||||
# hash in `hashes` matching: a URL-based or an option-based
|
||||
# one; no internet-sourced hash will be in `hashes`.
|
||||
|
|
@ -749,6 +759,7 @@ class PipXmlrpcTransport(xmlrpc_client.Transport):
|
|||
"""Provide a `xmlrpclib.Transport` implementation via a `PipSession`
|
||||
object.
|
||||
"""
|
||||
|
||||
def __init__(self, index_url, session, use_datetime=False):
|
||||
xmlrpc_client.Transport.__init__(self, use_datetime)
|
||||
index_parts = urllib_parse.urlparse(index_url)
|
||||
|
|
|
|||
|
|
@ -237,3 +237,8 @@ class HashMismatch(HashError):
|
|||
self.gots[hash_name].hexdigest())
|
||||
prefix = ' or'
|
||||
return '\n'.join(lines)
|
||||
|
||||
|
||||
class UnsupportedPythonVersion(InstallationError):
|
||||
"""Unsupported python version according to Requires-Python package
|
||||
metadata."""
|
||||
|
|
|
|||
|
|
@ -20,19 +20,22 @@ from pip.utils import (
|
|||
cached_property, splitext, normalize_path,
|
||||
ARCHIVE_EXTENSIONS, SUPPORTED_EXTENSIONS,
|
||||
)
|
||||
from pip.utils.deprecation import RemovedInPip9Warning, RemovedInPip10Warning
|
||||
from pip.utils.deprecation import RemovedInPip10Warning
|
||||
from pip.utils.logging import indent_log
|
||||
from pip.utils.packaging import check_requires_python
|
||||
from pip.exceptions import (
|
||||
DistributionNotFound, BestVersionAlreadyInstalled, InvalidWheelFilename,
|
||||
UnsupportedWheel,
|
||||
)
|
||||
from pip.download import HAS_TLS, is_url, path_to_url, url_to_path
|
||||
from pip.wheel import Wheel, wheel_ext
|
||||
from pip.pep425tags import supported_tags
|
||||
from pip.pep425tags import get_supported
|
||||
from pip._vendor import html5lib, requests, six
|
||||
from pip._vendor.packaging.version import parse as parse_version
|
||||
from pip._vendor.packaging.utils import canonicalize_name
|
||||
from pip._vendor.packaging import specifiers
|
||||
from pip._vendor.requests.exceptions import SSLError
|
||||
from pip._vendor.distlib.compat import unescape
|
||||
|
||||
|
||||
__all__ = ['FormatControl', 'fmt_ctl_handle_mutual_exclude', 'PackageFinder']
|
||||
|
|
@ -104,12 +107,24 @@ class PackageFinder(object):
|
|||
|
||||
def __init__(self, find_links, index_urls, allow_all_prereleases=False,
|
||||
trusted_hosts=None, process_dependency_links=False,
|
||||
session=None, format_control=None):
|
||||
session=None, format_control=None, platform=None,
|
||||
versions=None, abi=None, implementation=None):
|
||||
"""Create a PackageFinder.
|
||||
|
||||
:param format_control: A FormatControl object or None. Used to control
|
||||
the selection of source packages / binary packages when consulting
|
||||
the index and links.
|
||||
:param platform: A string or None. If None, searches for packages
|
||||
that are supported by the current system. Otherwise, will find
|
||||
packages that can be built on the platform passed in. These
|
||||
packages will only be downloaded for distribution: they will
|
||||
not be built locally.
|
||||
:param versions: A list of strings or None. This is passed directly
|
||||
to pep425tags.py in the get_supported() method.
|
||||
:param abi: A string or None. This is passed directly
|
||||
to pep425tags.py in the get_supported() method.
|
||||
:param implementation: A string or None. This is passed directly
|
||||
to pep425tags.py in the get_supported() method.
|
||||
"""
|
||||
if session is None:
|
||||
raise TypeError(
|
||||
|
|
@ -153,6 +168,14 @@ class PackageFinder(object):
|
|||
# The Session we'll use to make requests
|
||||
self.session = session
|
||||
|
||||
# The valid tags to check potential found wheel candidates against
|
||||
self.valid_tags = get_supported(
|
||||
versions=versions,
|
||||
platform=platform,
|
||||
abi=abi,
|
||||
impl=implementation,
|
||||
)
|
||||
|
||||
# If we don't have TLS enabled, then WARN if anyplace we're looking
|
||||
# relies on TLS.
|
||||
if not HAS_TLS:
|
||||
|
|
@ -175,7 +198,7 @@ class PackageFinder(object):
|
|||
warnings.warn(
|
||||
"Dependency Links processing has been deprecated and will be "
|
||||
"removed in a future release.",
|
||||
RemovedInPip9Warning,
|
||||
RemovedInPip10Warning,
|
||||
)
|
||||
self.dependency_links.extend(links)
|
||||
|
||||
|
|
@ -236,22 +259,22 @@ class PackageFinder(object):
|
|||
If not finding wheels, then sorted by version only.
|
||||
If finding wheels, then the sort order is by version, then:
|
||||
1. existing installs
|
||||
2. wheels ordered via Wheel.support_index_min()
|
||||
2. wheels ordered via Wheel.support_index_min(self.valid_tags)
|
||||
3. source archives
|
||||
Note: it was considered to embed this logic into the Link
|
||||
comparison operators, but then different sdist links
|
||||
with the same version, would have to be considered equal
|
||||
"""
|
||||
support_num = len(supported_tags)
|
||||
support_num = len(self.valid_tags)
|
||||
if candidate.location.is_wheel:
|
||||
# can raise InvalidWheelFilename
|
||||
wheel = Wheel(candidate.location.filename)
|
||||
if not wheel.supported():
|
||||
if not wheel.supported(self.valid_tags):
|
||||
raise UnsupportedWheel(
|
||||
"%s is not a supported wheel for this platform. It "
|
||||
"can't be sorted." % wheel.filename
|
||||
)
|
||||
pri = -(wheel.support_index_min())
|
||||
pri = -(wheel.support_index_min(self.valid_tags))
|
||||
else: # sdist
|
||||
pri = -(support_num)
|
||||
return (candidate.version, pri)
|
||||
|
|
@ -335,7 +358,9 @@ class PackageFinder(object):
|
|||
"""
|
||||
|
||||
def mkurl_pypi_url(url):
|
||||
loc = posixpath.join(url, urllib_parse.quote(project_name.lower()))
|
||||
loc = posixpath.join(
|
||||
url,
|
||||
urllib_parse.quote(canonicalize_name(project_name)))
|
||||
# For maximum compatibility with easy_install, ensure the path
|
||||
# ends in a trailing slash. Although this isn't in the spec
|
||||
# (and PyPI can handle it without the slash) some other index
|
||||
|
|
@ -579,7 +604,6 @@ class PackageFinder(object):
|
|||
|
||||
def _link_package_versions(self, link, search):
|
||||
"""Return an InstallationCandidate or None"""
|
||||
|
||||
version = None
|
||||
if link.egg_fragment:
|
||||
egg_info = link.egg_fragment
|
||||
|
|
@ -610,7 +634,8 @@ class PackageFinder(object):
|
|||
self._log_skipped_link(
|
||||
link, 'wrong project name (not %s)' % search.supplied)
|
||||
return
|
||||
if not wheel.supported():
|
||||
|
||||
if not wheel.supported(self.valid_tags):
|
||||
self._log_skipped_link(
|
||||
link, 'it is not compatible with this Python')
|
||||
return
|
||||
|
|
@ -638,6 +663,18 @@ class PackageFinder(object):
|
|||
self._log_skipped_link(
|
||||
link, 'Python version is incorrect')
|
||||
return
|
||||
try:
|
||||
support_this_python = check_requires_python(link.requires_python)
|
||||
except specifiers.InvalidSpecifier:
|
||||
logger.debug("Package %s has an invalid Requires-Python entry: %s",
|
||||
link.filename, link.requires_python)
|
||||
support_this_python = True
|
||||
|
||||
if not support_this_python:
|
||||
logger.debug("The package %s is incompatible with the python"
|
||||
"version in use. Acceptable python versions are:%s",
|
||||
link, link.requires_python)
|
||||
return
|
||||
logger.debug('Found link %s, version: %s', link, version)
|
||||
|
||||
return InstallationCandidate(search.supplied, version, link)
|
||||
|
|
@ -690,7 +727,7 @@ class HTMLPage(object):
|
|||
self.content = content
|
||||
self.parsed = html5lib.parse(
|
||||
self.content,
|
||||
encoding=encoding,
|
||||
transport_encoding=encoding,
|
||||
namespaceHTMLElements=False,
|
||||
)
|
||||
self.url = url
|
||||
|
|
@ -758,10 +795,10 @@ class HTMLPage(object):
|
|||
resp.raise_for_status()
|
||||
|
||||
# The check for archives above only works if the url ends with
|
||||
# something that looks like an archive. However that is not a
|
||||
# requirement of an url. Unless we issue a HEAD request on every
|
||||
# url we cannot know ahead of time for sure if something is HTML
|
||||
# or not. However we can check after we've downloaded it.
|
||||
# something that looks like an archive. However that is not a
|
||||
# requirement of an url. Unless we issue a HEAD request on every
|
||||
# url we cannot know ahead of time for sure if something is HTML
|
||||
# or not. However we can check after we've downloaded it.
|
||||
content_type = resp.headers.get('Content-Type', 'unknown')
|
||||
if not content_type.lower().startswith("text/html"):
|
||||
logger.debug(
|
||||
|
|
@ -826,7 +863,9 @@ class HTMLPage(object):
|
|||
url = self.clean_link(
|
||||
urllib_parse.urljoin(self.base_url, href)
|
||||
)
|
||||
yield Link(url, self)
|
||||
pyrequire = anchor.get('data-requires-python')
|
||||
pyrequire = unescape(pyrequire) if pyrequire else None
|
||||
yield Link(url, self, requires_python=pyrequire)
|
||||
|
||||
_clean_re = re.compile(r'[^a-z0-9$&+,/:;=?@.#%_\\|-]', re.I)
|
||||
|
||||
|
|
@ -840,7 +879,19 @@ class HTMLPage(object):
|
|||
|
||||
class Link(object):
|
||||
|
||||
def __init__(self, url, comes_from=None):
|
||||
def __init__(self, url, comes_from=None, requires_python=None):
|
||||
"""
|
||||
Object representing a parsed link from https://pypi.python.org/simple/*
|
||||
|
||||
url:
|
||||
url of the resource pointed to (href of the link)
|
||||
comes_from:
|
||||
instance of HTMLPage where the link was found, or string.
|
||||
requires_python:
|
||||
String containing the `Requires-Python` metadata field, specified
|
||||
in PEP 345. This may be specified by a data-requires-python
|
||||
attribute in the HTML link tag, as described in PEP 503.
|
||||
"""
|
||||
|
||||
# url can be a UNC windows share
|
||||
if url.startswith('\\\\'):
|
||||
|
|
@ -848,10 +899,15 @@ class Link(object):
|
|||
|
||||
self.url = url
|
||||
self.comes_from = comes_from
|
||||
self.requires_python = requires_python if requires_python else None
|
||||
|
||||
def __str__(self):
|
||||
if self.requires_python:
|
||||
rp = ' (requires-python:%s)' % self.requires_python
|
||||
else:
|
||||
rp = ''
|
||||
if self.comes_from:
|
||||
return '%s (from %s)' % (self.url, self.comes_from)
|
||||
return '%s (from %s)%s' % (self.url, self.comes_from, rp)
|
||||
else:
|
||||
return str(self.url)
|
||||
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ else:
|
|||
"The folder you are executing pip from can no longer be found."
|
||||
)
|
||||
|
||||
# under Mac OS X + virtualenv sys.prefix is not properly resolved
|
||||
# under macOS + virtualenv sys.prefix is not properly resolved
|
||||
# it is something like /path/to/python/bin/..
|
||||
# Note: using realpath due to tmp dirs on OSX being symlinks
|
||||
src_prefix = os.path.abspath(src_prefix)
|
||||
|
|
@ -110,7 +110,7 @@ else:
|
|||
config_basename,
|
||||
)
|
||||
|
||||
# Forcing to use /usr/local/bin for standard Mac OS X framework installs
|
||||
# Forcing to use /usr/local/bin for standard macOS framework installs
|
||||
# Also log to ~/Library/Logs/ for use with the Console.app log viewer
|
||||
if sys.platform[:6] == 'darwin' and sys.prefix[:16] == '/System/Library/':
|
||||
bin_py = '/usr/local/bin'
|
||||
|
|
|
|||
49
lib/python3.4/site-packages/pip/operations/check.py
Normal file
49
lib/python3.4/site-packages/pip/operations/check.py
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
|
||||
|
||||
def check_requirements(installed_dists):
|
||||
missing_reqs_dict = {}
|
||||
incompatible_reqs_dict = {}
|
||||
|
||||
for dist in installed_dists:
|
||||
key = '%s==%s' % (dist.project_name, dist.version)
|
||||
|
||||
missing_reqs = list(get_missing_reqs(dist, installed_dists))
|
||||
if missing_reqs:
|
||||
missing_reqs_dict[key] = missing_reqs
|
||||
|
||||
incompatible_reqs = list(get_incompatible_reqs(
|
||||
dist, installed_dists))
|
||||
if incompatible_reqs:
|
||||
incompatible_reqs_dict[key] = incompatible_reqs
|
||||
|
||||
return (missing_reqs_dict, incompatible_reqs_dict)
|
||||
|
||||
|
||||
def get_missing_reqs(dist, installed_dists):
|
||||
"""Return all of the requirements of `dist` that aren't present in
|
||||
`installed_dists`.
|
||||
|
||||
"""
|
||||
installed_names = set(d.project_name.lower() for d in installed_dists)
|
||||
missing_requirements = set()
|
||||
|
||||
for requirement in dist.requires():
|
||||
if requirement.project_name.lower() not in installed_names:
|
||||
missing_requirements.add(requirement)
|
||||
yield requirement
|
||||
|
||||
|
||||
def get_incompatible_reqs(dist, installed_dists):
|
||||
"""Return all of the requirements of `dist` that are present in
|
||||
`installed_dists`, but have incompatible versions.
|
||||
|
||||
"""
|
||||
installed_dists_by_name = {}
|
||||
for installed_dist in installed_dists:
|
||||
installed_dists_by_name[installed_dist.project_name] = installed_dist
|
||||
|
||||
for requirement in dist.requires():
|
||||
present_dist = installed_dists_by_name.get(requirement.project_name)
|
||||
|
||||
if present_dist and present_dist not in requirement:
|
||||
yield (requirement, present_dist)
|
||||
|
|
@ -5,9 +5,11 @@ import re
|
|||
|
||||
import pip
|
||||
from pip.req import InstallRequirement
|
||||
from pip.req.req_file import COMMENT_RE
|
||||
from pip.utils import get_installed_distributions
|
||||
from pip._vendor import pkg_resources
|
||||
from pip._vendor.packaging.utils import canonicalize_name
|
||||
from pip._vendor.pkg_resources import RequirementParseError
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
|
@ -42,67 +44,83 @@ def freeze(
|
|||
for dist in get_installed_distributions(local_only=local_only,
|
||||
skip=(),
|
||||
user_only=user_only):
|
||||
req = pip.FrozenRequirement.from_dist(
|
||||
dist,
|
||||
dependency_links
|
||||
)
|
||||
try:
|
||||
req = pip.FrozenRequirement.from_dist(
|
||||
dist,
|
||||
dependency_links
|
||||
)
|
||||
except RequirementParseError:
|
||||
logger.warning(
|
||||
"Could not parse requirement: %s",
|
||||
dist.project_name
|
||||
)
|
||||
continue
|
||||
installations[req.name] = req
|
||||
|
||||
if requirement:
|
||||
with open(requirement) as req_file:
|
||||
for line in req_file:
|
||||
if (not line.strip() or
|
||||
line.strip().startswith('#') or
|
||||
(skip_match and skip_match(line)) or
|
||||
line.startswith((
|
||||
'-r', '--requirement',
|
||||
'-Z', '--always-unzip',
|
||||
'-f', '--find-links',
|
||||
'-i', '--index-url',
|
||||
'--pre',
|
||||
'--trusted-host',
|
||||
'--process-dependency-links',
|
||||
'--extra-index-url'))):
|
||||
yield line.rstrip()
|
||||
continue
|
||||
# the options that don't get turned into an InstallRequirement
|
||||
# should only be emitted once, even if the same option is in multiple
|
||||
# requirements files, so we need to keep track of what has been emitted
|
||||
# so that we don't emit it again if it's seen again
|
||||
emitted_options = set()
|
||||
for req_file_path in requirement:
|
||||
with open(req_file_path) as req_file:
|
||||
for line in req_file:
|
||||
if (not line.strip() or
|
||||
line.strip().startswith('#') or
|
||||
(skip_match and skip_match(line)) or
|
||||
line.startswith((
|
||||
'-r', '--requirement',
|
||||
'-Z', '--always-unzip',
|
||||
'-f', '--find-links',
|
||||
'-i', '--index-url',
|
||||
'--pre',
|
||||
'--trusted-host',
|
||||
'--process-dependency-links',
|
||||
'--extra-index-url'))):
|
||||
line = line.rstrip()
|
||||
if line not in emitted_options:
|
||||
emitted_options.add(line)
|
||||
yield line
|
||||
continue
|
||||
|
||||
if line.startswith('-e') or line.startswith('--editable'):
|
||||
if line.startswith('-e'):
|
||||
line = line[2:].strip()
|
||||
if line.startswith('-e') or line.startswith('--editable'):
|
||||
if line.startswith('-e'):
|
||||
line = line[2:].strip()
|
||||
else:
|
||||
line = line[len('--editable'):].strip().lstrip('=')
|
||||
line_req = InstallRequirement.from_editable(
|
||||
line,
|
||||
default_vcs=default_vcs,
|
||||
isolated=isolated,
|
||||
wheel_cache=wheel_cache,
|
||||
)
|
||||
else:
|
||||
line = line[len('--editable'):].strip().lstrip('=')
|
||||
line_req = InstallRequirement.from_editable(
|
||||
line,
|
||||
default_vcs=default_vcs,
|
||||
isolated=isolated,
|
||||
wheel_cache=wheel_cache,
|
||||
)
|
||||
else:
|
||||
line_req = InstallRequirement.from_line(
|
||||
line,
|
||||
isolated=isolated,
|
||||
wheel_cache=wheel_cache,
|
||||
)
|
||||
line_req = InstallRequirement.from_line(
|
||||
COMMENT_RE.sub('', line).strip(),
|
||||
isolated=isolated,
|
||||
wheel_cache=wheel_cache,
|
||||
)
|
||||
|
||||
if not line_req.name:
|
||||
logger.info(
|
||||
"Skipping line because it's not clear what it "
|
||||
"would install: %s",
|
||||
line.strip(),
|
||||
)
|
||||
logger.info(
|
||||
" (add #egg=PackageName to the URL to avoid"
|
||||
" this warning)"
|
||||
)
|
||||
elif line_req.name not in installations:
|
||||
logger.warning(
|
||||
"Requirement file contains %s, but that package is"
|
||||
" not installed",
|
||||
line.strip(),
|
||||
)
|
||||
else:
|
||||
yield str(installations[line_req.name]).rstrip()
|
||||
del installations[line_req.name]
|
||||
if not line_req.name:
|
||||
logger.info(
|
||||
"Skipping line in requirement file [%s] because "
|
||||
"it's not clear what it would install: %s",
|
||||
req_file_path, line.strip(),
|
||||
)
|
||||
logger.info(
|
||||
" (add #egg=PackageName to the URL to avoid"
|
||||
" this warning)"
|
||||
)
|
||||
elif line_req.name not in installations:
|
||||
logger.warning(
|
||||
"Requirement file [%s] contains %s, but that "
|
||||
"package is not installed",
|
||||
req_file_path, COMMENT_RE.sub('', line).strip(),
|
||||
)
|
||||
else:
|
||||
yield str(installations[line_req.name]).rstrip()
|
||||
del installations[line_req.name]
|
||||
|
||||
yield(
|
||||
'## The following requirements were added by '
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import sys
|
|||
import warnings
|
||||
import platform
|
||||
import logging
|
||||
import ctypes
|
||||
|
||||
try:
|
||||
import sysconfig
|
||||
|
|
@ -16,7 +15,7 @@ except ImportError: # pragma nocover
|
|||
import distutils.util
|
||||
|
||||
from pip.compat import OrderedDict
|
||||
|
||||
import pip.utils.glibc
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -125,7 +124,7 @@ def get_platform():
|
|||
if sys.platform == 'darwin':
|
||||
# distutils.util.get_platform() returns the release based on the value
|
||||
# of MACOSX_DEPLOYMENT_TARGET on which Python was built, which may
|
||||
# be signficantly older than the user's current machine.
|
||||
# be significantly older than the user's current machine.
|
||||
release, _, machine = platform.mac_ver()
|
||||
split_ver = release.split('.')
|
||||
|
||||
|
|
@ -160,46 +159,17 @@ def is_manylinux1_compatible():
|
|||
pass
|
||||
|
||||
# Check glibc version. CentOS 5 uses glibc 2.5.
|
||||
return have_compatible_glibc(2, 5)
|
||||
|
||||
|
||||
def have_compatible_glibc(major, minimum_minor):
|
||||
# ctypes.CDLL(None) internally calls dlopen(NULL), and as the dlopen
|
||||
# manpage says, "If filename is NULL, then the returned handle is for the
|
||||
# main program". This way we can let the linker do the work to figure out
|
||||
# which libc our process is actually using.
|
||||
process_namespace = ctypes.CDLL(None)
|
||||
try:
|
||||
gnu_get_libc_version = process_namespace.gnu_get_libc_version
|
||||
except AttributeError:
|
||||
# Symbol doesn't exist -> therefore, we are not linked to
|
||||
# glibc.
|
||||
return False
|
||||
|
||||
# Call gnu_get_libc_version, which returns a string like "2.5".
|
||||
gnu_get_libc_version.restype = ctypes.c_char_p
|
||||
version_str = gnu_get_libc_version()
|
||||
# py2 / py3 compatibility:
|
||||
if not isinstance(version_str, str):
|
||||
version_str = version_str.decode("ascii")
|
||||
|
||||
# Parse string and check against requested version.
|
||||
version = [int(piece) for piece in version_str.split(".")]
|
||||
if len(version) < 2:
|
||||
warnings.warn("Expected glibc version with 2 components major.minor,"
|
||||
" got: %s" % version_str, RuntimeWarning)
|
||||
return False
|
||||
return version[0] == major and version[1] >= minimum_minor
|
||||
return pip.utils.glibc.have_compatible_glibc(2, 5)
|
||||
|
||||
|
||||
def get_darwin_arches(major, minor, machine):
|
||||
"""Return a list of supported arches (including group arches) for
|
||||
the given major, minor and machine architecture of an OS X machine.
|
||||
the given major, minor and machine architecture of an macOS machine.
|
||||
"""
|
||||
arches = []
|
||||
|
||||
def _supports_arch(major, minor, arch):
|
||||
# Looking at the application support for OS X versions in the chart
|
||||
# Looking at the application support for macOS versions in the chart
|
||||
# provided by https://en.wikipedia.org/wiki/OS_X#Versions it appears
|
||||
# our timeline looks roughly like:
|
||||
#
|
||||
|
|
@ -253,12 +223,19 @@ def get_darwin_arches(major, minor, machine):
|
|||
return arches
|
||||
|
||||
|
||||
def get_supported(versions=None, noarch=False):
|
||||
def get_supported(versions=None, noarch=False, platform=None,
|
||||
impl=None, abi=None):
|
||||
"""Return a list of supported tags for each version specified in
|
||||
`versions`.
|
||||
|
||||
:param versions: a list of string versions, of the form ["33", "32"],
|
||||
or None. The first version will be assumed to support our ABI.
|
||||
:param platform: specify the exact platform you want valid
|
||||
tags for, or None. If None, use the local system platform.
|
||||
:param impl: specify the exact implementation you want valid
|
||||
tags for, or None. If None, use the local interpreter impl.
|
||||
:param abi: specify the exact abi you want valid
|
||||
tags for, or None. If None, use the local interpreter abi.
|
||||
"""
|
||||
supported = []
|
||||
|
||||
|
|
@ -271,11 +248,11 @@ def get_supported(versions=None, noarch=False):
|
|||
for minor in range(version_info[-1], -1, -1):
|
||||
versions.append(''.join(map(str, major + (minor,))))
|
||||
|
||||
impl = get_abbr_impl()
|
||||
impl = impl or get_abbr_impl()
|
||||
|
||||
abis = []
|
||||
|
||||
abi = get_abi_tag()
|
||||
abi = abi or get_abi_tag()
|
||||
if abi:
|
||||
abis[0:0] = [abi]
|
||||
|
||||
|
|
@ -290,8 +267,8 @@ def get_supported(versions=None, noarch=False):
|
|||
abis.append('none')
|
||||
|
||||
if not noarch:
|
||||
arch = get_platform()
|
||||
if sys.platform == 'darwin':
|
||||
arch = platform or get_platform()
|
||||
if arch.startswith('macosx'):
|
||||
# support macosx-10.6-intel on macosx-10.9-x86_64
|
||||
match = _osx_arch_pat.match(arch)
|
||||
if match:
|
||||
|
|
@ -304,7 +281,7 @@ def get_supported(versions=None, noarch=False):
|
|||
else:
|
||||
# arch pattern didn't match (?!)
|
||||
arches = [arch]
|
||||
elif is_manylinux1_compatible():
|
||||
elif platform is None and is_manylinux1_compatible():
|
||||
arches = [arch.replace('linux', 'manylinux1'), arch]
|
||||
else:
|
||||
arches = [arch]
|
||||
|
|
@ -314,6 +291,15 @@ def get_supported(versions=None, noarch=False):
|
|||
for arch in arches:
|
||||
supported.append(('%s%s' % (impl, versions[0]), abi, arch))
|
||||
|
||||
# abi3 modules compatible with older version of Python
|
||||
for version in versions[1:]:
|
||||
# abi3 was introduced in Python 3.2
|
||||
if version in ('31', '30'):
|
||||
break
|
||||
for abi in abi3s: # empty set if not Python 3
|
||||
for arch in arches:
|
||||
supported.append(("%s%s" % (impl, version), abi, arch))
|
||||
|
||||
# Has binaries, does not use the Python API:
|
||||
for arch in arches:
|
||||
supported.append(('py%s' % (versions[0][0]), 'none', arch))
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ def process_line(line, filename, line_number, finder=None, comes_from=None,
|
|||
defaults.format_control = finder.format_control
|
||||
args_str, options_str = break_args_options(line)
|
||||
if sys.version_info < (2, 7, 3):
|
||||
# Priori to 2.7.3, shlex can not deal with unicode entries
|
||||
# Prior to 2.7.3, shlex cannot deal with unicode entries
|
||||
options_str = options_str.encode('utf8')
|
||||
opts, _ = parser.parse_args(shlex.split(options_str), defaults)
|
||||
|
||||
|
|
|
|||
|
|
@ -15,9 +15,11 @@ from distutils.util import change_root
|
|||
from email.parser import FeedParser
|
||||
|
||||
from pip._vendor import pkg_resources, six
|
||||
from pip._vendor.distlib.markers import interpret as markers_interpret
|
||||
from pip._vendor.packaging import specifiers
|
||||
from pip._vendor.packaging.markers import Marker
|
||||
from pip._vendor.packaging.requirements import InvalidRequirement, Requirement
|
||||
from pip._vendor.packaging.utils import canonicalize_name
|
||||
from pip._vendor.packaging.version import Version, parse as parse_version
|
||||
from pip._vendor.six.moves import configparser
|
||||
|
||||
import pip.wheel
|
||||
|
|
@ -25,7 +27,7 @@ import pip.wheel
|
|||
from pip.compat import native_str, get_stdlib, WINDOWS
|
||||
from pip.download import is_url, url_to_path, path_to_url, is_archive_file
|
||||
from pip.exceptions import (
|
||||
InstallationError, UninstallationError, UnsupportedWheel,
|
||||
InstallationError, UninstallationError,
|
||||
)
|
||||
from pip.locations import (
|
||||
bin_py, running_under_virtualenv, PIP_DELETE_MARKER_FILENAME, bin_user,
|
||||
|
|
@ -38,14 +40,13 @@ from pip.utils import (
|
|||
)
|
||||
|
||||
from pip.utils.hashes import Hashes
|
||||
from pip.utils.deprecation import RemovedInPip9Warning, RemovedInPip10Warning
|
||||
from pip.utils.deprecation import RemovedInPip10Warning
|
||||
from pip.utils.logging import indent_log
|
||||
from pip.utils.setuptools_build import SETUPTOOLS_SHIM
|
||||
from pip.utils.ui import open_spinner
|
||||
from pip.req.req_uninstall import UninstallPathSet
|
||||
from pip.vcs import vcs
|
||||
from pip.wheel import move_wheel_files, Wheel
|
||||
from pip._vendor.packaging.version import Version
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
|
@ -65,6 +66,10 @@ def _strip_extras(path):
|
|||
return path_no_extras, extras
|
||||
|
||||
|
||||
def _safe_extras(extras):
|
||||
return set(pkg_resources.safe_extra(extra) for extra in extras)
|
||||
|
||||
|
||||
class InstallRequirement(object):
|
||||
|
||||
def __init__(self, req, comes_from, source_dir=None, editable=False,
|
||||
|
|
@ -74,8 +79,8 @@ class InstallRequirement(object):
|
|||
self.extras = ()
|
||||
if isinstance(req, six.string_types):
|
||||
try:
|
||||
req = pkg_resources.Requirement.parse(req)
|
||||
except pkg_resources.RequirementParseError:
|
||||
req = Requirement(req)
|
||||
except InvalidRequirement:
|
||||
if os.path.sep in req:
|
||||
add_msg = "It looks like a path. Does it exist ?"
|
||||
elif '=' in req and not any(op in req for op in operators):
|
||||
|
|
@ -84,7 +89,7 @@ class InstallRequirement(object):
|
|||
add_msg = traceback.format_exc()
|
||||
raise InstallationError(
|
||||
"Invalid requirement: '%s'\n%s" % (req, add_msg))
|
||||
self.extras = req.extras
|
||||
self.extras = _safe_extras(req.extras)
|
||||
|
||||
self.req = req
|
||||
self.comes_from = comes_from
|
||||
|
|
@ -95,7 +100,10 @@ class InstallRequirement(object):
|
|||
self._wheel_cache = wheel_cache
|
||||
self.link = self.original_link = link
|
||||
self.as_egg = as_egg
|
||||
self.markers = markers
|
||||
if markers is not None:
|
||||
self.markers = markers
|
||||
else:
|
||||
self.markers = req and req.marker
|
||||
self._egg_info_path = None
|
||||
# This holds the pkg_resources.Distribution object if this requirement
|
||||
# is already available:
|
||||
|
|
@ -148,7 +156,7 @@ class InstallRequirement(object):
|
|||
wheel_cache=wheel_cache)
|
||||
|
||||
if extras_override is not None:
|
||||
res.extras = extras_override
|
||||
res.extras = _safe_extras(extras_override)
|
||||
|
||||
return res
|
||||
|
||||
|
|
@ -170,6 +178,8 @@ class InstallRequirement(object):
|
|||
markers = markers.strip()
|
||||
if not markers:
|
||||
markers = None
|
||||
else:
|
||||
markers = Marker(markers)
|
||||
else:
|
||||
markers = None
|
||||
name = name.strip()
|
||||
|
|
@ -209,11 +219,6 @@ class InstallRequirement(object):
|
|||
# wheel file
|
||||
if link.is_wheel:
|
||||
wheel = Wheel(link.filename) # can raise InvalidWheelFilename
|
||||
if not wheel.supported():
|
||||
raise UnsupportedWheel(
|
||||
"%s is not a supported wheel on this platform." %
|
||||
wheel.filename
|
||||
)
|
||||
req = "%s==%s" % (wheel.name, wheel.version)
|
||||
else:
|
||||
# set the req to the egg fragment. when it's not there, this
|
||||
|
|
@ -230,8 +235,8 @@ class InstallRequirement(object):
|
|||
wheel_cache=wheel_cache, constraint=constraint)
|
||||
|
||||
if extras:
|
||||
res.extras = pkg_resources.Requirement.parse('__placeholder__' +
|
||||
extras).extras
|
||||
res.extras = _safe_extras(
|
||||
Requirement('placeholder' + extras).extras)
|
||||
|
||||
return res
|
||||
|
||||
|
|
@ -312,7 +317,12 @@ class InstallRequirement(object):
|
|||
# package is not available yet so we create a temp directory
|
||||
# Once run_egg_info will have run, we'll be able
|
||||
# to fix it via _correct_build_location
|
||||
self._temp_build_dir = tempfile.mkdtemp('-build', 'pip-')
|
||||
# Some systems have /tmp as a symlink which confuses custom
|
||||
# builds (such as numpy). Thus, we ensure that the real path
|
||||
# is returned.
|
||||
self._temp_build_dir = os.path.realpath(
|
||||
tempfile.mkdtemp('-build', 'pip-')
|
||||
)
|
||||
self._ideal_build_dir = build_dir
|
||||
return self._temp_build_dir
|
||||
if self.editable:
|
||||
|
|
@ -362,7 +372,7 @@ class InstallRequirement(object):
|
|||
def name(self):
|
||||
if self.req is None:
|
||||
return None
|
||||
return native_str(self.req.project_name)
|
||||
return native_str(pkg_resources.safe_name(self.req.name))
|
||||
|
||||
@property
|
||||
def setup_py_dir(self):
|
||||
|
|
@ -426,33 +436,31 @@ class InstallRequirement(object):
|
|||
egg_info_cmd + egg_base_option,
|
||||
cwd=self.setup_py_dir,
|
||||
show_stdout=False,
|
||||
command_level=logging.DEBUG,
|
||||
command_desc='python setup.py egg_info')
|
||||
|
||||
if not self.req:
|
||||
if isinstance(
|
||||
pkg_resources.parse_version(self.pkg_info()["Version"]),
|
||||
Version):
|
||||
if isinstance(parse_version(self.pkg_info()["Version"]), Version):
|
||||
op = "=="
|
||||
else:
|
||||
op = "==="
|
||||
self.req = pkg_resources.Requirement.parse(
|
||||
self.req = Requirement(
|
||||
"".join([
|
||||
self.pkg_info()["Name"],
|
||||
op,
|
||||
self.pkg_info()["Version"],
|
||||
]))
|
||||
])
|
||||
)
|
||||
self._correct_build_location()
|
||||
else:
|
||||
metadata_name = canonicalize_name(self.pkg_info()["Name"])
|
||||
if canonicalize_name(self.req.project_name) != metadata_name:
|
||||
if canonicalize_name(self.req.name) != metadata_name:
|
||||
logger.warning(
|
||||
'Running setup.py (path:%s) egg_info for package %s '
|
||||
'produced metadata for project name %s. Fix your '
|
||||
'#egg=%s fragments.',
|
||||
self.setup_py, self.name, metadata_name, self.name
|
||||
)
|
||||
self.req = pkg_resources.Requirement.parse(metadata_name)
|
||||
self.req = Requirement(metadata_name)
|
||||
|
||||
def egg_info_data(self, filename):
|
||||
if self.satisfied_by is not None:
|
||||
|
|
@ -486,7 +494,7 @@ class InstallRequirement(object):
|
|||
# Don't search in anything that looks like a virtualenv
|
||||
# environment
|
||||
if (
|
||||
os.path.exists(
|
||||
os.path.lexists(
|
||||
os.path.join(root, dir, 'bin', 'python')
|
||||
) or
|
||||
os.path.exists(
|
||||
|
|
@ -540,7 +548,7 @@ class InstallRequirement(object):
|
|||
def assert_source_matches_version(self):
|
||||
assert self.source_dir
|
||||
version = self.pkg_info()['version']
|
||||
if version not in self.req:
|
||||
if self.req.specifier and version not in self.req.specifier:
|
||||
logger.warning(
|
||||
'Requested %s, but installing version %s',
|
||||
self,
|
||||
|
|
@ -682,6 +690,10 @@ class InstallRequirement(object):
|
|||
'easy-install.pth')
|
||||
paths_to_remove.add_pth(easy_install_pth, './' + easy_install_egg)
|
||||
|
||||
elif egg_info_exists and dist.egg_info.endswith('.dist-info'):
|
||||
for path in pip.wheel.uninstallation_paths(dist):
|
||||
paths_to_remove.add(path)
|
||||
|
||||
elif develop_egg_link:
|
||||
# develop egg
|
||||
with open(develop_egg_link, 'r') as fh:
|
||||
|
|
@ -695,10 +707,6 @@ class InstallRequirement(object):
|
|||
'easy-install.pth')
|
||||
paths_to_remove.add_pth(easy_install_pth, dist.location)
|
||||
|
||||
elif egg_info_exists and dist.egg_info.endswith('.dist-info'):
|
||||
for path in pip.wheel.uninstallation_paths(dist):
|
||||
paths_to_remove.add(path)
|
||||
|
||||
else:
|
||||
logger.debug(
|
||||
'Not sure how to uninstall: %s - Check: %s',
|
||||
|
|
@ -769,8 +777,8 @@ class InstallRequirement(object):
|
|||
archive_path = os.path.join(build_dir, archive_name)
|
||||
if os.path.exists(archive_path):
|
||||
response = ask_path_exists(
|
||||
'The file %s exists. (i)gnore, (w)ipe, (b)ackup ' %
|
||||
display_path(archive_path), ('i', 'w', 'b'))
|
||||
'The file %s exists. (i)gnore, (w)ipe, (b)ackup, (a)bort ' %
|
||||
display_path(archive_path), ('i', 'w', 'b', 'a'))
|
||||
if response == 'i':
|
||||
create_archive = False
|
||||
elif response == 'w':
|
||||
|
|
@ -784,6 +792,8 @@ class InstallRequirement(object):
|
|||
display_path(dest_file),
|
||||
)
|
||||
shutil.move(archive_path, dest_file)
|
||||
elif response == 'a':
|
||||
sys.exit(-1)
|
||||
if create_archive:
|
||||
zip = zipfile.ZipFile(
|
||||
archive_path, 'w', zipfile.ZIP_DEFLATED,
|
||||
|
|
@ -816,9 +826,15 @@ class InstallRequirement(object):
|
|||
name = name.replace(os.path.sep, '/')
|
||||
return name
|
||||
|
||||
def match_markers(self):
|
||||
def match_markers(self, extras_requested=None):
|
||||
if not extras_requested:
|
||||
# Provide an extra to safely evaluate the markers
|
||||
# without matching any extra
|
||||
extras_requested = ('',)
|
||||
if self.markers is not None:
|
||||
return markers_interpret(self.markers)
|
||||
return any(
|
||||
self.markers.evaluate({'extra': extra})
|
||||
for extra in extras_requested)
|
||||
else:
|
||||
return True
|
||||
|
||||
|
|
@ -850,30 +866,8 @@ class InstallRequirement(object):
|
|||
temp_location = tempfile.mkdtemp('-record', 'pip-')
|
||||
record_filename = os.path.join(temp_location, 'install-record.txt')
|
||||
try:
|
||||
install_args = [sys.executable, "-u"]
|
||||
install_args.append('-c')
|
||||
install_args.append(SETUPTOOLS_SHIM % self.setup_py)
|
||||
install_args += list(global_options) + \
|
||||
['install', '--record', record_filename]
|
||||
|
||||
if not self.as_egg:
|
||||
install_args += ['--single-version-externally-managed']
|
||||
|
||||
if root is not None:
|
||||
install_args += ['--root', root]
|
||||
if prefix is not None:
|
||||
install_args += ['--prefix', prefix]
|
||||
|
||||
if self.pycompile:
|
||||
install_args += ["--compile"]
|
||||
else:
|
||||
install_args += ["--no-compile"]
|
||||
|
||||
if running_under_virtualenv():
|
||||
py_ver_str = 'python' + sysconfig.get_python_version()
|
||||
install_args += ['--install-headers',
|
||||
os.path.join(sys.prefix, 'include', 'site',
|
||||
py_ver_str, self.name)]
|
||||
install_args = self.get_install_args(
|
||||
global_options, record_filename, root, prefix)
|
||||
msg = 'Running setup.py install for %s' % (self.name,)
|
||||
with open_spinner(msg) as spinner:
|
||||
with indent_log():
|
||||
|
|
@ -946,6 +940,34 @@ class InstallRequirement(object):
|
|||
self.source_dir = self.build_location(parent_dir)
|
||||
return self.source_dir
|
||||
|
||||
def get_install_args(self, global_options, record_filename, root, prefix):
|
||||
install_args = [sys.executable, "-u"]
|
||||
install_args.append('-c')
|
||||
install_args.append(SETUPTOOLS_SHIM % self.setup_py)
|
||||
install_args += list(global_options) + \
|
||||
['install', '--record', record_filename]
|
||||
|
||||
if not self.as_egg:
|
||||
install_args += ['--single-version-externally-managed']
|
||||
|
||||
if root is not None:
|
||||
install_args += ['--root', root]
|
||||
if prefix is not None:
|
||||
install_args += ['--prefix', prefix]
|
||||
|
||||
if self.pycompile:
|
||||
install_args += ["--compile"]
|
||||
else:
|
||||
install_args += ["--no-compile"]
|
||||
|
||||
if running_under_virtualenv():
|
||||
py_ver_str = 'python' + sysconfig.get_python_version()
|
||||
install_args += ['--install-headers',
|
||||
os.path.join(sys.prefix, 'include', 'site',
|
||||
py_ver_str, self.name)]
|
||||
|
||||
return install_args
|
||||
|
||||
def remove_temporary_source(self):
|
||||
"""Remove the source files from this requirement, if they are marked
|
||||
for deletion"""
|
||||
|
|
@ -994,12 +1016,24 @@ class InstallRequirement(object):
|
|||
if self.req is None:
|
||||
return False
|
||||
try:
|
||||
self.satisfied_by = pkg_resources.get_distribution(self.req)
|
||||
# get_distribution() will resolve the entire list of requirements
|
||||
# anyway, and we've already determined that we need the requirement
|
||||
# in question, so strip the marker so that we don't try to
|
||||
# evaluate it.
|
||||
no_marker = Requirement(str(self.req))
|
||||
no_marker.marker = None
|
||||
self.satisfied_by = pkg_resources.get_distribution(str(no_marker))
|
||||
if self.editable and self.satisfied_by:
|
||||
self.conflicts_with = self.satisfied_by
|
||||
# when installing editables, nothing pre-existing should ever
|
||||
# satisfy
|
||||
self.satisfied_by = None
|
||||
return True
|
||||
except pkg_resources.DistributionNotFound:
|
||||
return False
|
||||
except pkg_resources.VersionConflict:
|
||||
existing_dist = pkg_resources.get_distribution(
|
||||
self.req.project_name
|
||||
self.req.name
|
||||
)
|
||||
if self.use_user_site:
|
||||
if dist_in_usersite(existing_dist):
|
||||
|
|
@ -1085,24 +1119,6 @@ def _strip_postfix(req):
|
|||
return req
|
||||
|
||||
|
||||
def _build_req_from_url(url):
|
||||
|
||||
parts = [p for p in url.split('#', 1)[0].split('/') if p]
|
||||
|
||||
req = None
|
||||
if len(parts) > 2 and parts[-2] in ('tags', 'branches', 'tag', 'branch'):
|
||||
req = parts[-3]
|
||||
elif len(parts) > 1 and parts[-1] == 'trunk':
|
||||
req = parts[-2]
|
||||
if req:
|
||||
warnings.warn(
|
||||
'Sniffing the requirement name from the url is deprecated and '
|
||||
'will be removed in the future. Please specify an #egg segment '
|
||||
'instead.', RemovedInPip9Warning,
|
||||
stacklevel=2)
|
||||
return req
|
||||
|
||||
|
||||
def parse_editable(editable_req, default_vcs=None):
|
||||
"""Parses an editable requirement into:
|
||||
- a requirement name
|
||||
|
|
@ -1142,9 +1158,7 @@ def parse_editable(editable_req, default_vcs=None):
|
|||
return (
|
||||
package_name,
|
||||
url_no_extras,
|
||||
pkg_resources.Requirement.parse(
|
||||
'__placeholder__' + extras
|
||||
).extras,
|
||||
Requirement("placeholder" + extras.lower()).extras,
|
||||
)
|
||||
else:
|
||||
return package_name, url_no_extras, None
|
||||
|
|
@ -1156,6 +1170,11 @@ def parse_editable(editable_req, default_vcs=None):
|
|||
|
||||
if '+' not in url:
|
||||
if default_vcs:
|
||||
warnings.warn(
|
||||
"--default-vcs has been deprecated and will be removed in "
|
||||
"the future.",
|
||||
RemovedInPip10Warning,
|
||||
)
|
||||
url = default_vcs + '+' + url
|
||||
else:
|
||||
raise InstallationError(
|
||||
|
|
@ -1174,7 +1193,9 @@ def parse_editable(editable_req, default_vcs=None):
|
|||
|
||||
package_name = Link(url).egg_fragment
|
||||
if not package_name:
|
||||
package_name = _build_req_from_url(editable_req)
|
||||
raise InstallationError(
|
||||
"Could not detect requirement name, please specify one with #egg="
|
||||
)
|
||||
if not package_name:
|
||||
raise InstallationError(
|
||||
'--editable=%s is not the right format; it must have '
|
||||
|
|
|
|||
|
|
@ -14,14 +14,16 @@ from pip.download import (is_file_url, is_dir_url, is_vcs_url, url_to_path,
|
|||
from pip.exceptions import (InstallationError, BestVersionAlreadyInstalled,
|
||||
DistributionNotFound, PreviousBuildDirError,
|
||||
HashError, HashErrors, HashUnpinned,
|
||||
DirectoryUrlHashUnsupported, VcsHashUnsupported)
|
||||
DirectoryUrlHashUnsupported, VcsHashUnsupported,
|
||||
UnsupportedPythonVersion)
|
||||
from pip.req.req_install import InstallRequirement
|
||||
from pip.utils import (
|
||||
display_path, dist_in_usersite, ensure_dir, normalize_path)
|
||||
from pip.utils.hashes import MissingHashes
|
||||
from pip.utils.logging import indent_log
|
||||
from pip.utils.packaging import check_dist_requires_python
|
||||
from pip.vcs import vcs
|
||||
|
||||
from pip.wheel import Wheel
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -140,11 +142,12 @@ class Installed(DistAbstraction):
|
|||
class RequirementSet(object):
|
||||
|
||||
def __init__(self, build_dir, src_dir, download_dir, upgrade=False,
|
||||
ignore_installed=False, as_egg=False, target_dir=None,
|
||||
ignore_dependencies=False, force_reinstall=False,
|
||||
use_user_site=False, session=None, pycompile=True,
|
||||
isolated=False, wheel_download_dir=None,
|
||||
wheel_cache=None, require_hashes=False):
|
||||
upgrade_strategy=None, ignore_installed=False, as_egg=False,
|
||||
target_dir=None, ignore_dependencies=False,
|
||||
force_reinstall=False, use_user_site=False, session=None,
|
||||
pycompile=True, isolated=False, wheel_download_dir=None,
|
||||
wheel_cache=None, require_hashes=False,
|
||||
ignore_requires_python=False):
|
||||
"""Create a RequirementSet.
|
||||
|
||||
:param wheel_download_dir: Where still-packed .whl files should be
|
||||
|
|
@ -170,6 +173,7 @@ class RequirementSet(object):
|
|||
# the wheelhouse output by 'pip wheel'.
|
||||
self.download_dir = download_dir
|
||||
self.upgrade = upgrade
|
||||
self.upgrade_strategy = upgrade_strategy
|
||||
self.ignore_installed = ignore_installed
|
||||
self.force_reinstall = force_reinstall
|
||||
self.requirements = Requirements()
|
||||
|
|
@ -177,6 +181,7 @@ class RequirementSet(object):
|
|||
self.requirement_aliases = {}
|
||||
self.unnamed_requirements = []
|
||||
self.ignore_dependencies = ignore_dependencies
|
||||
self.ignore_requires_python = ignore_requires_python
|
||||
self.successfully_downloaded = []
|
||||
self.successfully_installed = []
|
||||
self.reqs_to_cleanup = []
|
||||
|
|
@ -207,7 +212,8 @@ class RequirementSet(object):
|
|||
return ('<%s object; %d requirement(s): %s>'
|
||||
% (self.__class__.__name__, len(reqs), reqs_str))
|
||||
|
||||
def add_requirement(self, install_req, parent_req_name=None):
|
||||
def add_requirement(self, install_req, parent_req_name=None,
|
||||
extras_requested=None):
|
||||
"""Add install_req as a requirement to install.
|
||||
|
||||
:param parent_req_name: The name of the requirement that needed this
|
||||
|
|
@ -216,21 +222,35 @@ class RequirementSet(object):
|
|||
links that point outside the Requirements set. parent_req must
|
||||
already be added. Note that None implies that this is a user
|
||||
supplied requirement, vs an inferred one.
|
||||
:param extras_requested: an iterable of extras used to evaluate the
|
||||
environement markers.
|
||||
:return: Additional requirements to scan. That is either [] if
|
||||
the requirement is not applicable, or [install_req] if the
|
||||
requirement is applicable and has just been added.
|
||||
"""
|
||||
name = install_req.name
|
||||
if not install_req.match_markers():
|
||||
logger.warning("Ignoring %s: markers %r don't match your "
|
||||
if not install_req.match_markers(extras_requested):
|
||||
logger.warning("Ignoring %s: markers '%s' don't match your "
|
||||
"environment", install_req.name,
|
||||
install_req.markers)
|
||||
return []
|
||||
|
||||
# This check has to come after we filter requirements with the
|
||||
# environment markers.
|
||||
if install_req.link and install_req.link.is_wheel:
|
||||
wheel = Wheel(install_req.link.filename)
|
||||
if not wheel.supported():
|
||||
raise InstallationError(
|
||||
"%s is not a supported wheel on this platform." %
|
||||
wheel.filename
|
||||
)
|
||||
|
||||
install_req.as_egg = self.as_egg
|
||||
install_req.use_user_site = self.use_user_site
|
||||
install_req.target_dir = self.target_dir
|
||||
install_req.pycompile = self.pycompile
|
||||
install_req.is_direct = (parent_req_name is None)
|
||||
|
||||
if not name:
|
||||
# url or path requirement w/o an egg fragment
|
||||
self.unnamed_requirements.append(install_req)
|
||||
|
|
@ -243,7 +263,7 @@ class RequirementSet(object):
|
|||
if (parent_req_name is None and existing_req and not
|
||||
existing_req.constraint and
|
||||
existing_req.extras == install_req.extras and not
|
||||
existing_req.req.specs == install_req.req.specs):
|
||||
existing_req.req.specifier == install_req.req.specifier):
|
||||
raise InstallationError(
|
||||
'Double requirement given: %s (already in %s, name=%r)'
|
||||
% (install_req, existing_req, name))
|
||||
|
|
@ -365,6 +385,13 @@ class RequirementSet(object):
|
|||
if hash_errors:
|
||||
raise hash_errors
|
||||
|
||||
def _is_upgrade_allowed(self, req):
|
||||
return self.upgrade and (
|
||||
self.upgrade_strategy == "eager" or (
|
||||
self.upgrade_strategy == "only-if-needed" and req.is_direct
|
||||
)
|
||||
)
|
||||
|
||||
def _check_skip_installed(self, req_to_install, finder):
|
||||
"""Check if req_to_install should be skipped.
|
||||
|
||||
|
|
@ -386,17 +413,20 @@ class RequirementSet(object):
|
|||
# Check whether to upgrade/reinstall this req or not.
|
||||
req_to_install.check_if_exists()
|
||||
if req_to_install.satisfied_by:
|
||||
skip_reason = 'satisfied (use --upgrade to upgrade)'
|
||||
if self.upgrade:
|
||||
best_installed = False
|
||||
upgrade_allowed = self._is_upgrade_allowed(req_to_install)
|
||||
|
||||
# Is the best version is installed.
|
||||
best_installed = False
|
||||
|
||||
if upgrade_allowed:
|
||||
# For link based requirements we have to pull the
|
||||
# tree down and inspect to assess the version #, so
|
||||
# its handled way down.
|
||||
if not (self.force_reinstall or req_to_install.link):
|
||||
try:
|
||||
finder.find_requirement(req_to_install, self.upgrade)
|
||||
finder.find_requirement(
|
||||
req_to_install, upgrade_allowed)
|
||||
except BestVersionAlreadyInstalled:
|
||||
skip_reason = 'up-to-date'
|
||||
best_installed = True
|
||||
except DistributionNotFound:
|
||||
# No distribution found, so we squash the
|
||||
|
|
@ -413,6 +443,15 @@ class RequirementSet(object):
|
|||
req_to_install.conflicts_with = \
|
||||
req_to_install.satisfied_by
|
||||
req_to_install.satisfied_by = None
|
||||
|
||||
# Figure out a nice message to say why we're skipping this.
|
||||
if best_installed:
|
||||
skip_reason = 'already up-to-date'
|
||||
elif self.upgrade_strategy == "only-if-needed":
|
||||
skip_reason = 'not upgraded as not directly required'
|
||||
else:
|
||||
skip_reason = 'already satisfied'
|
||||
|
||||
return skip_reason
|
||||
else:
|
||||
return None
|
||||
|
|
@ -453,7 +492,7 @@ class RequirementSet(object):
|
|||
'req_to_install.satisfied_by is set to %r'
|
||||
% (req_to_install.satisfied_by,))
|
||||
logger.info(
|
||||
'Requirement already %s: %s', skip_reason,
|
||||
'Requirement %s: %s', skip_reason,
|
||||
req_to_install)
|
||||
else:
|
||||
if (req_to_install.link and
|
||||
|
|
@ -479,6 +518,7 @@ class RequirementSet(object):
|
|||
abstract_dist.prep_for_dist()
|
||||
if self.is_download:
|
||||
req_to_install.archive(self.download_dir)
|
||||
req_to_install.check_if_exists()
|
||||
elif req_to_install.satisfied_by:
|
||||
if require_hashes:
|
||||
logger.debug(
|
||||
|
|
@ -509,7 +549,10 @@ class RequirementSet(object):
|
|||
% (req_to_install, req_to_install.source_dir)
|
||||
)
|
||||
req_to_install.populate_link(
|
||||
finder, self.upgrade, require_hashes)
|
||||
finder,
|
||||
self._is_upgrade_allowed(req_to_install),
|
||||
require_hashes
|
||||
)
|
||||
# We can't hit this spot and have populate_link return None.
|
||||
# req_to_install.satisfied_by is None here (because we're
|
||||
# guarded) and upgrade has no impact except when satisfied_by
|
||||
|
|
@ -619,9 +662,17 @@ class RequirementSet(object):
|
|||
# # parse dependencies # #
|
||||
# ###################### #
|
||||
dist = abstract_dist.dist(finder)
|
||||
try:
|
||||
check_dist_requires_python(dist)
|
||||
except UnsupportedPythonVersion as e:
|
||||
if self.ignore_requires_python:
|
||||
logger.warning(e.args[0])
|
||||
else:
|
||||
req_to_install.remove_temporary_source()
|
||||
raise
|
||||
more_reqs = []
|
||||
|
||||
def add_req(subreq):
|
||||
def add_req(subreq, extras_requested):
|
||||
sub_install_req = InstallRequirement(
|
||||
str(subreq),
|
||||
req_to_install,
|
||||
|
|
@ -629,7 +680,8 @@ class RequirementSet(object):
|
|||
wheel_cache=self._wheel_cache,
|
||||
)
|
||||
more_reqs.extend(self.add_requirement(
|
||||
sub_install_req, req_to_install.name))
|
||||
sub_install_req, req_to_install.name,
|
||||
extras_requested=extras_requested))
|
||||
|
||||
# We add req_to_install before its dependencies, so that we
|
||||
# can refer to it when adding dependencies.
|
||||
|
|
@ -656,7 +708,7 @@ class RequirementSet(object):
|
|||
set(dist.extras) & set(req_to_install.extras)
|
||||
)
|
||||
for subreq in dist.requires(available_requested):
|
||||
add_req(subreq)
|
||||
add_req(subreq, extras_requested=available_requested)
|
||||
|
||||
# cleanup tmp src
|
||||
self.reqs_to_cleanup.append(req_to_install)
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ __all__ = ['rmtree', 'display_path', 'backup_dir',
|
|||
'normalize_path',
|
||||
'renames', 'get_terminal_size', 'get_prog',
|
||||
'unzip_file', 'untar_file', 'unpack_file', 'call_subprocess',
|
||||
'captured_stdout', 'remove_tracebacks', 'ensure_dir',
|
||||
'captured_stdout', 'ensure_dir',
|
||||
'ARCHIVE_EXTENSIONS', 'SUPPORTED_EXTENSIONS',
|
||||
'get_installed_version']
|
||||
|
||||
|
|
@ -639,20 +639,9 @@ def unpack_file(filename, location, content_type, link):
|
|||
)
|
||||
|
||||
|
||||
def remove_tracebacks(output):
|
||||
pattern = (r'(?:\W+File "(?:.*)", line (?:.*)\W+(?:.*)\W+\^\W+)?'
|
||||
r'Syntax(?:Error|Warning): (?:.*)')
|
||||
output = re.sub(pattern, '', output)
|
||||
if PY2:
|
||||
return output
|
||||
# compileall.compile_dir() prints different messages to stdout
|
||||
# in Python 3
|
||||
return re.sub(r"\*\*\* Error compiling (?:.*)", '', output)
|
||||
|
||||
|
||||
def call_subprocess(cmd, show_stdout=True, cwd=None,
|
||||
on_returncode='raise',
|
||||
command_level=std_logging.DEBUG, command_desc=None,
|
||||
command_desc=None,
|
||||
extra_environ=None, spinner=None):
|
||||
# This function's handling of subprocess output is confusing and I
|
||||
# previously broke it terribly, so as penance I will write a long comment
|
||||
|
|
@ -686,7 +675,7 @@ def call_subprocess(cmd, show_stdout=True, cwd=None,
|
|||
part = '"%s"' % part.replace('"', '\\"')
|
||||
cmd_parts.append(part)
|
||||
command_desc = ' '.join(cmd_parts)
|
||||
logger.log(command_level, "Running command %s", command_desc)
|
||||
logger.debug("Running command %s", command_desc)
|
||||
env = os.environ.copy()
|
||||
if extra_environ:
|
||||
env.update(extra_environ)
|
||||
|
|
@ -745,7 +734,7 @@ def call_subprocess(cmd, show_stdout=True, cwd=None,
|
|||
raise ValueError('Invalid value: on_returncode=%s' %
|
||||
repr(on_returncode))
|
||||
if not show_stdout:
|
||||
return remove_tracebacks(''.join(all_output))
|
||||
return ''.join(all_output)
|
||||
|
||||
|
||||
def read_text_file(filename):
|
||||
|
|
@ -856,14 +845,17 @@ class cached_property(object):
|
|||
return value
|
||||
|
||||
|
||||
def get_installed_version(dist_name):
|
||||
def get_installed_version(dist_name, lookup_dirs=None):
|
||||
"""Get the installed version of dist_name avoiding pkg_resources cache"""
|
||||
# Create a requirement that we'll look for inside of setuptools.
|
||||
req = pkg_resources.Requirement.parse(dist_name)
|
||||
|
||||
# We want to avoid having this cached, so we need to construct a new
|
||||
# working set each time.
|
||||
working_set = pkg_resources.WorkingSet()
|
||||
if lookup_dirs is None:
|
||||
working_set = pkg_resources.WorkingSet()
|
||||
else:
|
||||
working_set = pkg_resources.WorkingSet(lookup_dirs)
|
||||
|
||||
# Get the installed distribution from our working set
|
||||
dist = working_set.find(req)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import os
|
|||
import sys
|
||||
|
||||
from pip.compat import WINDOWS, expanduser
|
||||
from pip._vendor.six import PY2, text_type
|
||||
|
||||
|
||||
def user_cache_dir(appname):
|
||||
|
|
@ -17,9 +18,9 @@ def user_cache_dir(appname):
|
|||
"appname" is the name of application.
|
||||
|
||||
Typical user cache directories are:
|
||||
Mac OS X: ~/Library/Caches/<AppName>
|
||||
macOS: ~/Library/Caches/<AppName>
|
||||
Unix: ~/.cache/<AppName> (XDG default)
|
||||
Windows: C:\Users\<username>\AppData\Local\<AppName>\Cache
|
||||
Windows: C:\Users\<username>\AppData\Local\<AppName>\Cache
|
||||
|
||||
On Windows the only suggestion in the MSDN docs is that local settings go
|
||||
in the `CSIDL_LOCAL_APPDATA` directory. This is identical to the
|
||||
|
|
@ -35,6 +36,11 @@ def user_cache_dir(appname):
|
|||
# Get the base path
|
||||
path = os.path.normpath(_get_win_folder("CSIDL_LOCAL_APPDATA"))
|
||||
|
||||
# When using Python 2, return paths as bytes on Windows like we do on
|
||||
# other operating systems. See helper function docs for more details.
|
||||
if PY2 and isinstance(path, text_type):
|
||||
path = _win_path_to_bytes(path)
|
||||
|
||||
# Add our app name and Cache directory to it
|
||||
path = os.path.join(path, appname, "Cache")
|
||||
elif sys.platform == "darwin":
|
||||
|
|
@ -67,7 +73,7 @@ def user_data_dir(appname, roaming=False):
|
|||
for a discussion of issues.
|
||||
|
||||
Typical user data directories are:
|
||||
Mac OS X: ~/Library/Application Support/<AppName>
|
||||
macOS: ~/Library/Application Support/<AppName>
|
||||
Unix: ~/.local/share/<AppName> # or in
|
||||
$XDG_DATA_HOME, if defined
|
||||
Win XP (not roaming): C:\Documents and Settings\<username>\ ...
|
||||
|
|
@ -110,12 +116,12 @@ def user_config_dir(appname, roaming=True):
|
|||
for a discussion of issues.
|
||||
|
||||
Typical user data directories are:
|
||||
Mac OS X: same as user_data_dir
|
||||
macOS: same as user_data_dir
|
||||
Unix: ~/.config/<AppName>
|
||||
Win *: same as user_data_dir
|
||||
|
||||
For Unix, we follow the XDG spec and support $XDG_CONFIG_HOME.
|
||||
That means, by deafult "~/.config/<AppName>".
|
||||
That means, by default "~/.config/<AppName>".
|
||||
"""
|
||||
if WINDOWS:
|
||||
path = user_data_dir(appname, roaming=roaming)
|
||||
|
|
@ -136,7 +142,7 @@ def site_config_dirs(appname):
|
|||
"appname" is the name of application.
|
||||
|
||||
Typical user config directories are:
|
||||
Mac OS X: /Library/Application Support/<AppName>/
|
||||
macOS: /Library/Application Support/<AppName>/
|
||||
Unix: /etc or $XDG_CONFIG_DIRS[i]/<AppName>/ for each value in
|
||||
$XDG_CONFIG_DIRS
|
||||
Win XP: C:\Documents and Settings\All Users\Application ...
|
||||
|
|
@ -222,3 +228,21 @@ if WINDOWS:
|
|||
_get_win_folder = _get_win_folder_with_ctypes
|
||||
except ImportError:
|
||||
_get_win_folder = _get_win_folder_from_registry
|
||||
|
||||
|
||||
def _win_path_to_bytes(path):
|
||||
"""Encode Windows paths to bytes. Only used on Python 2.
|
||||
|
||||
Motivation is to be consistent with other operating systems where paths
|
||||
are also returned as bytes. This avoids problems mixing bytes and Unicode
|
||||
elsewhere in the codebase. For more details and discussion see
|
||||
<https://github.com/pypa/pip/issues/3463>.
|
||||
|
||||
If encoding using ASCII and MBCS fails, return the original Unicode path.
|
||||
"""
|
||||
for encoding in ('ASCII', 'MBCS'):
|
||||
try:
|
||||
return path.encode(encoding)
|
||||
except (UnicodeEncodeError, LookupError):
|
||||
pass
|
||||
return path
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
"""
|
||||
A module that implments tooling to enable easy warnings about deprecations.
|
||||
A module that implements tooling to enable easy warnings about deprecations.
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
|
|
@ -15,15 +15,15 @@ class Pending(object):
|
|||
pass
|
||||
|
||||
|
||||
class RemovedInPip9Warning(PipDeprecationWarning):
|
||||
class RemovedInPip10Warning(PipDeprecationWarning):
|
||||
pass
|
||||
|
||||
|
||||
class RemovedInPip10Warning(PipDeprecationWarning, Pending):
|
||||
class RemovedInPip11Warning(PipDeprecationWarning, Pending):
|
||||
pass
|
||||
|
||||
|
||||
class Python26DeprecationWarning(PipDeprecationWarning, Pending):
|
||||
class Python26DeprecationWarning(PipDeprecationWarning):
|
||||
pass
|
||||
|
||||
|
||||
|
|
|
|||
81
lib/python3.4/site-packages/pip/utils/glibc.py
Normal file
81
lib/python3.4/site-packages/pip/utils/glibc.py
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
import re
|
||||
import ctypes
|
||||
import platform
|
||||
import warnings
|
||||
|
||||
|
||||
def glibc_version_string():
|
||||
"Returns glibc version string, or None if not using glibc."
|
||||
|
||||
# ctypes.CDLL(None) internally calls dlopen(NULL), and as the dlopen
|
||||
# manpage says, "If filename is NULL, then the returned handle is for the
|
||||
# main program". This way we can let the linker do the work to figure out
|
||||
# which libc our process is actually using.
|
||||
process_namespace = ctypes.CDLL(None)
|
||||
try:
|
||||
gnu_get_libc_version = process_namespace.gnu_get_libc_version
|
||||
except AttributeError:
|
||||
# Symbol doesn't exist -> therefore, we are not linked to
|
||||
# glibc.
|
||||
return None
|
||||
|
||||
# Call gnu_get_libc_version, which returns a string like "2.5"
|
||||
gnu_get_libc_version.restype = ctypes.c_char_p
|
||||
version_str = gnu_get_libc_version()
|
||||
# py2 / py3 compatibility:
|
||||
if not isinstance(version_str, str):
|
||||
version_str = version_str.decode("ascii")
|
||||
|
||||
return version_str
|
||||
|
||||
|
||||
# Separated out from have_compatible_glibc for easier unit testing
|
||||
def check_glibc_version(version_str, required_major, minimum_minor):
|
||||
# Parse string and check against requested version.
|
||||
#
|
||||
# We use a regexp instead of str.split because we want to discard any
|
||||
# random junk that might come after the minor version -- this might happen
|
||||
# in patched/forked versions of glibc (e.g. Linaro's version of glibc
|
||||
# uses version strings like "2.20-2014.11"). See gh-3588.
|
||||
m = re.match(r"(?P<major>[0-9]+)\.(?P<minor>[0-9]+)", version_str)
|
||||
if not m:
|
||||
warnings.warn("Expected glibc version with 2 components major.minor,"
|
||||
" got: %s" % version_str, RuntimeWarning)
|
||||
return False
|
||||
return (int(m.group("major")) == required_major and
|
||||
int(m.group("minor")) >= minimum_minor)
|
||||
|
||||
|
||||
def have_compatible_glibc(required_major, minimum_minor):
|
||||
version_str = glibc_version_string()
|
||||
if version_str is None:
|
||||
return False
|
||||
return check_glibc_version(version_str, required_major, minimum_minor)
|
||||
|
||||
|
||||
# platform.libc_ver regularly returns completely nonsensical glibc
|
||||
# versions. E.g. on my computer, platform says:
|
||||
#
|
||||
# ~$ python2.7 -c 'import platform; print(platform.libc_ver())'
|
||||
# ('glibc', '2.7')
|
||||
# ~$ python3.5 -c 'import platform; print(platform.libc_ver())'
|
||||
# ('glibc', '2.9')
|
||||
#
|
||||
# But the truth is:
|
||||
#
|
||||
# ~$ ldd --version
|
||||
# ldd (Debian GLIBC 2.22-11) 2.22
|
||||
#
|
||||
# This is unfortunate, because it means that the linehaul data on libc
|
||||
# versions that was generated by pip 8.1.2 and earlier is useless and
|
||||
# misleading. Solution: instead of using platform, use our code that actually
|
||||
# works.
|
||||
def libc_ver():
|
||||
glibc_version = glibc_version_string()
|
||||
if glibc_version is None:
|
||||
# For non-glibc platforms, fall back on platform.libc_ver
|
||||
return platform.libc_ver()
|
||||
else:
|
||||
return ("glibc", glibc_version)
|
||||
63
lib/python3.4/site-packages/pip/utils/packaging.py
Normal file
63
lib/python3.4/site-packages/pip/utils/packaging.py
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
from __future__ import absolute_import
|
||||
|
||||
from email.parser import FeedParser
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
from pip._vendor.packaging import specifiers
|
||||
from pip._vendor.packaging import version
|
||||
from pip._vendor import pkg_resources
|
||||
|
||||
from pip import exceptions
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def check_requires_python(requires_python):
|
||||
"""
|
||||
Check if the python version in use match the `requires_python` specifier.
|
||||
|
||||
Returns `True` if the version of python in use matches the requirement.
|
||||
Returns `False` if the version of python in use does not matches the
|
||||
requirement.
|
||||
|
||||
Raises an InvalidSpecifier if `requires_python` have an invalid format.
|
||||
"""
|
||||
if requires_python is None:
|
||||
# The package provides no information
|
||||
return True
|
||||
requires_python_specifier = specifiers.SpecifierSet(requires_python)
|
||||
|
||||
# We only use major.minor.micro
|
||||
python_version = version.parse('.'.join(map(str, sys.version_info[:3])))
|
||||
return python_version in requires_python_specifier
|
||||
|
||||
|
||||
def get_metadata(dist):
|
||||
if (isinstance(dist, pkg_resources.DistInfoDistribution) and
|
||||
dist.has_metadata('METADATA')):
|
||||
return dist.get_metadata('METADATA')
|
||||
elif dist.has_metadata('PKG-INFO'):
|
||||
return dist.get_metadata('PKG-INFO')
|
||||
|
||||
|
||||
def check_dist_requires_python(dist):
|
||||
metadata = get_metadata(dist)
|
||||
feed_parser = FeedParser()
|
||||
feed_parser.feed(metadata)
|
||||
pkg_info_dict = feed_parser.close()
|
||||
requires_python = pkg_info_dict.get('Requires-Python')
|
||||
try:
|
||||
if not check_requires_python(requires_python):
|
||||
raise exceptions.UnsupportedPythonVersion(
|
||||
"%s requires Python '%s' but the running Python is %s" % (
|
||||
dist.project_name,
|
||||
requires_python,
|
||||
'.'.join(map(str, sys.version_info[:3])),)
|
||||
)
|
||||
except specifiers.InvalidSpecifier as e:
|
||||
logger.warning(
|
||||
"Package %s has an invalid Requires-Python entry %s - %s" % (
|
||||
dist.project_name, requires_python, e))
|
||||
return
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
# Shim to wrap setup.py invocation with setuptools
|
||||
SETUPTOOLS_SHIM = (
|
||||
"import setuptools, tokenize;__file__=%r;"
|
||||
"exec(compile(getattr(tokenize, 'open', open)(__file__).read()"
|
||||
".replace('\\r\\n', '\\n'), __file__, 'exec'))"
|
||||
"f=getattr(tokenize, 'open', open)(__file__);"
|
||||
"code=f.read().replace('\\r\\n', '\\n');"
|
||||
"f.close();"
|
||||
"exec(compile(code, __file__, 'exec'))"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import errno
|
|||
import logging
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
from pip._vendor.six.moves.urllib import parse as urllib_parse
|
||||
|
||||
|
|
@ -106,7 +107,7 @@ class VersionControl(object):
|
|||
def _is_local_repository(self, repo):
|
||||
"""
|
||||
posix absolute paths start with os.path.sep,
|
||||
win32 ones ones start with drive (like c:\\folder)
|
||||
win32 ones start with drive (like c:\\folder)
|
||||
"""
|
||||
drive, tail = os.path.splitdrive(repo)
|
||||
return repo.startswith(os.path.sep) or drive
|
||||
|
|
@ -271,6 +272,8 @@ class VersionControl(object):
|
|||
)
|
||||
shutil.move(dest, dest_dir)
|
||||
checkout = True
|
||||
elif response == 'a':
|
||||
sys.exit(-1)
|
||||
return checkout
|
||||
|
||||
def unpack(self, location):
|
||||
|
|
@ -307,7 +310,7 @@ class VersionControl(object):
|
|||
|
||||
def run_command(self, cmd, show_stdout=True, cwd=None,
|
||||
on_returncode='raise',
|
||||
command_level=logging.DEBUG, command_desc=None,
|
||||
command_desc=None,
|
||||
extra_environ=None, spinner=None):
|
||||
"""
|
||||
Run a VCS subcommand
|
||||
|
|
@ -317,7 +320,7 @@ class VersionControl(object):
|
|||
cmd = [self.name] + cmd
|
||||
try:
|
||||
return call_subprocess(cmd, show_stdout, cwd,
|
||||
on_returncode, command_level,
|
||||
on_returncode,
|
||||
command_desc, extra_environ,
|
||||
spinner)
|
||||
except OSError as e:
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ from pip.compat import samefile
|
|||
from pip.exceptions import BadCommand
|
||||
from pip._vendor.six.moves.urllib import parse as urllib_parse
|
||||
from pip._vendor.six.moves.urllib import request as urllib_request
|
||||
from pip._vendor.packaging.version import parse as parse_version
|
||||
|
||||
from pip.utils import display_path, rmtree
|
||||
from pip.vcs import vcs, VersionControl
|
||||
|
|
@ -49,6 +50,19 @@ class Git(VersionControl):
|
|||
|
||||
super(Git, self).__init__(url, *args, **kwargs)
|
||||
|
||||
def get_git_version(self):
|
||||
VERSION_PFX = 'git version '
|
||||
version = self.run_command(['version'], show_stdout=False)
|
||||
if version.startswith(VERSION_PFX):
|
||||
version = version[len(VERSION_PFX):]
|
||||
else:
|
||||
version = ''
|
||||
# get first 3 positions of the git version becasue
|
||||
# on windows it is x.y.z.windows.t, and this parses as
|
||||
# LegacyVersion which always smaller than a Version.
|
||||
version = '.'.join(version.split('.')[:3])
|
||||
return parse_version(version)
|
||||
|
||||
def export(self, location):
|
||||
"""Export the Git repository at the url to the destination location"""
|
||||
temp_dir = tempfile.mkdtemp('-export', 'pip-')
|
||||
|
|
@ -99,7 +113,11 @@ class Git(VersionControl):
|
|||
|
||||
def update(self, dest, rev_options):
|
||||
# First fetch changes from the default remote
|
||||
self.run_command(['fetch', '-q'], cwd=dest)
|
||||
if self.get_git_version() >= parse_version('1.9.0'):
|
||||
# fetch tags in addition to everything else
|
||||
self.run_command(['fetch', '-q', '--tags'], cwd=dest)
|
||||
else:
|
||||
self.run_command(['fetch', '-q'], cwd=dest)
|
||||
# Then reset to wanted revision (maybe even origin/master)
|
||||
if rev_options:
|
||||
rev_options = self.check_rev_options(
|
||||
|
|
@ -139,8 +157,13 @@ class Git(VersionControl):
|
|||
remotes = self.run_command(
|
||||
['config', '--get-regexp', 'remote\..*\.url'],
|
||||
show_stdout=False, cwd=location)
|
||||
first_remote = remotes.splitlines()[0]
|
||||
url = first_remote.split(' ')[1]
|
||||
remotes = remotes.splitlines()
|
||||
found_remote = remotes[0]
|
||||
for remote in remotes:
|
||||
if remote.startswith('remote.origin.url '):
|
||||
found_remote = remote
|
||||
break
|
||||
url = found_remote.split(' ')[1]
|
||||
return url.strip()
|
||||
|
||||
def get_revision(self, location):
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ class Subversion(VersionControl):
|
|||
"""Export the svn repository at the url to the destination location"""
|
||||
url, rev = self.get_url_rev()
|
||||
rev_options = get_rev_options(url, rev)
|
||||
url = self.remove_auth_from_url(url)
|
||||
logger.info('Exporting svn repository %s to %s', url, location)
|
||||
with indent_log():
|
||||
if os.path.exists(location):
|
||||
|
|
@ -79,6 +80,7 @@ class Subversion(VersionControl):
|
|||
def obtain(self, dest):
|
||||
url, rev = self.get_url_rev()
|
||||
rev_options = get_rev_options(url, rev)
|
||||
url = self.remove_auth_from_url(url)
|
||||
if rev:
|
||||
rev_display = ' (to revision %s)' % rev
|
||||
else:
|
||||
|
|
@ -217,6 +219,24 @@ class Subversion(VersionControl):
|
|||
"""Always assume the versions don't match"""
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def remove_auth_from_url(url):
|
||||
# Return a copy of url with 'username:password@' removed.
|
||||
# username/pass params are passed to subversion through flags
|
||||
# and are not recognized in the url.
|
||||
|
||||
# parsed url
|
||||
purl = urllib_parse.urlsplit(url)
|
||||
stripped_netloc = \
|
||||
purl.netloc.split('@')[-1]
|
||||
|
||||
# stripped url
|
||||
url_pieces = (
|
||||
purl.scheme, stripped_netloc, purl.path, purl.query, purl.fragment
|
||||
)
|
||||
surl = urllib_parse.urlunsplit(url_pieces)
|
||||
return surl
|
||||
|
||||
|
||||
def get_rev_options(url, rev):
|
||||
if rev:
|
||||
|
|
|
|||
|
|
@ -298,10 +298,11 @@ def move_wheel_files(name, req, wheeldir, user=False, home=None, root=None,
|
|||
continue
|
||||
elif (is_base and
|
||||
s.endswith('.dist-info') and
|
||||
# is self.req.project_name case preserving?
|
||||
s.lower().startswith(
|
||||
req.project_name.replace('-', '_').lower())):
|
||||
assert not info_dir, 'Multiple .dist-info directories'
|
||||
canonicalize_name(s).startswith(
|
||||
canonicalize_name(req.name))):
|
||||
assert not info_dir, ('Multiple .dist-info directories: ' +
|
||||
destsubdir + ', ' +
|
||||
', '.join(info_dir))
|
||||
info_dir.append(destsubdir)
|
||||
for f in files:
|
||||
# Skip unwanted files
|
||||
|
|
@ -417,7 +418,7 @@ import sys
|
|||
from %(module)s import %(import_name)s
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(%(func)s())
|
||||
"""
|
||||
|
||||
|
|
@ -438,7 +439,7 @@ if __name__ == '__main__':
|
|||
# Because setuptools and pip are bundled with _ensurepip and virtualenv,
|
||||
# we need to use universal wheels. So, as a stopgap until Metadata 2.0, we
|
||||
# override the versioned entry points in the wheel and generate the
|
||||
# correct ones. This code is purely a short-term measure until Metadat 2.0
|
||||
# correct ones. This code is purely a short-term measure until Metadata 2.0
|
||||
# is available.
|
||||
#
|
||||
# To add the level of hack in this section of code, in order to support
|
||||
|
|
@ -757,11 +758,8 @@ class WheelBuilder(object):
|
|||
if not autobuilding:
|
||||
logger.info(
|
||||
'Skipping %s, due to already being wheel.', req.name)
|
||||
elif req.editable:
|
||||
if not autobuilding:
|
||||
logger.info(
|
||||
'Skipping bdist_wheel for %s, due to being editable',
|
||||
req.name)
|
||||
elif autobuilding and req.editable:
|
||||
pass
|
||||
elif autobuilding and req.link and not req.link.is_artifact:
|
||||
pass
|
||||
elif autobuilding and not req.source_dir:
|
||||
|
|
@ -801,8 +799,8 @@ class WheelBuilder(object):
|
|||
try:
|
||||
ensure_dir(output_dir)
|
||||
except OSError as e:
|
||||
logger.warn("Building wheel for %s failed: %s",
|
||||
req.name, e)
|
||||
logger.warning("Building wheel for %s failed: %s",
|
||||
req.name, e)
|
||||
build_failure.append(req)
|
||||
continue
|
||||
else:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue