55# Use true division operator always even in old python 2.x (used in `_extract_cases_from_module`)
66from __future__ import division
77
8- from functools import partial
8+ import functools
99from importlib import import_module
1010from inspect import getmembers , isfunction , ismethod
1111import re
1212from warnings import warn
1313
14- import makefun
15-
1614try :
1715 from typing import Union , Callable , Iterable , Any , Type , List , Tuple # noqa
1816except ImportError :
1917 pass
2018
2119from .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
2422from .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
2624
2725from . import fixture
2826from .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]
305303 if not meta .is_parametrized :
306304 # single unparametrized case function
307305 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 )
309307 print ("Case function %s > 1 lazy_value() with id %s and marks %s" % (case_fun_str , case_id , case_marks ))
310308 return (lazy_value (case_fun , id = case_id , marks = case_marks ),)
311309 else :
312310 # parametrized. create one version of the callable for each parametrized call
313311 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 )
315313 print ("Case function %s > tuple of lazy_value() with ids %s and marks %s"
316314 % (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 )
318317 for c in meta ._calls )
319318 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" )
321326 # create or reuse a fixture in the host (pytest collector: module or class) of the parametrization target
322327 fix_name = get_or_create_case_fixture (case_id , case_fun , host_class_or_module , debug )
323328
@@ -327,7 +332,7 @@ def case_to_argvalues(host_class_or_module, # type: Union[Type, ModuleType]
327332 # reference that case fixture
328333 argvalues_tuple = (fixture_ref (fix_name ),)
329334 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 )
331336 print ("Case function %s > fixture_ref(%r) with marks %s" % (case_fun_str , fix_name , case_marks ))
332337 return make_marked_parameter_value (argvalues_tuple , marks = case_marks ) if case_marks else argvalues_tuple
333338
@@ -358,8 +363,8 @@ def get_or_create_case_fixture(case_id, # type: str
358363 " %s. If you did not decorate it but still see this error, please report this issue"
359364 % case_fun )
360365
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' )
363368 true_case_func = case_fun .func if case_in_class else case_fun
364369 # case_host = case_fun.host_class if case_in_class else import_module(case_fun.__module__)
365370
@@ -397,11 +402,6 @@ def name_changer(name, i):
397402 if debug :
398403 print ("Case function %s > Creating fixture %r in %s" % (qname (true_case_func ), fix_name , target_host ))
399404
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-
405405 if case_in_class :
406406 if target_in_class :
407407 # both in class: direct copy of the non-partialized version
@@ -614,7 +614,7 @@ def _of_interest(x): # noqa
614614 # skip it
615615 continue
616616 # partialize the function to get one without the 'self' argument
617- new_m = partial (m , cls ())
617+ new_m = functools . partial (m , cls ())
618618 # remember the class
619619 new_m .host_class = cls
620620 # we have to recopy all metadata concerning the case function
0 commit comments