Coverage for /opt/homebrew/lib/python3.11/site-packages/_pytest/fixtures.py: 62%

820 statements  

« prev     ^ index     » next       coverage.py v7.2.3, created at 2023-05-04 13:14 +0700

1import functools 

2import inspect 

3import os 

4import sys 

5import warnings 

6from collections import defaultdict 

7from collections import deque 

8from contextlib import suppress 

9from pathlib import Path 

10from types import TracebackType 

11from typing import Any 

12from typing import Callable 

13from typing import cast 

14from typing import Dict 

15from typing import Generator 

16from typing import Generic 

17from typing import Iterable 

18from typing import Iterator 

19from typing import List 

20from typing import MutableMapping 

21from typing import NoReturn 

22from typing import Optional 

23from typing import Sequence 

24from typing import Set 

25from typing import Tuple 

26from typing import Type 

27from typing import TYPE_CHECKING 

28from typing import TypeVar 

29from typing import Union 

30 

31import attr 

32 

33import _pytest 

34from _pytest import nodes 

35from _pytest._code import getfslineno 

36from _pytest._code.code import FormattedExcinfo 

37from _pytest._code.code import TerminalRepr 

38from _pytest._io import TerminalWriter 

39from _pytest.compat import _format_args 

40from _pytest.compat import _PytestWrapper 

41from _pytest.compat import assert_never 

42from _pytest.compat import final 

43from _pytest.compat import get_real_func 

44from _pytest.compat import get_real_method 

45from _pytest.compat import getfuncargnames 

46from _pytest.compat import getimfunc 

47from _pytest.compat import getlocation 

48from _pytest.compat import is_generator 

49from _pytest.compat import NOTSET 

50from _pytest.compat import overload 

51from _pytest.compat import safe_getattr 

52from _pytest.config import _PluggyPlugin 

53from _pytest.config import Config 

54from _pytest.config.argparsing import Parser 

55from _pytest.deprecated import check_ispytest 

56from _pytest.deprecated import YIELD_FIXTURE 

57from _pytest.mark import Mark 

58from _pytest.mark import ParameterSet 

59from _pytest.mark.structures import MarkDecorator 

60from _pytest.outcomes import fail 

61from _pytest.outcomes import skip 

62from _pytest.outcomes import TEST_OUTCOME 

63from _pytest.pathlib import absolutepath 

64from _pytest.pathlib import bestrelpath 

65from _pytest.scope import HIGH_SCOPES 

66from _pytest.scope import Scope 

67from _pytest.stash import StashKey 

68 

69 

70if TYPE_CHECKING: 

71 from typing import Deque 

72 

73 from _pytest.scope import _ScopeName 

74 from _pytest.main import Session 

75 from _pytest.python import CallSpec2 

76 from _pytest.python import Metafunc 

77 

78 

79# The value of the fixture -- return/yield of the fixture function (type variable). 

80FixtureValue = TypeVar("FixtureValue") 

81# The type of the fixture function (type variable). 

82FixtureFunction = TypeVar("FixtureFunction", bound=Callable[..., object]) 

83# The type of a fixture function (type alias generic in fixture value). 

84_FixtureFunc = Union[ 

85 Callable[..., FixtureValue], Callable[..., Generator[FixtureValue, None, None]] 

86] 

87# The type of FixtureDef.cached_result (type alias generic in fixture value). 

88_FixtureCachedResult = Union[ 

89 Tuple[ 

90 # The result. 

91 FixtureValue, 

92 # Cache key. 

93 object, 

94 None, 

95 ], 

96 Tuple[ 

97 None, 

98 # Cache key. 

99 object, 

100 # Exc info if raised. 

101 Tuple[Type[BaseException], BaseException, TracebackType], 

102 ], 

103] 

104 

105 

106@attr.s(frozen=True, auto_attribs=True) 

107class PseudoFixtureDef(Generic[FixtureValue]): 

108 cached_result: "_FixtureCachedResult[FixtureValue]" 

109 _scope: Scope 

110 

111 

112def pytest_sessionstart(session: "Session") -> None: 

113 session._fixturemanager = FixtureManager(session) 

114 

115 

116def get_scope_package(node, fixturedef: "FixtureDef[object]"): 

117 import pytest 

118 

119 cls = pytest.Package 

120 current = node 

121 fixture_package_name = "{}/{}".format(fixturedef.baseid, "__init__.py") 

122 while current and ( 

123 type(current) is not cls or fixture_package_name != current.nodeid 

124 ): 

125 current = current.parent 

126 if current is None: 

127 return node.session 

128 return current 

129 

130 

131def get_scope_node( 

132 node: nodes.Node, scope: Scope 

133) -> Optional[Union[nodes.Item, nodes.Collector]]: 

134 import _pytest.python 

135 

136 if scope is Scope.Function: 

137 return node.getparent(nodes.Item) 

138 elif scope is Scope.Class: 

139 return node.getparent(_pytest.python.Class) 

140 elif scope is Scope.Module: 

141 return node.getparent(_pytest.python.Module) 

142 elif scope is Scope.Package: 

143 return node.getparent(_pytest.python.Package) 

144 elif scope is Scope.Session: 

145 return node.getparent(_pytest.main.Session) 

146 else: 

147 assert_never(scope) 

148 

149 

150# Used for storing artificial fixturedefs for direct parametrization. 

151name2pseudofixturedef_key = StashKey[Dict[str, "FixtureDef[Any]"]]() 

152 

153 

154def add_funcarg_pseudo_fixture_def( 

155 collector: nodes.Collector, metafunc: "Metafunc", fixturemanager: "FixtureManager" 

156) -> None: 

157 # This function will transform all collected calls to functions 

158 # if they use direct funcargs (i.e. direct parametrization) 

159 # because we want later test execution to be able to rely on 

160 # an existing FixtureDef structure for all arguments. 

161 # XXX we can probably avoid this algorithm if we modify CallSpec2 

162 # to directly care for creating the fixturedefs within its methods. 

163 if not metafunc._calls[0].funcargs: 

164 # This function call does not have direct parametrization. 

165 return 

166 # Collect funcargs of all callspecs into a list of values. 

167 arg2params: Dict[str, List[object]] = {} 

168 arg2scope: Dict[str, Scope] = {} 

169 for callspec in metafunc._calls: 

170 for argname, argvalue in callspec.funcargs.items(): 

171 assert argname not in callspec.params 

172 callspec.params[argname] = argvalue 

173 arg2params_list = arg2params.setdefault(argname, []) 

174 callspec.indices[argname] = len(arg2params_list) 

175 arg2params_list.append(argvalue) 

176 if argname not in arg2scope: 

177 scope = callspec._arg2scope.get(argname, Scope.Function) 

178 arg2scope[argname] = scope 

179 callspec.funcargs.clear() 

180 

181 # Register artificial FixtureDef's so that later at test execution 

182 # time we can rely on a proper FixtureDef to exist for fixture setup. 

183 arg2fixturedefs = metafunc._arg2fixturedefs 

184 for argname, valuelist in arg2params.items(): 

185 # If we have a scope that is higher than function, we need 

186 # to make sure we only ever create an according fixturedef on 

187 # a per-scope basis. We thus store and cache the fixturedef on the 

188 # node related to the scope. 

189 scope = arg2scope[argname] 

190 node = None 

191 if scope is not Scope.Function: 

192 node = get_scope_node(collector, scope) 

193 if node is None: 

194 assert scope is Scope.Class and isinstance( 

195 collector, _pytest.python.Module 

196 ) 

197 # Use module-level collector for class-scope (for now). 

198 node = collector 

199 if node is None: 

200 name2pseudofixturedef = None 

201 else: 

202 default: Dict[str, FixtureDef[Any]] = {} 

203 name2pseudofixturedef = node.stash.setdefault( 

204 name2pseudofixturedef_key, default 

205 ) 

206 if name2pseudofixturedef is not None and argname in name2pseudofixturedef: 

207 arg2fixturedefs[argname] = [name2pseudofixturedef[argname]] 

208 else: 

209 fixturedef = FixtureDef( 

210 fixturemanager=fixturemanager, 

211 baseid="", 

212 argname=argname, 

213 func=get_direct_param_fixture_func, 

214 scope=arg2scope[argname], 

215 params=valuelist, 

216 unittest=False, 

217 ids=None, 

218 ) 

219 arg2fixturedefs[argname] = [fixturedef] 

220 if name2pseudofixturedef is not None: 

221 name2pseudofixturedef[argname] = fixturedef 

222 

223 

224def getfixturemarker(obj: object) -> Optional["FixtureFunctionMarker"]: 

