2 new commits in pytest:
https://bitbucket.org/hpk42/pytest/commits/05ea7094569f/
Changeset: 05ea7094569f
User: hpk42
Date: 2013-11-21 12:21:52
Summary: refactor internal FixtureRequest handling to avoid monkeypatching.
One of the positive user-facing effects is that the "request" object
can now be used in closures.
Affected #: 3 files
diff -r dcbe5c70239930fafdc762d0a427f8814c1d4799 -r
05ea7094569fe3f3098fa8e965014d236bc3c907 CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -65,6 +65,10 @@
- fix issue221 - handle importing of namespace-package with no
__init__.py properly.
+- refactor internal FixtureRequest handling to avoid monkeypatching.
+ One of the positive user-facing effects is that the "request" object
+ can now be used in closures.
+
Changes between 2.4.1 and 2.4.2
-----------------------------------
diff -r dcbe5c70239930fafdc762d0a427f8814c1d4799 -r
05ea7094569fe3f3098fa8e965014d236bc3c907 _pytest/python.py
--- a/_pytest/python.py
+++ b/_pytest/python.py
@@ -4,7 +4,6 @@
import sys
import pytest
from _pytest.mark import MarkDecorator
-from _pytest.monkeypatch import monkeypatch
from py._code.code import TerminalRepr
import _pytest
@@ -1083,14 +1082,12 @@
self.fixturename = None
#: Scope string, one of "function", "cls", "module", "session"
self.scope = "function"
- self.getparent = pyfuncitem.getparent
self._funcargs = self._pyfuncitem.funcargs.copy()
- self._fixtureinfo = fi = pyfuncitem._fixtureinfo
- self._arg2fixturedefs = fi.name2fixturedefs
+ fixtureinfo = pyfuncitem._fixtureinfo
+ self._arg2fixturedefs = fixtureinfo.name2fixturedefs
self._arg2index = {}
- self.fixturenames = self._fixtureinfo.names_closure
+ self.fixturenames = fixtureinfo.names_closure
self._fixturemanager = pyfuncitem.session._fixturemanager
- self._parentid = pyfuncitem.parent.nodeid
self._fixturestack = []
@property
@@ -1104,7 +1101,7 @@
# we arrive here because of a getfuncargvalue(argname) usage which
# was naturally not knowable at parsing/collection time
fixturedefs = self._fixturemanager.getfixturedefs(
- argname, self._parentid)
+ argname, self._pyfuncitem.parent.nodeid)
self._arg2fixturedefs[argname] = fixturedefs
# fixturedefs is immutable so we maintain a decreasing index
index = self._arg2index.get(argname, 0) - 1
@@ -1270,29 +1267,21 @@
return fixturedef.cached_result # set by fixturedef.execute()
except AttributeError:
pass
-
- # prepare request fixturename and param attributes before
- # calling into fixture function
+ # prepare a subrequest object before calling fixture function
+ # (latter managed by fixturedef)
argname = fixturedef.argname
node = self._pyfuncitem
- mp = monkeypatch()
- mp.setattr(self, 'fixturename', argname)
+ scope = fixturedef.scope
try:
param = node.callspec.getparam(argname)
except (AttributeError, ValueError):
- pass
+ param = notset
else:
- mp.setattr(self, 'param', param, raising=False)
-
- # if a parametrize invocation set a scope it will override
- # the static scope defined with the fixture function
- scope = fixturedef.scope
- try:
- paramscopenum = node.callspec._arg2scopenum[argname]
- except (KeyError, AttributeError):
- pass
- else:
- if paramscopenum != scopenum_subfunction:
+ # if a parametrize invocation set a scope it will override
+ # the static scope defined with the fixture function
+ paramscopenum = node.callspec._arg2scopenum.get(argname)
+ if paramscopenum is not None and \
+ paramscopenum != scopenum_subfunction:
scope = scopes[paramscopenum]
# check if a higher-level scoped fixture accesses a lower level one
@@ -1302,31 +1291,29 @@
# try to report something helpful
lines = self._factorytraceback()
raise ScopeMismatchError("You tried to access the %r scoped "
- "funcarg %r with a %r scoped request object, "
+ "fixture %r with a %r scoped request object, "
"involved factories\n%s" %(
(scope, argname, self.scope, "\n".join(lines))))
__tracebackhide__ = False
- mp.setattr(self, "scope", scope)
+ else:
+ scope = self.scope
- # route request.addfinalizer to fixturedef
- mp.setattr(self, "addfinalizer", fixturedef.addfinalizer)
-
+ subrequest = SubRequest(self, argname, scope, param,
+ fixturedef.addfinalizer)
try:
# perform the fixture call
- val = fixturedef.execute(request=self)
+ val = fixturedef.execute(request=subrequest)
finally:
# if the fixture function failed it might still have
# registered finalizers so we can register
-
# prepare finalization according to scope
# (XXX analyse exact finalizing mechanics / cleanup)
self.session._setupstate.addfinalizer(fixturedef.finish,
- self.node)
+ subrequest.node)
self._fixturemanager.addargfinalizer(fixturedef.finish, argname)
for subargname in fixturedef.argnames: # XXX all deps?
self._fixturemanager.addargfinalizer(fixturedef.finish,
subargname)
- mp.undo()
return val
def _factorytraceback(self):
@@ -1358,6 +1345,28 @@
def __repr__(self):
return "<FixtureRequest for %r>" %(self.node)
+notset = object()
+class SubRequest(FixtureRequest):
+ """ a sub request for handling getting a fixture from a
+ test function/fixture. """
+ def __init__(self, request, argname, scope, param, addfinalizer):
+ self._parent_request = request
+ self.fixturename = argname
+ if param is not notset:
+ self.param = param
+ self.scope = scope
+ self.addfinalizer = addfinalizer
+ self._pyfuncitem = request._pyfuncitem
+ self._funcargs = request._funcargs
+ self._arg2fixturedefs = request._arg2fixturedefs
+ self._arg2index = request._arg2index
+ self.fixturenames = request.fixturenames
+ self._fixturemanager = request._fixturemanager
+ self._fixturestack = request._fixturestack
+
+ def __repr__(self):
+ return "<SubRequest %r for %r>" % (self.fixturename, self.node)
+
class ScopeMismatchError(Exception):
""" A fixture function tries to use a different fixture function which
which has a lower scope (e.g. a Session one calls a function one)
@@ -1399,8 +1408,8 @@
fm = self.request._fixturemanager
available = []
for name, fixturedef in fm._arg2fixturedefs.items():
- faclist = list(fm._matchfactories(fixturedef,
- self.request._parentid))
+ parentid = self.request._pyfuncitem.parent.nodeid
+ faclist = list(fm._matchfactories(fixturedef, parentid))
if faclist:
available.append(name)
msg = "fixture %r not found" % (self.argname,)
@@ -1744,7 +1753,6 @@
func()
# check neccesity of next commented call
self._fixturemanager.removefinalizer(self.finish)
- #print "finished", self
try:
del self.cached_result
except AttributeError:
diff -r dcbe5c70239930fafdc762d0a427f8814c1d4799 -r
05ea7094569fe3f3098fa8e965014d236bc3c907 testing/python/fixture.py
--- a/testing/python/fixture.py
+++ b/testing/python/fixture.py
@@ -473,7 +473,7 @@
assert l == ["module", "function", "class",
"function", "method", "function"]
""")
- reprec = testdir.inline_run()
+ reprec = testdir.inline_run("-v")
reprec.assertoutcome(passed=3)
def test_fixtures_sub_subdir_normalize_sep(self, testdir):
@@ -1792,6 +1792,20 @@
for test in ['test_a', 'test_b', 'test_c']:
assert reprec.matchreport(test).passed
+ def test_request_is_clean(self, testdir):
+ testdir.makepyfile("""
+ import pytest
+ l = []
+ @pytest.fixture(params=[1, 2])
+ def fix(request):
+ request.addfinalizer(lambda: l.append(request.param))
+ def test_fix(fix):
+ pass
+ """)
+ reprec = testdir.inline_run("-s")
+ l = reprec.getcalls("pytest_runtest_call")[0].item.module.l
+ assert l == [1,2]
+
def test_parametrize_separated_lifecycle(self, testdir):
testdir.makepyfile("""
import pytest
https://bitbucket.org/hpk42/pytest/commits/7c1e760976b2/
Changeset: 7c1e760976b2
User: hpk42
Date: 2013-11-21 12:31:22
Summary: fix py25 compat
Affected #: 1 file
diff -r 05ea7094569fe3f3098fa8e965014d236bc3c907 -r
7c1e760976b2e7097588da6d7d9cdc892330722f testing/test_runner.py
--- a/testing/test_runner.py
+++ b/testing/test_runner.py
@@ -1,3 +1,5 @@
+from __future__ import with_statement
+
import pytest, py, sys, os
from _pytest import runner, main
Repository URL: https://bitbucket.org/hpk42/pytest/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
_______________________________________________
pytest-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pytest-commit