Coverage for /usr/local/lib/python3.7/site-packages/_pytest/fixtures.py : 47%

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 collections import OrderedDict
9from typing import Dict
10from typing import List
11from typing import Tuple
13import attr
14import py
16import _pytest
17from _pytest._code.code import FormattedExcinfo
18from _pytest._code.code import TerminalRepr
19from _pytest.compat import _format_args
20from _pytest.compat import _PytestWrapper
21from _pytest.compat import get_real_func
22from _pytest.compat import get_real_method
23from _pytest.compat import getfslineno
24from _pytest.compat import getfuncargnames
25from _pytest.compat import getimfunc
26from _pytest.compat import getlocation
27from _pytest.compat import is_generator
28from _pytest.compat import NOTSET
29from _pytest.compat import safe_getattr
30from _pytest.compat import TYPE_CHECKING
31from _pytest.deprecated import FIXTURE_POSITIONAL_ARGUMENTS
32from _pytest.deprecated import FUNCARGNAMES
33from _pytest.outcomes import fail
34from _pytest.outcomes import TEST_OUTCOME
36if TYPE_CHECKING:
37 from typing import Type
39 from _pytest import nodes
42@attr.s(frozen=True)
43class PseudoFixtureDef:
44 cached_result = attr.ib()
45 scope = attr.ib()
48def pytest_sessionstart(session):
49 import _pytest.python
50 import _pytest.nodes
52 scopename2class.update(
53 {
54 "package": _pytest.python.Package,
55 "class": _pytest.python.Class,
56 "module": _pytest.python.Module,
57 "function": _pytest.nodes.Item,
58 "session": _pytest.main.Session,
59 }
60 )
61 session._fixturemanager = FixtureManager(session)
64scopename2class = {} # type: Dict[str, Type[nodes.Node]]
66scope2props = dict(session=()) # type: Dict[str, Tuple[str, ...]]
67scope2props["package"] = ("fspath",)
68scope2props["module"] = ("fspath", "module")
69scope2props["class"] = scope2props["module"] + ("cls",)
70scope2props["instance"] = scope2props["class"] + ("instance",)
71scope2props["function"] = scope2props["instance"] + ("function", "keywords")
74def scopeproperty(name=None, doc=None):
75 def decoratescope(func):
76 scopename = name or func.__name__
78 def provide(self):
79 if func.__name__ in scope2props[self.scope]:
80 return func(self)
81 raise AttributeError(
82 "{} not available in {}-scoped context".format(scopename, self.scope)
83 )
85 return property(provide, None, None, func.__doc__)
87 return decoratescope
90def get_scope_package(node, fixturedef):
91 import pytest
93 cls = pytest.Package
94 current = node
95 fixture_package_name = "{}/{}".format(fixturedef.baseid, "__init__.py")
96 while current and (
97 type(current) is not cls or fixture_package_name != current.nodeid
98 ):
99 current = current.parent
100 if current is None:
101 return node.session
102 return current
105def get_scope_node(node, scope):
106 cls = scopename2class.get(scope)
107 if cls is None:
108 raise ValueError("unknown scope")
109 return node.getparent(cls)
112def add_funcarg_pseudo_fixture_def(collector, metafunc, fixturemanager):
113 # this function will transform all collected calls to a functions
114 # if they use direct funcargs (i.e. direct parametrization)
115 # because we want later test execution to be able to rely on
116 # an existing FixtureDef structure for all arguments.
117 # XXX we can probably avoid this algorithm if we modify CallSpec2
118 # to directly care for creating the fixturedefs within its methods.
119 if not metafunc._calls[0].funcargs:
120 return # this function call does not have direct parametrization
121 # collect funcargs of all callspecs into a list of values
122 arg2params = {}
123 arg2scope = {}
124 for callspec in metafunc._calls:
125 for argname, argvalue in callspec.funcargs.items():
126 assert argname not in callspec.params
127 callspec.params[argname] = argvalue
128 arg2params_list = arg2params.setdefault(argname, [])
129 callspec.indices[argname] = len(arg2params_list)
130 arg2params_list.append(argvalue)
131 if argname not in arg2scope:
132 scopenum = callspec._arg2scopenum.get(argname, scopenum_function)
133 arg2scope[argname] = scopes[scopenum]
134 callspec.funcargs.clear()
136 # register artificial FixtureDef's so that later at test execution
137 # time we can rely on a proper FixtureDef to exist for fixture setup.
138 arg2fixturedefs = metafunc._arg2fixturedefs
139 for argname, valuelist in arg2params.items():
140 # if we have a scope that is higher than function we need
141 # to make sure we only ever create an according fixturedef on
142 # a per-scope basis. We thus store and cache the fixturedef on the
143 # node related to the scope.
144 scope = arg2scope[argname]
145 node = None
146 if scope != "function":
147 node = get_scope_node(collector, scope)
148 if node is None:
149 assert scope == "class" and isinstance(collector, _pytest.python.Module)
150 # use module-level collector for class-scope (for now)
151 node = collector
152 if node and argname in node._name2pseudofixturedef:
153 arg2fixturedefs[argname] = [node._name2pseudofixturedef[argname]]
154 else:
155 fixturedef = FixtureDef(
156 fixturemanager,
157 "",
158 argname,
159 get_direct_param_fixture_func,
160 arg2scope[argname],
161 valuelist,
162 False,
163 False,
164 )
165 arg2fixturedefs[argname] = [fixturedef]
166 if node is not None:
167 node._name2pseudofixturedef[argname] = fixturedef
170def getfixturemarker(obj):
171 """ return fixturemarker or None if it doesn't exist or raised
172 exceptions."""
173 try:
174 return getattr(obj, "_pytestfixturefunction", None)
175 except TEST_OUTCOME:
176 # some objects raise errors like request (from flask import request)
177 # we don't expect them to be fixture functions
178 return None
181def get_parametrized_fixture_keys(item, scopenum):
182 """ return list of keys for all parametrized arguments which match
183 the specified scope. """
184 assert scopenum < scopenum_function # function
185 try:
186 cs = item.callspec
187 except AttributeError:
188 pass
189 else:
190 # cs.indices.items() is random order of argnames. Need to
191 # sort this so that different calls to
192 # get_parametrized_fixture_keys will be deterministic.
193 for argname, param_index in sorted(cs.indices.items()):
194 if cs._arg2scopenum[argname] != scopenum:
195 continue
196 if scopenum == 0: # session
197 key = (argname, param_index)
198 elif scopenum == 1: # package
199 key = (argname, param_index, item.fspath.dirpath())
200 elif scopenum == 2: # module
201 key = (argname, param_index, item.fspath)
202 elif scopenum == 3: # class
203 key = (argname, param_index, item.fspath, item.cls)
204 yield key
207# algorithm for sorting on a per-parametrized resource setup basis
208# it is called for scopenum==0 (session) first and performs sorting
209# down to the lower scopes such as to minimize number of "high scope"
210# setups and teardowns
213def reorder_items(items):
214 argkeys_cache = {}
215 items_by_argkey = {}
216 for scopenum in range(0, scopenum_function):
217 argkeys_cache[scopenum] = d = {}
218 items_by_argkey[scopenum] = item_d = defaultdict(deque)
219 for item in items:
220 keys = OrderedDict.fromkeys(get_parametrized_fixture_keys(item, scopenum))
221 if keys:
222 d[item] = keys
223 for key in keys:
224 item_d[key].append(item)
225 items = OrderedDict.fromkeys(items)
226 return list(reorder_items_atscope(items, argkeys_cache, items_by_argkey, 0))
229def fix_cache_order(item, argkeys_cache, items_by_argkey):
230 for scopenum in range(0, scopenum_function):
231 for key in argkeys_cache[scopenum].get(item, []):
232 items_by_argkey[scopenum][key].appendleft(item)
235def reorder_items_atscope(items, argkeys_cache, items_by_argkey, scopenum):
236 if scopenum >= scopenum_function or len(items) < 3:
237 return items
238 ignore = set()
239 items_deque = deque(items)
240 items_done = OrderedDict()
241 scoped_items_by_argkey = items_by_argkey[scopenum]
242 scoped_argkeys_cache = argkeys_cache[scopenum]
243 while items_deque:
244 no_argkey_group = OrderedDict()
245 slicing_argkey = None
246 while items_deque:
247 item = items_deque.popleft()
248 if item in items_done or item in no_argkey_group:
249 continue
250 argkeys = OrderedDict.fromkeys(
251 k for k in scoped_argkeys_cache.get(item, []) if k not in ignore
252 )
253 if not argkeys:
254 no_argkey_group[item] = None
255 else:
256 slicing_argkey, _ = argkeys.popitem()
257 # we don't have to remove relevant items from later in the deque because they'll just be ignored
258 matching_items = [
259 i for i in scoped_items_by_argkey[slicing_argkey] if i in items
260 ]
261 for i in reversed(matching_items):
262 fix_cache_order(i, argkeys_cache, items_by_argkey)
263 items_deque.appendleft(i)
264 break
265 if no_argkey_group:
266 no_argkey_group = reorder_items_atscope(
267 no_argkey_group, argkeys_cache, items_by_argkey, scopenum + 1
268 )
269 for item in no_argkey_group:
270 items_done[item] = None
271 ignore.add(slicing_argkey)
272 return items_done
275def fillfixtures(function):
276 """ fill missing funcargs for a test function. """
277 try:
278 request = function._request
279 except AttributeError:
280 # XXX this special code path is only expected to execute
281 # with the oejskit plugin. It uses classes with funcargs
282 # and we thus have to work a bit to allow this.
283 fm = function.session._fixturemanager
284 fi = fm.getfixtureinfo(function.parent, function.obj, None)
285 function._fixtureinfo = fi
286 request = function._request = FixtureRequest(function)
287 request._fillfixtures()
288 # prune out funcargs for jstests
289 newfuncargs = {}
290 for name in fi.argnames:
291 newfuncargs[name] = function.funcargs[name]
292 function.funcargs = newfuncargs
293 else:
294 request._fillfixtures()
297def get_direct_param_fixture_func(request):
298 return request.param
301@attr.s(slots=True)
302class FuncFixtureInfo:
303 # original function argument names
304 argnames = attr.ib(type=tuple)
305 # argnames that function immediately requires. These include argnames +
306 # fixture names specified via usefixtures and via autouse=True in fixture
307 # definitions.
308 initialnames = attr.ib(type=tuple)
309 names_closure = attr.ib() # List[str]
310 name2fixturedefs = attr.ib() # List[str, List[FixtureDef]]
312 def prune_dependency_tree(self):
313 """Recompute names_closure from initialnames and name2fixturedefs
315 Can only reduce names_closure, which means that the new closure will
316 always be a subset of the old one. The order is preserved.
318 This method is needed because direct parametrization may shadow some
319 of the fixtures that were included in the originally built dependency
320 tree. In this way the dependency tree can get pruned, and the closure
321 of argnames may get reduced.
322 """
323 closure = set()
324 working_set = set(self.initialnames)
325 while working_set:
326 argname = working_set.pop()
327 # argname may be smth not included in the original names_closure,
328 # in which case we ignore it. This currently happens with pseudo
329 # FixtureDefs which wrap 'get_direct_param_fixture_func(request)'.
330 # So they introduce the new dependency 'request' which might have
331 # been missing in the original tree (closure).
332 if argname not in closure and argname in self.names_closure:
333 closure.add(argname)
334 if argname in self.name2fixturedefs:
335 working_set.update(self.name2fixturedefs[argname][-1].argnames)
337 self.names_closure[:] = sorted(closure, key=self.names_closure.index)
340class FixtureRequest:
341 """ A request for a fixture from a test or fixture function.
343 A request object gives access to the requesting test context
344 and has an optional ``param`` attribute in case
345 the fixture is parametrized indirectly.
346 """
348 def __init__(self, pyfuncitem):
349 self._pyfuncitem = pyfuncitem
350 #: fixture for which this request is being performed
351 self.fixturename = None
352 #: Scope string, one of "function", "class", "module", "session"
353 self.scope = "function"
354 self._fixture_defs = {} # argname -> FixtureDef
355 fixtureinfo = pyfuncitem._fixtureinfo
356 self._arg2fixturedefs = fixtureinfo.name2fixturedefs.copy()
357 self._arg2index = {}
358 self._fixturemanager = pyfuncitem.session._fixturemanager
360 @property
361 def fixturenames(self):
362 """names of all active fixtures in this request"""
363 result = list(self._pyfuncitem._fixtureinfo.names_closure)
364 result.extend(set(self._fixture_defs).difference(result))
365 return result
367 @property
368 def funcargnames(self):
369 """ alias attribute for ``fixturenames`` for pre-2.3 compatibility"""
370 warnings.warn(FUNCARGNAMES, stacklevel=2)
371 return self.fixturenames
373 @property
374 def node(self):
375 """ underlying collection node (depends on current request scope)"""
376 return self._getscopeitem(self.scope)
378 def _getnextfixturedef(self, argname):
379 fixturedefs = self._arg2fixturedefs.get(argname, None)
380 if fixturedefs is None:
381 # we arrive here because of a dynamic call to
382 # getfixturevalue(argname) usage which was naturally
383 # not known at parsing/collection time
384 parentid = self._pyfuncitem.parent.nodeid
385 fixturedefs = self._fixturemanager.getfixturedefs(argname, parentid)
386 self._arg2fixturedefs[argname] = fixturedefs
387 # fixturedefs list is immutable so we maintain a decreasing index
388 index = self._arg2index.get(argname, 0) - 1
389 if fixturedefs is None or (-index > len(fixturedefs)):
390 raise FixtureLookupError(argname, self)
391 self._arg2index[argname] = index
392 return fixturedefs[index]
394 @property
395 def config(self):
396 """ the pytest config object associated with this request. """
397 return self._pyfuncitem.config
399 @scopeproperty()
400 def function(self):
401 """ test function object if the request has a per-function scope. """
402 return self._pyfuncitem.obj
404 @scopeproperty("class")
405 def cls(self):
406 """ class (can be None) where the test function was collected. """
407 clscol = self._pyfuncitem.getparent(_pytest.python.Class)
408 if clscol:
409 return clscol.obj
411 @property
412 def instance(self):
413 """ instance (can be None) on which test function was collected. """
414 # unittest support hack, see _pytest.unittest.TestCaseFunction
415 try:
416 return self._pyfuncitem._testcase
417 except AttributeError:
418 function = getattr(self, "function", None)
419 return getattr(function, "__self__", None)
421 @scopeproperty()
422 def module(self):
423 """ python module object where the test function was collected. """
424 return self._pyfuncitem.getparent(_pytest.python.Module).obj
426 @scopeproperty()
427 def fspath(self) -> py.path.local:
428 """ the file system path of the test module which collected this test. """
429 return self._pyfuncitem.fspath
431 @property
432 def keywords(self):
433 """ keywords/markers dictionary for the underlying node. """
434 return self.node.keywords
436 @property
437 def session(self):
438 """ pytest session object. """
439 return self._pyfuncitem.session
441 def addfinalizer(self, finalizer):
442 """ add finalizer/teardown function to be called after the
443 last test within the requesting test context finished
444 execution. """
445 # XXX usually this method is shadowed by fixturedef specific ones
446 self._addfinalizer(finalizer, scope=self.scope)
448 def _addfinalizer(self, finalizer, scope):
449 colitem = self._getscopeitem(scope)
450 self._pyfuncitem.session._setupstate.addfinalizer(
451 finalizer=finalizer, colitem=colitem
452 )
454 def applymarker(self, marker):
455 """ Apply a marker to a single test function invocation.
456 This method is useful if you don't want to have a keyword/marker
457 on all function invocations.
459 :arg marker: a :py:class:`_pytest.mark.MarkDecorator` object
460 created by a call to ``pytest.mark.NAME(...)``.
461 """
462 self.node.add_marker(marker)
464 def raiseerror(self, msg):
465 """ raise a FixtureLookupError with the given message. """
466 raise self._fixturemanager.FixtureLookupError(None, self, msg)
468 def _fillfixtures(self):
469 item = self._pyfuncitem
470 fixturenames = getattr(item, "fixturenames", self.fixturenames)
471 for argname in fixturenames:
472 if argname not in item.funcargs:
473 item.funcargs[argname] = self.getfixturevalue(argname)
475 def getfixturevalue(self, argname):
476 """ Dynamically run a named fixture function.
478 Declaring fixtures via function argument is recommended where possible.
479 But if you can only decide whether to use another fixture at test
480 setup time, you may use this function to retrieve it inside a fixture
481 or test function body.
482 """
483 return self._get_active_fixturedef(argname).cached_result[0]
485 def _get_active_fixturedef(self, argname):
486 try:
487 return self._fixture_defs[argname]
488 except KeyError:
489 try:
490 fixturedef = self._getnextfixturedef(argname)
491 except FixtureLookupError:
492 if argname == "request":
493 cached_result = (self, [0], None)
494 scope = "function"
495 return PseudoFixtureDef(cached_result, scope)
496 raise
497 # remove indent to prevent the python3 exception
498 # from leaking into the call
499 self._compute_fixture_value(fixturedef)
500 self._fixture_defs[argname] = fixturedef
501 return fixturedef
503 def _get_fixturestack(self):
504 current = self
505 values = []
506 while 1:
507 fixturedef = getattr(current, "_fixturedef", None)
508 if fixturedef is None:
509 values.reverse()
510 return values
511 values.append(fixturedef)
512 current = current._parent_request
514 def _compute_fixture_value(self, fixturedef):
515 """
516 Creates a SubRequest based on "self" and calls the execute method of the given fixturedef object. This will
517 force the FixtureDef object to throw away any previous results and compute a new fixture value, which
518 will be stored into the FixtureDef object itself.
520 :param FixtureDef fixturedef:
521 """
522 # prepare a subrequest object before calling fixture function
523 # (latter managed by fixturedef)
524 argname = fixturedef.argname
525 funcitem = self._pyfuncitem
526 scope = fixturedef.scope
527 try:
528 param = funcitem.callspec.getparam(argname)
529 except (AttributeError, ValueError):
530 param = NOTSET
531 param_index = 0
532 has_params = fixturedef.params is not None
533 fixtures_not_supported = getattr(funcitem, "nofuncargs", False)
534 if has_params and fixtures_not_supported:
535 msg = (
536 "{name} does not support fixtures, maybe unittest.TestCase subclass?\n"
537 "Node id: {nodeid}\n"
538 "Function type: {typename}"
539 ).format(
540 name=funcitem.name,
541 nodeid=funcitem.nodeid,
542 typename=type(funcitem).__name__,
543 )
544 fail(msg, pytrace=False)
545 if has_params:
546 frame = inspect.stack()[3]
547 frameinfo = inspect.getframeinfo(frame[0])
548 source_path = frameinfo.filename
549 source_lineno = frameinfo.lineno
550 source_path = py.path.local(source_path)
551 if source_path.relto(funcitem.config.rootdir):
552 source_path = source_path.relto(funcitem.config.rootdir)
553 msg = (
554 "The requested fixture has no parameter defined for test:\n"
555 " {}\n\n"
556 "Requested fixture '{}' defined in:\n{}"
557 "\n\nRequested here:\n{}:{}".format(
558 funcitem.nodeid,
559 fixturedef.argname,
560 getlocation(fixturedef.func, funcitem.config.rootdir),
561 source_path,
562 source_lineno,
563 )
564 )
565 fail(msg, pytrace=False)
566 else:
567 param_index = funcitem.callspec.indices[argname]
568 # if a parametrize invocation set a scope it will override
569 # the static scope defined with the fixture function
570 paramscopenum = funcitem.callspec._arg2scopenum.get(argname)
571 if paramscopenum is not None:
572 scope = scopes[paramscopenum]
574 subrequest = SubRequest(self, scope, param, param_index, fixturedef)
576 # check if a higher-level scoped fixture accesses a lower level one
577 subrequest._check_scope(argname, self.scope, scope)
578 try:
579 # call the fixture function
580 fixturedef.execute(request=subrequest)
581 finally:
582 self._schedule_finalizers(fixturedef, subrequest)
584 def _schedule_finalizers(self, fixturedef, subrequest):
585 # if fixture function failed it might have registered finalizers
586 self.session._setupstate.addfinalizer(
587 functools.partial(fixturedef.finish, request=subrequest), subrequest.node
588 )
590 def _check_scope(self, argname, invoking_scope, requested_scope):
591 if argname == "request":
592 return
593 if scopemismatch(invoking_scope, requested_scope):
594 # try to report something helpful
595 lines = self._factorytraceback()
596 fail(
597 "ScopeMismatch: You tried to access the %r scoped "
598 "fixture %r with a %r scoped request object, "
599 "involved factories\n%s"
600 % ((requested_scope, argname, invoking_scope, "\n".join(lines))),
601 pytrace=False,
602 )
604 def _factorytraceback(self):
605 lines = []
606 for fixturedef in self._get_fixturestack():
607 factory = fixturedef.func
608 fs, lineno = getfslineno(factory)
609 p = self._pyfuncitem.session.fspath.bestrelpath(fs)
610 args = _format_args(factory)
611 lines.append("%s:%d: def %s%s" % (p, lineno + 1, factory.__name__, args))
612 return lines
614 def _getscopeitem(self, scope):
615 if scope == "function":
616 # this might also be a non-function Item despite its attribute name
617 return self._pyfuncitem
618 if scope == "package":
619 node = get_scope_package(self._pyfuncitem, self._fixturedef)
620 else:
621 node = get_scope_node(self._pyfuncitem, scope)
622 if node is None and scope == "class":
623 # fallback to function item itself
624 node = self._pyfuncitem
625 assert node, 'Could not obtain a node for scope "{}" for function {!r}'.format(
626 scope, self._pyfuncitem
627 )
628 return node
630 def __repr__(self):
631 return "<FixtureRequest for %r>" % (self.node)
634class SubRequest(FixtureRequest):
635 """ a sub request for handling getting a fixture from a
636 test function/fixture. """
638 def __init__(self, request, scope, param, param_index, fixturedef):
639 self._parent_request = request
640 self.fixturename = fixturedef.argname
641 if param is not NOTSET:
642 self.param = param
643 self.param_index = param_index
644 self.scope = scope
645 self._fixturedef = fixturedef
646 self._pyfuncitem = request._pyfuncitem
647 self._fixture_defs = request._fixture_defs
648 self._arg2fixturedefs = request._arg2fixturedefs
649 self._arg2index = request._arg2index
650 self._fixturemanager = request._fixturemanager
652 def __repr__(self):
653 return "<SubRequest {!r} for {!r}>".format(self.fixturename, self._pyfuncitem)
655 def addfinalizer(self, finalizer):
656 self._fixturedef.addfinalizer(finalizer)
658 def _schedule_finalizers(self, fixturedef, subrequest):
659 # if the executing fixturedef was not explicitly requested in the argument list (via
660 # getfixturevalue inside the fixture call) then ensure this fixture def will be finished
661 # first
662 if fixturedef.argname not in self.fixturenames:
663 fixturedef.addfinalizer(
664 functools.partial(self._fixturedef.finish, request=self)
665 )
666 super()._schedule_finalizers(fixturedef, subrequest)
669scopes = "session package module class function".split()
670scopenum_function = scopes.index("function")
673def scopemismatch(currentscope, newscope):
674 return scopes.index(newscope) > scopes.index(currentscope)
677def scope2index(scope, descr, where=None):
678 """Look up the index of ``scope`` and raise a descriptive value error
679 if not defined.
680 """
681 try:
682 return scopes.index(scope)
683 except ValueError:
684 fail(
685 "{} {}got an unexpected scope value '{}'".format(
686 descr, "from {} ".format(where) if where else "", scope
687 ),
688 pytrace=False,
689 )
692class FixtureLookupError(LookupError):
693 """ could not return a requested Fixture (missing or invalid). """
695 def __init__(self, argname, request, msg=None):
696 self.argname = argname
697 self.request = request
698 self.fixturestack = request._get_fixturestack()
699 self.msg = msg
701 def formatrepr(self) -> "FixtureLookupErrorRepr":
702 tblines = [] # type: List[str]
703 addline = tblines.append
704 stack = [self.request._pyfuncitem.obj]
705 stack.extend(map(lambda x: x.func, self.fixturestack))
706 msg = self.msg
707 if msg is not None:
708 # the last fixture raise an error, let's present
709 # it at the requesting side
710 stack = stack[:-1]
711 for function in stack:
712 fspath, lineno = getfslineno(function)
713 try:
714 lines, _ = inspect.getsourcelines(get_real_func(function))
715 except (IOError, IndexError, TypeError):
716 error_msg = "file %s, line %s: source code not available"
717 addline(error_msg % (fspath, lineno + 1))
718 else:
719 addline("file {}, line {}".format(fspath, lineno + 1))
720 for i, line in enumerate(lines):
721 line = line.rstrip()
722 addline(" " + line)
723 if line.lstrip().startswith("def"):
724 break
726 if msg is None:
727 fm = self.request._fixturemanager
728 available = set()
729 parentid = self.request._pyfuncitem.parent.nodeid
730 for name, fixturedefs in fm._arg2fixturedefs.items():
731 faclist = list(fm._matchfactories(fixturedefs, parentid))
732 if faclist:
733 available.add(name)
734 if self.argname in available:
735 msg = " recursive dependency involving fixture '{}' detected".format(
736 self.argname
737 )
738 else:
739 msg = "fixture '{}' not found".format(self.argname)
740 msg += "\n available fixtures: {}".format(", ".join(sorted(available)))
741 msg += "\n use 'pytest --fixtures [testpath]' for help on them."
743 return FixtureLookupErrorRepr(fspath, lineno, tblines, msg, self.argname)
746class FixtureLookupErrorRepr(TerminalRepr):
747 def __init__(self, filename, firstlineno, tblines, errorstring, argname):
748 self.tblines = tblines
749 self.errorstring = errorstring
750 self.filename = filename
751 self.firstlineno = firstlineno
752 self.argname = argname
754 def toterminal(self, tw: py.io.TerminalWriter) -> None:
755 # tw.line("FixtureLookupError: %s" %(self.argname), red=True)
756 for tbline in self.tblines:
757 tw.line(tbline.rstrip())
758 lines = self.errorstring.split("\n")
759 if lines:
760 tw.line(
761 "{} {}".format(FormattedExcinfo.fail_marker, lines[0].strip()),
762 red=True,
763 )
764 for line in lines[1:]:
765 tw.line(
766 "{} {}".format(FormattedExcinfo.flow_marker, line.strip()),
767 red=True,
768 )
769 tw.line()
770 tw.line("%s:%d" % (self.filename, self.firstlineno + 1))
773def fail_fixturefunc(fixturefunc, msg):
774 fs, lineno = getfslineno(fixturefunc)
775 location = "{}:{}".format(fs, lineno + 1)
776 source = _pytest._code.Source(fixturefunc)
777 fail(msg + ":\n\n" + str(source.indent()) + "\n" + location, pytrace=False)
780def call_fixture_func(fixturefunc, request, kwargs):
781 yieldctx = is_generator(fixturefunc)
782 if yieldctx:
783 it = fixturefunc(**kwargs)
784 res = next(it)
785 finalizer = functools.partial(_teardown_yield_fixture, fixturefunc, it)
786 request.addfinalizer(finalizer)
787 else:
788 res = fixturefunc(**kwargs)
789 return res
792def _teardown_yield_fixture(fixturefunc, it):
793 """Executes the teardown of a fixture function by advancing the iterator after the
794 yield and ensure the iteration ends (if not it means there is more than one yield in the function)"""
795 try:
796 next(it)
797 except StopIteration:
798 pass
799 else:
800 fail_fixturefunc(
801 fixturefunc, "yield_fixture function has more than one 'yield'"
802 )
805def _eval_scope_callable(scope_callable, fixture_name, config):
806 try:
807 result = scope_callable(fixture_name=fixture_name, config=config)
808 except Exception:
809 raise TypeError(
810 "Error evaluating {} while defining fixture '{}'.\n"
811 "Expected a function with the signature (*, fixture_name, config)".format(
812 scope_callable, fixture_name
813 )
814 )
815 if not isinstance(result, str):
816 fail(
817 "Expected {} to return a 'str' while defining fixture '{}', but it returned:\n"
818 "{!r}".format(scope_callable, fixture_name, result),
819 pytrace=False,
820 )
821 return result
824class FixtureDef:
825 """ A container for a factory definition. """
827 def __init__(
828 self,
829 fixturemanager,
830 baseid,
831 argname,
832 func,
833 scope,
834 params,
835 unittest=False,
836 ids=None,
837 ):
838 self._fixturemanager = fixturemanager
839 self.baseid = baseid or ""
840 self.has_location = baseid is not None
841 self.func = func
842 self.argname = argname
843 if callable(scope):
844 scope = _eval_scope_callable(scope, argname, fixturemanager.config)
845 self.scope = scope
846 self.scopenum = scope2index(
847 scope or "function",
848 descr="Fixture '{}'".format(func.__name__),
849 where=baseid,
850 )
851 self.params = params
852 self.argnames = getfuncargnames(func, name=argname, is_method=unittest)
853 self.unittest = unittest
854 self.ids = ids
855 self._finalizers = []
857 def addfinalizer(self, finalizer):
858 self._finalizers.append(finalizer)
860 def finish(self, request):
861 exceptions = []
862 try:
863 while self._finalizers:
864 try:
865 func = self._finalizers.pop()
866 func()
867 except: # noqa
868 exceptions.append(sys.exc_info())
869 if exceptions:
870 _, val, tb = exceptions[0]
871 # Ensure to not keep frame references through traceback.
872 del exceptions
873 raise val.with_traceback(tb)
874 finally:
875 hook = self._fixturemanager.session.gethookproxy(request.node.fspath)
876 hook.pytest_fixture_post_finalizer(fixturedef=self, request=request)
877 # even if finalization fails, we invalidate
878 # the cached fixture value and remove
879 # all finalizers because they may be bound methods which will
880 # keep instances alive
881 if hasattr(self, "cached_result"):
882 del self.cached_result
883 self._finalizers = []
885 def execute(self, request):
886 # get required arguments and register our own finish()
887 # with their finalization
888 for argname in self.argnames:
889 fixturedef = request._get_active_fixturedef(argname)
890 if argname != "request":
891 fixturedef.addfinalizer(functools.partial(self.finish, request=request))
893 my_cache_key = self.cache_key(request)
894 cached_result = getattr(self, "cached_result", None)
895 if cached_result is not None:
896 result, cache_key, err = cached_result
897 if my_cache_key == cache_key:
898 if err is not None:
899 _, val, tb = err
900 raise val.with_traceback(tb)
901 else:
902 return result
903 # we have a previous but differently parametrized fixture instance
904 # so we need to tear it down before creating a new one
905 self.finish(request)
906 assert not hasattr(self, "cached_result")
908 hook = self._fixturemanager.session.gethookproxy(request.node.fspath)
909 return hook.pytest_fixture_setup(fixturedef=self, request=request)
911 def cache_key(self, request):
912 return request.param_index if not hasattr(request, "param") else request.param
914 def __repr__(self):
915 return "<FixtureDef argname={!r} scope={!r} baseid={!r}>".format(
916 self.argname, self.scope, self.baseid
917 )
920def resolve_fixture_function(fixturedef, request):
921 """Gets the actual callable that can be called to obtain the fixture value, dealing with unittest-specific
922 instances and bound methods.
923 """
924 fixturefunc = fixturedef.func
925 if fixturedef.unittest:
926 if request.instance is not None:
927 # bind the unbound method to the TestCase instance
928 fixturefunc = fixturedef.func.__get__(request.instance)
929 else:
930 # the fixture function needs to be bound to the actual
931 # request.instance so that code working with "fixturedef" behaves
932 # as expected.
933 if request.instance is not None:
934 # handle the case where fixture is defined not in a test class, but some other class
935 # (for example a plugin class with a fixture), see #2270
936 if hasattr(fixturefunc, "__self__") and not isinstance(
937 request.instance, fixturefunc.__self__.__class__
938 ):
939 return fixturefunc
940 fixturefunc = getimfunc(fixturedef.func)
941 if fixturefunc != fixturedef.func:
942 fixturefunc = fixturefunc.__get__(request.instance)
943 return fixturefunc
946def pytest_fixture_setup(fixturedef, request):
947 """ Execution of fixture setup. """
948 kwargs = {}
949 for argname in fixturedef.argnames:
950 fixdef = request._get_active_fixturedef(argname)
951 result, arg_cache_key, exc = fixdef.cached_result
952 request._check_scope(argname, request.scope, fixdef.scope)
953 kwargs[argname] = result
955 fixturefunc = resolve_fixture_function(fixturedef, request)
956 my_cache_key = fixturedef.cache_key(request)
957 try:
958 result = call_fixture_func(fixturefunc, request, kwargs)
959 except TEST_OUTCOME:
960 fixturedef.cached_result = (None, my_cache_key, sys.exc_info())
961 raise
962 fixturedef.cached_result = (result, my_cache_key, None)
963 return result
966def _ensure_immutable_ids(ids):
967 if ids is None:
968 return
969 if callable(ids):
970 return ids
971 return tuple(ids)
974def wrap_function_to_error_out_if_called_directly(function, fixture_marker):
975 """Wrap the given fixture function so we can raise an error about it being called directly,
976 instead of used as an argument in a test function.
977 """
978 message = (
979 'Fixture "{name}" called directly. Fixtures are not meant to be called directly,\n'
980 "but are created automatically when test functions request them as parameters.\n"
981 "See https://docs.pytest.org/en/latest/fixture.html for more information about fixtures, and\n"
982 "https://docs.pytest.org/en/latest/deprecations.html#calling-fixtures-directly about how to update your code."
983 ).format(name=fixture_marker.name or function.__name__)
985 @functools.wraps(function)
986 def result(*args, **kwargs):
987 fail(message, pytrace=False)
989 # keep reference to the original function in our own custom attribute so we don't unwrap
990 # further than this point and lose useful wrappings like @mock.patch (#3774)
991 result.__pytest_wrapped__ = _PytestWrapper(function)
993 return result
996@attr.s(frozen=True)
997class FixtureFunctionMarker:
998 scope = attr.ib()
999 params = attr.ib(converter=attr.converters.optional(tuple))
1000 autouse = attr.ib(default=False)
1001 # Ignore type because of https://github.com/python/mypy/issues/6172.
1002 ids = attr.ib(default=None, converter=_ensure_immutable_ids) # type: ignore
1003 name = attr.ib(default=None)
1005 def __call__(self, function):
1006 if inspect.isclass(function):
1007 raise ValueError("class fixtures not supported (maybe in the future)")
1009 if getattr(function, "_pytestfixturefunction", False):
1010 raise ValueError(
1011 "fixture is being applied more than once to the same function"
1012 )
1014 function = wrap_function_to_error_out_if_called_directly(function, self)
1016 name = self.name or function.__name__
1017 if name == "request":
1018 location = getlocation(function)
1019 fail(
1020 "'request' is a reserved word for fixtures, use another name:\n {}".format(
1021 location
1022 ),
1023 pytrace=False,
1024 )
1025 function._pytestfixturefunction = self
1026 return function
1029FIXTURE_ARGS_ORDER = ("scope", "params", "autouse", "ids", "name")
1032def _parse_fixture_args(callable_or_scope, *args, **kwargs):
1033 arguments = {
1034 "scope": "function",
1035 "params": None,
1036 "autouse": False,
1037 "ids": None,
1038 "name": None,
1039 }
1040 kwargs = {
1041 key: value for key, value in kwargs.items() if arguments.get(key) != value
1042 }
1044 fixture_function = None
1045 if isinstance(callable_or_scope, str):
1046 args = list(args)
1047 args.insert(0, callable_or_scope)
1048 else:
1049 fixture_function = callable_or_scope
1051 positionals = set()
1052 for positional, argument_name in zip(args, FIXTURE_ARGS_ORDER):
1053 arguments[argument_name] = positional
1054 positionals.add(argument_name)
1056 duplicated_kwargs = {kwarg for kwarg in kwargs.keys() if kwarg in positionals}
1057 if duplicated_kwargs:
1058 raise TypeError(
1059 "The fixture arguments are defined as positional and keyword: {}. "
1060 "Use only keyword arguments.".format(", ".join(duplicated_kwargs))
1061 )
1063 if positionals:
1064 warnings.warn(FIXTURE_POSITIONAL_ARGUMENTS, stacklevel=2)
1066 arguments.update(kwargs)
1068 return fixture_function, arguments
1071def fixture(
1072 callable_or_scope=None,
1073 *args,
1074 scope="function",
1075 params=None,
1076 autouse=False,
1077 ids=None,
1078 name=None
1079):
1080 """Decorator to mark a fixture factory function.
1082 This decorator can be used, with or without parameters, to define a
1083 fixture function.
1085 The name of the fixture function can later be referenced to cause its
1086 invocation ahead of running tests: test
1087 modules or classes can use the ``pytest.mark.usefixtures(fixturename)``
1088 marker.
1090 Test functions can directly use fixture names as input
1091 arguments in which case the fixture instance returned from the fixture
1092 function will be injected.
1094 Fixtures can provide their values to test functions using ``return`` or ``yield``
1095 statements. When using ``yield`` the code block after the ``yield`` statement is executed
1096 as teardown code regardless of the test outcome, and must yield exactly once.
1098 :arg scope: the scope for which this fixture is shared, one of
1099 ``"function"`` (default), ``"class"``, ``"module"``,
1100 ``"package"`` or ``"session"`` (``"package"`` is considered **experimental**
1101 at this time).
1103 This parameter may also be a callable which receives ``(fixture_name, config)``
1104 as parameters, and must return a ``str`` with one of the values mentioned above.
1106 See :ref:`dynamic scope` in the docs for more information.
1108 :arg params: an optional list of parameters which will cause multiple
1109 invocations of the fixture function and all of the tests
1110 using it.
1111 The current parameter is available in ``request.param``.
1113 :arg autouse: if True, the fixture func is activated for all tests that
1114 can see it. If False (the default) then an explicit
1115 reference is needed to activate the fixture.
1117 :arg ids: list of string ids each corresponding to the params
1118 so that they are part of the test id. If no ids are provided
1119 they will be generated automatically from the params.
1121 :arg name: the name of the fixture. This defaults to the name of the
1122 decorated function. If a fixture is used in the same module in
1123 which it is defined, the function name of the fixture will be
1124 shadowed by the function arg that requests the fixture; one way
1125 to resolve this is to name the decorated function
1126 ``fixture_<fixturename>`` and then use
1127 ``@pytest.fixture(name='<fixturename>')``.
1128 """
1129 if params is not None:
1130 params = list(params)
1132 fixture_function, arguments = _parse_fixture_args(
1133 callable_or_scope,
1134 *args,
1135 scope=scope,
1136 params=params,
1137 autouse=autouse,
1138 ids=ids,
1139 name=name
1140 )
1141 scope = arguments.get("scope")
1142 params = arguments.get("params")
1143 autouse = arguments.get("autouse")
1144 ids = arguments.get("ids")
1145 name = arguments.get("name")
1147 if fixture_function and params is None and autouse is False:
1148 # direct decoration
1149 return FixtureFunctionMarker(scope, params, autouse, name=name)(
1150 fixture_function
1151 )
1153 return FixtureFunctionMarker(scope, params, autouse, ids=ids, name=name)
1156def yield_fixture(
1157 callable_or_scope=None,
1158 *args,
1159 scope="function",
1160 params=None,
1161 autouse=False,
1162 ids=None,
1163 name=None
1164):
1165 """ (return a) decorator to mark a yield-fixture factory function.
1167 .. deprecated:: 3.0
1168 Use :py:func:`pytest.fixture` directly instead.
1169 """
1170 return fixture(
1171 callable_or_scope,
1172 *args,
1173 scope=scope,
1174 params=params,
1175 autouse=autouse,
1176 ids=ids,
1177 name=name
1178 )
1181defaultfuncargprefixmarker = fixture()
1184@fixture(scope="session")
1185def pytestconfig(request):
1186 """Session-scoped fixture that returns the :class:`_pytest.config.Config` object.
1188 Example::
1190 def test_foo(pytestconfig):
1191 if pytestconfig.getoption("verbose") > 0:
1192 ...
1194 """
1195 return request.config
1198def pytest_addoption(parser):
1199 parser.addini(
1200 "usefixtures",
1201 type="args",
1202 default=[],
1203 help="list of default fixtures to be used with this project",
1204 )
1207class FixtureManager:
1208 """
1209 pytest fixtures definitions and information is stored and managed
1210 from this class.
1212 During collection fm.parsefactories() is called multiple times to parse
1213 fixture function definitions into FixtureDef objects and internal
1214 data structures.
1216 During collection of test functions, metafunc-mechanics instantiate
1217 a FuncFixtureInfo object which is cached per node/func-name.
1218 This FuncFixtureInfo object is later retrieved by Function nodes
1219 which themselves offer a fixturenames attribute.
1221 The FuncFixtureInfo object holds information about fixtures and FixtureDefs
1222 relevant for a particular function. An initial list of fixtures is
1223 assembled like this:
1225 - ini-defined usefixtures
1226 - autouse-marked fixtures along the collection chain up from the function
1227 - usefixtures markers at module/class/function level
1228 - test function funcargs
1230 Subsequently the funcfixtureinfo.fixturenames attribute is computed
1231 as the closure of the fixtures needed to setup the initial fixtures,
1232 i. e. fixtures needed by fixture functions themselves are appended
1233 to the fixturenames list.
1235 Upon the test-setup phases all fixturenames are instantiated, retrieved
1236 by a lookup of their FuncFixtureInfo.
1237 """
1239 FixtureLookupError = FixtureLookupError
1240 FixtureLookupErrorRepr = FixtureLookupErrorRepr
1242 def __init__(self, session):
1243 self.session = session
1244 self.config = session.config
1245 self._arg2fixturedefs = {}
1246 self._holderobjseen = set()
1247 self._arg2finish = {}
1248 self._nodeid_and_autousenames = [("", self.config.getini("usefixtures"))]
1249 session.config.pluginmanager.register(self, "funcmanage")
1251 def _get_direct_parametrize_args(self, node):
1252 """This function returns all the direct parametrization
1253 arguments of a node, so we don't mistake them for fixtures
1255 Check https://github.com/pytest-dev/pytest/issues/5036
1257 This things are done later as well when dealing with parametrization
1258 so this could be improved
1259 """
1260 from _pytest.mark import ParameterSet
1262 parametrize_argnames = []
1263 for marker in node.iter_markers(name="parametrize"):
1264 if not marker.kwargs.get("indirect", False):
1265 p_argnames, _ = ParameterSet._parse_parametrize_args(
1266 *marker.args, **marker.kwargs
1267 )
1268 parametrize_argnames.extend(p_argnames)
1270 return parametrize_argnames
1272 def getfixtureinfo(self, node, func, cls, funcargs=True):
1273 if funcargs and not getattr(node, "nofuncargs", False):
1274 argnames = getfuncargnames(func, name=node.name, cls=cls)
1275 else:
1276 argnames = ()
1278 usefixtures = itertools.chain.from_iterable(
1279 mark.args for mark in node.iter_markers(name="usefixtures")
1280 )
1281 initialnames = tuple(usefixtures) + argnames
1282 fm = node.session._fixturemanager
1283 initialnames, names_closure, arg2fixturedefs = fm.getfixtureclosure(
1284 initialnames, node, ignore_args=self._get_direct_parametrize_args(node)
1285 )
1286 return FuncFixtureInfo(argnames, initialnames, names_closure, arg2fixturedefs)
1288 def pytest_plugin_registered(self, plugin):
1289 nodeid = None
1290 try:
1291 p = py.path.local(plugin.__file__).realpath()
1292 except AttributeError:
1293 pass
1294 else:
1295 from _pytest import nodes
1297 # construct the base nodeid which is later used to check
1298 # what fixtures are visible for particular tests (as denoted
1299 # by their test id)
1300 if p.basename.startswith("conftest.py"):
1301 nodeid = p.dirpath().relto(self.config.rootdir)
1302 if p.sep != nodes.SEP:
1303 nodeid = nodeid.replace(p.sep, nodes.SEP)
1305 self.parsefactories(plugin, nodeid)
1307 def _getautousenames(self, nodeid):
1308 """ return a tuple of fixture names to be used. """
1309 autousenames = []
1310 for baseid, basenames in self._nodeid_and_autousenames:
1311 if nodeid.startswith(baseid):
1312 if baseid:
1313 i = len(baseid)
1314 nextchar = nodeid[i : i + 1]
1315 if nextchar and nextchar not in ":/":
1316 continue
1317 autousenames.extend(basenames)
1318 return autousenames
1320 def getfixtureclosure(self, fixturenames, parentnode, ignore_args=()):
1321 # collect the closure of all fixtures , starting with the given
1322 # fixturenames as the initial set. As we have to visit all
1323 # factory definitions anyway, we also return an arg2fixturedefs
1324 # mapping so that the caller can reuse it and does not have
1325 # to re-discover fixturedefs again for each fixturename
1326 # (discovering matching fixtures for a given name/node is expensive)
1328 parentid = parentnode.nodeid
1329 fixturenames_closure = self._getautousenames(parentid)
1331 def merge(otherlist):
1332 for arg in otherlist:
1333 if arg not in fixturenames_closure:
1334 fixturenames_closure.append(arg)
1336 merge(fixturenames)
1338 # at this point, fixturenames_closure contains what we call "initialnames",
1339 # which is a set of fixturenames the function immediately requests. We
1340 # need to return it as well, so save this.
1341 initialnames = tuple(fixturenames_closure)
1343 arg2fixturedefs = {}
1344 lastlen = -1
1345 while lastlen != len(fixturenames_closure):
1346 lastlen = len(fixturenames_closure)
1347 for argname in fixturenames_closure:
1348 if argname in ignore_args:
1349 continue
1350 if argname in arg2fixturedefs:
1351 continue
1352 fixturedefs = self.getfixturedefs(argname, parentid)
1353 if fixturedefs:
1354 arg2fixturedefs[argname] = fixturedefs
1355 merge(fixturedefs[-1].argnames)
1357 def sort_by_scope(arg_name):
1358 try:
1359 fixturedefs = arg2fixturedefs[arg_name]
1360 except KeyError:
1361 return scopes.index("function")
1362 else:
1363 return fixturedefs[-1].scopenum
1365 fixturenames_closure.sort(key=sort_by_scope)
1366 return initialnames, fixturenames_closure, arg2fixturedefs
1368 def pytest_generate_tests(self, metafunc):
1369 for argname in metafunc.fixturenames:
1370 faclist = metafunc._arg2fixturedefs.get(argname)
1371 if faclist:
1372 fixturedef = faclist[-1]
1373 if fixturedef.params is not None:
1374 markers = list(metafunc.definition.iter_markers("parametrize"))
1375 for parametrize_mark in markers:
1376 if "argnames" in parametrize_mark.kwargs:
1377 argnames = parametrize_mark.kwargs["argnames"]
1378 else:
1379 argnames = parametrize_mark.args[0]
1381 if not isinstance(argnames, (tuple, list)):
1382 argnames = [
1383 x.strip() for x in argnames.split(",") if x.strip()
1384 ]
1385 if argname in argnames:
1386 break
1387 else:
1388 metafunc.parametrize(
1389 argname,
1390 fixturedef.params,
1391 indirect=True,
1392 scope=fixturedef.scope,
1393 ids=fixturedef.ids,
1394 )
1395 else:
1396 continue # will raise FixtureLookupError at setup time
1398 def pytest_collection_modifyitems(self, items):
1399 # separate parametrized setups
1400 items[:] = reorder_items(items)
1402 def parsefactories(self, node_or_obj, nodeid=NOTSET, unittest=False):
1403 if nodeid is not NOTSET:
1404 holderobj = node_or_obj
1405 else:
1406 holderobj = node_or_obj.obj
1407 nodeid = node_or_obj.nodeid
1408 if holderobj in self._holderobjseen:
1409 return
1411 self._holderobjseen.add(holderobj)
1412 autousenames = []
1413 for name in dir(holderobj):
1414 # The attribute can be an arbitrary descriptor, so the attribute
1415 # access below can raise. safe_getatt() ignores such exceptions.
1416 obj = safe_getattr(holderobj, name, None)
1417 marker = getfixturemarker(obj)
1418 if not isinstance(marker, FixtureFunctionMarker):
1419 # magic globals with __getattr__ might have got us a wrong
1420 # fixture attribute
1421 continue
1423 if marker.name:
1424 name = marker.name
1426 # during fixture definition we wrap the original fixture function
1427 # to issue a warning if called directly, so here we unwrap it in order to not emit the warning
1428 # when pytest itself calls the fixture function
1429 obj = get_real_method(obj, holderobj)
1431 fixture_def = FixtureDef(
1432 self,
1433 nodeid,
1434 name,
1435 obj,
1436 marker.scope,
1437 marker.params,
1438 unittest=unittest,
1439 ids=marker.ids,
1440 )
1442 faclist = self._arg2fixturedefs.setdefault(name, [])
1443 if fixture_def.has_location:
1444 faclist.append(fixture_def)
1445 else:
1446 # fixturedefs with no location are at the front
1447 # so this inserts the current fixturedef after the
1448 # existing fixturedefs from external plugins but
1449 # before the fixturedefs provided in conftests.
1450 i = len([f for f in faclist if not f.has_location])
1451 faclist.insert(i, fixture_def)
1452 if marker.autouse:
1453 autousenames.append(name)
1455 if autousenames:
1456 self._nodeid_and_autousenames.append((nodeid or "", autousenames))
1458 def getfixturedefs(self, argname, nodeid):
1459 """
1460 Gets a list of fixtures which are applicable to the given node id.
1462 :param str argname: name of the fixture to search for
1463 :param str nodeid: full node id of the requesting test.
1464 :return: list[FixtureDef]
1465 """
1466 try:
1467 fixturedefs = self._arg2fixturedefs[argname]
1468 except KeyError:
1469 return None
1470 return tuple(self._matchfactories(fixturedefs, nodeid))
1472 def _matchfactories(self, fixturedefs, nodeid):
1473 from _pytest import nodes
1475 for fixturedef in fixturedefs:
1476 if nodes.ischildnode(fixturedef.baseid, nodeid):
1477 yield fixturedef