1
1
""" Python test discovery, setup and run of test functions. """
2
- import collections
3
2
import enum
4
3
import fnmatch
5
4
import inspect
6
5
import os
7
6
import sys
8
7
import warnings
8
+ from collections import Counter
9
+ from collections .abc import Sequence
9
10
from functools import partial
10
11
from textwrap import dedent
11
12
@@ -240,9 +241,6 @@ class PyobjContext:
240
241
class PyobjMixin (PyobjContext ):
241
242
_ALLOW_MARKERS = True
242
243
243
- def __init__ (self , * k , ** kw ):
244
- super ().__init__ (* k , ** kw )
245
-
246
244
@property
247
245
def obj (self ):
248
246
"""Underlying Python object."""
@@ -394,12 +392,8 @@ def _genfunctions(self, name, funcobj):
394
392
methods .append (module .pytest_generate_tests )
395
393
if hasattr (cls , "pytest_generate_tests" ):
396
394
methods .append (cls ().pytest_generate_tests )
397
- if methods :
398
- self .ihook .pytest_generate_tests .call_extra (
399
- methods , dict (metafunc = metafunc )
400
- )
401
- else :
402
- self .ihook .pytest_generate_tests (metafunc = metafunc )
395
+
396
+ self .ihook .pytest_generate_tests .call_extra (methods , dict (metafunc = metafunc ))
403
397
404
398
if not metafunc ._calls :
405
399
yield Function (name , parent = self , fixtureinfo = fixtureinfo )
@@ -444,13 +438,12 @@ def _inject_setup_module_fixture(self):
444
438
Using a fixture to invoke this methods ensures we play nicely and unsurprisingly with
445
439
other fixtures (#517).
446
440
"""
447
- setup_module = _get_non_fixture_func (self .obj , "setUpModule" )
448
- if setup_module is None :
449
- setup_module = _get_non_fixture_func (self .obj , "setup_module" )
450
-
451
- teardown_module = _get_non_fixture_func (self .obj , "tearDownModule" )
452
- if teardown_module is None :
453
- teardown_module = _get_non_fixture_func (self .obj , "teardown_module" )
441
+ setup_module = _get_first_non_fixture_func (
442
+ self .obj , ("setUpModule" , "setup_module" )
443
+ )
444
+ teardown_module = _get_first_non_fixture_func (
445
+ self .obj , ("tearDownModule" , "teardown_module" )
446
+ )
454
447
455
448
if setup_module is None and teardown_module is None :
456
449
return
@@ -472,8 +465,10 @@ def _inject_setup_function_fixture(self):
472
465
Using a fixture to invoke this methods ensures we play nicely and unsurprisingly with
473
466
other fixtures (#517).
474
467
"""
475
- setup_function = _get_non_fixture_func (self .obj , "setup_function" )
476
- teardown_function = _get_non_fixture_func (self .obj , "teardown_function" )
468
+ setup_function = _get_first_non_fixture_func (self .obj , ("setup_function" ,))
469
+ teardown_function = _get_first_non_fixture_func (
470
+ self .obj , ("teardown_function" ,)
471
+ )
477
472
if setup_function is None and teardown_function is None :
478
473
return
479
474
@@ -557,15 +552,15 @@ def __init__(self, fspath, parent=None, config=None, session=None, nodeid=None):
557
552
def setup (self ):
558
553
# not using fixtures to call setup_module here because autouse fixtures
559
554
# from packages are not called automatically (#4085)
560
- setup_module = _get_non_fixture_func ( self . obj , "setUpModule" )
561
- if setup_module is None :
562
- setup_module = _get_non_fixture_func ( self . obj , "setup_module" )
555
+ setup_module = _get_first_non_fixture_func (
556
+ self . obj , ( "setUpModule" , "setup_module" )
557
+ )
563
558
if setup_module is not None :
564
559
_call_with_optional_argument (setup_module , self .obj )
565
560
566
- teardown_module = _get_non_fixture_func ( self . obj , "tearDownModule" )
567
- if teardown_module is None :
568
- teardown_module = _get_non_fixture_func ( self . obj , "teardown_module" )
561
+ teardown_module = _get_first_non_fixture_func (
562
+ self . obj , ( "tearDownModule" , "teardown_module" )
563
+ )
569
564
if teardown_module is not None :
570
565
func = partial (_call_with_optional_argument , teardown_module , self .obj )
571
566
self .addfinalizer (func )
@@ -656,27 +651,6 @@ def collect(self):
656
651
pkg_prefixes .add (path )
657
652
658
653
659
- def _get_xunit_setup_teardown (holder , attr_name , param_obj = None ):
660
- """
661
- Return a callable to perform xunit-style setup or teardown if
662
- the function exists in the ``holder`` object.
663
- The ``param_obj`` parameter is the parameter which will be passed to the function
664
- when the callable is called without arguments, defaults to the ``holder`` object.
665
- Return ``None`` if a suitable callable is not found.
666
- """
667
- # TODO: only needed because of Package!
668
- param_obj = param_obj if param_obj is not None else holder
669
- result = _get_non_fixture_func (holder , attr_name )
670
- if result is not None :
671
- arg_count = result .__code__ .co_argcount
672
- if inspect .ismethod (result ):
673
- arg_count -= 1
674
- if arg_count :
675
- return lambda : result (param_obj )
676
- else :
677
- return result
678
-
679
-
680
654
def _call_with_optional_argument (func , arg ):
681
655
"""Call the given function with the given argument if func accepts one argument, otherwise
682
656
calls func without arguments"""
@@ -689,14 +663,15 @@ def _call_with_optional_argument(func, arg):
689
663
func ()
690
664
691
665
692
- def _get_non_fixture_func (obj , name ):
666
+ def _get_first_non_fixture_func (obj , names ):
693
667
"""Return the attribute from the given object to be used as a setup/teardown
694
668
xunit-style function, but only if not marked as a fixture to
695
669
avoid calling it twice.
696
670
"""
697
- meth = getattr (obj , name , None )
698
- if fixtures .getfixturemarker (meth ) is None :
699
- return meth
671
+ for name in names :
672
+ meth = getattr (obj , name , None )
673
+ if meth is not None and fixtures .getfixturemarker (meth ) is None :
674
+ return meth
700
675
701
676
702
677
class Class (PyCollector ):
@@ -736,7 +711,7 @@ def _inject_setup_class_fixture(self):
736
711
Using a fixture to invoke this methods ensures we play nicely and unsurprisingly with
737
712
other fixtures (#517).
738
713
"""
739
- setup_class = _get_non_fixture_func (self .obj , "setup_class" )
714
+ setup_class = _get_first_non_fixture_func (self .obj , ( "setup_class" ,) )
740
715
teardown_class = getattr (self .obj , "teardown_class" , None )
741
716
if setup_class is None and teardown_class is None :
742
717
return
@@ -760,7 +735,7 @@ def _inject_setup_method_fixture(self):
760
735
Using a fixture to invoke this methods ensures we play nicely and unsurprisingly with
761
736
other fixtures (#517).
762
737
"""
763
- setup_method = _get_non_fixture_func (self .obj , "setup_method" )
738
+ setup_method = _get_first_non_fixture_func (self .obj , ( "setup_method" ,) )
764
739
teardown_method = getattr (self .obj , "teardown_method" , None )
765
740
if setup_method is None and teardown_method is None :
766
741
return
@@ -1070,12 +1045,9 @@ def _resolve_arg_value_types(self, argnames, indirect):
1070
1045
* "params" if the argname should be the parameter of a fixture of the same name.
1071
1046
* "funcargs" if the argname should be a parameter to the parametrized test function.
1072
1047
"""
1073
- valtypes = {}
1074
- if indirect is True :
1075
- valtypes = dict .fromkeys (argnames , "params" )
1076
- elif indirect is False :
1077
- valtypes = dict .fromkeys (argnames , "funcargs" )
1078
- elif isinstance (indirect , (tuple , list )):
1048
+ if isinstance (indirect , bool ):
1049
+ valtypes = dict .fromkeys (argnames , "params" if indirect else "funcargs" )
1050
+ elif isinstance (indirect , Sequence ):
1079
1051
valtypes = dict .fromkeys (argnames , "funcargs" )
1080
1052
for arg in indirect :
1081
1053
if arg not in argnames :
@@ -1086,6 +1058,13 @@ def _resolve_arg_value_types(self, argnames, indirect):
1086
1058
pytrace = False ,
1087
1059
)
1088
1060
valtypes [arg ] = "params"
1061
+ else :
1062
+ fail (
1063
+ "In {func}: expected Sequence or boolean for indirect, got {type}" .format (
1064
+ type = type (indirect ).__name__ , func = self .function .__name__
1065
+ ),
1066
+ pytrace = False ,
1067
+ )
1089
1068
return valtypes
1090
1069
1091
1070
def _validate_if_using_arg_names (self , argnames , indirect ):
@@ -1213,7 +1192,7 @@ def idmaker(argnames, parametersets, idfn=None, ids=None, config=None, item=None
1213
1192
if len (set (ids )) != len (ids ):
1214
1193
# The ids are not unique
1215
1194
duplicates = [testid for testid in ids if ids .count (testid ) > 1 ]
1216
- counters = collections . defaultdict ( lambda : 0 )
1195
+ counters = Counter ( )
1217
1196
for index , testid in enumerate (ids ):
1218
1197
if testid in duplicates :
1219
1198
ids [index ] = testid + str (counters [testid ])
@@ -1402,14 +1381,11 @@ def __init__(
1402
1381
# https://github.com/pytest-dev/pytest/issues/4569
1403
1382
1404
1383
self .keywords .update (
1405
- dict .fromkeys (
1406
- [
1407
- mark .name
1408
- for mark in self .iter_markers ()
1409
- if mark .name not in self .keywords
1410
- ],
1411
- True ,
1412
- )
1384
+ {
1385
+ mark .name : True
1386
+ for mark in self .iter_markers ()
1387
+ if mark .name not in self .keywords
1388
+ }
1413
1389
)
1414
1390
1415
1391
if fixtureinfo is None :
0 commit comments