3
from py._code.code import FormattedExcinfo
11
from _pytest._code.code import TerminalRepr
12
from _pytest.compat import (
13
NOTSET, exc_clear, _format_args,
14
getfslineno, get_real_func,
15
is_generator, isclass, getimfunc,
16
getlocation, getfuncargnames,
19
def pytest_sessionstart(session):
20
session._fixturemanager = FixtureManager(session)
26
scope2props = dict(session=())
27
scope2props["module"] = ("fspath", "module")
28
scope2props["class"] = scope2props["module"] + ("cls",)
29
scope2props["instance"] = scope2props["class"] + ("instance", )
30
scope2props["function"] = scope2props["instance"] + ("function", "keywords")
32
def scopeproperty(name=None, doc=None):
33
def decoratescope(func):
34
scopename = name or func.__name__
37
if func.__name__ in scope2props[self.scope]:
39
raise AttributeError("%s not available in %s-scoped context" % (
40
scopename, self.scope))
42
return property(provide, None, None, func.__doc__)
46
def pytest_namespace():
47
scopename2class.update({
48
'class': pytest.Class,
49
'module': pytest.Module,
50
'function': pytest.Item,
54
'yield_fixture': yield_fixture,
55
'collect': {'_fillfuncargs': fillfixtures}
59
def get_scope_node(node, scope):
60
cls = scopename2class.get(scope)
62
if scope == "session":
64
raise ValueError("unknown scope")
65
return node.getparent(cls)
68
def add_funcarg_pseudo_fixture_def(collector, metafunc, fixturemanager):
69
# this function will transform all collected calls to a functions
70
# if they use direct funcargs (i.e. direct parametrization)
71
# because we want later test execution to be able to rely on
72
# an existing FixtureDef structure for all arguments.
73
# XXX we can probably avoid this algorithm if we modify CallSpec2
74
# to directly care for creating the fixturedefs within its methods.
75
if not metafunc._calls[0].funcargs:
76
return # this function call does not have direct parametrization
77
# collect funcargs of all callspecs into a list of values
80
for callspec in metafunc._calls:
81
for argname, argvalue in callspec.funcargs.items():
82
assert argname not in callspec.params
83
callspec.params[argname] = argvalue
84
arg2params_list = arg2params.setdefault(argname, [])
85
callspec.indices[argname] = len(arg2params_list)
86
arg2params_list.append(argvalue)
87
if argname not in arg2scope:
88
scopenum = callspec._arg2scopenum.get(argname,
90
arg2scope[argname] = scopes[scopenum]
91
callspec.funcargs.clear()
93
# register artificial FixtureDef's so that later at test execution
94
# time we can rely on a proper FixtureDef to exist for fixture setup.
95
arg2fixturedefs = metafunc._arg2fixturedefs
96
for argname, valuelist in arg2params.items():
97
# if we have a scope that is higher than function we need
98
# to make sure we only ever create an according fixturedef on
99
# a per-scope basis. We thus store and cache the fixturedef on the
100
# node related to the scope.
101
scope = arg2scope[argname]
103
if scope != "function":
104
node = get_scope_node(collector, scope)
106
assert scope == "class" and isinstance(collector, pytest.Module)
107
# use module-level collector for class-scope (for now)
109
if node and argname in node._name2pseudofixturedef:
110
arg2fixturedefs[argname] = [node._name2pseudofixturedef[argname]]
112
fixturedef = FixtureDef(fixturemanager, '', argname,
113
get_direct_param_fixture_func,
115
valuelist, False, False)
116
arg2fixturedefs[argname] = [fixturedef]
118
node._name2pseudofixturedef[argname] = fixturedef
122
def getfixturemarker(obj):
123
""" return fixturemarker or None if it doesn't exist or raised
126
return getattr(obj, "_pytestfixturefunction", None)
127
except KeyboardInterrupt:
130
# some objects raise errors like request (from flask import request)
131
# we don't expect them to be fixture functions
136
def get_parametrized_fixture_keys(item, scopenum):
137
""" return list of keys for all parametrized arguments which match
138
the specified scope. """
139
assert scopenum < scopenum_function # function
142
except AttributeError:
145
# cs.indictes.items() is random order of argnames but
146
# then again different functions (items) can change order of
147
# arguments so it doesn't matter much probably
148
for argname, param_index in cs.indices.items():
149
if cs._arg2scopenum[argname] != scopenum:
151
if scopenum == 0: # session
152
key = (argname, param_index)
153
elif scopenum == 1: # module
154
key = (argname, param_index, item.fspath)
155
elif scopenum == 2: # class
156
key = (argname, param_index, item.fspath, item.cls)
160
# algorithm for sorting on a per-parametrized resource setup basis
161
# it is called for scopenum==0 (session) first and performs sorting
162
# down to the lower scopes such as to minimize number of "high scope"
163
# setups and teardowns
165
def reorder_items(items):
167
for scopenum in range(0, scopenum_function):
168
argkeys_cache[scopenum] = d = {}
170
keys = set(get_parametrized_fixture_keys(item, scopenum))
173
return reorder_items_atscope(items, set(), argkeys_cache, 0)
175
def reorder_items_atscope(items, ignore, argkeys_cache, scopenum):
176
if scopenum >= scopenum_function or len(items) < 3:
180
items_before, items_same, items_other, newignore = \
181
slice_items(items, ignore, argkeys_cache[scopenum])
182
items_before = reorder_items_atscope(
183
items_before, ignore, argkeys_cache,scopenum+1)
184
if items_same is None:
185
# nothing to reorder in this scope
186
assert items_other is None
187
return items_done + items_before
188
items_done.extend(items_before)
189
items = items_same + items_other
193
def slice_items(items, ignore, scoped_argkeys_cache):
194
# we pick the first item which uses a fixture instance in the
195
# requested scope and which we haven't seen yet. We slice the input
196
# items list into a list of items_nomatch, items_same and
198
if scoped_argkeys_cache: # do we need to do work at all?
200
# first find a slicing key
201
for i, item in enumerate(it):
202
argkeys = scoped_argkeys_cache.get(item)
203
if argkeys is not None:
204
argkeys = argkeys.difference(ignore)
205
if argkeys: # found a slicing key
206
slicing_argkey = argkeys.pop()
207
items_before = items[:i]
210
# now slice the remainder of the list
212
argkeys = scoped_argkeys_cache.get(item)
213
if argkeys and slicing_argkey in argkeys and \
214
slicing_argkey not in ignore:
215
items_same.append(item)
217
items_other.append(item)
218
newignore = ignore.copy()
219
newignore.add(slicing_argkey)
220
return (items_before, items_same, items_other, newignore)
221
return items, None, None, None
225
class FuncargnamesCompatAttr:
226
""" helper class so that Metafunc, Function and FixtureRequest
227
don't need to each define the "funcargnames" compatibility attribute.
230
def funcargnames(self):
231
""" alias attribute for ``fixturenames`` for pre-2.3 compatibility"""
232
return self.fixturenames
235
def fillfixtures(function):
236
""" fill missing funcargs for a test function. """
238
request = function._request
239
except AttributeError:
240
# XXX this special code path is only expected to execute
241
# with the oejskit plugin. It uses classes with funcargs
242
# and we thus have to work a bit to allow this.
243
fm = function.session._fixturemanager
244
fi = fm.getfixtureinfo(function.parent, function.obj, None)
245
function._fixtureinfo = fi
246
request = function._request = FixtureRequest(function)
247
request._fillfixtures()
248
# prune out funcargs for jstests
250
for name in fi.argnames:
251
newfuncargs[name] = function.funcargs[name]
252
function.funcargs = newfuncargs
254
request._fillfixtures()
258
def get_direct_param_fixture_func(request):
261
class FuncFixtureInfo:
262
def __init__(self, argnames, names_closure, name2fixturedefs):
263
self.argnames = argnames
264
self.names_closure = names_closure
265
self.name2fixturedefs = name2fixturedefs
268
class FixtureRequest(FuncargnamesCompatAttr):
269
""" A request for a fixture from a test or fixture function.
271
A request object gives access to the requesting test context
272
and has an optional ``param`` attribute in case
273
the fixture is parametrized indirectly.
276
def __init__(self, pyfuncitem):
277
self._pyfuncitem = pyfuncitem
278
#: fixture for which this request is being performed
279
self.fixturename = None
280
#: Scope string, one of "function", "class", "module", "session"
281
self.scope = "function"
282
self._fixture_values = {} # argname -> fixture value
283
self._fixture_defs = {} # argname -> FixtureDef
284
fixtureinfo = pyfuncitem._fixtureinfo
285
self._arg2fixturedefs = fixtureinfo.name2fixturedefs.copy()
287
self._fixturemanager = pyfuncitem.session._fixturemanager
290
def fixturenames(self):
291
# backward incompatible note: now a readonly property
292
return list(self._pyfuncitem._fixtureinfo.names_closure)
296
""" underlying collection node (depends on current request scope)"""
297
return self._getscopeitem(self.scope)
300
def _getnextfixturedef(self, argname):
301
fixturedefs = self._arg2fixturedefs.get(argname, None)
302
if fixturedefs is None:
303
# we arrive here because of a a dynamic call to
304
# getfixturevalue(argname) usage which was naturally
305
# not known at parsing/collection time
306
parentid = self._pyfuncitem.parent.nodeid
307
fixturedefs = self._fixturemanager.getfixturedefs(argname, parentid)
308
self._arg2fixturedefs[argname] = fixturedefs
309
# fixturedefs list is immutable so we maintain a decreasing index
310
index = self._arg2index.get(argname, 0) - 1
311
if fixturedefs is None or (-index > len(fixturedefs)):
312
raise FixtureLookupError(argname, self)
313
self._arg2index[argname] = index
314
return fixturedefs[index]
318
""" the pytest config object associated with this request. """
319
return self._pyfuncitem.config
324
""" test function object if the request has a per-function scope. """
325
return self._pyfuncitem.obj
327
@scopeproperty("class")
329
""" class (can be None) where the test function was collected. """
330
clscol = self._pyfuncitem.getparent(pytest.Class)
336
""" instance (can be None) on which test function was collected. """
337
# unittest support hack, see _pytest.unittest.TestCaseFunction
339
return self._pyfuncitem._testcase
340
except AttributeError:
341
function = getattr(self, "function", None)
342
if function is not None:
343
return py.builtin._getimself(function)
347
""" python module object where the test function was collected. """
348
return self._pyfuncitem.getparent(pytest.Module).obj
352
""" the file system path of the test module which collected this test. """
353
return self._pyfuncitem.fspath
357
""" keywords/markers dictionary for the underlying node. """
358
return self.node.keywords
362
""" pytest session object. """
363
return self._pyfuncitem.session
365
def addfinalizer(self, finalizer):
366
""" add finalizer/teardown function to be called after the
367
last test within the requesting test context finished
369
# XXX usually this method is shadowed by fixturedef specific ones
370
self._addfinalizer(finalizer, scope=self.scope)
372
def _addfinalizer(self, finalizer, scope):
373
colitem = self._getscopeitem(scope)
374
self._pyfuncitem.session._setupstate.addfinalizer(
375
finalizer=finalizer, colitem=colitem)
377
def applymarker(self, marker):
378
""" Apply a marker to a single test function invocation.
379
This method is useful if you don't want to have a keyword/marker
380
on all function invocations.
382
:arg marker: a :py:class:`_pytest.mark.MarkDecorator` object
383
created by a call to ``pytest.mark.NAME(...)``.
386
self.node.keywords[marker.markname] = marker
387
except AttributeError:
388
raise ValueError(marker)
390
def raiseerror(self, msg):
391
""" raise a FixtureLookupError with the given message. """
392
raise self._fixturemanager.FixtureLookupError(None, self, msg)
394
def _fillfixtures(self):
395
item = self._pyfuncitem
396
fixturenames = getattr(item, "fixturenames", self.fixturenames)
397
for argname in fixturenames:
398
if argname not in item.funcargs:
399
item.funcargs[argname] = self.getfixturevalue(argname)
401
def cached_setup(self, setup, teardown=None, scope="module", extrakey=None):
402
""" (deprecated) Return a testing resource managed by ``setup`` &
403
``teardown`` calls. ``scope`` and ``extrakey`` determine when the
404
``teardown`` function will be called so that subsequent calls to
405
``setup`` would recreate the resource. With pytest-2.3 you often
406
do not need ``cached_setup()`` as you can directly declare a scope
407
on a fixture function and register a finalizer through
408
``request.addfinalizer()``.
410
:arg teardown: function receiving a previously setup resource.
411
:arg setup: a no-argument function creating a resource.
412
:arg scope: a string value out of ``function``, ``class``, ``module``
413
or ``session`` indicating the caching lifecycle of the resource.
414
:arg extrakey: added to internal caching key of (funcargname, scope).
416
if not hasattr(self.config, '_setupcache'):
417
self.config._setupcache = {} # XXX weakref?
418
cachekey = (self.fixturename, self._getscopeitem(scope), extrakey)
419
cache = self.config._setupcache
421
val = cache[cachekey]
423
self._check_scope(self.fixturename, self.scope, scope)
425
cache[cachekey] = val
426
if teardown is not None:
430
self._addfinalizer(finalizer, scope=scope)
433
def getfixturevalue(self, argname):
434
""" Dynamically run a named fixture function.
436
Declaring fixtures via function argument is recommended where possible.
437
But if you can only decide whether to use another fixture at test
438
setup time, you may use this function to retrieve it inside a fixture
439
or test function body.
441
return self._get_active_fixturedef(argname).cached_result[0]
443
def getfuncargvalue(self, argname):
444
""" Deprecated, use getfixturevalue. """
445
from _pytest import deprecated
447
deprecated.GETFUNCARGVALUE,
449
return self.getfixturevalue(argname)
451
def _get_active_fixturedef(self, argname):
453
return self._fixture_defs[argname]
456
fixturedef = self._getnextfixturedef(argname)
457
except FixtureLookupError:
458
if argname == "request":
459
class PseudoFixtureDef:
460
cached_result = (self, [0], None)
462
return PseudoFixtureDef
464
# remove indent to prevent the python3 exception
465
# from leaking into the call
466
result = self._getfixturevalue(fixturedef)
467
self._fixture_values[argname] = result
468
self._fixture_defs[argname] = fixturedef
471
def _get_fixturestack(self):
475
fixturedef = getattr(current, "_fixturedef", None)
476
if fixturedef is None:
480
current = current._parent_request
482
def _getfixturevalue(self, fixturedef):
483
# prepare a subrequest object before calling fixture function
484
# (latter managed by fixturedef)
485
argname = fixturedef.argname
486
funcitem = self._pyfuncitem
487
scope = fixturedef.scope
489
param = funcitem.callspec.getparam(argname)
490
except (AttributeError, ValueError):
493
if fixturedef.params is not None:
494
frame = inspect.stack()[3]
495
frameinfo = inspect.getframeinfo(frame[0])
496
source_path = frameinfo.filename
497
source_lineno = frameinfo.lineno
498
source_path = py.path.local(source_path)
499
if source_path.relto(funcitem.config.rootdir):
500
source_path = source_path.relto(funcitem.config.rootdir)
502
"The requested fixture has no parameter defined for the "
503
"current test.\n\nRequested fixture '{0}' defined in:\n{1}"
504
"\n\nRequested here:\n{2}:{3}".format(
506
getlocation(fixturedef.func, funcitem.config.rootdir),
513
# indices might not be set if old-style metafunc.addcall() was used
514
param_index = funcitem.callspec.indices.get(argname, 0)
515
# if a parametrize invocation set a scope it will override
516
# the static scope defined with the fixture function
517
paramscopenum = funcitem.callspec._arg2scopenum.get(argname)
518
if paramscopenum is not None:
519
scope = scopes[paramscopenum]
521
subrequest = SubRequest(self, scope, param, param_index, fixturedef)
523
# check if a higher-level scoped fixture accesses a lower level one
524
subrequest._check_scope(argname, self.scope, scope)
526
# clear sys.exc_info before invoking the fixture (python bug?)
527
# if its not explicitly cleared it will leak into the call
530
# call the fixture function
531
val = fixturedef.execute(request=subrequest)
533
# if fixture function failed it might have registered finalizers
534
self.session._setupstate.addfinalizer(fixturedef.finish,
538
def _check_scope(self, argname, invoking_scope, requested_scope):
539
if argname == "request":
541
if scopemismatch(invoking_scope, requested_scope):
542
# try to report something helpful
543
lines = self._factorytraceback()
544
pytest.fail("ScopeMismatch: You tried to access the %r scoped "
545
"fixture %r with a %r scoped request object, "
546
"involved factories\n%s" %(
547
(requested_scope, argname, invoking_scope, "\n".join(lines))),
550
def _factorytraceback(self):
552
for fixturedef in self._get_fixturestack():
553
factory = fixturedef.func
554
fs, lineno = getfslineno(factory)
555
p = self._pyfuncitem.session.fspath.bestrelpath(fs)
556
args = _format_args(factory)
557
lines.append("%s:%d: def %s%s" %(
558
p, lineno, factory.__name__, args))
561
def _getscopeitem(self, scope):
562
if scope == "function":
563
# this might also be a non-function Item despite its attribute name
564
return self._pyfuncitem
565
node = get_scope_node(self._pyfuncitem, scope)
566
if node is None and scope == "class":
567
# fallback to function item itself
568
node = self._pyfuncitem
573
return "<FixtureRequest for %r>" %(self.node)
576
class SubRequest(FixtureRequest):
577
""" a sub request for handling getting a fixture from a
578
test function/fixture. """
579
def __init__(self, request, scope, param, param_index, fixturedef):
580
self._parent_request = request
581
self.fixturename = fixturedef.argname
582
if param is not NOTSET:
584
self.param_index = param_index
586
self._fixturedef = fixturedef
587
self.addfinalizer = fixturedef.addfinalizer
588
self._pyfuncitem = request._pyfuncitem
589
self._fixture_values = request._fixture_values
590
self._fixture_defs = request._fixture_defs
591
self._arg2fixturedefs = request._arg2fixturedefs
592
self._arg2index = request._arg2index
593
self._fixturemanager = request._fixturemanager
596
return "<SubRequest %r for %r>" % (self.fixturename, self._pyfuncitem)
599
class ScopeMismatchError(Exception):
600
""" A fixture function tries to use a different fixture function which
601
which has a lower scope (e.g. a Session one calls a function one)
605
scopes = "session module class function".split()
606
scopenum_function = scopes.index("function")
609
def scopemismatch(currentscope, newscope):
610
return scopes.index(newscope) > scopes.index(currentscope)
613
def scope2index(scope, descr, where=None):
614
"""Look up the index of ``scope`` and raise a descriptive value error
618
return scopes.index(scope)
621
"{0} {1}has an unsupported scope value '{2}'".format(
622
descr, 'from {0} '.format(where) if where else '',
627
class FixtureLookupError(LookupError):
628
""" could not return a requested Fixture (missing or invalid). """
629
def __init__(self, argname, request, msg=None):
630
self.argname = argname
631
self.request = request
632
self.fixturestack = request._get_fixturestack()
635
def formatrepr(self):
637
addline = tblines.append
638
stack = [self.request._pyfuncitem.obj]
639
stack.extend(map(lambda x: x.func, self.fixturestack))
642
# the last fixture raise an error, let's present
643
# it at the requesting side
645
for function in stack:
646
fspath, lineno = getfslineno(function)
648
lines, _ = inspect.getsourcelines(get_real_func(function))
649
except (IOError, IndexError, TypeError):
650
error_msg = "file %s, line %s: source code not available"
651
addline(error_msg % (fspath, lineno+1))
653
addline("file %s, line %s" % (fspath, lineno+1))
654
for i, line in enumerate(lines):
657
if line.lstrip().startswith('def'):
661
fm = self.request._fixturemanager
663
parentid = self.request._pyfuncitem.parent.nodeid
664
for name, fixturedefs in fm._arg2fixturedefs.items():
665
faclist = list(fm._matchfactories(fixturedefs, parentid))
666
if faclist and name not in available:
667
available.append(name)
668
msg = "fixture %r not found" % (self.argname,)
669
msg += "\n available fixtures: %s" %(", ".join(sorted(available)),)
670
msg += "\n use 'pytest --fixtures [testpath]' for help on them."
672
return FixtureLookupErrorRepr(fspath, lineno, tblines, msg, self.argname)
675
class FixtureLookupErrorRepr(TerminalRepr):
676
def __init__(self, filename, firstlineno, tblines, errorstring, argname):
677
self.tblines = tblines
678
self.errorstring = errorstring
679
self.filename = filename
680
self.firstlineno = firstlineno
681
self.argname = argname
683
def toterminal(self, tw):
684
# tw.line("FixtureLookupError: %s" %(self.argname), red=True)
685
for tbline in self.tblines:
686
tw.line(tbline.rstrip())
687
lines = self.errorstring.split("\n")
689
tw.line('{0} {1}'.format(FormattedExcinfo.fail_marker,
690
lines[0].strip()), red=True)
691
for line in lines[1:]:
692
tw.line('{0} {1}'.format(FormattedExcinfo.flow_marker,
693
line.strip()), red=True)
695
tw.line("%s:%d" % (self.filename, self.firstlineno+1))
698
def fail_fixturefunc(fixturefunc, msg):
699
fs, lineno = getfslineno(fixturefunc)
700
location = "%s:%s" % (fs, lineno+1)
701
source = _pytest._code.Source(fixturefunc)
702
pytest.fail(msg + ":\n\n" + str(source.indent()) + "\n" + location,
705
def call_fixture_func(fixturefunc, request, kwargs):
706
yieldctx = is_generator(fixturefunc)
708
it = fixturefunc(**kwargs)
714
except StopIteration:
717
fail_fixturefunc(fixturefunc,
718
"yield_fixture function has more than one 'yield'")
720
request.addfinalizer(teardown)
722
res = fixturefunc(**kwargs)
727
""" A container for a factory definition. """
728
def __init__(self, fixturemanager, baseid, argname, func, scope, params,
729
unittest=False, ids=None):
730
self._fixturemanager = fixturemanager
731
self.baseid = baseid or ''
732
self.has_location = baseid is not None
734
self.argname = argname
736
self.scopenum = scope2index(
738
descr='fixture {0}'.format(func.__name__),
742
startindex = unittest and 1 or None
743
self.argnames = getfuncargnames(func, startindex=startindex)
744
self.unittest = unittest
748
def addfinalizer(self, finalizer):
749
self._finalizer.append(finalizer)
753
while self._finalizer:
754
func = self._finalizer.pop()
757
ihook = self._fixturemanager.session.ihook
758
ihook.pytest_fixture_post_finalizer(fixturedef=self)
759
# even if finalization fails, we invalidate
760
# the cached fixture value
761
if hasattr(self, "cached_result"):
762
del self.cached_result
764
def execute(self, request):
765
# get required arguments and register our own finish()
766
# with their finalization
767
for argname in self.argnames:
768
fixturedef = request._get_active_fixturedef(argname)
769
if argname != "request":
770
fixturedef.addfinalizer(self.finish)
772
my_cache_key = request.param_index
773
cached_result = getattr(self, "cached_result", None)
774
if cached_result is not None:
775
result, cache_key, err = cached_result
776
if my_cache_key == cache_key:
778
py.builtin._reraise(*err)
781
# we have a previous but differently parametrized fixture instance
782
# so we need to tear it down before creating a new one
784
assert not hasattr(self, "cached_result")
786
ihook = self._fixturemanager.session.ihook
787
return ihook.pytest_fixture_setup(fixturedef=self, request=request)
790
return ("<FixtureDef name=%r scope=%r baseid=%r >" %
791
(self.argname, self.scope, self.baseid))
793
def pytest_fixture_setup(fixturedef, request):
794
""" Execution of fixture setup. """
796
for argname in fixturedef.argnames:
797
fixdef = request._get_active_fixturedef(argname)
798
result, arg_cache_key, exc = fixdef.cached_result
799
request._check_scope(argname, request.scope, fixdef.scope)
800
kwargs[argname] = result
802
fixturefunc = fixturedef.func
803
if fixturedef.unittest:
804
if request.instance is not None:
805
# bind the unbound method to the TestCase instance
806
fixturefunc = fixturedef.func.__get__(request.instance)
808
# the fixture function needs to be bound to the actual
809
# request.instance so that code working with "fixturedef" behaves
811
if request.instance is not None:
812
fixturefunc = getimfunc(fixturedef.func)
813
if fixturefunc != fixturedef.func:
814
fixturefunc = fixturefunc.__get__(request.instance)
815
my_cache_key = request.param_index
817
result = call_fixture_func(fixturefunc, request, kwargs)
819
fixturedef.cached_result = (None, my_cache_key, sys.exc_info())
821
fixturedef.cached_result = (result, my_cache_key, None)
825
class FixtureFunctionMarker:
826
def __init__(self, scope, params, autouse=False, ids=None, name=None):
829
self.autouse = autouse
833
def __call__(self, function):
834
if isclass(function):
836
"class fixtures not supported (may be in the future)")
837
function._pytestfixturefunction = self
842
def fixture(scope="function", params=None, autouse=False, ids=None, name=None):
843
""" (return a) decorator to mark a fixture factory function.
845
This decorator can be used (with or or without parameters) to define
846
a fixture function. The name of the fixture function can later be
847
referenced to cause its invocation ahead of running tests: test
848
modules or classes can use the pytest.mark.usefixtures(fixturename)
849
marker. Test functions can directly use fixture names as input
850
arguments in which case the fixture instance returned from the fixture
851
function will be injected.
853
:arg scope: the scope for which this fixture is shared, one of
854
"function" (default), "class", "module" or "session".
856
:arg params: an optional list of parameters which will cause multiple
857
invocations of the fixture function and all of the tests
860
:arg autouse: if True, the fixture func is activated for all tests that
861
can see it. If False (the default) then an explicit
862
reference is needed to activate the fixture.
864
:arg ids: list of string ids each corresponding to the params
865
so that they are part of the test id. If no ids are provided
866
they will be generated automatically from the params.
868
:arg name: the name of the fixture. This defaults to the name of the
869
decorated function. If a fixture is used in the same module in
870
which it is defined, the function name of the fixture will be
871
shadowed by the function arg that requests the fixture; one way
872
to resolve this is to name the decorated function
873
``fixture_<fixturename>`` and then use
874
``@pytest.fixture(name='<fixturename>')``.
876
Fixtures can optionally provide their values to test functions using a ``yield`` statement,
877
instead of ``return``. In this case, the code block after the ``yield`` statement is executed
878
as teardown code regardless of the test outcome. A fixture function must yield exactly once.
880
if callable(scope) and params is None and autouse == False:
882
return FixtureFunctionMarker(
883
"function", params, autouse, name=name)(scope)
884
if params is not None and not isinstance(params, (list, tuple)):
885
params = list(params)
886
return FixtureFunctionMarker(scope, params, autouse, ids=ids, name=name)
889
def yield_fixture(scope="function", params=None, autouse=False, ids=None, name=None):
890
""" (return a) decorator to mark a yield-fixture factory function.
893
Use :py:func:`pytest.fixture` directly instead.
895
if callable(scope) and params is None and not autouse:
897
return FixtureFunctionMarker(
898
"function", params, autouse, ids=ids, name=name)(scope)
900
return FixtureFunctionMarker(scope, params, autouse, ids=ids, name=name)
903
defaultfuncargprefixmarker = fixture()
906
@fixture(scope="session")
907
def pytestconfig(request):
908
""" the pytest config object with access to command line opts."""
909
return request.config
912
class FixtureManager:
914
pytest fixtures definitions and information is stored and managed
917
During collection fm.parsefactories() is called multiple times to parse
918
fixture function definitions into FixtureDef objects and internal
921
During collection of test functions, metafunc-mechanics instantiate
922
a FuncFixtureInfo object which is cached per node/func-name.
923
This FuncFixtureInfo object is later retrieved by Function nodes
924
which themselves offer a fixturenames attribute.
926
The FuncFixtureInfo object holds information about fixtures and FixtureDefs
927
relevant for a particular function. An initial list of fixtures is
930
- ini-defined usefixtures
931
- autouse-marked fixtures along the collection chain up from the function
932
- usefixtures markers at module/class/function level
933
- test function funcargs
935
Subsequently the funcfixtureinfo.fixturenames attribute is computed
936
as the closure of the fixtures needed to setup the initial fixtures,
937
i. e. fixtures needed by fixture functions themselves are appended
938
to the fixturenames list.
940
Upon the test-setup phases all fixturenames are instantiated, retrieved
941
by a lookup of their FuncFixtureInfo.
944
_argprefix = "pytest_funcarg__"
945
FixtureLookupError = FixtureLookupError
946
FixtureLookupErrorRepr = FixtureLookupErrorRepr
948
def __init__(self, session):
949
self.session = session
950
self.config = session.config
951
self._arg2fixturedefs = {}
952
self._holderobjseen = set()
953
self._arg2finish = {}
954
self._nodeid_and_autousenames = [("", self.config.getini("usefixtures"))]
955
session.config.pluginmanager.register(self, "funcmanage")
958
def getfixtureinfo(self, node, func, cls, funcargs=True):
959
if funcargs and not hasattr(node, "nofuncargs"):
964
argnames = getfuncargnames(func, startindex)
967
usefixtures = getattr(func, "usefixtures", None)
968
initialnames = argnames
969
if usefixtures is not None:
970
initialnames = usefixtures.args + initialnames
971
fm = node.session._fixturemanager
972
names_closure, arg2fixturedefs = fm.getfixtureclosure(initialnames,
974
return FuncFixtureInfo(argnames, names_closure, arg2fixturedefs)
976
def pytest_plugin_registered(self, plugin):
979
p = py.path.local(plugin.__file__)
980
except AttributeError:
983
# construct the base nodeid which is later used to check
984
# what fixtures are visible for particular tests (as denoted
986
if p.basename.startswith("conftest.py"):
987
nodeid = p.dirpath().relto(self.config.rootdir)
989
nodeid = nodeid.replace(p.sep, "/")
990
self.parsefactories(plugin, nodeid)
992
def _getautousenames(self, nodeid):
993
""" return a tuple of fixture names to be used. """
995
for baseid, basenames in self._nodeid_and_autousenames:
996
if nodeid.startswith(baseid):
999
nextchar = nodeid[i:i+1]
1000
if nextchar and nextchar not in ":/":
1002
autousenames.extend(basenames)
1003
# make sure autousenames are sorted by scope, scopenum 0 is session
1005
key=lambda x: self._arg2fixturedefs[x][-1].scopenum)
1008
def getfixtureclosure(self, fixturenames, parentnode):
1009
# collect the closure of all fixtures , starting with the given
1010
# fixturenames as the initial set. As we have to visit all
1011
# factory definitions anyway, we also return a arg2fixturedefs
1012
# mapping so that the caller can reuse it and does not have
1013
# to re-discover fixturedefs again for each fixturename
1014
# (discovering matching fixtures for a given name/node is expensive)
1016
parentid = parentnode.nodeid
1017
fixturenames_closure = self._getautousenames(parentid)
1019
def merge(otherlist):
1020
for arg in otherlist:
1021
if arg not in fixturenames_closure:
1022
fixturenames_closure.append(arg)
1025
arg2fixturedefs = {}
1027
while lastlen != len(fixturenames_closure):
1028
lastlen = len(fixturenames_closure)
1029
for argname in fixturenames_closure:
1030
if argname in arg2fixturedefs:
1032
fixturedefs = self.getfixturedefs(argname, parentid)
1034
arg2fixturedefs[argname] = fixturedefs
1035
merge(fixturedefs[-1].argnames)
1036
return fixturenames_closure, arg2fixturedefs
1038
def pytest_generate_tests(self, metafunc):
1039
for argname in metafunc.fixturenames:
1040
faclist = metafunc._arg2fixturedefs.get(argname)
1042
fixturedef = faclist[-1]
1043
if fixturedef.params is not None:
1044
func_params = getattr(getattr(metafunc.function, 'parametrize', None), 'args', [[None]])
1045
# skip directly parametrized arguments
1046
argnames = func_params[0]
1047
if not isinstance(argnames, (tuple, list)):
1048
argnames = [x.strip() for x in argnames.split(",") if x.strip()]
1049
if argname not in func_params and argname not in argnames:
1050
metafunc.parametrize(argname, fixturedef.params,
1051
indirect=True, scope=fixturedef.scope,
1054
continue # will raise FixtureLookupError at setup time
1056
def pytest_collection_modifyitems(self, items):
1057
# separate parametrized setups
1058
items[:] = reorder_items(items)
1060
def parsefactories(self, node_or_obj, nodeid=NOTSET, unittest=False):
1061
if nodeid is not NOTSET:
1062
holderobj = node_or_obj
1064
holderobj = node_or_obj.obj
1065
nodeid = node_or_obj.nodeid
1066
if holderobj in self._holderobjseen:
1068
self._holderobjseen.add(holderobj)
1070
for name in dir(holderobj):
1071
obj = getattr(holderobj, name, None)
1072
# fixture functions have a pytest_funcarg__ prefix (pre-2.3 style)
1073
# or are "@pytest.fixture" marked
1074
marker = getfixturemarker(obj)
1076
if not name.startswith(self._argprefix):
1078
if not callable(obj):
1080
marker = defaultfuncargprefixmarker
1081
from _pytest import deprecated
1082
self.config.warn('C1', deprecated.FUNCARG_PREFIX.format(name=name))
1083
name = name[len(self._argprefix):]
1084
elif not isinstance(marker, FixtureFunctionMarker):
1085
# magic globals with __getattr__ might have got us a wrong
1091
msg = 'fixtures cannot have "pytest_funcarg__" prefix ' \
1092
'and be decorated with @pytest.fixture:\n%s' % name
1093
assert not name.startswith(self._argprefix), msg
1095
fixture_def = FixtureDef(self, nodeid, name, obj,
1096
marker.scope, marker.params,
1097
unittest=unittest, ids=marker.ids)
1099
faclist = self._arg2fixturedefs.setdefault(name, [])
1100
if fixture_def.has_location:
1101
faclist.append(fixture_def)
1103
# fixturedefs with no location are at the front
1104
# so this inserts the current fixturedef after the
1105
# existing fixturedefs from external plugins but
1106
# before the fixturedefs provided in conftests.
1107
i = len([f for f in faclist if not f.has_location])
1108
faclist.insert(i, fixture_def)
1110
autousenames.append(name)
1113
self._nodeid_and_autousenames.append((nodeid or '', autousenames))
1115
def getfixturedefs(self, argname, nodeid):
1117
Gets a list of fixtures which are applicable to the given node id.
1119
:param str argname: name of the fixture to search for
1120
:param str nodeid: full node id of the requesting test.
1121
:return: list[FixtureDef]
1124
fixturedefs = self._arg2fixturedefs[argname]
1128
return tuple(self._matchfactories(fixturedefs, nodeid))
1130
def _matchfactories(self, fixturedefs, nodeid):
1131
for fixturedef in fixturedefs:
1132
if nodeid.startswith(fixturedef.baseid):