mirror of https://github.com/pypa/pip
Add a TargetPython class.
This commit is contained in:
parent
9c8b2ea759
commit
b8d693c71e
|
@ -24,6 +24,7 @@ from pip._internal.exceptions import (
|
|||
)
|
||||
from pip._internal.index import PackageFinder
|
||||
from pip._internal.locations import running_under_virtualenv
|
||||
from pip._internal.models.target_python import TargetPython
|
||||
from pip._internal.req.constructors import (
|
||||
install_req_from_editable, install_req_from_line,
|
||||
)
|
||||
|
@ -344,6 +345,13 @@ class RequirementCommand(Command):
|
|||
)
|
||||
index_urls = []
|
||||
|
||||
target_python = TargetPython(
|
||||
platform=platform,
|
||||
py_version_info=py_version_info,
|
||||
abi=abi,
|
||||
implementation=implementation,
|
||||
)
|
||||
|
||||
return PackageFinder.create(
|
||||
find_links=options.find_links,
|
||||
format_control=options.format_control,
|
||||
|
@ -351,10 +359,7 @@ class RequirementCommand(Command):
|
|||
trusted_hosts=options.trusted_hosts,
|
||||
allow_all_prereleases=options.pre,
|
||||
session=session,
|
||||
platform=platform,
|
||||
py_version_info=py_version_info,
|
||||
abi=abi,
|
||||
implementation=implementation,
|
||||
target_python=target_python,
|
||||
prefer_binary=options.prefer_binary,
|
||||
ignore_requires_python=ignore_requires_python,
|
||||
)
|
||||
|
|
|
@ -8,7 +8,6 @@ import mimetypes
|
|||
import os
|
||||
import posixpath
|
||||
import re
|
||||
import sys
|
||||
from collections import namedtuple
|
||||
|
||||
from pip._vendor import html5lib, requests, six
|
||||
|
@ -29,12 +28,12 @@ from pip._internal.models.candidate import InstallationCandidate
|
|||
from pip._internal.models.format_control import FormatControl
|
||||
from pip._internal.models.index import PyPI
|
||||
from pip._internal.models.link import Link
|
||||
from pip._internal.pep425tags import get_supported, version_info_to_nodot
|
||||
from pip._internal.models.target_python import TargetPython
|
||||
from pip._internal.utils.compat import ipaddress
|
||||
from pip._internal.utils.logging import indent_log
|
||||
from pip._internal.utils.misc import (
|
||||
ARCHIVE_EXTENSIONS, SUPPORTED_EXTENSIONS, WHEEL_EXTENSION, normalize_path,
|
||||
normalize_version_info, path_to_url, redact_password_from_url,
|
||||
path_to_url, redact_password_from_url,
|
||||
)
|
||||
from pip._internal.utils.packaging import check_requires_python
|
||||
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
|
||||
|
@ -48,7 +47,6 @@ if MYPY_CHECK_RUNNING:
|
|||
)
|
||||
from pip._vendor.packaging.version import _BaseVersion
|
||||
from pip._vendor.requests import Response
|
||||
from pip._internal.pep425tags import Pep425Tag
|
||||
from pip._internal.req import InstallRequirement
|
||||
from pip._internal.download import PipSession
|
||||
|
||||
|
@ -308,35 +306,29 @@ class CandidateEvaluator(object):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
valid_tags, # type: List[Pep425Tag]
|
||||
target_python=None, # type: Optional[TargetPython]
|
||||
prefer_binary=False, # type: bool
|
||||
allow_all_prereleases=False, # type: bool
|
||||
py_version_info=None, # type: Optional[Tuple[int, int, int]]
|
||||
ignore_requires_python=None, # type: Optional[bool]
|
||||
):
|
||||
# type: (...) -> None
|
||||
"""
|
||||
:param target_python: The target Python interpreter to use to check
|
||||
both the Python version embedded in the filename and the package's
|
||||
"Requires-Python" metadata. If None (the default), then a
|
||||
TargetPython object will be constructed from the running Python.
|
||||
:param allow_all_prereleases: Whether to allow all pre-releases.
|
||||
:param py_version_info: A 3-tuple of ints representing the Python
|
||||
major-minor-micro version to use to check both the Python version
|
||||
embedded in the filename and the package's "Requires-Python"
|
||||
metadata. If None (the default), then `sys.version_info[:3]`
|
||||
will be used.
|
||||
:param ignore_requires_python: Whether to ignore incompatible
|
||||
"Requires-Python" values in links. Defaults to False.
|
||||
"""
|
||||
if py_version_info is None:
|
||||
py_version_info = sys.version_info[:3]
|
||||
if target_python is None:
|
||||
target_python = TargetPython()
|
||||
if ignore_requires_python is None:
|
||||
ignore_requires_python = False
|
||||
|
||||
py_version = '.'.join(map(str, py_version_info[:2]))
|
||||
|
||||
self._ignore_requires_python = ignore_requires_python
|
||||
self._prefer_binary = prefer_binary
|
||||
self._py_version = py_version
|
||||
self._py_version_info = py_version_info
|
||||
self._valid_tags = valid_tags
|
||||
self._target_python = target_python
|
||||
|
||||
# We compile the regex here instead of as a class attribute so as
|
||||
# not to impact pip start-up time. This is also okay because
|
||||
|
@ -348,7 +340,8 @@ class CandidateEvaluator(object):
|
|||
|
||||
def _is_wheel_supported(self, wheel):
|
||||
# type: (Wheel) -> bool
|
||||
return wheel.supported(self._valid_tags)
|
||||
valid_tags = self._target_python.get_tags()
|
||||
return wheel.supported(valid_tags)
|
||||
|
||||
def evaluate_link(self, link, search):
|
||||
# type: (Link, Search) -> Tuple[bool, Optional[str]]
|
||||
|
@ -410,11 +403,11 @@ class CandidateEvaluator(object):
|
|||
if match:
|
||||
version = version[:match.start()]
|
||||
py_version = match.group(1)
|
||||
if py_version != self._py_version:
|
||||
if py_version != self._target_python.py_version:
|
||||
return (False, 'Python version is incorrect')
|
||||
|
||||
supports_python = _check_link_requires_python(
|
||||
link, version_info=self._py_version_info,
|
||||
link, version_info=self._target_python.py_version_info,
|
||||
ignore_requires_python=self._ignore_requires_python,
|
||||
)
|
||||
if not supports_python:
|
||||
|
@ -474,7 +467,8 @@ class CandidateEvaluator(object):
|
|||
comparison operators, but then different sdist links
|
||||
with the same version, would have to be considered equal
|
||||
"""
|
||||
support_num = len(self._valid_tags)
|
||||
valid_tags = self._target_python.get_tags()
|
||||
support_num = len(valid_tags)
|
||||
build_tag = tuple() # type: BuildTag
|
||||
binary_preference = 0
|
||||
if candidate.location.is_wheel:
|
||||
|
@ -487,7 +481,7 @@ class CandidateEvaluator(object):
|
|||
)
|
||||
if self._prefer_binary:
|
||||
binary_preference = 1
|
||||
pri = -(wheel.support_index_min(self._valid_tags))
|
||||
pri = -(wheel.support_index_min(valid_tags))
|
||||
if wheel.build_tag is not None:
|
||||
match = re.match(r'^(\d+)(.*)$', wheel.build_tag)
|
||||
build_tag_groups = match.groups()
|
||||
|
@ -604,10 +598,7 @@ class PackageFinder(object):
|
|||
trusted_hosts=None, # type: Optional[Iterable[str]]
|
||||
session=None, # type: Optional[PipSession]
|
||||
format_control=None, # type: Optional[FormatControl]
|
||||
platform=None, # type: Optional[str]
|
||||
py_version_info=None, # type: Optional[Tuple[int, ...]]
|
||||
abi=None, # type: Optional[str]
|
||||
implementation=None, # type: Optional[str]
|
||||
target_python=None, # type: Optional[TargetPython]
|
||||
prefer_binary=False, # type: bool
|
||||
ignore_requires_python=None, # type: Optional[bool]
|
||||
):
|
||||
|
@ -620,19 +611,7 @@ class PackageFinder(object):
|
|||
: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 py_version_info: An optional tuple of ints representing the
|
||||
Python version information to use (e.g. `sys.version_info[:3]`).
|
||||
This can have length 1, 2, or 3. This is used to construct the
|
||||
value passed to pep425tags.py's get_supported() function.
|
||||
: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.
|
||||
:param target_python: The target Python interpreter.
|
||||
:param prefer_binary: Whether to prefer an old, but valid, binary
|
||||
dist over a new source dist.
|
||||
:param ignore_requires_python: Whether to ignore incompatible
|
||||
|
@ -662,24 +641,9 @@ class PackageFinder(object):
|
|||
for host in (trusted_hosts if trusted_hosts else [])
|
||||
] # type: List[SecureOrigin]
|
||||
|
||||
if py_version_info:
|
||||
versions = [version_info_to_nodot(py_version_info)]
|
||||
else:
|
||||
versions = None
|
||||
|
||||
py_version_info = normalize_version_info(py_version_info)
|
||||
|
||||
# The valid tags to check potential found wheel candidates against
|
||||
valid_tags = get_supported(
|
||||
versions=versions,
|
||||
platform=platform,
|
||||
abi=abi,
|
||||
impl=implementation,
|
||||
)
|
||||
candidate_evaluator = CandidateEvaluator(
|
||||
valid_tags=valid_tags, prefer_binary=prefer_binary,
|
||||
target_python=target_python, prefer_binary=prefer_binary,
|
||||
allow_all_prereleases=allow_all_prereleases,
|
||||
py_version_info=py_version_info,
|
||||
ignore_requires_python=ignore_requires_python,
|
||||
)
|
||||
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
import sys
|
||||
|
||||
from pip._internal.pep425tags import get_supported, version_info_to_nodot
|
||||
from pip._internal.utils.misc import normalize_version_info
|
||||
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
|
||||
|
||||
if MYPY_CHECK_RUNNING:
|
||||
from typing import Optional, Tuple
|
||||
|
||||
|
||||
class TargetPython(object):
|
||||
|
||||
"""
|
||||
Encapsulates the properties of a Python interpreter one is targeting
|
||||
for a package install, download, etc.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
platform=None, # type: Optional[str]
|
||||
py_version_info=None, # type: Optional[Tuple[int, ...]]
|
||||
abi=None, # type: Optional[str]
|
||||
implementation=None, # type: Optional[str]
|
||||
):
|
||||
# type: (...) -> None
|
||||
"""
|
||||
: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 py_version_info: An optional tuple of ints representing the
|
||||
Python version information to use (e.g. `sys.version_info[:3]`).
|
||||
This can have length 1, 2, or 3 when provided.
|
||||
:param abi: A string or None. This is passed to pep425tags.py's
|
||||
get_supported() function as is.
|
||||
:param implementation: A string or None. This is passed to
|
||||
pep425tags.py's get_supported() function as is.
|
||||
"""
|
||||
# Store the given py_version_info for when we call get_supported().
|
||||
self._given_py_version_info = py_version_info
|
||||
|
||||
if py_version_info is None:
|
||||
py_version_info = sys.version_info[:3]
|
||||
else:
|
||||
py_version_info = normalize_version_info(py_version_info)
|
||||
|
||||
py_version = '.'.join(map(str, py_version_info[:2]))
|
||||
|
||||
self.abi = abi
|
||||
self.implementation = implementation
|
||||
self.platform = platform
|
||||
self.py_version = py_version
|
||||
self.py_version_info = py_version_info
|
||||
|
||||
# This is used to cache the return value of get_tags().
|
||||
self._valid_tags = None
|
||||
|
||||
def get_tags(self):
|
||||
"""
|
||||
Return the supported tags to check wheel candidates against.
|
||||
"""
|
||||
if self._valid_tags is None:
|
||||
# Pass versions=None if no py_version_info was given since
|
||||
# versions=None uses special default logic.
|
||||
py_version_info = self._given_py_version_info
|
||||
if py_version_info is None:
|
||||
versions = None
|
||||
else:
|
||||
versions = [version_info_to_nodot(py_version_info)]
|
||||
|
||||
tags = get_supported(
|
||||
versions=versions,
|
||||
platform=self.platform,
|
||||
abi=self.abi,
|
||||
impl=self.implementation,
|
||||
)
|
||||
self._valid_tags = tags
|
||||
|
||||
return self._valid_tags
|
|
@ -22,6 +22,8 @@ SRC_DIR = Path(__file__).abspath.folder.folder.folder
|
|||
pyversion = sys.version[:3]
|
||||
pyversion_tuple = sys.version_info
|
||||
|
||||
CURRENT_PY_VERSION_INFO = sys.version_info[:3]
|
||||
|
||||
|
||||
def assert_paths_equal(actual, expected):
|
||||
os.path.normpath(actual) == os.path.normpath(expected)
|
||||
|
|
|
@ -14,6 +14,7 @@ from pip._internal.exceptions import (
|
|||
from pip._internal.index import (
|
||||
CandidateEvaluator, InstallationCandidate, Link, PackageFinder, Search,
|
||||
)
|
||||
from pip._internal.models.target_python import TargetPython
|
||||
from pip._internal.req.constructors import install_req_from_line
|
||||
|
||||
|
||||
|
@ -139,20 +140,16 @@ class TestWheel:
|
|||
"""
|
||||
Test not finding an unsupported wheel.
|
||||
"""
|
||||
monkeypatch.setattr(
|
||||
pip._internal.pep425tags,
|
||||
"get_supported",
|
||||
lambda **kw: [("py1", "none", "any")],
|
||||
)
|
||||
|
||||
req = install_req_from_line("simple.dist")
|
||||
target_python = TargetPython()
|
||||
# Make sure no tags will match.
|
||||
target_python._valid_tags = []
|
||||
finder = PackageFinder.create(
|
||||
[data.find_links],
|
||||
[],
|
||||
session=PipSession(),
|
||||
target_python=target_python,
|
||||
)
|
||||
valid_tags = pip._internal.pep425tags.get_supported()
|
||||
finder.candidate_evaluator = CandidateEvaluator(valid_tags=valid_tags)
|
||||
|
||||
with pytest.raises(DistributionNotFound):
|
||||
finder.find_requirement(req, True)
|
||||
|
@ -246,7 +243,9 @@ class TestWheel:
|
|||
('pyT', 'TEST', 'any'),
|
||||
('pyT', 'none', 'any'),
|
||||
]
|
||||
evaluator = CandidateEvaluator(valid_tags=valid_tags)
|
||||
target_python = TargetPython()
|
||||
target_python._valid_tags = valid_tags
|
||||
evaluator = CandidateEvaluator(target_python=target_python)
|
||||
sort_key = evaluator._sort_key
|
||||
results = sorted(links, key=sort_key, reverse=True)
|
||||
results2 = sorted(reversed(links), key=sort_key, reverse=True)
|
||||
|
@ -469,8 +468,7 @@ class TestCandidateEvaluator(object):
|
|||
def setup(self):
|
||||
self.search_name = 'pytest'
|
||||
self.canonical_name = 'pytest'
|
||||
valid_tags = pip._internal.pep425tags.get_supported()
|
||||
self.evaluator = CandidateEvaluator(valid_tags=valid_tags)
|
||||
self.evaluator = CandidateEvaluator()
|
||||
|
||||
@pytest.mark.parametrize('url, expected_version', [
|
||||
('http:/yo/pytest-1.0.tar.gz', '1.0'),
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import logging
|
||||
import os.path
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
from mock import Mock, patch
|
||||
from mock import Mock
|
||||
from pip._vendor import html5lib, requests
|
||||
|
||||
from pip._internal.download import PipSession
|
||||
|
@ -12,8 +11,8 @@ from pip._internal.index import (
|
|||
_check_link_requires_python, _clean_link, _determine_base_url,
|
||||
_egg_info_matches, _find_name_version_sep, _get_html_page,
|
||||
)
|
||||
|
||||
CURRENT_PY_VERSION_INFO = sys.version_info[:3]
|
||||
from pip._internal.models.target_python import TargetPython
|
||||
from tests.lib import CURRENT_PY_VERSION_INFO
|
||||
|
||||
|
||||
@pytest.mark.parametrize('requires_python, expected', [
|
||||
|
@ -84,33 +83,24 @@ def test_check_link_requires_python__invalid_requires(caplog):
|
|||
|
||||
class TestCandidateEvaluator:
|
||||
|
||||
@pytest.mark.parametrize('py_version_info, expected_py_version', [
|
||||
((2, 7, 14), '2.7'),
|
||||
((3, 6, 5), '3.6'),
|
||||
# Check a minor version with two digits.
|
||||
((3, 10, 1), '3.10'),
|
||||
])
|
||||
def test_init__py_version_info(self, py_version_info, expected_py_version):
|
||||
def test_init__target_python(self):
|
||||
"""
|
||||
Test the py_version_info argument.
|
||||
Test the target_python argument.
|
||||
"""
|
||||
evaluator = CandidateEvaluator([], py_version_info=py_version_info)
|
||||
target_python = TargetPython(py_version_info=(3, 7, 3))
|
||||
evaluator = CandidateEvaluator(target_python=target_python)
|
||||
# The target_python attribute should be set as is.
|
||||
assert evaluator._target_python is target_python
|
||||
|
||||
# The _py_version_info attribute should be set as is.
|
||||
assert evaluator._py_version_info == py_version_info
|
||||
assert evaluator._py_version == expected_py_version
|
||||
|
||||
def test_init__py_version_info_none(self):
|
||||
def test_init__target_python_none(self):
|
||||
"""
|
||||
Test passing None for the py_version_info argument.
|
||||
Test passing None for the target_python argument.
|
||||
"""
|
||||
evaluator = CandidateEvaluator([], py_version_info=None)
|
||||
# Get the index of the second dot.
|
||||
index = sys.version.find('.', 2)
|
||||
current_major_minor = sys.version[:index] # e.g. "3.6"
|
||||
|
||||
assert evaluator._py_version_info == CURRENT_PY_VERSION_INFO
|
||||
assert evaluator._py_version == current_major_minor
|
||||
evaluator = CandidateEvaluator(target_python=None)
|
||||
# Spot-check the default TargetPython object.
|
||||
actual_target_python = evaluator._target_python
|
||||
assert actual_target_python._given_py_version_info is None
|
||||
assert actual_target_python.py_version_info == CURRENT_PY_VERSION_INFO
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'py_version_info,ignore_requires_python,expected', [
|
||||
|
@ -124,6 +114,11 @@ class TestCandidateEvaluator:
|
|||
def test_evaluate_link(
|
||||
self, py_version_info, ignore_requires_python, expected,
|
||||
):
|
||||
target_python = TargetPython(py_version_info=py_version_info)
|
||||
evaluator = CandidateEvaluator(
|
||||
target_python=target_python,
|
||||
ignore_requires_python=ignore_requires_python,
|
||||
)
|
||||
link = Link(
|
||||
'https://example.com/#egg=twine-1.12',
|
||||
requires_python='== 3.6.5',
|
||||
|
@ -131,10 +126,6 @@ class TestCandidateEvaluator:
|
|||
search = Search(
|
||||
supplied='twine', canonical='twine', formats=['source'],
|
||||
)
|
||||
evaluator = CandidateEvaluator(
|
||||
[], py_version_info=py_version_info,
|
||||
ignore_requires_python=ignore_requires_python,
|
||||
)
|
||||
actual = evaluator.evaluate_link(link, search=search)
|
||||
assert actual == expected
|
||||
|
||||
|
@ -142,14 +133,14 @@ class TestCandidateEvaluator:
|
|||
"""
|
||||
Test an incompatible wheel.
|
||||
"""
|
||||
target_python = TargetPython(py_version_info=(3, 6, 4))
|
||||
# Set the valid tags to an empty list to make sure nothing matches.
|
||||
target_python._valid_tags = []
|
||||
evaluator = CandidateEvaluator(target_python=target_python)
|
||||
link = Link('https://example.com/sample-1.0-py2.py3-none-any.whl')
|
||||
search = Search(
|
||||
supplied='sample', canonical='sample', formats=['binary'],
|
||||
)
|
||||
# Pass an empty list for the valid tags to make sure nothing matches.
|
||||
evaluator = CandidateEvaluator(
|
||||
[], py_version_info=(3, 6, 4),
|
||||
)
|
||||
actual = evaluator.evaluate_link(link, search=search)
|
||||
expected = (
|
||||
False, "none of the wheel's tags match: py2-none-any, py3-none-any"
|
||||
|
@ -159,37 +150,19 @@ class TestCandidateEvaluator:
|
|||
|
||||
class TestPackageFinder:
|
||||
|
||||
@pytest.mark.parametrize('py_version_info, expected', [
|
||||
# Test tuples of varying lengths.
|
||||
((), (None, (0, 0, 0))),
|
||||
((2, ), (['2'], (2, 0, 0))),
|
||||
((3, ), (['3'], (3, 0, 0))),
|
||||
((3, 6,), (['36'], (3, 6, 0))),
|
||||
((3, 6, 5), (['36'], (3, 6, 5))),
|
||||
# Test a 2-digit minor version.
|
||||
((3, 10), (['310'], (3, 10, 0))),
|
||||
# Test passing None.
|
||||
(None, (None, CURRENT_PY_VERSION_INFO)),
|
||||
])
|
||||
@patch('pip._internal.index.get_supported')
|
||||
def test_create__py_version_info(
|
||||
self, mock_get_supported, py_version_info, expected,
|
||||
):
|
||||
def test_create__target_python(self):
|
||||
"""
|
||||
Test that the py_version_info argument is handled correctly.
|
||||
Test that target_python is passed to CandidateEvaluator as is.
|
||||
"""
|
||||
expected_versions, expected_evaluator_info = expected
|
||||
target_python = TargetPython(py_version_info=(3, 7, 3))
|
||||
finder = PackageFinder.create(
|
||||
[], [], py_version_info=py_version_info, session=object(),
|
||||
[], [], target_python=target_python, session=object(),
|
||||
)
|
||||
actual = mock_get_supported.call_args[1]['versions']
|
||||
assert actual == expected_versions
|
||||
|
||||
# For candidate_evaluator, we only need to test _py_version_info
|
||||
# since setting _py_version correctly is tested in
|
||||
# TestCandidateEvaluator.
|
||||
evaluator = finder.candidate_evaluator
|
||||
assert evaluator._py_version_info == expected_evaluator_info
|
||||
actual_target_python = evaluator._target_python
|
||||
assert actual_target_python is target_python
|
||||
assert actual_target_python.py_version_info == (3, 7, 3)
|
||||
|
||||
|
||||
def test_sort_locations_file_expand_dir(data):
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
import sys
|
||||
|
||||
import pytest
|
||||
from mock import patch
|
||||
|
||||
from pip._internal.models.target_python import TargetPython
|
||||
from tests.lib import CURRENT_PY_VERSION_INFO
|
||||
|
||||
|
||||
class TestTargetPython:
|
||||
|
||||
@pytest.mark.parametrize('py_version_info, expected', [
|
||||
((), ((0, 0, 0), '0.0')),
|
||||
((2, ), ((2, 0, 0), '2.0')),
|
||||
((3, ), ((3, 0, 0), '3.0')),
|
||||
((3, 7), ((3, 7, 0), '3.7')),
|
||||
((3, 7, 3), ((3, 7, 3), '3.7')),
|
||||
# Check a minor version with two digits.
|
||||
((3, 10, 1), ((3, 10, 1), '3.10')),
|
||||
])
|
||||
def test_init__py_version_info(self, py_version_info, expected):
|
||||
"""
|
||||
Test passing the py_version_info argument.
|
||||
"""
|
||||
expected_py_version_info, expected_py_version = expected
|
||||
|
||||
target_python = TargetPython(py_version_info=py_version_info)
|
||||
|
||||
# The _given_py_version_info attribute should be set as is.
|
||||
assert target_python._given_py_version_info == py_version_info
|
||||
|
||||
assert target_python.py_version_info == expected_py_version_info
|
||||
assert target_python.py_version == expected_py_version
|
||||
|
||||
def test_init__py_version_info_none(self):
|
||||
"""
|
||||
Test passing py_version_info=None.
|
||||
"""
|
||||
# Get the index of the second dot.
|
||||
index = sys.version.find('.', 2)
|
||||
current_major_minor = sys.version[:index] # e.g. "3.6"
|
||||
|
||||
target_python = TargetPython(py_version_info=None)
|
||||
|
||||
assert target_python._given_py_version_info is None
|
||||
|
||||
assert target_python.py_version_info == CURRENT_PY_VERSION_INFO
|
||||
assert target_python.py_version == current_major_minor
|
||||
|
||||
@pytest.mark.parametrize('py_version_info, expected_versions', [
|
||||
((), ['']),
|
||||
((2, ), ['2']),
|
||||
((3, ), ['3']),
|
||||
((3, 7), ['37']),
|
||||
((3, 7, 3), ['37']),
|
||||
# Check a minor version with two digits.
|
||||
((3, 10, 1), ['310']),
|
||||
# Check that versions=None is passed to get_tags().
|
||||
(None, None),
|
||||
])
|
||||
@patch('pip._internal.models.target_python.get_supported')
|
||||
def test_get_tags(
|
||||
self, mock_get_supported, py_version_info, expected_versions,
|
||||
):
|
||||
mock_get_supported.return_value = ['tag-1', 'tag-2']
|
||||
|
||||
target_python = TargetPython(py_version_info=py_version_info)
|
||||
actual = target_python.get_tags()
|
||||
assert actual == ['tag-1', 'tag-2']
|
||||
|
||||
actual = mock_get_supported.call_args[1]['versions']
|
||||
assert actual == expected_versions
|
||||
|
||||
# Check that the value was cached.
|
||||
assert target_python._valid_tags == ['tag-1', 'tag-2']
|
||||
|
||||
def test_get_tags__uses_cached_value(self):
|
||||
"""
|
||||
Test that get_tags() uses the cached value.
|
||||
"""
|
||||
target_python = TargetPython(py_version_info=None)
|
||||
target_python._valid_tags = ['tag-1', 'tag-2']
|
||||
actual = target_python.get_tags()
|
||||
assert actual == ['tag-1', 'tag-2']
|
Loading…
Reference in New Issue