Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1import functools 

2import inspect 

3import itertools 

4import sys 

5import warnings 

6from collections import defaultdict 

7from collections import deque 

8from types import TracebackType 

9from typing import Any 

10from typing import Callable 

11from typing import cast 

12from typing import Dict 

13from typing import Generator 

14from typing import Generic 

15from typing import Iterable 

16from typing import Iterator 

17from typing import List 

18from typing import Optional 

19from typing import Sequence 

20from typing import Set 

21from typing import Tuple 

22from typing import TypeVar 

23from typing import Union 

24 

25import attr 

26import py 

27 

28import _pytest 

29from _pytest._code import getfslineno 

30from _pytest._code.code import FormattedExcinfo 

31from _pytest._code.code import TerminalRepr 

32from _pytest._io import TerminalWriter 

33from _pytest.compat import _format_args 

34from _pytest.compat import _PytestWrapper 

35from _pytest.compat import get_real_func 

36from _pytest.compat import get_real_method 

37from _pytest.compat import getfuncargnames 

38from _pytest.compat import getimfunc 

39from _pytest.compat import getlocation 

40from _pytest.compat import is_generator 

41from _pytest.compat import NOTSET 

42from _pytest.compat import order_preserving_dict 

43from _pytest.compat import overload 

44from _pytest.compat import safe_getattr 

45from _pytest.compat import TYPE_CHECKING 

46from _pytest.config import _PluggyPlugin 

47from _pytest.config import Config 

48from _pytest.config.argparsing import Parser 

49from _pytest.deprecated import FIXTURE_POSITIONAL_ARGUMENTS 

50from _pytest.deprecated import FUNCARGNAMES 

51from _pytest.mark import ParameterSet 

52from _pytest.outcomes import fail 

53from _pytest.outcomes import TEST_OUTCOME 

54 

55if TYPE_CHECKING: 

56 from typing import Deque 

57 from typing import NoReturn 

58 from typing import Type 

59 from typing_extensions import Literal 

60 

61 from _pytest import nodes 

62 from _pytest.main import Session 

63 from _pytest.python import CallSpec2 

64 from _pytest.python import Function 

65 from _pytest.python import Metafunc 

66 

67 _Scope = Literal["session", "package", "module", "class", "function"] 

68 

69 

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

71_FixtureValue = TypeVar("_FixtureValue") 

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

73_FixtureFunction = TypeVar("_FixtureFunction", bound=Callable[..., object]) 

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

75_FixtureFunc = Union[ 

76 Callable[..., _FixtureValue], Callable[..., Generator[_FixtureValue, None, None]] 

77] 

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

79_FixtureCachedResult = Union[ 

80 Tuple[ 

81 # The result. 

82 _FixtureValue, 

83 # Cache key. 

84 object, 

85 None, 

86 ], 

87 Tuple[ 

88 None, 

89 # Cache key. 

90 object, 

91 # Exc info if raised. 

92 Tuple["Type[BaseException]", BaseException, TracebackType], 

93 ], 

94] 

95 

96 

97@attr.s(frozen=True) 

98class PseudoFixtureDef: 

99 cached_result = attr.ib(type="_FixtureCachedResult") 

100 scope = attr.ib(type="_Scope") 

101 

102 

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

104 import _pytest.python 

105 import _pytest.nodes 

106 

107 scopename2class.update( 

108 { 

109 "package": _pytest.python.Package, 

110 "class": _pytest.python.Class, 

111 "module": _pytest.python.Module, 

112 "function": _pytest.nodes.Item, 

113 "session": _pytest.main.Session, 

114 } 

115 ) 

116 session._fixturemanager = FixtureManager(session) 

117 

118 

119scopename2class = {} # type: Dict[str, Type[nodes.Node]] 

120 

121scope2props = dict(session=()) # type: Dict[str, Tuple[str, ...]] 

122scope2props["package"] = ("fspath",) 

123scope2props["module"] = ("fspath", "module") 

124scope2props["class"] = scope2props["module"] + ("cls",) 

125scope2props["instance"] = scope2props["class"] + ("instance",) 

126scope2props["function"] = scope2props["instance"] + ("function", "keywords") 

127 

128 

129def scopeproperty(name=None, doc=None): 

130 def decoratescope(func): 

131 scopename = name or func.__name__ 

132 

133 def provide(self): 

134 if func.__name__ in scope2props[self.scope]: 

135 return func(self) 

136 raise AttributeError( 

137 "{} not available in {}-scoped context".format(scopename, self.scope) 

138 ) 

139 

140 return property(provide, None, None, func.__doc__) 

141 

142 return decoratescope 

143 

144 

145def get_scope_package(node, fixturedef: "FixtureDef"): 

146 import pytest 

147 

148 cls = pytest.Package 

149 current = node 

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

151 while current and ( 

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

153 ): 

154 current = current.parent 

155 if current is None: 

156 return node.session 

157 return current 

158 

159 

160def get_scope_node(node, scope): 

161 cls = scopename2class.get(scope) 

162 if cls is None: 

163 raise ValueError("unknown scope") 

164 return node.getparent(cls) 

165 

166 

167def add_funcarg_pseudo_fixture_def( 

168 collector, metafunc: "Metafunc", fixturemanager: "FixtureManager" 

169) -> None: 

170 # this function will transform all collected calls to a functions 

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

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

173 # an existing FixtureDef structure for all arguments. 

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

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

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

177 return # this function call does not have direct parametrization 

178 # collect funcargs of all callspecs into a list of values 

179 arg2params = {} # type: Dict[str, List[object]] 

180 arg2scope = {} # type: Dict[str, _Scope] 

181 for callspec in metafunc._calls: 

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

183 assert argname not in callspec.params 

184 callspec.params[argname] = argvalue 

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

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

187 arg2params_list.append(argvalue) 

188 if argname not in arg2scope: 

189 scopenum = callspec._arg2scopenum.get(argname, scopenum_function) 

190 arg2scope[argname] = scopes[scopenum] 

191 callspec.funcargs.clear() 

192 

193 # register artificial FixtureDef's so that later at test execution 

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

195 arg2fixturedefs = metafunc._arg2fixturedefs 

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

197 # if we have a scope that is higher than function we need 

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

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

200 # node related to the scope. 

201 scope = arg2scope[argname] 

202 node = None 

203 if scope != "function": 

204 node = get_scope_node(collector, scope) 

205 if node is None: 

206 assert scope == "class" and isinstance(collector, _pytest.python.Module) 

207 # use module-level collector for class-scope (for now) 

208 node = collector 

209 if node and argname in node._name2pseudofixturedef: 

210 arg2fixturedefs[argname] = [node._name2pseudofixturedef[argname]] 

211 else: 

212 fixturedef = FixtureDef( 

213 fixturemanager=fixturemanager, 

214 baseid="", 

215 argname=argname, 

216 func=get_direct_param_fixture_func, 

217 scope=arg2scope[argname], 

218 params=valuelist, 

219 unittest=False, 

220 ids=None, 

221 ) 

