1. Brianna Laugher
  2. pytest

Commits

holger krekel  committed 74b8701

introduce a funcargcall object, holding meta information

  • Participants
  • Parent commits 25e7f16
  • Branches default

Comments (0)

Files changed (3)

File _pytest/main.py

View file
         seen = set()
         while funcargnames:
             argname = funcargnames.pop(0)
-            if argname in seen:
+            if argname in seen or argname == "request":
                 continue
             seen.add(argname)
             faclist = self.getfactorylist(argname, metafunc.parentid,
                                           metafunc.function, raising=False)
             if faclist is None:
                 continue # will raise FuncargLookupError at setup time
-            for fac in faclist:
-                marker = getattr(fac, "funcarg", None)
-                if marker is not None:
-                    params = marker.kwargs.get("params")
-                    scope = marker.kwargs.get("scope", "function")
-                    if params is not None:
-                        metafunc.parametrize(argname, params, indirect=True,
-                                             scope=scope)
-                newfuncargnames = getfuncargnames(fac)
-                newfuncargnames.remove("request")
-                funcargnames.extend(newfuncargnames)
+            for facdef in faclist:
+                if facdef.params is not None:
+                    metafunc.parametrize(argname, facdef.params, indirect=True,
+                                             scope=facdef.scope)
+                funcargnames.extend(facdef.funcargnames)
 
     def pytest_collection_modifyitems(self, items):
         # separate parametrized setups
                 continue
             # funcarg factories either have a pytest_funcarg__ prefix
             # or are "funcarg" marked
-            if hasattr(obj, "funcarg"):
+            if not callable(obj):
+                continue
+            marker = getattr(obj, "funcarg", None)
+            if marker is not None and isinstance(marker, MarkInfo):
                 assert not name.startswith(self._argprefix)
                 argname = name
+                scope = marker.kwargs.get("scope")
+                params = marker.kwargs.get("params")
             elif name.startswith(self._argprefix):
                 argname = name[len(self._argprefix):]
+                scope = None
+                params = None
             else:
                 # no funcargs. check if we have a setup function.
                 setup = getattr(obj, "setup", None)
                     self.setuplist.append(sf)
                 continue
             faclist = self.arg2facspec.setdefault(argname, [])
-            faclist.append((nodeid, obj))
+            factorydef = FactoryDef(self, nodeid, argname, obj, scope, params)
+            faclist.append(factorydef)
+            ### check scope/params mismatch?
 
     def getsetuplist(self, nodeid):
         l = []
 
     def getfactorylist(self, argname, nodeid, function, raising=True):
         try:
-            factorydef = self.arg2facspec[argname]
+            factorydeflist = self.arg2facspec[argname]
         except KeyError:
             if raising:
                 self._raiselookupfailed(argname, function, nodeid)
         else:
-            return self._matchfactories(factorydef, nodeid)
+            return self._matchfactories(factorydeflist, nodeid)
 
-    def _matchfactories(self, factorydef, nodeid):
+    def _matchfactories(self, factorydeflist, nodeid):
         l = []
-        for baseid, factory in factorydef:
+        for factorydef in factorydeflist:
             #print "check", basepath, nodeid
-            if nodeid.startswith(baseid):
-                l.append(factory)
+            if nodeid.startswith(factorydef.baseid):
+                l.append(factorydef)
         return l
 
     def _raiselookupfailed(self, argname, function, nodeid):
         raise FuncargLookupError(function, msg)
 
 
+class FactoryDef:
+    """ A container for a factory definition. """
+    def __init__(self, funcargmanager, baseid, argname, func, scope, params):
+        self.funcargmanager = funcargmanager
+        self.baseid = baseid
+        self.func = func
+        self.argname = argname
+        self.scope = scope
+        self.params = params
+        self.funcargnames = getfuncargnames(func)
+
 class SetupCall:
     """ a container/helper for managing calls to setup functions. """
     def __init__(self, funcargmanager, baseid, func, scope):

File _pytest/python.py

View file
         if not isinstance(argnames, (tuple, list)):
             argnames = (argnames,)
             argvalues = [(val,) for val in argvalues]
+        if scope is None:
+            scope = "function"
         scopenum = scopes.index(scope)
         if not indirect:
             #XXX should we also check for the opposite case?
         self._factorystack = []
 
     def _getfaclist(self, argname):
-        faclist = self._name2factory.get(argname, None)
-        if faclist is None:
-            faclist = self.funcargmanager.getfactorylist(argname,
-                                                         self.parentid,
-                                                         self.function)
-            self._name2factory[argname] = faclist
-        elif not faclist:
+        facdeflist = self._name2factory.get(argname, None)
+        if facdeflist is None:
+            facdeflist = self.funcargmanager.getfactorylist(
+                            argname, self.parentid, self.function)
+            self._name2factory[argname] = facdeflist
+        elif not facdeflist:
             self.funcargmanager._raiselookupfailed(argname, self.function,
                                                    self.parentid)
-        return faclist
+        return facdeflist
 
     def raiseerror(self, msg):
         """ raise a FuncargLookupError with the given message. """
             return self._funcargs[argname]
         except KeyError:
             pass
-        factorylist = self._getfaclist(argname)
-        funcargfactory = factorylist.pop()
-        self._factorystack.append(funcargfactory)
+        factorydeflist = self._getfaclist(argname)
+        factorydef = factorydeflist.pop()
+        self._factorystack.append(factorydef)
         try:
-            return self._getfuncargvalue(funcargfactory, argname)
+            return self._getfuncargvalue(factorydef)
         finally:
             self._factorystack.pop()
 
-    def _getfuncargvalue(self, funcargfactory, argname):
+    def _getfuncargvalue(self, factorydef):
         # collect funcargs from the factory
-        newnames = getfuncargnames(funcargfactory)
+        newnames = list(factorydef.funcargnames)
         newnames.remove("request")
+        argname = factorydef.argname
         factory_kwargs = {"request": self}
         def fillfactoryargs():
             for newname in newnames:
         else:
             mp.setattr(self, 'param', param, raising=False)
 
-        # implement funcarg marker scope
-        scope = readscope(funcargfactory, "funcarg")
-
+        scope = factorydef.scope
+        funcargfactory = factorydef.func
         if scope is not None:
             __tracebackhide__ = True
             if scopemismatch(self.scope, scope):
                 # try to report something helpful
                 lines = []
-                for factory in self._factorystack:
+                for factorydef in self._factorystack:
+                    factory = factorydef.func
                     fs, lineno = getfslineno(factory)
                     p = self._pyfuncitem.session.fspath.bestrelpath(fs)
                     args = inspect.formatargspec(*inspect.getargspec(factory))

File testing/test_python.py

View file
                     faclist = fm.getfactorylist(name, item.nodeid, item.obj)
                     assert len(faclist) == 1
                     fac = faclist[0]
-                    assert fac.__name__ == "pytest_funcarg__" + name
+                    assert fac.func.__name__ == "pytest_funcarg__" + name
         """)
         reprec = testdir.inline_run("-s")
         reprec.assertoutcome(passed=1)
                     faclist = fm.getfactorylist("hello", item.nodeid, item.obj)
                     print faclist
                     assert len(faclist) == 3
-                    assert faclist[0](item._request) == "conftest"
-                    assert faclist[1](item._request) == "module"
-                    assert faclist[2](item._request) == "class"
+                    assert faclist[0].func(item._request) == "conftest"
+                    assert faclist[1].func(item._request) == "module"
+                    assert faclist[2].func(item._request) == "class"
         """)
         reprec = testdir.inline_run("-s")
         reprec.assertoutcome(passed=1)