5
5
# Use true division operator always even in old python 2.x (used in `_extract_cases_from_module`)
6
6
from __future__ import division
7
7
8
- from functools import partial
8
+ import functools
9
9
from importlib import import_module
10
10
from inspect import getmembers , isfunction , ismethod
11
11
import re
12
12
from warnings import warn
13
13
14
- import makefun
15
-
16
14
try :
17
15
from typing import Union , Callable , Iterable , Any , Type , List , Tuple # noqa
18
16
except ImportError :
19
17
pass
20
18
21
19
from .common_mini_six import string_types
22
- from .common_others import get_code_first_line , AUTO , AUTO2 , qname
23
- from .common_pytest_marks import copy_pytest_marks , make_marked_parameter_value
20
+ from .common_others import get_code_first_line , AUTO , AUTO2 , qname , funcopy
21
+ from .common_pytest_marks import copy_pytest_marks , make_marked_parameter_value , remove_pytest_mark
24
22
from .common_pytest_lazy_values import lazy_value
25
- from .common_pytest import safe_isclass , MiniMetafunc , is_fixture , get_fixture_name , inject_host
23
+ from .common_pytest import safe_isclass , MiniMetafunc , is_fixture , get_fixture_name , inject_host , add_fixture_params
26
24
27
25
from . import fixture
28
26
from .case_funcs_new import matches_tag_query , is_case_function , is_case_class , CaseInfo , CASE_PREFIX_FUN
@@ -305,19 +303,26 @@ def case_to_argvalues(host_class_or_module, # type: Union[Type, ModuleType]
305
303
if not meta .is_parametrized :
306
304
# single unparametrized case function
307
305
if debug :
308
- case_fun_str = qname (case_fun .func if isinstance (case_fun , partial ) else case_fun )
306
+ case_fun_str = qname (case_fun .func if isinstance (case_fun , functools . partial ) else case_fun )
309
307
print ("Case function %s > 1 lazy_value() with id %s and marks %s" % (case_fun_str , case_id , case_marks ))
310
308
return (lazy_value (case_fun , id = case_id , marks = case_marks ),)
311
309
else :
312
310
# parametrized. create one version of the callable for each parametrized call
313
311
if debug :
314
- case_fun_str = qname (case_fun .func if isinstance (case_fun , partial ) else case_fun )
312
+ case_fun_str = qname (case_fun .func if isinstance (case_fun , functools . partial ) else case_fun )
315
313
print ("Case function %s > tuple of lazy_value() with ids %s and marks %s"
316
314
% (case_fun_str , ["%s-%s" % (case_id , c .id ) for c in meta ._calls ], [c .marks for c in meta ._calls ]))
317
- return tuple (lazy_value (partial (case_fun , ** c .funcargs ), id = "%s-%s" % (case_id , c .id ), marks = c .marks )
315
+ return tuple (lazy_value (functools .partial (case_fun , ** c .funcargs ),
316
+ id = "%s-%s" % (case_id , c .id ), marks = c .marks )
318
317
for c in meta ._calls )
319
318
else :
320
- # at least a required fixture:
319
+ # at least a required fixture (direct req or through @pytest.mark.usefixtures ):
320
+ # handle @pytest.mark.usefixtures by creating a wrapper where the fixture is added to the signature
321
+ if meta .fixturenames_not_in_sig :
322
+ # create a wrapper with an explicit requirement for the fixtures
323
+ case_fun = add_fixture_params (case_fun , meta .fixturenames_not_in_sig )
324
+ # remove the `usefixtures` mark
325
+ remove_pytest_mark (case_fun , "usefixtures" )
321
326
# create or reuse a fixture in the host (pytest collector: module or class) of the parametrization target
322
327
fix_name = get_or_create_case_fixture (case_id , case_fun , host_class_or_module , debug )
323
328
@@ -327,7 +332,7 @@ def case_to_argvalues(host_class_or_module, # type: Union[Type, ModuleType]
327
332
# reference that case fixture
328
333
argvalues_tuple = (fixture_ref (fix_name ),)
329
334
if debug :
330
- case_fun_str = qname (case_fun .func if isinstance (case_fun , partial ) else case_fun )
335
+ case_fun_str = qname (case_fun .func if isinstance (case_fun , functools . partial ) else case_fun )
331
336
print ("Case function %s > fixture_ref(%r) with marks %s" % (case_fun_str , fix_name , case_marks ))
332
337
return make_marked_parameter_value (argvalues_tuple , marks = case_marks ) if case_marks else argvalues_tuple
333
338
@@ -358,8 +363,8 @@ def get_or_create_case_fixture(case_id, # type: str
358
363
" %s. If you did not decorate it but still see this error, please report this issue"
359
364
% case_fun )
360
365
361
- # source
362
- case_in_class = isinstance (case_fun , partial ) and hasattr (case_fun , 'host_class' )
366
+ # source: detect a functools.partial wrapper created by us because of a host class
367
+ case_in_class = isinstance (case_fun , functools . partial ) and hasattr (case_fun , 'host_class' )
363
368
true_case_func = case_fun .func if case_in_class else case_fun
364
369
# case_host = case_fun.host_class if case_in_class else import_module(case_fun.__module__)
365
370
@@ -397,11 +402,6 @@ def name_changer(name, i):
397
402
if debug :
398
403
print ("Case function %s > Creating fixture %r in %s" % (qname (true_case_func ), fix_name , target_host ))
399
404
400
- def funcopy (f ):
401
- # apparently it is not possible to create an actual copy with copy() !
402
- # Use makefun.partial which preserves the parametrization marks (we need them)
403
- return makefun .partial (f )
404
-
405
405
if case_in_class :
406
406
if target_in_class :
407
407
# both in class: direct copy of the non-partialized version
@@ -614,7 +614,7 @@ def _of_interest(x): # noqa
614
614
# skip it
615
615
continue
616
616
# partialize the function to get one without the 'self' argument
617
- new_m = partial (m , cls ())
617
+ new_m = functools . partial (m , cls ())
618
618
# remember the class
619
619
new_m .host_class = cls
620
620
# we have to recopy all metadata concerning the case function
0 commit comments