| from __future__ import annotations | |
| from typing import Any | |
| from typing import cast | |
| from typing import Generic | |
| from typing import TypeVar | |
| __all__ = ["Stash", "StashKey"] | |
| T = TypeVar("T") | |
| D = TypeVar("D") | |
| class StashKey(Generic[T]): | |
| """``StashKey`` is an object used as a key to a :class:`Stash`. | |
| A ``StashKey`` is associated with the type ``T`` of the value of the key. | |
| A ``StashKey`` is unique and cannot conflict with another key. | |
| .. versionadded:: 7.0 | |
| """ | |
| __slots__ = () | |
| class Stash: | |
| r"""``Stash`` is a type-safe heterogeneous mutable mapping that | |
| allows keys and value types to be defined separately from | |
| where it (the ``Stash``) is created. | |
| Usually you will be given an object which has a ``Stash``, for example | |
| :class:`~pytest.Config` or a :class:`~_pytest.nodes.Node`: | |
| .. code-block:: python | |
| stash: Stash = some_object.stash | |
| If a module or plugin wants to store data in this ``Stash``, it creates | |
| :class:`StashKey`\s for its keys (at the module level): | |
| .. code-block:: python | |
| # At the top-level of the module | |
| some_str_key = StashKey[str]() | |
| some_bool_key = StashKey[bool]() | |
| To store information: | |
| .. code-block:: python | |
| # Value type must match the key. | |
| stash[some_str_key] = "value" | |
| stash[some_bool_key] = True | |
| To retrieve the information: | |
| .. code-block:: python | |
| # The static type of some_str is str. | |
| some_str = stash[some_str_key] | |
| # The static type of some_bool is bool. | |
| some_bool = stash[some_bool_key] | |
| .. versionadded:: 7.0 | |
| """ | |
| __slots__ = ("_storage",) | |
| def __init__(self) -> None: | |
| self._storage: dict[StashKey[Any], object] = {} | |
| def __setitem__(self, key: StashKey[T], value: T) -> None: | |
| """Set a value for key.""" | |
| self._storage[key] = value | |
| def __getitem__(self, key: StashKey[T]) -> T: | |
| """Get the value for key. | |
| Raises ``KeyError`` if the key wasn't set before. | |
| """ | |
| return cast(T, self._storage[key]) | |
| def get(self, key: StashKey[T], default: D) -> T | D: | |
| """Get the value for key, or return default if the key wasn't set | |
| before.""" | |
| try: | |
| return self[key] | |
| except KeyError: | |
| return default | |
| def setdefault(self, key: StashKey[T], default: T) -> T: | |
| """Return the value of key if already set, otherwise set the value | |
| of key to default and return default.""" | |
| try: | |
| return self[key] | |
| except KeyError: | |
| self[key] = default | |
| return default | |
| def __delitem__(self, key: StashKey[T]) -> None: | |
| """Delete the value for key. | |
| Raises ``KeyError`` if the key wasn't set before. | |
| """ | |
| del self._storage[key] | |
| def __contains__(self, key: StashKey[T]) -> bool: | |
| """Return whether key was set.""" | |
| return key in self._storage | |
| def __len__(self) -> int: | |
| """Return how many items exist in the stash.""" | |
| return len(self._storage) | |