2 new commits in pytest:

https://bitbucket.org/hpk42/pytest/changeset/f99a77d3329d/
changeset:   f99a77d3329d
user:        hpk42
date:        2012-10-06 21:01:13
summary:     allow metafunc.parametrize(scope=...) calls to override the scope 
of a Fixture function definition.  This is useful for cases where you want to 
dynamically
set scope and parametrization for a fixture instead of statically declaring
it on the fixture function.
affected #:  2 files

diff -r b10528b9cd1acc11edca5172a9d8520069acd246 -r 
f99a77d3329dc609b84368cf8811626e10c05378 _pytest/python.py
--- a/_pytest/python.py
+++ b/_pytest/python.py
@@ -628,7 +628,7 @@
         self._arg2scopenum = {}
 
     def parametrize(self, argnames, argvalues, indirect=False, ids=None,
-        scope="function"):
+        scope=None):
         """ Add new invocations to the underlying test function using the list
         of argvalues for the given argnames.  Parametrization is performed
         during the collection phase.  If you need to setup expensive resources
@@ -648,6 +648,11 @@
         :arg ids: list of string ids each corresponding to the argvalues so
             that they are part of the test id. If no ids are provided they will
             be generated automatically from the argvalues.
+
+        :arg scope: if specified: denotes the scope of the parameters.
+            The scope is used for sorting tests by parameters.  It will
+            also override any fixture-function defined scope, allowing
+            to set a dynamic scope from test context and configuration.
         """
         if not isinstance(argnames, (tuple, list)):
             argnames = (argnames,)
@@ -656,7 +661,7 @@
             argvalues = [(_notexists,) * len(argnames)]
 
         if scope is None:
-            scope = "function"
+            scope = "subfunction"
         scopenum = scopes.index(scope)
         if not indirect:
             #XXX should we also check for the opposite case?
@@ -893,9 +898,9 @@
                 setattr(self.markers, name, val)
 
         # contstruct a list of all neccessary fixtures for this test function
-        if hasattr(self.markers, "usefixtures"):
+        try:
             usefixtures = list(self.markers.usefixtures.args)
-        else:
+        except AttributeError:
             usefixtures = []
         self.fixturenames = (self.session._fixturemanager.getdefaultfixtures() 
+
                 usefixtures + self._getfuncargnames())
@@ -938,10 +943,7 @@
             fs, lineno = self._getfslineno()
             pytest.skip("got empty parameter set, function %s at %s:%d" %(
                 self.function.__name__, fs, lineno))
-
         super(Function, self).setup()
-        #if hasattr(self, "_request"):
-        #    self._request._callsetup()
         fillfixtures(self)
 
     def __eq__(self, other):
@@ -1103,7 +1105,6 @@
     def _fillfixtures(self):
         item = self._pyfuncitem
         fixturenames = getattr(item, "fixturenames", self.fixturenames)
-
         for argname in fixturenames:
             if argname not in item.funcargs:
                 item.funcargs[argname] = self.getfuncargvalue(argname)
@@ -1146,7 +1147,7 @@
         return val
 
     def getfuncargvalue(self, argname):
-        """ Retrieve a function argument by name for this test
+        """ Retrieve a fixture function argument by name for this test
         function invocation.  This allows one function argument factory
         to call another function argument factory.  If there are two
         funcarg factories for the same test function argument the first
@@ -1181,8 +1182,8 @@
         if fixturedef.active:
             return fixturedef.cached_result
 
-        # prepare request scope and param attributes before
-        # calling into factory
+        # prepare request _currentarg and param attributes before
+        # calling into fixture function
         argname = fixturedef.argname
         node = self._pyfuncitem
         mp = monkeypatch()
@@ -1193,7 +1194,18 @@
             pass
         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:
+                scope = scopes[paramscopenum]
+
         if scope is not None:
             __tracebackhide__ = True
             if scopemismatch(self.scope, scope):
