mirror of https://github.com/pypa/pip
Allow dotted version strings for --python-version.
This commit is contained in:
parent
9c8b2ea759
commit
4bb225d486
|
@ -0,0 +1,2 @@
|
|||
Allow ``--python-version`` to be passed as a dotted version string (e.g.
|
||||
``3.7`` or ``3.7.3``).
|
|
@ -14,6 +14,7 @@ import warnings
|
|||
from distutils.util import strtobool
|
||||
from functools import partial
|
||||
from optparse import SUPPRESS_HELP, Option, OptionGroup
|
||||
from textwrap import dedent
|
||||
|
||||
from pip._internal.exceptions import CommandError
|
||||
from pip._internal.locations import USER_CACHE_DIR, src_prefix
|
||||
|
@ -480,24 +481,49 @@ platform = partial(
|
|||
|
||||
# This was made a separate function for unit-testing purposes.
|
||||
def _convert_python_version(value):
|
||||
# type: (str) -> Tuple[int, ...]
|
||||
# type: (str) -> Tuple[Tuple[int, ...], Optional[str]]
|
||||
"""
|
||||
Convert a string like "3" or "34" into a tuple of ints.
|
||||
"""
|
||||
if len(value) == 1:
|
||||
parts = [value]
|
||||
else:
|
||||
parts = [value[0], value[1:]]
|
||||
Convert a version string like "3", "37", or "3.7.3" into a tuple of ints.
|
||||
|
||||
return tuple(int(part) for part in parts)
|
||||
:return: A 2-tuple (version_info, error_msg), where `error_msg` is
|
||||
non-None if and only if there was a parsing error.
|
||||
"""
|
||||
if not value:
|
||||
# The empty string is the same as not providing a value.
|
||||
return (None, None)
|
||||
|
||||
parts = value.split('.')
|
||||
if len(parts) > 3:
|
||||
return ((), 'at most three version parts are allowed')
|
||||
|
||||
if len(parts) == 1:
|
||||
# Then we are in the case of "3" or "37".
|
||||
value = parts[0]
|
||||
if len(value) > 1:
|
||||
parts = [value[0], value[1:]]
|
||||
|
||||
try:
|
||||
version_info = tuple(int(part) for part in parts)
|
||||
except ValueError:
|
||||
return ((), 'each version part must be an integer')
|
||||
|
||||
return (version_info, None)
|
||||
|
||||
|
||||
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.
|
||||
Handle a provided --python-version value.
|
||||
"""
|
||||
version_info = _convert_python_version(value)
|
||||
version_info, error_msg = _convert_python_version(value)
|
||||
if error_msg is not None:
|
||||
msg = (
|
||||
'invalid --python-version value: {!r}: {}'.format(
|
||||
value, error_msg,
|
||||
)
|
||||
)
|
||||
raise_option_error(parser, option=option, msg=msg)
|
||||
|
||||
parser.values.python_version = version_info
|
||||
|
||||
|
||||
|
@ -509,12 +535,13 @@ python_version = partial(
|
|||
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 "
|
||||
"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."),
|
||||
help=dedent("""\
|
||||
The Python interpreter version to use for wheel and "Requires-Python"
|
||||
compatibility checks. Defaults to a version derived from the running
|
||||
interpreter. The version can be specified using up to three dot-separated
|
||||
integers (e.g. "3" for 3.0.0, "3.7" for 3.7.0, or "3.7.3"). A major-minor
|
||||
version can also be given as a string without dots (e.g. "37" for 3.7.0).
|
||||
"""),
|
||||
) # type: Callable[..., Option]
|
||||
|
||||
|
||||
|
|
|
@ -4,12 +4,21 @@ from pip._internal.cli.cmdoptions import _convert_python_version
|
|||
|
||||
|
||||
@pytest.mark.parametrize('value, expected', [
|
||||
('2', (2,)),
|
||||
('3', (3,)),
|
||||
('34', (3, 4)),
|
||||
('', (None, None)),
|
||||
('2', ((2,), None)),
|
||||
('3', ((3,), None)),
|
||||
('3.7', ((3, 7), None)),
|
||||
('3.7.3', ((3, 7, 3), None)),
|
||||
# Test strings without dots of length bigger than 1.
|
||||
('34', ((3, 4), None)),
|
||||
# Test a 2-digit minor version.
|
||||
('310', (3, 10)),
|
||||
('310', ((3, 10), None)),
|
||||
# Test some values that fail to parse.
|
||||
('ab', ((), 'each version part must be an integer')),
|
||||
('3a', ((), 'each version part must be an integer')),
|
||||
('3.7.a', ((), 'each version part must be an integer')),
|
||||
('3.7.3.1', ((), 'at most three version parts are allowed')),
|
||||
])
|
||||
def test_convert_python_version(value, expected):
|
||||
actual = _convert_python_version(value)
|
||||
assert actual == expected
|
||||
assert actual == expected, 'actual: {!r}'.format(actual)
|
||||
|
|
Loading…
Reference in New Issue