Skip to content

Commit

Permalink
Change PackageFinder to use Tuple[int, ...] instead of List[str] for …
Browse files Browse the repository at this point in the history
…--python-version.
  • Loading branch information
cjerdonek committed May 28, 2019
1 parent fada348 commit 798d814
Show file tree
Hide file tree
Showing 9 changed files with 106 additions and 20 deletions.
4 changes: 2 additions & 2 deletions src/pip/_internal/cli/base_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ def _build_package_finder(
options, # type: Values
session, # type: PipSession
platform=None, # type: Optional[str]
python_versions=None, # type: Optional[List[str]]
py_version_info=None, # type: Optional[Tuple[int, ...]]
abi=None, # type: Optional[str]
implementation=None, # type: Optional[str]
ignore_requires_python=None, # type: Optional[bool]
Expand Down Expand Up @@ -352,7 +352,7 @@ def _build_package_finder(
allow_all_prereleases=options.pre,
session=session,
platform=platform,
versions=python_versions,
py_version_info=py_version_info,
abi=abi,
implementation=implementation,
prefer_binary=options.prefer_binary,
Expand Down
27 changes: 26 additions & 1 deletion src/pip/_internal/cli/cmdoptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from pip._internal.utils.ui import BAR_TYPES

if MYPY_CHECK_RUNNING:
from typing import Any, Callable, Dict, Optional
from typing import Any, Callable, Dict, Optional, Tuple
from optparse import OptionParser, Values
from pip._internal.cli.parser import ConfigOptionParser

Expand Down Expand Up @@ -478,11 +478,36 @@ def only_binary():
) # type: Callable[..., Option]


# This was made a separate function for unit-testing purposes.
def _convert_python_version(value):
# type: (str) -> Tuple[int, ...]
"""
Convert a string like "3" or "34" into a tuple of ints.
"""
if len(value) == 1:
parts = [value]
else:
parts = [value[0], value[1:]]

return tuple(int(part) for part in parts)


def _handle_python_version(option, opt_str, value, parser):
# type: (Option, str, str, OptionParser) -> None
"""
Convert a string like "3" or "34" into a tuple of ints.
"""
version_info = _convert_python_version(value)
parser.values.python_version = version_info


python_version = partial(
Option,
'--python-version',
dest='python_version',
metavar='python_version',
action='callback',
callback=_handle_python_version, type='str',
default=None,
help=("Only use wheels compatible with Python "
"interpreter version <version>. If not specified, then the "
Expand Down
7 changes: 1 addition & 6 deletions src/pip/_internal/commands/download.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,6 @@ def run(self, options, args):
# of the RequirementSet code require that property.
options.editables = []

if options.python_version:
python_versions = [options.python_version]
else:
python_versions = None

cmdoptions.check_dist_restriction(options)

options.src_dir = os.path.abspath(options.src_dir)
Expand All @@ -105,7 +100,7 @@ def run(self, options, args):
options=options,
session=session,
platform=options.platform,
python_versions=python_versions,
py_version_info=options.python_version,
abi=options.abi,
implementation=options.implementation,
)
Expand Down
7 changes: 1 addition & 6 deletions src/pip/_internal/commands/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,11 +251,6 @@ def run(self, options, args):

cmdoptions.check_dist_restriction(options, check_target=True)

if options.python_version:
python_versions = [options.python_version]
else:
python_versions = None

options.src_dir = os.path.abspath(options.src_dir)
install_options = options.install_options or []
if options.use_user_site:
Expand Down Expand Up @@ -294,7 +289,7 @@ def run(self, options, args):
options=options,
session=session,
platform=options.platform,
python_versions=python_versions,
py_version_info=options.python_version,
abi=options.abi,
implementation=options.implementation,
ignore_requires_python=options.ignore_requires_python,
Expand Down
15 changes: 11 additions & 4 deletions src/pip/_internal/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
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
from pip._internal.pep425tags import get_supported, version_info_to_nodot
from pip._internal.utils.compat import ipaddress
from pip._internal.utils.logging import indent_log
from pip._internal.utils.misc import (
Expand Down Expand Up @@ -604,7 +604,7 @@ def create(
session=None, # type: Optional[PipSession]
format_control=None, # type: Optional[FormatControl]
platform=None, # type: Optional[str]
versions=None, # type: Optional[List[str]]
py_version_info=None, # type: Optional[Tuple[int, ...]]
abi=None, # type: Optional[str]
implementation=None, # type: Optional[str]
prefer_binary=False, # type: bool
Expand All @@ -624,8 +624,10 @@ def create(
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 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
Expand Down Expand Up @@ -659,6 +661,11 @@ def create(
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

# The valid tags to check potential found wheel candidates against
valid_tags = get_supported(
versions=versions,
Expand Down
6 changes: 6 additions & 0 deletions src/pip/_internal/pep425tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ def get_abbr_impl():
return pyimpl


def version_info_to_nodot(version_info):
# type: (Tuple[int, ...]) -> str
# Only use up to the first two numbers.
return ''.join(map(str, version_info[:2]))


def get_impl_ver():
# type: () -> str
"""Return implementation version."""
Expand Down
15 changes: 15 additions & 0 deletions tests/unit/test_cmdoptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import pytest

from pip._internal.cli.cmdoptions import _convert_python_version


@pytest.mark.parametrize('value, expected', [
('2', (2,)),
('3', (3,)),
('34', (3, 4)),
# Test a 2-digit minor version.
('310', (3, 10)),
])
def test_convert_python_version(value, expected):
actual = _convert_python_version(value)
assert actual == expected
30 changes: 29 additions & 1 deletion tests/unit/test_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import sys

import pytest
from mock import Mock
from mock import Mock, patch
from pip._vendor import html5lib, requests

from pip._internal.download import PipSession
Expand Down Expand Up @@ -149,6 +149,34 @@ def test_evaluate_link__incompatible_wheel(self):
assert actual == expected


class TestPackageFinder:

@pytest.mark.parametrize('version_info, expected', [
((2,), ['2']),
((3,), ['3']),
((3, 6,), ['36']),
# Test a tuple of length 3.
((3, 6, 5), ['36']),
# Test a 2-digit minor version.
((3, 10), ['310']),
# Test falsey values.
(None, None),
((), None),
])
@patch('pip._internal.index.get_supported')
def test_create__py_version_info(
self, mock_get_supported, version_info, expected,
):
"""
Test that the py_version_info argument is handled correctly.
"""
PackageFinder.create(
[], [], py_version_info=version_info, session=object(),
)
actual = mock_get_supported.call_args[1]['versions']
assert actual == expected


def test_sort_locations_file_expand_dir(data):
"""
Test that a file:// dir gets listdir run with expand_dir
Expand Down
15 changes: 15 additions & 0 deletions tests/unit/test_pep425tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,21 @@
from pip._internal import pep425tags


@pytest.mark.parametrize('version_info, expected', [
((2,), '2'),
((2, 8), '28'),
((3,), '3'),
((3, 6), '36'),
# Test a tuple of length 3.
((3, 6, 5), '36'),
# Test a 2-digit minor version.
((3, 10), '310'),
])
def test_version_info_to_nodot(version_info, expected):
actual = pep425tags.version_info_to_nodot(version_info)
assert actual == expected


class TestPEP425Tags(object):

def mock_get_config_var(self, **kwd):
Expand Down

0 comments on commit 798d814

Please sign in to comment.