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