diff --git a/_pytest/impl b/_pytest/impl deleted file mode 100644 index 889e37e5a..000000000 --- a/_pytest/impl +++ /dev/null @@ -1,254 +0,0 @@ -Sorting per-resource ------------------------------ - -for any given set of items: - -- collect items per session-scoped parametrized funcarg -- re-order until items no parametrizations are mixed - - examples: - - test() - test1(s1) - test1(s2) - test2() - test3(s1) - test3(s2) - - gets sorted to: - - test() - test2() - test1(s1) - test3(s1) - test1(s2) - test3(s2) - - -the new @setup functions --------------------------------------- - -Consider a given @setup-marked function:: - - @pytest.mark.setup(maxscope=SCOPE) - def mysetup(request, arg1, arg2, ...) - ... - request.addfinalizer(fin) - ... - -then FUNCARGSET denotes the set of (arg1, arg2, ...) funcargs and -all of its dependent funcargs. The mysetup function will execute -for any matching test item once per scope. - -The scope is determined as the minimum scope of all scopes of the args -in FUNCARGSET and the given "maxscope". - -If mysetup has been called and no finalizers have been called it is -called "active". - -Furthermore the following rules apply: - -- if an arg value in FUNCARGSET is about to be torn down, the - mysetup-registered finalizers will execute as well. - -- There will never be two active mysetup invocations. - -Example 1, session scope:: - - @pytest.mark.funcarg(scope="session", params=[1,2]) - def db(request): - request.addfinalizer(db_finalize) - - @pytest.mark.setup - def mysetup(request, db): - request.addfinalizer(mysetup_finalize) - ... - -And a given test module: - - def test_something(): - ... - def test_otherthing(): - pass - -Here is what happens:: - - db(request) executes with request.param == 1 - mysetup(request, db) executes - test_something() executes - test_otherthing() executes - mysetup_finalize() executes - db_finalize() executes - db(request) executes with request.param == 2 - mysetup(request, db) executes - test_something() executes - test_otherthing() executes - mysetup_finalize() executes - db_finalize() executes - -Example 2, session/function scope:: - - @pytest.mark.funcarg(scope="session", params=[1,2]) - def db(request): - request.addfinalizer(db_finalize) - - @pytest.mark.setup(scope="function") - def mysetup(request, db): - ... - request.addfinalizer(mysetup_finalize) - ... - -And a given test module: - - def test_something(): - ... - def test_otherthing(): - pass - -Here is what happens:: - - db(request) executes with request.param == 1 - mysetup(request, db) executes - test_something() executes - mysetup_finalize() executes - mysetup(request, db) executes - test_otherthing() executes - mysetup_finalize() executes - db_finalize() executes - db(request) executes with request.param == 2 - mysetup(request, db) executes - test_something() executes - mysetup_finalize() executes - mysetup(request, db) executes - test_otherthing() executes - mysetup_finalize() executes - db_finalize() executes - - -Example 3 - funcargs session-mix ----------------------------------------- - -Similar with funcargs, an example:: - - @pytest.mark.funcarg(scope="session", params=[1,2]) - def db(request): - request.addfinalizer(db_finalize) - - @pytest.mark.funcarg(scope="function") - def table(request, db): - ... - request.addfinalizer(table_finalize) - ... - -And a given test module: - - def test_something(table): - ... - def test_otherthing(table): - pass - def test_thirdthing(): - pass - -Here is what happens:: - - db(request) executes with param == 1 - table(request, db) - test_something(table) - table_finalize() - table(request, db) - test_otherthing(table) - table_finalize() - db_finalize - db(request) executes with param == 2 - table(request, db) - test_something(table) - table_finalize() - table(request, db) - test_otherthing(table) - table_finalize() - db_finalize - test_thirdthing() - -Data structures --------------------- - -pytest internally maintains a dict of active funcargs with cache, param, -finalizer, (scopeitem?) information: - - active_funcargs = dict() - -if a parametrized "db" is activated: - - active_funcargs["db"] = FuncargInfo(dbvalue, paramindex, - FuncargFinalize(...), scopeitem) - -if a test is torn down and the next test requires a differently -parametrized "db": - - for argname in item.callspec.params: - if argname in active_funcargs: - funcarginfo = active_funcargs[argname] - if funcarginfo.param != item.callspec.params[argname]: - funcarginfo.callfinalizer() - del node2funcarg[funcarginfo.scopeitem] - del active_funcargs[argname] - nodes_to_be_torn_down = ... - for node in nodes_to_be_torn_down: - if node in node2funcarg: - argname = node2funcarg[node] - active_funcargs[argname].callfinalizer() - del node2funcarg[node] - del active_funcargs[argname] - -if a test is setup requiring a "db" funcarg: - - if "db" in active_funcargs: - return active_funcargs["db"][0] - funcarginfo = setup_funcarg() - active_funcargs["db"] = funcarginfo - node2funcarg[funcarginfo.scopeitem] = "db" - -Implementation plan for resources ------------------------------------------- - -1. Revert FuncargRequest to the old form, unmerge item/request - (done) -2. make funcarg factories be discovered at collection time -3. Introduce funcarg marker -4. Introduce funcarg scope parameter -5. Introduce funcarg parametrize parameter -6. make setup functions be discovered at collection time -7. (Introduce a pytest_fixture_protocol/setup_funcargs hook) - -methods and data structures --------------------------------- - -A FuncarcManager holds all information about funcarg definitions -including parametrization and scope definitions. It implements -a pytest_generate_tests hook which performs parametrization as appropriate. - -as a simple example, let's consider a tree where a test function requires -a "abc" funcarg and its factory defines it as parametrized and scoped -for Modules. When collections hits the function item, it creates -the metafunc object, and calls funcargdb.pytest_generate_tests(metafunc) -which looks up available funcarg factories and their scope and parametrization. -This information is equivalent to what can be provided today directly -at the function site and it should thus be relatively straight forward -to implement the additional way of defining parametrization/scoping. - -conftest loading: - each funcarg-factory will populate the session.funcargmanager - -When a test item is collected, it grows a dictionary -(funcargname2factorycalllist). A factory lookup is performed -for each required funcarg. The resulting factory call is stored -with the item. If a function is parametrized multiple items are -created with respective factory calls. Else if a factory is parametrized -multiple items and calls to the factory function are created as well. - -At setup time, an item populates a funcargs mapping, mapping names -to values. If a value is funcarg factories are queried for a given item -test functions and setup functions are put in a class -which looks up required funcarg factories. - -