diff --git a/src/_pytest/assertion/rewrite.py b/src/_pytest/assertion/rewrite.py index 33e2ef6cc..3c8ffde4e 100644 --- a/src/_pytest/assertion/rewrite.py +++ b/src/_pytest/assertion/rewrite.py @@ -38,13 +38,13 @@ from _pytest.config import Config from _pytest.main import Session from _pytest.pathlib import absolutepath from _pytest.pathlib import fnmatch_ex -from _pytest.store import StoreKey +from _pytest.stash import StashKey if TYPE_CHECKING: from _pytest.assertion import AssertionState -assertstate_key = StoreKey["AssertionState"]() +assertstate_key = StashKey["AssertionState"]() # pytest caches rewritten pycs in pycache dirs diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index f32991137..feca31f4c 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -56,7 +56,7 @@ from _pytest.pathlib import bestrelpath from _pytest.pathlib import import_path from _pytest.pathlib import ImportMode from _pytest.pathlib import resolve_package_path -from _pytest.store import Store +from _pytest.stash import Stash from _pytest.warning_types import PytestConfigWarning if TYPE_CHECKING: @@ -933,7 +933,7 @@ class Config: self._cleanup: List[Callable[[], None]] = [] # A place where plugins can store information on the config for their # own use. Currently only intended for internal plugins. - self._store = Store() + self._store = Stash() self.pluginmanager.register(self, "pytestconfig") self._configured = False self.hook.pytest_addoption.call_historic( diff --git a/src/_pytest/faulthandler.py b/src/_pytest/faulthandler.py index c8eb03101..fc2471f39 100644 --- a/src/_pytest/faulthandler.py +++ b/src/_pytest/faulthandler.py @@ -8,11 +8,11 @@ import pytest from _pytest.config import Config from _pytest.config.argparsing import Parser from _pytest.nodes import Item -from _pytest.store import StoreKey +from _pytest.stash import StashKey -fault_handler_stderr_key = StoreKey[TextIO]() -fault_handler_originally_enabled_key = StoreKey[bool]() +fault_handler_stderr_key = StashKey[TextIO]() +fault_handler_originally_enabled_key = StashKey[bool]() def pytest_addoption(parser: Parser) -> None: diff --git a/src/_pytest/fixtures.py b/src/_pytest/fixtures.py index b19c850a6..305ec0348 100644 --- a/src/_pytest/fixtures.py +++ b/src/_pytest/fixtures.py @@ -62,7 +62,7 @@ from _pytest.outcomes import fail from _pytest.outcomes import TEST_OUTCOME from _pytest.pathlib import absolutepath from _pytest.pathlib import bestrelpath -from _pytest.store import StoreKey +from _pytest.stash import StashKey if TYPE_CHECKING: from typing import Deque @@ -149,7 +149,7 @@ def get_scope_node( # Used for storing artificial fixturedefs for direct parametrization. -name2pseudofixturedef_key = StoreKey[Dict[str, "FixtureDef[Any]"]]() +name2pseudofixturedef_key = StashKey[Dict[str, "FixtureDef[Any]"]]() def add_funcarg_pseudo_fixture_def( diff --git a/src/_pytest/junitxml.py b/src/_pytest/junitxml.py index fafb5fa1a..d7b00cca1 100644 --- a/src/_pytest/junitxml.py +++ b/src/_pytest/junitxml.py @@ -30,11 +30,11 @@ from _pytest.config import filename_arg from _pytest.config.argparsing import Parser from _pytest.fixtures import FixtureRequest from _pytest.reports import TestReport -from _pytest.store import StoreKey +from _pytest.stash import StashKey from _pytest.terminal import TerminalReporter -xml_key = StoreKey["LogXML"]() +xml_key = StashKey["LogXML"]() def bin_xml_escape(arg: object) -> str: diff --git a/src/_pytest/logging.py b/src/_pytest/logging.py index 8b4865b5d..376a6b31f 100644 --- a/src/_pytest/logging.py +++ b/src/_pytest/logging.py @@ -31,15 +31,15 @@ from _pytest.deprecated import check_ispytest from _pytest.fixtures import fixture from _pytest.fixtures import FixtureRequest from _pytest.main import Session -from _pytest.store import StoreKey +from _pytest.stash import StashKey from _pytest.terminal import TerminalReporter DEFAULT_LOG_FORMAT = "%(levelname)-8s %(name)s:%(filename)s:%(lineno)d %(message)s" DEFAULT_LOG_DATE_FORMAT = "%H:%M:%S" _ANSI_ESCAPE_SEQ = re.compile(r"\x1b\[[\d;]+m") -caplog_handler_key = StoreKey["LogCaptureHandler"]() -caplog_records_key = StoreKey[Dict[str, List[logging.LogRecord]]]() +caplog_handler_key = StashKey["LogCaptureHandler"]() +caplog_records_key = StashKey[Dict[str, List[logging.LogRecord]]]() def _remove_ansi_escape_sequences(text: str) -> str: diff --git a/src/_pytest/mark/__init__.py b/src/_pytest/mark/__init__.py index 0dc3718e8..877b5ef1c 100644 --- a/src/_pytest/mark/__init__.py +++ b/src/_pytest/mark/__init__.py @@ -25,7 +25,7 @@ from _pytest.config import UsageError from _pytest.config.argparsing import Parser from _pytest.deprecated import MINUS_K_COLON from _pytest.deprecated import MINUS_K_DASH -from _pytest.store import StoreKey +from _pytest.stash import StashKey if TYPE_CHECKING: from _pytest.nodes import Item @@ -41,7 +41,7 @@ __all__ = [ ] -old_mark_config_key = StoreKey[Optional[Config]]() +old_mark_config_key = StashKey[Optional[Config]]() def param( diff --git a/src/_pytest/nodes.py b/src/_pytest/nodes.py index c8e286576..939c7b207 100644 --- a/src/_pytest/nodes.py +++ b/src/_pytest/nodes.py @@ -34,7 +34,7 @@ from _pytest.mark.structures import NodeKeywords from _pytest.outcomes import fail from _pytest.pathlib import absolutepath from _pytest.pathlib import commonpath -from _pytest.store import Store +from _pytest.stash import Stash from _pytest.warning_types import PytestWarning if TYPE_CHECKING: @@ -220,7 +220,7 @@ class Node(metaclass=NodeMeta): # A place where plugins can store information on the node for their # own use. Currently only intended for internal plugins. - self._store = Store() + self._store = Stash() @property def fspath(self) -> LEGACY_PATH: diff --git a/src/_pytest/pastebin.py b/src/_pytest/pastebin.py index 189ed3c5e..1ca7cc494 100644 --- a/src/_pytest/pastebin.py +++ b/src/_pytest/pastebin.py @@ -8,11 +8,11 @@ import pytest from _pytest.config import Config from _pytest.config import create_terminal_writer from _pytest.config.argparsing import Parser -from _pytest.store import StoreKey +from _pytest.stash import StashKey from _pytest.terminal import TerminalReporter -pastebinfile_key = StoreKey[IO[bytes]]() +pastebinfile_key = StashKey[IO[bytes]]() def pytest_addoption(parser: Parser) -> None: diff --git a/src/_pytest/skipping.py b/src/_pytest/skipping.py index f7a026ae7..18f9a49bc 100644 --- a/src/_pytest/skipping.py +++ b/src/_pytest/skipping.py @@ -21,7 +21,7 @@ from _pytest.outcomes import skip from _pytest.outcomes import xfail from _pytest.reports import BaseReport from _pytest.runner import CallInfo -from _pytest.store import StoreKey +from _pytest.stash import StashKey def pytest_addoption(parser: Parser) -> None: @@ -228,7 +228,7 @@ def evaluate_xfail_marks(item: Item) -> Optional[Xfail]: # Saves the xfail mark evaluation. Can be refreshed during call if None. -xfailed_key = StoreKey[Optional[Xfail]]() +xfailed_key = StashKey[Optional[Xfail]]() @hookimpl(tryfirst=True) diff --git a/src/_pytest/store.py b/src/_pytest/stash.py similarity index 58% rename from src/_pytest/store.py rename to src/_pytest/stash.py index 43fd9e89e..d6795b197 100644 --- a/src/_pytest/store.py +++ b/src/_pytest/stash.py @@ -6,59 +6,59 @@ from typing import TypeVar from typing import Union -__all__ = ["Store", "StoreKey"] +__all__ = ["Stash", "StashKey"] T = TypeVar("T") D = TypeVar("D") -class StoreKey(Generic[T]): - """StoreKey is an object used as a key to a Store. +class StashKey(Generic[T]): + """``StashKey`` is an object used as a key to a ``Stash``. - A StoreKey is associated with the type T of the value of the key. + A ``StashKey`` is associated with the type ``T`` of the value of the key. - A StoreKey is unique and cannot conflict with another key. + A ``StashKey`` is unique and cannot conflict with another key. """ __slots__ = () -class Store: - """Store is a type-safe heterogeneous mutable mapping that +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 Store) is created. + where it (the ``Stash``) is created. - Usually you will be given an object which has a ``Store``: + Usually you will be given an object which has a ``Stash``: .. code-block:: python - store: Store = some_object.store + stash: Stash = some_object.stash - If a module wants to store data in this Store, it creates StoreKeys + If a module wants to store data in this Stash, it creates ``StashKey``\s for its keys (at the module level): .. code-block:: python - some_str_key = StoreKey[str]() - some_bool_key = StoreKey[bool]() + some_str_key = StashKey[str]() + some_bool_key = StashKey[bool]() To store information: .. code-block:: python # Value type must match the key. - store[some_str_key] = "value" - store[some_bool_key] = True + 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 = store[some_str_key] + some_str = stash[some_str_key] # The static type of some_bool is bool. - some_bool = store[some_bool_key] + some_bool = stash[some_bool_key] Why use this? ------------- @@ -75,28 +75,28 @@ class Store: the object. Module External stores its data in private keys of this dict. This doesn't work well because retrieved values are untyped. - Good solution: module Internal adds a ``Store`` to the object. Module - External mints StoreKeys for its own keys. Module External stores and + Good solution: module Internal adds a ``Stash`` to the object. Module + External mints StashKeys for its own keys. Module External stores and retrieves its data using these keys. """ - __slots__ = ("_store",) + __slots__ = ("_storage",) def __init__(self) -> None: - self._store: Dict[StoreKey[Any], object] = {} + self._storage: Dict[StashKey[Any], object] = {} - def __setitem__(self, key: StoreKey[T], value: T) -> None: + def __setitem__(self, key: StashKey[T], value: T) -> None: """Set a value for key.""" - self._store[key] = value + self._storage[key] = value - def __getitem__(self, key: StoreKey[T]) -> T: + 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._store[key]) + return cast(T, self._storage[key]) - def get(self, key: StoreKey[T], default: D) -> Union[T, D]: + def get(self, key: StashKey[T], default: D) -> Union[T, D]: """Get the value for key, or return default if the key wasn't set before.""" try: @@ -104,7 +104,7 @@ class Store: except KeyError: return default - def setdefault(self, key: StoreKey[T], default: T) -> T: + 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: @@ -113,13 +113,13 @@ class Store: self[key] = default return default - def __delitem__(self, key: StoreKey[T]) -> None: + def __delitem__(self, key: StashKey[T]) -> None: """Delete the value for key. Raises ``KeyError`` if the key wasn't set before. """ - del self._store[key] + del self._storage[key] - def __contains__(self, key: StoreKey[T]) -> bool: + def __contains__(self, key: StashKey[T]) -> bool: """Return whether key was set.""" - return key in self._store + return key in self._storage diff --git a/testing/test_junitxml.py b/testing/test_junitxml.py index 5cb062932..0ded0685a 100644 --- a/testing/test_junitxml.py +++ b/testing/test_junitxml.py @@ -21,7 +21,7 @@ from _pytest.pytester import Pytester from _pytest.pytester import RunResult from _pytest.reports import BaseReport from _pytest.reports import TestReport -from _pytest.store import Store +from _pytest.stash import Stash @pytest.fixture(scope="session") @@ -951,7 +951,7 @@ def test_dont_configure_on_workers(tmp_path: Path) -> None: def __init__(self): self.pluginmanager = self self.option = self - self._store = Store() + self._store = Stash() def getini(self, name): return "pytest" diff --git a/testing/test_stash.py b/testing/test_stash.py new file mode 100644 index 000000000..f449a056c --- /dev/null +++ b/testing/test_stash.py @@ -0,0 +1,60 @@ +import pytest +from _pytest.stash import Stash +from _pytest.stash import StashKey + + +def test_stash() -> None: + stash = Stash() + + key1 = StashKey[str]() + key2 = StashKey[int]() + + # Basic functionality - single key. + assert key1 not in stash + stash[key1] = "hello" + assert key1 in stash + assert stash[key1] == "hello" + assert stash.get(key1, None) == "hello" + stash[key1] = "world" + assert stash[key1] == "world" + # Has correct type (no mypy error). + stash[key1] + "string" + + # No interaction with another key. + assert key2 not in stash + assert stash.get(key2, None) is None + with pytest.raises(KeyError): + stash[key2] + with pytest.raises(KeyError): + del stash[key2] + stash[key2] = 1 + assert stash[key2] == 1 + # Has correct type (no mypy error). + stash[key2] + 20 + del stash[key1] + with pytest.raises(KeyError): + del stash[key1] + with pytest.raises(KeyError): + stash[key1] + + # setdefault + stash[key1] = "existing" + assert stash.setdefault(key1, "default") == "existing" + assert stash[key1] == "existing" + key_setdefault = StashKey[bytes]() + assert stash.setdefault(key_setdefault, b"default") == b"default" + assert stash[key_setdefault] == b"default" + + # Can't accidentally add attributes to stash object itself. + with pytest.raises(AttributeError): + stash.foo = "nope" # type: ignore[attr-defined] + + # No interaction with anoter stash. + stash2 = Stash() + key3 = StashKey[int]() + assert key2 not in stash2 + stash2[key2] = 100 + stash2[key3] = 200 + assert stash2[key2] + stash2[key3] == 300 + assert stash[key2] == 1 + assert key3 not in stash diff --git a/testing/test_store.py b/testing/test_store.py deleted file mode 100644 index b6d4208a0..000000000 --- a/testing/test_store.py +++ /dev/null @@ -1,60 +0,0 @@ -import pytest -from _pytest.store import Store -from _pytest.store import StoreKey - - -def test_store() -> None: - store = Store() - - key1 = StoreKey[str]() - key2 = StoreKey[int]() - - # Basic functionality - single key. - assert key1 not in store - store[key1] = "hello" - assert key1 in store - assert store[key1] == "hello" - assert store.get(key1, None) == "hello" - store[key1] = "world" - assert store[key1] == "world" - # Has correct type (no mypy error). - store[key1] + "string" - - # No interaction with another key. - assert key2 not in store - assert store.get(key2, None) is None - with pytest.raises(KeyError): - store[key2] - with pytest.raises(KeyError): - del store[key2] - store[key2] = 1 - assert store[key2] == 1 - # Has correct type (no mypy error). - store[key2] + 20 - del store[key1] - with pytest.raises(KeyError): - del store[key1] - with pytest.raises(KeyError): - store[key1] - - # setdefault - store[key1] = "existing" - assert store.setdefault(key1, "default") == "existing" - assert store[key1] == "existing" - key_setdefault = StoreKey[bytes]() - assert store.setdefault(key_setdefault, b"default") == b"default" - assert store[key_setdefault] == b"default" - - # Can't accidentally add attributes to store object itself. - with pytest.raises(AttributeError): - store.foo = "nope" # type: ignore[attr-defined] - - # No interaction with anoter store. - store2 = Store() - key3 = StoreKey[int]() - assert key2 not in store2 - store2[key2] = 100 - store2[key3] = 200 - assert store2[key2] + store2[key3] == 300 - assert store[key2] == 1 - assert key3 not in store