Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document markers.default_environment() #753

Merged
merged 12 commits into from
Mar 11, 2024
Merged
1 change: 1 addition & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"sphinx.ext.doctest",
"sphinx.ext.extlinks",
"sphinx.ext.intersphinx",
"sphinx_toolbox.more_autodoc.autotypeddict",
]

# General information about the project.
Expand Down
13 changes: 13 additions & 0 deletions docs/markers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,19 @@ Reference
:raises: UndefinedEnvironmentName: If the marker accesses a value that
isn't present inside of the environment
dictionary.
:rtype: bool

.. autotypeddict:: packaging.markers.Environment

A dictionary that represents a Python environment.
edgarrmondragon marked this conversation as resolved.
Show resolved Hide resolved

.. function:: default_environment()

Returns a dictionary representing the current Python process. This is the
base environment that is used when evaluating markers in
:meth:`Marker.evaluate`.

:rtype: Environment

.. exception:: InvalidMarker

Expand Down
2 changes: 2 additions & 0 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
furo
sphinx-toolbox
typing-extensions>=4.1.0; python_version < "3.9"
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ exclude_lines = ["pragma: no cover", "@abc.abstractmethod", "@abc.abstractproper
strict = true
show_error_codes = true
enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"]
warn_unused_ignores = true

[[tool.mypy.overrides]]
module = ["_manylinux"]
Expand Down
35 changes: 35 additions & 0 deletions src/packaging/_compat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import sys
import typing

if sys.version_info[:2] >= (3, 8): # pragma: no cover
from typing import Literal
elif typing.TYPE_CHECKING: # pragma: no cover
from typing_extensions import Literal
else: # pragma: no cover
try:
from typing_extensions import Literal
except ImportError:

class Literal:
def __init_subclass__(*_args, **_kwargs):
pass


if sys.version_info[:2] >= (3, 9): # pragma: no cover
from typing import TypedDict
elif typing.TYPE_CHECKING: # pragma: no cover
from typing_extensions import TypedDict
else: # pragma: no cover
try:
from typing_extensions import TypedDict
except ImportError:

class TypedDict:
def __init_subclass__(*_args, **_kwargs):
pass


__all__ = [
"Literal",
"TypedDict",
]
90 changes: 87 additions & 3 deletions src/packaging/markers.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import sys
from typing import Any, Callable, Dict, List, Optional, Tuple, Union

from ._compat import TypedDict
pradyunsg marked this conversation as resolved.
Show resolved Hide resolved
from ._parser import (
MarkerAtom,
MarkerList,
Expand Down Expand Up @@ -50,6 +51,89 @@ class UndefinedEnvironmentName(ValueError):
"""


class Environment(TypedDict, total=False):
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.

Currently, the following implementations are identified: ``'CPython'`` (C
implementation of Python), ``'IronPython'`` (.NET implementation of Python),
``'Jython'`` (Java implementation of Python), ``'PyPy'`` (Python implementation of
Python).
edgarrmondragon marked this conversation as resolved.
Show resolved Hide resolved
"""

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.
"""

extra: Optional[str]
pradyunsg marked this conversation as resolved.
Show resolved Hide resolved
"""
An optional string used by wheels to signal which specifications apply to a given
extra in the wheel ``METADATA`` file.
"""


def _normalize_extra_values(results: Any) -> Any:
"""
Normalize extra values.
Expand Down Expand Up @@ -172,7 +256,7 @@ def format_full_version(info: "sys._version_info") -> str:
return version


def default_environment() -> Dict[str, str]:
def default_environment() -> Environment:
iver = format_full_version(sys.implementation.version)
implementation_name = sys.implementation.name
return {
Expand Down Expand Up @@ -243,10 +327,10 @@ def evaluate(self, environment: Optional[Dict[str, str]] = None) -> bool:
current_environment = default_environment()
current_environment["extra"] = ""
if environment is not None:
current_environment.update(environment)
current_environment.update(environment) # type: ignore[typeddict-item]
brettcannon marked this conversation as resolved.
Show resolved Hide resolved
# The API used to allow setting extra to None. We need to handle this
# case for backwards compatibility.
if current_environment["extra"] is None:
current_environment["extra"] = ""

return _evaluate_markers(self._markers, current_environment)
return _evaluate_markers(self._markers, current_environment) # type: ignore[arg-type] # noqa: E501
brettcannon marked this conversation as resolved.
Show resolved Hide resolved
19 changes: 1 addition & 18 deletions src/packaging/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import email.message
import email.parser
import email.policy
import sys
import typing
from typing import (
Any,
Expand All @@ -19,25 +18,9 @@
)

from . import requirements, specifiers, utils, version as version_module
from ._compat import Literal, TypedDict

T = typing.TypeVar("T")
if sys.version_info[:2] >= (3, 8): # pragma: no cover
from typing import Literal, TypedDict
else: # pragma: no cover
if typing.TYPE_CHECKING:
from typing_extensions import Literal, TypedDict
else:
try:
from typing_extensions import Literal, TypedDict
except ImportError:

class Literal:
def __init_subclass__(*_args, **_kwargs):
pass

class TypedDict:
def __init_subclass__(*_args, **_kwargs):
pass


try:
Expand Down