1from __future__ import absolute_import, division, print_function 2 3import functools 4import inspect 5import sys 6import warnings 7from collections import OrderedDict, deque, defaultdict 8from more_itertools import flatten 9 10import attr 11import py 12from py._code.code import FormattedExcinfo 13 14import _pytest 15from _pytest import nodes 16from _pytest._code.code import TerminalRepr 17from _pytest.compat import ( 18 NOTSET, 19 exc_clear, 20 _format_args, 21 getfslineno, 22 get_real_func, 23 is_generator, 24 isclass, 25 getimfunc, 26 getlocation, 27 getfuncargnames, 28 safe_getattr, 29 FuncargnamesCompatAttr, 30) 31from _pytest.outcomes import fail, TEST_OUTCOME 32 33FIXTURE_MSG = 'fixtures cannot have "pytest_funcarg__" prefix and be decorated with @pytest.fixture:\n{}' 34 35 36@attr.s(frozen=True) 37class PseudoFixtureDef(object): 38 cached_result = attr.ib() 39 scope = attr.ib() 40 41 42def pytest_sessionstart(session): 43 import _pytest.python 44 import _pytest.nodes 45 46 scopename2class.update( 47 { 48 "class": _pytest.python.Class, 49 "module": _pytest.python.Module, 50 "function": _pytest.nodes.Item, 51 "session": _pytest.main.Session, 52 } 53 ) 54 session._fixturemanager = FixtureManager(session) 55 56 57scopename2class = {} 58 59 60scope2props = dict(session=()) 61scope2props["module"] = ("fspath", "module") 62scope2props["class"] = scope2props["module"] + ("cls",) 63scope2props["instance"] = scope2props["class"] + ("instance",) 64scope2props["function"] = scope2props["instance"] + ("function", "keywords") 65 66 67def scopeproperty(name=None, doc=None): 68 69 def decoratescope(func): 70 scopename = name or func.__name__ 71 72 def provide(self): 73 if func.__name__ in scope2props[self.scope]: 74 return func(self) 75 raise AttributeError( 76 "%s not available in %s-scoped context" % (scopename, self.scope) 77 ) 78 79 return property(provide, None, None, func.__doc__) 80 81 return decoratescope 82 83 84def get_scope_node(node, scope): 85 cls = scopename2class.get(scope) 86 if cls is None: 87 raise ValueError("unknown scope") 88 return node.getparent(cls) 89 90 91def add_funcarg_pseudo_fixture_def(collector, metafunc, fixturemanager): 92 # this function will transform all collected calls to a functions 93 # if they use direct funcargs (i.e. direct parametrization) 94 # because we want later test execution to be able to rely on 95 # an existing FixtureDef structure for all arguments. 96 # XXX we can probably avoid this algorithm if we modify CallSpec2 97 # to directly care for creating the fixturedefs within its methods. 98 if not metafunc._calls[0].funcargs: 99 return # this function call does not have direct parametrization 100 # collect funcargs of all callspecs into a list of values 101 arg2params = {} 102 arg2scope = {} 103 for callspec in metafunc._calls: 104 for argname, argvalue in callspec.funcargs.items(): 105 assert argname not in callspec.params 106 callspec.params[argname] = argvalue 107 arg2params_list = arg2params.setdefault(argname, []) 108 callspec.indices[argname] = len(arg2params_list) 109 arg2params_list.append(argvalue) 110 if argname not in arg2scope: 111 scopenum = callspec._arg2scopenum.get(argname, scopenum_function) 112 arg2scope[argname] = scopes[scopenum] 113 callspec.funcargs.clear() 114 115 # register artificial FixtureDef's so that later at test execution 116 # time we can rely on a proper FixtureDef to exist for fixture setup. 117 arg2fixturedefs = metafunc._arg2fixturedefs 118 for argname, valuelist in arg2params.items(): 119 # if we have a scope that is higher than function we need 120 # to make sure we only ever create an according fixturedef on 121 # a per-scope basis. We thus store and cache the fixturedef on the 122 # node related to the scope. 123 scope = arg2scope[argname] 124 node = None 125 if scope != "function": 126 node = get_scope_node(collector, scope) 127 if node is None: 128 assert scope == "class" and isinstance(collector, _pytest.python.Module) 129 # use module-level collector for class-scope (for now) 130 node = collector 131 if node and argname in node._name2pseudofixturedef: 132 arg2fixturedefs[argname] = [node._name2pseudofixturedef[argname]] 133 else: 134 fixturedef = FixtureDef( 135 fixturemanager, 136 "", 137 argname, 138 get_direct_param_fixture_func, 139 arg2scope[argname], 140 valuelist, 141 False, 142 False, 143 ) 144 arg2fixturedefs[argname] = [fixturedef] 145 if node is not None: 146 node._name2pseudofixturedef[argname] = fixturedef 147 148 149def getfixturemarker(obj): 150 """ return fixturemarker or None if it doesn't exist or raised 151 exceptions.""" 152 try: 153 return getattr(obj, "_pytestfixturefunction", None) 154 except TEST_OUTCOME: 155 # some objects raise errors like request (from flask import request) 156 # we don't expect them to be fixture functions 157 return None 158 159 160def get_parametrized_fixture_keys(item, scopenum): 161 """ return list of keys for all parametrized arguments which match 162 the specified scope. """ 163 assert scopenum < scopenum_function # function 164 try: 165 cs = item.callspec 166 except AttributeError: 167 pass 168 else: 169 # cs.indices.items() is random order of argnames. Need to 170 # sort this so that different calls to 171 # get_parametrized_fixture_keys will be deterministic. 172 for argname, param_index in sorted(cs.indices.items()): 173 if cs._arg2scopenum[argname] != scopenum: 174 continue 175 if scopenum == 0: # session 176 key = (argname, param_index) 177 elif scopenum == 1: # module 178 key = (argname, param_index, item.fspath) 179 elif scopenum == 2: # class 180 key = (argname, param_index, item.fspath, item.cls) 181 yield key 182 183 184# algorithm for sorting on a per-parametrized resource setup basis 185# it is called for scopenum==0 (session) first and performs sorting 186# down to the lower scopes such as to minimize number of "high scope" 187# setups and teardowns 188 189 190def reorder_items(items): 191 argkeys_cache = {} 192 items_by_argkey = {} 193 for scopenum in range(0, scopenum_function): 194 argkeys_cache[scopenum] = d = {} 195 items_by_argkey[scopenum] = item_d = defaultdict(deque) 196 for item in items: 197 keys = OrderedDict.fromkeys(get_parametrized_fixture_keys(item, scopenum)) 198 if keys: 199 d[item] = keys 200 for key in keys: 201 item_d[key].append(item) 202 items = OrderedDict.fromkeys(items) 203 return list(reorder_items_atscope(items, argkeys_cache, items_by_argkey, 0)) 204 205 206def fix_cache_order(item, argkeys_cache, items_by_argkey): 207 for scopenum in range(0, scopenum_function): 208 for key in argkeys_cache[scopenum].get(item, []): 209 items_by_argkey[scopenum][key].appendleft(item) 210 211 212def reorder_items_atscope(items, argkeys_cache, items_by_argkey, scopenum): 213 if scopenum >= scopenum_function or len(items) < 3: 214 return items 215 ignore = set() 216 items_deque = deque(items) 217 items_done = OrderedDict() 218 scoped_items_by_argkey = items_by_argkey[scopenum] 219 scoped_argkeys_cache = argkeys_cache[scopenum] 220 while items_deque: 221 no_argkey_group = OrderedDict() 222 slicing_argkey = None 223 while items_deque: 224 item = items_deque.popleft() 225 if item in items_done or item in no_argkey_group: 226 continue 227 argkeys = OrderedDict.fromkeys( 228 k for k in scoped_argkeys_cache.get(item, []) if k not in ignore 229 ) 230 if not argkeys: 231 no_argkey_group[item] = None 232 else: 233 slicing_argkey, _ = argkeys.popitem() 234 # we don't have to remove relevant items from later in the deque because they'll just be ignored 235 matching_items = [ 236 i for i in scoped_items_by_argkey[slicing_argkey] if i in items 237 ] 238 for i in reversed(matching_items): 239 fix_cache_order(i, argkeys_cache, items_by_argkey) 240 items_deque.appendleft(i) 241 break 242 if no_argkey_group: 243 no_argkey_group = reorder_items_atscope( 244 no_argkey_group, argkeys_cache, items_by_argkey, scopenum + 1 245 ) 246 for item in no_argkey_group: 247 items_done[item] = None 248 ignore.add(slicing_argkey) 249 return items_done 250 251 252def fillfixtures(function): 253 """ fill missing funcargs for a test function. """ 254 try: 255 request = function._request 256 except AttributeError: 257 # XXX this special code path is only expected to execute 258 # with the oejskit plugin. It uses classes with funcargs 259 # and we thus have to work a bit to allow this. 260 fm = function.session._fixturemanager 261 fi = fm.getfixtureinfo(function.parent, function.obj, None) 262 function._fixtureinfo = fi 263 request = function._request = FixtureRequest(function) 264 request._fillfixtures() 265 # prune out funcargs for jstests 266 newfuncargs = {} 267 for name in fi.argnames: 268 newfuncargs[name] = function.funcargs[name] 269 function.funcargs = newfuncargs 270 else: 271 request._fillfixtures() 272 273 274def get_direct_param_fixture_func(request): 275 return request.param 276 277 278class FuncFixtureInfo(object): 279 280 def __init__(self, argnames, names_closure, name2fixturedefs): 281 self.argnames = argnames 282 self.names_closure = names_closure 283 self.name2fixturedefs = name2fixturedefs 284 285 286class FixtureRequest(FuncargnamesCompatAttr): 287 """ A request for a fixture from a test or fixture function. 288 289 A request object gives access to the requesting test context 290 and has an optional ``param`` attribute in case 291 the fixture is parametrized indirectly. 292 """ 293 294 def __init__(self, pyfuncitem): 295 self._pyfuncitem = pyfuncitem 296 #: fixture for which this request is being performed 297 self.fixturename = None 298 #: Scope string, one of "function", "class", "module", "session" 299 self.scope = "function" 300 self._fixture_defs = {} # argname -> FixtureDef 301 fixtureinfo = pyfuncitem._fixtureinfo 302 self._arg2fixturedefs = fixtureinfo.name2fixturedefs.copy() 303 self._arg2index = {} 304 self._fixturemanager = pyfuncitem.session._fixturemanager 305 306 @property 307 def fixturenames(self): 308 # backward incompatible note: now a readonly property 309 return list(self._pyfuncitem._fixtureinfo.names_closure) 310 311 @property 312 def node(self): 313 """ underlying collection node (depends on current request scope)""" 314 return self._getscopeitem(self.scope) 315 316 def _getnextfixturedef(self, argname): 317 fixturedefs = self._arg2fixturedefs.get(argname, None) 318 if fixturedefs is None: 319 # we arrive here because of a dynamic call to 320 # getfixturevalue(argname) usage which was naturally 321 # not known at parsing/collection time 322 parentid = self._pyfuncitem.parent.nodeid 323 fixturedefs = self._fixturemanager.getfixturedefs(argname, parentid) 324 self._arg2fixturedefs[argname] = fixturedefs 325 # fixturedefs list is immutable so we maintain a decreasing index 326 index = self._arg2index.get(argname, 0) - 1 327 if fixturedefs is None or (-index > len(fixturedefs)): 328 raise FixtureLookupError(argname, self) 329 self._arg2index[argname] = index 330 return fixturedefs[index] 331 332 @property 333 def config(self): 334 """ the pytest config object associated with this request. """ 335 return self._pyfuncitem.config 336 337 @scopeproperty() 338 def function(self): 339 """ test function object if the request has a per-function scope. """ 340 return self._pyfuncitem.obj 341 342 @scopeproperty("class") 343 def cls(self): 344 """ class (can be None) where the test function was collected. """ 345 clscol = self._pyfuncitem.getparent(_pytest.python.Class) 346 if clscol: 347 return clscol.obj 348 349 @property 350 def instance(self): 351 """ instance (can be None) on which test function was collected. """ 352 # unittest support hack, see _pytest.unittest.TestCaseFunction 353 try: 354 return self._pyfuncitem._testcase 355 except AttributeError: 356 function = getattr(self, "function", None) 357 return getattr(function, "__self__", None) 358 359 @scopeproperty() 360 def module(self): 361 """ python module object where the test function was collected. """ 362 return self._pyfuncitem.getparent(_pytest.python.Module).obj 363 364 @scopeproperty() 365 def fspath(self): 366 """ the file system path of the test module which collected this test. """ 367 return self._pyfuncitem.fspath 368 369 @property 370 def keywords(self): 371 """ keywords/markers dictionary for the underlying node. """ 372 return self.node.keywords 373 374 @property 375 def session(self): 376 """ pytest session object. """ 377 return self._pyfuncitem.session 378 379 def addfinalizer(self, finalizer): 380 """ add finalizer/teardown function to be called after the 381 last test within the requesting test context finished 382 execution. """ 383 # XXX usually this method is shadowed by fixturedef specific ones 384 self._addfinalizer(finalizer, scope=self.scope) 385 386 def _addfinalizer(self, finalizer, scope): 387 colitem = self._getscopeitem(scope) 388 self._pyfuncitem.session._setupstate.addfinalizer( 389 finalizer=finalizer, colitem=colitem 390 ) 391 392 def applymarker(self, marker): 393 """ Apply a marker to a single test function invocation. 394 This method is useful if you don't want to have a keyword/marker 395 on all function invocations. 396 397 :arg marker: a :py:class:`_pytest.mark.MarkDecorator` object 398 created by a call to ``pytest.mark.NAME(...)``. 399 """ 400 self.node.add_marker(marker) 401 402 def raiseerror(self, msg): 403 """ raise a FixtureLookupError with the given message. """ 404 raise self._fixturemanager.FixtureLookupError(None, self, msg) 405 406 def _fillfixtures(self): 407 item = self._pyfuncitem 408 fixturenames = getattr(item, "fixturenames", self.fixturenames) 409 for argname in fixturenames: 410 if argname not in item.funcargs: 411 item.funcargs[argname] = self.getfixturevalue(argname) 412 413 def cached_setup(self, setup, teardown=None, scope="module", extrakey=None): 414 """ (deprecated) Return a testing resource managed by ``setup`` & 415 ``teardown`` calls. ``scope`` and ``extrakey`` determine when the 416 ``teardown`` function will be called so that subsequent calls to 417 ``setup`` would recreate the resource. With pytest-2.3 you often 418 do not need ``cached_setup()`` as you can directly declare a scope 419 on a fixture function and register a finalizer through 420 ``request.addfinalizer()``. 421 422 :arg teardown: function receiving a previously setup resource. 423 :arg setup: a no-argument function creating a resource. 424 :arg scope: a string value out of ``function``, ``class``, ``module`` 425 or ``session`` indicating the caching lifecycle of the resource. 426 :arg extrakey: added to internal caching key of (funcargname, scope). 427 """ 428 if not hasattr(self.config, "_setupcache"): 429 self.config._setupcache = {} # XXX weakref? 430 cachekey = (self.fixturename, self._getscopeitem(scope), extrakey) 431 cache = self.config._setupcache 432 try: 433 val = cache[cachekey] 434 except KeyError: 435 self._check_scope(self.fixturename, self.scope, scope) 436 val = setup() 437 cache[cachekey] = val 438 if teardown is not None: 439 440 def finalizer(): 441 del cache[cachekey] 442 teardown(val) 443 444 self._addfinalizer(finalizer, scope=scope) 445 return val 446 447 def getfixturevalue(self, argname): 448 """ Dynamically run a named fixture function. 449 450 Declaring fixtures via function argument is recommended where possible. 451 But if you can only decide whether to use another fixture at test 452 setup time, you may use this function to retrieve it inside a fixture 453 or test function body. 454 """ 455 return self._get_active_fixturedef(argname).cached_result[0] 456 457 def getfuncargvalue(self, argname): 458 """ Deprecated, use getfixturevalue. """ 459 from _pytest import deprecated 460 461 warnings.warn(deprecated.GETFUNCARGVALUE, DeprecationWarning, stacklevel=2) 462 return self.getfixturevalue(argname) 463 464 def _get_active_fixturedef(self, argname): 465 try: 466 return self._fixture_defs[argname] 467 except KeyError: 468 try: 469 fixturedef = self._getnextfixturedef(argname) 470 except FixtureLookupError: 471 if argname == "request": 472 cached_result = (self, [0], None) 473 scope = "function" 474 return PseudoFixtureDef(cached_result, scope) 475 raise 476 # remove indent to prevent the python3 exception 477 # from leaking into the call 478 self._compute_fixture_value(fixturedef) 479 self._fixture_defs[argname] = fixturedef 480 return fixturedef 481 482 def _get_fixturestack(self): 483 current = self 484 values = [] 485 while 1: 486 fixturedef = getattr(current, "_fixturedef", None) 487 if fixturedef is None: 488 values.reverse() 489 return values 490 values.append(fixturedef) 491 current = current._parent_request 492 493 def _compute_fixture_value(self, fixturedef): 494 """ 495 Creates a SubRequest based on "self" and calls the execute method of the given fixturedef object. This will 496 force the FixtureDef object to throw away any previous results and compute a new fixture value, which 497 will be stored into the FixtureDef object itself. 498 499 :param FixtureDef fixturedef: 500 """ 501 # prepare a subrequest object before calling fixture function 502 # (latter managed by fixturedef) 503 argname = fixturedef.argname 504 funcitem = self._pyfuncitem 505 scope = fixturedef.scope 506 try: 507 param = funcitem.callspec.getparam(argname) 508 except (AttributeError, ValueError): 509 param = NOTSET 510 param_index = 0 511 if fixturedef.params is not None: 512 frame = inspect.stack()[3] 513 frameinfo = inspect.getframeinfo(frame[0]) 514 source_path = frameinfo.filename 515 source_lineno = frameinfo.lineno 516 source_path = py.path.local(source_path) 517 if source_path.relto(funcitem.config.rootdir): 518 source_path = source_path.relto(funcitem.config.rootdir) 519 msg = ( 520 "The requested fixture has no parameter defined for the " 521 "current test.\n\nRequested fixture '{}' defined in:\n{}" 522 "\n\nRequested here:\n{}:{}".format( 523 fixturedef.argname, 524 getlocation(fixturedef.func, funcitem.config.rootdir), 525 source_path, 526 source_lineno, 527 ) 528 ) 529 fail(msg) 530 else: 531 # indices might not be set if old-style metafunc.addcall() was used 532 param_index = funcitem.callspec.indices.get(argname, 0) 533 # if a parametrize invocation set a scope it will override 534 # the static scope defined with the fixture function 535 paramscopenum = funcitem.callspec._arg2scopenum.get(argname) 536 if paramscopenum is not None: 537 scope = scopes[paramscopenum] 538 539 subrequest = SubRequest(self, scope, param, param_index, fixturedef) 540 541 # check if a higher-level scoped fixture accesses a lower level one 542 subrequest._check_scope(argname, self.scope, scope) 543 544 # clear sys.exc_info before invoking the fixture (python bug?) 545 # if its not explicitly cleared it will leak into the call 546 exc_clear() 547 try: 548 # call the fixture function 549 fixturedef.execute(request=subrequest) 550 finally: 551 # if fixture function failed it might have registered finalizers 552 self.session._setupstate.addfinalizer( 553 functools.partial(fixturedef.finish, request=subrequest), 554 subrequest.node, 555 ) 556 557 def _check_scope(self, argname, invoking_scope, requested_scope): 558 if argname == "request": 559 return 560 if scopemismatch(invoking_scope, requested_scope): 561 # try to report something helpful 562 lines = self._factorytraceback() 563 fail( 564 "ScopeMismatch: You tried to access the %r scoped " 565 "fixture %r with a %r scoped request object, " 566 "involved factories\n%s" 567 % ((requested_scope, argname, invoking_scope, "\n".join(lines))), 568 pytrace=False, 569 ) 570 571 def _factorytraceback(self): 572 lines = [] 573 for fixturedef in self._get_fixturestack(): 574 factory = fixturedef.func 575 fs, lineno = getfslineno(factory) 576 p = self._pyfuncitem.session.fspath.bestrelpath(fs) 577 args = _format_args(factory) 578 lines.append("%s:%d: def %s%s" % (p, lineno, factory.__name__, args)) 579 return lines 580 581 def _getscopeitem(self, scope): 582 if scope == "function": 583 # this might also be a non-function Item despite its attribute name 584 return self._pyfuncitem 585 node = get_scope_node(self._pyfuncitem, scope) 586 if node is None and scope == "class": 587 # fallback to function item itself 588 node = self._pyfuncitem 589 assert node, 'Could not obtain a node for scope "{}" for function {!r}'.format( 590 scope, self._pyfuncitem 591 ) 592 return node 593 594 def __repr__(self): 595 return "<FixtureRequest for %r>" % (self.node) 596 597 598class SubRequest(FixtureRequest): 599 """ a sub request for handling getting a fixture from a 600 test function/fixture. """ 601 602 def __init__(self, request, scope, param, param_index, fixturedef): 603 self._parent_request = request 604 self.fixturename = fixturedef.argname 605 if param is not NOTSET: 606 self.param = param 607 self.param_index = param_index 608 self.scope = scope 609 self._fixturedef = fixturedef 610 self._pyfuncitem = request._pyfuncitem 611 self._fixture_defs = request._fixture_defs 612 self._arg2fixturedefs = request._arg2fixturedefs 613 self._arg2index = request._arg2index 614 self._fixturemanager = request._fixturemanager 615 616 def __repr__(self): 617 return "<SubRequest %r for %r>" % (self.fixturename, self._pyfuncitem) 618 619 def addfinalizer(self, finalizer): 620 self._fixturedef.addfinalizer(finalizer) 621 622 623class ScopeMismatchError(Exception): 624 """ A fixture function tries to use a different fixture function which 625 which has a lower scope (e.g. a Session one calls a function one) 626 """ 627 628 629scopes = "session module class function".split() 630scopenum_function = scopes.index("function") 631 632 633def scopemismatch(currentscope, newscope): 634 return scopes.index(newscope) > scopes.index(currentscope) 635 636 637def scope2index(scope, descr, where=None): 638 """Look up the index of ``scope`` and raise a descriptive value error 639 if not defined. 640 """ 641 try: 642 return scopes.index(scope) 643 except ValueError: 644 raise ValueError( 645 "{} {}has an unsupported scope value '{}'".format( 646 descr, "from {} ".format(where) if where else "", scope 647 ) 648 ) 649 650 651class FixtureLookupError(LookupError): 652 """ could not return a requested Fixture (missing or invalid). """ 653 654 def __init__(self, argname, request, msg=None): 655 self.argname = argname 656 self.request = request 657 self.fixturestack = request._get_fixturestack() 658 self.msg = msg 659 660 def formatrepr(self): 661 tblines = [] 662 addline = tblines.append 663 stack = [self.request._pyfuncitem.obj] 664 stack.extend(map(lambda x: x.func, self.fixturestack)) 665 msg = self.msg 666 if msg is not None: 667 # the last fixture raise an error, let's present 668 # it at the requesting side 669 stack = stack[:-1] 670 for function in stack: 671 fspath, lineno = getfslineno(function) 672 try: 673 lines, _ = inspect.getsourcelines(get_real_func(function)) 674 except (IOError, IndexError, TypeError): 675 error_msg = "file %s, line %s: source code not available" 676 addline(error_msg % (fspath, lineno + 1)) 677 else: 678 addline("file %s, line %s" % (fspath, lineno + 1)) 679 for i, line in enumerate(lines): 680 line = line.rstrip() 681 addline(" " + line) 682 if line.lstrip().startswith("def"): 683 break 684 685 if msg is None: 686 fm = self.request._fixturemanager 687 available = [] 688 parentid = self.request._pyfuncitem.parent.nodeid 689 for name, fixturedefs in fm._arg2fixturedefs.items(): 690 faclist = list(fm._matchfactories(fixturedefs, parentid)) 691 if faclist and name not in available: 692 available.append(name) 693 msg = "fixture %r not found" % (self.argname,) 694 msg += "\n available fixtures: %s" % (", ".join(sorted(available)),) 695 msg += "\n use 'pytest --fixtures [testpath]' for help on them." 696 697 return FixtureLookupErrorRepr(fspath, lineno, tblines, msg, self.argname) 698 699 700class FixtureLookupErrorRepr(TerminalRepr): 701 702 def __init__(self, filename, firstlineno, tblines, errorstring, argname): 703 self.tblines = tblines 704 self.errorstring = errorstring 705 self.filename = filename 706 self.firstlineno = firstlineno 707 self.argname = argname 708 709 def toterminal(self, tw): 710 # tw.line("FixtureLookupError: %s" %(self.argname), red=True) 711 for tbline in self.tblines: 712 tw.line(tbline.rstrip()) 713 lines = self.errorstring.split("\n") 714 if lines: 715 tw.line( 716 "{} {}".format(FormattedExcinfo.fail_marker, lines[0].strip()), 717 red=True, 718 ) 719 for line in lines[1:]: 720 tw.line( 721 "{} {}".format(FormattedExcinfo.flow_marker, line.strip()), 722 red=True, 723 ) 724 tw.line() 725 tw.line("%s:%d" % (self.filename, self.firstlineno + 1)) 726 727 728def fail_fixturefunc(fixturefunc, msg): 729 fs, lineno = getfslineno(fixturefunc) 730 location = "%s:%s" % (fs, lineno + 1) 731 source = _pytest._code.Source(fixturefunc) 732 fail(msg + ":\n\n" + str(source.indent()) + "\n" + location, pytrace=False) 733 734 735def call_fixture_func(fixturefunc, request, kwargs): 736 yieldctx = is_generator(fixturefunc) 737 if yieldctx: 738 it = fixturefunc(**kwargs) 739 res = next(it) 740 741 def teardown(): 742 try: 743 next(it) 744 except StopIteration: 745 pass 746 else: 747 fail_fixturefunc( 748 fixturefunc, "yield_fixture function has more than one 'yield'" 749 ) 750 751 request.addfinalizer(teardown) 752 else: 753 res = fixturefunc(**kwargs) 754 return res 755 756 757class FixtureDef(object): 758 """ A container for a factory definition. """ 759 760 def __init__( 761 self, 762 fixturemanager, 763 baseid, 764 argname, 765 func, 766 scope, 767 params, 768 unittest=False, 769 ids=None, 770 ): 771 self._fixturemanager = fixturemanager 772 self.baseid = baseid or "" 773 self.has_location = baseid is not None 774 self.func = func 775 self.argname = argname 776 self.scope = scope 777 self.scopenum = scope2index( 778 scope or "function", descr="fixture {}".format(func.__name__), where=baseid 779 ) 780 self.params = params 781 self.argnames = getfuncargnames(func, is_method=unittest) 782 self.unittest = unittest 783 self.ids = ids 784 self._finalizers = [] 785 786 def addfinalizer(self, finalizer): 787 self._finalizers.append(finalizer) 788 789 def finish(self, request): 790 exceptions = [] 791 try: 792 while self._finalizers: 793 try: 794 func = self._finalizers.pop() 795 func() 796 except: # noqa 797 exceptions.append(sys.exc_info()) 798 if exceptions: 799 e = exceptions[0] 800 del exceptions # ensure we don't keep all frames alive because of the traceback 801 py.builtin._reraise(*e) 802 803 finally: 804 hook = self._fixturemanager.session.gethookproxy(request.node.fspath) 805 hook.pytest_fixture_post_finalizer(fixturedef=self, request=request) 806 # even if finalization fails, we invalidate 807 # the cached fixture value and remove 808 # all finalizers because they may be bound methods which will 809 # keep instances alive 810 if hasattr(self, "cached_result"): 811 del self.cached_result 812 self._finalizers = [] 813 814 def execute(self, request): 815 # get required arguments and register our own finish() 816 # with their finalization 817 for argname in self.argnames: 818 fixturedef = request._get_active_fixturedef(argname) 819 if argname != "request": 820 fixturedef.addfinalizer(functools.partial(self.finish, request=request)) 821 822 my_cache_key = request.param_index 823 cached_result = getattr(self, "cached_result", None) 824 if cached_result is not None: 825 result, cache_key, err = cached_result 826 if my_cache_key == cache_key: 827 if err is not None: 828 py.builtin._reraise(*err) 829 else: 830 return result 831 # we have a previous but differently parametrized fixture instance 832 # so we need to tear it down before creating a new one 833 self.finish(request) 834 assert not hasattr(self, "cached_result") 835 836 hook = self._fixturemanager.session.gethookproxy(request.node.fspath) 837 return hook.pytest_fixture_setup(fixturedef=self, request=request) 838 839 def __repr__(self): 840 return ( 841 "<FixtureDef name=%r scope=%r baseid=%r >" 842 % (self.argname, self.scope, self.baseid) 843 ) 844 845 846def pytest_fixture_setup(fixturedef, request): 847 """ Execution of fixture setup. """ 848 kwargs = {} 849 for argname in fixturedef.argnames: 850 fixdef = request._get_active_fixturedef(argname) 851 result, arg_cache_key, exc = fixdef.cached_result 852 request._check_scope(argname, request.scope, fixdef.scope) 853 kwargs[argname] = result 854 855 fixturefunc = fixturedef.func 856 if fixturedef.unittest: 857 if request.instance is not None: 858 # bind the unbound method to the TestCase instance 859 fixturefunc = fixturedef.func.__get__(request.instance) 860 else: 861 # the fixture function needs to be bound to the actual 862 # request.instance so that code working with "fixturedef" behaves 863 # as expected. 864 if request.instance is not None: 865 fixturefunc = getimfunc(fixturedef.func) 866 if fixturefunc != fixturedef.func: 867 fixturefunc = fixturefunc.__get__(request.instance) 868 my_cache_key = request.param_index 869 try: 870 result = call_fixture_func(fixturefunc, request, kwargs) 871 except TEST_OUTCOME: 872 fixturedef.cached_result = (None, my_cache_key, sys.exc_info()) 873 raise 874 fixturedef.cached_result = (result, my_cache_key, None) 875 return result 876 877 878def _ensure_immutable_ids(ids): 879 if ids is None: 880 return 881 if callable(ids): 882 return ids 883 return tuple(ids) 884 885 886@attr.s(frozen=True) 887class FixtureFunctionMarker(object): 888 scope = attr.ib() 889 params = attr.ib(converter=attr.converters.optional(tuple)) 890 autouse = attr.ib(default=False) 891 ids = attr.ib(default=None, converter=_ensure_immutable_ids) 892 name = attr.ib(default=None) 893 894 def __call__(self, function): 895 if isclass(function): 896 raise ValueError("class fixtures not supported (may be in the future)") 897 898 if getattr(function, "_pytestfixturefunction", False): 899 raise ValueError( 900 "fixture is being applied more than once to the same function" 901 ) 902 903 function._pytestfixturefunction = self 904 return function 905 906 907def fixture(scope="function", params=None, autouse=False, ids=None, name=None): 908 """Decorator to mark a fixture factory function. 909 910 This decorator can be used (with or without parameters) to define a 911 fixture function. The name of the fixture function can later be 912 referenced to cause its invocation ahead of running tests: test 913 modules or classes can use the pytest.mark.usefixtures(fixturename) 914 marker. Test functions can directly use fixture names as input 915 arguments in which case the fixture instance returned from the fixture 916 function will be injected. 917 918 :arg scope: the scope for which this fixture is shared, one of 919 "function" (default), "class", "module" or "session". 920 921 :arg params: an optional list of parameters which will cause multiple 922 invocations of the fixture function and all of the tests 923 using it. 924 925 :arg autouse: if True, the fixture func is activated for all tests that 926 can see it. If False (the default) then an explicit 927 reference is needed to activate the fixture. 928 929 :arg ids: list of string ids each corresponding to the params 930 so that they are part of the test id. If no ids are provided 931 they will be generated automatically from the params. 932 933 :arg name: the name of the fixture. This defaults to the name of the 934 decorated function. If a fixture is used in the same module in 935 which it is defined, the function name of the fixture will be 936 shadowed by the function arg that requests the fixture; one way 937 to resolve this is to name the decorated function 938 ``fixture_<fixturename>`` and then use 939 ``@pytest.fixture(name='<fixturename>')``. 940 941 Fixtures can optionally provide their values to test functions using a ``yield`` statement, 942 instead of ``return``. In this case, the code block after the ``yield`` statement is executed 943 as teardown code regardless of the test outcome. A fixture function must yield exactly once. 944 """ 945 if callable(scope) and params is None and autouse is False: 946 # direct decoration 947 return FixtureFunctionMarker("function", params, autouse, name=name)(scope) 948 if params is not None and not isinstance(params, (list, tuple)): 949 params = list(params) 950 return FixtureFunctionMarker(scope, params, autouse, ids=ids, name=name) 951 952 953def yield_fixture(scope="function", params=None, autouse=False, ids=None, name=None): 954 """ (return a) decorator to mark a yield-fixture factory function. 955 956 .. deprecated:: 3.0 957 Use :py:func:`pytest.fixture` directly instead. 958 """ 959 if callable(scope) and params is None and not autouse: 960 # direct decoration 961 return FixtureFunctionMarker("function", params, autouse, ids=ids, name=name)( 962 scope 963 ) 964 else: 965 return FixtureFunctionMarker(scope, params, autouse, ids=ids, name=name) 966 967 968defaultfuncargprefixmarker = fixture() 969 970 971@fixture(scope="session") 972def pytestconfig(request): 973 """Session-scoped fixture that returns the :class:`_pytest.config.Config` object. 974 975 Example:: 976 977 def test_foo(pytestconfig): 978 if pytestconfig.getoption("verbose"): 979 ... 980 981 """ 982 return request.config 983 984 985class FixtureManager(object): 986 """ 987 pytest fixtures definitions and information is stored and managed 988 from this class. 989 990 During collection fm.parsefactories() is called multiple times to parse 991 fixture function definitions into FixtureDef objects and internal 992 data structures. 993 994 During collection of test functions, metafunc-mechanics instantiate 995 a FuncFixtureInfo object which is cached per node/func-name. 996 This FuncFixtureInfo object is later retrieved by Function nodes 997 which themselves offer a fixturenames attribute. 998 999 The FuncFixtureInfo object holds information about fixtures and FixtureDefs 1000 relevant for a particular function. An initial list of fixtures is 1001 assembled like this: 1002 1003 - ini-defined usefixtures 1004 - autouse-marked fixtures along the collection chain up from the function 1005 - usefixtures markers at module/class/function level 1006 - test function funcargs 1007 1008 Subsequently the funcfixtureinfo.fixturenames attribute is computed 1009 as the closure of the fixtures needed to setup the initial fixtures, 1010 i. e. fixtures needed by fixture functions themselves are appended 1011 to the fixturenames list. 1012 1013 Upon the test-setup phases all fixturenames are instantiated, retrieved 1014 by a lookup of their FuncFixtureInfo. 1015 """ 1016 1017 _argprefix = "pytest_funcarg__" 1018 FixtureLookupError = FixtureLookupError 1019 FixtureLookupErrorRepr = FixtureLookupErrorRepr 1020 1021 def __init__(self, session): 1022 self.session = session 1023 self.config = session.config 1024 self._arg2fixturedefs = {} 1025 self._holderobjseen = set() 1026 self._arg2finish = {} 1027 self._nodeid_and_autousenames = [("", self.config.getini("usefixtures"))] 1028 session.config.pluginmanager.register(self, "funcmanage") 1029 1030 def getfixtureinfo(self, node, func, cls, funcargs=True): 1031 if funcargs and not getattr(node, "nofuncargs", False): 1032 argnames = getfuncargnames(func, cls=cls) 1033 else: 1034 argnames = () 1035 usefixtures = flatten( 1036 mark.args for mark in node.iter_markers(name="usefixtures") 1037 ) 1038 initialnames = argnames 1039 initialnames = tuple(usefixtures) + initialnames 1040 fm = node.session._fixturemanager 1041 names_closure, arg2fixturedefs = fm.getfixtureclosure(initialnames, node) 1042 return FuncFixtureInfo(argnames, names_closure, arg2fixturedefs) 1043 1044 def pytest_plugin_registered(self, plugin): 1045 nodeid = None 1046 try: 1047 p = py.path.local(plugin.__file__) 1048 except AttributeError: 1049 pass 1050 else: 1051 # construct the base nodeid which is later used to check 1052 # what fixtures are visible for particular tests (as denoted 1053 # by their test id) 1054 if p.basename.startswith("conftest.py"): 1055 nodeid = p.dirpath().relto(self.config.rootdir) 1056 if p.sep != nodes.SEP: 1057 nodeid = nodeid.replace(p.sep, nodes.SEP) 1058 self.parsefactories(plugin, nodeid) 1059 1060 def _getautousenames(self, nodeid): 1061 """ return a tuple of fixture names to be used. """ 1062 autousenames = [] 1063 for baseid, basenames in self._nodeid_and_autousenames: 1064 if nodeid.startswith(baseid): 1065 if baseid: 1066 i = len(baseid) 1067 nextchar = nodeid[i:i + 1] 1068 if nextchar and nextchar not in ":/": 1069 continue 1070 autousenames.extend(basenames) 1071 return autousenames 1072 1073 def getfixtureclosure(self, fixturenames, parentnode): 1074 # collect the closure of all fixtures , starting with the given 1075 # fixturenames as the initial set. As we have to visit all 1076 # factory definitions anyway, we also return an arg2fixturedefs 1077 # mapping so that the caller can reuse it and does not have 1078 # to re-discover fixturedefs again for each fixturename 1079 # (discovering matching fixtures for a given name/node is expensive) 1080 1081 parentid = parentnode.nodeid 1082 fixturenames_closure = self._getautousenames(parentid) 1083 1084 def merge(otherlist): 1085 for arg in otherlist: 1086 if arg not in fixturenames_closure: 1087 fixturenames_closure.append(arg) 1088 1089 merge(fixturenames) 1090 arg2fixturedefs = {} 1091 lastlen = -1 1092 while lastlen != len(fixturenames_closure): 1093 lastlen = len(fixturenames_closure) 1094 for argname in fixturenames_closure: 1095 if argname in arg2fixturedefs: 1096 continue 1097 fixturedefs = self.getfixturedefs(argname, parentid) 1098 if fixturedefs: 1099 arg2fixturedefs[argname] = fixturedefs 1100 merge(fixturedefs[-1].argnames) 1101 1102 def sort_by_scope(arg_name): 1103 try: 1104 fixturedefs = arg2fixturedefs[arg_name] 1105 except KeyError: 1106 return scopes.index("function") 1107 else: 1108 return fixturedefs[-1].scopenum 1109 1110 fixturenames_closure.sort(key=sort_by_scope) 1111 return fixturenames_closure, arg2fixturedefs 1112 1113 def pytest_generate_tests(self, metafunc): 1114 for argname in metafunc.fixturenames: 1115 faclist = metafunc._arg2fixturedefs.get(argname) 1116 if faclist: 1117 fixturedef = faclist[-1] 1118 if fixturedef.params is not None: 1119 parametrize_func = getattr(metafunc.function, "parametrize", None) 1120 if parametrize_func is not None: 1121 parametrize_func = parametrize_func.combined 1122 func_params = getattr(parametrize_func, "args", [[None]]) 1123 func_kwargs = getattr(parametrize_func, "kwargs", {}) 1124 # skip directly parametrized arguments 1125 if "argnames" in func_kwargs: 1126 argnames = parametrize_func.kwargs["argnames"] 1127 else: 1128 argnames = func_params[0] 1129 if not isinstance(argnames, (tuple, list)): 1130 argnames = [x.strip() for x in argnames.split(",") if x.strip()] 1131 if argname not in func_params and argname not in argnames: 1132 metafunc.parametrize( 1133 argname, 1134 fixturedef.params, 1135 indirect=True, 1136 scope=fixturedef.scope, 1137 ids=fixturedef.ids, 1138 ) 1139 else: 1140 continue # will raise FixtureLookupError at setup time 1141 1142 def pytest_collection_modifyitems(self, items): 1143 # separate parametrized setups 1144 items[:] = reorder_items(items) 1145 1146 def parsefactories(self, node_or_obj, nodeid=NOTSET, unittest=False): 1147 if nodeid is not NOTSET: 1148 holderobj = node_or_obj 1149 else: 1150 holderobj = node_or_obj.obj 1151 nodeid = node_or_obj.nodeid 1152 if holderobj in self._holderobjseen: 1153 return 1154 self._holderobjseen.add(holderobj) 1155 autousenames = [] 1156 for name in dir(holderobj): 1157 # The attribute can be an arbitrary descriptor, so the attribute 1158 # access below can raise. safe_getatt() ignores such exceptions. 1159 obj = safe_getattr(holderobj, name, None) 1160 # fixture functions have a pytest_funcarg__ prefix (pre-2.3 style) 1161 # or are "@pytest.fixture" marked 1162 marker = getfixturemarker(obj) 1163 if marker is None: 1164 if not name.startswith(self._argprefix): 1165 continue 1166 if not callable(obj): 1167 continue 1168 marker = defaultfuncargprefixmarker 1169 from _pytest import deprecated 1170 1171 self.config.warn( 1172 "C1", deprecated.FUNCARG_PREFIX.format(name=name), nodeid=nodeid 1173 ) 1174 name = name[len(self._argprefix):] 1175 elif not isinstance(marker, FixtureFunctionMarker): 1176 # magic globals with __getattr__ might have got us a wrong 1177 # fixture attribute 1178 continue 1179 else: 1180 if marker.name: 1181 name = marker.name 1182 assert not name.startswith(self._argprefix), FIXTURE_MSG.format(name) 1183 1184 fixture_def = FixtureDef( 1185 self, 1186 nodeid, 1187 name, 1188 obj, 1189 marker.scope, 1190 marker.params, 1191 unittest=unittest, 1192 ids=marker.ids, 1193 ) 1194 1195 faclist = self._arg2fixturedefs.setdefault(name, []) 1196 if fixture_def.has_location: 1197 faclist.append(fixture_def) 1198 else: 1199 # fixturedefs with no location are at the front 1200 # so this inserts the current fixturedef after the 1201 # existing fixturedefs from external plugins but 1202 # before the fixturedefs provided in conftests. 1203 i = len([f for f in faclist if not f.has_location]) 1204 faclist.insert(i, fixture_def) 1205 if marker.autouse: 1206 autousenames.append(name) 1207 1208 if autousenames: 1209 self._nodeid_and_autousenames.append((nodeid or "", autousenames)) 1210 1211 def getfixturedefs(self, argname, nodeid): 1212 """ 1213 Gets a list of fixtures which are applicable to the given node id. 1214 1215 :param str argname: name of the fixture to search for 1216 :param str nodeid: full node id of the requesting test. 1217 :return: list[FixtureDef] 1218 """ 1219 try: 1220 fixturedefs = self._arg2fixturedefs[argname] 1221 except KeyError: 1222 return None 1223 else: 1224 return tuple(self._matchfactories(fixturedefs, nodeid)) 1225 1226 def _matchfactories(self, fixturedefs, nodeid): 1227 for fixturedef in fixturedefs: 1228 if nodes.ischildnode(fixturedef.baseid, nodeid): 1229 yield fixturedef 1230