222 arg2fixturedefs[argname] = [fixturedef] 

223 if node is not None: 

224 node._name2pseudofixturedef[argname] = fixturedef 

225 

226 

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

228 """ return fixturemarker or None if it doesn't exist or raised 

229 exceptions.""" 

230 try: 

231 fixturemarker = getattr( 

232 obj, "_pytestfixturefunction", None 

233 ) # type: Optional[FixtureFunctionMarker] 

234 except TEST_OUTCOME: 

235 # some objects raise errors like request (from flask import request) 

236 # we don't expect them to be fixture functions 

237 return None 

238 return fixturemarker 

239 

240 

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

242_Key = Tuple[object, ...] 

243 

244 

245def get_parametrized_fixture_keys(item: "nodes.Item", scopenum: int) -> Iterator[_Key]: 

246 """ return list of keys for all parametrized arguments which match 

247 the specified scope. """ 

248 assert scopenum < scopenum_function # function 

249 try: 

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

251 except AttributeError: 

252 pass 

253 else: 

254 cs = callspec # type: CallSpec2 

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

256 # sort this so that different calls to 

257 # get_parametrized_fixture_keys will be deterministic. 

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

259 if cs._arg2scopenum[argname] != scopenum: 

260 continue 

261 if scopenum == 0: # session 

262 key = (argname, param_index) # type: _Key 

263 elif scopenum == 1: # package 

264 key = (argname, param_index, item.fspath.dirpath()) 

265 elif scopenum == 2: # module 

266 key = (argname, param_index, item.fspath) 

267 elif scopenum == 3: # class 

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

269 key = (argname, param_index, item.fspath, item_cls) 

270 yield key 

271 

272 

273# algorithm for sorting on a per-parametrized resource setup basis 

274# it is called for scopenum==0 (session) first and performs sorting 

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

276# setups and teardowns 

277 

278 

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

280 argkeys_cache = {} # type: Dict[int, Dict[nodes.Item, Dict[_Key, None]]] 

281 items_by_argkey = {} # type: Dict[int, Dict[_Key, Deque[nodes.Item]]] 

282 for scopenum in range(0, scopenum_function): 

283 d = {} # type: Dict[nodes.Item, Dict[_Key, None]] 

284 argkeys_cache[scopenum] = d 

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

286 items_by_argkey[scopenum] = item_d 

287 for item in items: 

288 # cast is a workaround for https://github.com/python/typeshed/issues/3800. 

289 keys = cast( 

290 "Dict[_Key, None]", 

291 order_preserving_dict.fromkeys( 

292 get_parametrized_fixture_keys(item, scopenum), None 

293 ), 

294 ) 

295 if keys: 

296 d[item] = keys 

297 for key in keys: 

298 item_d[key].append(item) 

299 # cast is a workaround for https://github.com/python/typeshed/issues/3800. 

300 items_dict = cast( 

301 "Dict[nodes.Item, None]", order_preserving_dict.fromkeys(items, None) 

302 ) 

303 return list(reorder_items_atscope(items_dict, argkeys_cache, items_by_argkey, 0)) 

304 

305 

306def fix_cache_order( 

307 item: "nodes.Item", 

308 argkeys_cache: "Dict[int, Dict[nodes.Item, Dict[_Key, None]]]", 

309 items_by_argkey: "Dict[int, Dict[_Key, Deque[nodes.Item]]]", 

310) -> None: 

311 for scopenum in range(0, scopenum_function): 

312 for key in argkeys_cache[scopenum].get(item, []): 

313 items_by_argkey[scopenum][key].appendleft(item) 

314 

315 

