Merge pull request #6865 from bluetech/more-config-store

Convert a couple of places to use config store
This commit is contained in:
Ran Benita 2020-03-06 15:49:01 +02:00 committed by GitHub
commit 1df593f978
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 47 additions and 13 deletions

View File

@ -7,6 +7,7 @@ from typing import Optional
from _pytest.assertion import rewrite from _pytest.assertion import rewrite
from _pytest.assertion import truncate from _pytest.assertion import truncate
from _pytest.assertion import util from _pytest.assertion import util
from _pytest.assertion.rewrite import assertstate_key
from _pytest.compat import TYPE_CHECKING from _pytest.compat import TYPE_CHECKING
from _pytest.config import hookimpl from _pytest.config import hookimpl
@ -82,13 +83,13 @@ class AssertionState:
def install_importhook(config): def install_importhook(config):
"""Try to install the rewrite hook, raise SystemError if it fails.""" """Try to install the rewrite hook, raise SystemError if it fails."""
config._assertstate = AssertionState(config, "rewrite") config._store[assertstate_key] = AssertionState(config, "rewrite")
config._assertstate.hook = hook = rewrite.AssertionRewritingHook(config) config._store[assertstate_key].hook = hook = rewrite.AssertionRewritingHook(config)
sys.meta_path.insert(0, hook) sys.meta_path.insert(0, hook)
config._assertstate.trace("installed rewrite import hook") config._store[assertstate_key].trace("installed rewrite import hook")
def undo(): def undo():
hook = config._assertstate.hook hook = config._store[assertstate_key].hook
if hook is not None and hook in sys.meta_path: if hook is not None and hook in sys.meta_path:
sys.meta_path.remove(hook) sys.meta_path.remove(hook)
@ -100,7 +101,7 @@ def pytest_collection(session: "Session") -> None:
# this hook is only called when test modules are collected # this hook is only called when test modules are collected
# so for example not in the master process of pytest-xdist # so for example not in the master process of pytest-xdist
# (which does not collect test modules) # (which does not collect test modules)
assertstate = getattr(session.config, "_assertstate", None) assertstate = session.config._store.get(assertstate_key, None)
if assertstate: if assertstate:
if assertstate.hook is not None: if assertstate.hook is not None:
assertstate.hook.set_session(session) assertstate.hook.set_session(session)
@ -163,7 +164,7 @@ def pytest_runtest_protocol(item):
def pytest_sessionfinish(session): def pytest_sessionfinish(session):
assertstate = getattr(session.config, "_assertstate", None) assertstate = session.config._store.get(assertstate_key, None)
if assertstate: if assertstate:
if assertstate.hook is not None: if assertstate.hook is not None:
assertstate.hook.set_session(None) assertstate.hook.set_session(None)

View File

@ -26,9 +26,18 @@ from _pytest.assertion.util import ( # noqa: F401
format_explanation as _format_explanation, format_explanation as _format_explanation,
) )
from _pytest.compat import fspath from _pytest.compat import fspath
from _pytest.compat import TYPE_CHECKING
from _pytest.pathlib import fnmatch_ex from _pytest.pathlib import fnmatch_ex
from _pytest.pathlib import Path from _pytest.pathlib import Path
from _pytest.pathlib import PurePath from _pytest.pathlib import PurePath
from _pytest.store import StoreKey
if TYPE_CHECKING:
from _pytest.assertion import AssertionState # noqa: F401
assertstate_key = StoreKey["AssertionState"]()
# pytest caches rewritten pycs in pycache dirs # pytest caches rewritten pycs in pycache dirs
PYTEST_TAG = "{}-pytest-{}".format(sys.implementation.cache_tag, version) PYTEST_TAG = "{}-pytest-{}".format(sys.implementation.cache_tag, version)
@ -65,7 +74,7 @@ class AssertionRewritingHook(importlib.abc.MetaPathFinder, importlib.abc.Loader)
def find_spec(self, name, path=None, target=None): def find_spec(self, name, path=None, target=None):
if self._writing_pyc: if self._writing_pyc:
return None return None
state = self.config._assertstate state = self.config._store[assertstate_key]
if self._early_rewrite_bailout(name, state): if self._early_rewrite_bailout(name, state):
return None return None
state.trace("find_module called for: %s" % name) state.trace("find_module called for: %s" % name)
@ -104,7 +113,7 @@ class AssertionRewritingHook(importlib.abc.MetaPathFinder, importlib.abc.Loader)
def exec_module(self, module): def exec_module(self, module):
fn = Path(module.__spec__.origin) fn = Path(module.__spec__.origin)
state = self.config._assertstate state = self.config._store[assertstate_key]
self._rewritten_names.add(module.__name__) self._rewritten_names.add(module.__name__)

View File

@ -2,21 +2,28 @@ import os
import platform import platform
import sys import sys
import traceback import traceback
from typing import Any
from typing import Dict
from ..outcomes import fail from ..outcomes import fail
from ..outcomes import TEST_OUTCOME from ..outcomes import TEST_OUTCOME
from _pytest.config import Config
from _pytest.store import StoreKey
def cached_eval(config, expr, d): evalcache_key = StoreKey[Dict[str, Any]]()
if not hasattr(config, "_evalcache"):
config._evalcache = {}
def cached_eval(config: Config, expr: str, d: Dict[str, object]) -> Any:
default = {} # type: Dict[str, object]
evalcache = config._store.setdefault(evalcache_key, default)
try: try:
return config._evalcache[expr] return evalcache[expr]
except KeyError: except KeyError:
import _pytest._code import _pytest._code
exprcode = _pytest._code.compile(expr, mode="eval") exprcode = _pytest._code.compile(expr, mode="eval")
config._evalcache[expr] = x = eval(exprcode, d) evalcache[expr] = x = eval(exprcode, d)
return x return x

View File

@ -104,6 +104,15 @@ class Store:
except KeyError: except KeyError:
return default return default
def setdefault(self, key: StoreKey[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: StoreKey[T]) -> None: def __delitem__(self, key: StoreKey[T]) -> None:
"""Delete the value for key. """Delete the value for key.

View File

@ -37,6 +37,14 @@ def test_store() -> None:
with pytest.raises(KeyError): with pytest.raises(KeyError):
store[key1] 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. # Can't accidentally add attributes to store object itself.
with pytest.raises(AttributeError): with pytest.raises(AttributeError):
store.foo = "nope" # type: ignore[attr-defined] # noqa: F821 store.foo = "nope" # type: ignore[attr-defined] # noqa: F821