normalizer.py 3.2 KB

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