316def reorder_items_atscope( 

317 items: "Dict[nodes.Item, None]", 

318 argkeys_cache: "Dict[int, Dict[nodes.Item, Dict[_Key, None]]]", 

319 items_by_argkey: "Dict[int, Dict[_Key, Deque[nodes.Item]]]", 

320 scopenum: int, 

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

322 if scopenum >= scopenum_function or len(items) < 3: 

323 return items 

324 ignore = set() # type: Set[Optional[_Key]] 

325 items_deque = deque(items) 

326 items_done = order_preserving_dict() # type: Dict[nodes.Item, None] 

327 scoped_items_by_argkey = items_by_argkey[scopenum] 

328 scoped_argkeys_cache = argkeys_cache[scopenum] 

329 while items_deque: 

330 no_argkey_group = order_preserving_dict() # type: Dict[nodes.Item, None] 

331 slicing_argkey = None 

332 while items_deque: 

333 item = items_deque.popleft() 

334 if item in items_done or item in no_argkey_group: 

335 continue 

336 argkeys = order_preserving_dict.fromkeys( 

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

338 ) 

339 if not argkeys: 

340 no_argkey_group[item] = None 

341 else: 

342 slicing_argkey, _ = argkeys.popitem() 

343 # we don't have to remove relevant items from later in the deque because they'll just be ignored 

344 matching_items = [ 

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

346 ] 

347 for i in reversed(matching_items): 

348 fix_cache_order(i, argkeys_cache, items_by_argkey) 

349 items_deque.appendleft(i) 

350 break 

351 if no_argkey_group: 

352 no_argkey_group = reorder_items_atscope( 

353 no_argkey_group, argkeys_cache, items_by_argkey, scopenum + 1 

354 ) 

355 for item in no_argkey_group: 

356 items_done[item] = None 

357 ignore.add(slicing_argkey) 

358 return items_done 

359 

360 

361def fillfixtures(function: "Function") -> None: 

362 """ fill missing funcargs for a test function. """ 

363 # Uncomment this after 6.0 release (#7361) 

364 # warnings.warn(FILLFUNCARGS, stacklevel=2) 

365 try: 

366 request = function._request 

367 except AttributeError: 

368 # XXX this special code path is only expected to execute 

369 # with the oejskit plugin. It uses classes with funcargs 

370 # and we thus have to work a bit to allow this. 

371 fm = function.session._fixturemanager 

372 assert function.parent is not None 

373 fi = fm.getfixtureinfo(function.parent, function.obj, None) 

374 function._fixtureinfo = fi 

375 request = function._request = FixtureRequest(function) 

376 request._fillfixtures() 

377 # prune out funcargs for jstests 

378 newfuncargs = {} 

379 for name in fi.argnames: 

380 newfuncargs[name] = function.funcargs[name] 

381 function.funcargs = newfuncargs 

382 else: 

383 request._fillfixtures() 

384 

385 

386def get_direct_param_fixture_func(request): 

387 return request.param 

388 

389 

390@attr.s(slots=True) 

391class FuncFixtureInfo: 

392 # original function argument names 

393 argnames = attr.ib(type=Tuple[str, ...]) 

394 # argnames that function immediately requires. These include argnames + 

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

396 # definitions. 

397 initialnames = attr.ib(type=Tuple[str, ...]) 

398 names_closure = attr.ib(type=List[str]) 

399 name2fixturedefs = attr.ib(type=Dict[str, Sequence["FixtureDef"]]) 

400 

401 def prune_dependency_tree(self) -> None: 

402 """Recompute names_closure from initialnames and name2fixturedefs 

403 

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

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

406 

407 This method is needed because direct parametrization may shadow some 

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

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

410 of argnames may get reduced. 

411 """ 

412 closure = set() # type: Set[str] 

413 working_set = set(self.initialnames) 

414 while working_set: 

415 argname = working_set.pop() 

416 # argname may be smth not included in the original names_closure, 

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

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

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

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

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

422 closure.add(argname) 

423 if argname in self.name2fixturedefs: 

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

425 

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

427 

428 

429class FixtureRequest: 

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

431 

432 A request object gives access to the requesting test context 

433 and has an optional ``param`` attribute in case 

434 the fixture is parametrized indirectly. 

435 """ 

436 

437 def __init__(self, pyfuncitem) -> None: 

438 self._pyfuncitem = pyfuncitem 

439 #: fixture for which this request is being performed 

440 self.fixturename = None # type: Optional[str] 

441 #: Scope string, one of "function", "class", "module", "session" 

442 self.scope = "function" # type: _Scope 

443 self._fixture_defs = {} # type: Dict[str, FixtureDef] 

444 fixtureinfo = pyfuncitem._fixtureinfo # type: FuncFixtureInfo 

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

446 self._arg2index = {} # type: Dict[str, int] 

447 self._fixturemanager = ( 

448 pyfuncitem.session._fixturemanager 

449 ) # type: FixtureManager 

450 

451 @property 

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

453 """names of all active fixtures in this request""" 

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

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

456 return result 

457 

458 @property 

459 def funcargnames(self) -> List[str]: 

460 """ alias attribute for ``fixturenames`` for pre-2.3 compatibility""" 

461 warnings.warn(FUNCARGNAMES, stacklevel=2) 

462 return self.fixturenames 

463 

464 @property 

465 def node(self): 

466 """ underlying collection node (depends on current request scope)""" 

467 return self._getscopeitem(self.scope) 

468 

469 def _getnextfixturedef(self, argname: str) -> "FixtureDef": 

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

471 if fixturedefs is None: 

472 # we arrive here because of a dynamic call to 

473 # getfixturevalue(argname) usage which was naturally 

474 # not known at parsing/collection time 

475 assert self._pyfuncitem.parent is not None 

476 parentid = self._pyfuncitem.parent.nodeid 

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

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

479 # Can this be None here? 

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

481 # fixturedefs list is immutable so we maintain a decreasing index 

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

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

484 raise FixtureLookupError(argname, self) 

485 self._arg2index[argname] = index 

486 return fixturedefs[index] 

487 

488 @property 

489 def config(self) -> Config: 

490 """ the pytest config object associated with this request. """ 

491 return self._pyfuncitem.config # type: ignore[no-any-return] # noqa: F723 

492 

493 @scopeproperty() 

494 def function(self): 

495 """ test function object if the request has a per-function scope. """ 

496 return self._pyfuncitem.obj 

497 

498 @scopeproperty("class") 

499 def cls(self): 

500 """ class (can be None) where the test function was collected. """ 

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

502 if clscol: 

503 return clscol.obj 

504 

505 @property 

506 def instance(self): 

507 """ instance (can be None) on which test function was collected. """ 

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

509 try: 

510 return self._pyfuncitem._testcase 

511 except AttributeError: 

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

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

514 

515 @scopeproperty() 

516 def module(self): 

517 """ python module object where the test function was collected. """ 

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

519 

520 @scopeproperty() 

521 def fspath(self) -> py.path.local: 

522 """ the file system path of the test module which collected this test. """ 

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

524 return self._pyfuncitem.fspath # type: ignore 

525 

526 @property 

527 def keywords(self): 

528 """ keywords/markers dictionary for the underlying node. """ 

529 return self.node.keywords 

530 

531 @property 

532 def session(self): 

533 """ pytest session object. """ 

534 return self._pyfuncitem.session 

535 

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

537 """ add finalizer/teardown function to be called after the 

538 last test within the requesting test context finished 

539 execution. """ 

540 # XXX usually this method is shadowed by fixturedef specific ones 

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

542 

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

544 colitem = self._getscopeitem(scope) 

545 self._pyfuncitem.session._setupstate.addfinalizer( 

546 finalizer=finalizer, colitem=colitem 

547 ) 

548 

549 def applymarker(self, marker) -> None: 

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

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

552 on all function invocations. 

553 

554 :arg marker: a :py:class:`_pytest.mark.MarkDecorator` object 

555 created by a call to ``pytest.mark.NAME(...)``. 

556 """ 

557 self.node.add_marker(marker) 

558 

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

560 """ raise a FixtureLookupError with the given message. """ 

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

562 

563 def _fillfixtures(self) -> None: 

564 item = self._pyfuncitem 

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

566 for argname in fixturenames: 

567 if argname not in item.funcargs: 

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

569 

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

571 """ Dynamically run a named fixture function. 

572 

573 Declaring fixtures via function argument is recommended where possible. 

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

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

576 or test function body. 

577 

578 :raise pytest.FixtureLookupError: 

579 If the given fixture could not be found. 

580 """ 

581 fixturedef = self._get_active_fixturedef(argname) 

582 assert fixturedef.cached_result is not None 

583 return fixturedef.cached_result[0] 

584 

585 def _get_active_fixturedef( 

586 self, argname: str 

587 ) -> Union["FixtureDef", PseudoFixtureDef]: 

588 try: 

589 return self._fixture_defs[argname] 

590 except KeyError: 

591 try: 

592 fixturedef = self._getnextfixturedef(argname) 

593 except FixtureLookupError: 

594 if argname == "request": 

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

596 scope = "function" # type: _Scope 

597 return PseudoFixtureDef(cached_result, scope) 

598 raise 

599 # remove indent to prevent the python3 exception 

600 # from leaking into the call 

601 self._compute_fixture_value(fixturedef) 

602 self._fixture_defs[argname] = fixturedef 

603 return fixturedef 

604 

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

606 current = self 

607 values = [] # type: List[FixtureDef] 

608 while 1: 

609 fixturedef = getattr(current, "_fixturedef", None) 

610 if fixturedef is None: 

611 values.reverse() 

612 return values 

613 values.append(fixturedef) 

614 assert isinstance(current, SubRequest) 

615 current = current._parent_request 

616 

617 def _compute_fixture_value(self, fixturedef: "FixtureDef") -> None: 

618 """ 

619 Creates a SubRequest based on "self" and calls the execute method of the given fixturedef object. This will 

620 force the FixtureDef object to throw away any previous results and compute a new fixture value, which 

621 will be stored into the FixtureDef object itself. 

622 """ 

623 # prepare a subrequest object before calling fixture function 

624 # (latter managed by fixturedef) 

625 argname = fixturedef.argname 

626 funcitem = self._pyfuncitem 

627 scope = fixturedef.scope 

628 try: 

629 param = funcitem.callspec.getparam(argname) 

630 except (AttributeError, ValueError): 

631 param = NOTSET 

632 param_index = 0 

633 has_params = fixturedef.params is not None 

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

635 if has_params and fixtures_not_supported: 

636 msg = ( 

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

638 "Node id: {nodeid}\n" 

639 "Function type: {typename}" 

640 ).format( 

641 name=funcitem.name, 

642 nodeid=funcitem.nodeid, 

643 typename=type(funcitem).__name__, 

644 ) 

645 fail(msg, pytrace=False) 

646 if has_params: 

647 frame = inspect.stack()[3] 

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

649 source_path = py.path.local(frameinfo.filename) 

650 source_lineno = frameinfo.lineno 

651 rel_source_path = source_path.relto(funcitem.config.rootdir) 

652 if rel_source_path: 

653 source_path_str = rel_source_path 

654 else: 

655 source_path_str = str(source_path) 

656 msg = ( 

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

658 " {}\n\n" 

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

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

661 funcitem.nodeid, 

662 fixturedef.argname, 

663 getlocation(fixturedef.func, funcitem.config.rootdir), 

664 source_path_str, 

665 source_lineno, 

666 ) 

667 ) 

