1919 class SkipTest (Exception ):
2020 pass
2121
22+ try :
23+ import pytest
24+ except ImportError :
25+ pytest = None
26+
2227PY3 = sys .version_info [0 ] == 3
2328PY2 = sys .version_info [0 ] == 2
2429
@@ -352,6 +357,94 @@ def __init__(self, input, doc_func=None, skip_on_empty=False):
352357 def __call__ (self , test_func ):
353358 self .assert_not_in_testcase_subclass ()
354359
360+ input = self .get_input ()
361+ wrapper = self ._wrap_test_func (test_func , input )
362+ wrapper .parameterized_input = input
363+ wrapper .parameterized_func = test_func
364+ test_func .__name__ = "_parameterized_original_%s" % (test_func .__name__ , )
365+
366+ return wrapper
367+
368+ def _wrap_test_func (self , test_func , input ):
369+ """ Wraps a test function so that it will appropriately handle
370+ parameterization.
371+
372+ In the general case, the wrapper will enumerate the input, yielding
373+ test cases.
374+
375+ In the case of pytest4, the wrapper will use
376+ ``@pytest.mark.parametrize`` to parameterize the test function. """
377+
378+ if not input :
379+ if not self .skip_on_empty :
380+ raise ValueError (
381+ "Parameters iterable is empty (hint: use "
382+ "`parameterized([], skip_on_empty=True)` to skip "
383+ "this test when the input is empty)"
384+ )
385+ return wraps (test_func )(skip_on_empty_helper )
386+
387+ if pytest and pytest .__version__ > '4.0.0' :
388+ Undefined = object ()
389+ test_func_wrapped = test_func
390+ test_func_real , mock_patchings = unwrap_mock_patch_func (test_func_wrapped )
391+ func_argspec = getargspec (test_func_real )
392+
393+ func_args = func_argspec .args
394+ if mock_patchings :
395+ func_args = func_args [:- len (mock_patchings )]
396+
397+ func_args_no_self = func_args
398+ if func_args_no_self [:1 ] == ["self" ]:
399+ func_args_no_self = func_args_no_self [1 :]
400+
401+ args_with_default = dict (
402+ (arg , Undefined )
403+ for arg in func_args_no_self
404+ )
405+ for (arg , default ) in zip (reversed (func_args_no_self ), reversed (func_argspec .defaults or [])):
406+ args_with_default [arg ] = default
407+
408+ pytest_params = []
409+ for i in input :
410+ p = dict (args_with_default )
411+ for (arg , val ) in zip (func_args_no_self , i .args ):
412+ p [arg ] = val
413+ p .update (i .kwargs )
414+
415+ # Sanity check: all arguments should now be defined
416+ if any (v is Undefined for v in p .values ()):
417+ raise ValueError (
418+ "When parameterizing function %r: no value for arguments: %s" % (
419+ test_func ,
420+ ", " .join (
421+ repr (arg )
422+ for (arg , val ) in p .items ()
423+ if val is Undefined
424+ ),
425+ )
426+ )
427+
428+ pytest_params .append (pytest .param (* [
429+ p .get (arg ) for arg in func_args_no_self
430+ ]))
431+
432+ namespace = {
433+ "__test_func" : test_func_wrapped ,
434+ }
435+ wrapper_name = "parameterized_pytest_wrapper_%s" % (test_func .__name__ , )
436+ exec (
437+ "def %s(%s): return __test_func(%s)" % (
438+ wrapper_name ,
439+ "," .join (func_args ),
440+ "," .join (func_args ),
441+ ),
442+ namespace ,
443+ namespace ,
444+ )
445+
446+ return pytest .mark .parametrize ("," .join (func_args_no_self ), pytest_params )(namespace [wrapper_name ])
447+
355448 @wraps (test_func )
356449 def wrapper (test_self = None ):
357450 test_cls = test_self and type (test_self )
@@ -366,7 +459,7 @@ def wrapper(test_self=None):
366459 ) % (test_self , ))
367460
368461 original_doc = wrapper .__doc__
369- for num , args in enumerate (wrapper . parameterized_input ):
462+ for num , args in enumerate (input ):
370463 p = param .from_decorator (args )
371464 unbound_func , nose_tuple = self .param_as_nose_tuple (test_self , test_func , num , p )
372465 try :
@@ -383,21 +476,6 @@ def wrapper(test_self=None):
383476 if test_self is not None :
384477 delattr (test_cls , test_func .__name__ )
385478 wrapper .__doc__ = original_doc
386-
387- input = self .get_input ()
388- if not input :
389- if not self .skip_on_empty :
390- raise ValueError (
391- "Parameters iterable is empty (hint: use "
392- "`parameterized([], skip_on_empty=True)` to skip "
393- "this test when the input is empty)"
394- )
395- wrapper = wraps (test_func )(skip_on_empty_helper )
396-
397- wrapper .parameterized_input = input
398- wrapper .parameterized_func = test_func
399- test_func .__name__ = "_parameterized_original_%s" % (test_func .__name__ , )
400-
401479 return wrapper
402480
403481 def param_as_nose_tuple (self , test_self , func , num , p ):
@@ -618,6 +696,11 @@ def decorator(base_class):
618696
619697 return decorator
620698
699+ def unwrap_mock_patch_func (f ):
700+ if not hasattr (f , "patchings" ):
701+ return (f , [])
702+ real_func , patchings = unwrap_mock_patch_func (f .__wrapped__ )
703+ return (real_func , patchings + f .patchings )
621704
622705def get_class_name_suffix (params_dict ):
623706 if "name" in params_dict :
0 commit comments