@@ -394,19 +394,87 @@ def dont_skip_any_doctests(app, what, name, obj, skip, options):
394
394
395
395
autodoc_default_options = {'special-members' : None , 'private-members' : None }
396
396
397
+ # doctest optionflags for platform-specific tests
398
+ # they are skipped on other platforms
399
+ WINDOWS = doctest .register_optionflag ('WINDOWS' )
400
+ LINUX = doctest .register_optionflag ('LINUX' )
401
+ POSIX = doctest .register_optionflag ('POSIX' )
402
+
403
+ # doctest optionflag for tests that haven't been looked at yet
404
+ TODO = doctest .register_optionflag ('TODO' )
405
+
406
+ import sphinx .ext .doctest
407
+
408
+ class PlatformDocTestRunner (sphinx .ext .doctest .SphinxDocTestRunner ):
409
+ def run (self , test , compileflags = None , out = None , clear_globs = True ):
410
+ original_optionflags = self .optionflags | test .globs .get ('doctest_additional_flags' , 0 )
411
+ def filter_platform (example ):
412
+ optionflags = original_optionflags
413
+ if example .options :
414
+ for (optionflag , val ) in example .options .items ():
415
+ if val :
416
+ optionflags |= optionflag
417
+ else :
418
+ optionflags &= ~ optionflag
419
+
420
+ if (optionflags & WINDOWS ) == WINDOWS and sys .platform != 'win32' :
421
+ return False
422
+ if (optionflags & LINUX ) == LINUX and sys .platform != 'linux' :
423
+ return False
424
+ if (optionflags & POSIX ) == POSIX and os .name != 'posix' :
425
+ return False
426
+ return True
427
+
428
+ test .examples [:] = [example for example in test .examples if filter_platform (example )]
429
+
430
+ return super (PlatformDocTestRunner , self ).run (test , compileflags , out , clear_globs )
431
+
432
+ class PlatformDocTestBuilder (sphinx .ext .doctest .DocTestBuilder ):
433
+ _test_runner = None
434
+
435
+ @property
436
+ def test_runner (self ):
437
+ return self ._test_runner
438
+
439
+ @test_runner .setter
440
+ def test_runner (self , value ):
441
+ self ._test_runner = PlatformDocTestRunner (value ._checker , value ._verbose , value .optionflags )
442
+
397
443
if 'doctest' in sys .argv :
398
444
def setup (app ):
399
- pass # app.connect('autodoc-skip-member', dont_skip_any_doctests )
400
-
445
+ app .add_builder ( PlatformDocTestBuilder , override = True )
446
+ # app.connect('autodoc-skip-member', dont_skip_any_doctests)
401
447
# monkey patching paramiko due to https://github.com/paramiko/paramiko/pull/1661
402
448
import paramiko .client
403
449
import binascii
404
450
paramiko .client .hexlify = lambda x : binascii .hexlify (x ).decode ()
405
451
paramiko .util .safe_string = lambda x : '' # function result never *actually used*
406
452
407
453
class EndlessLoop (Exception ): pass
408
- def alrm_handler (sig , frame ):
409
- signal .alarm (180 ) # three minutes
410
- raise EndlessLoop ()
411
- signal .signal (signal .SIGALRM , alrm_handler )
412
- signal .alarm (600 ) # ten minutes
454
+ if hasattr (signal , 'alarm' ):
455
+ def alrm_handler (sig , frame ):
456
+ signal .alarm (180 ) # three minutes
457
+ raise EndlessLoop ()
458
+ signal .signal (signal .SIGALRM , alrm_handler )
459
+ signal .alarm (600 ) # ten minutes
460
+ else :
461
+ def sigabrt_handler (signum , frame ):
462
+ raise EndlessLoop ()
463
+ # thread.interrupt_main received the signum parameter in Python 3.10
464
+ if sys .version_info >= (3 , 10 ):
465
+ signal .signal (signal .SIGABRT , sigabrt_handler )
466
+ def alrm_handler ():
467
+ try :
468
+ import thread
469
+ except ImportError :
470
+ import _thread as thread
471
+ # pre Python 3.10 this raises a KeyboardInterrupt in the main thread.
472
+ # it might not show a traceback in that case, but it will stop the endless loop.
473
+ thread .interrupt_main (signal .SIGABRT )
474
+ timer = threading .Timer (interval = 180 , function = alrm_handler ) # three minutes
475
+ timer .daemon = True
476
+ timer .start ()
477
+ import threading
478
+ timer = threading .Timer (interval = 600 , function = alrm_handler ) # ten minutes
479
+ timer .daemon = True
480
+ timer .start ()
0 commit comments