225 """Return fixturemarker or None if it doesn't exist or raised 

226 exceptions.""" 

227 return cast( 

228 Optional[FixtureFunctionMarker], 

229 safe_getattr(obj, "_pytestfixturefunction", None), 

230 ) 

231 

232 

233# Parametrized fixture key, helper alias for code below. 

234_Key = Tuple[object, ...] 

235 

236 

237def get_parametrized_fixture_keys(item: nodes.Item, scope: Scope) -> Iterator[_Key]: 

238 """Return list of keys for all parametrized arguments which match 

239 the specified scope.""" 

240 assert scope is not Scope.Function 

241 try: 

242 callspec = item.callspec # type: ignore[attr-defined] 

243 except AttributeError: 

244 pass 

245 else: 

246 cs: CallSpec2 = callspec 

247 # cs.indices.items() is random order of argnames. Need to 

248 # sort this so that different calls to 

249 # get_parametrized_fixture_keys will be deterministic. 

250 for argname, param_index in sorted(cs.indices.items()): 

251 if cs._arg2scope[argname] != scope: 

252 continue 

253 if scope is Scope.Session: 

254 key: _Key = (argname, param_index) 

255 elif scope is Scope.Package: 

256 key = (argname, param_index, item.path.parent) 

257 elif scope is Scope.Module: 

258 key = (argname, param_index, item.path) 

259 elif scope is Scope.Class: 

260 item_cls = item.cls # type: ignore[attr-defined] 

261 key = (argname, param_index, item.path, item_cls) 

262 else: 

263 assert_never(scope) 

264 yield key 

265 

266 

267# Algorithm for sorting on a per-parametrized resource setup basis. 

268# It is called for Session scope first and performs sorting 

269# down to the lower scopes such as to minimize number of "high scope" 

270# setups and teardowns. 

271 

272 

273def reorder_items(items: Sequence[nodes.Item]) -> List[nodes.Item]: 

274 argkeys_cache: Dict[Scope, Dict[nodes.Item, Dict[_Key, None]]] = {} 

275 items_by_argkey: Dict[Scope, Dict[_Key, Deque[nodes.Item]]] = {} 

276 for scope in HIGH_SCOPES: 

277 d: Dict[nodes.Item, Dict[_Key, None]] = {} 

278 argkeys_cache[scope] = d 

279 item_d: Dict[_Key, Deque[nodes.Item]] = defaultdict(deque) 

280 items_by_argkey[scope] = item_d 

281 for item in items: 

282 keys = dict.fromkeys(get_parametrized_fixture_keys(item, scope), None) 

283 if keys: 

284 d[item] = keys 

285 for key in keys: 

286 item_d[key].append(item) 

287 items_dict = dict.fromkeys(items, None) 

288 return list( 

289 reorder_items_atscope(items_dict, argkeys_cache, items_by_argkey, Scope.Session) 

290 ) 

291 

292 

293def fix_cache_order( 

294 item: nodes.Item, 

295 argkeys_cache: Dict[Scope, Dict[nodes.Item, Dict[_Key, None]]], 

296 items_by_argkey: Dict[Scope, Dict[_Key, "Deque[nodes.Item]"]], 

297) -> None: 

298 for scope in HIGH_SCOPES: 

299 for key in argkeys_cache[scope].get(item, []): 

300 items_by_argkey[scope][key].appendleft(item) 

301 

302 

303def reorder_items_atscope( 

304 items: Dict[nodes.Item, None], 

305 argkeys_cache: Dict[Scope, Dict[nodes.Item, Dict[_Key, None]]], 

306 items_by_argkey: Dict[Scope, Dict[_Key, "Deque[nodes.Item]"]], 

307 scope: Scope, 

308) -> Dict[nodes.Item, None]: 

309 if scope is Scope.Function or len(items) < 3: 

310 return items 

311 ignore: Set[Optional[_Key]] = set() 

312 items_deque = deque(items) 

313 items_done: Dict[nodes.Item, None] = {} 

314 scoped_items_by_argkey = items_by_argkey[scope] 

315 scoped_argkeys_cache = argkeys_cache[scope] 

316 while items_deque: 

317 no_argkey_group: Dict[nodes.Item, None] = {} 

318 slicing_argkey = None 

319 while items_deque: 

320 item = items_deque.popleft() 

321 if item in items_done or item in no_argkey_group: 

322 continue 

323 argkeys = dict.fromkeys( 

324 (k for k in scoped_argkeys_cache.get(item, []) if k not in ignore), None 

325 ) 

326 if not argkeys: 

327 no_argkey_group[item] = None 

328 else: 

329 slicing_argkey, _ = argkeys.popitem() 

330 # We don't have to remove relevant items from later in the 

331 # deque because they'll just be ignored. 

332 matching_items = [ 

333 i for i in scoped_items_by_argkey[slicing_argkey] if i in items 

334 ] 

335 for i in reversed(matching_items): 

336 fix_cache_order(i, argkeys_cache, items_by_argkey) 

337 items_deque.appendleft(i) 

338 break 

339 if no_argkey_group: 

340 no_argkey_group = reorder_items_atscope( 

341 no_argkey_group, argkeys_cache, items_by_argkey, scope.next_lower() 

342 ) 

343 for item in no_argkey_group: 

344 items_done[item] = None 

345 ignore.add(slicing_argkey) 

346 return items_done 

347 

348 

349def get_direct_param_fixture_func(request: "FixtureRequest") -> Any: 

350 return request.param 

351 

352 

353@attr.s(slots=True, auto_attribs=True) 

354class FuncFixtureInfo: 

355 # Original function argument names. 

356 argnames: Tuple[str, ...] 

357 # Argnames that function immediately requires. These include argnames + 

358 # fixture names specified via usefixtures and via autouse=True in fixture 

359 # definitions. 

360 initialnames: Tuple[str, ...] 

361 names_closure: List[str] 

362 name2fixturedefs: Dict[str, Sequence["FixtureDef[Any]"]] 

363 

364 def prune_dependency_tree(self) -> None: 

365 """Recompute names_closure from initialnames and name2fixturedefs. 

366 

367 Can only reduce names_closure, which means that the new closure will 

368 always be a subset of the old one. The order is preserved. 

369 

370 This method is needed because direct parametrization may shadow some 

371 of the fixtures that were included in the originally built dependency 

372 tree. In this way the dependency tree can get pruned, and the closure 

373 of argnames may get reduced. 

374 """ 

375 closure: Set[str] = set() 

376 working_set = set(self.initialnames) 

377 while working_set: 

378 argname = working_set.pop() 

379 # Argname may be smth not included in the original names_closure, 

380 # in which case we ignore it. This currently happens with pseudo 

381 # FixtureDefs which wrap 'get_direct_param_fixture_func(request)'. 

382 # So they introduce the new dependency 'request' which might have 

383 # been missing in the original tree (closure). 

384 if argname not in closure and argname in self.names_closure: 

385 closure.add(argname) 

386 if argname in self.name2fixturedefs: 

387 working_set.update(self.name2fixturedefs[argname][-1].argnames) 

388 

389 self.names_closure[:] = sorted(closure, key=self.names_closure.index) 

390 

391 

392class FixtureRequest: 

393 """A request for a fixture from a test or fixture function. 

394 

395 A request object gives access to the requesting test context and has 

396 an optional ``param`` attribute in case the fixture is parametrized 

397 indirectly. 

398 """ 

399 

400 def __init__(self, pyfuncitem, *, _ispytest: bool = False) -> None: 

401 check_ispytest(_ispytest) 

402 self._pyfuncitem = pyfuncitem 

403 #: Fixture for which this request is being performed. 

404 self.fixturename: Optional[str] = None 

405 self._scope = Scope.Function 

406 self._fixture_defs: Dict[str, FixtureDef[Any]] = {} 

407 fixtureinfo: FuncFixtureInfo = pyfuncitem._fixtureinfo 

408 self._arg2fixturedefs = fixtureinfo.name2fixturedefs.copy() 

409 self._arg2index: Dict[str, int] = {} 

410 self._fixturemanager: FixtureManager = pyfuncitem.session._fixturemanager 

411 # Notes on the type of `param`: 

412 # -`request.param` is only defined in parametrized fixtures, and will raise 

413 # AttributeError otherwise. Python typing has no notion of "undefined", so 

414 # this cannot be reflected in the type. 

415 # - Technically `param` is only (possibly) defined on SubRequest, not 

416 # FixtureRequest, but the typing of that is still in flux so this cheats. 

417 # - In the future we might consider using a generic for the param type, but 

418 # for now just using Any. 

419 self.param: Any 

420 

421 @property 

422 def scope(self) -> "_ScopeName": 

