9
9
import re
10
10
import sys
11
11
import warnings
12
+ from distutils .version import LooseVersion
12
13
13
14
import pytest
14
15
import six
22
23
def indent (text , prefix ):
23
24
return '\n ' .join ([prefix + line for line in text .splitlines ()])
24
25
26
+ PYTEST_LT_5_4 = LooseVersion (pytest .__version__ ) < LooseVersion ('5.4' )
27
+
25
28
comment_characters = {
26
29
'.txt' : '#' ,
27
30
'.tex' : '%' ,
28
31
'.rst' : r'\.\.'
29
32
}
30
33
31
-
32
34
# For the IGNORE_WARNINGS option, we create a context manager that doesn't
33
35
# require us to add any imports to the example list and contains everything
34
36
# that is needed to silence warnings.
@@ -154,10 +156,7 @@ def pytest_configure(config):
154
156
class DocTestModulePlus (doctest_plugin .DoctestModule ):
155
157
# pytest 2.4.0 defines "collect". Prior to that, it defined
156
158
# "runtest". The "collect" approach is better, because we can
157
- # skip modules altogether that have no doctests. However, we
158
- # need to continue to override "runtest" so that the built-in
159
- # behavior (which doesn't do whitespace normalization or
160
- # handling __doctest_skip__) doesn't happen.
159
+ # skip modules altogether that have no doctests.
161
160
def collect (self ):
162
161
# When running directly from pytest we need to make sure that we
163
162
# don't accidentally import setup.py!
@@ -194,7 +193,7 @@ def collect(self):
194
193
# wrapping the source in a context manager.
195
194
if example .options .get (IGNORE_WARNINGS , False ):
196
195
example .source = ("with _doctestplus_ignore_all_warnings():\n "
197
- + indent (example .source , ' ' ))
196
+ + indent (example .source , ' ' ))
198
197
ignore_warnings_context_needed = True
199
198
200
199
if example .options .get (REMOTE_DATA ):
@@ -208,25 +207,34 @@ def collect(self):
208
207
yield doctest_plugin .DoctestItem (
209
208
test .name , self , runner , test )
210
209
211
- class DocTestTextfilePlus (doctest_plugin .DoctestItem , pytest .Module ):
212
- # Some pytest plugins such as hypothesis try and access the 'obj'
213
- # attribute, and by default this returns an error for this class
214
- # so we override it here to avoid any issues.
215
- def obj (self ):
216
- pass
217
-
218
- def runtest (self ):
219
- # satisfy `FixtureRequest` constructor...
220
- self .funcargs = {}
221
- fixture_request = doctest_plugin ._setup_fixtures (self )
222
-
223
- options = get_optionflags (self ) | FIX
210
+ class DocTestTextfilePlus (doctest_plugin .DoctestTextfile ):
224
211
225
- doctest .testfile (
226
- str (self .fspath ), module_relative = False ,
227
- optionflags = options , parser = DocTestParserPlus (),
228
- extraglobs = dict (getfixture = fixture_request .getfixturevalue ),
229
- raise_on_error = True , verbose = False , encoding = 'utf-8' )
212
+ def collect (self ):
213
+ from _pytest .doctest import (_get_runner , _get_checker ,
214
+ _get_continue_on_failure , DoctestItem )
215
+
216
+ encoding = 'utf-8'
217
+ text = self .fspath .read_text (encoding )
218
+ filename = str (self .fspath )
219
+ name = self .fspath .basename
220
+ globs = {"__name__" : "__main__" }
221
+
222
+ optionflags = get_optionflags (self ) | FIX
223
+
224
+ runner = _get_runner (
225
+ verbose = False ,
226
+ optionflags = optionflags ,
227
+ checker = _get_checker (),
228
+ continue_on_failure = _get_continue_on_failure (self .config ))
229
+
230
+ parser = DocTestParserPlus ()
231
+ test = parser .get_doctest (text , globs , name , filename , 0 )
232
+ if test .examples :
233
+ if PYTEST_LT_5_4 :
234
+ yield DoctestItem (test .name , self , runner , test )
235
+ else :
236
+ yield DoctestItem .from_parent (
237
+ self , name = test .name , runner = runner , dtest = test )
230
238
231
239
def reportinfo (self ):
232
240
"""
@@ -272,7 +280,7 @@ def parse(self, s, name=None):
272
280
if ext not in comment_characters :
273
281
warnings .warn ("file format '{}' is not recognized, assuming "
274
282
"'{}' as the comment character."
275
- .format (ext , comment_characters ['rst' ]))
283
+ .format (ext , comment_characters ['. rst' ]))
276
284
ext = '.rst'
277
285
comment_char = comment_characters [ext ]
278
286
@@ -452,8 +460,14 @@ def pytest_collect_file(self, path, parent):
452
460
if path .basename == 'conf.py' :
453
461
return None
454
462
463
+ if PYTEST_LT_5_4 :
464
+ x = self ._doctest_module_item_cls (path , parent )
465
+ else :
466
+ x = self ._doctest_textfile_item_cls .from_parent (
467
+ parent , fspath = path )
468
+
455
469
# Don't override the built-in doctest plugin
456
- return self . _doctest_module_item_cls ( path , parent )
470
+ return x
457
471
elif any ([path .check (fnmatch = pat ) for pat in self ._file_globs ]):
458
472
# Ignore generated .rst files
459
473
parts = str (path ).split (os .path .sep )
@@ -479,7 +493,13 @@ def pytest_collect_file(self, path, parent):
479
493
480
494
# TODO: Get better names on these items when they are
481
495
# displayed in py.test output
482
- return self ._doctest_textfile_item_cls (path , parent )
496
+ if PYTEST_LT_5_4 :
497
+ x = self ._doctest_textfile_item_cls (path , parent )
498
+ else :
499
+ x = self ._doctest_textfile_item_cls .from_parent (
500
+ parent , fspath = path )
501
+
502
+ return x
483
503
484
504
485
505
class DocTestFinderPlus (doctest .DocTestFinder ):
0 commit comments