Commit 1b27726f authored by Jason R. Coombs's avatar Jason R. Coombs

Update packaging to 20.4. Closes #2310.

parent 9d7b246c
...@@ -18,10 +18,10 @@ __title__ = "packaging" ...@@ -18,10 +18,10 @@ __title__ = "packaging"
__summary__ = "Core utilities for Python packages" __summary__ = "Core utilities for Python packages"
__uri__ = "https://github.com/pypa/packaging" __uri__ = "https://github.com/pypa/packaging"
__version__ = "19.2" __version__ = "20.4"
__author__ = "Donald Stufft and individual contributors" __author__ = "Donald Stufft and individual contributors"
__email__ = "donald@stufft.io" __email__ = "donald@stufft.io"
__license__ = "BSD or Apache License, Version 2.0" __license__ = "BSD-2-Clause or Apache-2.0"
__copyright__ = "Copyright 2014-2019 %s" % __author__ __copyright__ = "Copyright 2014-2019 %s" % __author__
...@@ -5,6 +5,11 @@ from __future__ import absolute_import, division, print_function ...@@ -5,6 +5,11 @@ from __future__ import absolute_import, division, print_function
import sys import sys
from ._typing import TYPE_CHECKING
if TYPE_CHECKING: # pragma: no cover
from typing import Any, Dict, Tuple, Type
PY2 = sys.version_info[0] == 2 PY2 = sys.version_info[0] == 2
PY3 = sys.version_info[0] == 3 PY3 = sys.version_info[0] == 3
...@@ -18,14 +23,16 @@ else: ...@@ -18,14 +23,16 @@ else:
def with_metaclass(meta, *bases): def with_metaclass(meta, *bases):
# type: (Type[Any], Tuple[Type[Any], ...]) -> Any
""" """
Create a base class with a metaclass. Create a base class with a metaclass.
""" """
# This requires a bit of explanation: the basic idea is to make a dummy # This requires a bit of explanation: the basic idea is to make a dummy
# metaclass for one level of class instantiation that replaces itself with # metaclass for one level of class instantiation that replaces itself with
# the actual metaclass. # the actual metaclass.
class metaclass(meta): class metaclass(meta): # type: ignore
def __new__(cls, name, this_bases, d): def __new__(cls, name, this_bases, d):
# type: (Type[Any], str, Tuple[Any], Dict[Any, Any]) -> Any
return meta(name, bases, d) return meta(name, bases, d)
return type.__new__(metaclass, "temporary_class", (), {}) return type.__new__(metaclass, "temporary_class", (), {})
...@@ -4,65 +4,83 @@ ...@@ -4,65 +4,83 @@
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
class Infinity(object): class InfinityType(object):
def __repr__(self): def __repr__(self):
# type: () -> str
return "Infinity" return "Infinity"
def __hash__(self): def __hash__(self):
# type: () -> int
return hash(repr(self)) return hash(repr(self))
def __lt__(self, other): def __lt__(self, other):
# type: (object) -> bool
return False return False
def __le__(self, other): def __le__(self, other):
# type: (object) -> bool
return False return False
def __eq__(self, other): def __eq__(self, other):
# type: (object) -> bool
return isinstance(other, self.__class__) return isinstance(other, self.__class__)
def __ne__(self, other): def __ne__(self, other):
# type: (object) -> bool
return not isinstance(other, self.__class__) return not isinstance(other, self.__class__)
def __gt__(self, other): def __gt__(self, other):
# type: (object) -> bool
return True return True
def __ge__(self, other): def __ge__(self, other):
# type: (object) -> bool
return True return True
def __neg__(self): def __neg__(self):
# type: (object) -> NegativeInfinityType
return NegativeInfinity return NegativeInfinity
Infinity = Infinity() Infinity = InfinityType()
class NegativeInfinity(object): class NegativeInfinityType(object):
def __repr__(self): def __repr__(self):
# type: () -> str
return "-Infinity" return "-Infinity"
def __hash__(self): def __hash__(self):
# type: () -> int
return hash(repr(self)) return hash(repr(self))
def __lt__(self, other): def __lt__(self, other):
# type: (object) -> bool
return True return True
def __le__(self, other): def __le__(self, other):
# type: (object) -> bool
return True return True
def __eq__(self, other): def __eq__(self, other):
# type: (object) -> bool
return isinstance(other, self.__class__) return isinstance(other, self.__class__)
def __ne__(self, other): def __ne__(self, other):
# type: (object) -> bool
return not isinstance(other, self.__class__) return not isinstance(other, self.__class__)
def __gt__(self, other): def __gt__(self, other):
# type: (object) -> bool
return False return False
def __ge__(self, other): def __ge__(self, other):
# type: (object) -> bool
return False return False
def __neg__(self): def __neg__(self):
# type: (object) -> InfinityType
return Infinity return Infinity
NegativeInfinity = NegativeInfinity() NegativeInfinity = NegativeInfinityType()
"""For neatly implementing static typing in packaging.
`mypy` - the static type analysis tool we use - uses the `typing` module, which
provides core functionality fundamental to mypy's functioning.
Generally, `typing` would be imported at runtime and used in that fashion -
it acts as a no-op at runtime and does not have any run-time overhead by
design.
As it turns out, `typing` is not vendorable - it uses separate sources for
Python 2/Python 3. Thus, this codebase can not expect it to be present.
To work around this, mypy allows the typing import to be behind a False-y
optional to prevent it from running at runtime and type-comments can be used
to remove the need for the types to be accessible directly during runtime.
This module provides the False-y guard in a nicely named fashion so that a
curious maintainer can reach here to read this.
In packaging, all static-typing related imports should be guarded as follows:
from packaging._typing import TYPE_CHECKING
if TYPE_CHECKING:
from typing import ...
Ref: https://github.com/python/mypy/issues/3216
"""
__all__ = ["TYPE_CHECKING", "cast"]
# The TYPE_CHECKING constant defined by the typing module is False at runtime
# but True while type checking.
if False: # pragma: no cover
from typing import TYPE_CHECKING
else:
TYPE_CHECKING = False
# typing's cast syntax requires calling typing.cast at runtime, but we don't
# want to import typing at runtime. Here, we inform the type checkers that
# we're importing `typing.cast` as `cast` and re-implement typing.cast's
# runtime behavior in a block that is ignored by type checkers.
if TYPE_CHECKING: # pragma: no cover
# not executed at runtime
from typing import cast
else:
# executed at runtime
def cast(type_, value): # noqa
return value
...@@ -13,8 +13,14 @@ from pkg_resources.extern.pyparsing import ZeroOrMore, Group, Forward, QuotedStr ...@@ -13,8 +13,14 @@ from pkg_resources.extern.pyparsing import ZeroOrMore, Group, Forward, QuotedStr
from pkg_resources.extern.pyparsing import Literal as L # noqa from pkg_resources.extern.pyparsing import Literal as L # noqa
from ._compat import string_types from ._compat import string_types
from ._typing import TYPE_CHECKING
from .specifiers import Specifier, InvalidSpecifier from .specifiers import Specifier, InvalidSpecifier
if TYPE_CHECKING: # pragma: no cover
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
Operator = Callable[[str, str], bool]
__all__ = [ __all__ = [
"InvalidMarker", "InvalidMarker",
...@@ -46,30 +52,37 @@ class UndefinedEnvironmentName(ValueError): ...@@ -46,30 +52,37 @@ class UndefinedEnvironmentName(ValueError):
class Node(object): class Node(object):
def __init__(self, value): def __init__(self, value):
# type: (Any) -> None
self.value = value self.value = value
def __str__(self): def __str__(self):
# type: () -> str
return str(self.value) return str(self.value)
def __repr__(self): def __repr__(self):
# type: () -> str
return "<{0}({1!r})>".format(self.__class__.__name__, str(self)) return "<{0}({1!r})>".format(self.__class__.__name__, str(self))
def serialize(self): def serialize(self):
# type: () -> str
raise NotImplementedError raise NotImplementedError
class Variable(Node): class Variable(Node):
def serialize(self): def serialize(self):
# type: () -> str
return str(self) return str(self)
class Value(Node): class Value(Node):
def serialize(self): def serialize(self):
# type: () -> str
return '"{0}"'.format(self) return '"{0}"'.format(self)
class Op(Node): class Op(Node):
def serialize(self): def serialize(self):
# type: () -> str
return str(self) return str(self)
...@@ -85,13 +98,13 @@ VARIABLE = ( ...@@ -85,13 +98,13 @@ VARIABLE = (
| L("python_version") | L("python_version")
| L("sys_platform") | L("sys_platform")
| L("os_name") | L("os_name")
| L("os.name") | L("os.name") # PEP-345
| L("sys.platform") # PEP-345 | L("sys.platform") # PEP-345
| L("platform.version") # PEP-345 | L("platform.version") # PEP-345
| L("platform.machine") # PEP-345 | L("platform.machine") # PEP-345
| L("platform.python_implementation") # PEP-345 | L("platform.python_implementation") # PEP-345
| L("python_implementation") # PEP-345 | L("python_implementation") # undocumented setuptools legacy
| L("extra") # undocumented setuptools legacy | L("extra") # PEP-508
) )
ALIASES = { ALIASES = {
"os.name": "os_name", "os.name": "os_name",
...@@ -131,6 +144,7 @@ MARKER = stringStart + MARKER_EXPR + stringEnd ...@@ -131,6 +144,7 @@ MARKER = stringStart + MARKER_EXPR + stringEnd
def _coerce_parse_result(results): def _coerce_parse_result(results):
# type: (Union[ParseResults, List[Any]]) -> List[Any]
if isinstance(results, ParseResults): if isinstance(results, ParseResults):
return [_coerce_parse_result(i) for i in results] return [_coerce_parse_result(i) for i in results]
else: else:
...@@ -138,6 +152,8 @@ def _coerce_parse_result(results): ...@@ -138,6 +152,8 @@ def _coerce_parse_result(results):
def _format_marker(marker, first=True): def _format_marker(marker, first=True):
# type: (Union[List[str], Tuple[Node, ...], str], Optional[bool]) -> str
assert isinstance(marker, (list, tuple, string_types)) assert isinstance(marker, (list, tuple, string_types))
# Sometimes we have a structure like [[...]] which is a single item list # Sometimes we have a structure like [[...]] which is a single item list
...@@ -172,10 +188,11 @@ _operators = { ...@@ -172,10 +188,11 @@ _operators = {
"!=": operator.ne, "!=": operator.ne,
">=": operator.ge, ">=": operator.ge,
">": operator.gt, ">": operator.gt,
} } # type: Dict[str, Operator]
def _eval_op(lhs, op, rhs): def _eval_op(lhs, op, rhs):
# type: (str, Op, str) -> bool
try: try:
spec = Specifier("".join([op.serialize(), rhs])) spec = Specifier("".join([op.serialize(), rhs]))
except InvalidSpecifier: except InvalidSpecifier:
...@@ -183,7 +200,7 @@ def _eval_op(lhs, op, rhs): ...@@ -183,7 +200,7 @@ def _eval_op(lhs, op, rhs):
else: else:
return spec.contains(lhs) return spec.contains(lhs)
oper = _operators.get(op.serialize()) oper = _operators.get(op.serialize()) # type: Optional[Operator]
if oper is None: if oper is None:
raise UndefinedComparison( raise UndefinedComparison(
"Undefined {0!r} on {1!r} and {2!r}.".format(op, lhs, rhs) "Undefined {0!r} on {1!r} and {2!r}.".format(op, lhs, rhs)
...@@ -192,13 +209,18 @@ def _eval_op(lhs, op, rhs): ...@@ -192,13 +209,18 @@ def _eval_op(lhs, op, rhs):
return oper(lhs, rhs) return oper(lhs, rhs)
_undefined = object() class Undefined(object):
pass
_undefined = Undefined()
def _get_env(environment, name): def _get_env(environment, name):
value = environment.get(name, _undefined) # type: (Dict[str, str], str) -> str
value = environment.get(name, _undefined) # type: Union[str, Undefined]
if value is _undefined: if isinstance(value, Undefined):
raise UndefinedEnvironmentName( raise UndefinedEnvironmentName(
"{0!r} does not exist in evaluation environment.".format(name) "{0!r} does not exist in evaluation environment.".format(name)
) )
...@@ -207,7 +229,8 @@ def _get_env(environment, name): ...@@ -207,7 +229,8 @@ def _get_env(environment, name):
def _evaluate_markers(markers, environment): def _evaluate_markers(markers, environment):
groups = [[]] # type: (List[Any], Dict[str, str]) -> bool
groups = [[]] # type: List[List[bool]]
for marker in markers: for marker in markers:
assert isinstance(marker, (list, tuple, string_types)) assert isinstance(marker, (list, tuple, string_types))
...@@ -234,6 +257,7 @@ def _evaluate_markers(markers, environment): ...@@ -234,6 +257,7 @@ def _evaluate_markers(markers, environment):
def format_full_version(info): 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 kind = info.releaselevel
if kind != "final": if kind != "final":
...@@ -242,9 +266,13 @@ def format_full_version(info): ...@@ -242,9 +266,13 @@ def format_full_version(info):
def default_environment(): def default_environment():
# type: () -> Dict[str, str]
if hasattr(sys, "implementation"): if hasattr(sys, "implementation"):
iver = format_full_version(sys.implementation.version) # Ignoring the `sys.implementation` reference for type checking due to
implementation_name = sys.implementation.name # 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: else:
iver = "0" iver = "0"
implementation_name = "" implementation_name = ""
...@@ -266,6 +294,7 @@ def default_environment(): ...@@ -266,6 +294,7 @@ def default_environment():
class Marker(object): class Marker(object):
def __init__(self, marker): def __init__(self, marker):
# type: (str) -> None
try: try:
self._markers = _coerce_parse_result(MARKER.parseString(marker)) self._markers = _coerce_parse_result(MARKER.parseString(marker))
except ParseException as e: except ParseException as e:
...@@ -275,12 +304,15 @@ class Marker(object): ...@@ -275,12 +304,15 @@ class Marker(object):
raise InvalidMarker(err_str) raise InvalidMarker(err_str)
def __str__(self): def __str__(self):
# type: () -> str
return _format_marker(self._markers) return _format_marker(self._markers)
def __repr__(self): def __repr__(self):
# type: () -> str
return "<Marker({0!r})>".format(str(self)) return "<Marker({0!r})>".format(str(self))
def evaluate(self, environment=None): def evaluate(self, environment=None):
# type: (Optional[Dict[str, str]]) -> bool
"""Evaluate a marker. """Evaluate a marker.
Return the boolean from evaluating the given marker against the Return the boolean from evaluating the given marker against the
......
...@@ -11,9 +11,13 @@ from pkg_resources.extern.pyparsing import ZeroOrMore, Word, Optional, Regex, Co ...@@ -11,9 +11,13 @@ from pkg_resources.extern.pyparsing import ZeroOrMore, Word, Optional, Regex, Co
from pkg_resources.extern.pyparsing import Literal as L # noqa from pkg_resources.extern.pyparsing import Literal as L # noqa
from pkg_resources.extern.six.moves.urllib import parse as urlparse from pkg_resources.extern.six.moves.urllib import parse as urlparse
from ._typing import TYPE_CHECKING
from .markers import MARKER_EXPR, Marker from .markers import MARKER_EXPR, Marker
from .specifiers import LegacySpecifier, Specifier, SpecifierSet from .specifiers import LegacySpecifier, Specifier, SpecifierSet
if TYPE_CHECKING: # pragma: no cover
from typing import List
class InvalidRequirement(ValueError): class InvalidRequirement(ValueError):
""" """
...@@ -89,6 +93,7 @@ class Requirement(object): ...@@ -89,6 +93,7 @@ class Requirement(object):
# TODO: Can we normalize the name and extra name? # TODO: Can we normalize the name and extra name?
def __init__(self, requirement_string): def __init__(self, requirement_string):
# type: (str) -> None
try: try:
req = REQUIREMENT.parseString(requirement_string) req = REQUIREMENT.parseString(requirement_string)
except ParseException as e: except ParseException as e:
...@@ -116,7 +121,8 @@ class Requirement(object): ...@@ -116,7 +121,8 @@ class Requirement(object):
self.marker = req.marker if req.marker else None self.marker = req.marker if req.marker else None
def __str__(self): def __str__(self):
parts = [self.name] # type: () -> str
parts = [self.name] # type: List[str]
if self.extras: if self.extras:
parts.append("[{0}]".format(",".join(sorted(self.extras)))) parts.append("[{0}]".format(",".join(sorted(self.extras))))
...@@ -135,4 +141,5 @@ class Requirement(object): ...@@ -135,4 +141,5 @@ class Requirement(object):
return "".join(parts) return "".join(parts)
def __repr__(self): def __repr__(self):
# type: () -> str
return "<Requirement({0!r})>".format(str(self)) return "<Requirement({0!r})>".format(str(self))
This diff is collapsed.
...@@ -5,28 +5,36 @@ from __future__ import absolute_import, division, print_function ...@@ -5,28 +5,36 @@ from __future__ import absolute_import, division, print_function
import re import re
from ._typing import TYPE_CHECKING, cast
from .version import InvalidVersion, Version from .version import InvalidVersion, Version
if TYPE_CHECKING: # pragma: no cover
from typing import NewType, Union
NormalizedName = NewType("NormalizedName", str)
_canonicalize_regex = re.compile(r"[-_.]+") _canonicalize_regex = re.compile(r"[-_.]+")
def canonicalize_name(name): def canonicalize_name(name):
# type: (str) -> NormalizedName
# This is taken from PEP 503. # This is taken from PEP 503.
return _canonicalize_regex.sub("-", name).lower() value = _canonicalize_regex.sub("-", name).lower()
return cast("NormalizedName", value)
def canonicalize_version(version): def canonicalize_version(_version):
# type: (str) -> Union[Version, str]
""" """
This is very similar to Version.__str__, but has one subtle differences This is very similar to Version.__str__, but has one subtle difference
with the way it handles the release segment. with the way it handles the release segment.
""" """
try: try:
version = Version(version) version = Version(_version)
except InvalidVersion: except InvalidVersion:
# Legacy versions cannot be normalized # Legacy versions cannot be normalized
return version return _version
parts = [] parts = []
......
This diff is collapsed.
packaging==19.2 packaging==20.4
pyparsing==2.2.1 pyparsing==2.2.1
six==1.10.0 six==1.10.0
appdirs==1.4.3 appdirs==1.4.3
...@@ -18,10 +18,10 @@ __title__ = "packaging" ...@@ -18,10 +18,10 @@ __title__ = "packaging"
__summary__ = "Core utilities for Python packages" __summary__ = "Core utilities for Python packages"
__uri__ = "https://github.com/pypa/packaging" __uri__ = "https://github.com/pypa/packaging"
__version__ = "19.2" __version__ = "20.4"
__author__ = "Donald Stufft and individual contributors" __author__ = "Donald Stufft and individual contributors"
__email__ = "donald@stufft.io" __email__ = "donald@stufft.io"
__license__ = "BSD or Apache License, Version 2.0" __license__ = "BSD-2-Clause or Apache-2.0"
__copyright__ = "Copyright 2014-2019 %s" % __author__ __copyright__ = "Copyright 2014-2019 %s" % __author__
...@@ -5,6 +5,11 @@ from __future__ import absolute_import, division, print_function ...@@ -5,6 +5,11 @@ from __future__ import absolute_import, division, print_function
import sys import sys
from ._typing import TYPE_CHECKING
if TYPE_CHECKING: # pragma: no cover
from typing import Any, Dict, Tuple, Type
PY2 = sys.version_info[0] == 2 PY2 = sys.version_info[0] == 2
PY3 = sys.version_info[0] == 3 PY3 = sys.version_info[0] == 3
...@@ -18,14 +23,16 @@ else: ...@@ -18,14 +23,16 @@ else:
def with_metaclass(meta, *bases): def with_metaclass(meta, *bases):
# type: (Type[Any], Tuple[Type[Any], ...]) -> Any
""" """
Create a base class with a metaclass. Create a base class with a metaclass.
""" """
# This requires a bit of explanation: the basic idea is to make a dummy # This requires a bit of explanation: the basic idea is to make a dummy
# metaclass for one level of class instantiation that replaces itself with # metaclass for one level of class instantiation that replaces itself with
# the actual metaclass. # the actual metaclass.
class metaclass(meta): class metaclass(meta): # type: ignore
def __new__(cls, name, this_bases, d): def __new__(cls, name, this_bases, d):
# type: (Type[Any], str, Tuple[Any], Dict[Any, Any]) -> Any
return meta(name, bases, d) return meta(name, bases, d)
return type.__new__(metaclass, "temporary_class", (), {}) return type.__new__(metaclass, "temporary_class", (), {})
...@@ -4,65 +4,83 @@ ...@@ -4,65 +4,83 @@
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
class Infinity(object): class InfinityType(object):
def __repr__(self): def __repr__(self):
# type: () -> str
return "Infinity" return "Infinity"
def __hash__(self): def __hash__(self):
# type: () -> int
return hash(repr(self)) return hash(repr(self))
def __lt__(self, other): def __lt__(self, other):
# type: (object) -> bool
return False return False
def __le__(self, other): def __le__(self, other):
# type: (object) -> bool
return False return False
def __eq__(self, other): def __eq__(self, other):
# type: (object) -> bool
return isinstance(other, self.__class__) return isinstance(other, self.__class__)
def __ne__(self, other): def __ne__(self, other):
# type: (object) -> bool
return not isinstance(other, self.__class__) return not isinstance(other, self.__class__)
def __gt__(self, other): def __gt__(self, other):
# type: (object) -> bool
return True return True
def __ge__(self, other): def __ge__(self, other):
# type: (object) -> bool
return True return True
def __neg__(self): def __neg__(self):
# type: (object) -> NegativeInfinityType
return NegativeInfinity return NegativeInfinity
Infinity = Infinity() Infinity = InfinityType()
class NegativeInfinity(object): class NegativeInfinityType(object):
def __repr__(self): def __repr__(self):
# type: () -> str
return "-Infinity" return "-Infinity"
def __hash__(self): def __hash__(self):
# type: () -> int
return hash(repr(self)) return hash(repr(self))
def __lt__(self, other): def __lt__(self, other):
# type: (object) -> bool
return True return True
def __le__(self, other): def __le__(self, other):
# type: (object) -> bool
return True return True
def __eq__(self, other): def __eq__(self, other):
# type: (object) -> bool
return isinstance(other, self.__class__) return isinstance(other, self.__class__)
def __ne__(self, other): def __ne__(self, other):
# type: (object) -> bool
return not isinstance(other, self.__class__) return not isinstance(other, self.__class__)
def __gt__(self, other): def __gt__(self, other):
# type: (object) -> bool
return False return False
def __ge__(self, other): def __ge__(self, other):
# type: (object) -> bool
return False return False
def __neg__(self): def __neg__(self):
# type: (object) -> InfinityType
return Infinity return Infinity
NegativeInfinity = NegativeInfinity() NegativeInfinity = NegativeInfinityType()
"""For neatly implementing static typing in packaging.
`mypy` - the static type analysis tool we use - uses the `typing` module, which
provides core functionality fundamental to mypy's functioning.
Generally, `typing` would be imported at runtime and used in that fashion -
it acts as a no-op at runtime and does not have any run-time overhead by
design.
As it turns out, `typing` is not vendorable - it uses separate sources for
Python 2/Python 3. Thus, this codebase can not expect it to be present.
To work around this, mypy allows the typing import to be behind a False-y
optional to prevent it from running at runtime and type-comments can be used
to remove the need for the types to be accessible directly during runtime.
This module provides the False-y guard in a nicely named fashion so that a
curious maintainer can reach here to read this.
In packaging, all static-typing related imports should be guarded as follows:
from packaging._typing import TYPE_CHECKING
if TYPE_CHECKING:
from typing import ...
Ref: https://github.com/python/mypy/issues/3216
"""
__all__ = ["TYPE_CHECKING", "cast"]
# The TYPE_CHECKING constant defined by the typing module is False at runtime
# but True while type checking.
if False: # pragma: no cover
from typing import TYPE_CHECKING
else:
TYPE_CHECKING = False
# typing's cast syntax requires calling typing.cast at runtime, but we don't
# want to import typing at runtime. Here, we inform the type checkers that
# we're importing `typing.cast` as `cast` and re-implement typing.cast's
# runtime behavior in a block that is ignored by type checkers.
if TYPE_CHECKING: # pragma: no cover
# not executed at runtime
from typing import cast
else:
# executed at runtime
def cast(type_, value): # noqa
return value
...@@ -13,8 +13,14 @@ from setuptools.extern.pyparsing import ZeroOrMore, Group, Forward, QuotedString ...@@ -13,8 +13,14 @@ from setuptools.extern.pyparsing import ZeroOrMore, Group, Forward, QuotedString
from setuptools.extern.pyparsing import Literal as L # noqa from setuptools.extern.pyparsing import Literal as L # noqa
from ._compat import string_types from ._compat import string_types
from ._typing import TYPE_CHECKING
from .specifiers import Specifier, InvalidSpecifier from .specifiers import Specifier, InvalidSpecifier
if TYPE_CHECKING: # pragma: no cover
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
Operator = Callable[[str, str], bool]
__all__ = [ __all__ = [
"InvalidMarker", "InvalidMarker",
...@@ -46,30 +52,37 @@ class UndefinedEnvironmentName(ValueError): ...@@ -46,30 +52,37 @@ class UndefinedEnvironmentName(ValueError):
class Node(object): class Node(object):
def __init__(self, value): def __init__(self, value):
# type: (Any) -> None
self.value = value self.value = value
def __str__(self): def __str__(self):
# type: () -> str
return str(self.value) return str(self.value)
def __repr__(self): def __repr__(self):
# type: () -> str
return "<{0}({1!r})>".format(self.__class__.__name__, str(self)) return "<{0}({1!r})>".format(self.__class__.__name__, str(self))
def serialize(self): def serialize(self):
# type: () -> str
raise NotImplementedError raise NotImplementedError
class Variable(Node): class Variable(Node):
def serialize(self): def serialize(self):
# type: () -> str
return str(self) return str(self)
class Value(Node): class Value(Node):
def serialize(self): def serialize(self):
# type: () -> str
return '"{0}"'.format(self) return '"{0}"'.format(self)
class Op(Node): class Op(Node):
def serialize(self): def serialize(self):
# type: () -> str
return str(self) return str(self)
...@@ -85,13 +98,13 @@ VARIABLE = ( ...@@ -85,13 +98,13 @@ VARIABLE = (
| L("python_version") | L("python_version")
| L("sys_platform") | L("sys_platform")
| L("os_name") | L("os_name")
| L("os.name") | L("os.name") # PEP-345
| L("sys.platform") # PEP-345 | L("sys.platform") # PEP-345
| L("platform.version") # PEP-345 | L("platform.version") # PEP-345
| L("platform.machine") # PEP-345 | L("platform.machine") # PEP-345
| L("platform.python_implementation") # PEP-345 | L("platform.python_implementation") # PEP-345
| L("python_implementation") # PEP-345 | L("python_implementation") # undocumented setuptools legacy
| L("extra") # undocumented setuptools legacy | L("extra") # PEP-508
) )
ALIASES = { ALIASES = {
"os.name": "os_name", "os.name": "os_name",
...@@ -131,6 +144,7 @@ MARKER = stringStart + MARKER_EXPR + stringEnd ...@@ -131,6 +144,7 @@ MARKER = stringStart + MARKER_EXPR + stringEnd
def _coerce_parse_result(results): def _coerce_parse_result(results):
# type: (Union[ParseResults, List[Any]]) -> List[Any]
if isinstance(results, ParseResults): if isinstance(results, ParseResults):
return [_coerce_parse_result(i) for i in results] return [_coerce_parse_result(i) for i in results]
else: else:
...@@ -138,6 +152,8 @@ def _coerce_parse_result(results): ...@@ -138,6 +152,8 @@ def _coerce_parse_result(results):
def _format_marker(marker, first=True): def _format_marker(marker, first=True):
# type: (Union[List[str], Tuple[Node, ...], str], Optional[bool]) -> str
assert isinstance(marker, (list, tuple, string_types)) assert isinstance(marker, (list, tuple, string_types))
# Sometimes we have a structure like [[...]] which is a single item list # Sometimes we have a structure like [[...]] which is a single item list
...@@ -172,10 +188,11 @@ _operators = { ...@@ -172,10 +188,11 @@ _operators = {
"!=": operator.ne, "!=": operator.ne,
">=": operator.ge, ">=": operator.ge,
">": operator.gt, ">": operator.gt,
} } # type: Dict[str, Operator]
def _eval_op(lhs, op, rhs): def _eval_op(lhs, op, rhs):
# type: (str, Op, str) -> bool
try: try:
spec = Specifier("".join([op.serialize(), rhs])) spec = Specifier("".join([op.serialize(), rhs]))
except InvalidSpecifier: except InvalidSpecifier:
...@@ -183,7 +200,7 @@ def _eval_op(lhs, op, rhs): ...@@ -183,7 +200,7 @@ def _eval_op(lhs, op, rhs):
else: else:
return spec.contains(lhs) return spec.contains(lhs)
oper = _operators.get(op.serialize()) oper = _operators.get(op.serialize()) # type: Optional[Operator]
if oper is None: if oper is None:
raise UndefinedComparison( raise UndefinedComparison(
"Undefined {0!r} on {1!r} and {2!r}.".format(op, lhs, rhs) "Undefined {0!r} on {1!r} and {2!r}.".format(op, lhs, rhs)
...@@ -192,13 +209,18 @@ def _eval_op(lhs, op, rhs): ...@@ -192,13 +209,18 @@ def _eval_op(lhs, op, rhs):
return oper(lhs, rhs) return oper(lhs, rhs)
_undefined = object() class Undefined(object):
pass
_undefined = Undefined()
def _get_env(environment, name): def _get_env(environment, name):
value = environment.get(name, _undefined) # type: (Dict[str, str], str) -> str
value = environment.get(name, _undefined) # type: Union[str, Undefined]
if value is _undefined: if isinstance(value, Undefined):
raise UndefinedEnvironmentName( raise UndefinedEnvironmentName(
"{0!r} does not exist in evaluation environment.".format(name) "{0!r} does not exist in evaluation environment.".format(name)
) )
...@@ -207,7 +229,8 @@ def _get_env(environment, name): ...@@ -207,7 +229,8 @@ def _get_env(environment, name):
def _evaluate_markers(markers, environment): def _evaluate_markers(markers, environment):
groups = [[]] # type: (List[Any], Dict[str, str]) -> bool
groups = [[]] # type: List[List[bool]]
for marker in markers: for marker in markers:
assert isinstance(marker, (list, tuple, string_types)) assert isinstance(marker, (list, tuple, string_types))
...@@ -234,6 +257,7 @@ def _evaluate_markers(markers, environment): ...@@ -234,6 +257,7 @@ def _evaluate_markers(markers, environment):
def format_full_version(info): 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 kind = info.releaselevel
if kind != "final": if kind != "final":
...@@ -242,9 +266,13 @@ def format_full_version(info): ...@@ -242,9 +266,13 @@ def format_full_version(info):
def default_environment(): def default_environment():
# type: () -> Dict[str, str]
if hasattr(sys, "implementation"): if hasattr(sys, "implementation"):
iver = format_full_version(sys.implementation.version) # Ignoring the `sys.implementation` reference for type checking due to
implementation_name = sys.implementation.name # 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: else:
iver = "0" iver = "0"
implementation_name = "" implementation_name = ""
...@@ -266,6 +294,7 @@ def default_environment(): ...@@ -266,6 +294,7 @@ def default_environment():
class Marker(object): class Marker(object):
def __init__(self, marker): def __init__(self, marker):
# type: (str) -> None
try: try:
self._markers = _coerce_parse_result(MARKER.parseString(marker)) self._markers = _coerce_parse_result(MARKER.parseString(marker))
except ParseException as e: except ParseException as e:
...@@ -275,12 +304,15 @@ class Marker(object): ...@@ -275,12 +304,15 @@ class Marker(object):
raise InvalidMarker(err_str) raise InvalidMarker(err_str)
def __str__(self): def __str__(self):
# type: () -> str
return _format_marker(self._markers) return _format_marker(self._markers)
def __repr__(self): def __repr__(self):
# type: () -> str
return "<Marker({0!r})>".format(str(self)) return "<Marker({0!r})>".format(str(self))
def evaluate(self, environment=None): def evaluate(self, environment=None):
# type: (Optional[Dict[str, str]]) -> bool
"""Evaluate a marker. """Evaluate a marker.
Return the boolean from evaluating the given marker against the Return the boolean from evaluating the given marker against the
......
...@@ -11,9 +11,13 @@ from setuptools.extern.pyparsing import ZeroOrMore, Word, Optional, Regex, Combi ...@@ -11,9 +11,13 @@ from setuptools.extern.pyparsing import ZeroOrMore, Word, Optional, Regex, Combi
from setuptools.extern.pyparsing import Literal as L # noqa from setuptools.extern.pyparsing import Literal as L # noqa
from setuptools.extern.six.moves.urllib import parse as urlparse from setuptools.extern.six.moves.urllib import parse as urlparse
from ._typing import TYPE_CHECKING
from .markers import MARKER_EXPR, Marker from .markers import MARKER_EXPR, Marker
from .specifiers import LegacySpecifier, Specifier, SpecifierSet from .specifiers import LegacySpecifier, Specifier, SpecifierSet
if TYPE_CHECKING: # pragma: no cover
from typing import List
class InvalidRequirement(ValueError): class InvalidRequirement(ValueError):
""" """
...@@ -89,6 +93,7 @@ class Requirement(object): ...@@ -89,6 +93,7 @@ class Requirement(object):
# TODO: Can we normalize the name and extra name? # TODO: Can we normalize the name and extra name?
def __init__(self, requirement_string): def __init__(self, requirement_string):
# type: (str) -> None
try: try:
req = REQUIREMENT.parseString(requirement_string) req = REQUIREMENT.parseString(requirement_string)
except ParseException as e: except ParseException as e:
...@@ -116,7 +121,8 @@ class Requirement(object): ...@@ -116,7 +121,8 @@ class Requirement(object):
self.marker = req.marker if req.marker else None self.marker = req.marker if req.marker else None
def __str__(self): def __str__(self):
parts = [self.name] # type: () -> str
parts = [self.name] # type: List[str]
if self.extras: if self.extras:
parts.append("[{0}]".format(",".join(sorted(self.extras)))) parts.append("[{0}]".format(",".join(sorted(self.extras))))
...@@ -135,4 +141,5 @@ class Requirement(object): ...@@ -135,4 +141,5 @@ class Requirement(object):
return "".join(parts) return "".join(parts)
def __repr__(self): def __repr__(self):
# type: () -> str
return "<Requirement({0!r})>".format(str(self)) return "<Requirement({0!r})>".format(str(self))
This diff is collapsed.
This diff is collapsed.
...@@ -5,28 +5,36 @@ from __future__ import absolute_import, division, print_function ...@@ -5,28 +5,36 @@ from __future__ import absolute_import, division, print_function
import re import re
from ._typing import TYPE_CHECKING, cast
from .version import InvalidVersion, Version from .version import InvalidVersion, Version
if TYPE_CHECKING: # pragma: no cover
from typing import NewType, Union
NormalizedName = NewType("NormalizedName", str)
_canonicalize_regex = re.compile(r"[-_.]+") _canonicalize_regex = re.compile(r"[-_.]+")
def canonicalize_name(name): def canonicalize_name(name):
# type: (str) -> NormalizedName
# This is taken from PEP 503. # This is taken from PEP 503.
return _canonicalize_regex.sub("-", name).lower() value = _canonicalize_regex.sub("-", name).lower()
return cast("NormalizedName", value)
def canonicalize_version(version): def canonicalize_version(_version):
# type: (str) -> Union[Version, str]
""" """
This is very similar to Version.__str__, but has one subtle differences This is very similar to Version.__str__, but has one subtle difference
with the way it handles the release segment. with the way it handles the release segment.
""" """
try: try:
version = Version(version) version = Version(_version)
except InvalidVersion: except InvalidVersion:
# Legacy versions cannot be normalized # Legacy versions cannot be normalized
return version return _version
parts = [] parts = []
......
This diff is collapsed.
packaging==19.2 packaging==20.4
pyparsing==2.2.1 pyparsing==2.2.1
six==1.10.0 six==1.10.0
ordered-set==3.1.1 ordered-set==3.1.1
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment