Edit File by line
/home/barbar84/www/wp-conte.../plugins/sujqvwi/ShExBy/shex_roo.../lib/python3..../site-pac.../pip
File: index.py
"""Routines related to PyPI, indexes"""
[0] Fix | Delete
from __future__ import absolute_import
[1] Fix | Delete
[2] Fix | Delete
import logging
[3] Fix | Delete
import cgi
[4] Fix | Delete
from collections import namedtuple
[5] Fix | Delete
import itertools
[6] Fix | Delete
import sys
[7] Fix | Delete
import os
[8] Fix | Delete
import re
[9] Fix | Delete
import mimetypes
[10] Fix | Delete
import posixpath
[11] Fix | Delete
import warnings
[12] Fix | Delete
[13] Fix | Delete
from pip._vendor.six.moves.urllib import parse as urllib_parse
[14] Fix | Delete
from pip._vendor.six.moves.urllib import request as urllib_request
[15] Fix | Delete
[16] Fix | Delete
from pip.compat import ipaddress
[17] Fix | Delete
from pip.utils import (
[18] Fix | Delete
cached_property, splitext, normalize_path,
[19] Fix | Delete
ARCHIVE_EXTENSIONS, SUPPORTED_EXTENSIONS,
[20] Fix | Delete
)
[21] Fix | Delete
from pip.utils.deprecation import RemovedInPip10Warning
[22] Fix | Delete
from pip.utils.logging import indent_log
[23] Fix | Delete
from pip.utils.packaging import check_requires_python
[24] Fix | Delete
from pip.exceptions import (
[25] Fix | Delete
DistributionNotFound, BestVersionAlreadyInstalled, InvalidWheelFilename,
[26] Fix | Delete
UnsupportedWheel,
[27] Fix | Delete
)
[28] Fix | Delete
from pip.download import HAS_TLS, is_url, path_to_url, url_to_path
[29] Fix | Delete
from pip.wheel import Wheel, wheel_ext
[30] Fix | Delete
from pip.pep425tags import get_supported
[31] Fix | Delete
from pip._vendor import html5lib, requests, six
[32] Fix | Delete
from pip._vendor.packaging.version import parse as parse_version
[33] Fix | Delete
from pip._vendor.packaging.utils import canonicalize_name
[34] Fix | Delete
from pip._vendor.packaging import specifiers
[35] Fix | Delete
from pip._vendor.requests.exceptions import SSLError
[36] Fix | Delete
from pip._vendor.distlib.compat import unescape
[37] Fix | Delete
[38] Fix | Delete
[39] Fix | Delete
__all__ = ['FormatControl', 'fmt_ctl_handle_mutual_exclude', 'PackageFinder']
[40] Fix | Delete
[41] Fix | Delete
[42] Fix | Delete
SECURE_ORIGINS = [
[43] Fix | Delete
# protocol, hostname, port
[44] Fix | Delete
# Taken from Chrome's list of secure origins (See: http://bit.ly/1qrySKC)
[45] Fix | Delete
("https", "*", "*"),
[46] Fix | Delete
("*", "localhost", "*"),
[47] Fix | Delete
("*", "127.0.0.0/8", "*"),
[48] Fix | Delete
("*", "::1/128", "*"),
[49] Fix | Delete
("file", "*", None),
[50] Fix | Delete
# ssh is always secure.
[51] Fix | Delete
("ssh", "*", "*"),
[52] Fix | Delete
]
[53] Fix | Delete
[54] Fix | Delete
[55] Fix | Delete
logger = logging.getLogger(__name__)
[56] Fix | Delete
[57] Fix | Delete
[58] Fix | Delete
class InstallationCandidate(object):
[59] Fix | Delete
[60] Fix | Delete
def __init__(self, project, version, location):
[61] Fix | Delete
self.project = project
[62] Fix | Delete
self.version = parse_version(version)
[63] Fix | Delete
self.location = location
[64] Fix | Delete
self._key = (self.project, self.version, self.location)
[65] Fix | Delete
[66] Fix | Delete
def __repr__(self):
[67] Fix | Delete
return "<InstallationCandidate({0!r}, {1!r}, {2!r})>".format(
[68] Fix | Delete
self.project, self.version, self.location,
[69] Fix | Delete
)
[70] Fix | Delete
[71] Fix | Delete
def __hash__(self):
[72] Fix | Delete
return hash(self._key)
[73] Fix | Delete
[74] Fix | Delete
def __lt__(self, other):
[75] Fix | Delete
return self._compare(other, lambda s, o: s < o)
[76] Fix | Delete
[77] Fix | Delete
def __le__(self, other):
[78] Fix | Delete
return self._compare(other, lambda s, o: s <= o)
[79] Fix | Delete
[80] Fix | Delete
def __eq__(self, other):
[81] Fix | Delete
return self._compare(other, lambda s, o: s == o)
[82] Fix | Delete
[83] Fix | Delete
def __ge__(self, other):
[84] Fix | Delete
return self._compare(other, lambda s, o: s >= o)
[85] Fix | Delete
[86] Fix | Delete
def __gt__(self, other):
[87] Fix | Delete
return self._compare(other, lambda s, o: s > o)
[88] Fix | Delete
[89] Fix | Delete
def __ne__(self, other):
[90] Fix | Delete
return self._compare(other, lambda s, o: s != o)
[91] Fix | Delete
[92] Fix | Delete
def _compare(self, other, method):
[93] Fix | Delete
if not isinstance(other, InstallationCandidate):
[94] Fix | Delete
return NotImplemented
[95] Fix | Delete
[96] Fix | Delete
return method(self._key, other._key)
[97] Fix | Delete
[98] Fix | Delete
[99] Fix | Delete
class PackageFinder(object):
[100] Fix | Delete
"""This finds packages.
[101] Fix | Delete
[102] Fix | Delete
This is meant to match easy_install's technique for looking for
[103] Fix | Delete
packages, by reading pages and looking for appropriate links.
[104] Fix | Delete
"""
[105] Fix | Delete
[106] Fix | Delete
def __init__(self, find_links, index_urls, allow_all_prereleases=False,
[107] Fix | Delete
trusted_hosts=None, process_dependency_links=False,
[108] Fix | Delete
session=None, format_control=None, platform=None,
[109] Fix | Delete
versions=None, abi=None, implementation=None):
[110] Fix | Delete
"""Create a PackageFinder.
[111] Fix | Delete
[112] Fix | Delete
:param format_control: A FormatControl object or None. Used to control
[113] Fix | Delete
the selection of source packages / binary packages when consulting
[114] Fix | Delete
the index and links.
[115] Fix | Delete
:param platform: A string or None. If None, searches for packages
[116] Fix | Delete
that are supported by the current system. Otherwise, will find
[117] Fix | Delete
packages that can be built on the platform passed in. These
[118] Fix | Delete
packages will only be downloaded for distribution: they will
[119] Fix | Delete
not be built locally.
[120] Fix | Delete
:param versions: A list of strings or None. This is passed directly
[121] Fix | Delete
to pep425tags.py in the get_supported() method.
[122] Fix | Delete
:param abi: A string or None. This is passed directly
[123] Fix | Delete
to pep425tags.py in the get_supported() method.
[124] Fix | Delete
:param implementation: A string or None. This is passed directly
[125] Fix | Delete
to pep425tags.py in the get_supported() method.
[126] Fix | Delete
"""
[127] Fix | Delete
if session is None:
[128] Fix | Delete
raise TypeError(
[129] Fix | Delete
"PackageFinder() missing 1 required keyword argument: "
[130] Fix | Delete
"'session'"
[131] Fix | Delete
)
[132] Fix | Delete
[133] Fix | Delete
# Build find_links. If an argument starts with ~, it may be
[134] Fix | Delete
# a local file relative to a home directory. So try normalizing
[135] Fix | Delete
# it and if it exists, use the normalized version.
[136] Fix | Delete
# This is deliberately conservative - it might be fine just to
[137] Fix | Delete
# blindly normalize anything starting with a ~...
[138] Fix | Delete
self.find_links = []
[139] Fix | Delete
for link in find_links:
[140] Fix | Delete
if link.startswith('~'):
[141] Fix | Delete
new_link = normalize_path(link)
[142] Fix | Delete
if os.path.exists(new_link):
[143] Fix | Delete
link = new_link
[144] Fix | Delete
self.find_links.append(link)
[145] Fix | Delete
[146] Fix | Delete
self.index_urls = index_urls
[147] Fix | Delete
self.dependency_links = []
[148] Fix | Delete
[149] Fix | Delete
# These are boring links that have already been logged somehow:
[150] Fix | Delete
self.logged_links = set()
[151] Fix | Delete
[152] Fix | Delete
self.format_control = format_control or FormatControl(set(), set())
[153] Fix | Delete
[154] Fix | Delete
# Domains that we won't emit warnings for when not using HTTPS
[155] Fix | Delete
self.secure_origins = [
[156] Fix | Delete
("*", host, "*")
[157] Fix | Delete
for host in (trusted_hosts if trusted_hosts else [])
[158] Fix | Delete
]
[159] Fix | Delete
[160] Fix | Delete
# Do we want to allow _all_ pre-releases?
[161] Fix | Delete
self.allow_all_prereleases = allow_all_prereleases
[162] Fix | Delete
[163] Fix | Delete
# Do we process dependency links?
[164] Fix | Delete
self.process_dependency_links = process_dependency_links
[165] Fix | Delete
[166] Fix | Delete
# The Session we'll use to make requests
[167] Fix | Delete
self.session = session
[168] Fix | Delete
[169] Fix | Delete
# The valid tags to check potential found wheel candidates against
[170] Fix | Delete
self.valid_tags = get_supported(
[171] Fix | Delete
versions=versions,
[172] Fix | Delete
platform=platform,
[173] Fix | Delete
abi=abi,
[174] Fix | Delete
impl=implementation,
[175] Fix | Delete
)
[176] Fix | Delete
[177] Fix | Delete
# If we don't have TLS enabled, then WARN if anyplace we're looking
[178] Fix | Delete
# relies on TLS.
[179] Fix | Delete
if not HAS_TLS:
[180] Fix | Delete
for link in itertools.chain(self.index_urls, self.find_links):
[181] Fix | Delete
parsed = urllib_parse.urlparse(link)
[182] Fix | Delete
if parsed.scheme == "https":
[183] Fix | Delete
logger.warning(
[184] Fix | Delete
"pip is configured with locations that require "
[185] Fix | Delete
"TLS/SSL, however the ssl module in Python is not "
[186] Fix | Delete
"available."
[187] Fix | Delete
)
[188] Fix | Delete
break
[189] Fix | Delete
[190] Fix | Delete
def add_dependency_links(self, links):
[191] Fix | Delete
# # FIXME: this shouldn't be global list this, it should only
[192] Fix | Delete
# # apply to requirements of the package that specifies the
[193] Fix | Delete
# # dependency_links value
[194] Fix | Delete
# # FIXME: also, we should track comes_from (i.e., use Link)
[195] Fix | Delete
if self.process_dependency_links:
[196] Fix | Delete
warnings.warn(
[197] Fix | Delete
"Dependency Links processing has been deprecated and will be "
[198] Fix | Delete
"removed in a future release.",
[199] Fix | Delete
RemovedInPip10Warning,
[200] Fix | Delete
)
[201] Fix | Delete
self.dependency_links.extend(links)
[202] Fix | Delete
[203] Fix | Delete
@staticmethod
[204] Fix | Delete
def _sort_locations(locations, expand_dir=False):
[205] Fix | Delete
"""
[206] Fix | Delete
Sort locations into "files" (archives) and "urls", and return
[207] Fix | Delete
a pair of lists (files,urls)
[208] Fix | Delete
"""
[209] Fix | Delete
files = []
[210] Fix | Delete
urls = []
[211] Fix | Delete
[212] Fix | Delete
# puts the url for the given file path into the appropriate list
[213] Fix | Delete
def sort_path(path):
[214] Fix | Delete
url = path_to_url(path)
[215] Fix | Delete
if mimetypes.guess_type(url, strict=False)[0] == 'text/html':
[216] Fix | Delete
urls.append(url)
[217] Fix | Delete
else:
[218] Fix | Delete
files.append(url)
[219] Fix | Delete
[220] Fix | Delete
for url in locations:
[221] Fix | Delete
[222] Fix | Delete
is_local_path = os.path.exists(url)
[223] Fix | Delete
is_file_url = url.startswith('file:')
[224] Fix | Delete
[225] Fix | Delete
if is_local_path or is_file_url:
[226] Fix | Delete
if is_local_path:
[227] Fix | Delete
path = url
[228] Fix | Delete
else:
[229] Fix | Delete
path = url_to_path(url)
[230] Fix | Delete
if os.path.isdir(path):
[231] Fix | Delete
if expand_dir:
[232] Fix | Delete
path = os.path.realpath(path)
[233] Fix | Delete
for item in os.listdir(path):
[234] Fix | Delete
sort_path(os.path.join(path, item))
[235] Fix | Delete
elif is_file_url:
[236] Fix | Delete
urls.append(url)
[237] Fix | Delete
elif os.path.isfile(path):
[238] Fix | Delete
sort_path(path)
[239] Fix | Delete
else:
[240] Fix | Delete
logger.warning(
[241] Fix | Delete
"Url '%s' is ignored: it is neither a file "
[242] Fix | Delete
"nor a directory.", url)
[243] Fix | Delete
elif is_url(url):
[244] Fix | Delete
# Only add url with clear scheme
[245] Fix | Delete
urls.append(url)
[246] Fix | Delete
else:
[247] Fix | Delete
logger.warning(
[248] Fix | Delete
"Url '%s' is ignored. It is either a non-existing "
[249] Fix | Delete
"path or lacks a specific scheme.", url)
[250] Fix | Delete
[251] Fix | Delete
return files, urls
[252] Fix | Delete
[253] Fix | Delete
def _candidate_sort_key(self, candidate):
[254] Fix | Delete
"""
[255] Fix | Delete
Function used to generate link sort key for link tuples.
[256] Fix | Delete
The greater the return value, the more preferred it is.
[257] Fix | Delete
If not finding wheels, then sorted by version only.
[258] Fix | Delete
If finding wheels, then the sort order is by version, then:
[259] Fix | Delete
1. existing installs
[260] Fix | Delete
2. wheels ordered via Wheel.support_index_min(self.valid_tags)
[261] Fix | Delete
3. source archives
[262] Fix | Delete
Note: it was considered to embed this logic into the Link
[263] Fix | Delete
comparison operators, but then different sdist links
[264] Fix | Delete
with the same version, would have to be considered equal
[265] Fix | Delete
"""
[266] Fix | Delete
support_num = len(self.valid_tags)
[267] Fix | Delete
if candidate.location.is_wheel:
[268] Fix | Delete
# can raise InvalidWheelFilename
[269] Fix | Delete
wheel = Wheel(candidate.location.filename)
[270] Fix | Delete
if not wheel.supported(self.valid_tags):
[271] Fix | Delete
raise UnsupportedWheel(
[272] Fix | Delete
"%s is not a supported wheel for this platform. It "
[273] Fix | Delete
"can't be sorted." % wheel.filename
[274] Fix | Delete
)
[275] Fix | Delete
pri = -(wheel.support_index_min(self.valid_tags))
[276] Fix | Delete
else: # sdist
[277] Fix | Delete
pri = -(support_num)
[278] Fix | Delete
return (candidate.version, pri)
[279] Fix | Delete
[280] Fix | Delete
def _validate_secure_origin(self, logger, location):
[281] Fix | Delete
# Determine if this url used a secure transport mechanism
[282] Fix | Delete
parsed = urllib_parse.urlparse(str(location))
[283] Fix | Delete
origin = (parsed.scheme, parsed.hostname, parsed.port)
[284] Fix | Delete
[285] Fix | Delete
# The protocol to use to see if the protocol matches.
[286] Fix | Delete
# Don't count the repository type as part of the protocol: in
[287] Fix | Delete
# cases such as "git+ssh", only use "ssh". (I.e., Only verify against
[288] Fix | Delete
# the last scheme.)
[289] Fix | Delete
protocol = origin[0].rsplit('+', 1)[-1]
[290] Fix | Delete
[291] Fix | Delete
# Determine if our origin is a secure origin by looking through our
[292] Fix | Delete
# hardcoded list of secure origins, as well as any additional ones
[293] Fix | Delete
# configured on this PackageFinder instance.
[294] Fix | Delete
for secure_origin in (SECURE_ORIGINS + self.secure_origins):
[295] Fix | Delete
if protocol != secure_origin[0] and secure_origin[0] != "*":
[296] Fix | Delete
continue
[297] Fix | Delete
[298] Fix | Delete
try:
[299] Fix | Delete
# We need to do this decode dance to ensure that we have a
[300] Fix | Delete
# unicode object, even on Python 2.x.
[301] Fix | Delete
addr = ipaddress.ip_address(
[302] Fix | Delete
origin[1]
[303] Fix | Delete
if (
[304] Fix | Delete
isinstance(origin[1], six.text_type) or
[305] Fix | Delete
origin[1] is None
[306] Fix | Delete
)
[307] Fix | Delete
else origin[1].decode("utf8")
[308] Fix | Delete
)
[309] Fix | Delete
network = ipaddress.ip_network(
[310] Fix | Delete
secure_origin[1]
[311] Fix | Delete
if isinstance(secure_origin[1], six.text_type)
[312] Fix | Delete
else secure_origin[1].decode("utf8")
[313] Fix | Delete
)
[314] Fix | Delete
except ValueError:
[315] Fix | Delete
# We don't have both a valid address or a valid network, so
[316] Fix | Delete
# we'll check this origin against hostnames.
[317] Fix | Delete
if (origin[1] and
[318] Fix | Delete
origin[1].lower() != secure_origin[1].lower() and
[319] Fix | Delete
secure_origin[1] != "*"):
[320] Fix | Delete
continue
[321] Fix | Delete
else:
[322] Fix | Delete
# We have a valid address and network, so see if the address
[323] Fix | Delete
# is contained within the network.
[324] Fix | Delete
if addr not in network:
[325] Fix | Delete
continue
[326] Fix | Delete
[327] Fix | Delete
# Check to see if the port patches
[328] Fix | Delete
if (origin[2] != secure_origin[2] and
[329] Fix | Delete
secure_origin[2] != "*" and
[330] Fix | Delete
secure_origin[2] is not None):
[331] Fix | Delete
continue
[332] Fix | Delete
[333] Fix | Delete
# If we've gotten here, then this origin matches the current
[334] Fix | Delete
# secure origin and we should return True
[335] Fix | Delete
return True
[336] Fix | Delete
[337] Fix | Delete
# If we've gotten to this point, then the origin isn't secure and we
[338] Fix | Delete
# will not accept it as a valid location to search. We will however
[339] Fix | Delete
# log a warning that we are ignoring it.
[340] Fix | Delete
logger.warning(
[341] Fix | Delete
"The repository located at %s is not a trusted or secure host and "
[342] Fix | Delete
"is being ignored. If this repository is available via HTTPS it "
[343] Fix | Delete
"is recommended to use HTTPS instead, otherwise you may silence "
[344] Fix | Delete
"this warning and allow it anyways with '--trusted-host %s'.",
[345] Fix | Delete
parsed.hostname,
[346] Fix | Delete
parsed.hostname,
[347] Fix | Delete
)
[348] Fix | Delete
[349] Fix | Delete
return False
[350] Fix | Delete
[351] Fix | Delete
def _get_index_urls_locations(self, project_name):
[352] Fix | Delete
"""Returns the locations found via self.index_urls
[353] Fix | Delete
[354] Fix | Delete
Checks the url_name on the main (first in the list) index and
[355] Fix | Delete
use this url_name to produce all locations
[356] Fix | Delete
"""
[357] Fix | Delete
[358] Fix | Delete
def mkurl_pypi_url(url):
[359] Fix | Delete
loc = posixpath.join(
[360] Fix | Delete
url,
[361] Fix | Delete
urllib_parse.quote(canonicalize_name(project_name)))
[362] Fix | Delete
# For maximum compatibility with easy_install, ensure the path
[363] Fix | Delete
# ends in a trailing slash. Although this isn't in the spec
[364] Fix | Delete
# (and PyPI can handle it without the slash) some other index
[365] Fix | Delete
# implementations might break if they relied on easy_install's
[366] Fix | Delete
# behavior.
[367] Fix | Delete
if not loc.endswith('/'):
[368] Fix | Delete
loc = loc + '/'
[369] Fix | Delete
return loc
[370] Fix | Delete
[371] Fix | Delete
return [mkurl_pypi_url(url) for url in self.index_urls]
[372] Fix | Delete
[373] Fix | Delete
def find_all_candidates(self, project_name):
[374] Fix | Delete
"""Find all available InstallationCandidate for project_name
[375] Fix | Delete
[376] Fix | Delete
This checks index_urls, find_links and dependency_links.
[377] Fix | Delete
All versions found are returned as an InstallationCandidate list.
[378] Fix | Delete
[379] Fix | Delete
See _link_package_versions for details on which files are accepted
[380] Fix | Delete
"""
[381] Fix | Delete
index_locations = self._get_index_urls_locations(project_name)
[382] Fix | Delete
index_file_loc, index_url_loc = self._sort_locations(index_locations)
[383] Fix | Delete
fl_file_loc, fl_url_loc = self._sort_locations(
[384] Fix | Delete
self.find_links, expand_dir=True)
[385] Fix | Delete
dep_file_loc, dep_url_loc = self._sort_locations(self.dependency_links)
[386] Fix | Delete
[387] Fix | Delete
file_locations = (
[388] Fix | Delete
Link(url) for url in itertools.chain(
[389] Fix | Delete
index_file_loc, fl_file_loc, dep_file_loc)
[390] Fix | Delete
)
[391] Fix | Delete
[392] Fix | Delete
# We trust every url that the user has given us whether it was given
[393] Fix | Delete
# via --index-url or --find-links
[394] Fix | Delete
# We explicitly do not trust links that came from dependency_links
[395] Fix | Delete
# We want to filter out any thing which does not have a secure origin.
[396] Fix | Delete
url_locations = [
[397] Fix | Delete
link for link in itertools.chain(
[398] Fix | Delete
(Link(url) for url in index_url_loc),
[399] Fix | Delete
(Link(url) for url in fl_url_loc),
[400] Fix | Delete
(Link(url) for url in dep_url_loc),
[401] Fix | Delete
)
[402] Fix | Delete
if self._validate_secure_origin(logger, link)
[403] Fix | Delete
]
[404] Fix | Delete
[405] Fix | Delete
logger.debug('%d location(s) to search for versions of %s:',
[406] Fix | Delete
len(url_locations), project_name)
[407] Fix | Delete
[408] Fix | Delete
for location in url_locations:
[409] Fix | Delete
logger.debug('* %s', location)
[410] Fix | Delete
[411] Fix | Delete
canonical_name = canonicalize_name(project_name)
[412] Fix | Delete
formats = fmt_ctl_formats(self.format_control, canonical_name)
[413] Fix | Delete
search = Search(project_name, canonical_name, formats)
[414] Fix | Delete
find_links_versions = self._package_versions(
[415] Fix | Delete
# We trust every directly linked archive in find_links
[416] Fix | Delete
(Link(url, '-f') for url in self.find_links),
[417] Fix | Delete
search
[418] Fix | Delete
)
[419] Fix | Delete
[420] Fix | Delete
page_versions = []
[421] Fix | Delete
for page in self._get_pages(url_locations, project_name):
[422] Fix | Delete
logger.debug('Analyzing links from page %s', page.url)
[423] Fix | Delete
with indent_log():
[424] Fix | Delete
page_versions.extend(
[425] Fix | Delete
self._package_versions(page.links, search)
[426] Fix | Delete
)
[427] Fix | Delete
[428] Fix | Delete
dependency_versions = self._package_versions(
[429] Fix | Delete
(Link(url) for url in self.dependency_links), search
[430] Fix | Delete
)
[431] Fix | Delete
if dependency_versions:
[432] Fix | Delete
logger.debug(
[433] Fix | Delete
'dependency_links found: %s',
[434] Fix | Delete
', '.join([
[435] Fix | Delete
version.location.url for version in dependency_versions
[436] Fix | Delete
])
[437] Fix | Delete
)
[438] Fix | Delete
[439] Fix | Delete
file_versions = self._package_versions(file_locations, search)
[440] Fix | Delete
if file_versions:
[441] Fix | Delete
file_versions.sort(reverse=True)
[442] Fix | Delete
logger.debug(
[443] Fix | Delete
'Local files found: %s',
[444] Fix | Delete
', '.join([
[445] Fix | Delete
url_to_path(candidate.location.url)
[446] Fix | Delete
for candidate in file_versions
[447] Fix | Delete
])
[448] Fix | Delete
)
[449] Fix | Delete
[450] Fix | Delete
# This is an intentional priority ordering
[451] Fix | Delete
return (
[452] Fix | Delete
file_versions + find_links_versions + page_versions +
[453] Fix | Delete
dependency_versions
[454] Fix | Delete
)
[455] Fix | Delete
[456] Fix | Delete
def find_requirement(self, req, upgrade):
[457] Fix | Delete
"""Try to find a Link matching req
[458] Fix | Delete
[459] Fix | Delete
Expects req, an InstallRequirement and upgrade, a boolean
[460] Fix | Delete
Returns a Link if found,
[461] Fix | Delete
Raises DistributionNotFound or BestVersionAlreadyInstalled otherwise
[462] Fix | Delete
"""
[463] Fix | Delete
all_candidates = self.find_all_candidates(req.name)
[464] Fix | Delete
[465] Fix | Delete
# Filter out anything which doesn't match our specifier
[466] Fix | Delete
compatible_versions = set(
[467] Fix | Delete
req.specifier.filter(
[468] Fix | Delete
# We turn the version object into a str here because otherwise
[469] Fix | Delete
# when we're debundled but setuptools isn't, Python will see
[470] Fix | Delete
# packaging.version.Version and
[471] Fix | Delete
# pkg_resources._vendor.packaging.version.Version as different
[472] Fix | Delete
# types. This way we'll use a str as a common data interchange
[473] Fix | Delete
# format. If we stop using the pkg_resources provided specifier
[474] Fix | Delete
# and start using our own, we can drop the cast to str().
[475] Fix | Delete
[str(c.version) for c in all_candidates],
[476] Fix | Delete
prereleases=(
[477] Fix | Delete
self.allow_all_prereleases
[478] Fix | Delete
if self.allow_all_prereleases else None
[479] Fix | Delete
),
[480] Fix | Delete
)
[481] Fix | Delete
)
[482] Fix | Delete
applicable_candidates = [
[483] Fix | Delete
# Again, converting to str to deal with debundling.
[484] Fix | Delete
c for c in all_candidates if str(c.version) in compatible_versions
[485] Fix | Delete
]
[486] Fix | Delete
[487] Fix | Delete
if applicable_candidates:
[488] Fix | Delete
best_candidate = max(applicable_candidates,
[489] Fix | Delete
key=self._candidate_sort_key)
[490] Fix | Delete
# If we cannot find a non-yanked candidate,
[491] Fix | Delete
# use the best one and print a warning about it.
[492] Fix | Delete
# Otherwise, try to find another best candidate, ignoring
[493] Fix | Delete
# all the yanked releases.
[494] Fix | Delete
if getattr(best_candidate.location, "yanked", False):
[495] Fix | Delete
nonyanked_candidates = [
[496] Fix | Delete
c for c in applicable_candidates
[497] Fix | Delete
if not getattr(c.location, "yanked", False)
[498] Fix | Delete
]
[499] Fix | Delete
It is recommended that you Edit text format, this type of Fix handles quite a lot in one request
Function