@@ -63,7 +63,7 @@ def repr_failure(self, excinfo):
63
63
lineno = test .lineno + example .lineno + 1
64
64
message = excinfo .type .__name__
65
65
reprlocation = ReprFileLocation (filename , lineno , message )
66
- checker = doctest . OutputChecker ()
66
+ checker = _get_unicode_checker ()
67
67
REPORT_UDIFF = doctest .REPORT_UDIFF
68
68
filelines = py .path .local (filename ).readlines (cr = 0 )
69
69
lines = []
@@ -100,7 +100,8 @@ def _get_flag_lookup():
100
100
NORMALIZE_WHITESPACE = doctest .NORMALIZE_WHITESPACE ,
101
101
ELLIPSIS = doctest .ELLIPSIS ,
102
102
IGNORE_EXCEPTION_DETAIL = doctest .IGNORE_EXCEPTION_DETAIL ,
103
- COMPARISON_FLAGS = doctest .COMPARISON_FLAGS )
103
+ COMPARISON_FLAGS = doctest .COMPARISON_FLAGS ,
104
+ ALLOW_UNICODE = _get_allow_unicode_flag ())
104
105
105
106
def get_optionflags (parent ):
106
107
optionflags_str = parent .config .getini ("doctest_optionflags" )
@@ -110,15 +111,30 @@ def get_optionflags(parent):
110
111
flag_acc |= flag_lookup_table [flag ]
111
112
return flag_acc
112
113
114
+
113
115
class DoctestTextfile (DoctestItem , pytest .File ):
116
+
114
117
def runtest (self ):
115
118
import doctest
116
119
fixture_request = _setup_fixtures (self )
117
- failed , tot = doctest .testfile (
118
- str (self .fspath ), module_relative = False ,
119
- optionflags = get_optionflags (self ),
120
- extraglobs = dict (getfixture = fixture_request .getfuncargvalue ),
121
- raise_on_error = True , verbose = 0 )
120
+
121
+ # inspired by doctest.testfile; ideally we would use it directly,
122
+ # but it doesn't support passing a custom checker
123
+ text = self .fspath .read ()
124
+ filename = str (self .fspath )
125
+ name = self .fspath .basename
126
+ globs = dict (getfixture = fixture_request .getfuncargvalue )
127
+ if '__name__' not in globs :
128
+ globs ['__name__' ] = '__main__'
129
+
130
+ optionflags = get_optionflags (self )
131
+ runner = doctest .DebugRunner (verbose = 0 , optionflags = optionflags ,
132
+ checker = _get_unicode_checker ())
133
+
134
+ parser = doctest .DocTestParser ()
135
+ test = parser .get_doctest (text , globs , name , filename , 0 )
136
+ runner .run (test )
137
+
122
138
123
139
class DoctestModule (pytest .File ):
124
140
def collect (self ):
@@ -139,7 +155,8 @@ def collect(self):
139
155
# uses internal doctest module parsing mechanism
140
156
finder = doctest .DocTestFinder ()
141
157
optionflags = get_optionflags (self )
142
- runner = doctest .DebugRunner (verbose = 0 , optionflags = optionflags )
158
+ runner = doctest .DebugRunner (verbose = 0 , optionflags = optionflags ,
159
+ checker = _get_unicode_checker ())
143
160
for test in finder .find (module , module .__name__ ,
144
161
extraglobs = doctest_globals ):
145
162
if test .examples : # skip empty doctests
@@ -160,3 +177,54 @@ def func():
160
177
fixture_request = FixtureRequest (doctest_item )
161
178
fixture_request ._fillfixtures ()
162
179
return fixture_request
180
+
181
+
182
+ def _get_unicode_checker ():
183
+ """
184
+ Returns a doctest.OutputChecker subclass that takes in account the
185
+ ALLOW_UNICODE option to ignore u'' prefixes in strings. Useful
186
+ when the same doctest should run in Python 2 and Python 3.
187
+
188
+ An inner class is used to avoid importing "doctest" at the module
189
+ level.
190
+ """
191
+ if hasattr (_get_unicode_checker , 'UnicodeOutputChecker' ):
192
+ return _get_unicode_checker .UnicodeOutputChecker ()
193
+
194
+ import doctest
195
+ import re
196
+
197
+ class UnicodeOutputChecker (doctest .OutputChecker ):
198
+ """
199
+ Copied from doctest_nose_plugin.py from the nltk project:
200
+ https://github.com/nltk/nltk
201
+ """
202
+
203
+ _literal_re = re .compile (r"(\W|^)[uU]([rR]?[\'\"])" , re .UNICODE )
204
+
205
+ def _remove_u_prefixes (self , txt ):
206
+ return re .sub (self ._literal_re , r'\1\2' , txt )
207
+
208
+ def check_output (self , want , got , optionflags ):
209
+ res = doctest .OutputChecker .check_output (self , want , got , optionflags )
210
+ if res :
211
+ return True
212
+
213
+ if not (optionflags & _get_allow_unicode_flag ()):
214
+ return False
215
+
216
+ cleaned_want = self ._remove_u_prefixes (want )
217
+ cleaned_got = self ._remove_u_prefixes (got )
218
+ res = doctest .OutputChecker .check_output (self , cleaned_want , cleaned_got , optionflags )
219
+ return res
220
+
221
+ _get_unicode_checker .UnicodeOutputChecker = UnicodeOutputChecker
222
+ return _get_unicode_checker .UnicodeOutputChecker ()
223
+
224
+
225
+ def _get_allow_unicode_flag ():
226
+ """
227
+ Registers and returns the ALLOW_UNICODE flag.
228
+ """
229
+ import doctest
230
+ return doctest .register_optionflag ('ALLOW_UNICODE' )
0 commit comments