423 """Scope string, one of "function", "class", "module", "package", "session".""" 

424 return self._scope.value 

425 

426 @property 

427 def fixturenames(self) -> List[str]: 

428 """Names of all active fixtures in this request.""" 

429 result = list(self._pyfuncitem._fixtureinfo.names_closure) 

430 result.extend(set(self._fixture_defs).difference(result)) 

431 return result 

432 

433 @property 

434 def node(self): 

435 """Underlying collection node (depends on current request scope).""" 

436 return self._getscopeitem(self._scope) 

437 

438 def _getnextfixturedef(self, argname: str) -> "FixtureDef[Any]": 

439 fixturedefs = self._arg2fixturedefs.get(argname, None) 

440 if fixturedefs is None: 

441 # We arrive here because of a dynamic call to 

442 # getfixturevalue(argname) usage which was naturally 

443 # not known at parsing/collection time. 

444 assert self._pyfuncitem.parent is not None 

445 parentid = self._pyfuncitem.parent.nodeid 

446 fixturedefs = self._fixturemanager.getfixturedefs(argname, parentid) 

447 # TODO: Fix this type ignore. Either add assert or adjust types. 

448 # Can this be None here? 

449 self._arg2fixturedefs[argname] = fixturedefs # type: ignore[assignment] 

450 # fixturedefs list is immutable so we maintain a decreasing index. 

451 index = self._arg2index.get(argname, 0) - 1 

452 if fixturedefs is None or (-index > len(fixturedefs)): 

453 raise FixtureLookupError(argname, self) 

454 self._arg2index[argname] = index 

455 return fixturedefs[index] 

456 

457 @property 

458 def config(self) -> Config: 

459 """The pytest config object associated with this request.""" 

460 return self._pyfuncitem.config # type: ignore[no-any-return] 

461 

462 @property 

463 def function(self): 

464 """Test function object if the request has a per-function scope.""" 

465 if self.scope != "function": 

466 raise AttributeError( 

467 f"function not available in {self.scope}-scoped context" 

468 ) 

469 return self._pyfuncitem.obj 

470 

471 @property 

472 def cls(self): 

473 """Class (can be None) where the test function was collected.""" 

474 if self.scope not in ("class", "function"): 

475 raise AttributeError(f"cls not available in {self.scope}-scoped context") 

476 clscol = self._pyfuncitem.getparent(_pytest.python.Class) 

477 if clscol: 

478 return clscol.obj 

479 

480 @property 

481 def instance(self): 

482 """Instance (can be None) on which test function was collected.""" 

483 # unittest support hack, see _pytest.unittest.TestCaseFunction. 

484 try: 

485 return self._pyfuncitem._testcase 

486 except AttributeError: 

487 function = getattr(self, "function", None) 

488 return getattr(function, "__self__", None) 

489 

490 @property 

491 def module(self): 

492 """Python module object where the test function was collected.""" 

493 if self.scope not in ("function", "class", "module"): 

494 raise AttributeError(f"module not available in {self.scope}-scoped context") 

495 return self._pyfuncitem.getparent(_pytest.python.Module).obj 

496 

497 @property 

498 def path(self) -> Path: 

499 """Path where the test function was collected.""" 

500 if self.scope not in ("function", "class", "module", "package"): 

501 raise AttributeError(f"path not available in {self.scope}-scoped context") 

502 # TODO: Remove ignore once _pyfuncitem is properly typed. 

503 return self._pyfuncitem.path # type: ignore 

504 

505 @property 

506 def keywords(self) -> MutableMapping[str, Any]: 

507 """Keywords/markers dictionary for the underlying node.""" 

508 node: nodes.Node = self.node 

509 return node.keywords 

510 

511 @property 

512 def session(self) -> "Session": 

513 """Pytest session object.""" 

514 return self._pyfuncitem.session # type: ignore[no-any-return] 

515 

516 def addfinalizer(self, finalizer: Callable[[], object]) -> None: 

517 """Add finalizer/teardown function to be called without arguments after 

518 the last test within the requesting test context finished execution.""" 

519 # XXX usually this method is shadowed by fixturedef specific ones. 

520 self._addfinalizer(finalizer, scope=self.scope) 

521 

522 def _addfinalizer(self, finalizer: Callable[[], object], scope) -> None: 

523 node = self._getscopeitem(scope) 

524 node.addfinalizer(finalizer) 

525 

526 def applymarker(self, marker: Union[str, MarkDecorator]) -> None: 

527 """Apply a marker to a single test function invocation. 

528 

529 This method is useful if you don't want to have a keyword/marker 

530 on all function invocations. 

531 

532 :param marker: 

533 An object created by a call to ``pytest.mark.NAME(...)``. 

534 """ 

535 self.node.add_marker(marker) 

536 

537 def raiseerror(self, msg: Optional[str]) -> NoReturn: 

538 """Raise a FixtureLookupError exception. 

539 

540 :param msg: 

541 An optional custom error message. 

542 """ 

543 raise self._fixturemanager.FixtureLookupError(None, self, msg) 

544 

545 def _fillfixtures(self) -> None: 

546 item = self._pyfuncitem 

547 fixturenames = getattr(item, "fixturenames", self.fixturenames) 

548 for argname in fixturenames: 

549 if argname not in item.funcargs: 

550 item.funcargs[argname] = self.getfixturevalue(argname) 

551 

552 def getfixturevalue(self, argname: str) -> Any: 

553 """Dynamically run a named fixture function. 

554 

555 Declaring fixtures via function argument is recommended where possible. 

556 But if you can only decide whether to use another fixture at test 

557 setup time, you may use this function to retrieve it inside a fixture 

558 or test function body. 

559 

560 This method can be used during the test setup phase or the test run 

561 phase, but during the test teardown phase a fixture's value may not 

562 be available. 

563 

564 :param argname: 

565 The fixture name. 

566 :raises pytest.FixtureLookupError: 

567 If the given fixture could not be found. 

568 """ 

569 fixturedef = self._get_active_fixturedef(argname) 

570 assert fixturedef.cached_result is not None, ( 

571 f'The fixture value for "{argname}" is not available. ' 

572 "This can happen when the fixture has already been torn down." 

573 ) 

574 return fixturedef.cached_result[0] 

575 

576 def _get_active_fixturedef( 

577 self, argname: str 

578 ) -> Union["FixtureDef[object]", PseudoFixtureDef[object]]: 

579 try: 

580 return self._fixture_defs[argname] 

581 except KeyError: 

582 try: 

583 fixturedef = self._getnextfixturedef(argname) 

584 except FixtureLookupError: 

585 if argname == "request": 

586 cached_result = (self, [0], None) 

587 return PseudoFixtureDef(cached_result, Scope.Function) 

588 raise 

589 # Remove indent to prevent the python3 exception 

590 # from leaking into the call. 

591 self._compute_fixture_value(fixturedef) 

592 self._fixture_defs[argname] = fixturedef 

593 return fixturedef 

594 

595 def _get_fixturestack(self) -> List["FixtureDef[Any]"]: 

596 current = self 

597 values: List[FixtureDef[Any]] = [] 

598 while isinstance(current, SubRequest): 

599 values.append(current._fixturedef) # type: ignore[has-type] 

600 current = current._parent_request 

601 values.reverse() 

602 return values 

603 

604 def _compute_fixture_value(self, fixturedef: "FixtureDef[object]") -> None: 

605 """Create a SubRequest based on "self" and call the execute method 

606 of the given FixtureDef object. 

607 

608 This will force the FixtureDef object to throw away any previous 

609 results and compute a new fixture value, which will be stored into 

610 the FixtureDef object itself. 

611 """ 

612 # prepare a subrequest object before calling fixture function 

613 # (latter managed by fixturedef) 

614 argname = fixturedef.argname 

615 funcitem = self._pyfuncitem 

616 scope = fixturedef._scope 

617 try: 

618 callspec = funcitem.callspec 

619 except AttributeError: 

620 callspec = None 

621 if callspec is not None and argname in callspec.params: 

622 param = callspec.params[argname] 

623 param_index = callspec.indices[argname] 

624 # If a parametrize invocation set a scope it will override 

625 # the static scope defined with the fixture function. 

626 with suppress(KeyError): 

627 scope = callspec._arg2scope[argname] 

628 else: 

629 param = NOTSET 

630 param_index = 0 

631 has_params = fixturedef.params is not None 

632 fixtures_not_supported = getattr(funcitem, "nofuncargs", False) 

633 if has_params and fixtures_not_supported: 

