fixtures.py 76 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017
  1. # mypy: allow-untyped-defs
  2. from __future__ import annotations
  3. import abc
  4. from collections import defaultdict
  5. from collections import deque
  6. from collections import OrderedDict
  7. from collections.abc import Callable
  8. from collections.abc import Generator
  9. from collections.abc import Iterable
  10. from collections.abc import Iterator
  11. from collections.abc import Mapping
  12. from collections.abc import MutableMapping
  13. from collections.abc import Sequence
  14. from collections.abc import Set as AbstractSet
  15. import dataclasses
  16. import functools
  17. import inspect
  18. import os
  19. from pathlib import Path
  20. import sys
  21. import types
  22. from typing import Any
  23. from typing import cast
  24. from typing import Final
  25. from typing import final
  26. from typing import Generic
  27. from typing import NoReturn
  28. from typing import Optional
  29. from typing import overload
  30. from typing import TYPE_CHECKING
  31. from typing import TypeVar
  32. from typing import Union
  33. import warnings
  34. import _pytest
  35. from _pytest import nodes
  36. from _pytest._code import getfslineno
  37. from _pytest._code import Source
  38. from _pytest._code.code import FormattedExcinfo
  39. from _pytest._code.code import TerminalRepr
  40. from _pytest._io import TerminalWriter
  41. from _pytest.compat import assert_never
  42. from _pytest.compat import get_real_func
  43. from _pytest.compat import getfuncargnames
  44. from _pytest.compat import getimfunc
  45. from _pytest.compat import getlocation
  46. from _pytest.compat import NOTSET
  47. from _pytest.compat import NotSetType
  48. from _pytest.compat import safe_getattr
  49. from _pytest.compat import safe_isclass
  50. from _pytest.compat import signature
  51. from _pytest.config import _PluggyPlugin
  52. from _pytest.config import Config
  53. from _pytest.config import ExitCode
  54. from _pytest.config.argparsing import Parser
  55. from _pytest.deprecated import check_ispytest
  56. from _pytest.deprecated import MARKED_FIXTURE
  57. from _pytest.deprecated import YIELD_FIXTURE
  58. from _pytest.main import Session
  59. from _pytest.mark import Mark
  60. from _pytest.mark import ParameterSet
  61. from _pytest.mark.structures import MarkDecorator
  62. from _pytest.outcomes import fail
  63. from _pytest.outcomes import skip
  64. from _pytest.outcomes import TEST_OUTCOME
  65. from _pytest.pathlib import absolutepath
  66. from _pytest.pathlib import bestrelpath
  67. from _pytest.scope import _ScopeName
  68. from _pytest.scope import HIGH_SCOPES
  69. from _pytest.scope import Scope
  70. from _pytest.warning_types import PytestRemovedIn9Warning
  71. from _pytest.warning_types import PytestWarning
  72. if sys.version_info < (3, 11):
  73. from exceptiongroup import BaseExceptionGroup
  74. if TYPE_CHECKING:
  75. from _pytest.python import CallSpec2
  76. from _pytest.python import Function
  77. from _pytest.python import Metafunc
  78. # The value of the fixture -- return/yield of the fixture function (type variable).
  79. FixtureValue = TypeVar("FixtureValue")
  80. # The type of the fixture function (type variable).
  81. FixtureFunction = TypeVar("FixtureFunction", bound=Callable[..., object])
  82. # The type of a fixture function (type alias generic in fixture value).
  83. _FixtureFunc = Union[
  84. Callable[..., FixtureValue], Callable[..., Generator[FixtureValue]]
  85. ]
  86. # The type of FixtureDef.cached_result (type alias generic in fixture value).
  87. _FixtureCachedResult = Union[
  88. tuple[
  89. # The result.
  90. FixtureValue,
  91. # Cache key.
  92. object,
  93. None,
  94. ],
  95. tuple[
  96. None,
  97. # Cache key.
  98. object,
  99. # The exception and the original traceback.
  100. tuple[BaseException, Optional[types.TracebackType]],
  101. ],
  102. ]
  103. @dataclasses.dataclass(frozen=True)
  104. class PseudoFixtureDef(Generic[FixtureValue]):
  105. cached_result: _FixtureCachedResult[FixtureValue]
  106. _scope: Scope
  107. def pytest_sessionstart(session: Session) -> None:
  108. session._fixturemanager = FixtureManager(session)
  109. def get_scope_package(
  110. node: nodes.Item,
  111. fixturedef: FixtureDef[object],
  112. ) -> nodes.Node | None:
  113. from _pytest.python import Package
  114. for parent in node.iter_parents():
  115. if isinstance(parent, Package) and parent.nodeid == fixturedef.baseid:
  116. return parent
  117. return node.session
  118. def get_scope_node(node: nodes.Node, scope: Scope) -> nodes.Node | None:
  119. """Get the closest parent node (including self) which matches the given
  120. scope.
  121. If there is no parent node for the scope (e.g. asking for class scope on a
  122. Module, or on a Function when not defined in a class), returns None.
  123. """
  124. import _pytest.python
  125. if scope is Scope.Function:
  126. # Type ignored because this is actually safe, see:
  127. # https://github.com/python/mypy/issues/4717
  128. return node.getparent(nodes.Item) # type: ignore[type-abstract]
  129. elif scope is Scope.Class:
  130. return node.getparent(_pytest.python.Class)
  131. elif scope is Scope.Module:
  132. return node.getparent(_pytest.python.Module)
  133. elif scope is Scope.Package:
  134. return node.getparent(_pytest.python.Package)
  135. elif scope is Scope.Session:
  136. return node.getparent(_pytest.main.Session)
  137. else:
  138. assert_never(scope)
  139. # TODO: Try to use FixtureFunctionDefinition instead of the marker
  140. def getfixturemarker(obj: object) -> FixtureFunctionMarker | None:
  141. """Return fixturemarker or None if it doesn't exist"""
  142. if isinstance(obj, FixtureFunctionDefinition):
  143. return obj._fixture_function_marker
  144. return None
  145. # Algorithm for sorting on a per-parametrized resource setup basis.
  146. # It is called for Session scope first and performs sorting
  147. # down to the lower scopes such as to minimize number of "high scope"
  148. # setups and teardowns.
  149. @dataclasses.dataclass(frozen=True)
  150. class ParamArgKey:
  151. """A key for a high-scoped parameter used by an item.
  152. For use as a hashable key in `reorder_items`. The combination of fields
  153. is meant to uniquely identify a particular "instance" of a param,
  154. potentially shared by multiple items in a scope.
  155. """
  156. #: The param name.
  157. argname: str
  158. param_index: int
  159. #: For scopes Package, Module, Class, the path to the file (directory in
  160. #: Package's case) of the package/module/class where the item is defined.
  161. scoped_item_path: Path | None
  162. #: For Class scope, the class where the item is defined.
  163. item_cls: type | None
  164. _V = TypeVar("_V")
  165. OrderedSet = dict[_V, None]
  166. def get_param_argkeys(item: nodes.Item, scope: Scope) -> Iterator[ParamArgKey]:
  167. """Return all ParamArgKeys for item matching the specified high scope."""
  168. assert scope is not Scope.Function
  169. try:
  170. callspec: CallSpec2 = item.callspec # type: ignore[attr-defined]
  171. except AttributeError:
  172. return
  173. item_cls = None
  174. if scope is Scope.Session:
  175. scoped_item_path = None
  176. elif scope is Scope.Package:
  177. # Package key = module's directory.
  178. scoped_item_path = item.path.parent
  179. elif scope is Scope.Module:
  180. scoped_item_path = item.path
  181. elif scope is Scope.Class:
  182. scoped_item_path = item.path
  183. item_cls = item.cls # type: ignore[attr-defined]
  184. else:
  185. assert_never(scope)
  186. for argname in callspec.indices:
  187. if callspec._arg2scope[argname] != scope:
  188. continue
  189. param_index = callspec.indices[argname]
  190. yield ParamArgKey(argname, param_index, scoped_item_path, item_cls)
  191. def reorder_items(items: Sequence[nodes.Item]) -> list[nodes.Item]:
  192. argkeys_by_item: dict[Scope, dict[nodes.Item, OrderedSet[ParamArgKey]]] = {}
  193. items_by_argkey: dict[Scope, dict[ParamArgKey, OrderedDict[nodes.Item, None]]] = {}
  194. for scope in HIGH_SCOPES:
  195. scoped_argkeys_by_item = argkeys_by_item[scope] = {}
  196. scoped_items_by_argkey = items_by_argkey[scope] = defaultdict(OrderedDict)
  197. for item in items:
  198. argkeys = dict.fromkeys(get_param_argkeys(item, scope))
  199. if argkeys:
  200. scoped_argkeys_by_item[item] = argkeys
  201. for argkey in argkeys:
  202. scoped_items_by_argkey[argkey][item] = None
  203. items_set = dict.fromkeys(items)
  204. return list(
  205. reorder_items_atscope(
  206. items_set, argkeys_by_item, items_by_argkey, Scope.Session
  207. )
  208. )
  209. def reorder_items_atscope(
  210. items: OrderedSet[nodes.Item],
  211. argkeys_by_item: Mapping[Scope, Mapping[nodes.Item, OrderedSet[ParamArgKey]]],
  212. items_by_argkey: Mapping[
  213. Scope, Mapping[ParamArgKey, OrderedDict[nodes.Item, None]]
  214. ],
  215. scope: Scope,
  216. ) -> OrderedSet[nodes.Item]:
  217. if scope is Scope.Function or len(items) < 3:
  218. return items
  219. scoped_items_by_argkey = items_by_argkey[scope]
  220. scoped_argkeys_by_item = argkeys_by_item[scope]
  221. ignore: set[ParamArgKey] = set()
  222. items_deque = deque(items)
  223. items_done: OrderedSet[nodes.Item] = {}
  224. while items_deque:
  225. no_argkey_items: OrderedSet[nodes.Item] = {}
  226. slicing_argkey = None
  227. while items_deque:
  228. item = items_deque.popleft()
  229. if item in items_done or item in no_argkey_items:
  230. continue
  231. argkeys = dict.fromkeys(
  232. k for k in scoped_argkeys_by_item.get(item, ()) if k not in ignore
  233. )
  234. if not argkeys:
  235. no_argkey_items[item] = None
  236. else:
  237. slicing_argkey, _ = argkeys.popitem()
  238. # We don't have to remove relevant items from later in the
  239. # deque because they'll just be ignored.
  240. matching_items = [
  241. i for i in scoped_items_by_argkey[slicing_argkey] if i in items
  242. ]
  243. for i in reversed(matching_items):
  244. items_deque.appendleft(i)
  245. # Fix items_by_argkey order.
  246. for other_scope in HIGH_SCOPES:
  247. other_scoped_items_by_argkey = items_by_argkey[other_scope]
  248. for argkey in argkeys_by_item[other_scope].get(i, ()):
  249. argkey_dict = other_scoped_items_by_argkey[argkey]
  250. if not hasattr(sys, "pypy_version_info"):
  251. argkey_dict[i] = None
  252. argkey_dict.move_to_end(i, last=False)
  253. else:
  254. # Work around a bug in PyPy:
  255. # https://github.com/pypy/pypy/issues/5257
  256. # https://github.com/pytest-dev/pytest/issues/13312
  257. bkp = argkey_dict.copy()
  258. argkey_dict.clear()
  259. argkey_dict[i] = None
  260. argkey_dict.update(bkp)
  261. break
  262. if no_argkey_items:
  263. reordered_no_argkey_items = reorder_items_atscope(
  264. no_argkey_items, argkeys_by_item, items_by_argkey, scope.next_lower()
  265. )
  266. items_done.update(reordered_no_argkey_items)
  267. if slicing_argkey is not None:
  268. ignore.add(slicing_argkey)
  269. return items_done
  270. @dataclasses.dataclass(frozen=True)
  271. class FuncFixtureInfo:
  272. """Fixture-related information for a fixture-requesting item (e.g. test
  273. function).
  274. This is used to examine the fixtures which an item requests statically
  275. (known during collection). This includes autouse fixtures, fixtures
  276. requested by the `usefixtures` marker, fixtures requested in the function
  277. parameters, and the transitive closure of these.
  278. An item may also request fixtures dynamically (using `request.getfixturevalue`);
  279. these are not reflected here.
  280. """
  281. __slots__ = ("argnames", "initialnames", "name2fixturedefs", "names_closure")
  282. # Fixture names that the item requests directly by function parameters.
  283. argnames: tuple[str, ...]
  284. # Fixture names that the item immediately requires. These include
  285. # argnames + fixture names specified via usefixtures and via autouse=True in
  286. # fixture definitions.
  287. initialnames: tuple[str, ...]
  288. # The transitive closure of the fixture names that the item requires.
  289. # Note: can't include dynamic dependencies (`request.getfixturevalue` calls).
  290. names_closure: list[str]
  291. # A map from a fixture name in the transitive closure to the FixtureDefs
  292. # matching the name which are applicable to this function.
  293. # There may be multiple overriding fixtures with the same name. The
  294. # sequence is ordered from furthest to closes to the function.
  295. name2fixturedefs: dict[str, Sequence[FixtureDef[Any]]]
  296. def prune_dependency_tree(self) -> None:
  297. """Recompute names_closure from initialnames and name2fixturedefs.
  298. Can only reduce names_closure, which means that the new closure will
  299. always be a subset of the old one. The order is preserved.
  300. This method is needed because direct parametrization may shadow some
  301. of the fixtures that were included in the originally built dependency
  302. tree. In this way the dependency tree can get pruned, and the closure
  303. of argnames may get reduced.
  304. """
  305. closure: set[str] = set()
  306. working_set = set(self.initialnames)
  307. while working_set:
  308. argname = working_set.pop()
  309. # Argname may be something not included in the original names_closure,
  310. # in which case we ignore it. This currently happens with pseudo
  311. # FixtureDefs which wrap 'get_direct_param_fixture_func(request)'.
  312. # So they introduce the new dependency 'request' which might have
  313. # been missing in the original tree (closure).
  314. if argname not in closure and argname in self.names_closure:
  315. closure.add(argname)
  316. if argname in self.name2fixturedefs:
  317. working_set.update(self.name2fixturedefs[argname][-1].argnames)
  318. self.names_closure[:] = sorted(closure, key=self.names_closure.index)
  319. class FixtureRequest(abc.ABC):
  320. """The type of the ``request`` fixture.
  321. A request object gives access to the requesting test context and has a
  322. ``param`` attribute in case the fixture is parametrized.
  323. """
  324. def __init__(
  325. self,
  326. pyfuncitem: Function,
  327. fixturename: str | None,
  328. arg2fixturedefs: dict[str, Sequence[FixtureDef[Any]]],
  329. fixture_defs: dict[str, FixtureDef[Any]],
  330. *,
  331. _ispytest: bool = False,
  332. ) -> None:
  333. check_ispytest(_ispytest)
  334. #: Fixture for which this request is being performed.
  335. self.fixturename: Final = fixturename
  336. self._pyfuncitem: Final = pyfuncitem
  337. # The FixtureDefs for each fixture name requested by this item.
  338. # Starts from the statically-known fixturedefs resolved during
  339. # collection. Dynamically requested fixtures (using
  340. # `request.getfixturevalue("foo")`) are added dynamically.
  341. self._arg2fixturedefs: Final = arg2fixturedefs
  342. # The evaluated argnames so far, mapping to the FixtureDef they resolved
  343. # to.
  344. self._fixture_defs: Final = fixture_defs
  345. # Notes on the type of `param`:
  346. # -`request.param` is only defined in parametrized fixtures, and will raise
  347. # AttributeError otherwise. Python typing has no notion of "undefined", so
  348. # this cannot be reflected in the type.
  349. # - Technically `param` is only (possibly) defined on SubRequest, not
  350. # FixtureRequest, but the typing of that is still in flux so this cheats.
  351. # - In the future we might consider using a generic for the param type, but
  352. # for now just using Any.
  353. self.param: Any
  354. @property
  355. def _fixturemanager(self) -> FixtureManager:
  356. return self._pyfuncitem.session._fixturemanager
  357. @property
  358. @abc.abstractmethod
  359. def _scope(self) -> Scope:
  360. raise NotImplementedError()
  361. @property
  362. def scope(self) -> _ScopeName:
  363. """Scope string, one of "function", "class", "module", "package", "session"."""
  364. return self._scope.value
  365. @abc.abstractmethod
  366. def _check_scope(
  367. self,
  368. requested_fixturedef: FixtureDef[object] | PseudoFixtureDef[object],
  369. requested_scope: Scope,
  370. ) -> None:
  371. raise NotImplementedError()
  372. @property
  373. def fixturenames(self) -> list[str]:
  374. """Names of all active fixtures in this request."""
  375. result = list(self._pyfuncitem.fixturenames)
  376. result.extend(set(self._fixture_defs).difference(result))
  377. return result
  378. @property
  379. @abc.abstractmethod
  380. def node(self):
  381. """Underlying collection node (depends on current request scope)."""
  382. raise NotImplementedError()
  383. @property
  384. def config(self) -> Config:
  385. """The pytest config object associated with this request."""
  386. return self._pyfuncitem.config
  387. @property
  388. def function(self):
  389. """Test function object if the request has a per-function scope."""
  390. if self.scope != "function":
  391. raise AttributeError(
  392. f"function not available in {self.scope}-scoped context"
  393. )
  394. return self._pyfuncitem.obj
  395. @property
  396. def cls(self):
  397. """Class (can be None) where the test function was collected."""
  398. if self.scope not in ("class", "function"):
  399. raise AttributeError(f"cls not available in {self.scope}-scoped context")
  400. clscol = self._pyfuncitem.getparent(_pytest.python.Class)
  401. if clscol:
  402. return clscol.obj
  403. @property
  404. def instance(self):
  405. """Instance (can be None) on which test function was collected."""
  406. if self.scope != "function":
  407. return None
  408. return getattr(self._pyfuncitem, "instance", None)
  409. @property
  410. def module(self):
  411. """Python module object where the test function was collected."""
  412. if self.scope not in ("function", "class", "module"):
  413. raise AttributeError(f"module not available in {self.scope}-scoped context")
  414. mod = self._pyfuncitem.getparent(_pytest.python.Module)
  415. assert mod is not None
  416. return mod.obj
  417. @property
  418. def path(self) -> Path:
  419. """Path where the test function was collected."""
  420. if self.scope not in ("function", "class", "module", "package"):
  421. raise AttributeError(f"path not available in {self.scope}-scoped context")
  422. return self._pyfuncitem.path
  423. @property
  424. def keywords(self) -> MutableMapping[str, Any]:
  425. """Keywords/markers dictionary for the underlying node."""
  426. node: nodes.Node = self.node
  427. return node.keywords
  428. @property
  429. def session(self) -> Session:
  430. """Pytest session object."""
  431. return self._pyfuncitem.session
  432. @abc.abstractmethod
  433. def addfinalizer(self, finalizer: Callable[[], object]) -> None:
  434. """Add finalizer/teardown function to be called without arguments after
  435. the last test within the requesting test context finished execution."""
  436. raise NotImplementedError()
  437. def applymarker(self, marker: str | MarkDecorator) -> None:
  438. """Apply a marker to a single test function invocation.
  439. This method is useful if you don't want to have a keyword/marker
  440. on all function invocations.
  441. :param marker:
  442. An object created by a call to ``pytest.mark.NAME(...)``.
  443. """
  444. self.node.add_marker(marker)
  445. def raiseerror(self, msg: str | None) -> NoReturn:
  446. """Raise a FixtureLookupError exception.
  447. :param msg:
  448. An optional custom error message.
  449. """
  450. raise FixtureLookupError(None, self, msg)
  451. def getfixturevalue(self, argname: str) -> Any:
  452. """Dynamically run a named fixture function.
  453. Declaring fixtures via function argument is recommended where possible.
  454. But if you can only decide whether to use another fixture at test
  455. setup time, you may use this function to retrieve it inside a fixture
  456. or test function body.
  457. This method can be used during the test setup phase or the test run
  458. phase, but during the test teardown phase a fixture's value may not
  459. be available.
  460. :param argname:
  461. The fixture name.
  462. :raises pytest.FixtureLookupError:
  463. If the given fixture could not be found.
  464. """
  465. # Note that in addition to the use case described in the docstring,
  466. # getfixturevalue() is also called by pytest itself during item and fixture
  467. # setup to evaluate the fixtures that are requested statically
  468. # (using function parameters, autouse, etc).
  469. fixturedef = self._get_active_fixturedef(argname)
  470. assert fixturedef.cached_result is not None, (
  471. f'The fixture value for "{argname}" is not available. '
  472. "This can happen when the fixture has already been torn down."
  473. )
  474. return fixturedef.cached_result[0]
  475. def _iter_chain(self) -> Iterator[SubRequest]:
  476. """Yield all SubRequests in the chain, from self up.
  477. Note: does *not* yield the TopRequest.
  478. """
  479. current = self
  480. while isinstance(current, SubRequest):
  481. yield current
  482. current = current._parent_request
  483. def _get_active_fixturedef(
  484. self, argname: str
  485. ) -> FixtureDef[object] | PseudoFixtureDef[object]:
  486. if argname == "request":
  487. cached_result = (self, [0], None)
  488. return PseudoFixtureDef(cached_result, Scope.Function)
  489. # If we already finished computing a fixture by this name in this item,
  490. # return it.
  491. fixturedef = self._fixture_defs.get(argname)
  492. if fixturedef is not None:
  493. self._check_scope(fixturedef, fixturedef._scope)
  494. return fixturedef
  495. # Find the appropriate fixturedef.
  496. fixturedefs = self._arg2fixturedefs.get(argname, None)
  497. if fixturedefs is None:
  498. # We arrive here because of a dynamic call to
  499. # getfixturevalue(argname) which was naturally
  500. # not known at parsing/collection time.
  501. fixturedefs = self._fixturemanager.getfixturedefs(argname, self._pyfuncitem)
  502. if fixturedefs is not None:
  503. self._arg2fixturedefs[argname] = fixturedefs
  504. # No fixtures defined with this name.
  505. if fixturedefs is None:
  506. raise FixtureLookupError(argname, self)
  507. # The are no fixtures with this name applicable for the function.
  508. if not fixturedefs:
  509. raise FixtureLookupError(argname, self)
  510. # A fixture may override another fixture with the same name, e.g. a
  511. # fixture in a module can override a fixture in a conftest, a fixture in
  512. # a class can override a fixture in the module, and so on.
  513. # An overriding fixture can request its own name (possibly indirectly);
  514. # in this case it gets the value of the fixture it overrides, one level
  515. # up.
  516. # Check how many `argname`s deep we are, and take the next one.
  517. # `fixturedefs` is sorted from furthest to closest, so use negative
  518. # indexing to go in reverse.
  519. index = -1
  520. for request in self._iter_chain():
  521. if request.fixturename == argname:
  522. index -= 1
  523. # If already consumed all of the available levels, fail.
  524. if -index > len(fixturedefs):
  525. raise FixtureLookupError(argname, self)
  526. fixturedef = fixturedefs[index]
  527. # Prepare a SubRequest object for calling the fixture.
  528. try:
  529. callspec = self._pyfuncitem.callspec
  530. except AttributeError:
  531. callspec = None
  532. if callspec is not None and argname in callspec.params:
  533. param = callspec.params[argname]
  534. param_index = callspec.indices[argname]
  535. # The parametrize invocation scope overrides the fixture's scope.
  536. scope = callspec._arg2scope[argname]
  537. else:
  538. param = NOTSET
  539. param_index = 0
  540. scope = fixturedef._scope
  541. self._check_fixturedef_without_param(fixturedef)
  542. # The parametrize invocation scope only controls caching behavior while
  543. # allowing wider-scoped fixtures to keep depending on the parametrized
  544. # fixture. Scope control is enforced for parametrized fixtures
  545. # by recreating the whole fixture tree on parameter change.
  546. # Hence `fixturedef._scope`, not `scope`.
  547. self._check_scope(fixturedef, fixturedef._scope)
  548. subrequest = SubRequest(
  549. self, scope, param, param_index, fixturedef, _ispytest=True
  550. )
  551. # Make sure the fixture value is cached, running it if it isn't
  552. fixturedef.execute(request=subrequest)
  553. self._fixture_defs[argname] = fixturedef
  554. return fixturedef
  555. def _check_fixturedef_without_param(self, fixturedef: FixtureDef[object]) -> None:
  556. """Check that this request is allowed to execute this fixturedef without
  557. a param."""
  558. funcitem = self._pyfuncitem
  559. has_params = fixturedef.params is not None
  560. fixtures_not_supported = getattr(funcitem, "nofuncargs", False)
  561. if has_params and fixtures_not_supported:
  562. msg = (
  563. f"{funcitem.name} does not support fixtures, maybe unittest.TestCase subclass?\n"
  564. f"Node id: {funcitem.nodeid}\n"
  565. f"Function type: {type(funcitem).__name__}"
  566. )
  567. fail(msg, pytrace=False)
  568. if has_params:
  569. frame = inspect.stack()[3]
  570. frameinfo = inspect.getframeinfo(frame[0])
  571. source_path = absolutepath(frameinfo.filename)
  572. source_lineno = frameinfo.lineno
  573. try:
  574. source_path_str = str(source_path.relative_to(funcitem.config.rootpath))
  575. except ValueError:
  576. source_path_str = str(source_path)
  577. location = getlocation(fixturedef.func, funcitem.config.rootpath)
  578. msg = (
  579. "The requested fixture has no parameter defined for test:\n"
  580. f" {funcitem.nodeid}\n\n"
  581. f"Requested fixture '{fixturedef.argname}' defined in:\n"
  582. f"{location}\n\n"
  583. f"Requested here:\n"
  584. f"{source_path_str}:{source_lineno}"
  585. )
  586. fail(msg, pytrace=False)
  587. def _get_fixturestack(self) -> list[FixtureDef[Any]]:
  588. values = [request._fixturedef for request in self._iter_chain()]
  589. values.reverse()
  590. return values
  591. @final
  592. class TopRequest(FixtureRequest):
  593. """The type of the ``request`` fixture in a test function."""
  594. def __init__(self, pyfuncitem: Function, *, _ispytest: bool = False) -> None:
  595. super().__init__(
  596. fixturename=None,
  597. pyfuncitem=pyfuncitem,
  598. arg2fixturedefs=pyfuncitem._fixtureinfo.name2fixturedefs.copy(),
  599. fixture_defs={},
  600. _ispytest=_ispytest,
  601. )
  602. @property
  603. def _scope(self) -> Scope:
  604. return Scope.Function
  605. def _check_scope(
  606. self,
  607. requested_fixturedef: FixtureDef[object] | PseudoFixtureDef[object],
  608. requested_scope: Scope,
  609. ) -> None:
  610. # TopRequest always has function scope so always valid.
  611. pass
  612. @property
  613. def node(self):
  614. return self._pyfuncitem
  615. def __repr__(self) -> str:
  616. return f"<FixtureRequest for {self.node!r}>"
  617. def _fillfixtures(self) -> None:
  618. item = self._pyfuncitem
  619. for argname in item.fixturenames:
  620. if argname not in item.funcargs:
  621. item.funcargs[argname] = self.getfixturevalue(argname)
  622. def addfinalizer(self, finalizer: Callable[[], object]) -> None:
  623. self.node.addfinalizer(finalizer)
  624. @final
  625. class SubRequest(FixtureRequest):
  626. """The type of the ``request`` fixture in a fixture function requested
  627. (transitively) by a test function."""
  628. def __init__(
  629. self,
  630. request: FixtureRequest,
  631. scope: Scope,
  632. param: Any,
  633. param_index: int,
  634. fixturedef: FixtureDef[object],
  635. *,
  636. _ispytest: bool = False,
  637. ) -> None:
  638. super().__init__(
  639. pyfuncitem=request._pyfuncitem,
  640. fixturename=fixturedef.argname,
  641. fixture_defs=request._fixture_defs,
  642. arg2fixturedefs=request._arg2fixturedefs,
  643. _ispytest=_ispytest,
  644. )
  645. self._parent_request: Final[FixtureRequest] = request
  646. self._scope_field: Final = scope
  647. self._fixturedef: Final[FixtureDef[object]] = fixturedef
  648. if param is not NOTSET:
  649. self.param = param
  650. self.param_index: Final = param_index
  651. def __repr__(self) -> str:
  652. return f"<SubRequest {self.fixturename!r} for {self._pyfuncitem!r}>"
  653. @property
  654. def _scope(self) -> Scope:
  655. return self._scope_field
  656. @property
  657. def node(self):
  658. scope = self._scope
  659. if scope is Scope.Function:
  660. # This might also be a non-function Item despite its attribute name.
  661. node: nodes.Node | None = self._pyfuncitem
  662. elif scope is Scope.Package:
  663. node = get_scope_package(self._pyfuncitem, self._fixturedef)
  664. else:
  665. node = get_scope_node(self._pyfuncitem, scope)
  666. if node is None and scope is Scope.Class:
  667. # Fallback to function item itself.
  668. node = self._pyfuncitem
  669. assert node, (
  670. f'Could not obtain a node for scope "{scope}" for function {self._pyfuncitem!r}'
  671. )
  672. return node
  673. def _check_scope(
  674. self,
  675. requested_fixturedef: FixtureDef[object] | PseudoFixtureDef[object],
  676. requested_scope: Scope,
  677. ) -> None:
  678. if isinstance(requested_fixturedef, PseudoFixtureDef):
  679. return
  680. if self._scope > requested_scope:
  681. # Try to report something helpful.
  682. argname = requested_fixturedef.argname
  683. fixture_stack = "\n".join(
  684. self._format_fixturedef_line(fixturedef)
  685. for fixturedef in self._get_fixturestack()
  686. )
  687. requested_fixture = self._format_fixturedef_line(requested_fixturedef)
  688. fail(
  689. f"ScopeMismatch: You tried to access the {requested_scope.value} scoped "
  690. f"fixture {argname} with a {self._scope.value} scoped request object. "
  691. f"Requesting fixture stack:\n{fixture_stack}\n"
  692. f"Requested fixture:\n{requested_fixture}",
  693. pytrace=False,
  694. )
  695. def _format_fixturedef_line(self, fixturedef: FixtureDef[object]) -> str:
  696. factory = fixturedef.func
  697. path, lineno = getfslineno(factory)
  698. if isinstance(path, Path):
  699. path = bestrelpath(self._pyfuncitem.session.path, path)
  700. sig = signature(factory)
  701. return f"{path}:{lineno + 1}: def {factory.__name__}{sig}"
  702. def addfinalizer(self, finalizer: Callable[[], object]) -> None:
  703. self._fixturedef.addfinalizer(finalizer)
  704. @final
  705. class FixtureLookupError(LookupError):
  706. """Could not return a requested fixture (missing or invalid)."""
  707. def __init__(
  708. self, argname: str | None, request: FixtureRequest, msg: str | None = None
  709. ) -> None:
  710. self.argname = argname
  711. self.request = request
  712. self.fixturestack = request._get_fixturestack()
  713. self.msg = msg
  714. def formatrepr(self) -> FixtureLookupErrorRepr:
  715. tblines: list[str] = []
  716. addline = tblines.append
  717. stack = [self.request._pyfuncitem.obj]
  718. stack.extend(map(lambda x: x.func, self.fixturestack))
  719. msg = self.msg
  720. # This function currently makes an assumption that a non-None msg means we
  721. # have a non-empty `self.fixturestack`. This is currently true, but if
  722. # somebody at some point want to extend the use of FixtureLookupError to
  723. # new cases it might break.
  724. # Add the assert to make it clearer to developer that this will fail, otherwise
  725. # it crashes because `fspath` does not get set due to `stack` being empty.
  726. assert self.msg is None or self.fixturestack, (
  727. "formatrepr assumptions broken, rewrite it to handle it"
  728. )
  729. if msg is not None:
  730. # The last fixture raise an error, let's present
  731. # it at the requesting side.
  732. stack = stack[:-1]
  733. for function in stack:
  734. fspath, lineno = getfslineno(function)
  735. try:
  736. lines, _ = inspect.getsourcelines(get_real_func(function))
  737. except (OSError, IndexError, TypeError):
  738. error_msg = "file %s, line %s: source code not available"
  739. addline(error_msg % (fspath, lineno + 1))
  740. else:
  741. addline(f"file {fspath}, line {lineno + 1}")
  742. for i, line in enumerate(lines):
  743. line = line.rstrip()
  744. addline(" " + line)
  745. if line.lstrip().startswith("def"):
  746. break
  747. if msg is None:
  748. fm = self.request._fixturemanager
  749. available = set()
  750. parent = self.request._pyfuncitem.parent
  751. assert parent is not None
  752. for name, fixturedefs in fm._arg2fixturedefs.items():
  753. faclist = list(fm._matchfactories(fixturedefs, parent))
  754. if faclist:
  755. available.add(name)
  756. if self.argname in available:
  757. msg = (
  758. f" recursive dependency involving fixture '{self.argname}' detected"
  759. )
  760. else:
  761. msg = f"fixture '{self.argname}' not found"
  762. msg += "\n available fixtures: {}".format(", ".join(sorted(available)))
  763. msg += "\n use 'pytest --fixtures [testpath]' for help on them."
  764. return FixtureLookupErrorRepr(fspath, lineno, tblines, msg, self.argname)
  765. class FixtureLookupErrorRepr(TerminalRepr):
  766. def __init__(
  767. self,
  768. filename: str | os.PathLike[str],
  769. firstlineno: int,
  770. tblines: Sequence[str],
  771. errorstring: str,
  772. argname: str | None,
  773. ) -> None:
  774. self.tblines = tblines
  775. self.errorstring = errorstring
  776. self.filename = filename
  777. self.firstlineno = firstlineno
  778. self.argname = argname
  779. def toterminal(self, tw: TerminalWriter) -> None:
  780. # tw.line("FixtureLookupError: %s" %(self.argname), red=True)
  781. for tbline in self.tblines:
  782. tw.line(tbline.rstrip())
  783. lines = self.errorstring.split("\n")
  784. if lines:
  785. tw.line(
  786. f"{FormattedExcinfo.fail_marker} {lines[0].strip()}",
  787. red=True,
  788. )
  789. for line in lines[1:]:
  790. tw.line(
  791. f"{FormattedExcinfo.flow_marker} {line.strip()}",
  792. red=True,
  793. )
  794. tw.line()
  795. tw.line(f"{os.fspath(self.filename)}:{self.firstlineno + 1}")
  796. def call_fixture_func(
  797. fixturefunc: _FixtureFunc[FixtureValue], request: FixtureRequest, kwargs
  798. ) -> FixtureValue:
  799. if inspect.isgeneratorfunction(fixturefunc):
  800. fixturefunc = cast(Callable[..., Generator[FixtureValue]], fixturefunc)
  801. generator = fixturefunc(**kwargs)
  802. try:
  803. fixture_result = next(generator)
  804. except StopIteration:
  805. raise ValueError(f"{request.fixturename} did not yield a value") from None
  806. finalizer = functools.partial(_teardown_yield_fixture, fixturefunc, generator)
  807. request.addfinalizer(finalizer)
  808. else:
  809. fixturefunc = cast(Callable[..., FixtureValue], fixturefunc)
  810. fixture_result = fixturefunc(**kwargs)
  811. return fixture_result
  812. def _teardown_yield_fixture(fixturefunc, it) -> None:
  813. """Execute the teardown of a fixture function by advancing the iterator
  814. after the yield and ensure the iteration ends (if not it means there is
  815. more than one yield in the function)."""
  816. try:
  817. next(it)
  818. except StopIteration:
  819. pass
  820. else:
  821. fs, lineno = getfslineno(fixturefunc)
  822. fail(
  823. f"fixture function has more than one 'yield':\n\n"
  824. f"{Source(fixturefunc).indent()}\n"
  825. f"{fs}:{lineno + 1}",
  826. pytrace=False,
  827. )
  828. def _eval_scope_callable(
  829. scope_callable: Callable[[str, Config], _ScopeName],
  830. fixture_name: str,
  831. config: Config,
  832. ) -> _ScopeName:
  833. try:
  834. # Type ignored because there is no typing mechanism to specify
  835. # keyword arguments, currently.
  836. result = scope_callable(fixture_name=fixture_name, config=config) # type: ignore[call-arg]
  837. except Exception as e:
  838. raise TypeError(
  839. f"Error evaluating {scope_callable} while defining fixture '{fixture_name}'.\n"
  840. "Expected a function with the signature (*, fixture_name, config)"
  841. ) from e
  842. if not isinstance(result, str):
  843. fail(
  844. f"Expected {scope_callable} to return a 'str' while defining fixture '{fixture_name}', but it returned:\n"
  845. f"{result!r}",
  846. pytrace=False,
  847. )
  848. return result
  849. @final
  850. class FixtureDef(Generic[FixtureValue]):
  851. """A container for a fixture definition.
  852. Note: At this time, only explicitly documented fields and methods are
  853. considered public stable API.
  854. """
  855. def __init__(
  856. self,
  857. config: Config,
  858. baseid: str | None,
  859. argname: str,
  860. func: _FixtureFunc[FixtureValue],
  861. scope: Scope | _ScopeName | Callable[[str, Config], _ScopeName] | None,
  862. params: Sequence[object] | None,
  863. ids: tuple[object | None, ...] | Callable[[Any], object | None] | None = None,
  864. *,
  865. _ispytest: bool = False,
  866. # only used in a deprecationwarning msg, can be removed in pytest9
  867. _autouse: bool = False,
  868. ) -> None:
  869. check_ispytest(_ispytest)
  870. # The "base" node ID for the fixture.
  871. #
  872. # This is a node ID prefix. A fixture is only available to a node (e.g.
  873. # a `Function` item) if the fixture's baseid is a nodeid of a parent of
  874. # node.
  875. #
  876. # For a fixture found in a Collector's object (e.g. a `Module`s module,
  877. # a `Class`'s class), the baseid is the Collector's nodeid.
  878. #
  879. # For a fixture found in a conftest plugin, the baseid is the conftest's
  880. # directory path relative to the rootdir.
  881. #
  882. # For other plugins, the baseid is the empty string (always matches).
  883. self.baseid: Final = baseid or ""
  884. # Whether the fixture was found from a node or a conftest in the
  885. # collection tree. Will be false for fixtures defined in non-conftest
  886. # plugins.
  887. self.has_location: Final = baseid is not None
  888. # The fixture factory function.
  889. self.func: Final = func
  890. # The name by which the fixture may be requested.
  891. self.argname: Final = argname
  892. if scope is None:
  893. scope = Scope.Function
  894. elif callable(scope):
  895. scope = _eval_scope_callable(scope, argname, config)
  896. if isinstance(scope, str):
  897. scope = Scope.from_user(
  898. scope, descr=f"Fixture '{func.__name__}'", where=baseid
  899. )
  900. self._scope: Final = scope
  901. # If the fixture is directly parametrized, the parameter values.
  902. self.params: Final = params
  903. # If the fixture is directly parametrized, a tuple of explicit IDs to
  904. # assign to the parameter values, or a callable to generate an ID given
  905. # a parameter value.
  906. self.ids: Final = ids
  907. # The names requested by the fixtures.
  908. self.argnames: Final = getfuncargnames(func, name=argname)
  909. # If the fixture was executed, the current value of the fixture.
  910. # Can change if the fixture is executed with different parameters.
  911. self.cached_result: _FixtureCachedResult[FixtureValue] | None = None
  912. self._finalizers: Final[list[Callable[[], object]]] = []
  913. # only used to emit a deprecationwarning, can be removed in pytest9
  914. self._autouse = _autouse
  915. @property
  916. def scope(self) -> _ScopeName:
  917. """Scope string, one of "function", "class", "module", "package", "session"."""
  918. return self._scope.value
  919. def addfinalizer(self, finalizer: Callable[[], object]) -> None:
  920. self._finalizers.append(finalizer)
  921. def finish(self, request: SubRequest) -> None:
  922. exceptions: list[BaseException] = []
  923. while self._finalizers:
  924. fin = self._finalizers.pop()
  925. try:
  926. fin()
  927. except BaseException as e:
  928. exceptions.append(e)
  929. node = request.node
  930. node.ihook.pytest_fixture_post_finalizer(fixturedef=self, request=request)
  931. # Even if finalization fails, we invalidate the cached fixture
  932. # value and remove all finalizers because they may be bound methods
  933. # which will keep instances alive.
  934. self.cached_result = None
  935. self._finalizers.clear()
  936. if len(exceptions) == 1:
  937. raise exceptions[0]
  938. elif len(exceptions) > 1:
  939. msg = f'errors while tearing down fixture "{self.argname}" of {node}'
  940. raise BaseExceptionGroup(msg, exceptions[::-1])
  941. def execute(self, request: SubRequest) -> FixtureValue:
  942. """Return the value of this fixture, executing it if not cached."""
  943. # Ensure that the dependent fixtures requested by this fixture are loaded.
  944. # This needs to be done before checking if we have a cached value, since
  945. # if a dependent fixture has their cache invalidated, e.g. due to
  946. # parametrization, they finalize themselves and fixtures depending on it
  947. # (which will likely include this fixture) setting `self.cached_result = None`.
  948. # See #4871
  949. requested_fixtures_that_should_finalize_us = []
  950. for argname in self.argnames:
  951. fixturedef = request._get_active_fixturedef(argname)
  952. # Saves requested fixtures in a list so we later can add our finalizer
  953. # to them, ensuring that if a requested fixture gets torn down we get torn
  954. # down first. This is generally handled by SetupState, but still currently
  955. # needed when this fixture is not parametrized but depends on a parametrized
  956. # fixture.
  957. if not isinstance(fixturedef, PseudoFixtureDef):
  958. requested_fixtures_that_should_finalize_us.append(fixturedef)
  959. # Check for (and return) cached value/exception.
  960. if self.cached_result is not None:
  961. request_cache_key = self.cache_key(request)
  962. cache_key = self.cached_result[1]
  963. try:
  964. # Attempt to make a normal == check: this might fail for objects
  965. # which do not implement the standard comparison (like numpy arrays -- #6497).
  966. cache_hit = bool(request_cache_key == cache_key)
  967. except (ValueError, RuntimeError):
  968. # If the comparison raises, use 'is' as fallback.
  969. cache_hit = request_cache_key is cache_key
  970. if cache_hit:
  971. if self.cached_result[2] is not None:
  972. exc, exc_tb = self.cached_result[2]
  973. raise exc.with_traceback(exc_tb)
  974. else:
  975. result = self.cached_result[0]
  976. return result
  977. # We have a previous but differently parametrized fixture instance
  978. # so we need to tear it down before creating a new one.
  979. self.finish(request)
  980. assert self.cached_result is None
  981. # Add finalizer to requested fixtures we saved previously.
  982. # We make sure to do this after checking for cached value to avoid
  983. # adding our finalizer multiple times. (#12135)
  984. finalizer = functools.partial(self.finish, request=request)
  985. for parent_fixture in requested_fixtures_that_should_finalize_us:
  986. parent_fixture.addfinalizer(finalizer)
  987. ihook = request.node.ihook
  988. try:
  989. # Setup the fixture, run the code in it, and cache the value
  990. # in self.cached_result
  991. result = ihook.pytest_fixture_setup(fixturedef=self, request=request)
  992. finally:
  993. # schedule our finalizer, even if the setup failed
  994. request.node.addfinalizer(finalizer)
  995. return result
  996. def cache_key(self, request: SubRequest) -> object:
  997. return getattr(request, "param", None)
  998. def __repr__(self) -> str:
  999. return f"<FixtureDef argname={self.argname!r} scope={self.scope!r} baseid={self.baseid!r}>"
  1000. def resolve_fixture_function(
  1001. fixturedef: FixtureDef[FixtureValue], request: FixtureRequest
  1002. ) -> _FixtureFunc[FixtureValue]:
  1003. """Get the actual callable that can be called to obtain the fixture
  1004. value."""
  1005. fixturefunc = fixturedef.func
  1006. # The fixture function needs to be bound to the actual
  1007. # request.instance so that code working with "fixturedef" behaves
  1008. # as expected.
  1009. instance = request.instance
  1010. if instance is not None:
  1011. # Handle the case where fixture is defined not in a test class, but some other class
  1012. # (for example a plugin class with a fixture), see #2270.
  1013. if hasattr(fixturefunc, "__self__") and not isinstance(
  1014. instance,
  1015. fixturefunc.__self__.__class__,
  1016. ):
  1017. return fixturefunc
  1018. fixturefunc = getimfunc(fixturedef.func)
  1019. if fixturefunc != fixturedef.func:
  1020. fixturefunc = fixturefunc.__get__(instance)
  1021. return fixturefunc
  1022. def pytest_fixture_setup(
  1023. fixturedef: FixtureDef[FixtureValue], request: SubRequest
  1024. ) -> FixtureValue:
  1025. """Execution of fixture setup."""
  1026. kwargs = {}
  1027. for argname in fixturedef.argnames:
  1028. kwargs[argname] = request.getfixturevalue(argname)
  1029. fixturefunc = resolve_fixture_function(fixturedef, request)
  1030. my_cache_key = fixturedef.cache_key(request)
  1031. if inspect.isasyncgenfunction(fixturefunc) or inspect.iscoroutinefunction(
  1032. fixturefunc
  1033. ):
  1034. auto_str = " with autouse=True" if fixturedef._autouse else ""
  1035. warnings.warn(
  1036. PytestRemovedIn9Warning(
  1037. f"{request.node.name!r} requested an async fixture "
  1038. f"{request.fixturename!r}{auto_str}, with no plugin or hook that "
  1039. "handled it. This is usually an error, as pytest does not natively "
  1040. "support it. "
  1041. "This will turn into an error in pytest 9.\n"
  1042. "See: https://docs.pytest.org/en/stable/deprecations.html#sync-test-depending-on-async-fixture"
  1043. ),
  1044. # no stacklevel will point at users code, so we just point here
  1045. stacklevel=1,
  1046. )
  1047. try:
  1048. result = call_fixture_func(fixturefunc, request, kwargs)
  1049. except TEST_OUTCOME as e:
  1050. if isinstance(e, skip.Exception):
  1051. # The test requested a fixture which caused a skip.
  1052. # Don't show the fixture as the skip location, as then the user
  1053. # wouldn't know which test skipped.
  1054. e._use_item_location = True
  1055. fixturedef.cached_result = (None, my_cache_key, (e, e.__traceback__))
  1056. raise
  1057. fixturedef.cached_result = (result, my_cache_key, None)
  1058. return result
  1059. @final
  1060. @dataclasses.dataclass(frozen=True)
  1061. class FixtureFunctionMarker:
  1062. scope: _ScopeName | Callable[[str, Config], _ScopeName]
  1063. params: tuple[object, ...] | None
  1064. autouse: bool = False
  1065. ids: tuple[object | None, ...] | Callable[[Any], object | None] | None = None
  1066. name: str | None = None
  1067. _ispytest: dataclasses.InitVar[bool] = False
  1068. def __post_init__(self, _ispytest: bool) -> None:
  1069. check_ispytest(_ispytest)
  1070. def __call__(self, function: FixtureFunction) -> FixtureFunctionDefinition:
  1071. if inspect.isclass(function):
  1072. raise ValueError("class fixtures not supported (maybe in the future)")
  1073. if isinstance(function, FixtureFunctionDefinition):
  1074. raise ValueError(
  1075. f"@pytest.fixture is being applied more than once to the same function {function.__name__!r}"
  1076. )
  1077. if hasattr(function, "pytestmark"):
  1078. warnings.warn(MARKED_FIXTURE, stacklevel=2)
  1079. fixture_definition = FixtureFunctionDefinition(
  1080. function=function, fixture_function_marker=self, _ispytest=True
  1081. )
  1082. name = self.name or function.__name__
  1083. if name == "request":
  1084. location = getlocation(function)
  1085. fail(
  1086. f"'request' is a reserved word for fixtures, use another name:\n {location}",
  1087. pytrace=False,
  1088. )
  1089. return fixture_definition
  1090. # TODO: paramspec/return type annotation tracking and storing
  1091. class FixtureFunctionDefinition:
  1092. def __init__(
  1093. self,
  1094. *,
  1095. function: Callable[..., Any],
  1096. fixture_function_marker: FixtureFunctionMarker,
  1097. instance: object | None = None,
  1098. _ispytest: bool = False,
  1099. ) -> None:
  1100. check_ispytest(_ispytest)
  1101. self.name = fixture_function_marker.name or function.__name__
  1102. # In order to show the function that this fixture contains in messages.
  1103. # Set the __name__ to be same as the function __name__ or the given fixture name.
  1104. self.__name__ = self.name
  1105. self._fixture_function_marker = fixture_function_marker
  1106. if instance is not None:
  1107. self._fixture_function = cast(
  1108. Callable[..., Any], function.__get__(instance)
  1109. )
  1110. else:
  1111. self._fixture_function = function
  1112. functools.update_wrapper(self, function)
  1113. def __repr__(self) -> str:
  1114. return f"<pytest_fixture({self._fixture_function})>"
  1115. def __get__(self, instance, owner=None):
  1116. """Behave like a method if the function it was applied to was a method."""
  1117. return FixtureFunctionDefinition(
  1118. function=self._fixture_function,
  1119. fixture_function_marker=self._fixture_function_marker,
  1120. instance=instance,
  1121. _ispytest=True,
  1122. )
  1123. def __call__(self, *args: Any, **kwds: Any) -> Any:
  1124. message = (
  1125. f'Fixture "{self.name}" called directly. Fixtures are not meant to be called directly,\n'
  1126. "but are created automatically when test functions request them as parameters.\n"
  1127. "See https://docs.pytest.org/en/stable/explanation/fixtures.html for more information about fixtures, and\n"
  1128. "https://docs.pytest.org/en/stable/deprecations.html#calling-fixtures-directly"
  1129. )
  1130. fail(message, pytrace=False)
  1131. def _get_wrapped_function(self) -> Callable[..., Any]:
  1132. return self._fixture_function
  1133. @overload
  1134. def fixture(
  1135. fixture_function: Callable[..., object],
  1136. *,
  1137. scope: _ScopeName | Callable[[str, Config], _ScopeName] = ...,
  1138. params: Iterable[object] | None = ...,
  1139. autouse: bool = ...,
  1140. ids: Sequence[object | None] | Callable[[Any], object | None] | None = ...,
  1141. name: str | None = ...,
  1142. ) -> FixtureFunctionDefinition: ...
  1143. @overload
  1144. def fixture(
  1145. fixture_function: None = ...,
  1146. *,
  1147. scope: _ScopeName | Callable[[str, Config], _ScopeName] = ...,
  1148. params: Iterable[object] | None = ...,
  1149. autouse: bool = ...,
  1150. ids: Sequence[object | None] | Callable[[Any], object | None] | None = ...,
  1151. name: str | None = None,
  1152. ) -> FixtureFunctionMarker: ...
  1153. def fixture(
  1154. fixture_function: FixtureFunction | None = None,
  1155. *,
  1156. scope: _ScopeName | Callable[[str, Config], _ScopeName] = "function",
  1157. params: Iterable[object] | None = None,
  1158. autouse: bool = False,
  1159. ids: Sequence[object | None] | Callable[[Any], object | None] | None = None,
  1160. name: str | None = None,
  1161. ) -> FixtureFunctionMarker | FixtureFunctionDefinition:
  1162. """Decorator to mark a fixture factory function.
  1163. This decorator can be used, with or without parameters, to define a
  1164. fixture function.
  1165. The name of the fixture function can later be referenced to cause its
  1166. invocation ahead of running tests: test modules or classes can use the
  1167. ``pytest.mark.usefixtures(fixturename)`` marker.
  1168. Test functions can directly use fixture names as input arguments in which
  1169. case the fixture instance returned from the fixture function will be
  1170. injected.
  1171. Fixtures can provide their values to test functions using ``return`` or
  1172. ``yield`` statements. When using ``yield`` the code block after the
  1173. ``yield`` statement is executed as teardown code regardless of the test
  1174. outcome, and must yield exactly once.
  1175. :param scope:
  1176. The scope for which this fixture is shared; one of ``"function"``
  1177. (default), ``"class"``, ``"module"``, ``"package"`` or ``"session"``.
  1178. This parameter may also be a callable which receives ``(fixture_name, config)``
  1179. as parameters, and must return a ``str`` with one of the values mentioned above.
  1180. See :ref:`dynamic scope` in the docs for more information.
  1181. :param params:
  1182. An optional list of parameters which will cause multiple invocations
  1183. of the fixture function and all of the tests using it. The current
  1184. parameter is available in ``request.param``.
  1185. :param autouse:
  1186. If True, the fixture func is activated for all tests that can see it.
  1187. If False (the default), an explicit reference is needed to activate
  1188. the fixture.
  1189. :param ids:
  1190. Sequence of ids each corresponding to the params so that they are
  1191. part of the test id. If no ids are provided they will be generated
  1192. automatically from the params.
  1193. :param name:
  1194. The name of the fixture. This defaults to the name of the decorated
  1195. function. If a fixture is used in the same module in which it is
  1196. defined, the function name of the fixture will be shadowed by the
  1197. function arg that requests the fixture; one way to resolve this is to
  1198. name the decorated function ``fixture_<fixturename>`` and then use
  1199. ``@pytest.fixture(name='<fixturename>')``.
  1200. """
  1201. fixture_marker = FixtureFunctionMarker(
  1202. scope=scope,
  1203. params=tuple(params) if params is not None else None,
  1204. autouse=autouse,
  1205. ids=None if ids is None else ids if callable(ids) else tuple(ids),
  1206. name=name,
  1207. _ispytest=True,
  1208. )
  1209. # Direct decoration.
  1210. if fixture_function:
  1211. return fixture_marker(fixture_function)
  1212. return fixture_marker
  1213. def yield_fixture(
  1214. fixture_function=None,
  1215. *args,
  1216. scope="function",
  1217. params=None,
  1218. autouse=False,
  1219. ids=None,
  1220. name=None,
  1221. ):
  1222. """(Return a) decorator to mark a yield-fixture factory function.
  1223. .. deprecated:: 3.0
  1224. Use :py:func:`pytest.fixture` directly instead.
  1225. """
  1226. warnings.warn(YIELD_FIXTURE, stacklevel=2)
  1227. return fixture(
  1228. fixture_function,
  1229. *args,
  1230. scope=scope,
  1231. params=params,
  1232. autouse=autouse,
  1233. ids=ids,
  1234. name=name,
  1235. )
  1236. @fixture(scope="session")
  1237. def pytestconfig(request: FixtureRequest) -> Config:
  1238. """Session-scoped fixture that returns the session's :class:`pytest.Config`
  1239. object.
  1240. Example::
  1241. def test_foo(pytestconfig):
  1242. if pytestconfig.get_verbosity() > 0:
  1243. ...
  1244. """
  1245. return request.config
  1246. def pytest_addoption(parser: Parser) -> None:
  1247. parser.addini(
  1248. "usefixtures",
  1249. type="args",
  1250. default=[],
  1251. help="List of default fixtures to be used with this project",
  1252. )
  1253. group = parser.getgroup("general")
  1254. group.addoption(
  1255. "--fixtures",
  1256. "--funcargs",
  1257. action="store_true",
  1258. dest="showfixtures",
  1259. default=False,
  1260. help="Show available fixtures, sorted by plugin appearance "
  1261. "(fixtures with leading '_' are only shown with '-v')",
  1262. )
  1263. group.addoption(
  1264. "--fixtures-per-test",
  1265. action="store_true",
  1266. dest="show_fixtures_per_test",
  1267. default=False,
  1268. help="Show fixtures per test",
  1269. )
  1270. def pytest_cmdline_main(config: Config) -> int | ExitCode | None:
  1271. if config.option.showfixtures:
  1272. showfixtures(config)
  1273. return 0
  1274. if config.option.show_fixtures_per_test:
  1275. show_fixtures_per_test(config)
  1276. return 0
  1277. return None
  1278. def _get_direct_parametrize_args(node: nodes.Node) -> set[str]:
  1279. """Return all direct parametrization arguments of a node, so we don't
  1280. mistake them for fixtures.
  1281. Check https://github.com/pytest-dev/pytest/issues/5036.
  1282. These things are done later as well when dealing with parametrization
  1283. so this could be improved.
  1284. """
  1285. parametrize_argnames: set[str] = set()
  1286. for marker in node.iter_markers(name="parametrize"):
  1287. if not marker.kwargs.get("indirect", False):
  1288. p_argnames, _ = ParameterSet._parse_parametrize_args(
  1289. *marker.args, **marker.kwargs
  1290. )
  1291. parametrize_argnames.update(p_argnames)
  1292. return parametrize_argnames
  1293. def deduplicate_names(*seqs: Iterable[str]) -> tuple[str, ...]:
  1294. """De-duplicate the sequence of names while keeping the original order."""
  1295. # Ideally we would use a set, but it does not preserve insertion order.
  1296. return tuple(dict.fromkeys(name for seq in seqs for name in seq))
  1297. class FixtureManager:
  1298. """pytest fixture definitions and information is stored and managed
  1299. from this class.
  1300. During collection fm.parsefactories() is called multiple times to parse
  1301. fixture function definitions into FixtureDef objects and internal
  1302. data structures.
  1303. During collection of test functions, metafunc-mechanics instantiate
  1304. a FuncFixtureInfo object which is cached per node/func-name.
  1305. This FuncFixtureInfo object is later retrieved by Function nodes
  1306. which themselves offer a fixturenames attribute.
  1307. The FuncFixtureInfo object holds information about fixtures and FixtureDefs
  1308. relevant for a particular function. An initial list of fixtures is
  1309. assembled like this:
  1310. - ini-defined usefixtures
  1311. - autouse-marked fixtures along the collection chain up from the function
  1312. - usefixtures markers at module/class/function level
  1313. - test function funcargs
  1314. Subsequently the funcfixtureinfo.fixturenames attribute is computed
  1315. as the closure of the fixtures needed to setup the initial fixtures,
  1316. i.e. fixtures needed by fixture functions themselves are appended
  1317. to the fixturenames list.
  1318. Upon the test-setup phases all fixturenames are instantiated, retrieved
  1319. by a lookup of their FuncFixtureInfo.
  1320. """
  1321. def __init__(self, session: Session) -> None:
  1322. self.session = session
  1323. self.config: Config = session.config
  1324. # Maps a fixture name (argname) to all of the FixtureDefs in the test
  1325. # suite/plugins defined with this name. Populated by parsefactories().
  1326. # TODO: The order of the FixtureDefs list of each arg is significant,
  1327. # explain.
  1328. self._arg2fixturedefs: Final[dict[str, list[FixtureDef[Any]]]] = {}
  1329. self._holderobjseen: Final[set[object]] = set()
  1330. # A mapping from a nodeid to a list of autouse fixtures it defines.
  1331. self._nodeid_autousenames: Final[dict[str, list[str]]] = {
  1332. "": self.config.getini("usefixtures"),
  1333. }
  1334. session.config.pluginmanager.register(self, "funcmanage")
  1335. def getfixtureinfo(
  1336. self,
  1337. node: nodes.Item,
  1338. func: Callable[..., object] | None,
  1339. cls: type | None,
  1340. ) -> FuncFixtureInfo:
  1341. """Calculate the :class:`FuncFixtureInfo` for an item.
  1342. If ``func`` is None, or if the item sets an attribute
  1343. ``nofuncargs = True``, then ``func`` is not examined at all.
  1344. :param node:
  1345. The item requesting the fixtures.
  1346. :param func:
  1347. The item's function.
  1348. :param cls:
  1349. If the function is a method, the method's class.
  1350. """
  1351. if func is not None and not getattr(node, "nofuncargs", False):
  1352. argnames = getfuncargnames(func, name=node.name, cls=cls)
  1353. else:
  1354. argnames = ()
  1355. usefixturesnames = self._getusefixturesnames(node)
  1356. autousenames = self._getautousenames(node)
  1357. initialnames = deduplicate_names(autousenames, usefixturesnames, argnames)
  1358. direct_parametrize_args = _get_direct_parametrize_args(node)
  1359. names_closure, arg2fixturedefs = self.getfixtureclosure(
  1360. parentnode=node,
  1361. initialnames=initialnames,
  1362. ignore_args=direct_parametrize_args,
  1363. )
  1364. return FuncFixtureInfo(argnames, initialnames, names_closure, arg2fixturedefs)
  1365. def pytest_plugin_registered(self, plugin: _PluggyPlugin, plugin_name: str) -> None:
  1366. # Fixtures defined in conftest plugins are only visible to within the
  1367. # conftest's directory. This is unlike fixtures in non-conftest plugins
  1368. # which have global visibility. So for conftests, construct the base
  1369. # nodeid from the plugin name (which is the conftest path).
  1370. if plugin_name and plugin_name.endswith("conftest.py"):
  1371. # Note: we explicitly do *not* use `plugin.__file__` here -- The
  1372. # difference is that plugin_name has the correct capitalization on
  1373. # case-insensitive systems (Windows) and other normalization issues
  1374. # (issue #11816).
  1375. conftestpath = absolutepath(plugin_name)
  1376. try:
  1377. nodeid = str(conftestpath.parent.relative_to(self.config.rootpath))
  1378. except ValueError:
  1379. nodeid = ""
  1380. if nodeid == ".":
  1381. nodeid = ""
  1382. if os.sep != nodes.SEP:
  1383. nodeid = nodeid.replace(os.sep, nodes.SEP)
  1384. else:
  1385. nodeid = None
  1386. self.parsefactories(plugin, nodeid)
  1387. def _getautousenames(self, node: nodes.Node) -> Iterator[str]:
  1388. """Return the names of autouse fixtures applicable to node."""
  1389. for parentnode in node.listchain():
  1390. basenames = self._nodeid_autousenames.get(parentnode.nodeid)
  1391. if basenames:
  1392. yield from basenames
  1393. def _getusefixturesnames(self, node: nodes.Item) -> Iterator[str]:
  1394. """Return the names of usefixtures fixtures applicable to node."""
  1395. for marker_node, mark in node.iter_markers_with_node(name="usefixtures"):
  1396. if not mark.args:
  1397. marker_node.warn(
  1398. PytestWarning(
  1399. f"usefixtures() in {node.nodeid} without arguments has no effect"
  1400. )
  1401. )
  1402. yield from mark.args
  1403. def getfixtureclosure(
  1404. self,
  1405. parentnode: nodes.Node,
  1406. initialnames: tuple[str, ...],
  1407. ignore_args: AbstractSet[str],
  1408. ) -> tuple[list[str], dict[str, Sequence[FixtureDef[Any]]]]:
  1409. # Collect the closure of all fixtures, starting with the given
  1410. # fixturenames as the initial set. As we have to visit all
  1411. # factory definitions anyway, we also return an arg2fixturedefs
  1412. # mapping so that the caller can reuse it and does not have
  1413. # to re-discover fixturedefs again for each fixturename
  1414. # (discovering matching fixtures for a given name/node is expensive).
  1415. fixturenames_closure = list(initialnames)
  1416. arg2fixturedefs: dict[str, Sequence[FixtureDef[Any]]] = {}
  1417. lastlen = -1
  1418. while lastlen != len(fixturenames_closure):
  1419. lastlen = len(fixturenames_closure)
  1420. for argname in fixturenames_closure:
  1421. if argname in ignore_args:
  1422. continue
  1423. if argname in arg2fixturedefs:
  1424. continue
  1425. fixturedefs = self.getfixturedefs(argname, parentnode)
  1426. if fixturedefs:
  1427. arg2fixturedefs[argname] = fixturedefs
  1428. for arg in fixturedefs[-1].argnames:
  1429. if arg not in fixturenames_closure:
  1430. fixturenames_closure.append(arg)
  1431. def sort_by_scope(arg_name: str) -> Scope:
  1432. try:
  1433. fixturedefs = arg2fixturedefs[arg_name]
  1434. except KeyError:
  1435. return Scope.Function
  1436. else:
  1437. return fixturedefs[-1]._scope
  1438. fixturenames_closure.sort(key=sort_by_scope, reverse=True)
  1439. return fixturenames_closure, arg2fixturedefs
  1440. def pytest_generate_tests(self, metafunc: Metafunc) -> None:
  1441. """Generate new tests based on parametrized fixtures used by the given metafunc"""
  1442. def get_parametrize_mark_argnames(mark: Mark) -> Sequence[str]:
  1443. args, _ = ParameterSet._parse_parametrize_args(*mark.args, **mark.kwargs)
  1444. return args
  1445. for argname in metafunc.fixturenames:
  1446. # Get the FixtureDefs for the argname.
  1447. fixture_defs = metafunc._arg2fixturedefs.get(argname)
  1448. if not fixture_defs:
  1449. # Will raise FixtureLookupError at setup time if not parametrized somewhere
  1450. # else (e.g @pytest.mark.parametrize)
  1451. continue
  1452. # If the test itself parametrizes using this argname, give it
  1453. # precedence.
  1454. if any(
  1455. argname in get_parametrize_mark_argnames(mark)
  1456. for mark in metafunc.definition.iter_markers("parametrize")
  1457. ):
  1458. continue
  1459. # In the common case we only look at the fixture def with the
  1460. # closest scope (last in the list). But if the fixture overrides
  1461. # another fixture, while requesting the super fixture, keep going
  1462. # in case the super fixture is parametrized (#1953).
  1463. for fixturedef in reversed(fixture_defs):
  1464. # Fixture is parametrized, apply it and stop.
  1465. if fixturedef.params is not None:
  1466. metafunc.parametrize(
  1467. argname,
  1468. fixturedef.params,
  1469. indirect=True,
  1470. scope=fixturedef.scope,
  1471. ids=fixturedef.ids,
  1472. )
  1473. break
  1474. # Not requesting the overridden super fixture, stop.
  1475. if argname not in fixturedef.argnames:
  1476. break
  1477. # Try next super fixture, if any.
  1478. def pytest_collection_modifyitems(self, items: list[nodes.Item]) -> None:
  1479. # Separate parametrized setups.
  1480. items[:] = reorder_items(items)
  1481. def _register_fixture(
  1482. self,
  1483. *,
  1484. name: str,
  1485. func: _FixtureFunc[object],
  1486. nodeid: str | None,
  1487. scope: Scope | _ScopeName | Callable[[str, Config], _ScopeName] = "function",
  1488. params: Sequence[object] | None = None,
  1489. ids: tuple[object | None, ...] | Callable[[Any], object | None] | None = None,
  1490. autouse: bool = False,
  1491. ) -> None:
  1492. """Register a fixture
  1493. :param name:
  1494. The fixture's name.
  1495. :param func:
  1496. The fixture's implementation function.
  1497. :param nodeid:
  1498. The visibility of the fixture. The fixture will be available to the
  1499. node with this nodeid and its children in the collection tree.
  1500. None means that the fixture is visible to the entire collection tree,
  1501. e.g. a fixture defined for general use in a plugin.
  1502. :param scope:
  1503. The fixture's scope.
  1504. :param params:
  1505. The fixture's parametrization params.
  1506. :param ids:
  1507. The fixture's IDs.
  1508. :param autouse:
  1509. Whether this is an autouse fixture.
  1510. """
  1511. fixture_def = FixtureDef(
  1512. config=self.config,
  1513. baseid=nodeid,
  1514. argname=name,
  1515. func=func,
  1516. scope=scope,
  1517. params=params,
  1518. ids=ids,
  1519. _ispytest=True,
  1520. _autouse=autouse,
  1521. )
  1522. faclist = self._arg2fixturedefs.setdefault(name, [])
  1523. if fixture_def.has_location:
  1524. faclist.append(fixture_def)
  1525. else:
  1526. # fixturedefs with no location are at the front
  1527. # so this inserts the current fixturedef after the
  1528. # existing fixturedefs from external plugins but
  1529. # before the fixturedefs provided in conftests.
  1530. i = len([f for f in faclist if not f.has_location])
  1531. faclist.insert(i, fixture_def)
  1532. if autouse:
  1533. self._nodeid_autousenames.setdefault(nodeid or "", []).append(name)
  1534. @overload
  1535. def parsefactories(
  1536. self,
  1537. node_or_obj: nodes.Node,
  1538. ) -> None:
  1539. raise NotImplementedError()
  1540. @overload
  1541. def parsefactories(
  1542. self,
  1543. node_or_obj: object,
  1544. nodeid: str | None,
  1545. ) -> None:
  1546. raise NotImplementedError()
  1547. def parsefactories(
  1548. self,
  1549. node_or_obj: nodes.Node | object,
  1550. nodeid: str | NotSetType | None = NOTSET,
  1551. ) -> None:
  1552. """Collect fixtures from a collection node or object.
  1553. Found fixtures are parsed into `FixtureDef`s and saved.
  1554. If `node_or_object` is a collection node (with an underlying Python
  1555. object), the node's object is traversed and the node's nodeid is used to
  1556. determine the fixtures' visibility. `nodeid` must not be specified in
  1557. this case.
  1558. If `node_or_object` is an object (e.g. a plugin), the object is
  1559. traversed and the given `nodeid` is used to determine the fixtures'
  1560. visibility. `nodeid` must be specified in this case; None and "" mean
  1561. total visibility.
  1562. """
  1563. if nodeid is not NOTSET:
  1564. holderobj = node_or_obj
  1565. else:
  1566. assert isinstance(node_or_obj, nodes.Node)
  1567. holderobj = cast(object, node_or_obj.obj) # type: ignore[attr-defined]
  1568. assert isinstance(node_or_obj.nodeid, str)
  1569. nodeid = node_or_obj.nodeid
  1570. if holderobj in self._holderobjseen:
  1571. return
  1572. # Avoid accessing `@property` (and other descriptors) when iterating fixtures.
  1573. if not safe_isclass(holderobj) and not isinstance(holderobj, types.ModuleType):
  1574. holderobj_tp: object = type(holderobj)
  1575. else:
  1576. holderobj_tp = holderobj
  1577. self._holderobjseen.add(holderobj)
  1578. for name in dir(holderobj):
  1579. # The attribute can be an arbitrary descriptor, so the attribute
  1580. # access below can raise. safe_getattr() ignores such exceptions.
  1581. obj_ub = safe_getattr(holderobj_tp, name, None)
  1582. if type(obj_ub) is FixtureFunctionDefinition:
  1583. marker = obj_ub._fixture_function_marker
  1584. if marker.name:
  1585. fixture_name = marker.name
  1586. else:
  1587. fixture_name = name
  1588. # OK we know it is a fixture -- now safe to look up on the _instance_.
  1589. try:
  1590. obj = getattr(holderobj, name)
  1591. # if the fixture is named in the decorator we cannot find it in the module
  1592. except AttributeError:
  1593. obj = obj_ub
  1594. func = obj._get_wrapped_function()
  1595. self._register_fixture(
  1596. name=fixture_name,
  1597. nodeid=nodeid,
  1598. func=func,
  1599. scope=marker.scope,
  1600. params=marker.params,
  1601. ids=marker.ids,
  1602. autouse=marker.autouse,
  1603. )
  1604. def getfixturedefs(
  1605. self, argname: str, node: nodes.Node
  1606. ) -> Sequence[FixtureDef[Any]] | None:
  1607. """Get FixtureDefs for a fixture name which are applicable
  1608. to a given node.
  1609. Returns None if there are no fixtures at all defined with the given
  1610. name. (This is different from the case in which there are fixtures
  1611. with the given name, but none applicable to the node. In this case,
  1612. an empty result is returned).
  1613. :param argname: Name of the fixture to search for.
  1614. :param node: The requesting Node.
  1615. """
  1616. try:
  1617. fixturedefs = self._arg2fixturedefs[argname]
  1618. except KeyError:
  1619. return None
  1620. return tuple(self._matchfactories(fixturedefs, node))
  1621. def _matchfactories(
  1622. self, fixturedefs: Iterable[FixtureDef[Any]], node: nodes.Node
  1623. ) -> Iterator[FixtureDef[Any]]:
  1624. parentnodeids = {n.nodeid for n in node.iter_parents()}
  1625. for fixturedef in fixturedefs:
  1626. if fixturedef.baseid in parentnodeids:
  1627. yield fixturedef
  1628. def show_fixtures_per_test(config: Config) -> int | ExitCode:
  1629. from _pytest.main import wrap_session
  1630. return wrap_session(config, _show_fixtures_per_test)
  1631. _PYTEST_DIR = Path(_pytest.__file__).parent
  1632. def _pretty_fixture_path(invocation_dir: Path, func) -> str:
  1633. loc = Path(getlocation(func, invocation_dir))
  1634. prefix = Path("...", "_pytest")
  1635. try:
  1636. return str(prefix / loc.relative_to(_PYTEST_DIR))
  1637. except ValueError:
  1638. return bestrelpath(invocation_dir, loc)
  1639. def _show_fixtures_per_test(config: Config, session: Session) -> None:
  1640. import _pytest.config
  1641. session.perform_collect()
  1642. invocation_dir = config.invocation_params.dir
  1643. tw = _pytest.config.create_terminal_writer(config)
  1644. verbose = config.get_verbosity()
  1645. def get_best_relpath(func) -> str:
  1646. loc = getlocation(func, invocation_dir)
  1647. return bestrelpath(invocation_dir, Path(loc))
  1648. def write_fixture(fixture_def: FixtureDef[object]) -> None:
  1649. argname = fixture_def.argname
  1650. if verbose <= 0 and argname.startswith("_"):
  1651. return
  1652. prettypath = _pretty_fixture_path(invocation_dir, fixture_def.func)
  1653. tw.write(f"{argname}", green=True)
  1654. tw.write(f" -- {prettypath}", yellow=True)
  1655. tw.write("\n")
  1656. fixture_doc = inspect.getdoc(fixture_def.func)
  1657. if fixture_doc:
  1658. write_docstring(
  1659. tw,
  1660. fixture_doc.split("\n\n", maxsplit=1)[0]
  1661. if verbose <= 0
  1662. else fixture_doc,
  1663. )
  1664. else:
  1665. tw.line(" no docstring available", red=True)
  1666. def write_item(item: nodes.Item) -> None:
  1667. # Not all items have _fixtureinfo attribute.
  1668. info: FuncFixtureInfo | None = getattr(item, "_fixtureinfo", None)
  1669. if info is None or not info.name2fixturedefs:
  1670. # This test item does not use any fixtures.
  1671. return
  1672. tw.line()
  1673. tw.sep("-", f"fixtures used by {item.name}")
  1674. # TODO: Fix this type ignore.
  1675. tw.sep("-", f"({get_best_relpath(item.function)})") # type: ignore[attr-defined]
  1676. # dict key not used in loop but needed for sorting.
  1677. for _, fixturedefs in sorted(info.name2fixturedefs.items()):
  1678. assert fixturedefs is not None
  1679. if not fixturedefs:
  1680. continue
  1681. # Last item is expected to be the one used by the test item.
  1682. write_fixture(fixturedefs[-1])
  1683. for session_item in session.items:
  1684. write_item(session_item)
  1685. def showfixtures(config: Config) -> int | ExitCode:
  1686. from _pytest.main import wrap_session
  1687. return wrap_session(config, _showfixtures_main)
  1688. def _showfixtures_main(config: Config, session: Session) -> None:
  1689. import _pytest.config
  1690. session.perform_collect()
  1691. invocation_dir = config.invocation_params.dir
  1692. tw = _pytest.config.create_terminal_writer(config)
  1693. verbose = config.get_verbosity()
  1694. fm = session._fixturemanager
  1695. available = []
  1696. seen: set[tuple[str, str]] = set()
  1697. for argname, fixturedefs in fm._arg2fixturedefs.items():
  1698. assert fixturedefs is not None
  1699. if not fixturedefs:
  1700. continue
  1701. for fixturedef in fixturedefs:
  1702. loc = getlocation(fixturedef.func, invocation_dir)
  1703. if (fixturedef.argname, loc) in seen:
  1704. continue
  1705. seen.add((fixturedef.argname, loc))
  1706. available.append(
  1707. (
  1708. len(fixturedef.baseid),
  1709. fixturedef.func.__module__,
  1710. _pretty_fixture_path(invocation_dir, fixturedef.func),
  1711. fixturedef.argname,
  1712. fixturedef,
  1713. )
  1714. )
  1715. available.sort()
  1716. currentmodule = None
  1717. for baseid, module, prettypath, argname, fixturedef in available:
  1718. if currentmodule != module:
  1719. if not module.startswith("_pytest."):
  1720. tw.line()
  1721. tw.sep("-", f"fixtures defined from {module}")
  1722. currentmodule = module
  1723. if verbose <= 0 and argname.startswith("_"):
  1724. continue
  1725. tw.write(f"{argname}", green=True)
  1726. if fixturedef.scope != "function":
  1727. tw.write(f" [{fixturedef.scope} scope]", cyan=True)
  1728. tw.write(f" -- {prettypath}", yellow=True)
  1729. tw.write("\n")
  1730. doc = inspect.getdoc(fixturedef.func)
  1731. if doc:
  1732. write_docstring(
  1733. tw, doc.split("\n\n", maxsplit=1)[0] if verbose <= 0 else doc
  1734. )
  1735. else:
  1736. tw.line(" no docstring available", red=True)
  1737. tw.line()
  1738. def write_docstring(tw: TerminalWriter, doc: str, indent: str = " ") -> None:
  1739. for line in doc.split("\n"):
  1740. tw.line(indent + line)