[pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci
This commit is contained in:
pre-commit-ci[bot] 2024-04-13 00:00:18 +00:00
parent 72ad6dc953
commit f4cd1ba0d6
813 changed files with 66015 additions and 58839 deletions

View file

@ -1,3 +1,5 @@
from __future__ import annotations
from .more import * # noqa
from .recipes import * # noqa

View file

@ -1,39 +1,55 @@
import warnings
from __future__ import annotations
from collections import Counter, defaultdict, deque, abc
import warnings
from collections import abc
from collections import Counter
from collections import defaultdict
from collections import deque
from collections.abc import Sequence
from concurrent.futures import ThreadPoolExecutor
from functools import partial, reduce, wraps
from heapq import merge, heapify, heapreplace, heappop
from itertools import (
chain,
compress,
count,
cycle,
dropwhile,
groupby,
islice,
repeat,
starmap,
takewhile,
tee,
zip_longest,
)
from math import exp, factorial, floor, log
from queue import Empty, Queue
from random import random, randrange, uniform
from operator import itemgetter, mul, sub, gt, lt
from sys import hexversion, maxsize
from functools import partial
from functools import reduce
from functools import wraps
from heapq import heapify
from heapq import heappop
from heapq import heapreplace
from heapq import merge
from itertools import chain
from itertools import compress
from itertools import count
from itertools import cycle
from itertools import dropwhile
from itertools import groupby
from itertools import islice
from itertools import repeat
from itertools import starmap
from itertools import takewhile
from itertools import tee
from itertools import zip_longest
from math import exp
from math import factorial
from math import floor
from math import log
from operator import gt
from operator import itemgetter
from operator import lt
from operator import mul
from operator import sub
from queue import Empty
from queue import Queue
from random import random
from random import randrange
from random import uniform
from sys import hexversion
from sys import maxsize
from time import monotonic
from .recipes import (
consume,
flatten,
pairwise,
powerset,
take,
unique_everseen,
)
from .recipes import consume
from .recipes import flatten
from .recipes import pairwise
from .recipes import powerset
from .recipes import take
from .recipes import unique_everseen
__all__ = [
'AbortThread',
@ -180,7 +196,7 @@ def first(iterable, default=_marker):
if default is _marker:
raise ValueError(
'first() was called on an empty iterable, and no '
'default value was provided.'
'default value was provided.',
) from e
return default
@ -209,7 +225,7 @@ def last(iterable, default=_marker):
if default is _marker:
raise ValueError(
'last() was called on an empty iterable, and no default was '
'provided.'
'provided.',
)
return default
@ -428,7 +444,7 @@ def collate(*iterables, **kwargs):
"""
warnings.warn(
"collate is no longer part of more_itertools, use heapq.merge",
'collate is no longer part of more_itertools, use heapq.merge',
DeprecationWarning,
)
return merge(*iterables, **kwargs)
@ -624,7 +640,7 @@ def distinct_permutations(iterable, r=None):
# Swap the value of A[i] with that of A[j], then reverse the
# sequence from A[i + 1] to form the new permutation
A[i], A[j] = A[j], A[i]
A[i + 1 :] = A[: i - size : -1] # A[i + 1:][::-1]
A[i + 1:] = A[: i - size: -1] # A[i + 1:][::-1]
# Algorithm: modified from the above
def _partial(A, r):
@ -662,9 +678,9 @@ def distinct_permutations(iterable, r=None):
break
# Reverse head[i + 1:] and swap it with tail[:r - (i + 1)]
tail += head[: i - r : -1] # head[i + 1:][::-1]
tail += head[: i - r: -1] # head[i + 1:][::-1]
i += 1
head[i:], tail[:] = tail[: r - i], tail[r - i :]
head[i:], tail[:] = tail[: r - i], tail[r - i:]
items = sorted(iterable)
@ -811,7 +827,7 @@ def substrings(iterable):
# And the rest
for n in range(2, item_count + 1):
for i in range(item_count - n + 1):
yield seq[i : i + n]
yield seq[i: i + n]
def substrings_indexes(seq, reverse=False):
@ -844,7 +860,7 @@ def substrings_indexes(seq, reverse=False):
if reverse:
r = reversed(r)
return (
(seq[i : i + L], i, i + L) for L in r for i in range(len(seq) - L + 1)
(seq[i: i + L], i, i + L) for L in r for i in range(len(seq) - L + 1)
)
@ -1046,9 +1062,9 @@ def collapse(iterable, base_type=None, levels=None):
def walk(node, level):
if (
((levels is not None) and (level > levels))
or isinstance(node, (str, bytes))
or ((base_type is not None) and isinstance(node, base_type))
((levels is not None) and (level > levels)) or
isinstance(node, (str, bytes)) or
((base_type is not None) and isinstance(node, base_type))
):
yield node
return
@ -1146,13 +1162,13 @@ def sliced(seq, n, strict=False):
For non-sliceable iterables, see :func:`chunked`.
"""
iterator = takewhile(len, (seq[i : i + n] for i in count(0, n)))
iterator = takewhile(len, (seq[i: i + n] for i in count(0, n)))
if strict:
def ret():
for _slice in iterator:
if len(_slice) != n:
raise ValueError("seq is not divisible by n.")
raise ValueError('seq is not divisible by n.')
yield _slice
return iter(ret())
@ -1475,7 +1491,7 @@ def stagger(iterable, offsets=(-1, 0, 1), longest=False, fillvalue=None):
children = tee(iterable, len(offsets))
return zip_offset(
*children, offsets=offsets, longest=longest, fillvalue=fillvalue
*children, offsets=offsets, longest=longest, fillvalue=fillvalue,
)
@ -1484,7 +1500,7 @@ class UnequalIterablesError(ValueError):
msg = 'Iterables have different lengths'
if details is not None:
msg += (': index 0 has length {}; index {} has length {}').format(
*details
*details,
)
super().__init__(msg)
@ -1635,17 +1651,18 @@ def sort_together(iterables, key_list=(0,), key=None, reverse=False):
# if key_list contains a single item, pass the item at that offset
# as the only argument to the key function
key_offset = key_list[0]
key_argument = lambda zipped_items: key(zipped_items[key_offset])
def key_argument(zipped_items): return key(zipped_items[key_offset])
else:
# if key_list contains multiple items, use itemgetter to return a
# tuple of items, which we pass as *args to the key function
get_key_items = itemgetter(*key_list)
key_argument = lambda zipped_items: key(
*get_key_items(zipped_items)
def key_argument(zipped_items): return key(
*get_key_items(zipped_items),
)
return list(
zip(*sorted(zip(*iterables), key=key_argument, reverse=reverse))
zip(*sorted(zip(*iterables), key=key_argument, reverse=reverse)),
)
@ -1954,12 +1971,12 @@ class numeric_range(abc.Sequence, abc.Hashable):
elif argc == 0:
raise TypeError(
'numeric_range expected at least '
'1 argument, got {}'.format(argc)
'1 argument, got {}'.format(argc),
)
else:
raise TypeError(
'numeric_range expected at most '
'3 arguments, got {}'.format(argc)
'3 arguments, got {}'.format(argc),
)
self._zero = type(self._step)(0)
@ -1992,9 +2009,9 @@ class numeric_range(abc.Sequence, abc.Hashable):
return empty_self and empty_other # True if both empty
else:
return (
self._start == other._start
and self._step == other._step
and self._get_by_index(-1) == other._get_by_index(-1)
self._start == other._start and
self._step == other._step and
self._get_by_index(-1) == other._get_by_index(-1)
)
else:
return False
@ -2023,7 +2040,7 @@ class numeric_range(abc.Sequence, abc.Hashable):
else:
raise TypeError(
'numeric range indices must be '
'integers or slices, not {}'.format(type(key).__name__)
'integers or slices, not {}'.format(type(key).__name__),
)
def __hash__(self):
@ -2063,19 +2080,19 @@ class numeric_range(abc.Sequence, abc.Hashable):
def __repr__(self):
if self._step == 1:
return "numeric_range({}, {})".format(
repr(self._start), repr(self._stop)
return 'numeric_range({}, {})'.format(
repr(self._start), repr(self._stop),
)
else:
return "numeric_range({}, {}, {})".format(
repr(self._start), repr(self._stop), repr(self._step)
return 'numeric_range({}, {}, {})'.format(
repr(self._start), repr(self._stop), repr(self._step),
)
def __reversed__(self):
return iter(
numeric_range(
self._get_by_index(-1), self._start - self._step, -self._step
)
self._get_by_index(-1), self._start - self._step, -self._step,
),
)
def count(self, value):
@ -2093,13 +2110,13 @@ class numeric_range(abc.Sequence, abc.Hashable):
if r == self._zero:
return int(q)
raise ValueError("{} is not in numeric range".format(value))
raise ValueError(f'{value} is not in numeric range')
def _get_by_index(self, i):
if i < 0:
i += self._len
if i < 0 or i >= self._len:
raise IndexError("numeric range object index out of range")
raise IndexError('numeric range object index out of range')
return self._start + i * self._step
@ -2468,7 +2485,7 @@ def consecutive_groups(iterable, ordering=lambda x: x):
"""
for k, g in groupby(
enumerate(iterable), key=lambda x: x[0] - ordering(x[1])
enumerate(iterable), key=lambda x: x[0] - ordering(x[1]),
):
yield map(itemgetter(1), g)
@ -2557,7 +2574,7 @@ class SequenceView(Sequence):
return len(self._target)
def __repr__(self):
return '{}({})'.format(self.__class__.__name__, repr(self._target))
return f'{self.__class__.__name__}({repr(self._target)})'
class seekable:
@ -3043,7 +3060,7 @@ def set_partitions(iterable, k=None):
if k is not None:
if k < 1:
raise ValueError(
"Can't partition in a negative or zero number of groups"
"Can't partition in a negative or zero number of groups",
)
elif k > n:
return
@ -3060,7 +3077,7 @@ def set_partitions(iterable, k=None):
yield [[e], *p]
for p in set_partitions_helper(M, k):
for i in range(len(p)):
yield p[:i] + [[e] + p[i]] + p[i + 1 :]
yield p[:i] + [[e] + p[i]] + p[i + 1:]
if k is None:
for k in range(1, n + 1):
@ -3225,9 +3242,9 @@ def distinct_combinations(iterable, r):
else:
generators.append(
unique_everseen(
enumerate(pool[cur_idx + 1 :], cur_idx + 1),
enumerate(pool[cur_idx + 1:], cur_idx + 1),
key=itemgetter(1),
)
),
)
level += 1
@ -3493,7 +3510,7 @@ class callback_iter:
q.put((args, kwargs))
self._future = self._executor.submit(
self._func, **{self._callback_kwd: callback}
self._func, **{self._callback_kwd: callback},
)
while True:
@ -3556,8 +3573,8 @@ def windowed_complete(iterable, n):
for i in range(size - n + 1):
beginning = seq[:i]
middle = seq[i : i + n]
end = seq[i + n :]
middle = seq[i: i + n]
end = seq[i + n:]
yield beginning, middle, end

View file

@ -7,22 +7,24 @@ Some backward-compatible usability improvements have been made.
.. [1] http://docs.python.org/library/itertools.html#recipes
"""
from __future__ import annotations
import operator
import warnings
from collections import deque
from itertools import (
chain,
combinations,
count,
cycle,
groupby,
islice,
repeat,
starmap,
tee,
zip_longest,
)
import operator
from random import randrange, sample, choice
from itertools import chain
from itertools import combinations
from itertools import count
from itertools import cycle
from itertools import groupby
from itertools import islice
from itertools import repeat
from itertools import starmap
from itertools import tee
from itertools import zip_longest
from random import choice
from random import randrange
from random import sample
__all__ = [
'all_equal',
@ -290,7 +292,7 @@ def grouper(iterable, n, fillvalue=None):
"""
if isinstance(iterable, int):
warnings.warn(
"grouper expects iterable as first parameter", DeprecationWarning
'grouper expects iterable as first parameter', DeprecationWarning,
)
n, iterable = iterable, n
args = [iter(iterable)] * n

View file

@ -5,6 +5,8 @@ entry has an index that can be looked up.
Based on a recipe originally posted to ActiveState Recipes by Raymond Hettiger,
and released under the MIT license.
"""
from __future__ import annotations
import itertools as it
from collections import deque
@ -13,10 +15,10 @@ try:
from collections.abc import MutableSet, Sequence
except ImportError:
# Python 2.7
from collections import MutableSet, Sequence
from collections.abc import MutableSet, Sequence
SLICE_ALL = slice(None)
__version__ = "3.1"
__version__ = '3.1'
def is_iterable(obj):
@ -33,9 +35,9 @@ def is_iterable(obj):
have an `__iter__` attribute anyway.
"""
return (
hasattr(obj, "__iter__")
and not isinstance(obj, str)
and not isinstance(obj, tuple)
hasattr(obj, '__iter__') and
not isinstance(obj, str) and
not isinstance(obj, tuple)
)
@ -89,7 +91,7 @@ class OrderedSet(MutableSet, Sequence):
return self.copy()
elif is_iterable(index):
return [self.items[i] for i in index]
elif hasattr(index, "__index__") or isinstance(index, slice):
elif hasattr(index, '__index__') or isinstance(index, slice):
result = self.items[index]
if isinstance(result, list):
return self.__class__(result)
@ -181,7 +183,7 @@ class OrderedSet(MutableSet, Sequence):
item_index = self.add(item)
except TypeError:
raise ValueError(
"Argument needs to be an iterable, got %s" % type(sequence)
'Argument needs to be an iterable, got %s' % type(sequence),
)
return item_index
@ -218,7 +220,7 @@ class OrderedSet(MutableSet, Sequence):
3
"""
if not self.items:
raise KeyError("Set is empty")
raise KeyError('Set is empty')
elem = self.items[-1]
del self.items[-1]
@ -274,8 +276,8 @@ class OrderedSet(MutableSet, Sequence):
def __repr__(self):
if not self:
return "%s()" % (self.__class__.__name__,)
return "%s(%r)" % (self.__class__.__name__, list(self))
return '{}()'.format(self.__class__.__name__)
return '{}({!r})'.format(self.__class__.__name__, list(self))
def __eq__(self, other):
"""
@ -484,5 +486,5 @@ class OrderedSet(MutableSet, Sequence):
items_to_add = [item for item in other if item not in self]
items_to_remove = set(other)
self._update_items(
[item for item in self.items if item not in items_to_remove] + items_to_add
[item for item in self.items if item not in items_to_remove] + items_to_add,
)

View file

@ -1,27 +1,27 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from __future__ import annotations
__all__ = [
"__title__",
"__summary__",
"__uri__",
"__version__",
"__author__",
"__email__",
"__license__",
"__copyright__",
'__title__',
'__summary__',
'__uri__',
'__version__',
'__author__',
'__email__',
'__license__',
'__copyright__',
]
__title__ = "packaging"
__summary__ = "Core utilities for Python packages"
__uri__ = "https://github.com/pypa/packaging"
__title__ = 'packaging'
__summary__ = 'Core utilities for Python packages'
__uri__ = 'https://github.com/pypa/packaging'
__version__ = "20.4"
__version__ = '20.4'
__author__ = "Donald Stufft and individual contributors"
__email__ = "donald@stufft.io"
__author__ = 'Donald Stufft and individual contributors'
__email__ = 'donald@stufft.io'
__license__ = "BSD-2-Clause or Apache-2.0"
__copyright__ = "Copyright 2014-2019 %s" % __author__
__license__ = 'BSD-2-Clause or Apache-2.0'
__copyright__ = 'Copyright 2014-2019 %s' % __author__

View file

@ -1,26 +1,24 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from __future__ import annotations
from .__about__ import (
__author__,
__copyright__,
__email__,
__license__,
__summary__,
__title__,
__uri__,
__version__,
)
from .__about__ import __author__
from .__about__ import __copyright__
from .__about__ import __email__
from .__about__ import __license__
from .__about__ import __summary__
from .__about__ import __title__
from .__about__ import __uri__
from .__about__ import __version__
__all__ = [
"__title__",
"__summary__",
"__uri__",
"__version__",
"__author__",
"__email__",
"__license__",
"__copyright__",
'__title__',
'__summary__',
'__uri__',
'__version__',
'__author__',
'__email__',
'__license__',
'__copyright__',
]

View file

@ -1,7 +1,7 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from __future__ import annotations
import sys
@ -35,4 +35,4 @@ def with_metaclass(meta, *bases):
# type: (Type[Any], str, Tuple[Any], Dict[Any, Any]) -> Any
return meta(name, bases, d)
return type.__new__(metaclass, "temporary_class", (), {})
return type.__new__(metaclass, 'temporary_class', (), {})

View file

@ -1,13 +1,13 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from __future__ import annotations
class InfinityType(object):
class InfinityType:
def __repr__(self):
# type: () -> str
return "Infinity"
return 'Infinity'
def __hash__(self):
# type: () -> int
@ -45,10 +45,10 @@ class InfinityType(object):
Infinity = InfinityType()
class NegativeInfinityType(object):
class NegativeInfinityType:
def __repr__(self):
# type: () -> str
return "-Infinity"
return '-Infinity'
def __hash__(self):
# type: () -> int

View file

@ -25,8 +25,9 @@ In packaging, all static-typing related imports should be guarded as follows:
Ref: https://github.com/python/mypy/issues/3216
"""
from __future__ import annotations
__all__ = ["TYPE_CHECKING", "cast"]
__all__ = ['TYPE_CHECKING', 'cast']
# The TYPE_CHECKING constant defined by the typing module is False at runtime
# but True while type checking.

View file

@ -1,20 +1,27 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from __future__ import annotations
import operator
import os
import platform
import sys
from setuptools.extern.pyparsing import ParseException, ParseResults, stringStart, stringEnd
from setuptools.extern.pyparsing import ZeroOrMore, Group, Forward, QuotedString
from setuptools.extern.pyparsing import Forward
from setuptools.extern.pyparsing import Group
from setuptools.extern.pyparsing import Literal as L # noqa
from setuptools.extern.pyparsing import ParseException
from setuptools.extern.pyparsing import ParseResults
from setuptools.extern.pyparsing import QuotedString
from setuptools.extern.pyparsing import stringEnd
from setuptools.extern.pyparsing import stringStart
from setuptools.extern.pyparsing import ZeroOrMore
from ._compat import string_types
from ._typing import TYPE_CHECKING
from .specifiers import Specifier, InvalidSpecifier
from .specifiers import InvalidSpecifier
from .specifiers import Specifier
if TYPE_CHECKING: # pragma: no cover
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
@ -23,11 +30,11 @@ if TYPE_CHECKING: # pragma: no cover
__all__ = [
"InvalidMarker",
"UndefinedComparison",
"UndefinedEnvironmentName",
"Marker",
"default_environment",
'InvalidMarker',
'UndefinedComparison',
'UndefinedEnvironmentName',
'Marker',
'default_environment',
]
@ -50,7 +57,7 @@ class UndefinedEnvironmentName(ValueError):
"""
class Node(object):
class Node:
def __init__(self, value):
# type: (Any) -> None
self.value = value
@ -61,7 +68,7 @@ class Node(object):
def __repr__(self):
# type: () -> str
return "<{0}({1!r})>".format(self.__class__.__name__, str(self))
return f'<{self.__class__.__name__}({str(self)!r})>'
def serialize(self):
# type: () -> str
@ -77,7 +84,7 @@ class Variable(Node):
class Value(Node):
def serialize(self):
# type: () -> str
return '"{0}"'.format(self)
return f'"{self}"'
class Op(Node):
@ -87,54 +94,54 @@ class Op(Node):
VARIABLE = (
L("implementation_version")
| L("platform_python_implementation")
| L("implementation_name")
| L("python_full_version")
| L("platform_release")
| L("platform_version")
| L("platform_machine")
| L("platform_system")
| L("python_version")
| L("sys_platform")
| L("os_name")
| L("os.name") # PEP-345
| L("sys.platform") # PEP-345
| L("platform.version") # PEP-345
| L("platform.machine") # PEP-345
| L("platform.python_implementation") # PEP-345
| L("python_implementation") # undocumented setuptools legacy
| L("extra") # PEP-508
L('implementation_version') |
L('platform_python_implementation') |
L('implementation_name') |
L('python_full_version') |
L('platform_release') |
L('platform_version') |
L('platform_machine') |
L('platform_system') |
L('python_version') |
L('sys_platform') |
L('os_name') |
L('os.name') | # PEP-345
L('sys.platform') | # PEP-345
L('platform.version') | # PEP-345
L('platform.machine') | # PEP-345
L('platform.python_implementation') | # PEP-345
L('python_implementation') | # undocumented setuptools legacy
L('extra') # PEP-508
)
ALIASES = {
"os.name": "os_name",
"sys.platform": "sys_platform",
"platform.version": "platform_version",
"platform.machine": "platform_machine",
"platform.python_implementation": "platform_python_implementation",
"python_implementation": "platform_python_implementation",
'os.name': 'os_name',
'sys.platform': 'sys_platform',
'platform.version': 'platform_version',
'platform.machine': 'platform_machine',
'platform.python_implementation': 'platform_python_implementation',
'python_implementation': 'platform_python_implementation',
}
VARIABLE.setParseAction(lambda s, l, t: Variable(ALIASES.get(t[0], t[0])))
VERSION_CMP = (
L("===") | L("==") | L(">=") | L("<=") | L("!=") | L("~=") | L(">") | L("<")
L('===') | L('==') | L('>=') | L('<=') | L('!=') | L('~=') | L('>') | L('<')
)
MARKER_OP = VERSION_CMP | L("not in") | L("in")
MARKER_OP = VERSION_CMP | L('not in') | L('in')
MARKER_OP.setParseAction(lambda s, l, t: Op(t[0]))
MARKER_VALUE = QuotedString("'") | QuotedString('"')
MARKER_VALUE.setParseAction(lambda s, l, t: Value(t[0]))
BOOLOP = L("and") | L("or")
BOOLOP = L('and') | L('or')
MARKER_VAR = VARIABLE | MARKER_VALUE
MARKER_ITEM = Group(MARKER_VAR + MARKER_OP + MARKER_VAR)
MARKER_ITEM.setParseAction(lambda s, l, t: tuple(t[0]))
LPAREN = L("(").suppress()
RPAREN = L(")").suppress()
LPAREN = L('(').suppress()
RPAREN = L(')').suppress()
MARKER_EXPR = Forward()
MARKER_ATOM = MARKER_ITEM | Group(LPAREN + MARKER_EXPR + RPAREN)
@ -161,40 +168,40 @@ def _format_marker(marker, first=True):
# the rest of this function so that we don't get extraneous () on the
# outside.
if (
isinstance(marker, list)
and len(marker) == 1
and isinstance(marker[0], (list, tuple))
isinstance(marker, list) and
len(marker) == 1 and
isinstance(marker[0], (list, tuple))
):
return _format_marker(marker[0])
if isinstance(marker, list):
inner = (_format_marker(m, first=False) for m in marker)
if first:
return " ".join(inner)
return ' '.join(inner)
else:
return "(" + " ".join(inner) + ")"
return '(' + ' '.join(inner) + ')'
elif isinstance(marker, tuple):
return " ".join([m.serialize() for m in marker])
return ' '.join([m.serialize() for m in marker])
else:
return marker
_operators = {
"in": lambda lhs, rhs: lhs in rhs,
"not in": lambda lhs, rhs: lhs not in rhs,
"<": operator.lt,
"<=": operator.le,
"==": operator.eq,
"!=": operator.ne,
">=": operator.ge,
">": operator.gt,
'in': lambda lhs, rhs: lhs in rhs,
'not in': lambda lhs, rhs: lhs not in rhs,
'<': operator.lt,
'<=': operator.le,
'==': operator.eq,
'!=': operator.ne,
'>=': operator.ge,
'>': operator.gt,
} # type: Dict[str, Operator]
def _eval_op(lhs, op, rhs):
# type: (str, Op, str) -> bool
try:
spec = Specifier("".join([op.serialize(), rhs]))
spec = Specifier(''.join([op.serialize(), rhs]))
except InvalidSpecifier:
pass
else:
@ -203,13 +210,13 @@ def _eval_op(lhs, op, rhs):
oper = _operators.get(op.serialize()) # type: Optional[Operator]
if oper is None:
raise UndefinedComparison(
"Undefined {0!r} on {1!r} and {2!r}.".format(op, lhs, rhs)
f'Undefined {op!r} on {lhs!r} and {rhs!r}.',
)
return oper(lhs, rhs)
class Undefined(object):
class Undefined:
pass
@ -222,7 +229,7 @@ def _get_env(environment, name):
if isinstance(value, Undefined):
raise UndefinedEnvironmentName(
"{0!r} does not exist in evaluation environment.".format(name)
f'{name!r} does not exist in evaluation environment.',
)
return value
@ -249,8 +256,8 @@ def _evaluate_markers(markers, environment):
groups[-1].append(_eval_op(lhs_value, op, rhs_value))
else:
assert marker in ["and", "or"]
if marker == "or":
assert marker in ['and', 'or']
if marker == 'or':
groups.append([])
return any(all(item) for item in groups)
@ -258,48 +265,48 @@ def _evaluate_markers(markers, environment):
def format_full_version(info):
# type: (sys._version_info) -> str
version = "{0.major}.{0.minor}.{0.micro}".format(info)
version = '{0.major}.{0.minor}.{0.micro}'.format(info)
kind = info.releaselevel
if kind != "final":
if kind != 'final':
version += kind[0] + str(info.serial)
return version
def default_environment():
# type: () -> Dict[str, str]
if hasattr(sys, "implementation"):
if hasattr(sys, 'implementation'):
# Ignoring the `sys.implementation` reference for type checking due to
# mypy not liking that the attribute doesn't exist in Python 2.7 when
# run with the `--py27` flag.
iver = format_full_version(sys.implementation.version) # type: ignore
implementation_name = sys.implementation.name # type: ignore
else:
iver = "0"
implementation_name = ""
iver = '0'
implementation_name = ''
return {
"implementation_name": implementation_name,
"implementation_version": iver,
"os_name": os.name,
"platform_machine": platform.machine(),
"platform_release": platform.release(),
"platform_system": platform.system(),
"platform_version": platform.version(),
"python_full_version": platform.python_version(),
"platform_python_implementation": platform.python_implementation(),
"python_version": ".".join(platform.python_version_tuple()[:2]),
"sys_platform": sys.platform,
'implementation_name': implementation_name,
'implementation_version': iver,
'os_name': os.name,
'platform_machine': platform.machine(),
'platform_release': platform.release(),
'platform_system': platform.system(),
'platform_version': platform.version(),
'python_full_version': platform.python_version(),
'platform_python_implementation': platform.python_implementation(),
'python_version': '.'.join(platform.python_version_tuple()[:2]),
'sys_platform': sys.platform,
}
class Marker(object):
class Marker:
def __init__(self, marker):
# type: (str) -> None
try:
self._markers = _coerce_parse_result(MARKER.parseString(marker))
except ParseException as e:
err_str = "Invalid marker: {0!r}, parse error at {1!r}".format(
marker, marker[e.loc : e.loc + 8]
err_str = 'Invalid marker: {!r}, parse error at {!r}'.format(
marker, marker[e.loc: e.loc + 8],
)
raise InvalidMarker(err_str)
@ -309,7 +316,7 @@ class Marker(object):
def __repr__(self):
# type: () -> str
return "<Marker({0!r})>".format(str(self))
return f'<Marker({str(self)!r})>'
def evaluate(self, environment=None):
# type: (Optional[Dict[str, str]]) -> bool

View file

@ -1,19 +1,29 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from __future__ import annotations
import string
import re
from setuptools.extern.pyparsing import stringStart, stringEnd, originalTextFor, ParseException
from setuptools.extern.pyparsing import ZeroOrMore, Word, Optional, Regex, Combine
from setuptools.extern.pyparsing import Literal as L # noqa
import string
from urllib import parse as urlparse
from setuptools.extern.pyparsing import Combine
from setuptools.extern.pyparsing import Literal as L # noqa
from setuptools.extern.pyparsing import Optional
from setuptools.extern.pyparsing import originalTextFor
from setuptools.extern.pyparsing import ParseException
from setuptools.extern.pyparsing import Regex
from setuptools.extern.pyparsing import stringEnd
from setuptools.extern.pyparsing import stringStart
from setuptools.extern.pyparsing import Word
from setuptools.extern.pyparsing import ZeroOrMore
from ._typing import TYPE_CHECKING
from .markers import MARKER_EXPR, Marker
from .specifiers import LegacySpecifier, Specifier, SpecifierSet
from .markers import Marker
from .markers import MARKER_EXPR
from .specifiers import LegacySpecifier
from .specifiers import Specifier
from .specifiers import SpecifierSet
if TYPE_CHECKING: # pragma: no cover
from typing import List
@ -27,43 +37,43 @@ class InvalidRequirement(ValueError):
ALPHANUM = Word(string.ascii_letters + string.digits)
LBRACKET = L("[").suppress()
RBRACKET = L("]").suppress()
LPAREN = L("(").suppress()
RPAREN = L(")").suppress()
COMMA = L(",").suppress()
SEMICOLON = L(";").suppress()
AT = L("@").suppress()
LBRACKET = L('[').suppress()
RBRACKET = L(']').suppress()
LPAREN = L('(').suppress()
RPAREN = L(')').suppress()
COMMA = L(',').suppress()
SEMICOLON = L(';').suppress()
AT = L('@').suppress()
PUNCTUATION = Word("-_.")
PUNCTUATION = Word('-_.')
IDENTIFIER_END = ALPHANUM | (ZeroOrMore(PUNCTUATION) + ALPHANUM)
IDENTIFIER = Combine(ALPHANUM + ZeroOrMore(IDENTIFIER_END))
NAME = IDENTIFIER("name")
NAME = IDENTIFIER('name')
EXTRA = IDENTIFIER
URI = Regex(r"[^ ]+")("url")
URI = Regex(r'[^ ]+')('url')
URL = AT + URI
EXTRAS_LIST = EXTRA + ZeroOrMore(COMMA + EXTRA)
EXTRAS = (LBRACKET + Optional(EXTRAS_LIST) + RBRACKET)("extras")
EXTRAS = (LBRACKET + Optional(EXTRAS_LIST) + RBRACKET)('extras')
VERSION_PEP440 = Regex(Specifier._regex_str, re.VERBOSE | re.IGNORECASE)
VERSION_LEGACY = Regex(LegacySpecifier._regex_str, re.VERBOSE | re.IGNORECASE)
VERSION_ONE = VERSION_PEP440 ^ VERSION_LEGACY
VERSION_MANY = Combine(
VERSION_ONE + ZeroOrMore(COMMA + VERSION_ONE), joinString=",", adjacent=False
)("_raw_spec")
_VERSION_SPEC = Optional(((LPAREN + VERSION_MANY + RPAREN) | VERSION_MANY))
_VERSION_SPEC.setParseAction(lambda s, l, t: t._raw_spec or "")
VERSION_ONE + ZeroOrMore(COMMA + VERSION_ONE), joinString=',', adjacent=False,
)('_raw_spec')
_VERSION_SPEC = Optional((LPAREN + VERSION_MANY + RPAREN) | VERSION_MANY)
_VERSION_SPEC.setParseAction(lambda s, l, t: t._raw_spec or '')
VERSION_SPEC = originalTextFor(_VERSION_SPEC)("specifier")
VERSION_SPEC = originalTextFor(_VERSION_SPEC)('specifier')
VERSION_SPEC.setParseAction(lambda s, l, t: t[1])
MARKER_EXPR = originalTextFor(MARKER_EXPR())("marker")
MARKER_EXPR = originalTextFor(MARKER_EXPR())('marker')
MARKER_EXPR.setParseAction(
lambda s, l, t: Marker(s[t._original_start : t._original_end])
lambda s, l, t: Marker(s[t._original_start: t._original_end]),
)
MARKER_SEPARATOR = SEMICOLON
MARKER = MARKER_SEPARATOR + MARKER_EXPR
@ -76,10 +86,10 @@ NAMED_REQUIREMENT = NAME + Optional(EXTRAS) + (URL_AND_MARKER | VERSION_AND_MARK
REQUIREMENT = stringStart + NAMED_REQUIREMENT + stringEnd
# setuptools.extern.pyparsing isn't thread safe during initialization, so we do it eagerly, see
# issue #104
REQUIREMENT.parseString("x[]")
REQUIREMENT.parseString('x[]')
class Requirement(object):
class Requirement:
"""Parse a requirement.
Parse a given requirement string into its parts, such as name, specifier,
@ -98,21 +108,21 @@ class Requirement(object):
req = REQUIREMENT.parseString(requirement_string)
except ParseException as e:
raise InvalidRequirement(
'Parse error at "{0!r}": {1}'.format(
requirement_string[e.loc : e.loc + 8], e.msg
)
'Parse error at "{!r}": {}'.format(
requirement_string[e.loc: e.loc + 8], e.msg,
),
)
self.name = req.name
if req.url:
parsed_url = urlparse.urlparse(req.url)
if parsed_url.scheme == "file":
if parsed_url.scheme == 'file':
if urlparse.urlunparse(parsed_url) != req.url:
raise InvalidRequirement("Invalid URL given")
raise InvalidRequirement('Invalid URL given')
elif not (parsed_url.scheme and parsed_url.netloc) or (
not parsed_url.scheme and not parsed_url.netloc
):
raise InvalidRequirement("Invalid URL: {0}".format(req.url))
raise InvalidRequirement(f'Invalid URL: {req.url}')
self.url = req.url
else:
self.url = None
@ -125,21 +135,21 @@ class Requirement(object):
parts = [self.name] # type: List[str]
if self.extras:
parts.append("[{0}]".format(",".join(sorted(self.extras))))
parts.append('[{}]'.format(','.join(sorted(self.extras))))
if self.specifier:
parts.append(str(self.specifier))
if self.url:
parts.append("@ {0}".format(self.url))
parts.append(f'@ {self.url}')
if self.marker:
parts.append(" ")
parts.append(' ')
if self.marker:
parts.append("; {0}".format(self.marker))
parts.append(f'; {self.marker}')
return "".join(parts)
return ''.join(parts)
def __repr__(self):
# type: () -> str
return "<Requirement({0!r})>".format(str(self))
return f'<Requirement({str(self)!r})>'

View file

@ -1,17 +1,20 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from __future__ import annotations
import abc
import functools
import itertools
import re
from ._compat import string_types, with_metaclass
from ._compat import string_types
from ._compat import with_metaclass
from ._typing import TYPE_CHECKING
from .utils import canonicalize_version
from .version import Version, LegacyVersion, parse
from .version import LegacyVersion
from .version import parse
from .version import Version
if TYPE_CHECKING: # pragma: no cover
from typing import (
@ -105,15 +108,15 @@ class _IndividualSpecifier(BaseSpecifier):
_operators = {} # type: Dict[str, str]
def __init__(self, spec="", prereleases=None):
def __init__(self, spec='', prereleases=None):
# type: (str, Optional[bool]) -> None
match = self._regex.search(spec)
if not match:
raise InvalidSpecifier("Invalid specifier: '{0}'".format(spec))
raise InvalidSpecifier(f"Invalid specifier: '{spec}'")
self._spec = (
match.group("operator").strip(),
match.group("version").strip(),
match.group('operator').strip(),
match.group('version').strip(),
) # type: Tuple[str, str]
# Store whether or not this Specifier should accept prereleases
@ -122,16 +125,16 @@ class _IndividualSpecifier(BaseSpecifier):
def __repr__(self):
# type: () -> str
pre = (
", prereleases={0!r}".format(self.prereleases)
f', prereleases={self.prereleases!r}'
if self._prereleases is not None
else ""
else ''
)
return "<{0}({1!r}{2})>".format(self.__class__.__name__, str(self), pre)
return f'<{self.__class__.__name__}({str(self)!r}{pre})>'
def __str__(self):
# type: () -> str
return "{0}{1}".format(*self._spec)
return '{}{}'.format(*self._spec)
@property
def _canonical_spec(self):
@ -169,7 +172,7 @@ class _IndividualSpecifier(BaseSpecifier):
def _get_operator(self, op):
# type: (str) -> CallableOperator
operator_callable = getattr(
self, "_compare_{0}".format(self._operators[op])
self, f'_compare_{self._operators[op]}',
) # type: CallableOperator
return operator_callable
@ -231,7 +234,7 @@ class _IndividualSpecifier(BaseSpecifier):
yielded = False
found_prereleases = []
kw = {"prereleases": prereleases if prereleases is not None else True}
kw = {'prereleases': prereleases if prereleases is not None else True}
# Attempt to iterate over all the values in the iterable and if any of
# them match, yield them.
@ -274,15 +277,15 @@ class LegacySpecifier(_IndividualSpecifier):
)
"""
_regex = re.compile(r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE)
_regex = re.compile(r'^\s*' + _regex_str + r'\s*$', re.VERBOSE | re.IGNORECASE)
_operators = {
"==": "equal",
"!=": "not_equal",
"<=": "less_than_equal",
">=": "greater_than_equal",
"<": "less_than",
">": "greater_than",
'==': 'equal',
'!=': 'not_equal',
'<=': 'less_than_equal',
'>=': 'greater_than_equal',
'<': 'less_than',
'>': 'greater_than',
}
def _coerce_version(self, version):
@ -317,7 +320,7 @@ class LegacySpecifier(_IndividualSpecifier):
def _require_version_compare(
fn # type: (Callable[[Specifier, ParsedVersion, str], bool])
fn, # type: (Callable[[Specifier, ParsedVersion, str], bool])
):
# type: (...) -> Callable[[Specifier, ParsedVersion, str], bool]
@functools.wraps(fn)
@ -425,17 +428,17 @@ class Specifier(_IndividualSpecifier):
)
"""
_regex = re.compile(r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE)
_regex = re.compile(r'^\s*' + _regex_str + r'\s*$', re.VERBOSE | re.IGNORECASE)
_operators = {
"~=": "compatible",
"==": "equal",
"!=": "not_equal",
"<=": "less_than_equal",
">=": "greater_than_equal",
"<": "less_than",
">": "greater_than",
"===": "arbitrary",
'~=': 'compatible',
'==': 'equal',
'!=': 'not_equal',
'<=': 'less_than_equal',
'>=': 'greater_than_equal',
'<': 'less_than',
'>': 'greater_than',
'===': 'arbitrary',
}
@_require_version_compare
@ -451,20 +454,20 @@ class Specifier(_IndividualSpecifier):
# We want everything but the last item in the version, but we want to
# ignore post and dev releases and we want to treat the pre-release as
# it's own separate segment.
prefix = ".".join(
prefix = '.'.join(
list(
itertools.takewhile(
lambda x: (not x.startswith("post") and not x.startswith("dev")),
lambda x: (not x.startswith('post') and not x.startswith('dev')),
_version_split(spec),
)
)[:-1]
),
)[:-1],
)
# Add the prefix notation to the end of our string
prefix += ".*"
prefix += '.*'
return self._get_operator(">=")(prospective, spec) and self._get_operator("==")(
prospective, prefix
return self._get_operator('>=')(prospective, spec) and self._get_operator('==')(
prospective, prefix,
)
@_require_version_compare
@ -472,7 +475,7 @@ class Specifier(_IndividualSpecifier):
# type: (ParsedVersion, str) -> bool
# We need special logic to handle prefix matching
if spec.endswith(".*"):
if spec.endswith('.*'):
# In the case of prefix matching we want to ignore local segment.
prospective = Version(prospective.public)
# Split the spec out by dots, and pretend that there is an implicit
@ -492,7 +495,7 @@ class Specifier(_IndividualSpecifier):
# Pad out our two sides with zeros so that they both equal the same
# length.
padded_spec, padded_prospective = _pad_version(
split_spec, shortened_prospective
split_spec, shortened_prospective,
)
return padded_prospective == padded_spec
@ -608,10 +611,10 @@ class Specifier(_IndividualSpecifier):
# operators, and if they are if they are including an explicit
# prerelease.
operator, version = self._spec
if operator in ["==", ">=", "<=", "~=", "==="]:
if operator in ['==', '>=', '<=', '~=', '===']:
# The == specifier can include a trailing .*, if it does we
# want to remove before parsing.
if operator == "==" and version.endswith(".*"):
if operator == '==' and version.endswith('.*'):
version = version[:-2]
# Parse the version, and if it is a pre-release than this
@ -627,13 +630,13 @@ class Specifier(_IndividualSpecifier):
self._prereleases = value
_prefix_regex = re.compile(r"^([0-9]+)((?:a|b|c|rc)[0-9]+)$")
_prefix_regex = re.compile(r'^([0-9]+)((?:a|b|c|rc)[0-9]+)$')
def _version_split(version):
# type: (str) -> List[str]
result = [] # type: List[str]
for item in version.split("."):
for item in version.split('.'):
match = _prefix_regex.search(item)
if match:
result.extend(match.groups())
@ -651,23 +654,23 @@ def _pad_version(left, right):
right_split.append(list(itertools.takewhile(lambda x: x.isdigit(), right)))
# Get the rest of our versions
left_split.append(left[len(left_split[0]) :])
right_split.append(right[len(right_split[0]) :])
left_split.append(left[len(left_split[0]):])
right_split.append(right[len(right_split[0]):])
# Insert our padding
left_split.insert(1, ["0"] * max(0, len(right_split[0]) - len(left_split[0])))
right_split.insert(1, ["0"] * max(0, len(left_split[0]) - len(right_split[0])))
left_split.insert(1, ['0'] * max(0, len(right_split[0]) - len(left_split[0])))
right_split.insert(1, ['0'] * max(0, len(left_split[0]) - len(right_split[0])))
return (list(itertools.chain(*left_split)), list(itertools.chain(*right_split)))
class SpecifierSet(BaseSpecifier):
def __init__(self, specifiers="", prereleases=None):
def __init__(self, specifiers='', prereleases=None):
# type: (str, Optional[bool]) -> None
# Split on , to break each individual specifier into it's own item, and
# strip each item to remove leading/trailing whitespace.
split_specifiers = [s.strip() for s in specifiers.split(",") if s.strip()]
split_specifiers = [s.strip() for s in specifiers.split(',') if s.strip()]
# Parsed each individual specifier, attempting first to make it a
# Specifier and falling back to a LegacySpecifier.
@ -688,16 +691,16 @@ class SpecifierSet(BaseSpecifier):
def __repr__(self):
# type: () -> str
pre = (
", prereleases={0!r}".format(self.prereleases)
f', prereleases={self.prereleases!r}'
if self._prereleases is not None
else ""
else ''
)
return "<SpecifierSet({0!r}{1})>".format(str(self), pre)
return f'<SpecifierSet({str(self)!r}{pre})>'
def __str__(self):
# type: () -> str
return ",".join(sorted(str(s) for s in self._specs))
return ','.join(sorted(str(s) for s in self._specs))
def __hash__(self):
# type: () -> int
@ -721,8 +724,8 @@ class SpecifierSet(BaseSpecifier):
specifier._prereleases = self._prereleases
else:
raise ValueError(
"Cannot combine SpecifierSets with True and False prerelease "
"overrides."
'Cannot combine SpecifierSets with True and False prerelease '
'overrides.',
)
return specifier

View file

@ -1,8 +1,7 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import
from __future__ import annotations
import distutils.util
@ -46,18 +45,18 @@ if TYPE_CHECKING: # pragma: no cover
logger = logging.getLogger(__name__)
INTERPRETER_SHORT_NAMES = {
"python": "py", # Generic.
"cpython": "cp",
"pypy": "pp",
"ironpython": "ip",
"jython": "jy",
'python': 'py', # Generic.
'cpython': 'cp',
'pypy': 'pp',
'ironpython': 'ip',
'jython': 'jy',
} # type: Dict[str, str]
_32_BIT_INTERPRETER = sys.maxsize <= 2 ** 32
class Tag(object):
class Tag:
"""
A representation of the tag triple for a wheel.
@ -65,7 +64,7 @@ class Tag(object):
is also supported.
"""
__slots__ = ["_interpreter", "_abi", "_platform"]
__slots__ = ['_interpreter', '_abi', '_platform']
def __init__(self, interpreter, abi, platform):
# type: (str, str, str) -> None
@ -94,9 +93,9 @@ class Tag(object):
return NotImplemented
return (
(self.platform == other.platform)
and (self.abi == other.abi)
and (self.interpreter == other.interpreter)
(self.platform == other.platform) and
(self.abi == other.abi) and
(self.interpreter == other.interpreter)
)
def __hash__(self):
@ -105,11 +104,11 @@ class Tag(object):
def __str__(self):
# type: () -> str
return "{}-{}-{}".format(self._interpreter, self._abi, self._platform)
return f'{self._interpreter}-{self._abi}-{self._platform}'
def __repr__(self):
# type: () -> str
return "<{self} @ {self_id}>".format(self=self, self_id=id(self))
return f'<{self} @ {id(self)}>'
def parse_tag(tag):
@ -121,10 +120,10 @@ def parse_tag(tag):
compressed tag set.
"""
tags = set()
interpreters, abis, platforms = tag.split("-")
for interpreter in interpreters.split("."):
for abi in abis.split("."):
for platform_ in platforms.split("."):
interpreters, abis, platforms = tag.split('-')
for interpreter in interpreters.split('.'):
for abi in abis.split('.'):
for platform_ in platforms.split('.'):
tags.add(Tag(interpreter, abi, platform_))
return frozenset(tags)
@ -136,13 +135,13 @@ def _warn_keyword_parameter(func_name, kwargs):
"""
if not kwargs:
return False
elif len(kwargs) > 1 or "warn" not in kwargs:
kwargs.pop("warn", None)
elif len(kwargs) > 1 or 'warn' not in kwargs:
kwargs.pop('warn', None)
arg = next(iter(kwargs.keys()))
raise TypeError(
"{}() got an unexpected keyword argument {!r}".format(func_name, arg)
f'{func_name}() got an unexpected keyword argument {arg!r}',
)
return kwargs["warn"]
return kwargs['warn']
def _get_config_var(name, warn=False):
@ -150,14 +149,14 @@ def _get_config_var(name, warn=False):
value = sysconfig.get_config_var(name)
if value is None and warn:
logger.debug(
"Config variable '%s' is unset, Python ABI tag may be incorrect", name
"Config variable '%s' is unset, Python ABI tag may be incorrect", name,
)
return value
def _normalize_string(string):
# type: (str) -> str
return string.replace(".", "_").replace("-", "_")
return string.replace('.', '_').replace('-', '_')
def _abi3_applies(python_version):
@ -175,33 +174,33 @@ def _cpython_abis(py_version, warn=False):
py_version = tuple(py_version) # To allow for version comparison.
abis = []
version = _version_nodot(py_version[:2])
debug = pymalloc = ucs4 = ""
with_debug = _get_config_var("Py_DEBUG", warn)
has_refcount = hasattr(sys, "gettotalrefcount")
debug = pymalloc = ucs4 = ''
with_debug = _get_config_var('Py_DEBUG', warn)
has_refcount = hasattr(sys, 'gettotalrefcount')
# Windows doesn't set Py_DEBUG, so checking for support of debug-compiled
# extension modules is the best option.
# https://github.com/pypa/pip/issues/3383#issuecomment-173267692
has_ext = "_d.pyd" in EXTENSION_SUFFIXES
has_ext = '_d.pyd' in EXTENSION_SUFFIXES
if with_debug or (with_debug is None and (has_refcount or has_ext)):
debug = "d"
debug = 'd'
if py_version < (3, 8):
with_pymalloc = _get_config_var("WITH_PYMALLOC", warn)
with_pymalloc = _get_config_var('WITH_PYMALLOC', warn)
if with_pymalloc or with_pymalloc is None:
pymalloc = "m"
pymalloc = 'm'
if py_version < (3, 3):
unicode_size = _get_config_var("Py_UNICODE_SIZE", warn)
unicode_size = _get_config_var('Py_UNICODE_SIZE', warn)
if unicode_size == 4 or (
unicode_size is None and sys.maxunicode == 0x10FFFF
):
ucs4 = "u"
ucs4 = 'u'
elif debug:
# Debug builds can also load "normal" extension modules.
# We can also assume no UCS-4 or pymalloc requirement.
abis.append("cp{version}".format(version=version))
abis.append(f'cp{version}')
abis.insert(
0,
"cp{version}{debug}{pymalloc}{ucs4}".format(
version=version, debug=debug, pymalloc=pymalloc, ucs4=ucs4
'cp{version}{debug}{pymalloc}{ucs4}'.format(
version=version, debug=debug, pymalloc=pymalloc, ucs4=ucs4,
),
)
return abis
@ -211,7 +210,7 @@ def cpython_tags(
python_version=None, # type: Optional[PythonVersion]
abis=None, # type: Optional[Iterable[str]]
platforms=None, # type: Optional[Iterable[str]]
**kwargs # type: bool
**kwargs, # type: bool
):
# type: (...) -> Iterator[Tag]
"""
@ -229,11 +228,11 @@ def cpython_tags(
If 'abi3' or 'none' are specified in 'abis' then they will be yielded at
their normal position and not at the beginning.
"""
warn = _warn_keyword_parameter("cpython_tags", kwargs)
warn = _warn_keyword_parameter('cpython_tags', kwargs)
if not python_version:
python_version = sys.version_info[:2]
interpreter = "cp{}".format(_version_nodot(python_version[:2]))
interpreter = f'cp{_version_nodot(python_version[:2])}'
if abis is None:
if len(python_version) > 1:
@ -242,7 +241,7 @@ def cpython_tags(
abis = []
abis = list(abis)
# 'abi3' and 'none' are explicitly handled later.
for explicit_abi in ("abi3", "none"):
for explicit_abi in ('abi3', 'none'):
try:
abis.remove(explicit_abi)
except ValueError:
@ -253,23 +252,21 @@ def cpython_tags(
for platform_ in platforms:
yield Tag(interpreter, abi, platform_)
if _abi3_applies(python_version):
for tag in (Tag(interpreter, "abi3", platform_) for platform_ in platforms):
yield tag
for tag in (Tag(interpreter, "none", platform_) for platform_ in platforms):
yield tag
yield from (Tag(interpreter, 'abi3', platform_) for platform_ in platforms)
yield from (Tag(interpreter, 'none', platform_) for platform_ in platforms)
if _abi3_applies(python_version):
for minor_version in range(python_version[1] - 1, 1, -1):
for platform_ in platforms:
interpreter = "cp{version}".format(
version=_version_nodot((python_version[0], minor_version))
interpreter = 'cp{version}'.format(
version=_version_nodot((python_version[0], minor_version)),
)
yield Tag(interpreter, "abi3", platform_)
yield Tag(interpreter, 'abi3', platform_)
def _generic_abi():
# type: () -> Iterator[str]
abi = sysconfig.get_config_var("SOABI")
abi = sysconfig.get_config_var('SOABI')
if abi:
yield _normalize_string(abi)
@ -278,7 +275,7 @@ def generic_tags(
interpreter=None, # type: Optional[str]
abis=None, # type: Optional[Iterable[str]]
platforms=None, # type: Optional[Iterable[str]]
**kwargs # type: bool
**kwargs, # type: bool
):
# type: (...) -> Iterator[Tag]
"""
@ -289,17 +286,17 @@ def generic_tags(
The "none" ABI will be added if it was not explicitly provided.
"""
warn = _warn_keyword_parameter("generic_tags", kwargs)
warn = _warn_keyword_parameter('generic_tags', kwargs)
if not interpreter:
interp_name = interpreter_name()
interp_version = interpreter_version(warn=warn)
interpreter = "".join([interp_name, interp_version])
interpreter = ''.join([interp_name, interp_version])
if abis is None:
abis = _generic_abi()
platforms = list(platforms or _platform_tags())
abis = list(abis)
if "none" not in abis:
abis.append("none")
if 'none' not in abis:
abis.append('none')
for abi in abis:
for platform_ in platforms:
yield Tag(interpreter, abi, platform_)
@ -314,11 +311,11 @@ def _py_interpreter_range(py_version):
all previous versions of that major version.
"""
if len(py_version) > 1:
yield "py{version}".format(version=_version_nodot(py_version[:2]))
yield "py{major}".format(major=py_version[0])
yield f'py{_version_nodot(py_version[:2])}'
yield f'py{py_version[0]}'
if len(py_version) > 1:
for minor in range(py_version[1] - 1, -1, -1):
yield "py{version}".format(version=_version_nodot((py_version[0], minor)))
yield f'py{_version_nodot((py_version[0], minor))}'
def compatible_tags(
@ -340,11 +337,11 @@ def compatible_tags(
platforms = list(platforms or _platform_tags())
for version in _py_interpreter_range(python_version):
for platform_ in platforms:
yield Tag(version, "none", platform_)
yield Tag(version, 'none', platform_)
if interpreter:
yield Tag(interpreter, "none", "any")
yield Tag(interpreter, 'none', 'any')
for version in _py_interpreter_range(python_version):
yield Tag(version, "none", "any")
yield Tag(version, 'none', 'any')
def _mac_arch(arch, is_32bit=_32_BIT_INTERPRETER):
@ -352,37 +349,37 @@ def _mac_arch(arch, is_32bit=_32_BIT_INTERPRETER):
if not is_32bit:
return arch
if arch.startswith("ppc"):
return "ppc"
if arch.startswith('ppc'):
return 'ppc'
return "i386"
return 'i386'
def _mac_binary_formats(version, cpu_arch):
# type: (MacVersion, str) -> List[str]
formats = [cpu_arch]
if cpu_arch == "x86_64":
if cpu_arch == 'x86_64':
if version < (10, 4):
return []
formats.extend(["intel", "fat64", "fat32"])
formats.extend(['intel', 'fat64', 'fat32'])
elif cpu_arch == "i386":
elif cpu_arch == 'i386':
if version < (10, 4):
return []
formats.extend(["intel", "fat32", "fat"])
formats.extend(['intel', 'fat32', 'fat'])
elif cpu_arch == "ppc64":
elif cpu_arch == 'ppc64':
# TODO: Need to care about 32-bit PPC for ppc64 through 10.2?
if version > (10, 5) or version < (10, 4):
return []
formats.append("fat64")
formats.append('fat64')
elif cpu_arch == "ppc":
elif cpu_arch == 'ppc':
if version > (10, 6):
return []
formats.extend(["fat32", "fat"])
formats.extend(['fat32', 'fat'])
formats.append("universal")
formats.append('universal')
return formats
@ -398,7 +395,7 @@ def mac_platforms(version=None, arch=None):
"""
version_str, _, cpu_arch = platform.mac_ver() # type: ignore
if version is None:
version = cast("MacVersion", tuple(map(int, version_str.split(".")[:2])))
version = cast('MacVersion', tuple(map(int, version_str.split('.')[:2])))
else:
version = version
if arch is None:
@ -409,7 +406,7 @@ def mac_platforms(version=None, arch=None):
compat_version = version[0], minor_version
binary_formats = _mac_binary_formats(compat_version, arch)
for binary_format in binary_formats:
yield "macosx_{major}_{minor}_{binary_format}".format(
yield 'macosx_{major}_{minor}_{binary_format}'.format(
major=compat_version[0],
minor=compat_version[1],
binary_format=binary_format,
@ -423,7 +420,7 @@ def _is_manylinux_compatible(name, glibc_version):
try:
import _manylinux # noqa
return bool(getattr(_manylinux, name + "_compatible"))
return bool(getattr(_manylinux, name + '_compatible'))
except (ImportError, AttributeError):
# Fall through to heuristic check below.
pass
@ -449,7 +446,7 @@ def _glibc_version_string_confstr():
try:
# os.confstr("CS_GNU_LIBC_VERSION") returns a string like "glibc 2.17".
version_string = os.confstr( # type: ignore[attr-defined] # noqa: F821
"CS_GNU_LIBC_VERSION"
'CS_GNU_LIBC_VERSION',
)
assert version_string is not None
_, version = version_string.split() # type: Tuple[str, str]
@ -488,7 +485,7 @@ def _glibc_version_string_ctypes():
version_str = gnu_get_libc_version() # type: str
# py2 / py3 compatibility:
if not isinstance(version_str, str):
version_str = version_str.decode("ascii")
version_str = version_str.decode('ascii')
return version_str
@ -502,17 +499,17 @@ def _check_glibc_version(version_str, required_major, minimum_minor):
# random junk that might come after the minor version -- this might happen
# in patched/forked versions of glibc (e.g. Linaro's version of glibc
# uses version strings like "2.20-2014.11"). See gh-3588.
m = re.match(r"(?P<major>[0-9]+)\.(?P<minor>[0-9]+)", version_str)
m = re.match(r'(?P<major>[0-9]+)\.(?P<minor>[0-9]+)', version_str)
if not m:
warnings.warn(
"Expected glibc version with 2 components major.minor,"
" got: %s" % version_str,
'Expected glibc version with 2 components major.minor,'
' got: %s' % version_str,
RuntimeWarning,
)
return False
return (
int(m.group("major")) == required_major
and int(m.group("minor")) >= minimum_minor
int(m.group('major')) == required_major and
int(m.group('minor')) >= minimum_minor
)
@ -528,7 +525,7 @@ def _have_compatible_glibc(required_major, minimum_minor):
# identify the architecture of the running executable in some cases, so we
# determine it dynamically by reading the information from the running
# process. This only applies on Linux, which uses the ELF format.
class _ELFFileHeader(object):
class _ELFFileHeader:
# https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#File_header
class _InvalidELFFileHeader(ValueError):
"""
@ -554,28 +551,28 @@ class _ELFFileHeader(object):
# type: (str) -> int
try:
(result,) = struct.unpack(
fmt, file.read(struct.calcsize(fmt))
fmt, file.read(struct.calcsize(fmt)),
) # type: (int, )
except struct.error:
raise _ELFFileHeader._InvalidELFFileHeader()
return result
self.e_ident_magic = unpack(">I")
self.e_ident_magic = unpack('>I')
if self.e_ident_magic != self.ELF_MAGIC_NUMBER:
raise _ELFFileHeader._InvalidELFFileHeader()
self.e_ident_class = unpack("B")
self.e_ident_class = unpack('B')
if self.e_ident_class not in {self.ELFCLASS32, self.ELFCLASS64}:
raise _ELFFileHeader._InvalidELFFileHeader()
self.e_ident_data = unpack("B")
self.e_ident_data = unpack('B')
if self.e_ident_data not in {self.ELFDATA2LSB, self.ELFDATA2MSB}:
raise _ELFFileHeader._InvalidELFFileHeader()
self.e_ident_version = unpack("B")
self.e_ident_osabi = unpack("B")
self.e_ident_abiversion = unpack("B")
self.e_ident_version = unpack('B')
self.e_ident_osabi = unpack('B')
self.e_ident_abiversion = unpack('B')
self.e_ident_pad = file.read(7)
format_h = "<H" if self.e_ident_data == self.ELFDATA2LSB else ">H"
format_i = "<I" if self.e_ident_data == self.ELFDATA2LSB else ">I"
format_q = "<Q" if self.e_ident_data == self.ELFDATA2LSB else ">Q"
format_h = '<H' if self.e_ident_data == self.ELFDATA2LSB else '>H'
format_i = '<I' if self.e_ident_data == self.ELFDATA2LSB else '>I'
format_q = '<Q' if self.e_ident_data == self.ELFDATA2LSB else '>Q'
format_p = format_i if self.e_ident_class == self.ELFCLASS32 else format_q
self.e_type = unpack(format_h)
self.e_machine = unpack(format_h)
@ -595,9 +592,9 @@ class _ELFFileHeader(object):
def _get_elf_header():
# type: () -> Optional[_ELFFileHeader]
try:
with open(sys.executable, "rb") as f:
with open(sys.executable, 'rb') as f:
elf_header = _ELFFileHeader(f)
except (IOError, OSError, TypeError, _ELFFileHeader._InvalidELFFileHeader):
except (OSError, TypeError, _ELFFileHeader._InvalidELFFileHeader):
return None
return elf_header
@ -635,9 +632,9 @@ def _is_linux_i686():
def _have_compatible_manylinux_abi(arch):
# type: (str) -> bool
if arch == "armv7l":
if arch == 'armv7l':
return _is_linux_armhf()
if arch == "i686":
if arch == 'i686':
return _is_linux_i686()
return True
@ -646,32 +643,32 @@ def _linux_platforms(is_32bit=_32_BIT_INTERPRETER):
# type: (bool) -> Iterator[str]
linux = _normalize_string(distutils.util.get_platform())
if is_32bit:
if linux == "linux_x86_64":
linux = "linux_i686"
elif linux == "linux_aarch64":
linux = "linux_armv7l"
if linux == 'linux_x86_64':
linux = 'linux_i686'
elif linux == 'linux_aarch64':
linux = 'linux_armv7l'
manylinux_support = []
_, arch = linux.split("_", 1)
_, arch = linux.split('_', 1)
if _have_compatible_manylinux_abi(arch):
if arch in {"x86_64", "i686", "aarch64", "armv7l", "ppc64", "ppc64le", "s390x"}:
if arch in {'x86_64', 'i686', 'aarch64', 'armv7l', 'ppc64', 'ppc64le', 's390x'}:
manylinux_support.append(
("manylinux2014", (2, 17))
('manylinux2014', (2, 17)),
) # CentOS 7 w/ glibc 2.17 (PEP 599)
if arch in {"x86_64", "i686"}:
if arch in {'x86_64', 'i686'}:
manylinux_support.append(
("manylinux2010", (2, 12))
('manylinux2010', (2, 12)),
) # CentOS 6 w/ glibc 2.12 (PEP 571)
manylinux_support.append(
("manylinux1", (2, 5))
('manylinux1', (2, 5)),
) # CentOS 5 w/ glibc 2.5 (PEP 513)
manylinux_support_iter = iter(manylinux_support)
for name, glibc_version in manylinux_support_iter:
if _is_manylinux_compatible(name, glibc_version):
yield linux.replace("linux", name)
yield linux.replace('linux', name)
break
# Support for a later manylinux implies support for an earlier version.
for name, _ in manylinux_support_iter:
yield linux.replace("linux", name)
yield linux.replace('linux', name)
yield linux
@ -685,9 +682,9 @@ def _platform_tags():
"""
Provides the platform tags for this installation.
"""
if platform.system() == "Darwin":
if platform.system() == 'Darwin':
return mac_platforms()
elif platform.system() == "Linux":
elif platform.system() == 'Linux':
return _linux_platforms()
else:
return _generic_platforms()
@ -711,8 +708,8 @@ def interpreter_version(**kwargs):
"""
Returns the version of the running interpreter.
"""
warn = _warn_keyword_parameter("interpreter_version", kwargs)
version = _get_config_var("py_version_nodot", warn=warn)
warn = _warn_keyword_parameter('interpreter_version', kwargs)
version = _get_config_var('py_version_nodot', warn=warn)
if version:
version = str(version)
else:
@ -723,9 +720,9 @@ def interpreter_version(**kwargs):
def _version_nodot(version):
# type: (PythonVersion) -> str
if any(v >= 10 for v in version):
sep = "_"
sep = '_'
else:
sep = ""
sep = ''
return sep.join(map(str, version))
@ -737,15 +734,12 @@ def sys_tags(**kwargs):
The order of the sequence corresponds to priority order for the
interpreter, from most to least important.
"""
warn = _warn_keyword_parameter("sys_tags", kwargs)
warn = _warn_keyword_parameter('sys_tags', kwargs)
interp_name = interpreter_name()
if interp_name == "cp":
for tag in cpython_tags(warn=warn):
yield tag
if interp_name == 'cp':
yield from cpython_tags(warn=warn)
else:
for tag in generic_tags():
yield tag
yield from generic_tags()
for tag in compatible_tags():
yield tag
yield from compatible_tags()

View file

@ -1,26 +1,28 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from __future__ import annotations
import re
from ._typing import TYPE_CHECKING, cast
from .version import InvalidVersion, Version
from ._typing import cast
from ._typing import TYPE_CHECKING
from .version import InvalidVersion
from .version import Version
if TYPE_CHECKING: # pragma: no cover
from typing import NewType, Union
NormalizedName = NewType("NormalizedName", str)
NormalizedName = NewType('NormalizedName', str)
_canonicalize_regex = re.compile(r"[-_.]+")
_canonicalize_regex = re.compile(r'[-_.]+')
def canonicalize_name(name):
# type: (str) -> NormalizedName
# This is taken from PEP 503.
value = _canonicalize_regex.sub("-", name).lower()
return cast("NormalizedName", value)
value = _canonicalize_regex.sub('-', name).lower()
return cast('NormalizedName', value)
def canonicalize_version(_version):
@ -40,26 +42,26 @@ def canonicalize_version(_version):
# Epoch
if version.epoch != 0:
parts.append("{0}!".format(version.epoch))
parts.append(f'{version.epoch}!')
# Release segment
# NB: This strips trailing '.0's to normalize
parts.append(re.sub(r"(\.0)+$", "", ".".join(str(x) for x in version.release)))
parts.append(re.sub(r'(\.0)+$', '', '.'.join(str(x) for x in version.release)))
# Pre-release
if version.pre is not None:
parts.append("".join(str(x) for x in version.pre))
parts.append(''.join(str(x) for x in version.pre))
# Post-release
if version.post is not None:
parts.append(".post{0}".format(version.post))
parts.append(f'.post{version.post}')
# Development release
if version.dev is not None:
parts.append(".dev{0}".format(version.dev))
parts.append(f'.dev{version.dev}')
# Local version segment
if version.local is not None:
parts.append("+{0}".format(version.local))
parts.append(f'+{version.local}')
return "".join(parts)
return ''.join(parts)

View file

@ -1,13 +1,14 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
from __future__ import absolute_import, division, print_function
from __future__ import annotations
import collections
import itertools
import re
from ._structures import Infinity, NegativeInfinity
from ._structures import Infinity
from ._structures import NegativeInfinity
from ._typing import TYPE_CHECKING
if TYPE_CHECKING: # pragma: no cover
@ -30,18 +31,18 @@ if TYPE_CHECKING: # pragma: no cover
],
]
CmpKey = Tuple[
int, Tuple[int, ...], PrePostDevType, PrePostDevType, PrePostDevType, LocalType
int, Tuple[int, ...], PrePostDevType, PrePostDevType, PrePostDevType, LocalType,
]
LegacyCmpKey = Tuple[int, Tuple[str, ...]]
VersionComparisonMethod = Callable[
[Union[CmpKey, LegacyCmpKey], Union[CmpKey, LegacyCmpKey]], bool
[Union[CmpKey, LegacyCmpKey], Union[CmpKey, LegacyCmpKey]], bool,
]
__all__ = ["parse", "Version", "LegacyVersion", "InvalidVersion", "VERSION_PATTERN"]
__all__ = ['parse', 'Version', 'LegacyVersion', 'InvalidVersion', 'VERSION_PATTERN']
_Version = collections.namedtuple(
"_Version", ["epoch", "release", "dev", "pre", "post", "local"]
'_Version', ['epoch', 'release', 'dev', 'pre', 'post', 'local'],
)
@ -64,7 +65,7 @@ class InvalidVersion(ValueError):
"""
class _BaseVersion(object):
class _BaseVersion:
_key = None # type: Union[CmpKey, LegacyCmpKey]
def __hash__(self):
@ -115,7 +116,7 @@ class LegacyVersion(_BaseVersion):
def __repr__(self):
# type: () -> str
return "<LegacyVersion({0})>".format(repr(str(self)))
return f'<LegacyVersion({repr(str(self))})>'
@property
def public(self):
@ -173,14 +174,14 @@ class LegacyVersion(_BaseVersion):
return False
_legacy_version_component_re = re.compile(r"(\d+ | [a-z]+ | \.| -)", re.VERBOSE)
_legacy_version_component_re = re.compile(r'(\d+ | [a-z]+ | \.| -)', re.VERBOSE)
_legacy_version_replacement_map = {
"pre": "c",
"preview": "c",
"-": "final-",
"rc": "c",
"dev": "@",
'pre': 'c',
'preview': 'c',
'-': 'final-',
'rc': 'c',
'dev': '@',
}
@ -189,17 +190,17 @@ def _parse_version_parts(s):
for part in _legacy_version_component_re.split(s):
part = _legacy_version_replacement_map.get(part, part)
if not part or part == ".":
if not part or part == '.':
continue
if part[:1] in "0123456789":
if part[:1] in '0123456789':
# pad for numeric comparison
yield part.zfill(8)
else:
yield "*" + part
yield '*' + part
# ensure that alpha/beta/candidate are before final
yield "*final"
yield '*final'
def _legacy_cmpkey(version):
@ -215,14 +216,14 @@ def _legacy_cmpkey(version):
# it's adoption of the packaging library.
parts = [] # type: List[str]
for part in _parse_version_parts(version.lower()):
if part.startswith("*"):
if part.startswith('*'):
# remove "-" before a prerelease tag
if part < "*final":
while parts and parts[-1] == "*final-":
if part < '*final':
while parts and parts[-1] == '*final-':
parts.pop()
# remove trailing zeros from each series of numeric parts
while parts and parts[-1] == "00000000":
while parts and parts[-1] == '00000000':
parts.pop()
parts.append(part)
@ -266,7 +267,7 @@ VERSION_PATTERN = r"""
class Version(_BaseVersion):
_regex = re.compile(r"^\s*" + VERSION_PATTERN + r"\s*$", re.VERBOSE | re.IGNORECASE)
_regex = re.compile(r'^\s*' + VERSION_PATTERN + r'\s*$', re.VERBOSE | re.IGNORECASE)
def __init__(self, version):
# type: (str) -> None
@ -274,18 +275,18 @@ class Version(_BaseVersion):
# Validate the version and parse it into pieces
match = self._regex.search(version)
if not match:
raise InvalidVersion("Invalid version: '{0}'".format(version))
raise InvalidVersion(f"Invalid version: '{version}'")
# Store the parsed out pieces of the version
self._version = _Version(
epoch=int(match.group("epoch")) if match.group("epoch") else 0,
release=tuple(int(i) for i in match.group("release").split(".")),
pre=_parse_letter_version(match.group("pre_l"), match.group("pre_n")),
epoch=int(match.group('epoch')) if match.group('epoch') else 0,
release=tuple(int(i) for i in match.group('release').split('.')),
pre=_parse_letter_version(match.group('pre_l'), match.group('pre_n')),
post=_parse_letter_version(
match.group("post_l"), match.group("post_n1") or match.group("post_n2")
match.group('post_l'), match.group('post_n1') or match.group('post_n2'),
),
dev=_parse_letter_version(match.group("dev_l"), match.group("dev_n")),
local=_parse_local_version(match.group("local")),
dev=_parse_letter_version(match.group('dev_l'), match.group('dev_n')),
local=_parse_local_version(match.group('local')),
)
# Generate a key which will be used for sorting
@ -300,7 +301,7 @@ class Version(_BaseVersion):
def __repr__(self):
# type: () -> str
return "<Version({0})>".format(repr(str(self)))
return f'<Version({repr(str(self))})>'
def __str__(self):
# type: () -> str
@ -308,28 +309,28 @@ class Version(_BaseVersion):
# Epoch
if self.epoch != 0:
parts.append("{0}!".format(self.epoch))
parts.append(f'{self.epoch}!')
# Release segment
parts.append(".".join(str(x) for x in self.release))
parts.append('.'.join(str(x) for x in self.release))
# Pre-release
if self.pre is not None:
parts.append("".join(str(x) for x in self.pre))
parts.append(''.join(str(x) for x in self.pre))
# Post-release
if self.post is not None:
parts.append(".post{0}".format(self.post))
parts.append(f'.post{self.post}')
# Development release
if self.dev is not None:
parts.append(".dev{0}".format(self.dev))
parts.append(f'.dev{self.dev}')
# Local version segment
if self.local is not None:
parts.append("+{0}".format(self.local))
parts.append(f'+{self.local}')
return "".join(parts)
return ''.join(parts)
@property
def epoch(self):
@ -363,14 +364,14 @@ class Version(_BaseVersion):
def local(self):
# type: () -> Optional[str]
if self._version.local:
return ".".join(str(x) for x in self._version.local)
return '.'.join(str(x) for x in self._version.local)
else:
return None
@property
def public(self):
# type: () -> str
return str(self).split("+", 1)[0]
return str(self).split('+', 1)[0]
@property
def base_version(self):
@ -379,12 +380,12 @@ class Version(_BaseVersion):
# Epoch
if self.epoch != 0:
parts.append("{0}!".format(self.epoch))
parts.append(f'{self.epoch}!')
# Release segment
parts.append(".".join(str(x) for x in self.release))
parts.append('.'.join(str(x) for x in self.release))
return "".join(parts)
return ''.join(parts)
@property
def is_prerelease(self):
@ -435,27 +436,27 @@ def _parse_letter_version(
# We consider some words to be alternate spellings of other words and
# in those cases we want to normalize the spellings to our preferred
# spelling.
if letter == "alpha":
letter = "a"
elif letter == "beta":
letter = "b"
elif letter in ["c", "pre", "preview"]:
letter = "rc"
elif letter in ["rev", "r"]:
letter = "post"
if letter == 'alpha':
letter = 'a'
elif letter == 'beta':
letter = 'b'
elif letter in ['c', 'pre', 'preview']:
letter = 'rc'
elif letter in ['rev', 'r']:
letter = 'post'
return letter, int(number)
if not letter and number:
# We assume if we are given a number, but we are not given a letter
# then this is using the implicit post release syntax (e.g. 1.0-1)
letter = "post"
letter = 'post'
return letter, int(number)
return None
_local_version_separators = re.compile(r"[\._-]")
_local_version_separators = re.compile(r'[\._-]')
def _parse_local_version(local):
@ -487,7 +488,7 @@ def _cmpkey(
# re-reverse it back into the correct order and make it a tuple and use
# that for our sorting key.
_release = tuple(
reversed(list(itertools.dropwhile(lambda x: x == 0, reversed(release))))
reversed(list(itertools.dropwhile(lambda x: x == 0, reversed(release)))),
)
# We need to "trick" the sorting algorithm to put 1.0.dev0 before 1.0a0.
@ -529,7 +530,7 @@ def _cmpkey(
# - Shorter versions sort before longer versions when the prefixes
# match exactly
_local = tuple(
(i, "") if isinstance(i, int) else (NegativeInfinity, i) for i in local
(i, '') if isinstance(i, int) else (NegativeInfinity, i) for i in local
)
return epoch, _release, _pre, _post, _dev, _local