634 msg = ( 

635 "{name} does not support fixtures, maybe unittest.TestCase subclass?\n" 

636 "Node id: {nodeid}\n" 

637 "Function type: {typename}" 

638 ).format( 

639 name=funcitem.name, 

640 nodeid=funcitem.nodeid, 

641 typename=type(funcitem).__name__, 

642 ) 

643 fail(msg, pytrace=False) 

644 if has_params: 

645 frame = inspect.stack()[3] 

646 frameinfo = inspect.getframeinfo(frame[0]) 

647 source_path = absolutepath(frameinfo.filename) 

648 source_lineno = frameinfo.lineno 

649 try: 

650 source_path_str = str( 

651 source_path.relative_to(funcitem.config.rootpath) 

652 ) 

653 except ValueError: 

654 source_path_str = str(source_path) 

655 msg = ( 

656 "The requested fixture has no parameter defined for test:\n" 

657 " {}\n\n" 

658 "Requested fixture '{}' defined in:\n{}" 

659 "\n\nRequested here:\n{}:{}".format( 

660 funcitem.nodeid, 

661 fixturedef.argname, 

662 getlocation(fixturedef.func, funcitem.config.rootpath), 

663 source_path_str, 

664 source_lineno, 

665 ) 

666 ) 

667 fail(msg, pytrace=False) 

668 

669 subrequest = SubRequest( 

670 self, scope, param, param_index, fixturedef, _ispytest=True 

671 ) 

672 

673 # Check if a higher-level scoped fixture accesses a lower level one. 

674 subrequest._check_scope(argname, self._scope, scope) 

675 try: 

676 # Call the fixture function. 

677 fixturedef.execute(request=subrequest) 

678 finally: 

679 self._schedule_finalizers(fixturedef, subrequest) 

680 

681 def _schedule_finalizers( 

682 self, fixturedef: "FixtureDef[object]", subrequest: "SubRequest" 

683 ) -> None: 

684 # If fixture function failed it might have registered finalizers. 

685 subrequest.node.addfinalizer(lambda: fixturedef.finish(request=subrequest)) 

686 

687 def _check_scope( 

688 self, 

689 argname: str, 

690 invoking_scope: Scope, 

691 requested_scope: Scope, 

692 ) -> None: 

693 if argname == "request": 

694 return 

695 if invoking_scope > requested_scope: 

696 # Try to report something helpful. 

697 text = "\n".join(self._factorytraceback()) 

698 fail( 

699 f"ScopeMismatch: You tried to access the {requested_scope.value} scoped " 

700 f"fixture {argname} with a {invoking_scope.value} scoped request object, " 

701 f"involved factories:\n{text}", 

702 pytrace=False, 

703 ) 

704 

705 def _factorytraceback(self) -> List[str]: 

706 lines = [] 

707 for fixturedef in self._get_fixturestack(): 

708 factory = fixturedef.func 

709 fs, lineno = getfslineno(factory) 

710 if isinstance(fs, Path): 

711 session: Session = self._pyfuncitem.session 

712 p = bestrelpath(session.path, fs) 

713 else: 

714 p = fs 

715 args = _format_args(factory) 

716 lines.append("%s:%d: def %s%s" % (p, lineno + 1, factory.__name__, args)) 

717 return lines 

718 

719 def _getscopeitem( 

720 self, scope: Union[Scope, "_ScopeName"] 

721 ) -> Union[nodes.Item, nodes.Collector]: 

722 if isinstance(scope, str): 

723 scope = Scope(scope) 

724 if scope is Scope.Function: 

725 # This might also be a non-function Item despite its attribute name. 

726 node: Optional[Union[nodes.Item, nodes.Collector]] = self._pyfuncitem 

727 elif scope is Scope.Package: 

728 # FIXME: _fixturedef is not defined on FixtureRequest (this class), 

729 # but on FixtureRequest (a subclass). 

730 node = get_scope_package(self._pyfuncitem, self._fixturedef) # type: ignore[attr-defined] 

731 else: 

732 node = get_scope_node(self._pyfuncitem, scope) 

733 if node is None and scope is Scope.Class: 

734 # Fallback to function item itself. 

735 node = self._pyfuncitem 

736 assert node, 'Could not obtain a node for scope "{}" for function {!r}'.format( 

737 scope, self._pyfuncitem 

738 ) 

739 return node 

740 

741 def __repr__(self) -> str: 

742 return "<FixtureRequest for %r>" % (self.node) 

743 

744 

745@final 

746class SubRequest(FixtureRequest): 

747 """A sub request for handling getting a fixture from a test function/fixture.""" 

748 

749 def __init__( 

750 self, 

751 request: "FixtureRequest", 

752 scope: Scope, 

753 param: Any, 

754 param_index: int, 

755 fixturedef: "FixtureDef[object]", 

756 *, 

757 _ispytest: bool = False, 

758 ) -> None: 

759 check_ispytest(_ispytest) 

760 self._parent_request = request 

761 self.fixturename = fixturedef.argname 

762 if param is not NOTSET: 

763 self.param = param 

764 self.param_index = param_index 

765 self._scope = scope 

766 self._fixturedef = fixturedef 

767 self._pyfuncitem = request._pyfuncitem 

768 self._fixture_defs = request._fixture_defs 

769 self._arg2fixturedefs = request._arg2fixturedefs 

770 self._arg2index = request._arg2index 

771 self._fixturemanager = request._fixturemanager 

772 

773 def __repr__(self) -> str: 

774 return f"<SubRequest {self.fixturename!r} for {self._pyfuncitem!r}>" 

775 

776 def addfinalizer(self, finalizer: Callable[[], object]) -> None: 

777 """Add finalizer/teardown function to be called without arguments after 

778 the last test within the requesting test context finished execution.""" 

779 self._fixturedef.addfinalizer(finalizer) 

780 

781 def _schedule_finalizers( 

782 self, fixturedef: "FixtureDef[object]", subrequest: "SubRequest" 

783 ) -> None: 

784 # If the executing fixturedef was not explicitly requested in the argument list (via 

785 # getfixturevalue inside the fixture call) then ensure this fixture def will be finished 

786 # first. 

787 if fixturedef.argname not in self.fixturenames: 

788 fixturedef.addfinalizer( 

789 functools.partial(self._fixturedef.finish, request=self) 

790 ) 

791 super()._schedule_finalizers(fixturedef, subrequest) 

792 

793 

794@final 

795class FixtureLookupError(LookupError): 

796 """Could not return a requested fixture (missing or invalid).""" 

797 

798 def __init__( 

799 self, argname: Optional[str], request: FixtureRequest, msg: Optional[str] = None 

800 ) -> None: 

801 self.argname = argname 

802 self.request = request 

803 self.fixturestack = request._get_fixturestack() 

804 self.msg = msg 

805 

806 def formatrepr(self) -> "FixtureLookupErrorRepr": 

807 tblines: List[str] = [] 

808 addline = tblines.append 

809 stack = [self.request._pyfuncitem.obj] 

810 stack.extend(map(lambda x: x.func, self.fixturestack)) 

811 msg = self.msg 

812 if msg is not None: 

813 # The last fixture raise an error, let's present 

814 # it at the requesting side. 

815 stack = stack[:-1] 

816 for function in stack: 

817 fspath, lineno = getfslineno(function) 

818 try: 

819 lines, _ = inspect.getsourcelines(get_real_func(function)) 

820 except (OSError, IndexError, TypeError): 

821 error_msg = "file %s, line %s: source code not available" 

822 addline(error_msg % (fspath, lineno + 1)) 

823 else: 

824 addline(f"file {fspath}, line {lineno + 1}") 

825 for i, line in enumerate(lines): 

826 line = line.rstrip() 

827 addline(" " + line) 

828 if line.lstrip().startswith("def"): 

829 break 

830 

831 if msg is None: 

832 fm = self.request._fixturemanager 

833 available = set() 

834 parentid = self.request._pyfuncitem.parent.nodeid 

835 for name, fixturedefs in fm._arg2fixturedefs.items(): 

836 faclist = list(fm._matchfactories(fixturedefs, parentid)) 

837 if faclist: 

838 available.add(name) 

839 if self.argname in available: 

840 msg = " recursive dependency involving fixture '{}' detected".format( 

841 self.argname 

842 ) 

843 else: 

844 msg = f"fixture '{self.argname}' not found" 

845 msg += "\n available fixtures: {}".format(", ".join(sorted(available))) 

846 msg += "\n use 'pytest --fixtures [testpath]' for help on them." 

847 

848 return FixtureLookupErrorRepr(fspath, lineno, tblines, msg, self.argname) 

849 

850 

851class FixtureLookupErrorRepr(TerminalRepr): 