668 fail(msg, pytrace=False) 

669 else: 

670 param_index = funcitem.callspec.indices[argname] 

671 # if a parametrize invocation set a scope it will override 

672 # the static scope defined with the fixture function 

673 paramscopenum = funcitem.callspec._arg2scopenum.get(argname) 

674 if paramscopenum is not None: 

675 scope = scopes[paramscopenum] 

676 

677 subrequest = SubRequest(self, scope, param, param_index, fixturedef) 

678 

679 # check if a higher-level scoped fixture accesses a lower level one 

680 subrequest._check_scope(argname, self.scope, scope) 

681 try: 

682 # call the fixture function 

683 fixturedef.execute(request=subrequest) 

684 finally: 

685 self._schedule_finalizers(fixturedef, subrequest) 

686 

687 def _schedule_finalizers( 

688 self, fixturedef: "FixtureDef", subrequest: "SubRequest" 

689 ) -> None: 

690 # if fixture function failed it might have registered finalizers 

691 self.session._setupstate.addfinalizer( 

692 functools.partial(fixturedef.finish, request=subrequest), subrequest.node 

693 ) 

694 

695 def _check_scope(self, argname, invoking_scope: "_Scope", requested_scope) -> None: 

696 if argname == "request": 

697 return 

698 if scopemismatch(invoking_scope, requested_scope): 

699 # try to report something helpful 

700 lines = self._factorytraceback() 

701 fail( 

702 "ScopeMismatch: You tried to access the %r scoped " 

703 "fixture %r with a %r scoped request object, " 

704 "involved factories\n%s" 

705 % ((requested_scope, argname, invoking_scope, "\n".join(lines))), 

706 pytrace=False, 

707 ) 

708 

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

710 lines = [] 

711 for fixturedef in self._get_fixturestack(): 

712 factory = fixturedef.func 

713 fs, lineno = getfslineno(factory) 

714 p = self._pyfuncitem.session.fspath.bestrelpath(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(self, scope): 

720 if scope == "function": 

721 # this might also be a non-function Item despite its attribute name 

722 return self._pyfuncitem 

723 if scope == "package": 

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

725 # but on FixtureRequest (a subclass). 

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

727 else: 

728 node = get_scope_node(self._pyfuncitem, scope) 

729 if node is None and scope == "class": 

730 # fallback to function item itself 

731 node = self._pyfuncitem 

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

733 scope, self._pyfuncitem 

734 ) 

735 return node 

736 

737 def __repr__(self) -> str: 

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

739 

740 

741class SubRequest(FixtureRequest): 

742 """ a sub request for handling getting a fixture from a 

743 test function/fixture. """ 

744 

745 def __init__( 

746 self, 

747 request: "FixtureRequest", 

748 scope: "_Scope", 

749 param, 

750 param_index: int, 

751 fixturedef: "FixtureDef", 

752 ) -> None: 

753 self._parent_request = request 

754 self.fixturename = fixturedef.argname # type: str 

755 if param is not NOTSET: 

756 self.param = param 

757 self.param_index = param_index 

758 self.scope = scope 

759 self._fixturedef = fixturedef 

760 self._pyfuncitem = request._pyfuncitem 

761 self._fixture_defs = request._fixture_defs 

762 self._arg2fixturedefs = request._arg2fixturedefs 

763 self._arg2index = request._arg2index 

764 self._fixturemanager = request._fixturemanager 

765 

766 def __repr__(self) -> str: 

767 return "<SubRequest {!r} for {!r}>".format(self.fixturename, self._pyfuncitem) 

768 

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

770 self._fixturedef.addfinalizer(finalizer) 

771 

772 def _schedule_finalizers( 

773 self, fixturedef: "FixtureDef", subrequest: "SubRequest" 

774 ) -> None: 

775 # if the executing fixturedef was not explicitly requested in the argument list (via 

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

777 # first 

778 if fixturedef.argname not in self.fixturenames: 

779 fixturedef.addfinalizer( 

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

781 ) 

782 super()._schedule_finalizers(fixturedef, subrequest) 

783 

784 

785scopes = ["session", "package", "module", "class", "function"] # type: List[_Scope] 

786scopenum_function = scopes.index("function") 

787 

788 

789def scopemismatch(currentscope: "_Scope", newscope: "_Scope") -> bool: 

790 return scopes.index(newscope) > scopes.index(currentscope) 

791 

792 

793def scope2index(scope: str, descr: str, where: Optional[str] = None) -> int: 

794 """Look up the index of ``scope`` and raise a descriptive value error 

795 if not defined. 

796 """ 

797 strscopes = scopes # type: Sequence[str] 

798 try: 

799 return strscopes.index(scope) 

800 except ValueError: 

801 fail( 

802 "{} {}got an unexpected scope value '{}'".format( 

803 descr, "from {} ".format(where) if where else "", scope 

804 ), 

805 pytrace=False, 

806 ) 

807 

808 

809class FixtureLookupError(LookupError): 

810 """ could not return a requested Fixture (missing or invalid). """ 

811 

812 def __init__( 

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

814 ) -> None: 

815 self.argname = argname 

816 self.request = request 

817 self.fixturestack = request._get_fixturestack() 

818 self.msg = msg 

819 

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

821 tblines = [] # type: List[str] 

822 addline = tblines.append 

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

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

825 msg = self.msg 

826 if msg is not None: 

827 # the last fixture raise an error, let's present 

828 # it at the requesting side 

829 stack = stack[:-1] 

830 for function in stack: 

831 fspath, lineno = getfslineno(function) 

832 try: 

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

