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