852 def __init__( 

853 self, 

854 filename: Union[str, "os.PathLike[str]"], 

855 firstlineno: int, 

856 tblines: Sequence[str], 

857 errorstring: str, 

858 argname: Optional[str], 

859 ) -> None: 

860 self.tblines = tblines 

861 self.errorstring = errorstring 

862 self.filename = filename 

863 self.firstlineno = firstlineno 

864 self.argname = argname 

865 

866 def toterminal(self, tw: TerminalWriter) -> None: 

867 # tw.line("FixtureLookupError: %s" %(self.argname), red=True) 

868 for tbline in self.tblines: 

869 tw.line(tbline.rstrip()) 

870 lines = self.errorstring.split("\n") 

871 if lines: 

872 tw.line( 

873 f"{FormattedExcinfo.fail_marker} {lines[0].strip()}", 

874 red=True, 

875 ) 

876 for line in lines[1:]: 

877 tw.line( 

878 f"{FormattedExcinfo.flow_marker} {line.strip()}", 

879 red=True, 

880 ) 

881 tw.line() 

882 tw.line("%s:%d" % (os.fspath(self.filename), self.firstlineno + 1)) 

883 

884 

885def fail_fixturefunc(fixturefunc, msg: str) -> NoReturn: 

886 fs, lineno = getfslineno(fixturefunc) 

887 location = f"{fs}:{lineno + 1}" 

888 source = _pytest._code.Source(fixturefunc) 

889 fail(msg + ":\n\n" + str(source.indent()) + "\n" + location, pytrace=False) 

890 

891 

892def call_fixture_func( 

893 fixturefunc: "_FixtureFunc[FixtureValue]", request: FixtureRequest, kwargs 

894) -> FixtureValue: 

895 if is_generator(fixturefunc): 

896 fixturefunc = cast( 

897 Callable[..., Generator[FixtureValue, None, None]], fixturefunc 

898 ) 

899 generator = fixturefunc(**kwargs) 

900 try: 

901 fixture_result = next(generator) 

902 except StopIteration: 

903 raise ValueError(f"{request.fixturename} did not yield a value") from None 

904 finalizer = functools.partial(_teardown_yield_fixture, fixturefunc, generator) 

905 request.addfinalizer(finalizer) 

906 else: 

907 fixturefunc = cast(Callable[..., FixtureValue], fixturefunc) 

908 fixture_result = fixturefunc(**kwargs) 

909 return fixture_result 

910 

911 

912def _teardown_yield_fixture(fixturefunc, it) -> None: 

913 """Execute the teardown of a fixture function by advancing the iterator 

914 after the yield and ensure the iteration ends (if not it means there is 

915 more than one yield in the function).""" 

916 try: 

917 next(it) 

918 except StopIteration: 

919 pass 

920 else: 

921 fail_fixturefunc(fixturefunc, "fixture function has more than one 'yield'") 

922 

923 

924def _eval_scope_callable( 

925 scope_callable: "Callable[[str, Config], _ScopeName]", 

926 fixture_name: str, 

927 config: Config, 

928) -> "_ScopeName": 

929 try: 

930 # Type ignored because there is no typing mechanism to specify 

931 # keyword arguments, currently. 

932 result = scope_callable(fixture_name=fixture_name, config=config) # type: ignore[call-arg] 

933 except Exception as e: 

934 raise TypeError( 

935 "Error evaluating {} while defining fixture '{}'.\n" 

936 "Expected a function with the signature (*, fixture_name, config)".format( 

937 scope_callable, fixture_name 

938 ) 

939 ) from e 

940 if not isinstance(result, str): 

941 fail( 

942 "Expected {} to return a 'str' while defining fixture '{}', but it returned:\n" 

943 "{!r}".format(scope_callable, fixture_name, result), 

944 pytrace=False, 

945 ) 

946 return result 

947 

948 

949@final 

950class FixtureDef(Generic[FixtureValue]): 

951 """A container for a fixture definition.""" 

952 

953 def __init__( 

954 self, 

955 fixturemanager: "FixtureManager", 

956 baseid: Optional[str], 

957 argname: str, 

958 func: "_FixtureFunc[FixtureValue]", 

959 scope: Union[Scope, "_ScopeName", Callable[[str, Config], "_ScopeName"], None], 

960 params: Optional[Sequence[object]], 

961 unittest: bool = False, 

962 ids: Optional[ 

963 Union[Tuple[Optional[object], ...], Callable[[Any], Optional[object]]] 

964 ] = None, 

965 ) -> None: 

966 self._fixturemanager = fixturemanager 

967 # The "base" node ID for the fixture. 

968 # 

969 # This is a node ID prefix. A fixture is only available to a node (e.g. 

970 # a `Function` item) if the fixture's baseid is a parent of the node's 

971 # nodeid (see the `iterparentnodeids` function for what constitutes a 

972 # "parent" and a "prefix" in this context). 

973 # 

974 # For a fixture found in a Collector's object (e.g. a `Module`s module, 

975 # a `Class`'s class), the baseid is the Collector's nodeid. 

976 # 

977 # For a fixture found in a conftest plugin, the baseid is the conftest's 

978 # directory path relative to the rootdir. 

979 # 

980 # For other plugins, the baseid is the empty string (always matches). 

981 self.baseid = baseid or "" 

982 # Whether the fixture was found from a node or a conftest in the 

983 # collection tree. Will be false for fixtures defined in non-conftest 

984 # plugins. 

985 self.has_location = baseid is not None 

986 # The fixture factory function. 

987 self.func = func 

988 # The name by which the fixture may be requested. 

989 self.argname = argname 

990 if scope is None: 

991 scope = Scope.Function 

992 elif callable(scope): 

993 scope = _eval_scope_callable(scope, argname, fixturemanager.config) 

994 if isinstance(scope, str): 

995 scope = Scope.from_user( 

996 scope, descr=f"Fixture '{func.__name__}'", where=baseid 

997 ) 

998 self._scope = scope 

999 # If the fixture is directly parametrized, the parameter values. 

1000 self.params: Optional[Sequence[object]] = params 

1001 # If the fixture is directly parametrized, a tuple of explicit IDs to 

1002 # assign to the parameter values, or a callable to generate an ID given 

1003 # a parameter value. 

1004 self.ids = ids 

1005 # The names requested by the fixtures. 

1006 self.argnames = getfuncargnames(func, name=argname, is_method=unittest) 

1007 # Whether the fixture was collected from a unittest TestCase class. 

1008 # Note that it really only makes sense to define autouse fixtures in 

1009 # unittest TestCases. 

1010 self.unittest = unittest 

1011 # If the fixture was executed, the current value of the fixture. 

1012 # Can change if the fixture is executed with different parameters. 

1013 self.cached_result: Optional[_FixtureCachedResult[FixtureValue]] = None 

1014 self._finalizers: List[Callable[[], object]] = [] 

1015 

1016 @property 

1017 def scope(self) -> "_ScopeName": 

1018 """Scope string, one of "function", "class", "module", "package", "session".""" 

1019 return self._scope.value 

1020 

1021 def addfinalizer(self, finalizer: Callable[[], object]) -> None: 

1022 self._finalizers.append(finalizer) 

1023 

1024 def finish(self, request: SubRequest) -> None: 

1025 exc = None 

1026 try: 

1027 while self._finalizers: 

1028 try: 

1029 func = self._finalizers.pop() 

1030 func() 

1031 except BaseException as e: 

1032 # XXX Only first exception will be seen by user, 

1033 # ideally all should be reported. 

1034 if exc is None: 

1035 exc = e 

1036 if exc: 

1037 raise exc 

1038 finally: 

1039 ihook = request.node.ihook 

1040 ihook.pytest_fixture_post_finalizer(fixturedef=self, request=request) 

1041 # Even if finalization fails, we invalidate the cached fixture 

1042 # value and remove all finalizers because they may be bound methods 

1043 # which will keep instances alive. 

1044 self.cached_result = None 

1045 self._finalizers = [] 

1046 

1047 def execute(self, request: SubRequest) -> FixtureValue: 

1048 # Get required arguments and register our own finish() 

1049 # with their finalization. 

1050 for argname in self.argnames: 

1051 fixturedef = request._get_active_fixturedef(argname) 

1052 if argname != "request": 

1053 # PseudoFixtureDef is only for "request". 

1054 assert isinstance(fixturedef, FixtureDef) 

1055 fixturedef.addfinalizer(functools.partial(self.finish, request=request)) 

1056 

1057 my_cache_key = self.cache_key(request) 

1058 if self.cached_result is not None: 

1059 # note: comparison with `==` can fail (or be expensive) for e.g. 

1060 # numpy arrays (#6497). 

1061 cache_key = self.cached_result[1] 

