6
6
import traceback
7
7
import warnings
8
8
from contextlib import contextmanager
9
+ from typing import Dict
10
+ from typing import List
11
+ from typing import Optional
9
12
from typing import Sequence
10
13
from typing import Tuple
14
+ from typing import Union
11
15
12
16
import pytest
13
17
from _pytest import outcomes
20
24
from _pytest .python_api import approx
21
25
from _pytest .warning_types import PytestWarning
22
26
27
+ if False : # TYPE_CHECKING
28
+ import doctest
29
+ from typing import Type
30
+
23
31
DOCTEST_REPORT_CHOICE_NONE = "none"
24
32
DOCTEST_REPORT_CHOICE_CDIFF = "cdiff"
25
33
DOCTEST_REPORT_CHOICE_NDIFF = "ndiff"
36
44
37
45
# Lazy definition of runner class
38
46
RUNNER_CLASS = None
47
+ # Lazy definition of output checker class
48
+ CHECKER_CLASS = None # type: Optional[Type[doctest.OutputChecker]]
39
49
40
50
41
51
def pytest_addoption (parser ):
@@ -139,7 +149,7 @@ def __init__(self, failures):
139
149
self .failures = failures
140
150
141
151
142
- def _init_runner_class ():
152
+ def _init_runner_class () -> "Type[doctest.DocTestRunner]" :
143
153
import doctest
144
154
145
155
class PytestDoctestRunner (doctest .DebugRunner ):
@@ -177,12 +187,19 @@ def report_unexpected_exception(self, out, test, example, exc_info):
177
187
return PytestDoctestRunner
178
188
179
189
180
- def _get_runner (checker = None , verbose = None , optionflags = 0 , continue_on_failure = True ):
190
+ def _get_runner (
191
+ checker : Optional ["doctest.OutputChecker" ] = None ,
192
+ verbose : Optional [bool ] = None ,
193
+ optionflags : int = 0 ,
194
+ continue_on_failure : bool = True ,
195
+ ) -> "doctest.DocTestRunner" :
181
196
# We need this in order to do a lazy import on doctest
182
197
global RUNNER_CLASS
183
198
if RUNNER_CLASS is None :
184
199
RUNNER_CLASS = _init_runner_class ()
185
- return RUNNER_CLASS (
200
+ # Type ignored because the continue_on_failure argument is only defined on
201
+ # PytestDoctestRunner, which is lazily defined so can't be used as a type.
202
+ return RUNNER_CLASS ( # type: ignore
186
203
checker = checker ,
187
204
verbose = verbose ,
188
205
optionflags = optionflags ,
@@ -211,7 +228,7 @@ def setup(self):
211
228
def runtest (self ):
212
229
_check_all_skipped (self .dtest )
213
230
self ._disable_output_capturing_for_darwin ()
214
- failures = []
231
+ failures = [] # type: List[doctest.DocTestFailure]
215
232
self .runner .run (self .dtest , out = failures )
216
233
if failures :
217
234
raise MultipleDoctestFailures (failures )
@@ -232,7 +249,9 @@ def _disable_output_capturing_for_darwin(self):
232
249
def repr_failure (self , excinfo ):
233
250
import doctest
234
251
235
- failures = None
252
+ failures = (
253
+ None
254
+ ) # type: Optional[List[Union[doctest.DocTestFailure, doctest.UnexpectedException]]]
236
255
if excinfo .errisinstance ((doctest .DocTestFailure , doctest .UnexpectedException )):
237
256
failures = [excinfo .value ]
238
257
elif excinfo .errisinstance (MultipleDoctestFailures ):
@@ -255,8 +274,10 @@ def repr_failure(self, excinfo):
255
274
self .config .getoption ("doctestreport" )
256
275
)
257
276
if lineno is not None :
277
+ assert failure .test .docstring is not None
258
278
lines = failure .test .docstring .splitlines (False )
259
279
# add line numbers to the left of the error message
280
+ assert test .lineno is not None
260
281
lines = [
261
282
"%03d %s" % (i + test .lineno + 1 , x )
262
283
for (i , x ) in enumerate (lines )
@@ -288,7 +309,7 @@ def reportinfo(self):
288
309
return self .fspath , self .dtest .lineno , "[doctest] %s" % self .name
289
310
290
311
291
- def _get_flag_lookup ():
312
+ def _get_flag_lookup () -> Dict [ str , int ] :
292
313
import doctest
293
314
294
315
return dict (
@@ -340,14 +361,16 @@ def collect(self):
340
361
optionflags = get_optionflags (self )
341
362
342
363
runner = _get_runner (
343
- verbose = 0 ,
364
+ verbose = False ,
344
365
optionflags = optionflags ,
345
366
checker = _get_checker (),
346
367
continue_on_failure = _get_continue_on_failure (self .config ),
347
368
)
348
369
349
370
parser = doctest .DocTestParser ()
350
- test = parser .get_doctest (text , globs , name , filename , 0 )
371
+ # Remove ignore once this reaches mypy:
372
+ # https://github.com/python/typeshed/commit/3e4a251b2b6da6bb43137acf5abf81ecfa7ba8ee
373
+ test = parser .get_doctest (text , globs , name , filename , 0 ) # type: ignore
351
374
if test .examples :
352
375
yield DoctestItem (test .name , self , runner , test )
353
376
@@ -419,7 +442,8 @@ def _find(self, tests, obj, name, module, source_lines, globs, seen):
419
442
return
420
443
with _patch_unwrap_mock_aware ():
421
444
422
- doctest .DocTestFinder ._find (
445
+ # Type ignored because this is a private function.
446
+ doctest .DocTestFinder ._find ( # type: ignore
423
447
self , tests , obj , name , module , source_lines , globs , seen
424
448
)
425
449
@@ -437,7 +461,7 @@ def _find(self, tests, obj, name, module, source_lines, globs, seen):
437
461
finder = MockAwareDocTestFinder ()
438
462
optionflags = get_optionflags (self )
439
463
runner = _get_runner (
440
- verbose = 0 ,
464
+ verbose = False ,
441
465
optionflags = optionflags ,
442
466
checker = _get_checker (),
443
467
continue_on_failure = _get_continue_on_failure (self .config ),
@@ -466,24 +490,7 @@ def func():
466
490
return fixture_request
467
491
468
492
469
- def _get_checker ():
470
- """
471
- Returns a doctest.OutputChecker subclass that supports some
472
- additional options:
473
-
474
- * ALLOW_UNICODE and ALLOW_BYTES options to ignore u'' and b''
475
- prefixes (respectively) in string literals. Useful when the same
476
- doctest should run in Python 2 and Python 3.
477
-
478
- * NUMBER to ignore floating-point differences smaller than the
479
- precision of the literal number in the doctest.
480
-
481
- An inner class is used to avoid importing "doctest" at the module
482
- level.
483
- """
484
- if hasattr (_get_checker , "LiteralsOutputChecker" ):
485
- return _get_checker .LiteralsOutputChecker ()
486
-
493
+ def _init_checker_class () -> "Type[doctest.OutputChecker]" :
487
494
import doctest
488
495
import re
489
496
@@ -573,11 +580,31 @@ def _remove_unwanted_precision(self, want, got):
573
580
offset += w .end () - w .start () - (g .end () - g .start ())
574
581
return got
575
582
576
- _get_checker .LiteralsOutputChecker = LiteralsOutputChecker
577
- return _get_checker .LiteralsOutputChecker ()
583
+ return LiteralsOutputChecker
584
+
585
+
586
+ def _get_checker () -> "doctest.OutputChecker" :
587
+ """
588
+ Returns a doctest.OutputChecker subclass that supports some
589
+ additional options:
590
+
591
+ * ALLOW_UNICODE and ALLOW_BYTES options to ignore u'' and b''
592
+ prefixes (respectively) in string literals. Useful when the same
593
+ doctest should run in Python 2 and Python 3.
594
+
595
+ * NUMBER to ignore floating-point differences smaller than the
596
+ precision of the literal number in the doctest.
597
+
598
+ An inner class is used to avoid importing "doctest" at the module
599
+ level.
600
+ """
601
+ global CHECKER_CLASS
602
+ if CHECKER_CLASS is None :
603
+ CHECKER_CLASS = _init_checker_class ()
604
+ return CHECKER_CLASS ()
578
605
579
606
580
- def _get_allow_unicode_flag ():
607
+ def _get_allow_unicode_flag () -> int :
581
608
"""
582
609
Registers and returns the ALLOW_UNICODE flag.
583
610
"""
@@ -586,7 +613,7 @@ def _get_allow_unicode_flag():
586
613
return doctest .register_optionflag ("ALLOW_UNICODE" )
587
614
588
615
589
- def _get_allow_bytes_flag ():
616
+ def _get_allow_bytes_flag () -> int :
590
617
"""
591
618
Registers and returns the ALLOW_BYTES flag.
592
619
"""
@@ -595,7 +622,7 @@ def _get_allow_bytes_flag():
595
622
return doctest .register_optionflag ("ALLOW_BYTES" )
596
623
597
624
598
- def _get_number_flag ():
625
+ def _get_number_flag () -> int :
599
626
"""
600
627
Registers and returns the NUMBER flag.
601
628
"""
@@ -604,7 +631,7 @@ def _get_number_flag():
604
631
return doctest .register_optionflag ("NUMBER" )
605
632
606
633
607
- def _get_report_choice (key ) :
634
+ def _get_report_choice (key : str ) -> int :
608
635
"""
609
636
This function returns the actual `doctest` module flag value, we want to do it as late as possible to avoid
610
637
importing `doctest` and all its dependencies when parsing options, as it adds overhead and breaks tests.
0 commit comments