1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
|
import copy
from typing import Any, Dict, List, Tuple
import pytest
from .lazy_fixture import LazyFixtureWrapper
from .lazy_fixture_callable import LazyFixtureCallableWrapper
def _get_fixturenames_closure_and_arg2fixturedefs(fm, metafunc, value) -> Tuple[List[str], Dict[str, Any]]:
if isinstance(value, LazyFixtureCallableWrapper):
extra_fixturenames_args, arg2fixturedefs_args = _get_fixturenames_closure_and_arg2fixturedefs(
fm,
metafunc,
value.args,
)
extra_fixturenames_kwargs, arg2fixturedefs_kwargs = _get_fixturenames_closure_and_arg2fixturedefs(
fm,
metafunc,
value.kwargs,
)
return [*extra_fixturenames_args, *extra_fixturenames_kwargs], {
**arg2fixturedefs_args,
**arg2fixturedefs_kwargs,
}
if isinstance(value, LazyFixtureWrapper):
if pytest.version_tuple >= (8, 0, 0):
fixturenames_closure, arg2fixturedefs = fm.getfixtureclosure(metafunc.definition.parent, [value.name], {})
else: # pragma: no cover
# TODO: add tox
_, fixturenames_closure, arg2fixturedefs = fm.getfixtureclosure([value.name], metafunc.definition.parent)
return fixturenames_closure, arg2fixturedefs
extra_fixturenames, arg2fixturedefs = [], {}
# we need to check exact type
if type(value) is dict: # noqa: E721
value = list(value.values())
# we need to check exact type
if type(value) in {list, tuple, set}:
for val in value:
ef, arg2f = _get_fixturenames_closure_and_arg2fixturedefs(fm, metafunc, val)
extra_fixturenames.extend(ef)
arg2fixturedefs.update(arg2f)
return extra_fixturenames, arg2fixturedefs
def normalize_metafunc_calls(metafunc, used_keys=None):
newcalls = []
for callspec in metafunc._calls:
calls = _normalize_call(callspec, metafunc, used_keys)
newcalls.extend(calls)
metafunc._calls = newcalls
def _copy_metafunc(metafunc):
copied = copy.copy(metafunc)
copied.fixturenames = copy.copy(metafunc.fixturenames)
copied._calls = []
copied._arg2fixturedefs = copy.copy(metafunc._arg2fixturedefs)
return copied
def _normalize_call(callspec, metafunc, used_keys):
fm = metafunc.config.pluginmanager.get_plugin("funcmanage")
used_keys = used_keys or set()
valtype_keys = callspec.params.keys() - used_keys
for arg in valtype_keys:
value = callspec.params[arg]
fixturenames_closure, arg2fixturedefs = _get_fixturenames_closure_and_arg2fixturedefs(fm, metafunc, value)
if fixturenames_closure and arg2fixturedefs:
extra_fixturenames = [fname for fname in fixturenames_closure if fname not in callspec.params]
newmetafunc = _copy_metafunc(metafunc)
newmetafunc.fixturenames = extra_fixturenames
newmetafunc._arg2fixturedefs.update(arg2fixturedefs)
newmetafunc._calls = [callspec]
fm.pytest_generate_tests(newmetafunc)
normalize_metafunc_calls(newmetafunc, used_keys | {arg})
return newmetafunc._calls
used_keys.add(arg)
return [callspec]
|