1062 if my_cache_key is cache_key: 

1063 if self.cached_result[2] is not None: 

1064 _, val, tb = self.cached_result[2] 

1065 raise val.with_traceback(tb) 

1066 else: 

1067 result = self.cached_result[0] 

1068 return result 

1069 # We have a previous but differently parametrized fixture instance 

1070 # so we need to tear it down before creating a new one. 

1071 self.finish(request) 

1072 assert self.cached_result is None 

1073 

1074 ihook = request.node.ihook 

1075 result = ihook.pytest_fixture_setup(fixturedef=self, request=request) 

1076 return result 

1077 

1078 def cache_key(self, request: SubRequest) -> object: 

1079 return request.param_index if not hasattr(request, "param") else request.param 

1080 

1081 def __repr__(self) -> str: 

1082 return "<FixtureDef argname={!r} scope={!r} baseid={!r}>".format( 

1083 self.argname, self.scope, self.baseid 

1084 ) 

1085 

1086 

1087def resolve_fixture_function( 

1088 fixturedef: FixtureDef[FixtureValue], request: FixtureRequest 

1089) -> "_FixtureFunc[FixtureValue]": 

1090 """Get the actual callable that can be called to obtain the fixture 

1091 value, dealing with unittest-specific instances and bound methods.""" 

1092 fixturefunc = fixturedef.func 

1093 if fixturedef.unittest: 

1094 if request.instance is not None: 

1095 # Bind the unbound method to the TestCase instance. 

1096 fixturefunc = fixturedef.func.__get__(request.instance) # type: ignore[union-attr] 

1097 else: 

1098 # The fixture function needs to be bound to the actual 

1099 # request.instance so that code working with "fixturedef" behaves 

1100 # as expected. 

1101 if request.instance is not None: 

1102 # Handle the case where fixture is defined not in a test class, but some other class 

1103 # (for example a plugin class with a fixture), see #2270. 

1104 if hasattr(fixturefunc, "__self__") and not isinstance( 

1105 request.instance, fixturefunc.__self__.__class__ # type: ignore[union-attr] 

1106 ): 

1107 return fixturefunc 

1108 fixturefunc = getimfunc(fixturedef.func) 

1109 if fixturefunc != fixturedef.func: 

1110 fixturefunc = fixturefunc.__get__(request.instance) # type: ignore[union-attr] 

1111 return fixturefunc 

1112 

1113 

1114def pytest_fixture_setup( 

1115 fixturedef: FixtureDef[FixtureValue], request: SubRequest 

1116) -> FixtureValue: 

1117 """Execution of fixture setup.""" 

1118 kwargs = {} 

1119 for argname in fixturedef.argnames: 

1120 fixdef = request._get_active_fixturedef(argname) 

1121 assert fixdef.cached_result is not None 

1122 result, arg_cache_key, exc = fixdef.cached_result 

1123 request._check_scope(argname, request._scope, fixdef._scope) 

1124 kwargs[argname] = result 

1125 

1126 fixturefunc = resolve_fixture_function(fixturedef, request) 

1127 my_cache_key = fixturedef.cache_key(request) 

1128 try: 

1129 result = call_fixture_func(fixturefunc, request, kwargs) 

1130 except TEST_OUTCOME: 

1131 exc_info = sys.exc_info() 

1132 assert exc_info[0] is not None 

1133 if isinstance( 

1134 exc_info[1], skip.Exception 

1135 ) and not fixturefunc.__name__.startswith("xunit_setup"): 

1136 exc_info[1]._use_item_location = True # type: ignore[attr-defined] 

1137 fixturedef.cached_result = (None, my_cache_key, exc_info) 

1138 raise 

1139 fixturedef.cached_result = (result, my_cache_key, None) 

1140 return result 

1141 

1142 

1143def _ensure_immutable_ids( 

1144 ids: Optional[Union[Sequence[Optional[object]], Callable[[Any], Optional[object]]]] 

1145) -> Optional[Union[Tuple[Optional[object], ...], Callable[[Any], Optional[object]]]]: 

1146 if ids is None: 

1147 return None 

1148 if callable(ids): 

1149 return ids 

1150 return tuple(ids) 

1151 

1152 

1153def _params_converter( 

1154 params: Optional[Iterable[object]], 

1155) -> Optional[Tuple[object, ...]]: 

1156 return tuple(params) if params is not None else None 

1157 

1158 

1159def wrap_function_to_error_out_if_called_directly( 

1160 function: FixtureFunction, 

1161 fixture_marker: "FixtureFunctionMarker", 

1162) -> FixtureFunction: 

1163 """Wrap the given fixture function so we can raise an error about it being called directly, 

1164 instead of used as an argument in a test function.""" 

1165 message = ( 

1166 'Fixture "{name}" called directly. Fixtures are not meant to be called directly,\n' 

1167 "but are created automatically when test functions request them as parameters.\n" 

1168 "See https://docs.pytest.org/en/stable/explanation/fixtures.html for more information about fixtures, and\n" 

1169 "https://docs.pytest.org/en/stable/deprecations.html#calling-fixtures-directly about how to update your code." 

1170 ).format(name=fixture_marker.name or function.__name__) 

1171 

1172 @functools.wraps(function) 

1173 def result(*args, **kwargs): 

1174 fail(message, pytrace=False) 

1175 

1176 # Keep reference to the original function in our own custom attribute so we don't unwrap 

1177 # further than this point and lose useful wrappings like @mock.patch (#3774). 

1178 result.__pytest_wrapped__ = _PytestWrapper(function) # type: ignore[attr-defined] 

1179 

1180 return cast(FixtureFunction, result) 

1181 

1182 

1183@final 

1184@attr.s(frozen=True, auto_attribs=True) 

1185class FixtureFunctionMarker: 

1186 scope: "Union[_ScopeName, Callable[[str, Config], _ScopeName]]" 

1187 params: Optional[Tuple[object, ...]] = attr.ib(converter=_params_converter) 

1188 autouse: bool = False 

1189 ids: Optional[ 

1190 Union[Tuple[Optional[object], ...], Callable[[Any], Optional[object]]] 

1191 ] = attr.ib( 

1192 default=None, 

1193 converter=_ensure_immutable_ids, 

1194 ) 

1195 name: Optional[str] = None 

1196 

1197 def __call__(self, function: FixtureFunction) -> FixtureFunction: 

1198 if inspect.isclass(function): 

1199 raise ValueError("class fixtures not supported (maybe in the future)") 

1200 

1201 if getattr(function, "_pytestfixturefunction", False): 

1202 raise ValueError( 

1203 "fixture is being applied more than once to the same function" 

1204 ) 

1205 

1206 function = wrap_function_to_error_out_if_called_directly(function, self) 

1207 

1208 name = self.name or function.__name__ 

1209 if name == "request": 

1210 location = getlocation(function) 

1211 fail( 

1212 "'request' is a reserved word for fixtures, use another name:\n {}".format( 

1213 location 

1214 ), 

1215 pytrace=False, 

1216 ) 

1217 

1218 # Type ignored because https://github.com/python/mypy/issues/2087. 

1219 function._pytestfixturefunction = self # type: ignore[attr-defined] 

1220 return function 

1221 

1222 

1223@overload 

1224def fixture( 

1225 fixture_function: FixtureFunction, 

1226 *, 

1227 scope: "Union[_ScopeName, Callable[[str, Config], _ScopeName]]" = ..., 

1228 params: Optional[Iterable[object]] = ..., 

1229 autouse: bool = ..., 

1230 ids: Optional[ 

1231 Union[Sequence[Optional[object]], Callable[[Any], Optional[object]]] 

1232 ] = ..., 

1233 name: Optional[str] = ..., 

1234) -> FixtureFunction: 

1235 ... 

1236 

1237 

1238@overload 

1239def fixture( # noqa: F811 

1240 fixture_function: None = ..., 

1241 *, 

1242 scope: "Union[_ScopeName, Callable[[str, Config], _ScopeName]]" = ..., 

1243 params: Optional[Iterable[object]] = ..., 

1244 autouse: bool = ..., 

1245 ids: Optional[ 

1246 Union[Sequence[Optional[object]], Callable[[Any], Optional[object]]] 

1247 ] = ..., 

1248 name: Optional[str] = None, 

1249) -> FixtureFunctionMarker: 

1250 ... 

1251 

1252 

1253def fixture( # noqa: F811 

1254 fixture_function: Optional[FixtureFunction] = None, 

1255 *, 

1256 scope: "Union[_ScopeName, Callable[[str, Config], _ScopeName]]" = "function", 

1257 params: Optional[Iterable[object]] = None, 

1258 autouse: bool = False, 

1259 ids: Optional[ 

1260 Union[Sequence[Optional[object]], Callable[[Any], Optional[object]]] 

1261 ] = None, 

1262 name: Optional[str] = None, 

1263) -> Union[FixtureFunctionMarker, FixtureFunction]: 

