014ReviewseniorPython / pytest真实来源改编 pytest
pytest:缓存 skipif/xfail 字符串条件的求值
审查一个 pytest 收集性能优化 PR:作者为 skipif/xfail 的字符串条件引入求值缓存,避免同一条件被反复编译和求值。
@@ -8,6 +8,30 @@ from typing import Dict from ..outcomes import fail from ..outcomes import TEST_OUTCOME+from _pytest.config import Config+from _pytest.store import StoreKey+++evalcache_key = StoreKey[Dict[str, Any]]()+++def cached_eval(config: Config, expr: str, d: Dict[str, object]) -> Any:+ """Evaluate a condition string at most once per test session.++ Large suites attach the same skipif/xfail condition string to hundreds+ of tests; compiling and evaluating it again for every item is wasted+ work during collection. The result for each expression is stored on the+ session config and reused on later hits.+ """+ default = {} # type: Dict[str, object]+ evalcache = config._store.setdefault(evalcache_key, default)+ try:+ return evalcache[expr]+ except KeyError:+ import _pytest._code++ exprcode = _pytest._code.compile(expr, mode="eval")+ evalcache[expr] = x = eval(exprcode, d)+ return x class MarkEvaluator:@@ -70,10 +94,7 @@ class MarkEvaluator: for expr in args: self.expr = expr if isinstance(expr, str): d = self._getglobals()- import _pytest._code-- exprcode = _pytest._code.compile(expr, mode="eval")- result = eval(exprcode, d)+ result = cached_eval(self.item.config, expr, d) else: if "reason" not in mark.kwargs: # XXX better be checked at collection time@@ -117,6 +117,27 @@ class TestEvaluator: assert ev.istrue() expl = ev.getexplanation() assert expl == "condition: config._hackxyz" + def test_skipif_string_condition_cached(self, testdir):+ # Two tests carrying the same condition string: the second+ # evaluation is served from the cache and both are still skipped.+ testdir.makepyfile(+ """+ import pytest++ skip_all = True++ @pytest.mark.skipif("skip_all")+ def test_one():+ assert False++ @pytest.mark.skipif("skip_all")+ def test_two():+ assert False+ """+ )+ result = testdir.runpytest()+ result.assert_outcomes(skipped=2)+ class TestXFail: @pytest.mark.parametrize("strict", [True, False])