store: rename Store to Stash

The name "stash" is a bit more distinguishable and more evocative of the
intended usage.
This commit is contained in:
Ran Benita 2021-07-18 13:51:09 +03:00
parent 940c6e2337
commit 5470d33e82
14 changed files with 115 additions and 115 deletions

View File

@ -38,13 +38,13 @@ from _pytest.config import Config
from _pytest.main import Session from _pytest.main import Session
from _pytest.pathlib import absolutepath from _pytest.pathlib import absolutepath
from _pytest.pathlib import fnmatch_ex from _pytest.pathlib import fnmatch_ex
from _pytest.store import StoreKey from _pytest.stash import StashKey
if TYPE_CHECKING: if TYPE_CHECKING:
from _pytest.assertion import AssertionState from _pytest.assertion import AssertionState
assertstate_key = StoreKey["AssertionState"]() assertstate_key = StashKey["AssertionState"]()
# pytest caches rewritten pycs in pycache dirs # pytest caches rewritten pycs in pycache dirs

View File

@ -56,7 +56,7 @@ from _pytest.pathlib import bestrelpath
from _pytest.pathlib import import_path from _pytest.pathlib import import_path
from _pytest.pathlib import ImportMode from _pytest.pathlib import ImportMode
from _pytest.pathlib import resolve_package_path from _pytest.pathlib import resolve_package_path
from _pytest.store import Store from _pytest.stash import Stash
from _pytest.warning_types import PytestConfigWarning from _pytest.warning_types import PytestConfigWarning
if TYPE_CHECKING: if TYPE_CHECKING:
@ -933,7 +933,7 @@ class Config:
self._cleanup: List[Callable[[], None]] = [] self._cleanup: List[Callable[[], None]] = []
# A place where plugins can store information on the config for their # A place where plugins can store information on the config for their
# own use. Currently only intended for internal plugins. # own use. Currently only intended for internal plugins.
self._store = Store() self._store = Stash()
self.pluginmanager.register(self, "pytestconfig") self.pluginmanager.register(self, "pytestconfig")
self._configured = False self._configured = False
self.hook.pytest_addoption.call_historic( self.hook.pytest_addoption.call_historic(

View File

@ -8,11 +8,11 @@ import pytest
from _pytest.config import Config from _pytest.config import Config
from _pytest.config.argparsing import Parser from _pytest.config.argparsing import Parser
from _pytest.nodes import Item from _pytest.nodes import Item
from _pytest.store import StoreKey from _pytest.stash import StashKey
fault_handler_stderr_key = StoreKey[TextIO]() fault_handler_stderr_key = StashKey[TextIO]()
fault_handler_originally_enabled_key = StoreKey[bool]() fault_handler_originally_enabled_key = StashKey[bool]()
def pytest_addoption(parser: Parser) -> None: def pytest_addoption(parser: Parser) -> None:

View File

@ -62,7 +62,7 @@ from _pytest.outcomes import fail
from _pytest.outcomes import TEST_OUTCOME from _pytest.outcomes import TEST_OUTCOME
from _pytest.pathlib import absolutepath from _pytest.pathlib import absolutepath
from _pytest.pathlib import bestrelpath from _pytest.pathlib import bestrelpath
from _pytest.store import StoreKey from _pytest.stash import StashKey
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Deque from typing import Deque
@ -149,7 +149,7 @@ def get_scope_node(
# Used for storing artificial fixturedefs for direct parametrization. # 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( def add_funcarg_pseudo_fixture_def(

View File

@ -30,11 +30,11 @@ from _pytest.config import filename_arg
from _pytest.config.argparsing import Parser from _pytest.config.argparsing import Parser
from _pytest.fixtures import FixtureRequest from _pytest.fixtures import FixtureRequest
from _pytest.reports import TestReport from _pytest.reports import TestReport
from _pytest.store import StoreKey from _pytest.stash import StashKey
from _pytest.terminal import TerminalReporter from _pytest.terminal import TerminalReporter
xml_key = StoreKey["LogXML"]() xml_key = StashKey["LogXML"]()
def bin_xml_escape(arg: object) -> str: def bin_xml_escape(arg: object) -> str:

View File

@ -31,15 +31,15 @@ from _pytest.deprecated import check_ispytest
from _pytest.fixtures import fixture from _pytest.fixtures import fixture
from _pytest.fixtures import FixtureRequest from _pytest.fixtures import FixtureRequest
from _pytest.main import Session from _pytest.main import Session
from _pytest.store import StoreKey from _pytest.stash import StashKey
from _pytest.terminal import TerminalReporter from _pytest.terminal import TerminalReporter
DEFAULT_LOG_FORMAT = "%(levelname)-8s %(name)s:%(filename)s:%(lineno)d %(message)s" DEFAULT_LOG_FORMAT = "%(levelname)-8s %(name)s:%(filename)s:%(lineno)d %(message)s"
DEFAULT_LOG_DATE_FORMAT = "%H:%M:%S" DEFAULT_LOG_DATE_FORMAT = "%H:%M:%S"
_ANSI_ESCAPE_SEQ = re.compile(r"\x1b\[[\d;]+m") _ANSI_ESCAPE_SEQ = re.compile(r"\x1b\[[\d;]+m")
caplog_handler_key = StoreKey["LogCaptureHandler"]() caplog_handler_key = StashKey["LogCaptureHandler"]()
caplog_records_key = StoreKey[Dict[str, List[logging.LogRecord]]]() caplog_records_key = StashKey[Dict[str, List[logging.LogRecord]]]()
def _remove_ansi_escape_sequences(text: str) -> str: def _remove_ansi_escape_sequences(text: str) -> str:

View File

@ -25,7 +25,7 @@ from _pytest.config import UsageError
from _pytest.config.argparsing import Parser from _pytest.config.argparsing import Parser
from _pytest.deprecated import MINUS_K_COLON from _pytest.deprecated import MINUS_K_COLON
from _pytest.deprecated import MINUS_K_DASH from _pytest.deprecated import MINUS_K_DASH
from _pytest.store import StoreKey from _pytest.stash import StashKey
if TYPE_CHECKING: if TYPE_CHECKING:
from _pytest.nodes import Item 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( def param(

View File

@ -34,7 +34,7 @@ from _pytest.mark.structures import NodeKeywords
from _pytest.outcomes import fail from _pytest.outcomes import fail
from _pytest.pathlib import absolutepath from _pytest.pathlib import absolutepath
from _pytest.pathlib import commonpath from _pytest.pathlib import commonpath
from _pytest.store import Store from _pytest.stash import Stash
from _pytest.warning_types import PytestWarning from _pytest.warning_types import PytestWarning
if TYPE_CHECKING: if TYPE_CHECKING:
@ -220,7 +220,7 @@ class Node(metaclass=NodeMeta):
# A place where plugins can store information on the node for their # A place where plugins can store information on the node for their
# own use. Currently only intended for internal plugins. # own use. Currently only intended for internal plugins.
self._store = Store() self._store = Stash()
@property @property
def fspath(self) -> LEGACY_PATH: def fspath(self) -> LEGACY_PATH:

View File

@ -8,11 +8,11 @@ import pytest
from _pytest.config import Config from _pytest.config import Config
from _pytest.config import create_terminal_writer from _pytest.config import create_terminal_writer
from _pytest.config.argparsing import Parser from _pytest.config.argparsing import Parser
from _pytest.store import StoreKey from _pytest.stash import StashKey
from _pytest.terminal import TerminalReporter from _pytest.terminal import TerminalReporter
pastebinfile_key = StoreKey[IO[bytes]]() pastebinfile_key = StashKey[IO[bytes]]()
def pytest_addoption(parser: Parser) -> None: def pytest_addoption(parser: Parser) -> None:

View File

@ -21,7 +21,7 @@ from _pytest.outcomes import skip
from _pytest.outcomes import xfail from _pytest.outcomes import xfail
from _pytest.reports import BaseReport from _pytest.reports import BaseReport
from _pytest.runner import CallInfo from _pytest.runner import CallInfo
from _pytest.store import StoreKey from _pytest.stash import StashKey
def pytest_addoption(parser: Parser) -> None: 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. # 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) @hookimpl(tryfirst=True)

View File

@ -6,59 +6,59 @@ from typing import TypeVar
from typing import Union from typing import Union
__all__ = ["Store", "StoreKey"] __all__ = ["Stash", "StashKey"]
T = TypeVar("T") T = TypeVar("T")
D = TypeVar("D") D = TypeVar("D")
class StoreKey(Generic[T]): class StashKey(Generic[T]):
"""StoreKey is an object used as a key to a Store. """``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__ = () __slots__ = ()
class Store: class Stash:
"""Store is a type-safe heterogeneous mutable mapping that r"""``Stash`` is a type-safe heterogeneous mutable mapping that
allows keys and value types to be defined separately from 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 .. 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): for its keys (at the module level):
.. code-block:: python .. code-block:: python
some_str_key = StoreKey[str]() some_str_key = StashKey[str]()
some_bool_key = StoreKey[bool]() some_bool_key = StashKey[bool]()
To store information: To store information:
.. code-block:: python .. code-block:: python
# Value type must match the key. # Value type must match the key.
store[some_str_key] = "value" stash[some_str_key] = "value"
store[some_bool_key] = True stash[some_bool_key] = True
To retrieve the information: To retrieve the information:
.. code-block:: python .. code-block:: python
# The static type of some_str is str. # 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. # The static type of some_bool is bool.
some_bool = store[some_bool_key] some_bool = stash[some_bool_key]
Why use this? Why use this?
------------- -------------
@ -75,28 +75,28 @@ class Store:
the object. Module External stores its data in private keys of this dict. the object. Module External stores its data in private keys of this dict.
This doesn't work well because retrieved values are untyped. This doesn't work well because retrieved values are untyped.
Good solution: module Internal adds a ``Store`` to the object. Module Good solution: module Internal adds a ``Stash`` to the object. Module
External mints StoreKeys for its own keys. Module External stores and External mints StashKeys for its own keys. Module External stores and
retrieves its data using these keys. retrieves its data using these keys.
""" """
__slots__ = ("_store",) __slots__ = ("_storage",)
def __init__(self) -> None: 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.""" """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. """Get the value for key.
Raises ``KeyError`` if the key wasn't set before. 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 """Get the value for key, or return default if the key wasn't set
before.""" before."""
try: try:
@ -104,7 +104,7 @@ class Store:
except KeyError: except KeyError:
return default 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 """Return the value of key if already set, otherwise set the value
of key to default and return default.""" of key to default and return default."""
try: try:
@ -113,13 +113,13 @@ class Store:
self[key] = default self[key] = default
return default return default
def __delitem__(self, key: StoreKey[T]) -> None: def __delitem__(self, key: StashKey[T]) -> None:
"""Delete the value for key. """Delete the value for key.
Raises ``KeyError`` if the key wasn't set before. 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 whether key was set."""
return key in self._store return key in self._storage

View File

@ -21,7 +21,7 @@ from _pytest.pytester import Pytester
from _pytest.pytester import RunResult from _pytest.pytester import RunResult
from _pytest.reports import BaseReport from _pytest.reports import BaseReport
from _pytest.reports import TestReport from _pytest.reports import TestReport
from _pytest.store import Store from _pytest.stash import Stash
@pytest.fixture(scope="session") @pytest.fixture(scope="session")
@ -951,7 +951,7 @@ def test_dont_configure_on_workers(tmp_path: Path) -> None:
def __init__(self): def __init__(self):
self.pluginmanager = self self.pluginmanager = self
self.option = self self.option = self
self._store = Store() self._store = Stash()
def getini(self, name): def getini(self, name):
return "pytest" return "pytest"

60
testing/test_stash.py Normal file
View File

@ -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

View File

@ -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