1264 """Decorator to mark a fixture factory function. 

1265 

1266 This decorator can be used, with or without parameters, to define a 

1267 fixture function. 

1268 

1269 The name of the fixture function can later be referenced to cause its 

1270 invocation ahead of running tests: test modules or classes can use the 

1271 ``pytest.mark.usefixtures(fixturename)`` marker. 

1272 

1273 Test functions can directly use fixture names as input arguments in which 

1274 case the fixture instance returned from the fixture function will be 

1275 injected. 

1276 

1277 Fixtures can provide their values to test functions using ``return`` or 

1278 ``yield`` statements. When using ``yield`` the code block after the 

1279 ``yield`` statement is executed as teardown code regardless of the test 

1280 outcome, and must yield exactly once. 

1281 

1282 :param scope: 

1283 The scope for which this fixture is shared; one of ``"function"`` 

1284 (default), ``"class"``, ``"module"``, ``"package"`` or ``"session"``. 

1285 

1286 This parameter may also be a callable which receives ``(fixture_name, config)`` 

1287 as parameters, and must return a ``str`` with one of the values mentioned above. 

1288 

1289 See :ref:`dynamic scope` in the docs for more information. 

1290 

1291 :param params: 

1292 An optional list of parameters which will cause multiple invocations 

1293 of the fixture function and all of the tests using it. The current 

1294 parameter is available in ``request.param``. 

1295 

1296 :param autouse: 

1297 If True, the fixture func is activated for all tests that can see it. 

1298 If False (the default), an explicit reference is needed to activate 

1299 the fixture. 

1300 

1301 :param ids: 

1302 Sequence of ids each corresponding to the params so that they are 

1303 part of the test id. If no ids are provided they will be generated 

1304 automatically from the params. 

1305 

1306 :param name: 

1307 The name of the fixture. This defaults to the name of the decorated 

1308 function. If a fixture is used in the same module in which it is 

1309 defined, the function name of the fixture will be shadowed by the 

1310 function arg that requests the fixture; one way to resolve this is to 

1311 name the decorated function ``fixture_<fixturename>`` and then use 

1312 ``@pytest.fixture(name='<fixturename>')``. 

1313 """ 

1314 fixture_marker = FixtureFunctionMarker( 

1315 scope=scope, 

1316 params=params, 

1317 autouse=autouse, 

1318 ids=ids, 

1319 name=name, 

1320 ) 

1321 

1322 # Direct decoration. 

1323 if fixture_function: 

1324 return fixture_marker(fixture_function) 

1325 

1326 return fixture_marker 

1327 

1328 

1329def yield_fixture( 

1330 fixture_function=None, 

1331 *args, 

1332 scope="function", 

1333 params=None, 

1334 autouse=False, 

1335 ids=None, 

1336 name=None, 

1337): 

1338 """(Return a) decorator to mark a yield-fixture factory function. 

1339 

1340 .. deprecated:: 3.0 

1341 Use :py:func:`pytest.fixture` directly instead. 

1342 """ 

1343 warnings.warn(YIELD_FIXTURE, stacklevel=2) 

1344 return fixture( 

1345 fixture_function, 

1346 *args, 

1347 scope=scope, 

1348 params=params, 

1349 autouse=autouse, 

1350 ids=ids, 

1351 name=name, 

1352 ) 

1353 

1354 

1355@fixture(scope="session") 

1356def pytestconfig(request: FixtureRequest) -> Config: 

1357 """Session-scoped fixture that returns the session's :class:`pytest.Config` 

1358 object. 

1359 

1360 Example:: 

1361 

1362 def test_foo(pytestconfig): 

1363 if pytestconfig.getoption("verbose") > 0: 

1364 ... 

1365 

1366 """ 

1367 return request.config 

1368 

1369 

1370def pytest_addoption(parser: Parser) -> None: 

1371 parser.addini( 

1372 "usefixtures", 

1373 type="args", 

1374 default=[], 

1375 help="List of default fixtures to be used with this project", 

1376 ) 

1377 

1378 

1379class FixtureManager: 

1380 """pytest fixture definitions and information is stored and managed 

1381 from this class. 

1382 

1383 During collection fm.parsefactories() is called multiple times to parse 

1384 fixture function definitions into FixtureDef objects and internal 

1385 data structures. 

1386 

1387 During collection of test functions, metafunc-mechanics instantiate 

1388 a FuncFixtureInfo object which is cached per node/func-name. 

1389 This FuncFixtureInfo object is later retrieved by Function nodes 

1390 which themselves offer a fixturenames attribute. 

1391 

1392 The FuncFixtureInfo object holds information about fixtures and FixtureDefs 

1393 relevant for a particular function. An initial list of fixtures is 

1394 assembled like this: 

1395 

1396 - ini-defined usefixtures 

1397 - autouse-marked fixtures along the collection chain up from the function 

1398 - usefixtures markers at module/class/function level 

1399 - test function funcargs 

1400 

1401 Subsequently the funcfixtureinfo.fixturenames attribute is computed 

1402 as the closure of the fixtures needed to setup the initial fixtures, 

1403 i.e. fixtures needed by fixture functions themselves are appended 

1404 to the fixturenames list. 

1405 

1406 Upon the test-setup phases all fixturenames are instantiated, retrieved 

1407 by a lookup of their FuncFixtureInfo. 

1408 """ 

1409 

1410 FixtureLookupError = FixtureLookupError 

1411 FixtureLookupErrorRepr = FixtureLookupErrorRepr 

1412 

1413 def __init__(self, session: "Session") -> None: 

1414 self.session = session 

1415 self.config: Config = session.config 

1416 self._arg2fixturedefs: Dict[str, List[FixtureDef[Any]]] = {} 

1417 self._holderobjseen: Set[object] = set() 

1418 # A mapping from a nodeid to a list of autouse fixtures it defines. 

1419 self._nodeid_autousenames: Dict[str, List[str]] = { 

1420 "": self.config.getini("usefixtures"), 

1421 } 

1422 session.config.pluginmanager.register(self, "funcmanage") 

1423 

1424 def _get_direct_parametrize_args(self, node: nodes.Node) -> List[str]: 

1425 """Return all direct parametrization arguments of a node, so we don't 

1426 mistake them for fixtures. 

1427 

1428 Check https://github.com/pytest-dev/pytest/issues/5036. 

1429 

1430 These things are done later as well when dealing with parametrization 

1431 so this could be improved. 

1432 """ 

1433 parametrize_argnames: List[str] = [] 

1434 for marker in node.iter_markers(name="parametrize"): 

1435 if not marker.kwargs.get("indirect", False): 

1436 p_argnames, _ = ParameterSet._parse_parametrize_args( 

1437 *marker.args, **marker.kwargs 

1438 ) 

1439 parametrize_argnames.extend(p_argnames) 

1440 

1441 return parametrize_argnames 

1442 

1443 def getfixtureinfo( 

1444 self, node: nodes.Node, func, cls, funcargs: bool = True 

1445 ) -> FuncFixtureInfo: 

1446 if funcargs and not getattr(node, "nofuncargs", False): 

1447 argnames = getfuncargnames(func, name=node.name, cls=cls) 

1448 else: 

1449 argnames = () 

1450 

1451 usefixtures = tuple( 

1452 arg for mark in node.iter_markers(name="usefixtures") for arg in mark.args 

1453 ) 

1454 initialnames = usefixtures + argnames 

1455 fm = node.session._fixturemanager 

1456 initialnames, names_closure, arg2fixturedefs = fm.getfixtureclosure( 

1457 initialnames, node, ignore_args=self._get_direct_parametrize_args(node) 

1458 ) 

1459 return FuncFixtureInfo(argnames, initialnames, names_closure, arg2fixturedefs) 

1460 

1461 def pytest_plugin_registered(self, plugin: _PluggyPlugin) -> None: 

1462 nodeid = None 

1463 try: 

1464 p = absolutepath(plugin.__file__) # type: ignore[attr-defined] 

1465 except AttributeError: 

1466 pass 

1467 else: 

1468 # Construct the base nodeid which is later used to check 

1469 # what fixtures are visible for particular tests (as denoted 

1470 # by their test id). 

1471 if p.name.startswith("conftest.py"): 

1472 try: 

1473 nodeid = str(p.parent.relative_to(self.config.rootpath)) 

1474 except ValueError: 

1475 nodeid = "" 

1476 if nodeid == ".": 