834 except (OSError, IndexError, TypeError): 

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

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

837 else: 

838 addline("file {}, line {}".format(fspath, lineno + 1)) 

839 for i, line in enumerate(lines): 

840 line = line.rstrip() 

841 addline(" " + line) 

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

843 break 

844 

845 if msg is None: 

846 fm = self.request._fixturemanager 

847 available = set() 

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

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

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

851 if faclist: 

852 available.add(name) 

853 if self.argname in available: 

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

855 self.argname 

856 ) 

857 else: 

858 msg = "fixture '{}' not found".format(self.argname) 

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

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

861 

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

863 

864 

865class FixtureLookupErrorRepr(TerminalRepr): 

866 def __init__( 

867 self, 

868 filename: Union[str, py.path.local], 

869 firstlineno: int, 

870 tblines: Sequence[str], 

871 errorstring: str, 

872 argname: Optional[str], 

873 ) -> None: 

874 self.tblines = tblines 

875 self.errorstring = errorstring 

876 self.filename = filename 

877 self.firstlineno = firstlineno 

878 self.argname = argname 

879 

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

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

882 for tbline in self.tblines: 

883 tw.line(tbline.rstrip()) 

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

885 if lines: 

886 tw.line( 

887 "{} {}".format(FormattedExcinfo.fail_marker, lines[0].strip()), 

888 red=True, 

889 ) 

890 for line in lines[1:]: 

891 tw.line( 

892 "{} {}".format(FormattedExcinfo.flow_marker, line.strip()), 

893 red=True, 

894 ) 

895 tw.line() 

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

897 

898 

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

900 fs, lineno = getfslineno(fixturefunc) 

901 location = "{}:{}".format(fs, lineno + 1) 

902 source = _pytest._code.Source(fixturefunc) 

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

904 

905 

906def call_fixture_func( 

907 fixturefunc: "_FixtureFunc[_FixtureValue]", request: FixtureRequest, kwargs 

908) -> _FixtureValue: 

909 if is_generator(fixturefunc): 

910 fixturefunc = cast( 

911 Callable[..., Generator[_FixtureValue, None, None]], fixturefunc 

912 ) 

913 generator = fixturefunc(**kwargs) 

914 try: 

915 fixture_result = next(generator) 

916 except StopIteration: 

917 raise ValueError( 

918 "{} did not yield a value".format(request.fixturename) 

919 ) from None 

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

921 request.addfinalizer(finalizer) 

922 else: 

923 fixturefunc = cast(Callable[..., _FixtureValue], fixturefunc) 

924 fixture_result = fixturefunc(**kwargs) 

925 return fixture_result 

926 

927 

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

929 """Executes the teardown of a fixture function by advancing the iterator after the 

930 yield and ensure the iteration ends (if not it means there is more than one yield in the function)""" 

931 try: 

932 next(it) 

933 except StopIteration: 

934 pass 

935 else: 

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

937 

938 

939def _eval_scope_callable( 

940 scope_callable: "Callable[[str, Config], _Scope]", 

941 fixture_name: str, 

942 config: Config, 

943) -> "_Scope": 

944 try: 

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

946 # keyword arguments, currently. 

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

948 except Exception as e: 

949 raise TypeError( 

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

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

952 scope_callable, fixture_name 

953 ) 

954 ) from e 

955 if not isinstance(result, str): 

956 fail( 

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

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

959 pytrace=False, 

960 ) 

961 return result 

962 

963 

964class FixtureDef(Generic[_FixtureValue]): 

965 """ A container for a factory definition. """ 

966 

967 def __init__( 

968 self, 

969 fixturemanager: "FixtureManager", 

970 baseid, 

971 argname: str, 

972 func: "_FixtureFunc[_FixtureValue]", 

973 scope: "Union[_Scope, Callable[[str, Config], _Scope]]", 

974 params: Optional[Sequence[object]], 

975 unittest: bool = False, 

976 ids: Optional[ 

977 Union[ 

978 Tuple[Union[None, str, float, int, bool], ...], 

979 Callable[[Any], Optional[object]], 

980 ] 

981 ] = None, 

982 ) -> None: 

983 self._fixturemanager = fixturemanager 

984 self.baseid = baseid or "" 

985 self.has_location = baseid is not None 

986 self.func = func 

987 self.argname = argname 

988 if callable(scope): 

989 scope_ = _eval_scope_callable(scope, argname, fixturemanager.config) 

990 else: 

991 scope_ = scope 

992 self.scopenum = scope2index( 

993 scope_ or "function", 

994 descr="Fixture '{}'".format(func.__name__), 

995 where=baseid, 

996 ) 

997 self.scope = scope_ 

998 self.params = params # type: Optional[Sequence[object]] 

999 self.argnames = getfuncargnames( 

1000 func, name=argname, is_method=unittest 

1001 ) # type: Tuple[str, ...] 

1002 self.unittest = unittest 

1003 self.ids = ids 

1004 self.cached_result = None # type: Optional[_FixtureCachedResult[_FixtureValue]] 

1005 self._finalizers = [] # type: List[Callable[[], object]] 

1006 

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

1008 self._finalizers.append(finalizer) 

1009 

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

1011 exc = None 

1012 try: 

1013 while self._finalizers: 

1014 try: 

1015 func = self._finalizers.pop() 

1016 func() 

1017 except BaseException as e: 

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

1019 # ideally all should be reported. 

1020 if exc is None: 

1021 exc = e 

1022 if exc: 

1023 raise exc 

1024 finally: 

1025 hook = self._fixturemanager.session.gethookproxy(request.node.fspath) 

1026 hook.pytest_fixture_post_finalizer(fixturedef=self, request=request) 

1027 # even if finalization fails, we invalidate 

1028 # the cached fixture value and remove 

1029 # all finalizers because they may be bound methods which will 

1030 # keep instances alive 

1031 self.cached_result = None 

1032 self._finalizers = [] 

1033 

1034 def execute(self, request: SubRequest) -> _FixtureValue: 

1035 # get required arguments and register our own finish() 

1036 # with their finalization 

1037 for argname in self.argnames: 

1038 fixturedef = request._get_active_fixturedef(argname) 

1039 if argname != "request": 

1040 # PseudoFixtureDef is only for "request". 

1041 assert isinstance(fixturedef, FixtureDef) 

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

1043 

1044 my_cache_key = self.cache_key(request) 

1045 if self.cached_result is not None: 

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

1047 # numpy arrays (#6497) 

1048 cache_key = self.cached_result[1] 

1049 if my_cache_key is cache_key: 

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

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

1052 raise val.with_traceback(tb) 

1053 else: 

1054 result = self.cached_result[0] 

1055 return result 

1056 # we have a previous but differently parametrized fixture instance 

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

1058 self.finish(request) 

1059 assert self.cached_result is None 

1060 

1061 hook = self._fixturemanager.session.gethookproxy(request.node.fspath) 

1062 result = hook.pytest_fixture_setup(fixturedef=self, request=request) 