@@ -1251,7 +1263,8 @@
     which has a lower scope (e.g. a Session one calls a function one)
     """
 
-scopes = "session module class function".split()
+scopes = "session module class function subfunction".split()
+scopenum_subfunction = scopes.index("subfunction")
 def scopemismatch(currentscope, newscope):
     return scopes.index(newscope) > scopes.index(currentscope)
 


diff -r b10528b9cd1acc11edca5172a9d8520069acd246 -r 
f99a77d3329dc609b84368cf8811626e10c05378 testing/test_python.py
--- a/testing/test_python.py
+++ b/testing/test_python.py
@@ -1370,6 +1370,28 @@
             "*1 passed*"
         ])
 
+    @pytest.mark.parametrize(("scope", "length"),
+                             [("module", 2), ("function", 4)])
+    def test_parametrize_scope_overrides(self, testdir, scope, length):
+        testdir.makepyfile("""
+            import pytest
+            l = []
+            def pytest_generate_tests(metafunc):
+                if "arg" in metafunc.funcargnames:
+                    metafunc.parametrize("arg", [1,2], indirect=True,
+                                         scope=%r)
+            def pytest_funcarg__arg(request):
+                l.append(request.param)
+                return request.param
+            def test_hello(arg):
+                assert arg in (1,2)
+            def test_world(arg):
+                assert arg in (1,2)
+            def test_checklength():
+                assert len(l) == %d
+        """ % (scope, length))
+        reprec = testdir.inline_run()
+        reprec.assertoutcome(passed=5)
 
 def test_conftest_funcargs_only_available_in_subdir(testdir):
     sub1 = testdir.mkpydir("sub1")



https://bitbucket.org/hpk42/pytest/changeset/0a8334dc2fb3/
changeset:   0a8334dc2fb3
user:        hpk42
date:        2012-10-06 21:03:55
summary:     - allow to use fixtures directly, i.e. without ()
- also allow scope to be determined by a dynamic function
affected #:  4 files

diff -r f99a77d3329dc609b84368cf8811626e10c05378 -r 
0a8334dc2fb38cb19b43962810b857de3bb1bd61 _pytest/__init__.py
--- a/_pytest/__init__.py
+++ b/_pytest/__init__.py
@@ -1,2 +1,2 @@
 #
-__version__ = '2.3.0.dev18'
+__version__ = '2.3.0.dev19'


diff -r f99a77d3329dc609b84368cf8811626e10c05378 -r 
0a8334dc2fb38cb19b43962810b857de3bb1bd61 _pytest/python.py
--- a/_pytest/python.py
+++ b/_pytest/python.py
@@ -26,19 +26,27 @@
     """ return a decorator to mark a fixture factory function.
 
     The name of the fixture function can be referenced in a test context
-    to cause activation ahead of running tests.  Test modules or classes
-    can use the pytest.mark.needsfixtures(fixturename) marker to specify
-    needed fixtures.  Test functions can use fixture names as input arguments
-    in which case the object returned from the fixture function will be
-    injected.
+    to cause its invocation ahead of running tests.  Test modules or classes
+    can use the pytest.mark.usefixtures(fixturename) marker to specify
+    needed fixtures.  Test functions can also use fixture names as input
+    arguments in which case the fixture instance returned from the fixture
+    function will be injected.
 
     :arg scope: the scope for which this fixture is shared, one of
                 "function", "class", "module", "session". Defaults to 
"function".
     :arg params: an optional list of parameters which will cause multiple
                 invocations of the fixture functions and their dependent
                 tests.
+
+    :arg autoactive: if True, the fixture func is activated for all tests that
+                can see it.  If False (the default) then an explicit
+                reference is needed to activate the fixture.
     """
-    return FixtureFunctionMarker(scope, params, autoactive=autoactive)
+    if hasattr(scope, "__call__") and params is None and autoactive == False:
+        # direct decoration
+        return FixtureFunctionMarker(None, params, autoactive)(scope)
+    else:
+        return FixtureFunctionMarker(scope, params, autoactive=autoactive)
 
 defaultfuncargprefixmarker = fixture()
 


diff -r f99a77d3329dc609b84368cf8811626e10c05378 -r 
0a8334dc2fb38cb19b43962810b857de3bb1bd61 setup.py
--- a/setup.py
+++ b/setup.py
@@ -24,7 +24,7 @@
         name='pytest',
         description='py.test: simple powerful testing with Python',
         long_description = long_description,
-        version='2.3.0.dev18',
+        version='2.3.0.dev19',
         url='http://pytest.org',
         license='MIT license',
         platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'],


diff -r f99a77d3329dc609b84368cf8811626e10c05378 -r 
0a8334dc2fb38cb19b43962810b857de3bb1bd61 testing/test_python.py
--- a/testing/test_python.py
+++ b/testing/test_python.py
@@ -1701,7 +1701,20 @@
     ])
 
 
-class TestFixtureFactory:
+class TestFixtureUsages:
+    def test_noargfixturedec(self, testdir):
+        testdir.makepyfile("""
+            import pytest
+            @pytest.fixture
+            def arg1():
+                return 1
+
+            def test_func(arg1):
+                assert arg1 == 1
+        """)
+        reprec = testdir.inline_run()
+        reprec.assertoutcome(passed=1)
+
     def test_receives_funcargs(self, testdir):
         testdir.makepyfile("""
             import pytest

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.
_______________________________________________
py-svn mailing list
py-svn@codespeak.net
http://codespeak.net/mailman/listinfo/py-svn

Reply via email to