1477 nodeid = "" 

1478 if os.sep != nodes.SEP: 

1479 nodeid = nodeid.replace(os.sep, nodes.SEP) 

1480 

1481 self.parsefactories(plugin, nodeid) 

1482 

1483 def _getautousenames(self, nodeid: str) -> Iterator[str]: 

1484 """Return the names of autouse fixtures applicable to nodeid.""" 

1485 for parentnodeid in nodes.iterparentnodeids(nodeid): 

1486 basenames = self._nodeid_autousenames.get(parentnodeid) 

1487 if basenames: 

1488 yield from basenames 

1489 

1490 def getfixtureclosure( 

1491 self, 

1492 fixturenames: Tuple[str, ...], 

1493 parentnode: nodes.Node, 

1494 ignore_args: Sequence[str] = (), 

1495 ) -> Tuple[Tuple[str, ...], List[str], Dict[str, Sequence[FixtureDef[Any]]]]: 

1496 # Collect the closure of all fixtures, starting with the given 

1497 # fixturenames as the initial set. As we have to visit all 

1498 # factory definitions anyway, we also return an arg2fixturedefs 

1499 # mapping so that the caller can reuse it and does not have 

1500 # to re-discover fixturedefs again for each fixturename 

1501 # (discovering matching fixtures for a given name/node is expensive). 

1502 

1503 parentid = parentnode.nodeid 

1504 fixturenames_closure = list(self._getautousenames(parentid)) 

1505 

1506 def merge(otherlist: Iterable[str]) -> None: 

1507 for arg in otherlist: 

1508 if arg not in fixturenames_closure: 

1509 fixturenames_closure.append(arg) 

1510 

1511 merge(fixturenames) 

1512 

1513 # At this point, fixturenames_closure contains what we call "initialnames", 

1514 # which is a set of fixturenames the function immediately requests. We 

1515 # need to return it as well, so save this. 

1516 initialnames = tuple(fixturenames_closure) 

1517 

1518 arg2fixturedefs: Dict[str, Sequence[FixtureDef[Any]]] = {} 

1519 lastlen = -1 

1520 while lastlen != len(fixturenames_closure): 

1521 lastlen = len(fixturenames_closure) 

1522 for argname in fixturenames_closure: 

1523 if argname in ignore_args: 

1524 continue 

1525 if argname in arg2fixturedefs: 

1526 continue 

1527 fixturedefs = self.getfixturedefs(argname, parentid) 

1528 if fixturedefs: 

1529 arg2fixturedefs[argname] = fixturedefs 

1530 merge(fixturedefs[-1].argnames) 

1531 

1532 def sort_by_scope(arg_name: str) -> Scope: 

1533 try: 

1534 fixturedefs = arg2fixturedefs[arg_name] 

1535 except KeyError: 

1536 return Scope.Function 

1537 else: 

1538 return fixturedefs[-1]._scope 

1539 

1540 fixturenames_closure.sort(key=sort_by_scope, reverse=True) 

1541 return initialnames, fixturenames_closure, arg2fixturedefs 

1542 

1543 def pytest_generate_tests(self, metafunc: "Metafunc") -> None: 

1544 """Generate new tests based on parametrized fixtures used by the given metafunc""" 

1545 

1546 def get_parametrize_mark_argnames(mark: Mark) -> Sequence[str]: 

1547 args, _ = ParameterSet._parse_parametrize_args(*mark.args, **mark.kwargs) 

1548 return args 

1549 

1550 for argname in metafunc.fixturenames: 

1551 # Get the FixtureDefs for the argname. 

1552 fixture_defs = metafunc._arg2fixturedefs.get(argname) 

1553 if not fixture_defs: 

1554 # Will raise FixtureLookupError at setup time if not parametrized somewhere 

1555 # else (e.g @pytest.mark.parametrize) 

1556 continue 

1557 

1558 # If the test itself parametrizes using this argname, give it 

1559 # precedence. 

1560 if any( 

1561 argname in get_parametrize_mark_argnames(mark) 

1562 for mark in metafunc.definition.iter_markers("parametrize") 

1563 ): 

1564 continue 

1565 

1566 # In the common case we only look at the fixture def with the 

1567 # closest scope (last in the list). But if the fixture overrides 

1568 # another fixture, while requesting the super fixture, keep going 

1569 # in case the super fixture is parametrized (#1953). 

1570 for fixturedef in reversed(fixture_defs): 

1571 # Fixture is parametrized, apply it and stop. 

1572 if fixturedef.params is not None: 

1573 metafunc.parametrize( 

1574 argname, 

1575 fixturedef.params, 

1576 indirect=True, 

1577 scope=fixturedef.scope, 

1578 ids=fixturedef.ids, 

1579 ) 

1580 break 

1581 

1582 # Not requesting the overridden super fixture, stop. 

1583 if argname not in fixturedef.argnames: 

1584 break 

1585 

1586 # Try next super fixture, if any. 

1587 

1588 def pytest_collection_modifyitems(self, items: List[nodes.Item]) -> None: 

1589 # Separate parametrized setups. 

1590 items[:] = reorder_items(items) 

1591 

1592 def parsefactories( 

1593 self, node_or_obj, nodeid=NOTSET, unittest: bool = False 

1594 ) -> None: 

1595 if nodeid is not NOTSET: 

1596 holderobj = node_or_obj 

1597 else: 

1598 holderobj = node_or_obj.obj 

1599 nodeid = node_or_obj.nodeid 

1600 if holderobj in self._holderobjseen: 

1601 return 

1602 

1603 self._holderobjseen.add(holderobj) 

1604 autousenames = [] 

1605 for name in dir(holderobj): 

1606 # ugly workaround for one of the fspath deprecated property of node 

1607 # todo: safely generalize 

1608 if isinstance(holderobj, nodes.Node) and name == "fspath": 

1609 continue 

1610 

1611 # The attribute can be an arbitrary descriptor, so the attribute 

1612 # access below can raise. safe_getatt() ignores such exceptions. 

1613 obj = safe_getattr(holderobj, name, None) 

1614 marker = getfixturemarker(obj) 

1615 if not isinstance(marker, FixtureFunctionMarker): 

1616 # Magic globals with __getattr__ might have got us a wrong 

1617 # fixture attribute. 

1618 continue 

1619 

1620 if marker.name: 

1621 name = marker.name 

1622 

1623 # During fixture definition we wrap the original fixture function 

1624 # to issue a warning if called directly, so here we unwrap it in 

1625 # order to not emit the warning when pytest itself calls the 

1626 # fixture function. 

1627 obj = get_real_method(obj, holderobj) 

1628 

1629 fixture_def = FixtureDef( 

1630 fixturemanager=self, 

1631 baseid=nodeid, 

1632 argname=name, 

1633 func=obj, 

1634 scope=marker.scope, 

1635 params=marker.params, 

1636 unittest=unittest, 

1637 ids=marker.ids, 

1638 ) 

1639 

1640 faclist = self._arg2fixturedefs.setdefault(name, []) 

1641 if fixture_def.has_location: 

1642 faclist.append(fixture_def) 

1643 else: 

1644 # fixturedefs with no location are at the front 

1645 # so this inserts the current fixturedef after the 

1646 # existing fixturedefs from external plugins but 

1647 # before the fixturedefs provided in conftests. 

1648 i = len([f for f in faclist if not f.has_location]) 

1649 faclist.insert(i, fixture_def) 

1650 if marker.autouse: 

1651 autousenames.append(name) 

1652 

1653 if autousenames: 

1654 self._nodeid_autousenames.setdefault(nodeid or "", []).extend(autousenames) 

1655 

1656 def getfixturedefs( 

1657 self, argname: str, nodeid: str 

1658 ) -> Optional[Sequence[FixtureDef[Any]]]: 

1659 """Get a list of fixtures which are applicable to the given node id. 

1660 

1661 :param str argname: Name of the fixture to search for. 

1662 :param str nodeid: Full node id of the requesting test. 

1663 :rtype: Sequence[FixtureDef] 

1664 """ 

1665 try: 

1666 fixturedefs = self._arg2fixturedefs[argname] 

1667 except KeyError: 

1668 return None 

1669 return tuple(self._matchfactories(fixturedefs, nodeid)) 

1670 

1671 def _matchfactories( 

1672 self, fixturedefs: Iterable[FixtureDef[Any]], nodeid: str 

1673 ) -> Iterator[FixtureDef[Any]]: 

1674 parentnodeids = set(nodes.iterparentnodeids(nodeid)) 

1675 for fixturedef in fixturedefs: 

1676 if fixturedef.baseid in parentnodeids: 

1677 yield fixturedef