remove _fixturestack attribute now that we have a proper request->subrequest->subrequest chain.

This commit is contained in:
holger krekel 2013-11-21 13:15:32 +01:00
parent 238b890d9b
commit 2e90aaf7af
1 changed files with 31 additions and 24 deletions

View File

@ -10,6 +10,7 @@ import _pytest
cutdir = py.path.local(_pytest.__file__).dirpath() cutdir = py.path.local(_pytest.__file__).dirpath()
NoneType = type(None) NoneType = type(None)
NOTSET = object()
callable = py.builtin.callable callable = py.builtin.callable
@ -943,18 +944,18 @@ class RaisesContext(object):
# #
# the basic py.test Function item # the basic py.test Function item
# #
_dummy = object()
class Function(FunctionMixin, pytest.Item, FuncargnamesCompatAttr): class Function(FunctionMixin, pytest.Item, FuncargnamesCompatAttr):
""" a Function Item is responsible for setting up and executing a """ a Function Item is responsible for setting up and executing a
Python test function. Python test function.
""" """
_genid = None _genid = None
def __init__(self, name, parent, args=None, config=None, def __init__(self, name, parent, args=None, config=None,
callspec=None, callobj=_dummy, keywords=None, session=None): callspec=None, callobj=NOTSET, keywords=None, session=None):
super(Function, self).__init__(name, parent, config=config, super(Function, self).__init__(name, parent, config=config,
session=session) session=session)
self._args = args self._args = args
if callobj is not _dummy: if callobj is not NOTSET:
self.obj = callobj self.obj = callobj
for name, val in (py.builtin._getfuncdict(self.obj) or {}).items(): for name, val in (py.builtin._getfuncdict(self.obj) or {}).items():
@ -1088,7 +1089,6 @@ class FixtureRequest(FuncargnamesCompatAttr):
self._arg2index = {} self._arg2index = {}
self.fixturenames = fixtureinfo.names_closure self.fixturenames = fixtureinfo.names_closure
self._fixturemanager = pyfuncitem.session._fixturemanager self._fixturemanager = pyfuncitem.session._fixturemanager
self._fixturestack = []
@property @property
def node(self): def node(self):
@ -1254,13 +1254,20 @@ class FixtureRequest(FuncargnamesCompatAttr):
if argname == "request": if argname == "request":
return self return self
raise raise
self._fixturestack.append(fixturedef) result = self._getfuncargvalue(fixturedef)
try: self._funcargs[argname] = result
result = self._getfuncargvalue(fixturedef) return result
self._funcargs[argname] = result
return result def _get_fixturestack(self):
finally: current = self
self._fixturestack.pop() l = []
while 1:
fixturedef = getattr(current, "_fixturedef", None)
if fixturedef is None:
l.reverse()
return l
l.append(fixturedef)
current = current._parent_request
def _getfuncargvalue(self, fixturedef): def _getfuncargvalue(self, fixturedef):
try: try:
@ -1275,7 +1282,7 @@ class FixtureRequest(FuncargnamesCompatAttr):
try: try:
param = node.callspec.getparam(argname) param = node.callspec.getparam(argname)
except (AttributeError, ValueError): except (AttributeError, ValueError):
param = notset param = NOTSET
else: else:
# if a parametrize invocation set a scope it will override # if a parametrize invocation set a scope it will override
# the static scope defined with the fixture function # the static scope defined with the fixture function
@ -1284,21 +1291,20 @@ class FixtureRequest(FuncargnamesCompatAttr):
paramscopenum != scopenum_subfunction: paramscopenum != scopenum_subfunction:
scope = scopes[paramscopenum] scope = scopes[paramscopenum]
subrequest = SubRequest(self, scope, param, fixturedef)
# check if a higher-level scoped fixture accesses a lower level one # check if a higher-level scoped fixture accesses a lower level one
if scope is not None: if scope is not None:
__tracebackhide__ = True __tracebackhide__ = True
if scopemismatch(self.scope, scope): if scopemismatch(self.scope, scope):
# try to report something helpful # try to report something helpful
lines = self._factorytraceback() lines = subrequest._factorytraceback()
raise ScopeMismatchError("You tried to access the %r scoped " raise ScopeMismatchError("You tried to access the %r scoped "
"fixture %r with a %r scoped request object, " "fixture %r with a %r scoped request object, "
"involved factories\n%s" %( "involved factories\n%s" %(
(scope, argname, self.scope, "\n".join(lines)))) (scope, argname, self.scope, "\n".join(lines))))
__tracebackhide__ = False __tracebackhide__ = False
else:
scope = self.scope
subrequest = SubRequest(self, scope, param, fixturedef)
try: try:
# perform the fixture call # perform the fixture call
val = fixturedef.execute(request=subrequest) val = fixturedef.execute(request=subrequest)
@ -1317,7 +1323,7 @@ class FixtureRequest(FuncargnamesCompatAttr):
def _factorytraceback(self): def _factorytraceback(self):
lines = [] lines = []
for fixturedef in self._fixturestack: for fixturedef in self._get_fixturestack():
factory = fixturedef.func factory = fixturedef.func
fs, lineno = getfslineno(factory) fs, lineno = getfslineno(factory)
p = self._pyfuncitem.session.fspath.bestrelpath(fs) p = self._pyfuncitem.session.fspath.bestrelpath(fs)
@ -1344,16 +1350,17 @@ class FixtureRequest(FuncargnamesCompatAttr):
def __repr__(self): def __repr__(self):
return "<FixtureRequest for %r>" %(self.node) return "<FixtureRequest for %r>" %(self.node)
notset = object()
class SubRequest(FixtureRequest): class SubRequest(FixtureRequest):
""" a sub request for handling getting a fixture from a """ a sub request for handling getting a fixture from a
test function/fixture. """ test function/fixture. """
def __init__(self, request, scope, param, fixturedef): def __init__(self, request, scope, param, fixturedef):
self._parent_request = request self._parent_request = request
self.fixturename = fixturedef.argname self.fixturename = fixturedef.argname
if param is not notset: if param is not NOTSET:
self.param = param self.param = param
self.scope = scope self.scope = scope
self._fixturedef = fixturedef
self.addfinalizer = fixturedef.addfinalizer self.addfinalizer = fixturedef.addfinalizer
self._pyfuncitem = request._pyfuncitem self._pyfuncitem = request._pyfuncitem
self._funcargs = request._funcargs self._funcargs = request._funcargs
@ -1361,10 +1368,10 @@ class SubRequest(FixtureRequest):
self._arg2index = request._arg2index self._arg2index = request._arg2index
self.fixturenames = request.fixturenames self.fixturenames = request.fixturenames
self._fixturemanager = request._fixturemanager self._fixturemanager = request._fixturemanager
self._fixturestack = request._fixturestack
def __repr__(self): def __repr__(self):
return "<SubRequest %r for %r>" % (self.fixturename, self.node) return "<SubRequest %r for %r>" % (self.fixturename, self._pyfuncitem)
class ScopeMismatchError(Exception): class ScopeMismatchError(Exception):
""" A fixture function tries to use a different fixture function which """ A fixture function tries to use a different fixture function which
@ -1381,7 +1388,7 @@ class FixtureLookupError(LookupError):
def __init__(self, argname, request, msg=None): def __init__(self, argname, request, msg=None):
self.argname = argname self.argname = argname
self.request = request self.request = request
self.fixturestack = list(request._fixturestack) self.fixturestack = request._get_fixturestack()
self.msg = msg self.msg = msg
def formatrepr(self): def formatrepr(self):
@ -1619,8 +1626,8 @@ class FixtureManager:
for fin in reversed(l): for fin in reversed(l):
fin() fin()
def parsefactories(self, node_or_obj, nodeid=_dummy, unittest=False): def parsefactories(self, node_or_obj, nodeid=NOTSET, unittest=False):
if nodeid is not _dummy: if nodeid is not NOTSET:
holderobj = node_or_obj holderobj = node_or_obj
else: else:
holderobj = node_or_obj.obj holderobj = node_or_obj.obj