| 
							
								 | 
							
							# 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 annotations
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							import operator
 | 
						
						
						
						
							 | 
							
								 | 
							
							import os
 | 
						
						
						
						
							 | 
							
								 | 
							
							import platform
 | 
						
						
						
						
							 | 
							
								 | 
							
							import sys
 | 
						
						
						
						
							 | 
							
								 | 
							
							from typing import AbstractSet, Any, Callable, Literal, TypedDict, Union, cast
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							from ._parser import MarkerAtom, MarkerList, Op, Value, Variable
 | 
						
						
						
						
							 | 
							
								 | 
							
							from ._parser import parse_marker as _parse_marker
 | 
						
						
						
						
							 | 
							
								 | 
							
							from ._tokenizer import ParserSyntaxError
 | 
						
						
						
						
							 | 
							
								 | 
							
							from .specifiers import InvalidSpecifier, Specifier
 | 
						
						
						
						
							 | 
							
								 | 
							
							from .utils import canonicalize_name
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							__all__ = [
 | 
						
						
						
						
							 | 
							
								 | 
							
							    "EvaluateContext",
 | 
						
						
						
						
							 | 
							
								 | 
							
							    "InvalidMarker",
 | 
						
						
						
						
							 | 
							
								 | 
							
							    "Marker",
 | 
						
						
						
						
							 | 
							
								 | 
							
							    "UndefinedComparison",
 | 
						
						
						
						
							 | 
							
								 | 
							
							    "UndefinedEnvironmentName",
 | 
						
						
						
						
							 | 
							
								 | 
							
							    "default_environment",
 | 
						
						
						
						
							 | 
							
								 | 
							
							]
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							Operator = Callable[[str, Union[str, AbstractSet[str]]], bool]
 | 
						
						
						
						
							 | 
							
								 | 
							
							EvaluateContext = Literal["metadata", "lock_file", "requirement"]
 | 
						
						
						
						
							 | 
							
								 | 
							
							MARKERS_ALLOWING_SET = {"extras", "dependency_groups"}
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							class InvalidMarker(ValueError):
 | 
						
						
						
						
							 | 
							
								 | 
							
							    """
 | 
						
						
						
						
							 | 
							
								 | 
							
							    An invalid marker was found, users should refer to PEP 508.
 | 
						
						
						
						
							 | 
							
								 | 
							
							    """
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							class UndefinedComparison(ValueError):
 | 
						
						
						
						
							 | 
							
								 | 
							
							    """
 | 
						
						
						
						
							 | 
							
								 | 
							
							    An invalid operation was attempted on a value that doesn't support it.
 | 
						
						
						
						
							 | 
							
								 | 
							
							    """
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							class UndefinedEnvironmentName(ValueError):
 | 
						
						
						
						
							 | 
							
								 | 
							
							    """
 | 
						
						
						
						
							 | 
							
								 | 
							
							    A name was attempted to be used that does not exist inside of the
 | 
						
						
						
						
							 | 
							
								 | 
							
							    environment.
 | 
						
						
						
						
							 | 
							
								 | 
							
							    """
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							class Environment(TypedDict):
 | 
						
						
						
						
							 | 
							
								 | 
							
							    implementation_name: str
 | 
						
						
						
						
							 | 
							
								 | 
							
							    """The implementation's identifier, e.g. ``'cpython'``."""
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							    implementation_version: str
 | 
						
						
						
						
							 | 
							
								 | 
							
							    """
 | 
						
						
						
						
							 | 
							
								 | 
							
							    The implementation's version, e.g. ``'3.13.0a2'`` for CPython 3.13.0a2, or
 | 
						
						
						
						
							 | 
							
								 | 
							
							    ``'7.3.13'`` for PyPy3.10 v7.3.13.
 | 
						
						
						
						
							 | 
							
								 | 
							
							    """
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							    os_name: str
 | 
						
						
						
						
							 | 
							
								 | 
							
							    """
 | 
						
						
						
						
							 | 
							
								 | 
							
							    The value of :py:data:`os.name`. The name of the operating system dependent module
 | 
						
						
						
						
							 | 
							
								 | 
							
							    imported, e.g. ``'posix'``.
 | 
						
						
						
						
							 | 
							
								 | 
							
							    """
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							    platform_machine: str
 | 
						
						
						
						
							 | 
							
								 | 
							
							    """
 | 
						
						
						
						
							 | 
							
								 | 
							
							    Returns the machine type, e.g. ``'i386'``.
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							    An empty string if the value cannot be determined.
 | 
						
						
						
						
							 | 
							
								 | 
							
							    """
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							    platform_release: str
 | 
						
						
						
						
							 | 
							
								 | 
							
							    """
 | 
						
						
						
						
							 | 
							
								 | 
							
							    The system's release, e.g. ``'2.2.0'`` or ``'NT'``.
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							    An empty string if the value cannot be determined.
 | 
						
						
						
						
							 | 
							
								 | 
							
							    """
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							    platform_system: str
 | 
						
						
						
						
							 | 
							
								 | 
							
							    """
 | 
						
						
						
						
							 | 
							
								 | 
							
							    The system/OS name, e.g. ``'Linux'``, ``'Windows'`` or ``'Java'``.
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							    An empty string if the value cannot be determined.
 | 
						
						
						
						
							 | 
							
								 | 
							
							    """
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							    platform_version: str
 | 
						
						
						
						
							 | 
							
								 | 
							
							    """
 | 
						
						
						
						
							 | 
							
								 | 
							
							    The system's release version, e.g. ``'#3 on degas'``.
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							    An empty string if the value cannot be determined.
 | 
						
						
						
						
							 | 
							
								 | 
							
							    """
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							    python_full_version: str
 | 
						
						
						
						
							 | 
							
								 | 
							
							    """
 | 
						
						
						
						
							 | 
							
								 | 
							
							    The Python version as string ``'major.minor.patchlevel'``.
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							    Note that unlike the Python :py:data:`sys.version`, this value will always include
 | 
						
						
						
						
							 | 
							
								 | 
							
							    the patchlevel (it defaults to 0).
 | 
						
						
						
						
							 | 
							
								 | 
							
							    """
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							    platform_python_implementation: str
 | 
						
						
						
						
							 | 
							
								 | 
							
							    """
 | 
						
						
						
						
							 | 
							
								 | 
							
							    A string identifying the Python implementation, e.g. ``'CPython'``.
 | 
						
						
						
						
							 | 
							
								 | 
							
							    """
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							    python_version: str
 | 
						
						
						
						
							 | 
							
								 | 
							
							    """The Python version as string ``'major.minor'``."""
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							    sys_platform: str
 | 
						
						
						
						
							 | 
							
								 | 
							
							    """
 | 
						
						
						
						
							 | 
							
								 | 
							
							    This string contains a platform identifier that can be used to append
 | 
						
						
						
						
							 | 
							
								 | 
							
							    platform-specific components to :py:data:`sys.path`, for instance.
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							    For Unix systems, except on Linux and AIX, this is the lowercased OS name as
 | 
						
						
						
						
							 | 
							
								 | 
							
							    returned by ``uname -s`` with the first part of the version as returned by
 | 
						
						
						
						
							 | 
							
								 | 
							
							    ``uname -r`` appended, e.g. ``'sunos5'`` or ``'freebsd8'``, at the time when Python
 | 
						
						
						
						
							 | 
							
								 | 
							
							    was built.
 | 
						
						
						
						
							 | 
							
								 | 
							
							    """
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							def _normalize_extra_values(results: Any) -> Any:
 | 
						
						
						
						
							 | 
							
								 | 
							
							    """
 | 
						
						
						
						
							 | 
							
								 | 
							
							    Normalize extra values.
 | 
						
						
						
						
							 | 
							
								 | 
							
							    """
 | 
						
						
						
						
							 | 
							
								 | 
							
							    if isinstance(results[0], tuple):
 | 
						
						
						
						
							 | 
							
								 | 
							
							        lhs, op, rhs = results[0]
 | 
						
						
						
						
							 | 
							
								 | 
							
							        if isinstance(lhs, Variable) and lhs.value == "extra":
 | 
						
						
						
						
							 | 
							
								 | 
							
							            normalized_extra = canonicalize_name(rhs.value)
 | 
						
						
						
						
							 | 
							
								 | 
							
							            rhs = Value(normalized_extra)
 | 
						
						
						
						
							 | 
							
								 | 
							
							        elif isinstance(rhs, Variable) and rhs.value == "extra":
 | 
						
						
						
						
							 | 
							
								 | 
							
							            normalized_extra = canonicalize_name(lhs.value)
 | 
						
						
						
						
							 | 
							
								 | 
							
							            lhs = Value(normalized_extra)
 | 
						
						
						
						
							 | 
							
								 | 
							
							        results[0] = lhs, op, rhs
 | 
						
						
						
						
							 | 
							
								 | 
							
							    return results
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							def _format_marker(
 | 
						
						
						
						
							 | 
							
								 | 
							
							    marker: list[str] | MarkerAtom | str, first: bool | None = True
 | 
						
						
						
						
							 | 
							
								 | 
							
							) -> str:
 | 
						
						
						
						
							 | 
							
								 | 
							
							    assert isinstance(marker, (list, tuple, str))
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							    # Sometimes we have a structure like [[...]] which is a single item list
 | 
						
						
						
						
							 | 
							
								 | 
							
							    # where the single item is itself it's own list. In that case we want skip
 | 
						
						
						
						
							 | 
							
								 | 
							
							    # 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))
 | 
						
						
						
						
							 | 
							
								 | 
							
							    ):
 | 
						
						
						
						
							 | 
							
								 | 
							
							        return _format_marker(marker[0])
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							    if isinstance(marker, list):
 | 
						
						
						
						
							 | 
							
								 | 
							
							        inner = (_format_marker(m, first=False) for m in marker)
 | 
						
						
						
						
							 | 
							
								 | 
							
							        if first:
 | 
						
						
						
						
							 | 
							
								 | 
							
							            return " ".join(inner)
 | 
						
						
						
						
							 | 
							
								 | 
							
							        else:
 | 
						
						
						
						
							 | 
							
								 | 
							
							            return "(" + " ".join(inner) + ")"
 | 
						
						
						
						
							 | 
							
								 | 
							
							    elif isinstance(marker, tuple):
 | 
						
						
						
						
							 | 
							
								 | 
							
							        return " ".join([m.serialize() for m in marker])
 | 
						
						
						
						
							 | 
							
								 | 
							
							    else:
 | 
						
						
						
						
							 | 
							
								 | 
							
							        return marker
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							_operators: dict[str, Operator] = {
 | 
						
						
						
						
							 | 
							
								 | 
							
							    "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,
 | 
						
						
						
						
							 | 
							
								 | 
							
							}
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							def _eval_op(lhs: str, op: Op, rhs: str | AbstractSet[str]) -> bool:
 | 
						
						
						
						
							 | 
							
								 | 
							
							    if isinstance(rhs, str):
 | 
						
						
						
						
							 | 
							
								 | 
							
							        try:
 | 
						
						
						
						
							 | 
							
								 | 
							
							            spec = Specifier("".join([op.serialize(), rhs]))
 | 
						
						
						
						
							 | 
							
								 | 
							
							        except InvalidSpecifier:
 | 
						
						
						
						
							 | 
							
								 | 
							
							            pass
 | 
						
						
						
						
							 | 
							
								 | 
							
							        else:
 | 
						
						
						
						
							 | 
							
								 | 
							
							            return spec.contains(lhs, prereleases=True)
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							    oper: Operator | None = _operators.get(op.serialize())
 | 
						
						
						
						
							 | 
							
								 | 
							
							    if oper is None:
 | 
						
						
						
						
							 | 
							
								 | 
							
							        raise UndefinedComparison(f"Undefined {op!r} on {lhs!r} and {rhs!r}.")
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							    return oper(lhs, rhs)
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							def _normalize(
 | 
						
						
						
						
							 | 
							
								 | 
							
							    lhs: str, rhs: str | AbstractSet[str], key: str
 | 
						
						
						
						
							 | 
							
								 | 
							
							) -> tuple[str, str | AbstractSet[str]]:
 | 
						
						
						
						
							 | 
							
								 | 
							
							    # PEP 685 – Comparison of extra names for optional distribution dependencies
 | 
						
						
						
						
							 | 
							
								 | 
							
							    # https://peps.python.org/pep-0685/
 | 
						
						
						
						
							 | 
							
								 | 
							
							    # > When comparing extra names, tools MUST normalize the names being
 | 
						
						
						
						
							 | 
							
								 | 
							
							    # > compared using the semantics outlined in PEP 503 for names
 | 
						
						
						
						
							 | 
							
								 | 
							
							    if key == "extra":
 | 
						
						
						
						
							 | 
							
								 | 
							
							        assert isinstance(rhs, str), "extra value must be a string"
 | 
						
						
						
						
							 | 
							
								 | 
							
							        return (canonicalize_name(lhs), canonicalize_name(rhs))
 | 
						
						
						
						
							 | 
							
								 | 
							
							    if key in MARKERS_ALLOWING_SET:
 | 
						
						
						
						
							 | 
							
								 | 
							
							        if isinstance(rhs, str):  # pragma: no cover
 | 
						
						
						
						
							 | 
							
								 | 
							
							            return (canonicalize_name(lhs), canonicalize_name(rhs))
 | 
						
						
						
						
							 | 
							
								 | 
							
							        else:
 | 
						
						
						
						
							 | 
							
								 | 
							
							            return (canonicalize_name(lhs), {canonicalize_name(v) for v in rhs})
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							    # other environment markers don't have such standards
 | 
						
						
						
						
							 | 
							
								 | 
							
							    return lhs, rhs
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							def _evaluate_markers(
 | 
						
						
						
						
							 | 
							
								 | 
							
							    markers: MarkerList, environment: dict[str, str | AbstractSet[str]]
 | 
						
						
						
						
							 | 
							
								 | 
							
							) -> bool:
 | 
						
						
						
						
							 | 
							
								 | 
							
							    groups: list[list[bool]] = [[]]
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							    for marker in markers:
 | 
						
						
						
						
							 | 
							
								 | 
							
							        assert isinstance(marker, (list, tuple, str))
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							        if isinstance(marker, list):
 | 
						
						
						
						
							 | 
							
								 | 
							
							            groups[-1].append(_evaluate_markers(marker, environment))
 | 
						
						
						
						
							 | 
							
								 | 
							
							        elif isinstance(marker, tuple):
 | 
						
						
						
						
							 | 
							
								 | 
							
							            lhs, op, rhs = marker
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							            if isinstance(lhs, Variable):
 | 
						
						
						
						
							 | 
							
								 | 
							
							                environment_key = lhs.value
 | 
						
						
						
						
							 | 
							
								 | 
							
							                lhs_value = environment[environment_key]
 | 
						
						
						
						
							 | 
							
								 | 
							
							                rhs_value = rhs.value
 | 
						
						
						
						
							 | 
							
								 | 
							
							            else:
 | 
						
						
						
						
							 | 
							
								 | 
							
							                lhs_value = lhs.value
 | 
						
						
						
						
							 | 
							
								 | 
							
							                environment_key = rhs.value
 | 
						
						
						
						
							 | 
							
								 | 
							
							                rhs_value = environment[environment_key]
 | 
						
						
						
						
							 | 
							
								 | 
							
							            assert isinstance(lhs_value, str), "lhs must be a string"
 | 
						
						
						
						
							 | 
							
								 | 
							
							            lhs_value, rhs_value = _normalize(lhs_value, rhs_value, key=environment_key)
 | 
						
						
						
						
							 | 
							
								 | 
							
							            groups[-1].append(_eval_op(lhs_value, op, rhs_value))
 | 
						
						
						
						
							 | 
							
								 | 
							
							        else:
 | 
						
						
						
						
							 | 
							
								 | 
							
							            assert marker in ["and", "or"]
 | 
						
						
						
						
							 | 
							
								 | 
							
							            if marker == "or":
 | 
						
						
						
						
							 | 
							
								 | 
							
							                groups.append([])
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							    return any(all(item) for item in groups)
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							def format_full_version(info: sys._version_info) -> str:
 | 
						
						
						
						
							 | 
							
								 | 
							
							    version = f"{info.major}.{info.minor}.{info.micro}"
 | 
						
						
						
						
							 | 
							
								 | 
							
							    kind = info.releaselevel
 | 
						
						
						
						
							 | 
							
								 | 
							
							    if kind != "final":
 | 
						
						
						
						
							 | 
							
								 | 
							
							        version += kind[0] + str(info.serial)
 | 
						
						
						
						
							 | 
							
								 | 
							
							    return version
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							def default_environment() -> Environment:
 | 
						
						
						
						
							 | 
							
								 | 
							
							    iver = format_full_version(sys.implementation.version)
 | 
						
						
						
						
							 | 
							
								 | 
							
							    implementation_name = sys.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,
 | 
						
						
						
						
							 | 
							
								 | 
							
							    }
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							class Marker:
 | 
						
						
						
						
							 | 
							
								 | 
							
							    def __init__(self, marker: str) -> None:
 | 
						
						
						
						
							 | 
							
								 | 
							
							        # Note: We create a Marker object without calling this constructor in
 | 
						
						
						
						
							 | 
							
								 | 
							
							        #       packaging.requirements.Requirement. If any additional logic is
 | 
						
						
						
						
							 | 
							
								 | 
							
							        #       added here, make sure to mirror/adapt Requirement.
 | 
						
						
						
						
							 | 
							
								 | 
							
							        try:
 | 
						
						
						
						
							 | 
							
								 | 
							
							            self._markers = _normalize_extra_values(_parse_marker(marker))
 | 
						
						
						
						
							 | 
							
								 | 
							
							            # The attribute `_markers` can be described in terms of a recursive type:
 | 
						
						
						
						
							 | 
							
								 | 
							
							            # MarkerList = List[Union[Tuple[Node, ...], str, MarkerList]]
 | 
						
						
						
						
							 | 
							
								 | 
							
							            #
 | 
						
						
						
						
							 | 
							
								 | 
							
							            # For example, the following expression:
 | 
						
						
						
						
							 | 
							
								 | 
							
							            # python_version > "3.6" or (python_version == "3.6" and os_name == "unix")
 | 
						
						
						
						
							 | 
							
								 | 
							
							            #
 | 
						
						
						
						
							 | 
							
								 | 
							
							            # is parsed into:
 | 
						
						
						
						
							 | 
							
								 | 
							
							            # [
 | 
						
						
						
						
							 | 
							
								 | 
							
							            #     (<Variable('python_version')>, <Op('>')>, <Value('3.6')>),
 | 
						
						
						
						
							 | 
							
								 | 
							
							            #     'and',
 | 
						
						
						
						
							 | 
							
								 | 
							
							            #     [
 | 
						
						
						
						
							 | 
							
								 | 
							
							            #         (<Variable('python_version')>, <Op('==')>, <Value('3.6')>),
 | 
						
						
						
						
							 | 
							
								 | 
							
							            #         'or',
 | 
						
						
						
						
							 | 
							
								 | 
							
							            #         (<Variable('os_name')>, <Op('==')>, <Value('unix')>)
 | 
						
						
						
						
							 | 
							
								 | 
							
							            #     ]
 | 
						
						
						
						
							 | 
							
								 | 
							
							            # ]
 | 
						
						
						
						
							 | 
							
								 | 
							
							        except ParserSyntaxError as e:
 | 
						
						
						
						
							 | 
							
								 | 
							
							            raise InvalidMarker(str(e)) from e
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							    def __str__(self) -> str:
 | 
						
						
						
						
							 | 
							
								 | 
							
							        return _format_marker(self._markers)
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							    def __repr__(self) -> str:
 | 
						
						
						
						
							 | 
							
								 | 
							
							        return f"<Marker('{self}')>"
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							    def __hash__(self) -> int:
 | 
						
						
						
						
							 | 
							
								 | 
							
							        return hash((self.__class__.__name__, str(self)))
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							    def __eq__(self, other: Any) -> bool:
 | 
						
						
						
						
							 | 
							
								 | 
							
							        if not isinstance(other, Marker):
 | 
						
						
						
						
							 | 
							
								 | 
							
							            return NotImplemented
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							        return str(self) == str(other)
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							    def evaluate(
 | 
						
						
						
						
							 | 
							
								 | 
							
							        self,
 | 
						
						
						
						
							 | 
							
								 | 
							
							        environment: dict[str, str] | None = None,
 | 
						
						
						
						
							 | 
							
								 | 
							
							        context: EvaluateContext = "metadata",
 | 
						
						
						
						
							 | 
							
								 | 
							
							    ) -> bool:
 | 
						
						
						
						
							 | 
							
								 | 
							
							        """Evaluate a marker.
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							        Return the boolean from evaluating the given marker against the
 | 
						
						
						
						
							 | 
							
								 | 
							
							        environment. environment is an optional argument to override all or
 | 
						
						
						
						
							 | 
							
								 | 
							
							        part of the determined environment. The *context* parameter specifies what
 | 
						
						
						
						
							 | 
							
								 | 
							
							        context the markers are being evaluated for, which influences what markers
 | 
						
						
						
						
							 | 
							
								 | 
							
							        are considered valid. Acceptable values are "metadata" (for core metadata;
 | 
						
						
						
						
							 | 
							
								 | 
							
							        default), "lock_file", and "requirement" (i.e. all other situations).
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							        The environment is determined from the current Python process.
 | 
						
						
						
						
							 | 
							
								 | 
							
							        """
 | 
						
						
						
						
							 | 
							
								 | 
							
							        current_environment = cast(
 | 
						
						
						
						
							 | 
							
								 | 
							
							            "dict[str, str | AbstractSet[str]]", default_environment()
 | 
						
						
						
						
							 | 
							
								 | 
							
							        )
 | 
						
						
						
						
							 | 
							
								 | 
							
							        if context == "lock_file":
 | 
						
						
						
						
							 | 
							
								 | 
							
							            current_environment.update(
 | 
						
						
						
						
							 | 
							
								 | 
							
							                extras=frozenset(), dependency_groups=frozenset()
 | 
						
						
						
						
							 | 
							
								 | 
							
							            )
 | 
						
						
						
						
							 | 
							
								 | 
							
							        elif context == "metadata":
 | 
						
						
						
						
							 | 
							
								 | 
							
							            current_environment["extra"] = ""
 | 
						
						
						
						
							 | 
							
								 | 
							
							        if environment is not None:
 | 
						
						
						
						
							 | 
							
								 | 
							
							            current_environment.update(environment)
 | 
						
						
						
						
							 | 
							
								 | 
							
							            # The API used to allow setting extra to None. We need to handle this
 | 
						
						
						
						
							 | 
							
								 | 
							
							            # case for backwards compatibility.
 | 
						
						
						
						
							 | 
							
								 | 
							
							            if "extra" in current_environment and current_environment["extra"] is None:
 | 
						
						
						
						
							 | 
							
								 | 
							
							                current_environment["extra"] = ""
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							        return _evaluate_markers(
 | 
						
						
						
						
							 | 
							
								 | 
							
							            self._markers, _repair_python_full_version(current_environment)
 | 
						
						
						
						
							 | 
							
								 | 
							
							        )
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							
 | 
						
						
						
						
							 | 
							
								 | 
							
							def _repair_python_full_version(
 | 
						
						
						
						
							 | 
							
								 | 
							
							    env: dict[str, str | AbstractSet[str]],
 | 
						
						
						
						
							 | 
							
								 | 
							
							) -> dict[str, str | AbstractSet[str]]:
 | 
						
						
						
						
							 | 
							
								 | 
							
							    """
 | 
						
						
						
						
							 | 
							
								 | 
							
							    Work around platform.python_version() returning something that is not PEP 440
 | 
						
						
						
						
							 | 
							
								 | 
							
							    compliant for non-tagged Python builds.
 | 
						
						
						
						
							 | 
							
								 | 
							
							    """
 | 
						
						
						
						
							 | 
							
								 | 
							
							    python_full_version = cast(str, env["python_full_version"])
 | 
						
						
						
						
							 | 
							
								 | 
							
							    if python_full_version.endswith("+"):
 | 
						
						
						
						
							 | 
							
								 | 
							
							        env["python_full_version"] = f"{python_full_version}local"
 | 
						
						
						
						
							 | 
							
								 | 
							
							    return env
 |