@@ -101,15 +101,14 @@ def _test():
101101import re
102102import sys
103103import traceback
104+ import types
104105import unittest
105106from io import StringIO , IncrementalNewlineDecoder
106107from collections import namedtuple
107108import _colorize # Used in doctests
108109from _colorize import ANSIColors , can_colorize
109110
110111
111- __unittest = True
112-
113112class TestResults (namedtuple ('TestResults' , 'failed attempted' )):
114113 def __new__ (cls , failed , attempted , * , skipped = 0 ):
115114 results = super ().__new__ (cls , failed , attempted )
@@ -387,7 +386,7 @@ def __init__(self, out):
387386 self .__out = out
388387 self .__debugger_used = False
389388 # do not play signal games in the pdb
390- pdb . Pdb . __init__ (self , stdout = out , nosigint = True )
389+ super (). __init__ (stdout = out , nosigint = True )
391390 # still use input() to get user input
392391 self .use_rawinput = 1
393392
@@ -1280,6 +1279,11 @@ def __init__(self, checker=None, verbose=None, optionflags=0):
12801279 # Reporting methods
12811280 #/////////////////////////////////////////////////////////////////
12821281
1282+ def report_skip (self , out , test , example ):
1283+ """
1284+ Report that the given example was skipped.
1285+ """
1286+
12831287 def report_start (self , out , test , example ):
12841288 """
12851289 Report that the test runner is about to process the given
@@ -1377,6 +1381,8 @@ def __run(self, test, compileflags, out):
13771381
13781382 # If 'SKIP' is set, then skip this example.
13791383 if self .optionflags & SKIP :
1384+ if not quiet :
1385+ self .report_skip (out , test , example )
13801386 skips += 1
13811387 continue
13821388
@@ -2274,12 +2280,63 @@ def set_unittest_reportflags(flags):
22742280 return old
22752281
22762282
2283+ class _DocTestCaseRunner (DocTestRunner ):
2284+
2285+ def __init__ (self , * args , test_case , test_result , ** kwargs ):
2286+ super ().__init__ (* args , ** kwargs )
2287+ self ._test_case = test_case
2288+ self ._test_result = test_result
2289+ self ._examplenum = 0
2290+
2291+ def _subTest (self ):
2292+ subtest = unittest .case ._SubTest (self ._test_case , str (self ._examplenum ), {})
2293+ self ._examplenum += 1
2294+ return subtest
2295+
2296+ def report_skip (self , out , test , example ):
2297+ unittest .case ._addSkip (self ._test_result , self ._subTest (), '' )
2298+
2299+ def report_success (self , out , test , example , got ):
2300+ self ._test_result .addSubTest (self ._test_case , self ._subTest (), None )
2301+
2302+ def report_unexpected_exception (self , out , test , example , exc_info ):
2303+ tb = self ._add_traceback (exc_info [2 ], test , example )
2304+ exc_info = (* exc_info [:2 ], tb )
2305+ self ._test_result .addSubTest (self ._test_case , self ._subTest (), exc_info )
2306+
2307+ def report_failure (self , out , test , example , got ):
2308+ msg = ('Failed example:\n ' + _indent (example .source ) +
2309+ self ._checker .output_difference (example , got , self .optionflags ).rstrip ('\n ' ))
2310+ exc = self ._test_case .failureException (msg )
2311+ tb = self ._add_traceback (None , test , example )
2312+ exc_info = (type (exc ), exc , tb )
2313+ self ._test_result .addSubTest (self ._test_case , self ._subTest (), exc_info )
2314+
2315+ def _add_traceback (self , traceback , test , example ):
2316+ if test .lineno is None or example .lineno is None :
2317+ lineno = None
2318+ else :
2319+ lineno = test .lineno + example .lineno + 1
2320+ return types .SimpleNamespace (
2321+ tb_frame = types .SimpleNamespace (
2322+ f_globals = test .globs ,
2323+ f_code = types .SimpleNamespace (
2324+ co_filename = test .filename ,
2325+ co_name = test .name ,
2326+ ),
2327+ ),
2328+ tb_next = traceback ,
2329+ tb_lasti = - 1 ,
2330+ tb_lineno = lineno ,
2331+ )
2332+
2333+
22772334class DocTestCase (unittest .TestCase ):
22782335
22792336 def __init__ (self , test , optionflags = 0 , setUp = None , tearDown = None ,
22802337 checker = None ):
22812338
2282- unittest . TestCase . __init__ (self )
2339+ super (). __init__ ()
22832340 self ._dt_optionflags = optionflags
22842341 self ._dt_checker = checker
22852342 self ._dt_test = test
@@ -2303,30 +2360,28 @@ def tearDown(self):
23032360 test .globs .clear ()
23042361 test .globs .update (self ._dt_globs )
23052362
2363+ def run (self , result = None ):
2364+ self ._test_result = result
2365+ return super ().run (result )
2366+
23062367 def runTest (self ):
23072368 test = self ._dt_test
2308- old = sys .stdout
2309- new = StringIO ()
23102369 optionflags = self ._dt_optionflags
2370+ result = self ._test_result
23112371
23122372 if not (optionflags & REPORTING_FLAGS ):
23132373 # The option flags don't include any reporting flags,
23142374 # so add the default reporting flags
23152375 optionflags |= _unittest_reportflags
2376+ if getattr (result , 'failfast' , False ):
2377+ optionflags |= FAIL_FAST
23162378
2317- runner = DocTestRunner (optionflags = optionflags ,
2318- checker = self ._dt_checker , verbose = False )
2319-
2320- try :
2321- runner .DIVIDER = "-" * 70
2322- results = runner .run (test , out = new .write , clear_globs = False )
2323- if results .skipped == results .attempted :
2324- raise unittest .SkipTest ("all examples were skipped" )
2325- finally :
2326- sys .stdout = old
2327-
2328- if results .failed :
2329- raise self .failureException (self .format_failure (new .getvalue ().rstrip ('\n ' )))
2379+ runner = _DocTestCaseRunner (optionflags = optionflags ,
2380+ checker = self ._dt_checker , verbose = False ,
2381+ test_case = self , test_result = result )
2382+ results = runner .run (test , clear_globs = False )
2383+ if results .skipped == results .attempted :
2384+ raise unittest .SkipTest ("all examples were skipped" )
23302385
23312386 def format_failure (self , err ):
23322387 test = self ._dt_test
@@ -2441,7 +2496,7 @@ def shortDescription(self):
24412496class SkipDocTestCase (DocTestCase ):
24422497 def __init__ (self , module ):
24432498 self .module = module
2444- DocTestCase .__init__ (self , None )
2499+ super () .__init__ (None )
24452500
24462501 def setUp (self ):
24472502 self .skipTest ("DocTestSuite will not work with -O2 and above" )
0 commit comments