1063 return result 

1064 

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

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

1067 

1068 def __repr__(self) -> str: 

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

1070 self.argname, self.scope, self.baseid 

1071 ) 

1072 

1073 

1074def resolve_fixture_function( 

1075 fixturedef: FixtureDef[_FixtureValue], request: FixtureRequest 

1076) -> "_FixtureFunc[_FixtureValue]": 

1077 """Gets the actual callable that can be called to obtain the fixture value, dealing with unittest-specific 

1078 instances and bound methods. 

1079 """ 

1080 fixturefunc = fixturedef.func 

1081 if fixturedef.unittest: 

1082 if request.instance is not None: 

1083 # bind the unbound method to the TestCase instance 

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

1085 else: 

1086 # the fixture function needs to be bound to the actual 

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

1088 # as expected. 

1089 if request.instance is not None: 

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

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

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

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

1094 ): 

1095 return fixturefunc 

1096 fixturefunc = getimfunc(fixturedef.func) 

1097 if fixturefunc != fixturedef.func: 

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

1099 return fixturefunc 

1100 

1101 

1102def pytest_fixture_setup( 

1103 fixturedef: FixtureDef[_FixtureValue], request: SubRequest 

1104) -> _FixtureValue: 

1105 """ Execution of fixture setup. """ 

1106 kwargs = {} 

1107 for argname in fixturedef.argnames: 

1108 fixdef = request._get_active_fixturedef(argname) 

1109 assert fixdef.cached_result is not None 

1110 result, arg_cache_key, exc = fixdef.cached_result 

1111 request._check_scope(argname, request.scope, fixdef.scope) 

1112 kwargs[argname] = result 

1113 

1114 fixturefunc = resolve_fixture_function(fixturedef, request) 

1115 my_cache_key = fixturedef.cache_key(request) 

1116 try: 

1117 result = call_fixture_func(fixturefunc, request, kwargs) 

1118 except TEST_OUTCOME: 

1119 exc_info = sys.exc_info() 

1120 assert exc_info[0] is not None 

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

1122 raise 

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

1124 return result 

1125 

1126 

1127def _ensure_immutable_ids( 

1128 ids: Optional[ 

1129 Union[ 

1130 Iterable[Union[None, str, float, int, bool]], 

1131 Callable[[Any], Optional[object]], 

1132 ] 

1133 ], 

1134) -> Optional[ 

1135 Union[ 

1136 Tuple[Union[None, str, float, int, bool], ...], 

1137 Callable[[Any], Optional[object]], 

1138 ] 

1139]: 

1140 if ids is None: 

1141 return None 

1142 if callable(ids): 

1143 return ids 

1144 return tuple(ids) 

1145 

1146 

