@@ -468,28 +468,28 @@ def requires_zlib(reason='requires zlib'):
468468 import zlib
469469 except ImportError :
470470 zlib = None
471- return unittest . skipUnless (zlib , reason )
471+ return skipUnless (zlib , reason , label = 'requires_zlib' )
472472
473473def requires_gzip (reason = 'requires gzip' ):
474474 try :
475475 import gzip
476476 except ImportError :
477477 gzip = None
478- return unittest . skipUnless (gzip , reason )
478+ return skipUnless (gzip , reason , label = 'requires_gzip' )
479479
480480def requires_bz2 (reason = 'requires bz2' ):
481481 try :
482482 import bz2
483483 except ImportError :
484484 bz2 = None
485- return unittest . skipUnless (bz2 , reason )
485+ return skipUnless (bz2 , reason , label = 'requires_bz2' )
486486
487487def requires_lzma (reason = 'requires lzma' ):
488488 try :
489489 import lzma
490490 except ImportError :
491491 lzma = None
492- return unittest . skipUnless (lzma , reason )
492+ return skipUnless (lzma , reason , label = 'requires_lzma' )
493493
494494def has_no_debug_ranges ():
495495 try :
@@ -500,16 +500,17 @@ def has_no_debug_ranges():
500500 return not bool (config ['code_debug_ranges' ])
501501
502502def requires_debug_ranges (reason = 'requires co_positions / debug_ranges' ):
503- return unittest . skipIf (has_no_debug_ranges (), reason )
503+ return skipIf (has_no_debug_ranges (), reason , label = 'requires_debug_ranges' )
504504
505505def requires_legacy_unicode_capi ():
506506 try :
507507 from _testcapi import unicode_legacy_string
508508 except ImportError :
509509 unicode_legacy_string = None
510510
511- return unittest .skipUnless (unicode_legacy_string ,
512- 'requires legacy Unicode C API' )
511+ return skipUnless (unicode_legacy_string ,
512+ 'requires legacy Unicode C API' ,
513+ label = 'requires_legacy_unicode_capi' )
513514
514515# Is not actually used in tests, but is kept for compatibility.
515516is_jython = sys .platform .startswith ('java' )
@@ -529,13 +530,13 @@ def requires_legacy_unicode_capi():
529530has_fork_support = hasattr (os , "fork" ) and not is_emscripten and not is_wasi
530531
531532def requires_fork ():
532- return unittest . skipUnless (has_fork_support , "requires working os.fork()" )
533+ return skipUnless (has_fork_support , "requires working os.fork()" , label = 'requires_fork' )
533534
534535has_subprocess_support = not is_emscripten and not is_wasi
535536
536537def requires_subprocess ():
537538 """Used for subprocess, os.spawn calls, fd inheritance"""
538- return unittest . skipUnless (has_subprocess_support , "requires subprocess support" )
539+ return skipUnless (has_subprocess_support , "requires subprocess support" , label = 'requires_subprocess' )
539540
540541# Emscripten's socket emulation and WASI sockets have limitations.
541542has_socket_support = not is_emscripten and not is_wasi
@@ -550,7 +551,7 @@ def requires_working_socket(*, module=False):
550551 if not has_socket_support :
551552 raise unittest .SkipTest (msg )
552553 else :
553- return unittest . skipUnless (has_socket_support , msg )
554+ return skipUnless (has_socket_support , msg , label = 'requires_socket' )
554555
555556# Does strftime() support glibc extension like '%4Y'?
556557has_strftime_extensions = False
@@ -951,6 +952,8 @@ def bigmemtest(size, memuse, dry_run=True):
951952 test doesn't support dummy runs when -M is not specified.
952953 """
953954 def decorator (f ):
955+ @mark ('bigmemtest' )
956+ @functools .wraps (f )
954957 def wrapper (self ):
955958 size = wrapper .size
956959 memuse = wrapper .memuse
@@ -987,6 +990,8 @@ def wrapper(self):
987990
988991def bigaddrspacetest (f ):
989992 """Decorator for tests that fill the address space."""
993+ @mark ('bigaddrspacetest' )
994+ @functools .wraps (f )
990995 def wrapper (self ):
991996 if max_memuse < MAX_Py_ssize_t :
992997 if MAX_Py_ssize_t >= 2 ** 63 - 1 and max_memuse >= 2 ** 31 :
@@ -1003,16 +1008,31 @@ def wrapper(self):
10031008#=======================================================================
10041009# unittest integration.
10051010
1006- def _id (obj ):
1007- return obj
1011+ def mark (label ):
1012+ def decorator (test ):
1013+ setattr (test , label , True )
1014+ return test
1015+ return decorator
1016+
1017+ def combine (* decorators ):
1018+ def decorator (test ):
1019+ for deco in reversed (decorators ):
1020+ test = deco (test )
1021+ return test
1022+ return decorator
1023+
1024+ def skipUnless (condition , reason , * , label ):
1025+ return combine (unittest .skipUnless (condition , reason ), mark (label ))
1026+
1027+ def skipIf (condition , reason , * , label ):
1028+ return combine (unittest .skipIf (condition , reason ), mark (label ))
10081029
10091030def requires_resource (resource ):
10101031 if resource == 'gui' and not _is_gui_available ():
1011- return unittest .skip (_is_gui_available .reason )
1012- if is_resource_enabled (resource ):
1013- return _id
1014- else :
1015- return unittest .skip ("resource {0!r} is not enabled" .format (resource ))
1032+ return skipUnless (False , _is_gui_available .reason , label = 'requires_gui' )
1033+ return skipUnless (is_resource_enabled (resource ),
1034+ f"resource { resource !r} is not enabled" ,
1035+ label = 'requires_' + resource )
10161036
10171037def cpython_only (test ):
10181038 """
@@ -1021,8 +1041,16 @@ def cpython_only(test):
10211041 return impl_detail (cpython = True )(test )
10221042
10231043def impl_detail (msg = None , ** guards ):
1044+ guards , _ = _parse_guards (guards )
1045+ decorators = []
1046+ for name in reversed (guards ):
1047+ if guards [name ]:
1048+ label = f'impl_detail_{ name } '
1049+ else :
1050+ label = f'impl_detail_no_{ name } '
1051+ decorators .append (mark (label ))
10241052 if check_impl_detail (** guards ):
1025- return _id
1053+ return combine ( * decorators )
10261054 if msg is None :
10271055 guardnames , default = _parse_guards (guards )
10281056 if default :
@@ -1031,7 +1059,7 @@ def impl_detail(msg=None, **guards):
10311059 msg = "implementation detail specific to {0}"
10321060 guardnames = sorted (guardnames .keys ())
10331061 msg = msg .format (' or ' .join (guardnames ))
1034- return unittest .skip (msg )
1062+ return combine ( unittest .skip (msg ), * decorators )
10351063
10361064def _parse_guards (guards ):
10371065 # Returns a tuple ({platform_name: run_me}, default_value)
@@ -1133,17 +1161,16 @@ def _run_suite(suite):
11331161
11341162# By default, don't filter tests
11351163_match_test_func = None
1164+ _match_test_func2 = None
11361165
11371166_accept_test_patterns = None
11381167_ignore_test_patterns = None
11391168
11401169
11411170def match_test (test ):
11421171 # Function used by support.run_unittest() and regrtest --list-cases
1143- if _match_test_func is None :
1144- return True
1145- else :
1146- return _match_test_func (test .id ())
1172+ return ((_match_test_func is None or _match_test_func (test .id ())) and
1173+ (_match_test_func2 is None or _match_test_func2 (test )))
11471174
11481175
11491176def _is_full_match_test (pattern ):
@@ -1189,6 +1216,45 @@ def match_function(test_id):
11891216 _match_test_func = match_function
11901217
11911218
1219+ def _check_obj_labels (obj , labels ):
1220+ for label in labels :
1221+ if hasattr (obj , label ):
1222+ return True
1223+ return False
1224+
1225+ def _check_test_labels (test , labels ):
1226+ if _check_obj_labels (test , labels ):
1227+ return True
1228+ testMethod = getattr (test , test ._testMethodName )
1229+ while testMethod is not None :
1230+ if _check_obj_labels (testMethod , labels ):
1231+ return True
1232+ testMethod = getattr (testMethod , '__wrapped__' , None )
1233+ return False
1234+
1235+ def set_match_tests2 (accept_labels = None , ignore_labels = None ):
1236+ global _match_test_func2
1237+
1238+ if accept_labels is None :
1239+ accept_labels = ()
1240+ if ignore_labels is None :
1241+ ignore_labels = ()
1242+ # Create a copy since label lists can be mutable and so modified later
1243+ accept_labels = tuple (accept_labels )
1244+ ignore_labels = tuple (ignore_labels )
1245+
1246+ def match_function (test ):
1247+ accept = True
1248+ ignore = False
1249+ if accept_labels :
1250+ accept = _check_test_labels (test , accept_labels )
1251+ if ignore_labels :
1252+ ignore = _check_test_labels (test , ignore_labels )
1253+ return accept and not ignore
1254+
1255+ _match_test_func2 = match_function
1256+
1257+
11921258def _compile_match_function (patterns ):
11931259 if not patterns :
11941260 func = None
0 commit comments