11# -*- coding: utf-8 -*-
2- import os
32import sys
43import types
54from collections import defaultdict
6- import py
75import pytest
86from _pytest .fixtures import scopenum_function
97
@@ -50,6 +48,14 @@ def pytest_runtest_call(item):
5048 item .funcargs [arg ] = item ._request .getfixturevalue (val .name )
5149
5250
51+ @pytest .hookimpl (hookwrapper = True )
52+ def pytest_pycollect_makeitem (collector , name , obj ):
53+ global current_node
54+ current_node = collector
55+ yield
56+ current_node = None
57+
58+
5359@pytest .hookimpl (hookwrapper = True )
5460def pytest_generate_tests (metafunc ):
5561 yield
@@ -66,40 +72,57 @@ def normalize_metafunc_calls(metafunc, valtype):
6672 metafunc ._calls = newcalls
6773
6874
75+ def parametrize_callspecs (callspecs , metafunc , fname , fparams ):
76+ allnewcallspecs = []
77+ for i , param in enumerate (fparams ):
78+ try :
79+ newcallspecs = [call .copy () for call in callspecs ]
80+ except TypeError :
81+ # pytest < 3.6.3
82+ newcallspecs = [call .copy (metafunc ) for call in callspecs ]
83+
84+ # TODO: for now it uses only function scope
85+ # TODO: idlist
86+ setmulti_args = (
87+ {fname : 'params' }, (fname ,), (param ,),
88+ None , (), scopenum_function , i
89+ )
90+ try :
91+ for newcallspec in newcallspecs :
92+ newcallspec .setmulti2 (* setmulti_args )
93+ except AttributeError :
94+ # pytest < 3.3.0
95+ for newcallspec in newcallspecs :
96+ newcallspec .setmulti (* setmulti_args )
97+ allnewcallspecs .extend (newcallspecs )
98+ return allnewcallspecs
99+
100+
69101def normalize_call (callspec , metafunc , valtype , used_keys = None ):
70102 fm = metafunc .config .pluginmanager .get_plugin ('funcmanage' )
71- config = metafunc .config
72103
73104 used_keys = used_keys or set ()
74105 valtype_keys = set (getattr (callspec , valtype ).keys ()) - used_keys
75106
76- newcalls = []
77107 for arg in valtype_keys :
78108 val = getattr (callspec , valtype )[arg ]
79109 if is_lazy_fixture (val ):
80- fname = val .name
81- nodeid = get_nodeid (metafunc .module , config .rootdir )
82- fdef = fm .getfixturedefs (fname , nodeid )
83- if fname not in callspec .params and fdef and fdef [- 1 ].params :
84- for i , param in enumerate (fdef [0 ].params ):
85- try :
86- newcallspec = callspec .copy ()
87- except TypeError :
88- # pytest < 3.6.3
89- newcallspec = callspec .copy (metafunc )
90-
91- # TODO: for now it uses only function scope
92- # TODO: idlist
93- setmulti_args = (
94- {fname : 'params' }, (fname ,), (param ,),
95- None , (), scopenum_function , i
96- )
97- try :
98- newcallspec .setmulti2 (* setmulti_args )
99- except AttributeError :
100- # pytest < 3.3.0
101- newcallspec .setmulti (* setmulti_args )
102-
110+ try :
111+ _ , fixturenames_closure , arg2fixturedefs = fm .getfixtureclosure ([val .name ], metafunc .definition .parent )
112+ except AttributeError :
113+ # pytest < 3.10.0
114+ fixturenames_closure , arg2fixturedefs = fm .getfixtureclosure ([val .name ], current_node )
115+
116+ extra_fixture_params = [(fname , arg2fixturedefs [fname ][0 ].params )
117+ for fname in fixturenames_closure if fname not in callspec .params
118+ if arg2fixturedefs .get (fname ) and arg2fixturedefs [fname ][0 ].params ]
119+
120+ if extra_fixture_params :
121+ newcallspecs = [callspec ]
122+ for fname , fparams in extra_fixture_params :
123+ newcallspecs = parametrize_callspecs (newcallspecs , metafunc , fname , fparams )
124+ newcalls = []
125+ for newcallspec in newcallspecs :
103126 calls = normalize_call (newcallspec , metafunc , valtype , used_keys | set ([arg ]))
104127 newcalls .extend (calls )
105128 return newcalls
@@ -151,14 +174,6 @@ def _tree_to_list(trees, leave):
151174 return lst
152175
153176
154- def get_nodeid (module , rootdir ):
155- path = py .path .local (module .__file__ )
156- relpath = path .relto (rootdir )
157- if os .sep != "/" :
158- relpath = relpath .replace (os .sep , "/" )
159- return relpath
160-
161-
162177def lazy_fixture (names ):
163178 if isinstance (names , string_type ):
164179 return LazyFixture (names )
0 commit comments