1147def _params_converter( 

1148 params: Optional[Iterable[object]], 

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

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

1151 

1152 

1153def wrap_function_to_error_out_if_called_directly(function, fixture_marker): 

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

1155 instead of used as an argument in a test function. 

1156 """ 

1157 message = ( 

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

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

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

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

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

1163 

1164 @functools.wraps(function) 

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

1166 fail(message, pytrace=False) 

1167 

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

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

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

1171 

1172 return result 

1173 

1174 

1175@attr.s(frozen=True) 

1176class FixtureFunctionMarker: 

1177 scope = attr.ib(type="Union[_Scope, Callable[[str, Config], _Scope]]") 

1178 params = attr.ib(type=Optional[Tuple[object, ...]], converter=_params_converter) 

1179 autouse = attr.ib(type=bool, default=False) 

1180 ids = attr.ib( 

1181 type=Union[ 

1182 Tuple[Union[None, str, float, int, bool], ...], 

1183 Callable[[Any], Optional[object]], 

1184 ], 

1185 default=None, 

1186 converter=_ensure_immutable_ids, 

1187 ) 

1188 name = attr.ib(type=Optional[str], default=None) 

1189 

1190 def __call__(self, function: _FixtureFunction) -> _FixtureFunction: 

1191 if inspect.isclass(function): 

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

1193 

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

1195 raise ValueError( 

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

1197 ) 

1198 

1199 function = wrap_function_to_error_out_if_called_directly(function, self) 

1200 

1201 name = self.name or function.__name__ 

1202 if name == "request": 

1203 location = getlocation(function) 

1204 fail( 

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

1206 location 

1207 ), 

1208 pytrace=False, 

1209 ) 

1210 

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

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

1213 return function 

1214 

1215 

1216@overload 

1217def fixture( 

1218 fixture_function: _FixtureFunction, 

1219 *, 

1220 scope: "Union[_Scope, Callable[[str, Config], _Scope]]" = ..., 

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

1222 autouse: bool = ..., 

1223 ids: Optional[ 

1224 Union[ 

1225 Iterable[Union[None, str, float, int, bool]], 

1226 Callable[[Any], Optional[object]], 

1227 ] 

1228 ] = ..., 

1229 name: Optional[str] = ... 

1230) -> _FixtureFunction: 

1231 raise NotImplementedError() 

1232 

1233 

1234@overload # noqa: F811 

1235def fixture( # noqa: F811 

1236 fixture_function: None = ..., 

1237 *, 

1238 scope: "Union[_Scope, Callable[[str, Config], _Scope]]" = ..., 

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

1240 autouse: bool = ..., 

1241 ids: Optional[ 

1242 Union[ 

1243 Iterable[Union[None, str, float, int, bool]], 

1244 Callable[[Any], Optional[object]], 

1245 ] 

1246 ] = ..., 

1247 name: Optional[str] = None 

1248) -> FixtureFunctionMarker: 

1249 raise NotImplementedError() 

1250 

1251 

1252def fixture( # noqa: F811 

1253 fixture_function: Optional[_FixtureFunction] = None, 

1254 *args: Any, 

1255 scope: "Union[_Scope, Callable[[str, Config], _Scope]]" = "function", 

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

1257 autouse: bool = False, 

1258 ids: Optional[ 

1259 Union[ 

1260 Iterable[Union[None, str, float, int, bool]], 

1261 Callable[[Any], Optional[object]], 

1262 ] 

1263 ] = None, 

1264 name: Optional[str] = None 

1265) -> Union[FixtureFunctionMarker, _FixtureFunction]: 

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

1267 

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

1269 fixture function. 

1270 

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

1272 invocation ahead of running tests: test 

1273 modules or classes can use the ``pytest.mark.usefixtures(fixturename)`` 

1274 marker. 

1275 

1276 Test functions can directly use fixture names as input 

1277 arguments in which case the fixture instance returned from the fixture 

1278 function will be injected. 

1279 

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

1281 statements. When using ``yield`` the code block after the ``yield`` statement is executed 

1282 as teardown code regardless of the test outcome, and must yield exactly once. 

1283 

1284 :arg scope: the scope for which this fixture is shared, one of 

1285 ``"function"`` (default), ``"class"``, ``"module"``, 

1286 ``"package"`` or ``"session"``. 

1287 

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

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

1290 

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

1292 

1293 :arg params: an optional list of parameters which will cause multiple 

1294 invocations of the fixture function and all of the tests 

1295 using it. 

1296 The current parameter is available in ``request.param``. 

1297 

1298 :arg autouse: if True, the fixture func is activated for all tests that 

1299 can see it. If False (the default) then an explicit 

1300 reference is needed to activate the fixture. 

1301 

1302 :arg ids: list of string ids each corresponding to the params 

1303 so that they are part of the test id. If no ids are provided 

1304 they will be generated automatically from the params. 

1305 

1306 :arg name: the name of the fixture. This defaults to the name of the 

1307 decorated function. If a fixture is used in the same module in 

1308 which it is defined, the function name of the fixture will be 

1309 shadowed by the function arg that requests the fixture; one way 

1310 to resolve this is to name the decorated function 

1311 ``fixture_<fixturename>`` and then use 

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

1313 """ 

1314 # Positional arguments backward compatibility. 

1315 # If a kwarg is equal to its default, assume it was not explicitly 

1316 # passed, i.e. not duplicated. The more correct way is to use a 

1317 # **kwargs and check `in`, but that obfuscates the function signature. 

1318 if isinstance(fixture_function, str): 

1319 # It's actually the first positional argument, scope. 

1320 args = (fixture_function, *args) 

1321 fixture_function = None 

1322 duplicated_args = [] 

1323 if len(args) > 0: 

1324 if scope == "function": 

1325 scope = args[0] 

1326 else: 

1327 duplicated_args.append("scope") 

1328 if len(args) > 1: 

1329 if params is None: 

1330 params = args[1] 

1331 else: 

1332 duplicated_args.append("params") 

1333 if len(args) > 2: 

1334 if autouse is False: 

1335 autouse = args[2] 

1336 else: 

1337 duplicated_args.append("autouse") 

1338 if len(args) > 3: 

1339 if ids is None: 

1340 ids = args[3] 

1341 else: 

1342 duplicated_args.append("ids") 

1343 if len(args) > 4: 

1344 if name is None: 

1345 name = args[4] 

1346 else: 

1347 duplicated_args.append("name") 

1348 if len(args) > 5: 

1349 raise TypeError( 

1350 "fixture() takes 5 positional arguments but {} were given".format(len(args)) 

1351 ) 

1352 if duplicated_args: 

1353 raise TypeError( 

1354 "The fixture arguments are defined as positional and keyword: {}. " 

1355 "Use only keyword arguments.".format(", ".join(duplicated_args)) 

1356 ) 

1357 if args: 

1358 warnings.warn(FIXTURE_POSITIONAL_ARGUMENTS, stacklevel=2) 

1359 # End backward compatiblity. 

1360 

1361 fixture_marker = FixtureFunctionMarker( 

1362 scope=scope, params=params, autouse=autouse, ids=ids, name=name, 

1363 ) 

1364 

1365 # Direct decoration. 

1366 if fixture_function: 

1367 return fixture_marker(fixture_function) 

1368 

1369 return fixture_marker 

1370 

1371 

1372def yield_fixture( 

1373 fixture_function=None, 

1374 *args, 

1375 scope="function", 

1376 params=None, 

1377 autouse=False, 

1378 ids=None, 

1379 name=None 

1380): 

1381 """ (return a) decorator to mark a yield-fixture factory function. 

1382 

1383 .. deprecated:: 3.0 

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

1385 """ 

1386 return fixture( 

1387 fixture_function, 

1388 *args, 

1389 scope=scope, 

1390 params=params, 

1391 autouse=autouse, 

1392 ids=ids, 

1393 name=name, 

1394 ) 

1395 

1396 

1397@fixture(scope="session") 

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

1399 """Session-scoped fixture that returns the :class:`_pytest.config.Config` object. 

1400 

1401 Example:: 

1402 

1403 def test_foo(pytestconfig): 

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

1405 ... 

1406 

1407 """ 

1408 return request.config 

1409 

1410 

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

1412 parser.addini( 

1413 "usefixtures", 

1414 type="args", 

1415 default=[], 

1416 help="list of default fixtures to be used with this project", 

1417 ) 

1418 

1419 

1420class FixtureManager: 

1421 """ 

1422 pytest fixtures definitions and information is stored and managed 

1423 from this class. 

1424 

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

1426 fixture function definitions into FixtureDef objects and internal 

1427 data structures. 

1428 

1429 During collection of test functions, metafunc-mechanics instantiate 

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

1431 This FuncFixtureInfo object is later retrieved by Function nodes 

1432 which themselves offer a fixturenames attribute. 

1433 

1434 The FuncFixtureInfo object holds information about fixtures and FixtureDefs 

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

1436 assembled like this: 

1437 

1438 - ini-defined usefixtures 

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

1440 - usefixtures markers at module/class/function level 

1441 - test function funcargs 

1442 

1443 Subsequently the funcfixtureinfo.fixturenames attribute is computed 

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

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

1446 to the fixturenames list. 

1447 

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

1449 by a lookup of their FuncFixtureInfo. 

1450 """ 

1451 

1452 FixtureLookupError = FixtureLookupError 

1453 FixtureLookupErrorRepr = FixtureLookupErrorRepr 

1454 

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

1456 self.session = session 

1457 self.config = session.config # type: Config 

1458 self._arg2fixturedefs = {} # type: Dict[str, List[FixtureDef]] 

1459 self._holderobjseen = set() # type: Set 

1460 self._nodeid_and_autousenames = [ 

1461 ("", self.config.getini("usefixtures")) 

1462 ] # type: List[Tuple[str, List[str]]] 

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

1464 

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

1466 """This function returns all the direct parametrization 

1467 arguments of a node, so we don't mistake them for fixtures 

1468 

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

1470 

1471 This things are done later as well when dealing with parametrization 

1472 so this could be improved 

1473 """ 

1474 parametrize_argnames = [] # type: List[str] 

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

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

1477 p_argnames, _ = ParameterSet._parse_parametrize_args( 

1478 *marker.args, **marker.kwargs 

1479 ) 

1480 parametrize_argnames.extend(p_argnames) 

1481 

1482 return parametrize_argnames 

1483 

1484 def getfixtureinfo( 

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

1486 ) -> FuncFixtureInfo: 

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

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

1489 else: 

1490 argnames = () 

1491 

1492 usefixtures = itertools.chain.from_iterable( 

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

1494 ) 

1495 initialnames = tuple(usefixtures) + argnames 

1496 fm = node.session._fixturemanager 

1497 initialnames, names_closure, arg2fixturedefs = fm.getfixtureclosure( 

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

1499 ) 

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

1501 

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

1503 nodeid = None 

1504 try: 

1505 p = py.path.local(plugin.__file__) # type: ignore[attr-defined] 

1506 except AttributeError: 

1507 pass 

1508 else: 

1509 from _pytest import nodes 

1510 

1511 # construct the base nodeid which is later used to check 

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

1513 # by their test id) 

1514 if p.basename.startswith("conftest.py"): 

1515 nodeid = p.dirpath().relto(self.config.rootdir) 

1516 if p.sep != nodes.SEP: 

1517 nodeid = nodeid.replace(p.sep, nodes.SEP) 

1518 

1519 self.parsefactories(plugin, nodeid) 

1520 

1521 def _getautousenames(self, nodeid: str) -> List[str]: 

1522 """ return a tuple of fixture names to be used. """ 

1523 autousenames = [] # type: List[str] 

1524 for baseid, basenames in self._nodeid_and_autousenames: 

1525 if nodeid.startswith(baseid): 

1526 if baseid: 

1527 i = len(baseid) 

1528 nextchar = nodeid[i : i + 1] 

1529 if nextchar and nextchar not in ":/": 

1530 continue 

1531 autousenames.extend(basenames) 

1532 return autousenames 

1533 

1534 def getfixtureclosure( 

1535 self, fixturenames: Tuple[str, ...], parentnode, ignore_args: Sequence[str] = () 

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

1537 # collect the closure of all fixtures , starting with the given 

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

1539 # factory definitions anyway, we also return an arg2fixturedefs 

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

1541 # to re-discover fixturedefs again for each fixturename 

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

1543 

1544 parentid = parentnode.nodeid 

1545 fixturenames_closure = self._getautousenames(parentid) 

1546 

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

1548 for arg in otherlist: 

1549 if arg not in fixturenames_closure: 

1550 fixturenames_closure.append(arg) 

1551 

1552 merge(fixturenames) 

1553 

1554 # at this point, fixturenames_closure contains what we call "initialnames", 

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

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

1557 initialnames = tuple(fixturenames_closure) 

1558 

1559 arg2fixturedefs = {} # type: Dict[str, Sequence[FixtureDef]] 

1560 lastlen = -1 

1561 while lastlen != len(fixturenames_closure): 

1562 lastlen = len(fixturenames_closure) 

1563 for argname in fixturenames_closure: 

1564 if argname in ignore_args: 

1565 continue 

1566 if argname in arg2fixturedefs: 

1567 continue 

1568 fixturedefs = self.getfixturedefs(argname, parentid) 

1569 if fixturedefs: 

1570 arg2fixturedefs[argname] = fixturedefs 

1571 merge(fixturedefs[-1].argnames) 

1572 

1573 def sort_by_scope(arg_name: str) -> int: 

1574 try: 

1575 fixturedefs = arg2fixturedefs[arg_name] 

1576 except KeyError: 

1577 return scopes.index("function") 

1578 else: 

1579 return fixturedefs[-1].scopenum 

1580 

1581 fixturenames_closure.sort(key=sort_by_scope) 

1582 return initialnames, fixturenames_closure, arg2fixturedefs 

1583 

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

1585 for argname in metafunc.fixturenames: 

1586 faclist = metafunc._arg2fixturedefs.get(argname) 

1587 if faclist: 

1588 fixturedef = faclist[-1] 

1589 if fixturedef.params is not None: 

1590 markers = list(metafunc.definition.iter_markers("parametrize")) 

1591 for parametrize_mark in markers: 

1592 if "argnames" in parametrize_mark.kwargs: 

1593 argnames = parametrize_mark.kwargs["argnames"] 

1594 else: 

1595 argnames = parametrize_mark.args[0] 

1596 

1597 if not isinstance(argnames, (tuple, list)): 

1598 argnames = [ 

1599 x.strip() for x in argnames.split(",") if x.strip() 

1600 ] 

1601 if argname in argnames: 

1602 break 

1603 else: 

1604 metafunc.parametrize( 

1605 argname, 

1606 fixturedef.params, 

1607 indirect=True, 

1608 scope=fixturedef.scope, 

1609 ids=fixturedef.ids, 

1610 ) 

1611 else: 

1612 continue # will raise FixtureLookupError at setup time 

1613 

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

1615 # separate parametrized setups 

1616 items[:] = reorder_items(items) 

1617 

1618 def parsefactories( 

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

1620 ) -> None: 

1621 if nodeid is not NOTSET: 

1622 holderobj = node_or_obj 

1623 else: 

1624 holderobj = node_or_obj.obj 

1625 nodeid = node_or_obj.nodeid 

1626 if holderobj in self._holderobjseen: 

1627 return 

1628 

1629 self._holderobjseen.add(holderobj) 

1630 autousenames = [] 

1631 for name in dir(holderobj): 

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

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

1634 obj = safe_getattr(holderobj, name, None) 

1635 marker = getfixturemarker(obj) 

1636 if not isinstance(marker, FixtureFunctionMarker): 

1637 # magic globals with __getattr__ might have got us a wrong 

1638 # fixture attribute 

1639 continue 

1640 

1641 if marker.name: 

1642 name = marker.name 

1643 

1644 # during fixture definition we wrap the original fixture function 

1645 # to issue a warning if called directly, so here we unwrap it in order to not emit the warning 

1646 # when pytest itself calls the fixture function 

1647 obj = get_real_method(obj, holderobj) 

1648 

1649 fixture_def = FixtureDef( 

1650 fixturemanager=self, 

1651 baseid=nodeid, 

1652 argname=name, 

1653 func=obj, 

1654 scope=marker.scope, 

1655 params=marker.params, 

1656 unittest=unittest, 

1657 ids=marker.ids, 

1658 ) 

1659 

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

1661 if fixture_def.has_location: 

1662 faclist.append(fixture_def) 

1663 else: 

1664 # fixturedefs with no location are at the front 

1665 # so this inserts the current fixturedef after the 

1666 # existing fixturedefs from external plugins but 

1667 # before the fixturedefs provided in conftests. 

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

1669 faclist.insert(i, fixture_def) 

1670 if marker.autouse: 

1671 autousenames.append(name) 

1672 

1673 if autousenames: 

1674 self._nodeid_and_autousenames.append((nodeid or "", autousenames)) 

1675 

1676 def getfixturedefs( 

1677 self, argname: str, nodeid: str 

1678 ) -> Optional[Sequence[FixtureDef]]: 

1679 """ 

1680 Gets a list of fixtures which are applicable to the given node id. 

1681 

1682 :param str argname: name of the fixture to search for 

1683 :param str nodeid: full node id of the requesting test. 

1684 :return: list[FixtureDef] 

1685 """ 

1686 try: 

1687 fixturedefs = self._arg2fixturedefs[argname] 

1688 except KeyError: 

1689 return None 

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

1691 

1692 def _matchfactories( 

1693 self, fixturedefs: Iterable[FixtureDef], nodeid: str 

1694 ) -> Iterator[FixtureDef]: 

1695 from _pytest import nodes 

1696 

1697 for fixturedef in fixturedefs: 

1698 if nodes.ischildnode(fixturedef.baseid, nodeid): 

1699 yield fixturedef