7 new commits in pytest:
https://bitbucket.org/hpk42/pytest/changeset/baed16626500/ changeset: baed16626500 user: hpk42 date: 2012-10-16 13:47:59 summary: add plan for better fixture implementation, an xfailing test and a slight refactoring of Metafunc tests/creation affected #: 3 files diff -r 0cf1ef1efbea1aae3d892ff97dec2b8d4ac4231d -r baed16626500839e76c81901e9112cc898b61536 IMPL.txt --- /dev/null +++ b/IMPL.txt @@ -0,0 +1,40 @@ + +internal fixture mechanics +---------------------------- + +fixture mechanics are contained in the python.py plugin. + +pytest fixtures are stored and managed from the FixtureManager (fm) class. +Upon collection fm.parsefactories() is called multiple times to parse +fixture function definitions into FixtureDef objects. + +During collection of test functions, metafunc needs to grow a "fixturenames" +list so that pytest_generate_tests() hooks can check it. These fixturenames +are a closure of all known fixtures to be used for this function: + +- ini-defined usefixtures +- autouse-marked fixtures along the collection chain up from the function +- usefixtures markers at module/class/function level +- test function funcargs + +The latter list (without the closure) is also called "_initialfixtures" +and will be used during the test setup phase. + +Upon the test-setup phases initialfixtures are instantiated which +will subsequently create the full fixture closure (as was computed in +metafunc.fixturenames during collection). As fixture functions +can invoke request.getfuncargvalue() the actual closure may be even +bigger. + +object model +--------------------- + +As part of the metafunc-protocol parents of Function nodes get a +FuncFixtureInfos() object, containing helping/caching for +for a function. .getfixtureinfo(func) returns a FixtureInfo with these +attributes: + +- names_initial: list of initial fixture names (see above) +- names_closure: closure of all fixture names +- name2fixturedeflist: for creating the value + diff -r 0cf1ef1efbea1aae3d892ff97dec2b8d4ac4231d -r baed16626500839e76c81901e9112cc898b61536 _pytest/python.py --- a/_pytest/python.py +++ b/_pytest/python.py @@ -309,8 +309,7 @@ clscol = self.getparent(Class) cls = clscol and clscol.obj or None transfer_markers(funcobj, cls, module) - metafunc = Metafunc(funcobj, parentnode=self, config=self.config, - cls=cls, module=module) + metafunc = Metafunc(funcobj, parentnode=self, cls=cls, module=module) gentesthook = self.config.hook.pytest_generate_tests extra = [module] if cls is not None: @@ -612,25 +611,23 @@ return self.fixturenames class Metafunc(FuncargnamesCompatAttr): - def __init__(self, function, config=None, cls=None, module=None, - parentnode=None): - self.config = config + def __init__(self, function, parentnode, cls=None, module=None): + self.config = parentnode.config self.module = module self.function = function self.parentnode = parentnode - self._parentid = getattr(parentnode, "nodeid", "") argnames = getfuncargnames(function, startindex=int(cls is not None)) - if parentnode is not None: + try: fm = parentnode.session._fixturemanager + except AttributeError: + self.fixturenames = argnames + else: self.fixturenames, self._arg2fixturedeflist = fm.getfixtureclosure( argnames, parentnode) - else: - self.fixturenames = argnames self.cls = cls self.module = module self._calls = [] self._ids = py.builtin.set() - self._arg2scopenum = {} def parametrize(self, argnames, argvalues, indirect=False, ids=None, scope=None): diff -r 0cf1ef1efbea1aae3d892ff97dec2b8d4ac4231d -r baed16626500839e76c81901e9112cc898b61536 testing/test_python.py --- a/testing/test_python.py +++ b/testing/test_python.py @@ -284,22 +284,22 @@ pass def func2(): pass - f1 = pytest.Function(name="name", config=config, - args=(1,), callobj=func1, session=session) + f1 = pytest.Function(name="name", parent=session, config=config, + args=(1,), callobj=func1) f2 = pytest.Function(name="name",config=config, - args=(1,), callobj=func2, session=session) + args=(1,), callobj=func2, parent=session) assert not f1 == f2 assert f1 != f2 - f3 = pytest.Function(name="name", config=config, - args=(1,2), callobj=func2, session=session) + f3 = pytest.Function(name="name", parent=session, config=config, + args=(1,2), callobj=func2) assert not f3 == f2 assert f3 != f2 assert not f3 == f1 assert f3 != f1 - f1_b = pytest.Function(name="name", config=config, - args=(1,), callobj=func1, session=session) + f1_b = pytest.Function(name="name", parent=session, config=config, + args=(1,), callobj=func1) assert f1 == f1_b assert not f1 != f1_b @@ -909,15 +909,20 @@ ]) class TestMetafunc: + def Metafunc(self, func): + class parent: + config = None + return funcargs.Metafunc(func, parentnode=parent) + def test_no_funcargs(self, testdir): def function(): pass - metafunc = funcargs.Metafunc(function) + metafunc = self.Metafunc(function) assert not metafunc.fixturenames repr(metafunc._calls) def test_function_basic(self): def func(arg1, arg2="qwe"): pass - metafunc = funcargs.Metafunc(func) + metafunc = self.Metafunc(func) assert len(metafunc.fixturenames) == 1 assert 'arg1' in metafunc.fixturenames assert metafunc.function is func @@ -925,7 +930,7 @@ def test_addcall_no_args(self): def func(arg1): pass - metafunc = funcargs.Metafunc(func) + metafunc = self.Metafunc(func) metafunc.addcall() assert len(metafunc._calls) == 1 call = metafunc._calls[0] @@ -934,7 +939,7 @@ def test_addcall_id(self): def func(arg1): pass - metafunc = funcargs.Metafunc(func) + metafunc = self.Metafunc(func) pytest.raises(ValueError, "metafunc.addcall(id=None)") metafunc.addcall(id=1) @@ -947,7 +952,7 @@ def test_addcall_param(self): def func(arg1): pass - metafunc = funcargs.Metafunc(func) + metafunc = self.Metafunc(func) class obj: pass metafunc.addcall(param=obj) metafunc.addcall(param=obj) @@ -959,7 +964,7 @@ def test_addcall_funcargs(self): def func(x): pass - metafunc = funcargs.Metafunc(func) + metafunc = self.Metafunc(func) class obj: pass metafunc.addcall(funcargs={"x": 2}) metafunc.addcall(funcargs={"x": 3}) @@ -971,7 +976,7 @@ def test_parametrize_error(self): def func(x, y): pass - metafunc = funcargs.Metafunc(func) + metafunc = self.Metafunc(func) metafunc.parametrize("x", [1,2]) pytest.raises(ValueError, lambda: metafunc.parametrize("x", [5,6])) pytest.raises(ValueError, lambda: metafunc.parametrize("x", [5,6])) @@ -981,7 +986,7 @@ def test_parametrize_and_id(self): def func(x, y): pass - metafunc = funcargs.Metafunc(func) + metafunc = self.Metafunc(func) metafunc.parametrize("x", [1,2], ids=['basic', 'advanced']) metafunc.parametrize("y", ["abc", "def"]) @@ -990,7 +995,7 @@ def test_parametrize_with_userobjects(self): def func(x, y): pass - metafunc = funcargs.Metafunc(func) + metafunc = self.Metafunc(func) class A: pass metafunc.parametrize("x", [A(), A()]) @@ -1002,7 +1007,7 @@ def test_addcall_and_parametrize(self): def func(x, y): pass - metafunc = funcargs.Metafunc(func) + metafunc = self.Metafunc(func) metafunc.addcall({'x': 1}) metafunc.parametrize('y', [2,3]) assert len(metafunc._calls) == 2 @@ -1013,7 +1018,7 @@ def test_parametrize_indirect(self): def func(x, y): pass - metafunc = funcargs.Metafunc(func) + metafunc = self.Metafunc(func) metafunc.parametrize('x', [1], indirect=True) metafunc.parametrize('y', [2,3], indirect=True) metafunc.parametrize('unnamed', [1], indirect=True) @@ -1025,7 +1030,7 @@ def test_addcalls_and_parametrize_indirect(self): def func(x, y): pass - metafunc = funcargs.Metafunc(func) + metafunc = self.Metafunc(func) metafunc.addcall(param="123") metafunc.parametrize('x', [1], indirect=True) metafunc.parametrize('y', [2,3], indirect=True) @@ -1038,7 +1043,6 @@ def test_parametrize_functional(self, testdir): testdir.makepyfile(""" def pytest_generate_tests(metafunc): - assert "test_parametrize_functional" in metafunc._parentid metafunc.parametrize('x', [1,2], indirect=True) metafunc.parametrize('y', [2]) def pytest_funcarg__x(request): @@ -1058,7 +1062,7 @@ ]) def test_parametrize_onearg(self): - metafunc = funcargs.Metafunc(lambda x: None) + metafunc = self.Metafunc(lambda x: None) metafunc.parametrize("x", [1,2]) assert len(metafunc._calls) == 2 assert metafunc._calls[0].funcargs == dict(x=1) @@ -1067,7 +1071,7 @@ assert metafunc._calls[1].id == "2" def test_parametrize_onearg_indirect(self): - metafunc = funcargs.Metafunc(lambda x: None) + metafunc = self.Metafunc(lambda x: None) metafunc.parametrize("x", [1,2], indirect=True) assert metafunc._calls[0].params == dict(x=1) assert metafunc._calls[0].id == "1" @@ -1075,7 +1079,7 @@ assert metafunc._calls[1].id == "2" def test_parametrize_twoargs(self): - metafunc = funcargs.Metafunc(lambda x,y: None) + metafunc = self.Metafunc(lambda x,y: None) metafunc.parametrize(("x", "y"), [(1,2), (3,4)]) assert len(metafunc._calls) == 2 assert metafunc._calls[0].funcargs == dict(x=1, y=2) @@ -2004,6 +2008,28 @@ reprec = testdir.inline_run("-s") reprec.assertoutcome(passed=1) + @pytest.mark.xfail + def test_two_classes_separated_autouse(self, testdir): + testdir.makepyfile(""" + import pytest + class TestA: + l = [] + @pytest.fixture(autouse=True) + def setup1(self): + self.l.append(1) + def test_setup1(self): + assert self.l == [1] + class TestB: + l = [] + @pytest.fixture(autouse=True) + def setup2(self): + self.l.append(1) + def test_setup2(self): + assert self.l == [1] + """) + reprec = testdir.inline_run() + reprec.assertoutcome(passed=2) + def test_setup_at_classlevel(self, testdir): testdir.makepyfile(""" import pytest https://bitbucket.org/hpk42/pytest/changeset/20d77f40c3ab/ changeset: 20d77f40c3ab user: hpk42 date: 2012-10-16 13:47:59 summary: implement fixture information stored on the parentnode of functions to be reused by metafunc mechanics and Function setup affected #: 4 files diff -r baed16626500839e76c81901e9112cc898b61536 -r 20d77f40c3abab579f2be1b310db8529b5234e8c IMPL.txt --- a/IMPL.txt +++ b/IMPL.txt @@ -30,7 +30,7 @@ --------------------- As part of the metafunc-protocol parents of Function nodes get a -FuncFixtureInfos() object, containing helping/caching for +ParentFixtures() object, containing helping/caching for for a function. .getfixtureinfo(func) returns a FixtureInfo with these attributes: diff -r baed16626500839e76c81901e9112cc898b61536 -r 20d77f40c3abab579f2be1b310db8529b5234e8c _pytest/python.py --- a/_pytest/python.py +++ b/_pytest/python.py @@ -309,7 +309,11 @@ clscol = self.getparent(Class) cls = clscol and clscol.obj or None transfer_markers(funcobj, cls, module) - metafunc = Metafunc(funcobj, parentnode=self, cls=cls, module=module) + if not hasattr(self, "_fixturemapper"): + self._fixturemapper = FixtureMapper(self) + fixtureinfo = self._fixturemapper.getfixtureinfo(funcobj, cls) + metafunc = Metafunc(funcobj, fixtureinfo, self.config, + cls=cls, module=module) gentesthook = self.config.hook.pytest_generate_tests extra = [module] if cls is not None: @@ -326,6 +330,32 @@ callspec=callspec, callobj=funcobj, keywords={callspec.id:True}) +class FixtureMapper: + def __init__(self, node): + self.node = node + self.fm = node.session._fixturemanager + self._name2fixtureinfo = {} + + def getfixtureinfo(self, func, cls): + try: + return self._name2fixtureinfo[func] + except KeyError: + pass + argnames = getfuncargnames(func, int(cls is not None)) + usefixtures = getattr(func, "usefixtures", None) + if usefixtures is not None: + argnames = usefixtures.args + argnames + names_closure, arg2fixturedeflist = self.fm.getfixtureclosure( + argnames, self.node) + fixtureinfo = FuncFixtureInfo(names_closure, arg2fixturedeflist) + self._name2fixtureinfo[func] = fixtureinfo + return fixtureinfo + +class FuncFixtureInfo: + def __init__(self, names_closure, name2fixturedeflist): + self.names_closure = names_closure + self.name2fixturedeflist = name2fixturedeflist + def transfer_markers(funcobj, cls, mod): # XXX this should rather be code in the mark plugin or the mark # plugin should merge with the python plugin. @@ -611,19 +641,12 @@ return self.fixturenames class Metafunc(FuncargnamesCompatAttr): - def __init__(self, function, parentnode, cls=None, module=None): - self.config = parentnode.config + def __init__(self, function, fixtureinfo, config, cls=None, module=None): + self.config = config self.module = module self.function = function - self.parentnode = parentnode - argnames = getfuncargnames(function, startindex=int(cls is not None)) - try: - fm = parentnode.session._fixturemanager - except AttributeError: - self.fixturenames = argnames - else: - self.fixturenames, self._arg2fixturedeflist = fm.getfixtureclosure( - argnames, parentnode) + self.fixturenames = fixtureinfo.names_closure + self._arg2fixturedeflist = fixtureinfo.name2fixturedeflist self.cls = cls self.module = module self._calls = [] @@ -878,7 +901,7 @@ Python test function. """ _genid = None - def __init__(self, name, parent=None, args=None, config=None, + def __init__(self, name, parent, args=None, config=None, callspec=None, callobj=_dummy, keywords=None, session=None): super(Function, self).__init__(name, parent, config=config, session=session) @@ -908,9 +931,9 @@ # contstruct a list of all neccessary fixtures for this test function try: - usefixtures = list(self.markers.usefixtures.args) + usefixtures = self.markers.usefixtures.args except AttributeError: - usefixtures = [] + usefixtures = () self.fixturenames = (self.session._fixturemanager.getdefaultfixtures() + usefixtures + self._getfuncargnames()) @@ -1377,16 +1400,16 @@ self.pytest_plugin_registered(plugin) def getdefaultfixtures(self): - """ return a list of default fixture names (XXX for the given file path). """ + """ return a tuple of default fixture names (XXX for the given file path). """ try: return self._defaultfixtures except AttributeError: - defaultfixtures = list(self.config.getini("usefixtures")) + defaultfixtures = tuple(self.config.getini("usefixtures")) # make sure the self._autofixtures list is sorted # by scope, scopenum 0 is session self._autofixtures.sort( key=lambda x: self.arg2fixturedeflist[x][-1].scopenum) - defaultfixtures.extend(self._autofixtures) + defaultfixtures = defaultfixtures + tuple(self._autofixtures) self._defaultfixtures = defaultfixtures return defaultfixtures @@ -1573,8 +1596,8 @@ getattr(function, '__defaults__', None)) or () numdefaults = len(defaults) if numdefaults: - return argnames[startindex:-numdefaults] - return argnames[startindex:] + return tuple(argnames[startindex:-numdefaults]) + return tuple(argnames[startindex:]) # algorithm for sorting on a per-parametrized resource setup basis diff -r baed16626500839e76c81901e9112cc898b61536 -r 20d77f40c3abab579f2be1b310db8529b5234e8c _pytest/unittest.py --- a/_pytest/unittest.py +++ b/_pytest/unittest.py @@ -53,7 +53,7 @@ _excinfo = None def _getfuncargnames(self): - return [] + return () def setup(self): self._testcase = self.parent.obj(self.name) diff -r baed16626500839e76c81901e9112cc898b61536 -r 20d77f40c3abab579f2be1b310db8529b5234e8c testing/test_python.py --- a/testing/test_python.py +++ b/testing/test_python.py @@ -535,17 +535,17 @@ def f(): pass assert not funcargs.getfuncargnames(f) def g(arg): pass - assert funcargs.getfuncargnames(g) == ['arg'] + assert funcargs.getfuncargnames(g) == ('arg',) def h(arg1, arg2="hello"): pass - assert funcargs.getfuncargnames(h) == ['arg1'] + assert funcargs.getfuncargnames(h) == ('arg1',) def h(arg1, arg2, arg3="hello"): pass - assert funcargs.getfuncargnames(h) == ['arg1', 'arg2'] + assert funcargs.getfuncargnames(h) == ('arg1', 'arg2') class A: def f(self, arg1, arg2="hello"): pass - assert funcargs.getfuncargnames(A().f) == ['arg1'] + assert funcargs.getfuncargnames(A().f) == ('arg1',) if sys.version_info < (3,0): - assert funcargs.getfuncargnames(A.f) == ['arg1'] + assert funcargs.getfuncargnames(A.f) == ('arg1',) class TestFillFixtures: @@ -910,9 +910,16 @@ class TestMetafunc: def Metafunc(self, func): - class parent: - config = None - return funcargs.Metafunc(func, parentnode=parent) + # the unit tests of this class check if things work correctly + # on the funcarg level, so we don't need a full blown + # initiliazation + class FixtureInfo: + name2fixturedeflist = None + def __init__(self, names): + self.names_closure = names + names = funcargs.getfuncargnames(func) + fixtureinfo = FixtureInfo(names) + return funcargs.Metafunc(func, fixtureinfo, None) def test_no_funcargs(self, testdir): def function(): pass @@ -1393,6 +1400,20 @@ reprec = testdir.inline_run() reprec.assertoutcome(passed=5) + def test_usemarkers_seen_in_generate_tests(self, testdir): + testdir.makepyfile(""" + import pytest + def pytest_generate_tests(metafunc): + assert "abc" in metafunc.fixturenames + metafunc.parametrize("abc", [1]) + + @pytest.mark.usefixtures("abc") + def test_function(): + pass + """) + reprec = testdir.inline_run() + reprec.assertoutcome(passed=1) + def test_conftest_funcargs_only_available_in_subdir(testdir): sub1 = testdir.mkpydir("sub1") sub2 = testdir.mkpydir("sub2") https://bitbucket.org/hpk42/pytest/changeset/08b363d15353/ changeset: 08b363d15353 user: hpk42 date: 2012-10-16 13:48:00 summary: use fixturemapper/fixtureinfo from Function objects affected #: 3 files diff -r 20d77f40c3abab579f2be1b310db8529b5234e8c -r 08b363d153530c7821817f10a4b2dce355ee2724 _pytest/python.py --- a/_pytest/python.py +++ b/_pytest/python.py @@ -266,6 +266,18 @@ return fspath, lineno, modpath class PyCollector(PyobjMixin, pytest.Collector): + def _fixturemapper(): + def get(self): + try: + return self._fixturemapper_memo + except AttributeError: + self._fixturemapper_memo = FixtureMapper(self, funcargs=False) + return self._fixturemapper_memo + def set(self, val): + assert not hasattr(self, "_fixturemapper_memo") + self._fixturemapper_memo = val + return property(get, set) + _fixturemapper = _fixturemapper() def funcnamefilter(self, name): for prefix in self.config.getini("python_functions"): @@ -309,7 +321,7 @@ clscol = self.getparent(Class) cls = clscol and clscol.obj or None transfer_markers(funcobj, cls, module) - if not hasattr(self, "_fixturemapper"): + if not hasattr(self, "_fixturemapper_memo"): self._fixturemapper = FixtureMapper(self) fixtureinfo = self._fixturemapper.getfixtureinfo(funcobj, cls) metafunc = Metafunc(funcobj, fixtureinfo, self.config, @@ -331,17 +343,21 @@ keywords={callspec.id:True}) class FixtureMapper: - def __init__(self, node): + def __init__(self, node, funcargs=True): self.node = node self.fm = node.session._fixturemanager self._name2fixtureinfo = {} + self.hasfuncargs = funcargs def getfixtureinfo(self, func, cls): try: return self._name2fixtureinfo[func] except KeyError: pass - argnames = getfuncargnames(func, int(cls is not None)) + if self.hasfuncargs: + argnames = getfuncargnames(func, int(cls is not None)) + else: + argnames = () usefixtures = getattr(func, "usefixtures", None) if usefixtures is not None: argnames = usefixtures.args + argnames @@ -929,17 +945,9 @@ for name, val in keywords.items(): setattr(self.markers, name, val) - # contstruct a list of all neccessary fixtures for this test function - try: - usefixtures = self.markers.usefixtures.args - except AttributeError: - usefixtures = () - self.fixturenames = (self.session._fixturemanager.getdefaultfixtures() + - usefixtures + self._getfuncargnames()) - - def _getfuncargnames(self): - startindex = int(self.cls is not None) - return getfuncargnames(self.obj, startindex=startindex) + fixtureinfo = self.parent._fixturemapper.getfixtureinfo(self.obj, + self.cls) + self.fixturenames = fixtureinfo.names_closure @property def function(self): diff -r 20d77f40c3abab579f2be1b310db8529b5234e8c -r 08b363d153530c7821817f10a4b2dce355ee2724 _pytest/unittest.py --- a/_pytest/unittest.py +++ b/_pytest/unittest.py @@ -20,6 +20,7 @@ return UnitTestCase(name, parent=collector) class UnitTestCase(pytest.Class): + def collect(self): self.session._fixturemanager._parsefactories(self.obj, self.nodeid, unittest=True) @@ -52,9 +53,6 @@ class TestCaseFunction(pytest.Function): _excinfo = None - def _getfuncargnames(self): - return () - def setup(self): self._testcase = self.parent.obj(self.name) self._obj = getattr(self._testcase, self.name) diff -r 20d77f40c3abab579f2be1b310db8529b5234e8c -r 08b363d153530c7821817f10a4b2dce355ee2724 testing/test_python.py --- a/testing/test_python.py +++ b/testing/test_python.py @@ -280,6 +280,7 @@ config = testdir.parseconfigure() session = testdir.Session(config) session._fixturemanager = FixtureManager(session) + session._fixturemapper = funcargs.FixtureMapper(session, funcargs=False) def func1(): pass def func2(): @@ -579,6 +580,7 @@ pass """) funcargs.fillfixtures(item) + del item.funcargs["request"] assert len(item.funcargs) == 2 assert item.funcargs['some'] == "test_func" assert item.funcargs['other'] == 42 @@ -685,7 +687,9 @@ val2 = req.getfuncargvalue("other") # see about caching assert val2 == 2 pytest._fillfuncargs(item) - assert item.funcargs == {'something': 1} + assert item.funcargs["something"] == 1 + assert len(item.funcargs) == 2 + assert "request" in item.funcargs #assert item.funcargs == {'something': 1, "other": 2} def test_request_addfinalizer(self, testdir): https://bitbucket.org/hpk42/pytest/changeset/4bdfe68104d5/ changeset: 4bdfe68104d5 user: hpk42 date: 2012-10-16 13:48:00 summary: use FixtureInfo from FixtureRequest affected #: 1 file diff -r 08b363d153530c7821817f10a4b2dce355ee2724 -r 4bdfe68104d5ec3a93670bf9f1e6b0702cd3a8c8 _pytest/python.py --- a/_pytest/python.py +++ b/_pytest/python.py @@ -372,6 +372,16 @@ self.names_closure = names_closure self.name2fixturedeflist = name2fixturedeflist + def getname2fixturedeflist_copy(self): + d = {} + for name, val in self.name2fixturedeflist.items(): + try: + val = list(val) + except TypeError: + pass + d[name] = val + return d + def transfer_markers(funcobj, cls, mod): # XXX this should rather be code in the mark plugin or the mark # plugin should merge with the python plugin. @@ -580,6 +590,9 @@ try: request = function._request except AttributeError: + # the special jstests class with a custom .obj + fi = FixtureMapper(function).getfixtureinfo(function.obj, None) + function._fixtureinfo = fi request = function._request = FixtureRequest(function) request._fillfixtures() @@ -922,6 +935,18 @@ super(Function, self).__init__(name, parent, config=config, session=session) self._args = args + if callobj is not _dummy: + self.obj = callobj + + for name, val in (py.builtin._getfuncdict(self.obj) or {}).items(): + setattr(self.markers, name, val) + if keywords: + for name, val in keywords.items(): + setattr(self.markers, name, val) + + fi = self.parent._fixturemapper.getfixtureinfo(self.obj, self.cls) + self._fixtureinfo = fi + self.fixturenames = fi.names_closure if self._isyieldedfunction(): assert not callspec, ( "yielded functions (deprecated) cannot have funcargs") @@ -936,18 +961,6 @@ self.funcargs = {} self._request = req = FixtureRequest(self) #req._discoverfactories() - if callobj is not _dummy: - self.obj = callobj - - for name, val in (py.builtin._getfuncdict(self.obj) or {}).items(): - setattr(self.markers, name, val) - if keywords: - for name, val in keywords.items(): - setattr(self.markers, name, val) - - fixtureinfo = self.parent._fixturemapper.getfixtureinfo(self.obj, - self.cls) - self.fixturenames = fixtureinfo.names_closure @property def function(self): @@ -1041,13 +1054,11 @@ self.scope = "function" self.getparent = pyfuncitem.getparent self._funcargs = self._pyfuncitem.funcargs.copy() - self._arg2fixturedeflist = {} + self._fixtureinfo = fi = pyfuncitem._fixtureinfo + self._arg2fixturedeflist = fi.getname2fixturedeflist_copy() + self.fixturenames = self._fixtureinfo.names_closure self._fixturemanager = pyfuncitem.session._fixturemanager self._parentid = pyfuncitem.parent.nodeid - self.fixturenames, self._arg2fixturedeflist_ = \ - self._fixturemanager.getfixtureclosure( - getfuncargnames(self.function), # XXX _pyfuncitem... - pyfuncitem.parent) self._fixturestack = [] @property https://bitbucket.org/hpk42/pytest/changeset/648c93461248/ changeset: 648c93461248 user: hpk42 date: 2012-10-16 13:59:12 summary: make factorydeflist immutable by using an index affected #: 3 files diff -r 4bdfe68104d5ec3a93670bf9f1e6b0702cd3a8c8 -r 648c9346124894406687104a05891d6b68eb844b IMPL.txt --- a/IMPL.txt +++ b/IMPL.txt @@ -36,5 +36,5 @@ - names_initial: list of initial fixture names (see above) - names_closure: closure of all fixture names -- name2fixturedeflist: for creating the value +- name2fixturedefs: for creating the value diff -r 4bdfe68104d5ec3a93670bf9f1e6b0702cd3a8c8 -r 648c9346124894406687104a05891d6b68eb844b _pytest/python.py --- a/_pytest/python.py +++ b/_pytest/python.py @@ -361,26 +361,16 @@ usefixtures = getattr(func, "usefixtures", None) if usefixtures is not None: argnames = usefixtures.args + argnames - names_closure, arg2fixturedeflist = self.fm.getfixtureclosure( + names_closure, arg2fixturedefs = self.fm.getfixtureclosure( argnames, self.node) - fixtureinfo = FuncFixtureInfo(names_closure, arg2fixturedeflist) + fixtureinfo = FuncFixtureInfo(names_closure, arg2fixturedefs) self._name2fixtureinfo[func] = fixtureinfo return fixtureinfo class FuncFixtureInfo: - def __init__(self, names_closure, name2fixturedeflist): + def __init__(self, names_closure, name2fixturedefs): self.names_closure = names_closure - self.name2fixturedeflist = name2fixturedeflist - - def getname2fixturedeflist_copy(self): - d = {} - for name, val in self.name2fixturedeflist.items(): - try: - val = list(val) - except TypeError: - pass - d[name] = val - return d + self.name2fixturedefs = name2fixturedefs def transfer_markers(funcobj, cls, mod): # XXX this should rather be code in the mark plugin or the mark @@ -675,7 +665,7 @@ self.module = module self.function = function self.fixturenames = fixtureinfo.names_closure - self._arg2fixturedeflist = fixtureinfo.name2fixturedeflist + self._arg2fixturedefs = fixtureinfo.name2fixturedefs self.cls = cls self.module = module self._calls = [] @@ -804,12 +794,12 @@ fm = session._fixturemanager available = [] - for argname in fm.arg2fixturedeflist: - fixturedeflist = fm.getfixturedeflist(argname, nodeid) - assert fixturedeflist is not None - if not fixturedeflist: + for argname in fm.arg2fixturedefs: + fixturedefs = fm.getfixturedefs(argname, nodeid) + assert fixturedefs is not None + if not fixturedefs: continue - fixturedef = fixturedeflist[-1] + fixturedef = fixturedefs[-1] loc = getlocation(fixturedef.func, curdir) available.append((len(fixturedef.baseid), curdir.bestrelpath(loc), @@ -1055,7 +1045,8 @@ self.getparent = pyfuncitem.getparent self._funcargs = self._pyfuncitem.funcargs.copy() self._fixtureinfo = fi = pyfuncitem._fixtureinfo - self._arg2fixturedeflist = fi.getname2fixturedeflist_copy() + self._arg2fixturedefs = fi.name2fixturedefs + self._arg2index = {} self.fixturenames = self._fixtureinfo.names_closure self._fixturemanager = pyfuncitem.session._fixturemanager self._parentid = pyfuncitem.parent.nodeid @@ -1066,15 +1057,20 @@ """ underlying collection node (depends on current request scope)""" return self._getscopeitem(self.scope) - def _getfixturedeflist(self, argname): - fixturedeflist = self._arg2fixturedeflist.get(argname, None) - if fixturedeflist is None: - fixturedeflist = self._fixturemanager.getfixturedeflist( + def _getnextfixturedef(self, argname): + fixturedefs = self._arg2fixturedefs.get(argname, None) + if fixturedefs is None: + # 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) - self._arg2fixturedeflist[argname] = fixturedeflist - if not fixturedeflist: + self._arg2fixturedefs[argname] = fixturedefs + # fixturedefs is immutable so we maintain a decreasing index + index = self._arg2index.get(argname, 0) - 1 + if fixturedefs is None or (-index > len(fixturedefs)): raise FixtureLookupError(argname, self) - return fixturedeflist + self._arg2index[argname] = index + return fixturedefs[index] @property def config(self): @@ -1212,12 +1208,11 @@ except KeyError: pass try: - fixturedeflist = self._getfixturedeflist(argname) + fixturedef = self._getnextfixturedef(argname) except FixtureLookupError: if argname == "request": return self raise - fixturedef = fixturedeflist.pop() self._fixturestack.append(fixturedef) try: result = self._getfuncargvalue(fixturedef) @@ -1353,7 +1348,7 @@ fm = self.request._fixturemanager nodeid = self.request._parentid available = [] - for name, fixturedef in fm.arg2fixturedeflist.items(): + for name, fixturedef in fm.arg2fixturedefs.items(): faclist = list(fm._matchfactories(fixturedef, self.request._parentid)) if faclist: available.append(name) @@ -1388,7 +1383,7 @@ def __init__(self, session): self.session = session self.config = session.config - self.arg2fixturedeflist = {} + self.arg2fixturedefs = {} self._seenplugins = set() self._holderobjseen = set() self._arg2finish = {} @@ -1427,7 +1422,7 @@ # make sure the self._autofixtures list is sorted # by scope, scopenum 0 is session self._autofixtures.sort( - key=lambda x: self.arg2fixturedeflist[x][-1].scopenum) + key=lambda x: self.arg2fixturedefs[x][-1].scopenum) defaultfixtures = defaultfixtures + tuple(self._autofixtures) self._defaultfixtures = defaultfixtures return defaultfixtures @@ -1435,7 +1430,7 @@ def getfixtureclosure(self, fixturenames, parentnode): # collect the closure of all fixtures , starting with the given # fixturenames as the initial set. As we have to visit all - # factory definitions anyway, we also return a arg2fixturedeflist + # factory definitions anyway, we also return a arg2fixturedefs # mapping so that the caller can reuse it and does not have # to re-discover fixturedefs again for each fixturename # (discovering matching fixtures for a given name/node is expensive) @@ -1447,23 +1442,23 @@ if arg not in fixturenames_closure: fixturenames_closure.append(arg) merge(fixturenames) - arg2fixturedeflist = {} + arg2fixturedefs = {} lastlen = -1 while lastlen != len(fixturenames_closure): lastlen = len(fixturenames_closure) for argname in fixturenames_closure: - if argname in arg2fixturedeflist: + if argname in arg2fixturedefs: continue - fixturedeflist = self.getfixturedeflist(argname, parentid) - arg2fixturedeflist[argname] = fixturedeflist - if fixturedeflist is not None: - for fixturedef in fixturedeflist: + fixturedefs = self.getfixturedefs(argname, parentid) + arg2fixturedefs[argname] = fixturedefs + if fixturedefs is not None: + for fixturedef in fixturedefs: merge(fixturedef.fixturenames) - return fixturenames_closure, arg2fixturedeflist + return fixturenames_closure, arg2fixturedefs def pytest_generate_tests(self, metafunc): for argname in metafunc.fixturenames: - faclist = metafunc._arg2fixturedeflist[argname] + faclist = metafunc._arg2fixturedefs[argname] if faclist is None: continue # will raise FixtureLookupError at setup time for fixturedef in faclist: @@ -1527,7 +1522,7 @@ fixturedef = FixtureDef(self, nodeid, name, obj, marker.scope, marker.params, unittest=unittest) - faclist = self.arg2fixturedeflist.setdefault(name, []) + faclist = self.arg2fixturedefs.setdefault(name, []) faclist.append(fixturedef) if marker.autouse: self._autofixtures.append(name) @@ -1536,16 +1531,16 @@ except AttributeError: pass - def getfixturedeflist(self, argname, nodeid): + def getfixturedefs(self, argname, nodeid): try: - fixturedeflist = self.arg2fixturedeflist[argname] + fixturedefs = self.arg2fixturedefs[argname] except KeyError: return None else: - return list(self._matchfactories(fixturedeflist, nodeid)) + return tuple(self._matchfactories(fixturedefs, nodeid)) - def _matchfactories(self, fixturedeflist, nodeid): - for fixturedef in fixturedeflist: + def _matchfactories(self, fixturedefs, nodeid): + for fixturedef in fixturedefs: if nodeid.startswith(fixturedef.baseid): yield fixturedef diff -r 4bdfe68104d5ec3a93670bf9f1e6b0702cd3a8c8 -r 648c9346124894406687104a05891d6b68eb844b testing/test_python.py --- a/testing/test_python.py +++ b/testing/test_python.py @@ -640,7 +640,7 @@ assert req.cls.__name__ == "TestB" assert req.instance.__class__ == req.cls - def XXXtest_request_contains_funcarg_arg2fixturedeflist(self, testdir): + def XXXtest_request_contains_funcarg_arg2fixturedefs(self, testdir): modcol = testdir.getmodulecol(""" def pytest_funcarg__something(request): pass @@ -650,9 +650,9 @@ """) item1, = testdir.genitems([modcol]) assert item1.name == "test_method" - arg2fixturedeflist = funcargs.FixtureRequest(item1)._arg2fixturedeflist - assert len(arg2fixturedeflist) == 1 - assert arg2fixturedeflist[0].__name__ == "pytest_funcarg__something" + arg2fixturedefs = funcargs.FixtureRequest(item1)._arg2fixturedefs + assert len(arg2fixturedefs) == 1 + assert arg2fixturedefs[0].__name__ == "pytest_funcarg__something" def test_getfuncargvalue_recursive(self, testdir): testdir.makeconftest(""" @@ -918,7 +918,7 @@ # on the funcarg level, so we don't need a full blown # initiliazation class FixtureInfo: - name2fixturedeflist = None + name2fixturedefs = None def __init__(self, names): self.names_closure = names names = funcargs.getfuncargnames(func) @@ -1974,7 +1974,7 @@ testdir.makepyfile(""" def test_hello(item, fm): for name in ("fm", "hello", "item"): - faclist = fm.getfixturedeflist(name, item.nodeid) + faclist = fm.getfixturedefs(name, item.nodeid) assert len(faclist) == 1 fac = faclist[0] assert fac.func.__name__ == "pytest_funcarg__" + name @@ -1990,7 +1990,7 @@ def pytest_funcarg__hello(self, request): return "class" def test_hello(self, item, fm): - faclist = fm.getfixturedeflist("hello", item.nodeid) + faclist = fm.getfixturedefs("hello", item.nodeid) print (faclist) assert len(faclist) == 3 assert faclist[0].func(item._request) == "conftest" https://bitbucket.org/hpk42/pytest/changeset/eb495bd8132e/ changeset: eb495bd8132e user: hpk42 date: 2012-10-16 14:19:38 summary: strike another use of getfuncargnames() and rename FixtureDef.fixturenames to "argnames" because it's really just the fixture function arguments affected #: 1 file diff -r 648c9346124894406687104a05891d6b68eb844b -r eb495bd8132e038f69f45ca775d60cdd1a7af818 _pytest/python.py --- a/_pytest/python.py +++ b/_pytest/python.py @@ -142,25 +142,9 @@ if pyfuncitem._isyieldedfunction(): testfunction(*pyfuncitem._args) else: - try: - fixturenames = pyfuncitem.fixturenames - except AttributeError: - funcargs = pyfuncitem.funcargs - else: - funcargs = {} - for name in fixturenames: - funcargs[name] = pyfuncitem.funcargs[name] - testfunction(**funcargs) - -def pytest_pyfunc_call(__multicall__, pyfuncitem): - if not __multicall__.execute(): - testfunction = pyfuncitem.obj - if pyfuncitem._isyieldedfunction(): - testfunction(*pyfuncitem._args) - else: funcargs = pyfuncitem.funcargs testargs = {} - for arg in getfuncargnames(testfunction): + for arg in pyfuncitem._fixtureinfo.argnames: testargs[arg] = funcargs[arg] testfunction(**testargs) @@ -359,16 +343,19 @@ else: argnames = () usefixtures = getattr(func, "usefixtures", None) + initialnames = argnames if usefixtures is not None: - argnames = usefixtures.args + argnames + initialnames = usefixtures.args + initialnames names_closure, arg2fixturedefs = self.fm.getfixtureclosure( - argnames, self.node) - fixtureinfo = FuncFixtureInfo(names_closure, arg2fixturedefs) + initialnames, self.node) + fixtureinfo = FuncFixtureInfo(argnames, names_closure, + arg2fixturedefs) self._name2fixtureinfo[func] = fixtureinfo return fixtureinfo class FuncFixtureInfo: - def __init__(self, names_closure, name2fixturedefs): + def __init__(self, argnames, names_closure, name2fixturedefs): + self.argnames = argnames self.names_closure = names_closure self.name2fixturedefs = name2fixturedefs @@ -1265,7 +1252,7 @@ # (XXX analyse exact finalizing mechanics / cleanup) self.session._setupstate.addfinalizer(fixturedef.finish, self.node) self._fixturemanager.addargfinalizer(fixturedef.finish, argname) - for subargname in fixturedef.fixturenames: # XXX all deps? + for subargname in fixturedef.argnames: # XXX all deps? self._fixturemanager.addargfinalizer(fixturedef.finish, subargname) mp.setattr(self, "addfinalizer", fixturedef.addfinalizer) # finally perform the fixture call @@ -1453,7 +1440,7 @@ arg2fixturedefs[argname] = fixturedefs if fixturedefs is not None: for fixturedef in fixturedefs: - merge(fixturedef.fixturenames) + merge(fixturedef.argnames) return fixturenames_closure, arg2fixturedefs def pytest_generate_tests(self, metafunc): @@ -1567,7 +1554,7 @@ self.scopenum = scopes.index(scope or "function") self.params = params startindex = unittest and 1 or None - self.fixturenames = getfuncargnames(func, startindex=startindex) + self.argnames = getfuncargnames(func, startindex=startindex) self.unittest = unittest self.active = False self._finalizer = [] @@ -1587,7 +1574,7 @@ def execute(self, request): kwargs = {} - for newname in self.fixturenames: + for newname in self.argnames: kwargs[newname] = request.getfuncargvalue(newname) if self.unittest: result = self.func(request.instance, **kwargs) https://bitbucket.org/hpk42/pytest/changeset/5f7bfa93ff2e/ changeset: 5f7bfa93ff2e user: hpk42 date: 2012-10-16 16:13:12 summary: refine parsefactories interface, fix two_classes test originally reported by Alex Okrushko, also add a few more tests to make sure autouse-fixtures are properly distinguished affected #: 5 files diff -r eb495bd8132e038f69f45ca775d60cdd1a7af818 -r 5f7bfa93ff2eb7a7dded4c2096704264e692311d _pytest/__init__.py --- a/_pytest/__init__.py +++ b/_pytest/__init__.py @@ -1,2 +1,2 @@ # -__version__ = '2.3.0.dev23' +__version__ = '2.3.0.dev24' diff -r eb495bd8132e038f69f45ca775d60cdd1a7af818 -r 5f7bfa93ff2eb7a7dded4c2096704264e692311d _pytest/python.py --- a/_pytest/python.py +++ b/_pytest/python.py @@ -83,7 +83,7 @@ group.addoption('--fixtures', '--fixtures', action="store_true", dest="showfixtures", default=False, help="show available fixtures, sorted by plugin appearance") - parser.addini("usefixtures", type="args", default=(), + parser.addini("usefixtures", type="args", default=[], help="list of default fixtures to be used with this project") parser.addini("python_files", type="args", default=('test_*.py', '*_test.py'), @@ -379,7 +379,7 @@ return self._memoizedcall('_obj', self._importtestmodule) def collect(self): - self.session._fixturemanager._parsefactories(self.obj, self.nodeid) + self.session._fixturemanager.parsefactories(self) return super(Module, self).collect() def _importtestmodule(self): @@ -452,7 +452,7 @@ return obj def collect(self): - self.session._fixturemanager._parsefactories(self.obj, self.nodeid) + self.session._fixturemanager.parsefactories(self) return super(Instance, self).collect() def newinstance(self): @@ -781,7 +781,7 @@ fm = session._fixturemanager available = [] - for argname in fm.arg2fixturedefs: + for argname in fm._arg2fixturedefs: fixturedefs = fm.getfixturedefs(argname, nodeid) assert fixturedefs is not None if not fixturedefs: @@ -1335,7 +1335,7 @@ fm = self.request._fixturemanager nodeid = self.request._parentid available = [] - for name, fixturedef in fm.arg2fixturedefs.items(): + for name, fixturedef in fm._arg2fixturedefs.items(): faclist = list(fm._matchfactories(fixturedef, self.request._parentid)) if faclist: available.append(name) @@ -1370,11 +1370,11 @@ def __init__(self, session): self.session = session self.config = session.config - self.arg2fixturedefs = {} + self._arg2fixturedefs = {} self._seenplugins = set() self._holderobjseen = set() self._arg2finish = {} - self._autofixtures = [] + self._nodeid_and_autousenames = [("", self.config.getini("usefixtures"))] session.config.pluginmanager.register(self, "funcmanage") ### XXX this hook should be called for historic events like pytest_configure @@ -1391,7 +1391,7 @@ else: if p.basename.startswith("conftest.py"): nodeid = p.dirpath().relto(self.session.fspath) - self._parsefactories(plugin, nodeid) + self.parsefactories(plugin, nodeid) self._seenplugins.add(plugin) @pytest.mark.tryfirst @@ -1400,19 +1400,21 @@ for plugin in plugins: self.pytest_plugin_registered(plugin) - def getdefaultfixtures(self): - """ return a tuple of default fixture names (XXX for the given file path). """ - try: - return self._defaultfixtures - except AttributeError: - defaultfixtures = tuple(self.config.getini("usefixtures")) - # make sure the self._autofixtures list is sorted - # by scope, scopenum 0 is session - self._autofixtures.sort( - key=lambda x: self.arg2fixturedefs[x][-1].scopenum) - defaultfixtures = defaultfixtures + tuple(self._autofixtures) - self._defaultfixtures = defaultfixtures - return defaultfixtures + def _getautousenames(self, nodeid): + """ return a tuple of fixture names to be used. """ + autousenames = [] + for baseid, basenames in self._nodeid_and_autousenames: + if nodeid.startswith(baseid): + if baseid: + i = len(baseid) + 1 + nextchar = nodeid[i:i+1] + if nextchar and nextchar not in ":/": + continue + autousenames.extend(basenames) + # make sure autousenames are sorted by scope, scopenum 0 is session + autousenames.sort( + key=lambda x: self._arg2fixturedefs[x][-1].scopenum) + return autousenames def getfixtureclosure(self, fixturenames, parentnode): # collect the closure of all fixtures , starting with the given @@ -1423,7 +1425,7 @@ # (discovering matching fixtures for a given name/node is expensive) parentid = parentnode.nodeid - fixturenames_closure = list(self.getdefaultfixtures()) + fixturenames_closure = self._getautousenames(parentid) def merge(otherlist): for arg in otherlist: if arg not in fixturenames_closure: @@ -1484,10 +1486,16 @@ for fin in l: fin() - def _parsefactories(self, holderobj, nodeid, unittest=False): + def parsefactories(self, node_or_obj, nodeid=None, unittest=False): + if nodeid is not None: + holderobj = node_or_obj + else: + holderobj = node_or_obj.obj + nodeid = node_or_obj.nodeid if holderobj in self._holderobjseen: return self._holderobjseen.add(holderobj) + autousenames = [] for name in dir(holderobj): obj = getattr(holderobj, name) if not callable(obj): @@ -1509,18 +1517,16 @@ fixturedef = FixtureDef(self, nodeid, name, obj, marker.scope, marker.params, unittest=unittest) - faclist = self.arg2fixturedefs.setdefault(name, []) + faclist = self._arg2fixturedefs.setdefault(name, []) faclist.append(fixturedef) if marker.autouse: - self._autofixtures.append(name) - try: - del self._defaultfixtures - except AttributeError: - pass + autousenames.append(name) + if autousenames: + self._nodeid_and_autousenames.append((nodeid, autousenames)) def getfixturedefs(self, argname, nodeid): try: - fixturedefs = self.arg2fixturedefs[argname] + fixturedefs = self._arg2fixturedefs[argname] except KeyError: return None else: diff -r eb495bd8132e038f69f45ca775d60cdd1a7af818 -r 5f7bfa93ff2eb7a7dded4c2096704264e692311d _pytest/unittest.py --- a/_pytest/unittest.py +++ b/_pytest/unittest.py @@ -22,8 +22,7 @@ class UnitTestCase(pytest.Class): def collect(self): - self.session._fixturemanager._parsefactories(self.obj, self.nodeid, - unittest=True) + self.session._fixturemanager.parsefactories(self, unittest=True) loader = py.std.unittest.TestLoader() module = self.getparent(pytest.Module).obj cls = self.obj diff -r eb495bd8132e038f69f45ca775d60cdd1a7af818 -r 5f7bfa93ff2eb7a7dded4c2096704264e692311d 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.dev23', + version='2.3.0.dev24', url='http://pytest.org', license='MIT license', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], diff -r eb495bd8132e038f69f45ca775d60cdd1a7af818 -r 5f7bfa93ff2eb7a7dded4c2096704264e692311d testing/test_python.py --- a/testing/test_python.py +++ b/testing/test_python.py @@ -2026,14 +2026,14 @@ def test_parsefactories_conftest(self, testdir): testdir.makepyfile(""" def test_check_setup(item, fm): - assert len(fm._autofixtures) == 2 - assert "perfunction2" in fm._autofixtures - assert "perfunction" in fm._autofixtures + autousenames = fm._getautousenames(item.nodeid) + assert len(autousenames) == 2 + assert "perfunction2" in autousenames + assert "perfunction" in autousenames """) reprec = testdir.inline_run("-s") reprec.assertoutcome(passed=1) - @pytest.mark.xfail def test_two_classes_separated_autouse(self, testdir): testdir.makepyfile(""" import pytest @@ -2113,6 +2113,45 @@ reprec = testdir.inline_run("-s") reprec.assertoutcome(failed=0, passed=0) + def test_autouse_in_conftests(self, testdir): + a = testdir.mkdir("a") + b = testdir.mkdir("a1") + conftest = testdir.makeconftest(""" + import pytest + @pytest.fixture(autouse=True) + def hello(): + xxx + """) + conftest.move(a.join(conftest.basename)) + a.join("test_something.py").write("def test_func(): pass") + b.join("test_otherthing.py").write("def test_func(): pass") + result = testdir.runpytest() + result.stdout.fnmatch_lines(""" + *1 passed*1 error* + """) + + def test_autouse_in_module_and_two_classes(self, testdir): + testdir.makepyfile(""" + import pytest + l = [] + @pytest.fixture(autouse=True) + def append1(): + l.append("module") + def test_x(): + assert l == ["module"] + + class TestA: + @pytest.fixture(autouse=True) + def append2(self): + l.append("A") + def test_hello(self): + assert l == ["module", "module", "A"], l + class TestA2: + def test_world(self): + assert l == ["module", "module", "A", "module"], l + """) + reprec = testdir.inline_run() + reprec.assertoutcome(passed=3) class TestSetupManagement: def test_funcarg_and_setup(self, testdir): @@ -2220,7 +2259,7 @@ def test_2(self): pass """) - reprec = testdir.inline_run("-v",) + reprec = testdir.inline_run("-v","-s") reprec.assertoutcome(passed=8) config = reprec.getcalls("pytest_unconfigure")[0].config l = config._conftest.getconftestmodules(p)[0].l 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