##// END OF EJS Templates
Make default argv for testing instances....
Fernando Perez -
Show More
@@ -1,875 +1,889 b''
1 1 """Nose Plugin that supports IPython doctests.
2 2
3 3 Limitations:
4 4
5 5 - When generating examples for use as doctests, make sure that you have
6 6 pretty-printing OFF. This can be done either by starting ipython with the
7 7 flag '--nopprint', by setting pprint to 0 in your ipythonrc file, or by
8 8 interactively disabling it with %Pprint. This is required so that IPython
9 9 output matches that of normal Python, which is used by doctest for internal
10 10 execution.
11 11
12 12 - Do not rely on specific prompt numbers for results (such as using
13 13 '_34==True', for example). For IPython tests run via an external process the
14 14 prompt numbers may be different, and IPython tests run as normal python code
15 15 won't even have these special _NN variables set at all.
16 16 """
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Module imports
20 20
21 21 # From the standard library
22 22 import __builtin__
23 23 import commands
24 24 import doctest
25 25 import inspect
26 26 import logging
27 27 import os
28 28 import re
29 29 import sys
30 30 import traceback
31 31 import unittest
32 32
33 33 from inspect import getmodule
34 34 from StringIO import StringIO
35 35
36 36 # We are overriding the default doctest runner, so we need to import a few
37 37 # things from doctest directly
38 38 from doctest import (REPORTING_FLAGS, REPORT_ONLY_FIRST_FAILURE,
39 39 _unittest_reportflags, DocTestRunner,
40 40 _extract_future_flags, pdb, _OutputRedirectingPdb,
41 41 _exception_traceback,
42 42 linecache)
43 43
44 44 # Third-party modules
45 45 import nose.core
46 46
47 47 from nose.plugins import doctests, Plugin
48 48 from nose.util import anyp, getpackage, test_address, resolve_name, tolist
49 49
50 50 #-----------------------------------------------------------------------------
51 51 # Module globals and other constants
52 52
53 53 log = logging.getLogger(__name__)
54 54
55 55 ###########################################################################
56 56 # *** HACK ***
57 57 # We must start our own ipython object and heavily muck with it so that all the
58 58 # modifications IPython makes to system behavior don't send the doctest
59 59 # machinery into a fit. This code should be considered a gross hack, but it
60 60 # gets the job done.
61 61
62 def default_argv():
63 """Return a valid default argv for creating testing instances of ipython"""
64
65 # Get the install directory for the user configuration and tell ipython to
66 # use the default profile from there.
67 from IPython import UserConfig
68 ipcdir = os.path.dirname(UserConfig.__file__)
69 #ipconf = os.path.join(ipcdir,'ipy_user_conf.py')
70 ipconf = os.path.join(ipcdir,'ipythonrc')
71 #print 'conf:',ipconf # dbg
72
73 return ['--colors=NoColor','--noterm_title','-rcfile=%s' % ipconf]
74
62 75
63 76 # Hack to modify the %run command so we can sync the user's namespace with the
64 77 # test globals. Once we move over to a clean magic system, this will be done
65 78 # with much less ugliness.
66 79
67 80 class py_file_finder(object):
68 81 def __init__(self,test_filename):
69 82 self.test_filename = test_filename
70 83
71 84 def __call__(self,name):
72 85 from IPython.genutils import get_py_filename
73 86 try:
74 87 return get_py_filename(name)
75 88 except IOError:
76 89 test_dir = os.path.dirname(self.test_filename)
77 90 new_path = os.path.join(test_dir,name)
78 91 return get_py_filename(new_path)
79 92
80 93
81 94 def _run_ns_sync(self,arg_s,runner=None):
82 95 """Modified version of %run that syncs testing namespaces.
83 96
84 97 This is strictly needed for running doctests that call %run.
85 98 """
86 99
87 100 finder = py_file_finder(_run_ns_sync.test_filename)
88 101 out = _ip.IP.magic_run_ori(arg_s,runner,finder)
89 102 _run_ns_sync.test_globs.update(_ip.user_ns)
90 103 return out
91 104
92 105
93 106 class ipnsdict(dict):
94 107 """A special subclass of dict for use as an IPython namespace in doctests.
95 108
96 109 This subclass adds a simple checkpointing capability so that when testing
97 110 machinery clears it (we use it as the test execution context), it doesn't
98 111 get completely destroyed.
99 112 """
100 113
101 114 def __init__(self,*a):
102 115 dict.__init__(self,*a)
103 116 self._savedict = {}
104 117
105 118 def clear(self):
106 119 dict.clear(self)
107 120 self.update(self._savedict)
108 121
109 122 def _checkpoint(self):
110 123 self._savedict.clear()
111 124 self._savedict.update(self)
112 125
113 126 def update(self,other):
114 127 self._checkpoint()
115 128 dict.update(self,other)
116 129 # If '_' is in the namespace, python won't set it when executing code,
117 130 # and we have examples that test it. So we ensure that the namespace
118 131 # is always 'clean' of it before it's used for test code execution.
119 132 self.pop('_',None)
120 133
121 134
122 135 def start_ipython():
123 136 """Start a global IPython shell, which we need for IPython-specific syntax.
124 137 """
125 138
126 139 # This function should only ever run once!
127 140 if hasattr(start_ipython,'already_called'):
128 141 return
129 142 start_ipython.already_called = True
130 143
131 144 # Ok, first time we're called, go ahead
132 145 import new
133 146
134 147 import IPython
135 148
136 149 def xsys(cmd):
137 150 """Execute a command and print its output.
138 151
139 152 This is just a convenience function to replace the IPython system call
140 153 with one that is more doctest-friendly.
141 154 """
142 155 cmd = _ip.IP.var_expand(cmd,depth=1)
143 156 sys.stdout.write(commands.getoutput(cmd))
144 157 sys.stdout.flush()
145 158
146 159 # Store certain global objects that IPython modifies
147 160 _displayhook = sys.displayhook
148 161 _excepthook = sys.excepthook
149 162 _main = sys.modules.get('__main__')
150 163
164 argv = default_argv()
165
151 166 # Start IPython instance. We customize it to start with minimal frills.
152 167 user_ns,global_ns = IPython.ipapi.make_user_namespaces(ipnsdict(),dict())
153 IPython.Shell.IPShell(['--colors=NoColor','--noterm_title'],
154 user_ns,global_ns)
168 IPython.Shell.IPShell(argv,user_ns,global_ns)
155 169
156 170 # Deactivate the various python system hooks added by ipython for
157 171 # interactive convenience so we don't confuse the doctest system
158 172 sys.modules['__main__'] = _main
159 173 sys.displayhook = _displayhook
160 174 sys.excepthook = _excepthook
161 175
162 176 # So that ipython magics and aliases can be doctested (they work by making
163 177 # a call into a global _ip object)
164 178 _ip = IPython.ipapi.get()
165 179 __builtin__._ip = _ip
166 180
167 181 # Modify the IPython system call with one that uses getoutput, so that we
168 182 # can capture subcommands and print them to Python's stdout, otherwise the
169 183 # doctest machinery would miss them.
170 184 _ip.system = xsys
171 185
172 186 # Also patch our %run function in.
173 187 im = new.instancemethod(_run_ns_sync,_ip.IP, _ip.IP.__class__)
174 188 _ip.IP.magic_run_ori = _ip.IP.magic_run
175 189 _ip.IP.magic_run = im
176 190
177 191 # The start call MUST be made here. I'm not sure yet why it doesn't work if
178 192 # it is made later, at plugin initialization time, but in all my tests, that's
179 193 # the case.
180 194 start_ipython()
181 195
182 196 # *** END HACK ***
183 197 ###########################################################################
184 198
185 199 # Classes and functions
186 200
187 201 def is_extension_module(filename):
188 202 """Return whether the given filename is an extension module.
189 203
190 204 This simply checks that the extension is either .so or .pyd.
191 205 """
192 206 return os.path.splitext(filename)[1].lower() in ('.so','.pyd')
193 207
194 208
195 209 class DocTestSkip(object):
196 210 """Object wrapper for doctests to be skipped."""
197 211
198 212 ds_skip = """Doctest to skip.
199 213 >>> 1 #doctest: +SKIP
200 214 """
201 215
202 216 def __init__(self,obj):
203 217 self.obj = obj
204 218
205 219 def __getattribute__(self,key):
206 220 if key == '__doc__':
207 221 return DocTestSkip.ds_skip
208 222 else:
209 223 return getattr(object.__getattribute__(self,'obj'),key)
210 224
211 225 # Modified version of the one in the stdlib, that fixes a python bug (doctests
212 226 # not found in extension modules, http://bugs.python.org/issue3158)
213 227 class DocTestFinder(doctest.DocTestFinder):
214 228
215 229 def _from_module(self, module, object):
216 230 """
217 231 Return true if the given object is defined in the given
218 232 module.
219 233 """
220 234 if module is None:
221 235 return True
222 236 elif inspect.isfunction(object):
223 237 return module.__dict__ is object.func_globals
224 238 elif inspect.isbuiltin(object):
225 239 return module.__name__ == object.__module__
226 240 elif inspect.isclass(object):
227 241 return module.__name__ == object.__module__
228 242 elif inspect.ismethod(object):
229 243 # This one may be a bug in cython that fails to correctly set the
230 244 # __module__ attribute of methods, but since the same error is easy
231 245 # to make by extension code writers, having this safety in place
232 246 # isn't such a bad idea
233 247 return module.__name__ == object.im_class.__module__
234 248 elif inspect.getmodule(object) is not None:
235 249 return module is inspect.getmodule(object)
236 250 elif hasattr(object, '__module__'):
237 251 return module.__name__ == object.__module__
238 252 elif isinstance(object, property):
239 253 return True # [XX] no way not be sure.
240 254 else:
241 255 raise ValueError("object must be a class or function")
242 256
243 257 def _find(self, tests, obj, name, module, source_lines, globs, seen):
244 258 """
245 259 Find tests for the given object and any contained objects, and
246 260 add them to `tests`.
247 261 """
248 262
249 263 if hasattr(obj,"skip_doctest"):
250 264 #print 'SKIPPING DOCTEST FOR:',obj # dbg
251 265 obj = DocTestSkip(obj)
252 266
253 267 doctest.DocTestFinder._find(self,tests, obj, name, module,
254 268 source_lines, globs, seen)
255 269
256 270 # Below we re-run pieces of the above method with manual modifications,
257 271 # because the original code is buggy and fails to correctly identify
258 272 # doctests in extension modules.
259 273
260 274 # Local shorthands
261 275 from inspect import isroutine, isclass, ismodule
262 276
263 277 # Look for tests in a module's contained objects.
264 278 if inspect.ismodule(obj) and self._recurse:
265 279 for valname, val in obj.__dict__.items():
266 280 valname1 = '%s.%s' % (name, valname)
267 281 if ( (isroutine(val) or isclass(val))
268 282 and self._from_module(module, val) ):
269 283
270 284 self._find(tests, val, valname1, module, source_lines,
271 285 globs, seen)
272 286
273 287 # Look for tests in a class's contained objects.
274 288 if inspect.isclass(obj) and self._recurse:
275 289 #print 'RECURSE into class:',obj # dbg
276 290 for valname, val in obj.__dict__.items():
277 291 # Special handling for staticmethod/classmethod.
278 292 if isinstance(val, staticmethod):
279 293 val = getattr(obj, valname)
280 294 if isinstance(val, classmethod):
281 295 val = getattr(obj, valname).im_func
282 296
283 297 # Recurse to methods, properties, and nested classes.
284 298 if ((inspect.isfunction(val) or inspect.isclass(val) or
285 299 inspect.ismethod(val) or
286 300 isinstance(val, property)) and
287 301 self._from_module(module, val)):
288 302 valname = '%s.%s' % (name, valname)
289 303 self._find(tests, val, valname, module, source_lines,
290 304 globs, seen)
291 305
292 306
293 307 class IPDoctestOutputChecker(doctest.OutputChecker):
294 308 """Second-chance checker with support for random tests.
295 309
296 310 If the default comparison doesn't pass, this checker looks in the expected
297 311 output string for flags that tell us to ignore the output.
298 312 """
299 313
300 314 random_re = re.compile(r'#\s*random\s+')
301 315
302 316 def check_output(self, want, got, optionflags):
303 317 """Check output, accepting special markers embedded in the output.
304 318
305 319 If the output didn't pass the default validation but the special string
306 320 '#random' is included, we accept it."""
307 321
308 322 # Let the original tester verify first, in case people have valid tests
309 323 # that happen to have a comment saying '#random' embedded in.
310 324 ret = doctest.OutputChecker.check_output(self, want, got,
311 325 optionflags)
312 326 if not ret and self.random_re.search(want):
313 327 #print >> sys.stderr, 'RANDOM OK:',want # dbg
314 328 return True
315 329
316 330 return ret
317 331
318 332
319 333 class DocTestCase(doctests.DocTestCase):
320 334 """Proxy for DocTestCase: provides an address() method that
321 335 returns the correct address for the doctest case. Otherwise
322 336 acts as a proxy to the test case. To provide hints for address(),
323 337 an obj may also be passed -- this will be used as the test object
324 338 for purposes of determining the test address, if it is provided.
325 339 """
326 340
327 341 # Note: this method was taken from numpy's nosetester module.
328 342
329 343 # Subclass nose.plugins.doctests.DocTestCase to work around a bug in
330 344 # its constructor that blocks non-default arguments from being passed
331 345 # down into doctest.DocTestCase
332 346
333 347 def __init__(self, test, optionflags=0, setUp=None, tearDown=None,
334 348 checker=None, obj=None, result_var='_'):
335 349 self._result_var = result_var
336 350 doctests.DocTestCase.__init__(self, test,
337 351 optionflags=optionflags,
338 352 setUp=setUp, tearDown=tearDown,
339 353 checker=checker)
340 354 # Now we must actually copy the original constructor from the stdlib
341 355 # doctest class, because we can't call it directly and a bug in nose
342 356 # means it never gets passed the right arguments.
343 357
344 358 self._dt_optionflags = optionflags
345 359 self._dt_checker = checker
346 360 self._dt_test = test
347 361 self._dt_setUp = setUp
348 362 self._dt_tearDown = tearDown
349 363
350 364 # XXX - store this runner once in the object!
351 365 runner = IPDocTestRunner(optionflags=optionflags,
352 366 checker=checker, verbose=False)
353 367 self._dt_runner = runner
354 368
355 369
356 370 # Each doctest should remember what directory it was loaded from...
357 371 self._ori_dir = os.getcwd()
358 372
359 373 # Modified runTest from the default stdlib
360 374 def runTest(self):
361 375 test = self._dt_test
362 376 runner = self._dt_runner
363 377
364 378 old = sys.stdout
365 379 new = StringIO()
366 380 optionflags = self._dt_optionflags
367 381
368 382 if not (optionflags & REPORTING_FLAGS):
369 383 # The option flags don't include any reporting flags,
370 384 # so add the default reporting flags
371 385 optionflags |= _unittest_reportflags
372 386
373 387 try:
374 388 # Save our current directory and switch out to the one where the
375 389 # test was originally created, in case another doctest did a
376 390 # directory change. We'll restore this in the finally clause.
377 391 curdir = os.getcwd()
378 392 os.chdir(self._ori_dir)
379 393
380 394 runner.DIVIDER = "-"*70
381 395 failures, tries = runner.run(test,out=new.write,
382 396 clear_globs=False)
383 397 finally:
384 398 sys.stdout = old
385 399 os.chdir(curdir)
386 400
387 401 if failures:
388 402 raise self.failureException(self.format_failure(new.getvalue()))
389 403
390 404 def setUp(self):
391 405 """Modified test setup that syncs with ipython namespace"""
392 406
393 407 if isinstance(self._dt_test.examples[0],IPExample):
394 408 # for IPython examples *only*, we swap the globals with the ipython
395 409 # namespace, after updating it with the globals (which doctest
396 410 # fills with the necessary info from the module being tested).
397 411 _ip.IP.user_ns.update(self._dt_test.globs)
398 412 self._dt_test.globs = _ip.IP.user_ns
399 413
400 414 doctests.DocTestCase.setUp(self)
401 415
402 416
403 417 # A simple subclassing of the original with a different class name, so we can
404 418 # distinguish and treat differently IPython examples from pure python ones.
405 419 class IPExample(doctest.Example): pass
406 420
407 421
408 422 class IPExternalExample(doctest.Example):
409 423 """Doctest examples to be run in an external process."""
410 424
411 425 def __init__(self, source, want, exc_msg=None, lineno=0, indent=0,
412 426 options=None):
413 427 # Parent constructor
414 428 doctest.Example.__init__(self,source,want,exc_msg,lineno,indent,options)
415 429
416 430 # An EXTRA newline is needed to prevent pexpect hangs
417 431 self.source += '\n'
418 432
419 433
420 434 class IPDocTestParser(doctest.DocTestParser):
421 435 """
422 436 A class used to parse strings containing doctest examples.
423 437
424 438 Note: This is a version modified to properly recognize IPython input and
425 439 convert any IPython examples into valid Python ones.
426 440 """
427 441 # This regular expression is used to find doctest examples in a
428 442 # string. It defines three groups: `source` is the source code
429 443 # (including leading indentation and prompts); `indent` is the
430 444 # indentation of the first (PS1) line of the source code; and
431 445 # `want` is the expected output (including leading indentation).
432 446
433 447 # Classic Python prompts or default IPython ones
434 448 _PS1_PY = r'>>>'
435 449 _PS2_PY = r'\.\.\.'
436 450
437 451 _PS1_IP = r'In\ \[\d+\]:'
438 452 _PS2_IP = r'\ \ \ \.\.\.+:'
439 453
440 454 _RE_TPL = r'''
441 455 # Source consists of a PS1 line followed by zero or more PS2 lines.
442 456 (?P<source>
443 457 (?:^(?P<indent> [ ]*) (?P<ps1> %s) .*) # PS1 line
444 458 (?:\n [ ]* (?P<ps2> %s) .*)*) # PS2 lines
445 459 \n? # a newline
446 460 # Want consists of any non-blank lines that do not start with PS1.
447 461 (?P<want> (?:(?![ ]*$) # Not a blank line
448 462 (?![ ]*%s) # Not a line starting with PS1
449 463 (?![ ]*%s) # Not a line starting with PS2
450 464 .*$\n? # But any other line
451 465 )*)
452 466 '''
453 467
454 468 _EXAMPLE_RE_PY = re.compile( _RE_TPL % (_PS1_PY,_PS2_PY,_PS1_PY,_PS2_PY),
455 469 re.MULTILINE | re.VERBOSE)
456 470
457 471 _EXAMPLE_RE_IP = re.compile( _RE_TPL % (_PS1_IP,_PS2_IP,_PS1_IP,_PS2_IP),
458 472 re.MULTILINE | re.VERBOSE)
459 473
460 474 # Mark a test as being fully random. In this case, we simply append the
461 475 # random marker ('#random') to each individual example's output. This way
462 476 # we don't need to modify any other code.
463 477 _RANDOM_TEST = re.compile(r'#\s*all-random\s+')
464 478
465 479 # Mark tests to be executed in an external process - currently unsupported.
466 480 _EXTERNAL_IP = re.compile(r'#\s*ipdoctest:\s*EXTERNAL')
467 481
468 482 def ip2py(self,source):
469 483 """Convert input IPython source into valid Python."""
470 484 out = []
471 485 newline = out.append
472 486 #print 'IPSRC:\n',source,'\n###' # dbg
473 487 # The input source must be first stripped of all bracketing whitespace
474 488 # and turned into lines, so it looks to the parser like regular user
475 489 # input
476 490 for lnum,line in enumerate(source.strip().splitlines()):
477 491 newline(_ip.IP.prefilter(line,lnum>0))
478 492 newline('') # ensure a closing newline, needed by doctest
479 493 #print "PYSRC:", '\n'.join(out) # dbg
480 494 return '\n'.join(out)
481 495
482 496 def parse(self, string, name='<string>'):
483 497 """
484 498 Divide the given string into examples and intervening text,
485 499 and return them as a list of alternating Examples and strings.
486 500 Line numbers for the Examples are 0-based. The optional
487 501 argument `name` is a name identifying this string, and is only
488 502 used for error messages.
489 503 """
490 504
491 505 #print 'Parse string:\n',string # dbg
492 506
493 507 string = string.expandtabs()
494 508 # If all lines begin with the same indentation, then strip it.
495 509 min_indent = self._min_indent(string)
496 510 if min_indent > 0:
497 511 string = '\n'.join([l[min_indent:] for l in string.split('\n')])
498 512
499 513 output = []
500 514 charno, lineno = 0, 0
501 515
502 516 # We make 'all random' tests by adding the '# random' mark to every
503 517 # block of output in the test.
504 518 if self._RANDOM_TEST.search(string):
505 519 random_marker = '\n# random'
506 520 else:
507 521 random_marker = ''
508 522
509 523 # Whether to convert the input from ipython to python syntax
510 524 ip2py = False
511 525 # Find all doctest examples in the string. First, try them as Python
512 526 # examples, then as IPython ones
513 527 terms = list(self._EXAMPLE_RE_PY.finditer(string))
514 528 if terms:
515 529 # Normal Python example
516 530 #print '-'*70 # dbg
517 531 #print 'PyExample, Source:\n',string # dbg
518 532 #print '-'*70 # dbg
519 533 Example = doctest.Example
520 534 else:
521 535 # It's an ipython example. Note that IPExamples are run
522 536 # in-process, so their syntax must be turned into valid python.
523 537 # IPExternalExamples are run out-of-process (via pexpect) so they
524 538 # don't need any filtering (a real ipython will be executing them).
525 539 terms = list(self._EXAMPLE_RE_IP.finditer(string))
526 540 if self._EXTERNAL_IP.search(string):
527 541 #print '-'*70 # dbg
528 542 #print 'IPExternalExample, Source:\n',string # dbg
529 543 #print '-'*70 # dbg
530 544 Example = IPExternalExample
531 545 else:
532 546 #print '-'*70 # dbg
533 547 #print 'IPExample, Source:\n',string # dbg
534 548 #print '-'*70 # dbg
535 549 Example = IPExample
536 550 ip2py = True
537 551
538 552 for m in terms:
539 553 # Add the pre-example text to `output`.
540 554 output.append(string[charno:m.start()])
541 555 # Update lineno (lines before this example)
542 556 lineno += string.count('\n', charno, m.start())
543 557 # Extract info from the regexp match.
544 558 (source, options, want, exc_msg) = \
545 559 self._parse_example(m, name, lineno,ip2py)
546 560
547 561 # Append the random-output marker (it defaults to empty in most
548 562 # cases, it's only non-empty for 'all-random' tests):
549 563 want += random_marker
550 564
551 565 if Example is IPExternalExample:
552 566 options[doctest.NORMALIZE_WHITESPACE] = True
553 567 want += '\n'
554 568
555 569 # Create an Example, and add it to the list.
556 570 if not self._IS_BLANK_OR_COMMENT(source):
557 571 output.append(Example(source, want, exc_msg,
558 572 lineno=lineno,
559 573 indent=min_indent+len(m.group('indent')),
560 574 options=options))
561 575 # Update lineno (lines inside this example)
562 576 lineno += string.count('\n', m.start(), m.end())
563 577 # Update charno.
564 578 charno = m.end()
565 579 # Add any remaining post-example text to `output`.
566 580 output.append(string[charno:])
567 581 return output
568 582
569 583 def _parse_example(self, m, name, lineno,ip2py=False):
570 584 """
571 585 Given a regular expression match from `_EXAMPLE_RE` (`m`),
572 586 return a pair `(source, want)`, where `source` is the matched
573 587 example's source code (with prompts and indentation stripped);
574 588 and `want` is the example's expected output (with indentation
575 589 stripped).
576 590
577 591 `name` is the string's name, and `lineno` is the line number
578 592 where the example starts; both are used for error messages.
579 593
580 594 Optional:
581 595 `ip2py`: if true, filter the input via IPython to convert the syntax
582 596 into valid python.
583 597 """
584 598
585 599 # Get the example's indentation level.
586 600 indent = len(m.group('indent'))
587 601
588 602 # Divide source into lines; check that they're properly
589 603 # indented; and then strip their indentation & prompts.
590 604 source_lines = m.group('source').split('\n')
591 605
592 606 # We're using variable-length input prompts
593 607 ps1 = m.group('ps1')
594 608 ps2 = m.group('ps2')
595 609 ps1_len = len(ps1)
596 610
597 611 self._check_prompt_blank(source_lines, indent, name, lineno,ps1_len)
598 612 if ps2:
599 613 self._check_prefix(source_lines[1:], ' '*indent + ps2, name, lineno)
600 614
601 615 source = '\n'.join([sl[indent+ps1_len+1:] for sl in source_lines])
602 616
603 617 if ip2py:
604 618 # Convert source input from IPython into valid Python syntax
605 619 source = self.ip2py(source)
606 620
607 621 # Divide want into lines; check that it's properly indented; and
608 622 # then strip the indentation. Spaces before the last newline should
609 623 # be preserved, so plain rstrip() isn't good enough.
610 624 want = m.group('want')
611 625 want_lines = want.split('\n')
612 626 if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]):
613 627 del want_lines[-1] # forget final newline & spaces after it
614 628 self._check_prefix(want_lines, ' '*indent, name,
615 629 lineno + len(source_lines))
616 630
617 631 # Remove ipython output prompt that might be present in the first line
618 632 want_lines[0] = re.sub(r'Out\[\d+\]: \s*?\n?','',want_lines[0])
619 633
620 634 want = '\n'.join([wl[indent:] for wl in want_lines])
621 635
622 636 # If `want` contains a traceback message, then extract it.
623 637 m = self._EXCEPTION_RE.match(want)
624 638 if m:
625 639 exc_msg = m.group('msg')
626 640 else:
627 641 exc_msg = None
628 642
629 643 # Extract options from the source.
630 644 options = self._find_options(source, name, lineno)
631 645
632 646 return source, options, want, exc_msg
633 647
634 648 def _check_prompt_blank(self, lines, indent, name, lineno, ps1_len):
635 649 """
636 650 Given the lines of a source string (including prompts and
637 651 leading indentation), check to make sure that every prompt is
638 652 followed by a space character. If any line is not followed by
639 653 a space character, then raise ValueError.
640 654
641 655 Note: IPython-modified version which takes the input prompt length as a
642 656 parameter, so that prompts of variable length can be dealt with.
643 657 """
644 658 space_idx = indent+ps1_len
645 659 min_len = space_idx+1
646 660 for i, line in enumerate(lines):
647 661 if len(line) >= min_len and line[space_idx] != ' ':
648 662 raise ValueError('line %r of the docstring for %s '
649 663 'lacks blank after %s: %r' %
650 664 (lineno+i+1, name,
651 665 line[indent:space_idx], line))
652 666
653 667
654 668 SKIP = doctest.register_optionflag('SKIP')
655 669
656 670
657 671 class IPDocTestRunner(doctest.DocTestRunner,object):
658 672 """Test runner that synchronizes the IPython namespace with test globals.
659 673 """
660 674
661 675 def run(self, test, compileflags=None, out=None, clear_globs=True):
662 676
663 677 # Hack: ipython needs access to the execution context of the example,
664 678 # so that it can propagate user variables loaded by %run into
665 679 # test.globs. We put them here into our modified %run as a function
666 680 # attribute. Our new %run will then only make the namespace update
667 681 # when called (rather than unconconditionally updating test.globs here
668 682 # for all examples, most of which won't be calling %run anyway).
669 683 _run_ns_sync.test_globs = test.globs
670 684 _run_ns_sync.test_filename = test.filename
671 685
672 686 return super(IPDocTestRunner,self).run(test,
673 687 compileflags,out,clear_globs)
674 688
675 689
676 690 class DocFileCase(doctest.DocFileCase):
677 691 """Overrides to provide filename
678 692 """
679 693 def address(self):
680 694 return (self._dt_test.filename, None, None)
681 695
682 696
683 697 class ExtensionDoctest(doctests.Doctest):
684 698 """Nose Plugin that supports doctests in extension modules.
685 699 """
686 700 name = 'extdoctest' # call nosetests with --with-extdoctest
687 701 enabled = True
688 702
689 703 def __init__(self,exclude_patterns=None):
690 704 """Create a new ExtensionDoctest plugin.
691 705
692 706 Parameters
693 707 ----------
694 708
695 709 exclude_patterns : sequence of strings, optional
696 710 These patterns are compiled as regular expressions, subsequently used
697 711 to exclude any filename which matches them from inclusion in the test
698 712 suite (using pattern.search(), NOT pattern.match() ).
699 713 """
700 714
701 715 if exclude_patterns is None:
702 716 exclude_patterns = []
703 717 self.exclude_patterns = map(re.compile,exclude_patterns)
704 718 doctests.Doctest.__init__(self)
705 719
706 720 def options(self, parser, env=os.environ):
707 721 Plugin.options(self, parser, env)
708 722 parser.add_option('--doctest-tests', action='store_true',
709 723 dest='doctest_tests',
710 724 default=env.get('NOSE_DOCTEST_TESTS',True),
711 725 help="Also look for doctests in test modules. "
712 726 "Note that classes, methods and functions should "
713 727 "have either doctests or non-doctest tests, "
714 728 "not both. [NOSE_DOCTEST_TESTS]")
715 729 parser.add_option('--doctest-extension', action="append",
716 730 dest="doctestExtension",
717 731 help="Also look for doctests in files with "
718 732 "this extension [NOSE_DOCTEST_EXTENSION]")
719 733 # Set the default as a list, if given in env; otherwise
720 734 # an additional value set on the command line will cause
721 735 # an error.
722 736 env_setting = env.get('NOSE_DOCTEST_EXTENSION')
723 737 if env_setting is not None:
724 738 parser.set_defaults(doctestExtension=tolist(env_setting))
725 739
726 740
727 741 def configure(self, options, config):
728 742 Plugin.configure(self, options, config)
729 743 self.doctest_tests = options.doctest_tests
730 744 self.extension = tolist(options.doctestExtension)
731 745
732 746 self.parser = doctest.DocTestParser()
733 747 self.finder = DocTestFinder()
734 748 self.checker = IPDoctestOutputChecker()
735 749 self.globs = None
736 750 self.extraglobs = None
737 751
738 752
739 753 def loadTestsFromExtensionModule(self,filename):
740 754 bpath,mod = os.path.split(filename)
741 755 modname = os.path.splitext(mod)[0]
742 756 try:
743 757 sys.path.append(bpath)
744 758 module = __import__(modname)
745 759 tests = list(self.loadTestsFromModule(module))
746 760 finally:
747 761 sys.path.pop()
748 762 return tests
749 763
750 764 # NOTE: the method below is almost a copy of the original one in nose, with
751 765 # a few modifications to control output checking.
752 766
753 767 def loadTestsFromModule(self, module):
754 768 #print '*** ipdoctest - lTM',module # dbg
755 769
756 770 if not self.matches(module.__name__):
757 771 log.debug("Doctest doesn't want module %s", module)
758 772 return
759 773
760 774 tests = self.finder.find(module,globs=self.globs,
761 775 extraglobs=self.extraglobs)
762 776 if not tests:
763 777 return
764 778
765 779 # always use whitespace and ellipsis options
766 780 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
767 781
768 782 tests.sort()
769 783 module_file = module.__file__
770 784 if module_file[-4:] in ('.pyc', '.pyo'):
771 785 module_file = module_file[:-1]
772 786 for test in tests:
773 787 if not test.examples:
774 788 continue
775 789 if not test.filename:
776 790 test.filename = module_file
777 791
778 792 yield DocTestCase(test,
779 793 optionflags=optionflags,
780 794 checker=self.checker)
781 795
782 796
783 797 def loadTestsFromFile(self, filename):
784 798 if is_extension_module(filename):
785 799 for t in self.loadTestsFromExtensionModule(filename):
786 800 yield t
787 801 else:
788 802 if self.extension and anyp(filename.endswith, self.extension):
789 803 name = os.path.basename(filename)
790 804 dh = open(filename)
791 805 try:
792 806 doc = dh.read()
793 807 finally:
794 808 dh.close()
795 809 test = self.parser.get_doctest(
796 810 doc, globs={'__file__': filename}, name=name,
797 811 filename=filename, lineno=0)
798 812 if test.examples:
799 813 #print 'FileCase:',test.examples # dbg
800 814 yield DocFileCase(test)
801 815 else:
802 816 yield False # no tests to load
803 817
804 818 def wantFile(self,filename):
805 819 """Return whether the given filename should be scanned for tests.
806 820
807 821 Modified version that accepts extension modules as valid containers for
808 822 doctests.
809 823 """
810 824 #print '*** ipdoctest- wantFile:',filename # dbg
811 825
812 826 for pat in self.exclude_patterns:
813 827 if pat.search(filename):
814 828 #print '###>>> SKIP:',filename # dbg
815 829 return False
816 830
817 831 if is_extension_module(filename):
818 832 return True
819 833 else:
820 834 return doctests.Doctest.wantFile(self,filename)
821 835
822 836
823 837 class IPythonDoctest(ExtensionDoctest):
824 838 """Nose Plugin that supports doctests in extension modules.
825 839 """
826 840 name = 'ipdoctest' # call nosetests with --with-ipdoctest
827 841 enabled = True
828 842
829 843 def makeTest(self, obj, parent):
830 844 """Look for doctests in the given object, which will be a
831 845 function, method or class.
832 846 """
833 847 # always use whitespace and ellipsis options
834 848 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
835 849
836 850 doctests = self.finder.find(obj, module=getmodule(parent))
837 851 if doctests:
838 852 for test in doctests:
839 853 if len(test.examples) == 0:
840 854 continue
841 855
842 856 yield DocTestCase(test, obj=obj,
843 857 optionflags=optionflags,
844 858 checker=self.checker)
845 859
846 860 def options(self, parser, env=os.environ):
847 861 Plugin.options(self, parser, env)
848 862 parser.add_option('--ipdoctest-tests', action='store_true',
849 863 dest='ipdoctest_tests',
850 864 default=env.get('NOSE_IPDOCTEST_TESTS',True),
851 865 help="Also look for doctests in test modules. "
852 866 "Note that classes, methods and functions should "
853 867 "have either doctests or non-doctest tests, "
854 868 "not both. [NOSE_IPDOCTEST_TESTS]")
855 869 parser.add_option('--ipdoctest-extension', action="append",
856 870 dest="ipdoctest_extension",
857 871 help="Also look for doctests in files with "
858 872 "this extension [NOSE_IPDOCTEST_EXTENSION]")
859 873 # Set the default as a list, if given in env; otherwise
860 874 # an additional value set on the command line will cause
861 875 # an error.
862 876 env_setting = env.get('NOSE_IPDOCTEST_EXTENSION')
863 877 if env_setting is not None:
864 878 parser.set_defaults(ipdoctest_extension=tolist(env_setting))
865 879
866 880 def configure(self, options, config):
867 881 Plugin.configure(self, options, config)
868 882 self.doctest_tests = options.ipdoctest_tests
869 883 self.extension = tolist(options.ipdoctest_extension)
870 884
871 885 self.parser = IPDocTestParser()
872 886 self.finder = DocTestFinder(parser=self.parser)
873 887 self.checker = IPDoctestOutputChecker()
874 888 self.globs = None
875 889 self.extraglobs = None
General Comments 0
You need to be logged in to leave comments. Login now