diff --git a/src/pip/_internal/index.py b/src/pip/_internal/index.py index 43510fa9c..98b2b4c40 100644 --- a/src/pip/_internal/index.py +++ b/src/pip/_internal/index.py @@ -266,10 +266,24 @@ class CandidateEvaluator(object): def __init__( self, valid_tags, # type: List[Pep425Tag] - prefer_binary=False # type: bool + prefer_binary=False, # type: bool + py_version_info=None, # type: Optional[Tuple[int, ...]] ): # type: (...) -> None + """ + :param py_version_info: The Python version, as a 3-tuple of ints + representing a major-minor-micro version, to use to check both + the Python version embedded in the filename and the package's + "Requires-Python" metadata. Defaults to `sys.version_info[:3]`. + """ + if py_version_info is None: + py_version_info = sys.version_info[:3] + + py_version = '.'.join(map(str, py_version_info[:2])) + self._prefer_binary = prefer_binary + self._py_version = py_version + self._py_version_info = py_version_info self._valid_tags = valid_tags # We compile the regex here instead of as a class attribute so as @@ -342,11 +356,11 @@ class CandidateEvaluator(object): if match: version = version[:match.start()] py_version = match.group(1) - if py_version != sys.version[:3]: + if py_version != self._py_version: return (False, 'Python version is incorrect') try: support_this_python = check_requires_python( - link.requires_python, version_info=sys.version_info[:3], + link.requires_python, version_info=self._py_version_info, ) except specifiers.InvalidSpecifier: logger.debug("Package %s has an invalid Requires-Python entry: %s", diff --git a/tests/unit/test_index.py b/tests/unit/test_index.py index 3bdd5695d..72c76b08a 100644 --- a/tests/unit/test_index.py +++ b/tests/unit/test_index.py @@ -1,5 +1,6 @@ import logging import os.path +import sys import pytest from mock import Mock @@ -7,11 +8,36 @@ from pip._vendor import html5lib, requests from pip._internal.download import PipSession from pip._internal.index import ( - Link, PackageFinder, _clean_link, _determine_base_url, _egg_info_matches, - _find_name_version_sep, _get_html_page, + CandidateEvaluator, Link, PackageFinder, _clean_link, _determine_base_url, + _egg_info_matches, _find_name_version_sep, _get_html_page, ) +class TestCandidateEvaluator: + + @pytest.mark.parametrize("version_info, expected", [ + ((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(self, version_info, expected): + """ + Test the _py_version attribute. + """ + evaluator = CandidateEvaluator([], py_version_info=version_info) + assert evaluator._py_version == expected + + def test_init__py_version_default(self): + """ + Test the _py_version attribute's default value. + """ + evaluator = CandidateEvaluator([]) + # Get the index of the second dot. + index = sys.version.find('.', 2) + assert evaluator._py_version == sys.version[:index] + + def test_sort_locations_file_expand_dir(data): """ Test that a file:// dir gets listdir run with expand_dir