@@ -302,6 +302,9 @@ def is_resource_enabled(resource):
302302
303303def requires (resource , msg = None ):
304304 """Raise ResourceDenied if the specified resource is not available."""
305+ f = sys ._getframe (1 )
306+ if f .f_globals is f .f_locals :
307+ mark (f'requires_{ resource } ' , globals = f .f_globals )
305308 if not is_resource_enabled (resource ):
306309 if msg is None :
307310 msg = "Use of the %r resource not enabled" % resource
@@ -536,22 +539,27 @@ def requires_fork():
536539
537540def requires_subprocess ():
538541 """Used for subprocess, os.spawn calls, fd inheritance"""
539- return skipUnless (has_subprocess_support , "requires subprocess support" , label = 'requires_subprocess' )
542+ return skipUnless (has_subprocess_support , "requires subprocess support" ,
543+ label = 'requires_subprocess' )
540544
541545# Emscripten's socket emulation and WASI sockets have limitations.
542546has_socket_support = not is_emscripten and not is_wasi
543547
544- def requires_working_socket (* , module = False ):
548+ def requires_working_socket (* , module = False , globals = None ):
545549 """Skip tests or modules that require working sockets
546550
547551 Can be used as a function/class decorator or to skip an entire module.
548552 """
553+ label = 'requires_socket'
549554 msg = "requires socket support"
550- if module :
555+ if module or globals is not None :
556+ if globals is None :
557+ globals = sys ._getframe (1 ).f_globals
558+ mark (label , globals = globals )
551559 if not has_socket_support :
552560 raise unittest .SkipTest (msg )
553561 else :
554- return skipUnless (has_socket_support , msg , label = 'requires_socket' )
562+ return skipUnless (has_socket_support , msg , label = label )
555563
556564# Does strftime() support glibc extension like '%4Y'?
557565has_strftime_extensions = False
@@ -1008,9 +1016,18 @@ def wrapper(self):
10081016#=======================================================================
10091017# unittest integration.
10101018
1011- def mark (label ):
1019+ def mark (label , * , globals = None ):
1020+ """Add a label to test.
1021+
1022+ To add a label to method or class, use it as a decorator.
1023+
1024+ To add a label to module, pass the globals() dict as the globals argument.
1025+ """
1026+ if globals is not None :
1027+ globals [f'_label_{ label } ' ] = True
1028+ return
10121029 def decorator (test ):
1013- setattr (test , label , True )
1030+ setattr (test , f'_label_ { label } ' , True )
10141031 return test
10151032 return decorator
10161033
@@ -1028,11 +1045,12 @@ def skipIf(condition, reason, *, label):
10281045 return combine (unittest .skipIf (condition , reason ), mark (label ))
10291046
10301047def requires_resource (resource ):
1048+ label = 'requires_' + resource
10311049 if resource == 'gui' and not _is_gui_available ():
1032- return skipUnless (False , _is_gui_available .reason , label = 'requires_gui' )
1050+ return skipUnless (False , _is_gui_available .reason , label = label )
10331051 return skipUnless (is_resource_enabled (resource ),
10341052 f"resource { resource !r} is not enabled" ,
1035- label = 'requires_' + resource )
1053+ label = label )
10361054
10371055def cpython_only (test ):
10381056 """
@@ -1218,7 +1236,7 @@ def match_function(test_id):
12181236
12191237def _check_obj_labels (obj , labels ):
12201238 for label in labels :
1221- if hasattr (obj , label ):
1239+ if hasattr (obj , f'_label_ { label } ' ):
12221240 return True
12231241 return False
12241242
@@ -1230,6 +1248,12 @@ def _check_test_labels(test, labels):
12301248 if _check_obj_labels (testMethod , labels ):
12311249 return True
12321250 testMethod = getattr (testMethod , '__wrapped__' , None )
1251+ try :
1252+ module = sys .modules [test .__class__ .__module__ ]
1253+ if _check_obj_labels (module , labels ):
1254+ return True
1255+ except KeyError :
1256+ pass
12331257 return False
12341258
12351259def set_match_tests2 (accept_labels = None , ignore_labels = None ):
0 commit comments