##// END OF EJS Templates
Massive amount of work to improve the test suite, restores doctests....
Fernando Perez -
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -0,0 +1,185 b''
1 """Tests for code execution (%run and related), which is particularly tricky.
2
3 Because of how %run manages namespaces, and the fact that we are trying here to
4 verify subtle object deletion and reference counting issues, the %run tests
5 will be kept in this separate file. This makes it easier to aggregate in one
6 place the tricks needed to handle it; most other magics are much easier to test
7 and we do so in a common test_magic file.
8 """
9 from __future__ import absolute_import
10
11 #-----------------------------------------------------------------------------
12 # Imports
13 #-----------------------------------------------------------------------------
14
15 # stdlib
16 import os
17 import sys
18 import tempfile
19
20 # third-party
21 import nose.tools as nt
22
23 # our own
24 from IPython.utils.platutils import find_cmd
25 from IPython.utils import genutils
26 from IPython.testing import decorators as dec
27 from IPython.testing import tools as tt
28
29 #-----------------------------------------------------------------------------
30 # Test functions begin
31 #-----------------------------------------------------------------------------
32
33 def doctest_refbug():
34 """Very nasty problem with references held by multiple runs of a script.
35 See: https://bugs.launchpad.net/ipython/+bug/269966
36
37 In [1]: _ip.clear_main_mod_cache()
38 # random
39
40 In [2]: %run refbug
41
42 In [3]: call_f()
43 lowercased: hello
44
45 In [4]: %run refbug
46
47 In [5]: call_f()
48 lowercased: hello
49 lowercased: hello
50 """
51
52
53 def doctest_run_builtins():
54 r"""Check that %run doesn't damage __builtins__.
55
56 In [1]: import tempfile
57
58 In [2]: bid1 = id(__builtins__)
59
60 In [3]: fname = tempfile.mkstemp('.py')[1]
61
62 In [3]: f = open(fname,'w')
63
64 In [4]: f.write('pass\n')
65
66 In [5]: f.flush()
67
68 In [6]: t1 = type(__builtins__)
69
70 In [7]: %run "$fname"
71
72 In [7]: f.close()
73
74 In [8]: bid2 = id(__builtins__)
75
76 In [9]: t2 = type(__builtins__)
77
78 In [10]: t1 == t2
79 Out[10]: True
80
81 In [10]: bid1 == bid2
82 Out[10]: True
83
84 In [12]: try:
85 ....: os.unlink(fname)
86 ....: except:
87 ....: pass
88 ....:
89 """
90
91 # For some tests, it will be handy to organize them in a class with a common
92 # setup that makes a temp file
93
94 class TempFileMixin(object):
95 def mktmp(self, src, ext='.py'):
96 """Make a valid python temp file."""
97 fname, f = tt.temp_pyfile(src, ext)
98 self.tmpfile = f
99 self.fname = fname
100
101 def teardown(self):
102 self.tmpfile.close()
103 try:
104 os.unlink(self.fname)
105 except:
106 # On Windows, even though we close the file, we still can't delete
107 # it. I have no clue why
108 pass
109
110
111 class TestMagicRunPass(TempFileMixin):
112
113 def setup(self):
114 """Make a valid python temp file."""
115 self.mktmp('pass\n')
116
117 def run_tmpfile(self):
118 _ip = get_ipython()
119 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
120 # See below and ticket https://bugs.launchpad.net/bugs/366353
121 _ip.magic('run "%s"' % self.fname)
122
123 def test_builtins_id(self):
124 """Check that %run doesn't damage __builtins__ """
125 _ip = get_ipython()
126 # Test that the id of __builtins__ is not modified by %run
127 bid1 = id(_ip.user_ns['__builtins__'])
128 self.run_tmpfile()
129 bid2 = id(_ip.user_ns['__builtins__'])
130 tt.assert_equals(bid1, bid2)
131
132 def test_builtins_type(self):
133 """Check that the type of __builtins__ doesn't change with %run.
134
135 However, the above could pass if __builtins__ was already modified to
136 be a dict (it should be a module) by a previous use of %run. So we
137 also check explicitly that it really is a module:
138 """
139 _ip = get_ipython()
140 self.run_tmpfile()
141 tt.assert_equals(type(_ip.user_ns['__builtins__']),type(sys))
142
143 def test_prompts(self):
144 """Test that prompts correctly generate after %run"""
145 self.run_tmpfile()
146 _ip = get_ipython()
147 p2 = str(_ip.outputcache.prompt2).strip()
148 nt.assert_equals(p2[:3], '...')
149
150
151 class TestMagicRunSimple(TempFileMixin):
152
153 def test_simpledef(self):
154 """Test that simple class definitions work."""
155 src = ("class foo: pass\n"
156 "def f(): return foo()")
157 self.mktmp(src)
158 _ip.magic('run "%s"' % self.fname)
159 _ip.runlines('t = isinstance(f(), foo)')
160 nt.assert_true(_ip.user_ns['t'])
161
162 def test_obj_del(self):
163 """Test that object's __del__ methods are called on exit."""
164
165 # This test is known to fail on win32.
166 # See ticket https://bugs.launchpad.net/bugs/366334
167 src = ("class A(object):\n"
168 " def __del__(self):\n"
169 " print 'object A deleted'\n"
170 "a = A()\n")
171 self.mktmp(src)
172 tt.ipexec_validate(self.fname, 'object A deleted')
173
174 def test_tclass(self):
175 mydir = os.path.dirname(__file__)
176 tc = os.path.join(mydir, 'tclass')
177 src = ("%%run '%s' C-first\n"
178 "%%run '%s' C-second\n") % (tc, tc)
179 self.mktmp(src, '.ipy')
180 out = """\
181 ARGV 1-: ['C-first']
182 ARGV 1-: ['C-second']
183 tclass.py: deleting object: C-first
184 """
185 tt.ipexec_validate(self.fname, out)
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
@@ -1,994 +1,994 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 """
4 4 Prefiltering components.
5 5
6 6 Prefilters transform user input before it is exec'd by Python. These
7 7 transforms are used to implement additional syntax such as !ls and %magic.
8 8
9 9 Authors:
10 10
11 11 * Brian Granger
12 12 * Fernando Perez
13 13 * Dan Milstein
14 14 * Ville Vainio
15 15 """
16 16
17 17 #-----------------------------------------------------------------------------
18 18 # Copyright (C) 2008-2009 The IPython Development Team
19 19 #
20 20 # Distributed under the terms of the BSD License. The full license is in
21 21 # the file COPYING, distributed as part of this software.
22 22 #-----------------------------------------------------------------------------
23 23
24 24 #-----------------------------------------------------------------------------
25 25 # Imports
26 26 #-----------------------------------------------------------------------------
27 27
28 28 import __builtin__
29 29 import codeop
30 30 import keyword
31 31 import os
32 32 import re
33 33 import sys
34 34
35 35 from IPython.core.alias import AliasManager
36 36 from IPython.core.autocall import IPyAutocall
37 37 from IPython.core.component import Component
38 38 from IPython.core.splitinput import split_user_input
39 39 from IPython.core.page import page
40 40
41 41 from IPython.utils.traitlets import List, Int, Any, Str, CBool, Bool
42 42 from IPython.utils.genutils import make_quoted_expr, Term
43 43 from IPython.utils.autoattr import auto_attr
44 44
45 45 #-----------------------------------------------------------------------------
46 46 # Global utilities, errors and constants
47 47 #-----------------------------------------------------------------------------
48 48
49 49 # Warning, these cannot be changed unless various regular expressions
50 50 # are updated in a number of places. Not great, but at least we told you.
51 51 ESC_SHELL = '!'
52 52 ESC_SH_CAP = '!!'
53 53 ESC_HELP = '?'
54 54 ESC_MAGIC = '%'
55 55 ESC_QUOTE = ','
56 56 ESC_QUOTE2 = ';'
57 57 ESC_PAREN = '/'
58 58
59 59
60 60 class PrefilterError(Exception):
61 61 pass
62 62
63 63
64 64 # RegExp to identify potential function names
65 65 re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$')
66 66
67 67 # RegExp to exclude strings with this start from autocalling. In
68 68 # particular, all binary operators should be excluded, so that if foo is
69 69 # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
70 70 # characters '!=()' don't need to be checked for, as the checkPythonChars
71 71 # routine explicitely does so, to catch direct calls and rebindings of
72 72 # existing names.
73 73
74 74 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
75 75 # it affects the rest of the group in square brackets.
76 76 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
77 77 r'|^is |^not |^in |^and |^or ')
78 78
79 79 # try to catch also methods for stuff in lists/tuples/dicts: off
80 80 # (experimental). For this to work, the line_split regexp would need
81 81 # to be modified so it wouldn't break things at '['. That line is
82 82 # nasty enough that I shouldn't change it until I can test it _well_.
83 83 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
84 84
85 85
86 86 # Handler Check Utilities
87 87 def is_shadowed(identifier, ip):
88 88 """Is the given identifier defined in one of the namespaces which shadow
89 89 the alias and magic namespaces? Note that an identifier is different
90 90 than ifun, because it can not contain a '.' character."""
91 91 # This is much safer than calling ofind, which can change state
92 92 return (identifier in ip.user_ns \
93 93 or identifier in ip.internal_ns \
94 94 or identifier in ip.ns_table['builtin'])
95 95
96 96
97 97 #-----------------------------------------------------------------------------
98 98 # The LineInfo class used throughout
99 99 #-----------------------------------------------------------------------------
100 100
101 101
102 102 class LineInfo(object):
103 103 """A single line of input and associated info.
104 104
105 105 Includes the following as properties:
106 106
107 107 line
108 108 The original, raw line
109 109
110 110 continue_prompt
111 111 Is this line a continuation in a sequence of multiline input?
112 112
113 113 pre
114 114 The initial esc character or whitespace.
115 115
116 116 pre_char
117 117 The escape character(s) in pre or the empty string if there isn't one.
118 118 Note that '!!' is a possible value for pre_char. Otherwise it will
119 119 always be a single character.
120 120
121 121 pre_whitespace
122 122 The leading whitespace from pre if it exists. If there is a pre_char,
123 123 this is just ''.
124 124
125 125 ifun
126 126 The 'function part', which is basically the maximal initial sequence
127 127 of valid python identifiers and the '.' character. This is what is
128 128 checked for alias and magic transformations, used for auto-calling,
129 129 etc.
130 130
131 131 the_rest
132 132 Everything else on the line.
133 133 """
134 134 def __init__(self, line, continue_prompt):
135 135 self.line = line
136 136 self.continue_prompt = continue_prompt
137 137 self.pre, self.ifun, self.the_rest = split_user_input(line)
138 138
139 139 self.pre_char = self.pre.strip()
140 140 if self.pre_char:
141 141 self.pre_whitespace = '' # No whitespace allowd before esc chars
142 142 else:
143 143 self.pre_whitespace = self.pre
144 144
145 145 self._oinfo = None
146 146
147 147 def ofind(self, ip):
148 148 """Do a full, attribute-walking lookup of the ifun in the various
149 149 namespaces for the given IPython InteractiveShell instance.
150 150
151 151 Return a dict with keys: found,obj,ospace,ismagic
152 152
153 153 Note: can cause state changes because of calling getattr, but should
154 154 only be run if autocall is on and if the line hasn't matched any
155 155 other, less dangerous handlers.
156 156
157 157 Does cache the results of the call, so can be called multiple times
158 158 without worrying about *further* damaging state.
159 159 """
160 160 if not self._oinfo:
161 161 self._oinfo = ip.shell._ofind(self.ifun)
162 162 return self._oinfo
163 163
164 164 def __str__(self):
165 165 return "Lineinfo [%s|%s|%s]" %(self.pre,self.ifun,self.the_rest)
166 166
167 167
168 168 #-----------------------------------------------------------------------------
169 169 # Main Prefilter manager
170 170 #-----------------------------------------------------------------------------
171 171
172 172
173 173 class PrefilterManager(Component):
174 174 """Main prefilter component.
175 175
176 176 The IPython prefilter is run on all user input before it is run. The
177 177 prefilter consumes lines of input and produces transformed lines of
178 178 input.
179 179
180 180 The iplementation consists of two phases:
181 181
182 182 1. Transformers
183 183 2. Checkers and handlers
184 184
185 185 Over time, we plan on deprecating the checkers and handlers and doing
186 186 everything in the transformers.
187 187
188 188 The transformers are instances of :class:`PrefilterTransformer` and have
189 189 a single method :meth:`transform` that takes a line and returns a
190 190 transformed line. The transformation can be accomplished using any
191 191 tool, but our current ones use regular expressions for speed. We also
192 192 ship :mod:`pyparsing` in :mod:`IPython.external` for use in transformers.
193 193
194 194 After all the transformers have been run, the line is fed to the checkers,
195 195 which are instances of :class:`PrefilterChecker`. The line is passed to
196 196 the :meth:`check` method, which either returns `None` or a
197 197 :class:`PrefilterHandler` instance. If `None` is returned, the other
198 198 checkers are tried. If an :class:`PrefilterHandler` instance is returned,
199 199 the line is passed to the :meth:`handle` method of the returned
200 200 handler and no further checkers are tried.
201 201
202 202 Both transformers and checkers have a `priority` attribute, that determines
203 203 the order in which they are called. Smaller priorities are tried first.
204 204
205 205 Both transformers and checkers also have `enabled` attribute, which is
206 206 a boolean that determines if the instance is used.
207 207
208 208 Users or developers can change the priority or enabled attribute of
209 209 transformers or checkers, but they must call the :meth:`sort_checkers`
210 210 or :meth:`sort_transformers` method after changing the priority.
211 211 """
212 212
213 213 multi_line_specials = CBool(True, config=True)
214 214
215 215 def __init__(self, parent, config=None):
216 216 super(PrefilterManager, self).__init__(parent, config=config)
217 217 self.init_transformers()
218 218 self.init_handlers()
219 219 self.init_checkers()
220 220
221 221 @auto_attr
222 222 def shell(self):
223 223 return Component.get_instances(
224 224 root=self.root,
225 225 klass='IPython.core.iplib.InteractiveShell')[0]
226 226
227 227 #-------------------------------------------------------------------------
228 228 # API for managing transformers
229 229 #-------------------------------------------------------------------------
230 230
231 231 def init_transformers(self):
232 232 """Create the default transformers."""
233 233 self._transformers = []
234 234 for transformer_cls in _default_transformers:
235 235 transformer_cls(self, config=self.config)
236 236
237 237 def sort_transformers(self):
238 238 """Sort the transformers by priority.
239 239
240 240 This must be called after the priority of a transformer is changed.
241 241 The :meth:`register_transformer` method calls this automatically.
242 242 """
243 243 self._transformers.sort(cmp=lambda x,y: x.priority-y.priority)
244 244
245 245 @property
246 246 def transformers(self):
247 247 """Return a list of checkers, sorted by priority."""
248 248 return self._transformers
249 249
250 250 def register_transformer(self, transformer):
251 251 """Register a transformer instance."""
252 252 if transformer not in self._transformers:
253 253 self._transformers.append(transformer)
254 254 self.sort_transformers()
255 255
256 256 def unregister_transformer(self, transformer):
257 257 """Unregister a transformer instance."""
258 258 if transformer in self._transformers:
259 259 self._transformers.remove(transformer)
260 260
261 261 #-------------------------------------------------------------------------
262 262 # API for managing checkers
263 263 #-------------------------------------------------------------------------
264 264
265 265 def init_checkers(self):
266 266 """Create the default checkers."""
267 267 self._checkers = []
268 268 for checker in _default_checkers:
269 269 checker(self, config=self.config)
270 270
271 271 def sort_checkers(self):
272 272 """Sort the checkers by priority.
273 273
274 274 This must be called after the priority of a checker is changed.
275 275 The :meth:`register_checker` method calls this automatically.
276 276 """
277 277 self._checkers.sort(cmp=lambda x,y: x.priority-y.priority)
278 278
279 279 @property
280 280 def checkers(self):
281 281 """Return a list of checkers, sorted by priority."""
282 282 return self._checkers
283 283
284 284 def register_checker(self, checker):
285 285 """Register a checker instance."""
286 286 if checker not in self._checkers:
287 287 self._checkers.append(checker)
288 288 self.sort_checkers()
289 289
290 290 def unregister_checker(self, checker):
291 291 """Unregister a checker instance."""
292 292 if checker in self._checkers:
293 293 self._checkers.remove(checker)
294 294
295 295 #-------------------------------------------------------------------------
296 296 # API for managing checkers
297 297 #-------------------------------------------------------------------------
298 298
299 299 def init_handlers(self):
300 300 """Create the default handlers."""
301 301 self._handlers = {}
302 302 self._esc_handlers = {}
303 303 for handler in _default_handlers:
304 304 handler(self, config=self.config)
305 305
306 306 @property
307 307 def handlers(self):
308 308 """Return a dict of all the handlers."""
309 309 return self._handlers
310 310
311 311 def register_handler(self, name, handler, esc_strings):
312 312 """Register a handler instance by name with esc_strings."""
313 313 self._handlers[name] = handler
314 314 for esc_str in esc_strings:
315 315 self._esc_handlers[esc_str] = handler
316 316
317 317 def unregister_handler(self, name, handler, esc_strings):
318 318 """Unregister a handler instance by name with esc_strings."""
319 319 try:
320 320 del self._handlers[name]
321 321 except KeyError:
322 322 pass
323 323 for esc_str in esc_strings:
324 324 h = self._esc_handlers.get(esc_str)
325 325 if h is handler:
326 326 del self._esc_handlers[esc_str]
327 327
328 328 def get_handler_by_name(self, name):
329 329 """Get a handler by its name."""
330 330 return self._handlers.get(name)
331 331
332 332 def get_handler_by_esc(self, esc_str):
333 333 """Get a handler by its escape string."""
334 334 return self._esc_handlers.get(esc_str)
335 335
336 336 #-------------------------------------------------------------------------
337 337 # Main prefiltering API
338 338 #-------------------------------------------------------------------------
339 339
340 340 def prefilter_line_info(self, line_info):
341 341 """Prefilter a line that has been converted to a LineInfo object.
342 342
343 343 This implements the checker/handler part of the prefilter pipe.
344 344 """
345 345 # print "prefilter_line_info: ", line_info
346 346 handler = self.find_handler(line_info)
347 347 return handler.handle(line_info)
348 348
349 349 def find_handler(self, line_info):
350 350 """Find a handler for the line_info by trying checkers."""
351 351 for checker in self.checkers:
352 352 if checker.enabled:
353 353 handler = checker.check(line_info)
354 354 if handler:
355 355 return handler
356 356 return self.get_handler_by_name('normal')
357 357
358 358 def transform_line(self, line, continue_prompt):
359 359 """Calls the enabled transformers in order of increasing priority."""
360 360 for transformer in self.transformers:
361 361 if transformer.enabled:
362 362 line = transformer.transform(line, continue_prompt)
363 363 return line
364 364
365 365 def prefilter_line(self, line, continue_prompt):
366 366 """Prefilter a single input line as text.
367 367
368 368 This method prefilters a single line of text by calling the
369 369 transformers and then the checkers/handlers.
370 370 """
371 371
372 372 # print "prefilter_line: ", line, continue_prompt
373 373 # All handlers *must* return a value, even if it's blank ('').
374 374
375 375 # Lines are NOT logged here. Handlers should process the line as
376 376 # needed, update the cache AND log it (so that the input cache array
377 377 # stays synced).
378 378
379 379 # save the line away in case we crash, so the post-mortem handler can
380 380 # record it
381 381 self.shell._last_input_line = line
382 382
383 383 if not line:
384 384 # Return immediately on purely empty lines, so that if the user
385 385 # previously typed some whitespace that started a continuation
386 386 # prompt, he can break out of that loop with just an empty line.
387 387 # This is how the default python prompt works.
388 388
389 389 # Only return if the accumulated input buffer was just whitespace!
390 390 if ''.join(self.shell.buffer).isspace():
391 391 self.shell.buffer[:] = []
392 392 return ''
393 393
394 394 # At this point, we invoke our transformers.
395 395 if not continue_prompt or (continue_prompt and self.multi_line_specials):
396 396 line = self.transform_line(line, continue_prompt)
397 397
398 398 # Now we compute line_info for the checkers and handlers
399 399 line_info = LineInfo(line, continue_prompt)
400 400
401 401 # the input history needs to track even empty lines
402 402 stripped = line.strip()
403 403
404 404 normal_handler = self.get_handler_by_name('normal')
405 405 if not stripped:
406 406 if not continue_prompt:
407 407 self.shell.outputcache.prompt_count -= 1
408 408
409 409 return normal_handler.handle(line_info)
410 410
411 411 # special handlers are only allowed for single line statements
412 412 if continue_prompt and not self.multi_line_specials:
413 413 return normal_handler.handle(line_info)
414 414
415 415 prefiltered = self.prefilter_line_info(line_info)
416 416 # print "prefiltered line: %r" % prefiltered
417 417 return prefiltered
418 418
419 def prefilter_lines(self, lines, continue_prompt):
419 def prefilter_lines(self, lines, continue_prompt=False):
420 420 """Prefilter multiple input lines of text.
421 421
422 422 This is the main entry point for prefiltering multiple lines of
423 423 input. This simply calls :meth:`prefilter_line` for each line of
424 424 input.
425 425
426 426 This covers cases where there are multiple lines in the user entry,
427 427 which is the case when the user goes back to a multiline history
428 428 entry and presses enter.
429 429 """
430 430 out = []
431 431 for line in lines.rstrip('\n').split('\n'):
432 432 out.append(self.prefilter_line(line, continue_prompt))
433 433 return '\n'.join(out)
434 434
435 435
436 436 #-----------------------------------------------------------------------------
437 437 # Prefilter transformers
438 438 #-----------------------------------------------------------------------------
439 439
440 440
441 441 class PrefilterTransformer(Component):
442 442 """Transform a line of user input."""
443 443
444 444 priority = Int(100, config=True)
445 445 shell = Any
446 446 prefilter_manager = Any
447 447 enabled = Bool(True, config=True)
448 448
449 449 def __init__(self, parent, config=None):
450 450 super(PrefilterTransformer, self).__init__(parent, config=config)
451 451 self.prefilter_manager.register_transformer(self)
452 452
453 453 @auto_attr
454 454 def shell(self):
455 455 return Component.get_instances(
456 456 root=self.root,
457 457 klass='IPython.core.iplib.InteractiveShell')[0]
458 458
459 459 @auto_attr
460 460 def prefilter_manager(self):
461 461 return PrefilterManager.get_instances(root=self.root)[0]
462 462
463 463 def transform(self, line, continue_prompt):
464 464 """Transform a line, returning the new one."""
465 465 return None
466 466
467 467 def __repr__(self):
468 468 return "<%s(priority=%r, enabled=%r)>" % (
469 469 self.__class__.__name__, self.priority, self.enabled)
470 470
471 471
472 472 _assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
473 473 r'\s*=\s*!(?P<cmd>.*)')
474 474
475 475
476 476 class AssignSystemTransformer(PrefilterTransformer):
477 477 """Handle the `files = !ls` syntax."""
478 478
479 479 priority = Int(100, config=True)
480 480
481 481 def transform(self, line, continue_prompt):
482 482 m = _assign_system_re.match(line)
483 483 if m is not None:
484 484 cmd = m.group('cmd')
485 485 lhs = m.group('lhs')
486 486 expr = make_quoted_expr("sc -l =%s" % cmd)
487 487 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
488 488 return new_line
489 489 return line
490 490
491 491
492 492 _assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
493 493 r'\s*=\s*%(?P<cmd>.*)')
494 494
495 495 class AssignMagicTransformer(PrefilterTransformer):
496 496 """Handle the `a = %who` syntax."""
497 497
498 498 priority = Int(200, config=True)
499 499
500 500 def transform(self, line, continue_prompt):
501 501 m = _assign_magic_re.match(line)
502 502 if m is not None:
503 503 cmd = m.group('cmd')
504 504 lhs = m.group('lhs')
505 505 expr = make_quoted_expr(cmd)
506 506 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
507 507 return new_line
508 508 return line
509 509
510 510
511 511 #-----------------------------------------------------------------------------
512 512 # Prefilter checkers
513 513 #-----------------------------------------------------------------------------
514 514
515 515
516 516 class PrefilterChecker(Component):
517 517 """Inspect an input line and return a handler for that line."""
518 518
519 519 priority = Int(100, config=True)
520 520 shell = Any
521 521 prefilter_manager = Any
522 522 enabled = Bool(True, config=True)
523 523
524 524 def __init__(self, parent, config=None):
525 525 super(PrefilterChecker, self).__init__(parent, config=config)
526 526 self.prefilter_manager.register_checker(self)
527 527
528 528 @auto_attr
529 529 def shell(self):
530 530 return Component.get_instances(
531 531 root=self.root,
532 532 klass='IPython.core.iplib.InteractiveShell')[0]
533 533
534 534 @auto_attr
535 535 def prefilter_manager(self):
536 536 return PrefilterManager.get_instances(root=self.root)[0]
537 537
538 538 def check(self, line_info):
539 539 """Inspect line_info and return a handler instance or None."""
540 540 return None
541 541
542 542 def __repr__(self):
543 543 return "<%s(priority=%r, enabled=%r)>" % (
544 544 self.__class__.__name__, self.priority, self.enabled)
545 545
546 546
547 547 class EmacsChecker(PrefilterChecker):
548 548
549 549 priority = Int(100, config=True)
550 550 enabled = Bool(False, config=True)
551 551
552 552 def check(self, line_info):
553 553 "Emacs ipython-mode tags certain input lines."
554 554 if line_info.line.endswith('# PYTHON-MODE'):
555 555 return self.prefilter_manager.get_handler_by_name('emacs')
556 556 else:
557 557 return None
558 558
559 559
560 560 class ShellEscapeChecker(PrefilterChecker):
561 561
562 562 priority = Int(200, config=True)
563 563
564 564 def check(self, line_info):
565 565 if line_info.line.lstrip().startswith(ESC_SHELL):
566 566 return self.prefilter_manager.get_handler_by_name('shell')
567 567
568 568
569 569 class IPyAutocallChecker(PrefilterChecker):
570 570
571 571 priority = Int(300, config=True)
572 572
573 573 def check(self, line_info):
574 574 "Instances of IPyAutocall in user_ns get autocalled immediately"
575 575 obj = self.shell.user_ns.get(line_info.ifun, None)
576 576 if isinstance(obj, IPyAutocall):
577 577 obj.set_ip(self.shell)
578 578 return self.prefilter_manager.get_handler_by_name('auto')
579 579 else:
580 580 return None
581 581
582 582
583 583 class MultiLineMagicChecker(PrefilterChecker):
584 584
585 585 priority = Int(400, config=True)
586 586
587 587 def check(self, line_info):
588 588 "Allow ! and !! in multi-line statements if multi_line_specials is on"
589 589 # Note that this one of the only places we check the first character of
590 590 # ifun and *not* the pre_char. Also note that the below test matches
591 591 # both ! and !!.
592 592 if line_info.continue_prompt \
593 593 and self.prefilter_manager.multi_line_specials:
594 594 if line_info.ifun.startswith(ESC_MAGIC):
595 595 return self.prefilter_manager.get_handler_by_name('magic')
596 596 else:
597 597 return None
598 598
599 599
600 600 class EscCharsChecker(PrefilterChecker):
601 601
602 602 priority = Int(500, config=True)
603 603
604 604 def check(self, line_info):
605 605 """Check for escape character and return either a handler to handle it,
606 606 or None if there is no escape char."""
607 607 if line_info.line[-1] == ESC_HELP \
608 608 and line_info.pre_char != ESC_SHELL \
609 609 and line_info.pre_char != ESC_SH_CAP:
610 610 # the ? can be at the end, but *not* for either kind of shell escape,
611 611 # because a ? can be a vaild final char in a shell cmd
612 612 return self.prefilter_manager.get_handler_by_name('help')
613 613 else:
614 614 # This returns None like it should if no handler exists
615 615 return self.prefilter_manager.get_handler_by_esc(line_info.pre_char)
616 616
617 617
618 618 class AssignmentChecker(PrefilterChecker):
619 619
620 620 priority = Int(600, config=True)
621 621
622 622 def check(self, line_info):
623 623 """Check to see if user is assigning to a var for the first time, in
624 624 which case we want to avoid any sort of automagic / autocall games.
625 625
626 626 This allows users to assign to either alias or magic names true python
627 627 variables (the magic/alias systems always take second seat to true
628 628 python code). E.g. ls='hi', or ls,that=1,2"""
629 629 if line_info.the_rest:
630 630 if line_info.the_rest[0] in '=,':
631 631 return self.prefilter_manager.get_handler_by_name('normal')
632 632 else:
633 633 return None
634 634
635 635
636 636 class AutoMagicChecker(PrefilterChecker):
637 637
638 638 priority = Int(700, config=True)
639 639
640 640 def check(self, line_info):
641 641 """If the ifun is magic, and automagic is on, run it. Note: normal,
642 642 non-auto magic would already have been triggered via '%' in
643 643 check_esc_chars. This just checks for automagic. Also, before
644 644 triggering the magic handler, make sure that there is nothing in the
645 645 user namespace which could shadow it."""
646 646 if not self.shell.automagic or not hasattr(self.shell,'magic_'+line_info.ifun):
647 647 return None
648 648
649 649 # We have a likely magic method. Make sure we should actually call it.
650 650 if line_info.continue_prompt and not self.shell.multi_line_specials:
651 651 return None
652 652
653 653 head = line_info.ifun.split('.',1)[0]
654 654 if is_shadowed(head, self.shell):
655 655 return None
656 656
657 657 return self.prefilter_manager.get_handler_by_name('magic')
658 658
659 659
660 660 class AliasChecker(PrefilterChecker):
661 661
662 662 priority = Int(800, config=True)
663 663
664 664 @auto_attr
665 665 def alias_manager(self):
666 666 return AliasManager.get_instances(root=self.root)[0]
667 667
668 668 def check(self, line_info):
669 669 "Check if the initital identifier on the line is an alias."
670 670 # Note: aliases can not contain '.'
671 671 head = line_info.ifun.split('.',1)[0]
672 672 if line_info.ifun not in self.alias_manager \
673 673 or head not in self.alias_manager \
674 674 or is_shadowed(head, self.shell):
675 675 return None
676 676
677 677 return self.prefilter_manager.get_handler_by_name('alias')
678 678
679 679
680 680 class PythonOpsChecker(PrefilterChecker):
681 681
682 682 priority = Int(900, config=True)
683 683
684 684 def check(self, line_info):
685 685 """If the 'rest' of the line begins with a function call or pretty much
686 686 any python operator, we should simply execute the line (regardless of
687 687 whether or not there's a possible autocall expansion). This avoids
688 688 spurious (and very confusing) geattr() accesses."""
689 689 if line_info.the_rest and line_info.the_rest[0] in '!=()<>,+*/%^&|':
690 690 return self.prefilter_manager.get_handler_by_name('normal')
691 691 else:
692 692 return None
693 693
694 694
695 695 class AutocallChecker(PrefilterChecker):
696 696
697 697 priority = Int(1000, config=True)
698 698
699 699 def check(self, line_info):
700 700 "Check if the initial word/function is callable and autocall is on."
701 701 if not self.shell.autocall:
702 702 return None
703 703
704 704 oinfo = line_info.ofind(self.shell) # This can mutate state via getattr
705 705 if not oinfo['found']:
706 706 return None
707 707
708 708 if callable(oinfo['obj']) \
709 709 and (not re_exclude_auto.match(line_info.the_rest)) \
710 710 and re_fun_name.match(line_info.ifun):
711 711 return self.prefilter_manager.get_handler_by_name('auto')
712 712 else:
713 713 return None
714 714
715 715
716 716 #-----------------------------------------------------------------------------
717 717 # Prefilter handlers
718 718 #-----------------------------------------------------------------------------
719 719
720 720
721 721 class PrefilterHandler(Component):
722 722
723 723 handler_name = Str('normal')
724 724 esc_strings = List([])
725 725 shell = Any
726 726 prefilter_manager = Any
727 727
728 728 def __init__(self, parent, config=None):
729 729 super(PrefilterHandler, self).__init__(parent, config=config)
730 730 self.prefilter_manager.register_handler(
731 731 self.handler_name,
732 732 self,
733 733 self.esc_strings
734 734 )
735 735
736 736 @auto_attr
737 737 def shell(self):
738 738 return Component.get_instances(
739 739 root=self.root,
740 740 klass='IPython.core.iplib.InteractiveShell')[0]
741 741
742 742 @auto_attr
743 743 def prefilter_manager(self):
744 744 return PrefilterManager.get_instances(root=self.root)[0]
745 745
746 746 def handle(self, line_info):
747 747 # print "normal: ", line_info
748 748 """Handle normal input lines. Use as a template for handlers."""
749 749
750 750 # With autoindent on, we need some way to exit the input loop, and I
751 751 # don't want to force the user to have to backspace all the way to
752 752 # clear the line. The rule will be in this case, that either two
753 753 # lines of pure whitespace in a row, or a line of pure whitespace but
754 754 # of a size different to the indent level, will exit the input loop.
755 755 line = line_info.line
756 756 continue_prompt = line_info.continue_prompt
757 757
758 758 if (continue_prompt and self.shell.autoindent and line.isspace() and
759 759 (0 < abs(len(line) - self.shell.indent_current_nsp) <= 2 or
760 760 (self.shell.buffer[-1]).isspace() )):
761 761 line = ''
762 762
763 763 self.shell.log(line, line, continue_prompt)
764 764 return line
765 765
766 766 def __str__(self):
767 767 return "<%s(name=%s)>" % (self.__class__.__name__, self.handler_name)
768 768
769 769
770 770 class AliasHandler(PrefilterHandler):
771 771
772 772 handler_name = Str('alias')
773 773
774 774 @auto_attr
775 775 def alias_manager(self):
776 776 return AliasManager.get_instances(root=self.root)[0]
777 777
778 778 def handle(self, line_info):
779 779 """Handle alias input lines. """
780 780 transformed = self.alias_manager.expand_aliases(line_info.ifun,line_info.the_rest)
781 781 # pre is needed, because it carries the leading whitespace. Otherwise
782 782 # aliases won't work in indented sections.
783 783 line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace,
784 784 make_quoted_expr(transformed))
785 785
786 786 self.shell.log(line_info.line, line_out, line_info.continue_prompt)
787 787 return line_out
788 788
789 789
790 790 class ShellEscapeHandler(PrefilterHandler):
791 791
792 792 handler_name = Str('shell')
793 793 esc_strings = List([ESC_SHELL, ESC_SH_CAP])
794 794
795 795 def handle(self, line_info):
796 796 """Execute the line in a shell, empty return value"""
797 797 magic_handler = self.prefilter_manager.get_handler_by_name('magic')
798 798
799 799 line = line_info.line
800 800 if line.lstrip().startswith(ESC_SH_CAP):
801 801 # rewrite LineInfo's line, ifun and the_rest to properly hold the
802 802 # call to %sx and the actual command to be executed, so
803 803 # handle_magic can work correctly. Note that this works even if
804 804 # the line is indented, so it handles multi_line_specials
805 805 # properly.
806 806 new_rest = line.lstrip()[2:]
807 807 line_info.line = '%ssx %s' % (ESC_MAGIC, new_rest)
808 808 line_info.ifun = 'sx'
809 809 line_info.the_rest = new_rest
810 810 return magic_handler.handle(line_info)
811 811 else:
812 812 cmd = line.lstrip().lstrip(ESC_SHELL)
813 813 line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace,
814 814 make_quoted_expr(cmd))
815 815 # update cache/log and return
816 816 self.shell.log(line, line_out, line_info.continue_prompt)
817 817 return line_out
818 818
819 819
820 820 class MagicHandler(PrefilterHandler):
821 821
822 822 handler_name = Str('magic')
823 823 esc_strings = List([ESC_MAGIC])
824 824
825 825 def handle(self, line_info):
826 826 """Execute magic functions."""
827 827 ifun = line_info.ifun
828 828 the_rest = line_info.the_rest
829 829 cmd = '%sget_ipython().magic(%s)' % (line_info.pre_whitespace,
830 830 make_quoted_expr(ifun + " " + the_rest))
831 831 self.shell.log(line_info.line, cmd, line_info.continue_prompt)
832 832 return cmd
833 833
834 834
835 835 class AutoHandler(PrefilterHandler):
836 836
837 837 handler_name = Str('auto')
838 838 esc_strings = List([ESC_PAREN, ESC_QUOTE, ESC_QUOTE2])
839 839
840 840 def handle(self, line_info):
841 841 """Hande lines which can be auto-executed, quoting if requested."""
842 842 line = line_info.line
843 843 ifun = line_info.ifun
844 844 the_rest = line_info.the_rest
845 845 pre = line_info.pre
846 846 continue_prompt = line_info.continue_prompt
847 847 obj = line_info.ofind(self)['obj']
848 848 #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun,the_rest) # dbg
849 849
850 850 # This should only be active for single-line input!
851 851 if continue_prompt:
852 852 self.shell.log(line,line,continue_prompt)
853 853 return line
854 854
855 855 force_auto = isinstance(obj, IPyAutocall)
856 856 auto_rewrite = True
857 857
858 858 if pre == ESC_QUOTE:
859 859 # Auto-quote splitting on whitespace
860 860 newcmd = '%s("%s")' % (ifun,'", "'.join(the_rest.split()) )
861 861 elif pre == ESC_QUOTE2:
862 862 # Auto-quote whole string
863 863 newcmd = '%s("%s")' % (ifun,the_rest)
864 864 elif pre == ESC_PAREN:
865 865 newcmd = '%s(%s)' % (ifun,",".join(the_rest.split()))
866 866 else:
867 867 # Auto-paren.
868 868 # We only apply it to argument-less calls if the autocall
869 869 # parameter is set to 2. We only need to check that autocall is <
870 870 # 2, since this function isn't called unless it's at least 1.
871 871 if not the_rest and (self.shell.autocall < 2) and not force_auto:
872 872 newcmd = '%s %s' % (ifun,the_rest)
873 873 auto_rewrite = False
874 874 else:
875 875 if not force_auto and the_rest.startswith('['):
876 876 if hasattr(obj,'__getitem__'):
877 877 # Don't autocall in this case: item access for an object
878 878 # which is BOTH callable and implements __getitem__.
879 879 newcmd = '%s %s' % (ifun,the_rest)
880 880 auto_rewrite = False
881 881 else:
882 882 # if the object doesn't support [] access, go ahead and
883 883 # autocall
884 884 newcmd = '%s(%s)' % (ifun.rstrip(),the_rest)
885 885 elif the_rest.endswith(';'):
886 886 newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1])
887 887 else:
888 888 newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
889 889
890 890 if auto_rewrite:
891 891 rw = self.shell.outputcache.prompt1.auto_rewrite() + newcmd
892 892
893 893 try:
894 894 # plain ascii works better w/ pyreadline, on some machines, so
895 895 # we use it and only print uncolored rewrite if we have unicode
896 896 rw = str(rw)
897 897 print >>Term.cout, rw
898 898 except UnicodeEncodeError:
899 899 print "-------------->" + newcmd
900 900
901 901 # log what is now valid Python, not the actual user input (without the
902 902 # final newline)
903 903 self.shell.log(line,newcmd,continue_prompt)
904 904 return newcmd
905 905
906 906
907 907 class HelpHandler(PrefilterHandler):
908 908
909 909 handler_name = Str('help')
910 910 esc_strings = List([ESC_HELP])
911 911
912 912 def handle(self, line_info):
913 913 """Try to get some help for the object.
914 914
915 915 obj? or ?obj -> basic information.
916 916 obj?? or ??obj -> more details.
917 917 """
918 918 normal_handler = self.prefilter_manager.get_handler_by_name('normal')
919 919 line = line_info.line
920 920 # We need to make sure that we don't process lines which would be
921 921 # otherwise valid python, such as "x=1 # what?"
922 922 try:
923 923 codeop.compile_command(line)
924 924 except SyntaxError:
925 925 # We should only handle as help stuff which is NOT valid syntax
926 926 if line[0]==ESC_HELP:
927 927 line = line[1:]
928 928 elif line[-1]==ESC_HELP:
929 929 line = line[:-1]
930 930 self.shell.log(line, '#?'+line, line_info.continue_prompt)
931 931 if line:
932 932 #print 'line:<%r>' % line # dbg
933 933 self.shell.magic_pinfo(line)
934 934 else:
935 935 page(self.shell.usage, screen_lines=self.shell.usable_screen_length)
936 936 return '' # Empty string is needed here!
937 937 except:
938 938 raise
939 939 # Pass any other exceptions through to the normal handler
940 940 return normal_handler.handle(line_info)
941 941 else:
942 942 raise
943 943 # If the code compiles ok, we should handle it normally
944 944 return normal_handler.handle(line_info)
945 945
946 946
947 947 class EmacsHandler(PrefilterHandler):
948 948
949 949 handler_name = Str('emacs')
950 950 esc_strings = List([])
951 951
952 952 def handle(self, line_info):
953 953 """Handle input lines marked by python-mode."""
954 954
955 955 # Currently, nothing is done. Later more functionality can be added
956 956 # here if needed.
957 957
958 958 # The input cache shouldn't be updated
959 959 return line_info.line
960 960
961 961
962 962 #-----------------------------------------------------------------------------
963 963 # Defaults
964 964 #-----------------------------------------------------------------------------
965 965
966 966
967 967 _default_transformers = [
968 968 AssignSystemTransformer,
969 969 AssignMagicTransformer
970 970 ]
971 971
972 972 _default_checkers = [
973 973 EmacsChecker,
974 974 ShellEscapeChecker,
975 975 IPyAutocallChecker,
976 976 MultiLineMagicChecker,
977 977 EscCharsChecker,
978 978 AssignmentChecker,
979 979 AutoMagicChecker,
980 980 AliasChecker,
981 981 PythonOpsChecker,
982 982 AutocallChecker
983 983 ]
984 984
985 985 _default_handlers = [
986 986 PrefilterHandler,
987 987 AliasHandler,
988 988 ShellEscapeHandler,
989 989 MagicHandler,
990 990 AutoHandler,
991 991 HelpHandler,
992 992 EmacsHandler
993 993 ]
994 994
@@ -1,27 +1,29 b''
1 """Simple script to instantiate a class for testing %run"""
1 """Simple script to be run *twice*, to check reference counting bugs.
2 2
3 import sys
4
5 # An external test will check that calls to f() work after %run
6 class foo: pass
3 See test_run for details."""
7 4
8 def f():
9 return foo()
5 import sys
10 6
11 # We also want to ensure that while objects remain available for immediate
12 # access, objects from *previous* runs of the same script get collected, to
13 # avoid accumulating massive amounts of old references.
7 # We want to ensure that while objects remain available for immediate access,
8 # objects from *previous* runs of the same script get collected, to avoid
9 # accumulating massive amounts of old references.
14 10 class C(object):
15 11 def __init__(self,name):
16 12 self.name = name
17 13
18 14 def __del__(self):
19 15 print 'tclass.py: deleting object:',self.name
20 16
17
21 18 try:
22 19 name = sys.argv[1]
23 20 except IndexError:
24 21 pass
25 22 else:
26 23 if name.startswith('C'):
27 24 c = C(name)
25
26 #print >> sys.stderr, "ARGV:", sys.argv # dbg
27 # This print statement is NOT debugging, we're making the check on a completely
28 # separate process so we verify by capturing stdout.
29 print 'ARGV 1-:', sys.argv[1:]
@@ -1,347 +1,191 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 from __future__ import absolute_import
5 6
7 #-----------------------------------------------------------------------------
8 # Imports
9 #-----------------------------------------------------------------------------
10
11 # stdlib
6 12 import os
7 13 import sys
8 14 import tempfile
9 15 import types
10 16 from cStringIO import StringIO
11 17
18 # third-party
12 19 import nose.tools as nt
13 20
21 # our own
22 from IPython.utils import genutils
14 23 from IPython.utils.platutils import find_cmd, get_long_path_name
15 24 from IPython.testing import decorators as dec
16 25 from IPython.testing import tools as tt
17 26
18 27 #-----------------------------------------------------------------------------
19 28 # Test functions begin
29 #-----------------------------------------------------------------------------
20 30
21 31 def test_rehashx():
22 32 # clear up everything
23 33 _ip = get_ipython()
24 34 _ip.alias_manager.alias_table.clear()
25 35 del _ip.db['syscmdlist']
26 36
27 37 _ip.magic('rehashx')
28 38 # Practically ALL ipython development systems will have more than 10 aliases
29 39
30 40 yield (nt.assert_true, len(_ip.alias_manager.alias_table) > 10)
31 41 for key, val in _ip.alias_manager.alias_table.items():
32 42 # we must strip dots from alias names
33 43 nt.assert_true('.' not in key)
34 44
35 45 # rehashx must fill up syscmdlist
36 46 scoms = _ip.db['syscmdlist']
37 47 yield (nt.assert_true, len(scoms) > 10)
38 48
39 49
40 50 def doctest_hist_f():
41 51 """Test %hist -f with temporary filename.
42 52
43 53 In [9]: import tempfile
44 54
45 55 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
46 56
47 57 In [11]: %hist -n -f $tfile 3
48 58 """
49 59
50 60
51 61 def doctest_hist_r():
52 62 """Test %hist -r
53 63
54 64 XXX - This test is not recording the output correctly. Not sure why...
55 65
56 66 In [20]: 'hist' in _ip.lsmagic()
57 67 Out[20]: True
58 68
59 69 In [6]: x=1
60 70
61 71 In [7]: %hist -n -r 2
62 72 x=1 # random
63 73 hist -n -r 2 # random
64 74 """
65 75
66 # This test is known to fail on win32.
67 # See ticket https://bugs.launchpad.net/bugs/366334
68 def test_obj_del():
69 _ip = get_ipython()
70 """Test that object's __del__ methods are called on exit."""
71 test_dir = os.path.dirname(__file__)
72 del_file = os.path.join(test_dir,'obj_del.py')
73 ipython_cmd = find_cmd('ipython')
74 out = _ip.getoutput('%s %s' % (ipython_cmd, del_file))
75 nt.assert_equals(out,'obj_del.py: object A deleted')
76
77 76
78 77 def test_shist():
79 78 # Simple tests of ShadowHist class - test generator.
80 79 import os, shutil, tempfile
81 80
82 81 from IPython.utils import pickleshare
83 82 from IPython.core.history import ShadowHist
84 83
85 84 tfile = tempfile.mktemp('','tmp-ipython-')
86 85
87 86 db = pickleshare.PickleShareDB(tfile)
88 87 s = ShadowHist(db)
89 88 s.add('hello')
90 89 s.add('world')
91 90 s.add('hello')
92 91 s.add('hello')
93 92 s.add('karhu')
94 93
95 94 yield nt.assert_equals,s.all(),[(1, 'hello'), (2, 'world'), (3, 'karhu')]
96 95
97 96 yield nt.assert_equal,s.get(2),'world'
98 97
99 98 shutil.rmtree(tfile)
100 99
101 100
102 101 # XXX failing for now, until we get clearcmd out of quarantine. But we should
103 102 # fix this and revert the skip to happen only if numpy is not around.
104 103 #@dec.skipif_not_numpy
105 104 @dec.skipknownfailure
106 105 def test_numpy_clear_array_undec():
107 106 from IPython.extensions import clearcmd
108 107
109 108 _ip.ex('import numpy as np')
110 109 _ip.ex('a = np.empty(2)')
111 110 yield (nt.assert_true, 'a' in _ip.user_ns)
112 111 _ip.magic('clear array')
113 112 yield (nt.assert_false, 'a' in _ip.user_ns)
114 113
115 114
116 @dec.skip()
117 def test_fail_dec(*a,**k):
118 yield nt.assert_true, False
119
120 @dec.skip('This one shouldn not run')
121 def test_fail_dec2(*a,**k):
122 yield nt.assert_true, False
123
124 @dec.skipknownfailure
125 def test_fail_dec3(*a,**k):
126 yield nt.assert_true, False
127
128
129 def doctest_refbug():
130 """Very nasty problem with references held by multiple runs of a script.
131 See: https://bugs.launchpad.net/ipython/+bug/269966
132
133 In [1]: _ip.clear_main_mod_cache()
134
135 In [2]: run refbug
136
137 In [3]: call_f()
138 lowercased: hello
139
140 In [4]: run refbug
141
142 In [5]: call_f()
143 lowercased: hello
144 lowercased: hello
145 """
146
147 #-----------------------------------------------------------------------------
148 # Tests for %run
149 #-----------------------------------------------------------------------------
150
151 # %run is critical enough that it's a good idea to have a solid collection of
152 # tests for it, some as doctests and some as normal tests.
153
154 def doctest_run_ns():
155 """Classes declared %run scripts must be instantiable afterwards.
156
157 In [11]: run tclass foo
158
159 In [12]: isinstance(f(),foo)
160 Out[12]: True
161 """
162
163
164 def doctest_run_ns2():
165 """Classes declared %run scripts must be instantiable afterwards.
166
167 In [4]: run tclass C-first_pass
168
169 In [5]: run tclass C-second_pass
170 tclass.py: deleting object: C-first_pass
171 """
172
173 def doctest_run_builtins():
174 """Check that %run doesn't damage __builtins__ via a doctest.
175
176 This is similar to the test_run_builtins, but I want *both* forms of the
177 test to catch any possible glitches in our testing machinery, since that
178 modifies %run somewhat. So for this, we have both a normal test (below)
179 and a doctest (this one).
180
181 In [1]: import tempfile
182
183 In [2]: bid1 = id(__builtins__)
184
185 In [3]: fname = tempfile.mkstemp()[1]
186
187 In [3]: f = open(fname,'w')
188
189 In [4]: f.write('pass\\n')
190
191 In [5]: f.flush()
192
193 In [6]: print type(__builtins__)
194 <type 'module'>
195
196 In [7]: %run "$fname"
197
198 In [7]: f.close()
199
200 In [8]: bid2 = id(__builtins__)
201
202 In [9]: print type(__builtins__)
203 <type 'module'>
204
205 In [10]: bid1 == bid2
206 Out[10]: True
207
208 In [12]: try:
209 ....: os.unlink(fname)
210 ....: except:
211 ....: pass
212 ....:
213 """
214
215 # For some tests, it will be handy to organize them in a class with a common
216 # setup that makes a temp file
217
218 class TestMagicRun(object):
219
220 def setup(self):
221 """Make a valid python temp file."""
222 fname = tempfile.mkstemp('.py')[1]
223 f = open(fname,'w')
224 f.write('pass\n')
225 f.flush()
226 self.tmpfile = f
227 self.fname = fname
228
229 def run_tmpfile(self):
230 _ip = get_ipython()
231 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
232 # See below and ticket https://bugs.launchpad.net/bugs/366353
233 _ip.magic('run "%s"' % self.fname)
234
235 def test_builtins_id(self):
236 """Check that %run doesn't damage __builtins__ """
237 _ip = get_ipython()
238 # Test that the id of __builtins__ is not modified by %run
239 bid1 = id(_ip.user_ns['__builtins__'])
240 self.run_tmpfile()
241 bid2 = id(_ip.user_ns['__builtins__'])
242 tt.assert_equals(bid1, bid2)
243
244 def test_builtins_type(self):
245 """Check that the type of __builtins__ doesn't change with %run.
246
247 However, the above could pass if __builtins__ was already modified to
248 be a dict (it should be a module) by a previous use of %run. So we
249 also check explicitly that it really is a module:
250 """
251 _ip = get_ipython()
252 self.run_tmpfile()
253 tt.assert_equals(type(_ip.user_ns['__builtins__']),type(sys))
254
255 def test_prompts(self):
256 """Test that prompts correctly generate after %run"""
257 self.run_tmpfile()
258 _ip = get_ipython()
259 p2 = str(_ip.outputcache.prompt2).strip()
260 nt.assert_equals(p2[:3], '...')
261
262 def teardown(self):
263 self.tmpfile.close()
264 try:
265 os.unlink(self.fname)
266 except:
267 # On Windows, even though we close the file, we still can't delete
268 # it. I have no clue why
269 pass
270
271 115 # Multiple tests for clipboard pasting
272 116 @dec.parametric
273 117 def test_paste():
274 118 _ip = get_ipython()
275 119 def paste(txt, flags='-q'):
276 120 """Paste input text, by default in quiet mode"""
277 121 hooks.clipboard_get = lambda : txt
278 122 _ip.magic('paste '+flags)
279 123
280 124 # Inject fake clipboard hook but save original so we can restore it later
281 125 hooks = _ip.hooks
282 126 user_ns = _ip.user_ns
283 127 original_clip = hooks.clipboard_get
284 128
285 129 try:
286 130 # This try/except with an emtpy except clause is here only because
287 131 # try/yield/finally is invalid syntax in Python 2.4. This will be
288 132 # removed when we drop 2.4-compatibility, and the emtpy except below
289 133 # will be changed to a finally.
290 134
291 135 # Run tests with fake clipboard function
292 136 user_ns.pop('x', None)
293 137 paste('x=1')
294 138 yield nt.assert_equal(user_ns['x'], 1)
295 139
296 140 user_ns.pop('x', None)
297 141 paste('>>> x=2')
298 142 yield nt.assert_equal(user_ns['x'], 2)
299 143
300 144 paste("""
301 145 >>> x = [1,2,3]
302 146 >>> y = []
303 147 >>> for i in x:
304 148 ... y.append(i**2)
305 149 ...
306 150 """)
307 151 yield nt.assert_equal(user_ns['x'], [1,2,3])
308 152 yield nt.assert_equal(user_ns['y'], [1,4,9])
309 153
310 154 # Now, test that paste -r works
311 155 user_ns.pop('x', None)
312 156 yield nt.assert_false('x' in user_ns)
313 157 _ip.magic('paste -r')
314 158 yield nt.assert_equal(user_ns['x'], [1,2,3])
315 159
316 160 # Also test paste echoing, by temporarily faking the writer
317 161 w = StringIO()
318 162 writer = _ip.write
319 163 _ip.write = w.write
320 164 code = """
321 165 a = 100
322 166 b = 200"""
323 167 try:
324 168 paste(code,'')
325 169 out = w.getvalue()
326 170 finally:
327 171 _ip.write = writer
328 172 yield nt.assert_equal(user_ns['a'], 100)
329 173 yield nt.assert_equal(user_ns['b'], 200)
330 174 yield nt.assert_equal(out, code+"\n## -- End pasted text --\n")
331 175
332 176 finally:
333 177 # This should be in a finally clause, instead of the bare except above.
334 178 # Restore original hook
335 179 hooks.clipboard_get = original_clip
336 180
337 181
338 182 def test_time():
339 183 _ip.magic('time None')
340 184
341 185
342 186 def doctest_time():
343 187 """
344 188 In [10]: %time None
345 189 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
346 190 Wall time: 0.00 s
347 191 """
@@ -1,310 +1,313 b''
1 1 """Decorators for labeling test objects.
2 2
3 3 Decorators that merely return a modified version of the original function
4 4 object are straightforward. Decorators that return a new function object need
5 5 to use nose.tools.make_decorator(original_function)(decorator) in returning the
6 6 decorator, in order to preserve metadata such as function name, setup and
7 7 teardown functions and so on - see nose.tools for more information.
8 8
9 9 This module provides a set of useful decorators meant to be ready to use in
10 10 your own tests. See the bottom of the file for the ready-made ones, and if you
11 11 find yourself writing a new one that may be of generic use, add it here.
12 12
13 13 Included decorators:
14 14
15 15
16 16 Lightweight testing that remains unittest-compatible.
17 17
18 18 - @parametric, for parametric test support that is vastly easier to use than
19 19 nose's for debugging. With ours, if a test fails, the stack under inspection
20 20 is that of the test and not that of the test framework.
21 21
22 22 - An @as_unittest decorator can be used to tag any normal parameter-less
23 23 function as a unittest TestCase. Then, both nose and normal unittest will
24 24 recognize it as such. This will make it easier to migrate away from Nose if
25 25 we ever need/want to while maintaining very lightweight tests.
26 26
27 27 NOTE: This file contains IPython-specific decorators and imports the
28 28 numpy.testing.decorators file, which we've copied verbatim. Any of our own
29 29 code will be added at the bottom if we end up extending this.
30 30
31 31 Authors
32 32 -------
33 33
34 34 - Fernando Perez <Fernando.Perez@berkeley.edu>
35 35 """
36 36
37 37 #-----------------------------------------------------------------------------
38 38 # Copyright (C) 2009-2010 The IPython Development Team
39 39 #
40 40 # Distributed under the terms of the BSD License. The full license is in
41 41 # the file COPYING, distributed as part of this software.
42 42 #-----------------------------------------------------------------------------
43 43
44 44 #-----------------------------------------------------------------------------
45 45 # Imports
46 46 #-----------------------------------------------------------------------------
47 47
48 48 # Stdlib imports
49 49 import inspect
50 50 import sys
51 51 import unittest
52 52
53 53 # Third-party imports
54 54
55 55 # This is Michele Simionato's decorator module, kept verbatim.
56 56 from IPython.external.decorator import decorator, update_wrapper
57 57
58 58 # Our own modules
59 59 import nosepatch # monkeypatch nose
60 60
61 61 # We already have python3-compliant code for parametric tests
62 62 if sys.version[0]=='2':
63 63 from _paramtestpy2 import parametric
64 64 else:
65 65 from _paramtestpy3 import parametric
66 66
67 # Expose the unittest-driven decorators
68 from ipunittest import ipdoctest, ipdocstring
69
67 70 # Grab the numpy-specific decorators which we keep in a file that we
68 71 # occasionally update from upstream: decorators.py is a copy of
69 72 # numpy.testing.decorators, we expose all of it here.
70 73 from IPython.external.decorators import *
71 74
72 75 #-----------------------------------------------------------------------------
73 76 # Classes and functions
74 77 #-----------------------------------------------------------------------------
75 78
76 79 # Simple example of the basic idea
77 80 def as_unittest(func):
78 81 """Decorator to make a simple function into a normal test via unittest."""
79 82 class Tester(unittest.TestCase):
80 83 def test(self):
81 84 func()
82 85
83 86 Tester.__name__ = func.__name__
84 87
85 88 return Tester
86 89
87 90 # Utility functions
88 91
89 92 def apply_wrapper(wrapper,func):
90 93 """Apply a wrapper to a function for decoration.
91 94
92 95 This mixes Michele Simionato's decorator tool with nose's make_decorator,
93 96 to apply a wrapper in a decorator so that all nose attributes, as well as
94 97 function signature and other properties, survive the decoration cleanly.
95 98 This will ensure that wrapped functions can still be well introspected via
96 99 IPython, for example.
97 100 """
98 101 import nose.tools
99 102
100 103 return decorator(wrapper,nose.tools.make_decorator(func)(wrapper))
101 104
102 105
103 106 def make_label_dec(label,ds=None):
104 107 """Factory function to create a decorator that applies one or more labels.
105 108
106 109 Parameters
107 110 ----------
108 111 label : string or sequence
109 112 One or more labels that will be applied by the decorator to the functions
110 113 it decorates. Labels are attributes of the decorated function with their
111 114 value set to True.
112 115
113 116 ds : string
114 117 An optional docstring for the resulting decorator. If not given, a
115 118 default docstring is auto-generated.
116 119
117 120 Returns
118 121 -------
119 122 A decorator.
120 123
121 124 Examples
122 125 --------
123 126
124 127 A simple labeling decorator:
125 128 >>> slow = make_label_dec('slow')
126 129 >>> print slow.__doc__
127 130 Labels a test as 'slow'.
128 131
129 132 And one that uses multiple labels and a custom docstring:
130 133 >>> rare = make_label_dec(['slow','hard'],
131 134 ... "Mix labels 'slow' and 'hard' for rare tests.")
132 135 >>> print rare.__doc__
133 136 Mix labels 'slow' and 'hard' for rare tests.
134 137
135 138 Now, let's test using this one:
136 139 >>> @rare
137 140 ... def f(): pass
138 141 ...
139 142 >>>
140 143 >>> f.slow
141 144 True
142 145 >>> f.hard
143 146 True
144 147 """
145 148
146 149 if isinstance(label,basestring):
147 150 labels = [label]
148 151 else:
149 152 labels = label
150 153
151 154 # Validate that the given label(s) are OK for use in setattr() by doing a
152 155 # dry run on a dummy function.
153 156 tmp = lambda : None
154 157 for label in labels:
155 158 setattr(tmp,label,True)
156 159
157 160 # This is the actual decorator we'll return
158 161 def decor(f):
159 162 for label in labels:
160 163 setattr(f,label,True)
161 164 return f
162 165
163 166 # Apply the user's docstring, or autogenerate a basic one
164 167 if ds is None:
165 168 ds = "Labels a test as %r." % label
166 169 decor.__doc__ = ds
167 170
168 171 return decor
169 172
170 173
171 174 # Inspired by numpy's skipif, but uses the full apply_wrapper utility to
172 175 # preserve function metadata better and allows the skip condition to be a
173 176 # callable.
174 177 def skipif(skip_condition, msg=None):
175 178 ''' Make function raise SkipTest exception if skip_condition is true
176 179
177 180 Parameters
178 181 ----------
179 182 skip_condition : bool or callable.
180 183 Flag to determine whether to skip test. If the condition is a
181 184 callable, it is used at runtime to dynamically make the decision. This
182 185 is useful for tests that may require costly imports, to delay the cost
183 186 until the test suite is actually executed.
184 187 msg : string
185 188 Message to give on raising a SkipTest exception
186 189
187 190 Returns
188 191 -------
189 192 decorator : function
190 193 Decorator, which, when applied to a function, causes SkipTest
191 194 to be raised when the skip_condition was True, and the function
192 195 to be called normally otherwise.
193 196
194 197 Notes
195 198 -----
196 199 You will see from the code that we had to further decorate the
197 200 decorator with the nose.tools.make_decorator function in order to
198 201 transmit function name, and various other metadata.
199 202 '''
200 203
201 204 def skip_decorator(f):
202 205 # Local import to avoid a hard nose dependency and only incur the
203 206 # import time overhead at actual test-time.
204 207 import nose
205 208
206 209 # Allow for both boolean or callable skip conditions.
207 210 if callable(skip_condition):
208 211 skip_val = lambda : skip_condition()
209 212 else:
210 213 skip_val = lambda : skip_condition
211 214
212 215 def get_msg(func,msg=None):
213 216 """Skip message with information about function being skipped."""
214 217 if msg is None: out = 'Test skipped due to test condition.'
215 218 else: out = msg
216 219 return "Skipping test: %s. %s" % (func.__name__,out)
217 220
218 221 # We need to define *two* skippers because Python doesn't allow both
219 222 # return with value and yield inside the same function.
220 223 def skipper_func(*args, **kwargs):
221 224 """Skipper for normal test functions."""
222 225 if skip_val():
223 226 raise nose.SkipTest(get_msg(f,msg))
224 227 else:
225 228 return f(*args, **kwargs)
226 229
227 230 def skipper_gen(*args, **kwargs):
228 231 """Skipper for test generators."""
229 232 if skip_val():
230 233 raise nose.SkipTest(get_msg(f,msg))
231 234 else:
232 235 for x in f(*args, **kwargs):
233 236 yield x
234 237
235 238 # Choose the right skipper to use when building the actual generator.
236 239 if nose.util.isgenerator(f):
237 240 skipper = skipper_gen
238 241 else:
239 242 skipper = skipper_func
240 243
241 244 return nose.tools.make_decorator(f)(skipper)
242 245
243 246 return skip_decorator
244 247
245 248 # A version with the condition set to true, common case just to attacha message
246 249 # to a skip decorator
247 250 def skip(msg=None):
248 251 """Decorator factory - mark a test function for skipping from test suite.
249 252
250 253 Parameters
251 254 ----------
252 255 msg : string
253 256 Optional message to be added.
254 257
255 258 Returns
256 259 -------
257 260 decorator : function
258 261 Decorator, which, when applied to a function, causes SkipTest
259 262 to be raised, with the optional message added.
260 263 """
261 264
262 265 return skipif(True,msg)
263 266
264 267
265 268 #-----------------------------------------------------------------------------
266 269 # Utility functions for decorators
267 270 def numpy_not_available():
268 271 """Can numpy be imported? Returns true if numpy does NOT import.
269 272
270 273 This is used to make a decorator to skip tests that require numpy to be
271 274 available, but delay the 'import numpy' to test execution time.
272 275 """
273 276 try:
274 277 import numpy
275 278 np_not_avail = False
276 279 except ImportError:
277 280 np_not_avail = True
278 281
279 282 return np_not_avail
280 283
281 284 #-----------------------------------------------------------------------------
282 285 # Decorators for public use
283 286
284 287 skip_doctest = make_label_dec('skip_doctest',
285 288 """Decorator - mark a function or method for skipping its doctest.
286 289
287 290 This decorator allows you to mark a function whose docstring you wish to
288 291 omit from testing, while preserving the docstring for introspection, help,
289 292 etc.""")
290 293
291 294 # Decorators to skip certain tests on specific platforms.
292 295 skip_win32 = skipif(sys.platform == 'win32',
293 296 "This test does not run under Windows")
294 297 skip_linux = skipif(sys.platform == 'linux2',
295 298 "This test does not run under Linux")
296 299 skip_osx = skipif(sys.platform == 'darwin',"This test does not run under OS X")
297 300
298 301
299 302 # Decorators to skip tests if not on specific platforms.
300 303 skip_if_not_win32 = skipif(sys.platform != 'win32',
301 304 "This test only runs under Windows")
302 305 skip_if_not_linux = skipif(sys.platform != 'linux2',
303 306 "This test only runs under Linux")
304 307 skip_if_not_osx = skipif(sys.platform != 'darwin',
305 308 "This test only runs under OSX")
306 309
307 310 # Other skip decorators
308 311 skipif_not_numpy = skipif(numpy_not_available,"This test requires numpy")
309 312
310 313 skipknownfailure = skip('This test is known to fail')
@@ -1,383 +1,393 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
5 5 itself from the command line. There are two ways of running this script:
6 6
7 7 1. With the syntax `iptest all`. This runs our entire test suite by
8 8 calling this script (with different arguments) or trial recursively. This
9 9 causes modules and package to be tested in different processes, using nose
10 10 or trial where appropriate.
11 11 2. With the regular nose syntax, like `iptest -vvs IPython`. In this form
12 12 the script simply calls nose, but with special command line flags and
13 13 plugins loaded.
14 14
15 15 For now, this script requires that both nose and twisted are installed. This
16 16 will change in the future.
17 17 """
18 18
19 from __future__ import absolute_import
20
19 21 #-----------------------------------------------------------------------------
20 22 # Module imports
21 23 #-----------------------------------------------------------------------------
22 24
23 25 import os
24 26 import os.path as path
25 27 import signal
26 28 import sys
27 29 import subprocess
28 30 import tempfile
29 31 import time
30 32 import warnings
31 33
32 34 import nose.plugins.builtin
33 35 from nose.core import TestProgram
34 36
35 37 from IPython.utils import genutils
36 38 from IPython.utils.platutils import find_cmd, FindCmdError
39 from . import globalipapp
40 from .plugin.ipdoctest import IPythonDoctest
37 41
38 42 pjoin = path.join
39 43
40 44 #-----------------------------------------------------------------------------
41 45 # Warnings control
42 46 #-----------------------------------------------------------------------------
43 47 # Twisted generates annoying warnings with Python 2.6, as will do other code
44 48 # that imports 'sets' as of today
45 49 warnings.filterwarnings('ignore', 'the sets module is deprecated',
46 50 DeprecationWarning )
47 51
48 52 #-----------------------------------------------------------------------------
49 53 # Logic for skipping doctests
50 54 #-----------------------------------------------------------------------------
51 55
52 56 def test_for(mod):
53 57 """Test to see if mod is importable."""
54 58 try:
55 59 __import__(mod)
56 60 except ImportError:
57 61 return False
58 62 else:
59 63 return True
60 64
61 65 have_curses = test_for('_curses')
62 66 have_wx = test_for('wx')
63 67 have_wx_aui = test_for('wx.aui')
64 68 have_zi = test_for('zope.interface')
65 69 have_twisted = test_for('twisted')
66 70 have_foolscap = test_for('foolscap')
67 71 have_objc = test_for('objc')
68 72 have_pexpect = test_for('pexpect')
69 73 have_gtk = test_for('gtk')
70 74 have_gobject = test_for('gobject')
71 75
72 76
73 77 def make_exclude():
74 78
75 79 # For the IPythonDoctest plugin, we need to exclude certain patterns that
76 80 # cause testing problems. We should strive to minimize the number of
77 81 # skipped modules, since this means untested code. As the testing
78 82 # machinery solidifies, this list should eventually become empty.
79 EXCLUDE = [pjoin('IPython', 'external'),
83
84 # Note that these exclusions only mean that the docstrings are not analyzed
85 # for examples to be run as tests, if there are other test functions in
86 # those modules, they do get run.
87 exclusions = [pjoin('IPython', 'external'),
80 88 pjoin('IPython', 'frontend', 'process', 'winprocess.py'),
81 89 pjoin('IPython_doctest_plugin'),
82 90 pjoin('IPython', 'quarantine'),
83 91 pjoin('IPython', 'deathrow'),
84 92 pjoin('IPython', 'testing', 'attic'),
85 93 pjoin('IPython', 'testing', 'tools'),
86 94 pjoin('IPython', 'testing', 'mkdoctests'),
87 95 pjoin('IPython', 'lib', 'inputhook')
88 96 ]
89 97
90 98 if not have_wx:
91 EXCLUDE.append(pjoin('IPython', 'gui'))
92 EXCLUDE.append(pjoin('IPython', 'frontend', 'wx'))
93 EXCLUDE.append(pjoin('IPython', 'lib', 'inputhookwx'))
99 exclusions.append(pjoin('IPython', 'gui'))
100 exclusions.append(pjoin('IPython', 'frontend', 'wx'))
101 exclusions.append(pjoin('IPython', 'lib', 'inputhookwx'))
94 102
95 103 if not have_gtk or not have_gobject:
96 EXCLUDE.append(pjoin('IPython', 'lib', 'inputhookgtk'))
104 exclusions.append(pjoin('IPython', 'lib', 'inputhookgtk'))
97 105
98 106 if not have_wx_aui:
99 EXCLUDE.append(pjoin('IPython', 'gui', 'wx', 'wxIPython'))
107 exclusions.append(pjoin('IPython', 'gui', 'wx', 'wxIPython'))
100 108
101 109 if not have_objc:
102 EXCLUDE.append(pjoin('IPython', 'frontend', 'cocoa'))
110 exclusions.append(pjoin('IPython', 'frontend', 'cocoa'))
103 111
104 112 if not sys.platform == 'win32':
105 EXCLUDE.append(pjoin('IPython', 'utils', 'platutils_win32'))
113 exclusions.append(pjoin('IPython', 'utils', 'platutils_win32'))
106 114
107 115 # These have to be skipped on win32 because the use echo, rm, cd, etc.
108 116 # See ticket https://bugs.launchpad.net/bugs/366982
109 117 if sys.platform == 'win32':
110 EXCLUDE.append(pjoin('IPython', 'testing', 'plugin', 'test_exampleip'))
111 EXCLUDE.append(pjoin('IPython', 'testing', 'plugin', 'dtexample'))
118 exclusions.append(pjoin('IPython', 'testing', 'plugin', 'test_exampleip'))
119 exclusions.append(pjoin('IPython', 'testing', 'plugin', 'dtexample'))
112 120
113 121 if not os.name == 'posix':
114 EXCLUDE.append(pjoin('IPython', 'utils', 'platutils_posix'))
122 exclusions.append(pjoin('IPython', 'utils', 'platutils_posix'))
115 123
116 124 if not have_pexpect:
117 EXCLUDE.append(pjoin('IPython', 'scripts', 'irunner'))
125 exclusions.append(pjoin('IPython', 'scripts', 'irunner'))
118 126
119 127 # This is scary. We still have things in frontend and testing that
120 128 # are being tested by nose that use twisted. We need to rethink
121 129 # how we are isolating dependencies in testing.
122 130 if not (have_twisted and have_zi and have_foolscap):
123 EXCLUDE.append(pjoin('IPython', 'frontend', 'asyncfrontendbase'))
124 EXCLUDE.append(pjoin('IPython', 'frontend', 'prefilterfrontend'))
125 EXCLUDE.append(pjoin('IPython', 'frontend', 'frontendbase'))
126 EXCLUDE.append(pjoin('IPython', 'frontend', 'linefrontendbase'))
127 EXCLUDE.append(pjoin('IPython', 'frontend', 'tests',
131 exclusions.append(pjoin('IPython', 'frontend', 'asyncfrontendbase'))
132 exclusions.append(pjoin('IPython', 'frontend', 'prefilterfrontend'))
133 exclusions.append(pjoin('IPython', 'frontend', 'frontendbase'))
134 exclusions.append(pjoin('IPython', 'frontend', 'linefrontendbase'))
135 exclusions.append(pjoin('IPython', 'frontend', 'tests',
128 136 'test_linefrontend'))
129 EXCLUDE.append(pjoin('IPython', 'frontend', 'tests',
137 exclusions.append(pjoin('IPython', 'frontend', 'tests',
130 138 'test_frontendbase'))
131 EXCLUDE.append(pjoin('IPython', 'frontend', 'tests',
139 exclusions.append(pjoin('IPython', 'frontend', 'tests',
132 140 'test_prefilterfrontend'))
133 EXCLUDE.append(pjoin('IPython', 'frontend', 'tests',
141 exclusions.append(pjoin('IPython', 'frontend', 'tests',
134 142 'test_asyncfrontendbase')),
135 EXCLUDE.append(pjoin('IPython', 'testing', 'parametric'))
136 EXCLUDE.append(pjoin('IPython', 'testing', 'util'))
143 exclusions.append(pjoin('IPython', 'testing', 'parametric'))
144 exclusions.append(pjoin('IPython', 'testing', 'util'))
137 145
138 146 # This is needed for the reg-exp to match on win32 in the ipdoctest plugin.
139 147 if sys.platform == 'win32':
140 EXCLUDE = [s.replace('\\','\\\\') for s in EXCLUDE]
148 exclusions = [s.replace('\\','\\\\') for s in exclusions]
141 149
142 return EXCLUDE
150 return exclusions
143 151
144 152
145 153 #-----------------------------------------------------------------------------
146 154 # Functions and classes
147 155 #-----------------------------------------------------------------------------
148 156
149 157 class IPTester(object):
150 158 """Call that calls iptest or trial in a subprocess.
151 159 """
152 160 #: string, name of test runner that will be called
153 161 runner = None
154 162 #: list, parameters for test runner
155 163 params = None
156 164 #: list, arguments of system call to be made to call test runner
157 165 call_args = None
158 166 #: list, process ids of subprocesses we start (for cleanup)
159 167 pids = None
160 168
161 169 def __init__(self,runner='iptest',params=None):
162 170 """Create new test runner."""
163 171 if runner == 'iptest':
164 172 # Find our own 'iptest' script OS-level entry point
165 173 try:
166 iptest_path = find_cmd('iptest')
174 iptest_path = os.path.abspath(find_cmd('iptest'))
167 175 except FindCmdError:
168 176 # Script not installed (may be the case for testing situations
169 177 # that are running from a source tree only), pull from internal
170 178 # path:
171 179 iptest_path = pjoin(genutils.get_ipython_package_dir(),
172 180 'scripts','iptest')
173 self.runner = [iptest_path,'-v']
181 self.runner = ['python', iptest_path, '-v']
174 182 else:
175 self.runner = [find_cmd('trial')]
183 self.runner = ['python', os.path.abspath(find_cmd('trial'))]
176 184 if params is None:
177 185 params = []
178 186 if isinstance(params,str):
179 187 params = [params]
180 188 self.params = params
181 189
182 190 # Assemble call
183 191 self.call_args = self.runner+self.params
184 192
185 193 # Store pids of anything we start to clean up on deletion, if possible
186 194 # (on posix only, since win32 has no os.kill)
187 195 self.pids = []
188 196
189 197 if sys.platform == 'win32':
190 198 def _run_cmd(self):
191 199 # On Windows, use os.system instead of subprocess.call, because I
192 200 # was having problems with subprocess and I just don't know enough
193 201 # about win32 to debug this reliably. Os.system may be the 'old
194 202 # fashioned' way to do it, but it works just fine. If someone
195 203 # later can clean this up that's fine, as long as the tests run
196 204 # reliably in win32.
197 205 return os.system(' '.join(self.call_args))
198 206 else:
199 207 def _run_cmd(self):
200 208 subp = subprocess.Popen(self.call_args)
201 209 self.pids.append(subp.pid)
202 210 # If this fails, the pid will be left in self.pids and cleaned up
203 211 # later, but if the wait call succeeds, then we can clear the
204 212 # stored pid.
205 213 retcode = subp.wait()
206 214 self.pids.pop()
207 215 return retcode
208 216
209 217 def run(self):
210 218 """Run the stored commands"""
211 219 try:
212 220 return self._run_cmd()
213 221 except:
214 222 import traceback
215 223 traceback.print_exc()
216 224 return 1 # signal failure
217 225
218 226 def __del__(self):
219 227 """Cleanup on exit by killing any leftover processes."""
220 228
221 229 if not hasattr(os, 'kill'):
222 230 return
223 231
224 232 for pid in self.pids:
225 233 try:
226 234 print 'Cleaning stale PID:', pid
227 235 os.kill(pid, signal.SIGKILL)
228 236 except OSError:
229 237 # This is just a best effort, if we fail or the process was
230 238 # really gone, ignore it.
231 239 pass
232 240
233 241
234 242 def make_runners():
235 243 """Define the top-level packages that need to be tested.
236 244 """
237 245
238 246 nose_packages = ['config', 'core', 'extensions', 'frontend', 'lib',
239 247 'scripts', 'testing', 'utils']
240 248 trial_packages = ['kernel']
241 #trial_packages = [] # dbg
242 249
243 250 if have_wx:
244 251 nose_packages.append('gui')
245 252
253 #nose_packages = ['core'] # dbg
254 #trial_packages = [] # dbg
255
246 256 nose_packages = ['IPython.%s' % m for m in nose_packages ]
247 257 trial_packages = ['IPython.%s' % m for m in trial_packages ]
248 258
249 259 # Make runners, most with nose
250 260 nose_testers = [IPTester(params=v) for v in nose_packages]
251 261 runners = dict(zip(nose_packages, nose_testers))
252 262 # And add twisted ones if conditions are met
253 263 if have_zi and have_twisted and have_foolscap:
254 264 trial_testers = [IPTester('trial',params=v) for v in trial_packages]
255 265 runners.update(dict(zip(trial_packages,trial_testers)))
256 266
257 267 return runners
258 268
259 269
260 270 def run_iptest():
261 271 """Run the IPython test suite using nose.
262 272
263 273 This function is called when this script is **not** called with the form
264 274 `iptest all`. It simply calls nose with appropriate command line flags
265 275 and accepts all of the standard nose arguments.
266 276 """
267 277
268 278 warnings.filterwarnings('ignore',
269 279 'This will be removed soon. Use IPython.testing.util instead')
270 280
271 argv = sys.argv + [
272 # Loading ipdoctest causes problems with Twisted.
273 # I am removing this as a temporary fix to get the
274 # test suite back into working shape. Our nose
275 # plugin needs to be gone through with a fine
276 # toothed comb to find what is causing the problem.
277 # '--with-ipdoctest',
278 # '--ipdoctest-tests','--ipdoctest-extension=txt',
279 # '--detailed-errors',
280
281 argv = sys.argv + [ '--detailed-errors',
282 # Loading ipdoctest causes problems with Twisted, but
283 # our test suite runner now separates things and runs
284 # all Twisted tests with trial.
285 '--with-ipdoctest',
286 '--ipdoctest-tests','--ipdoctest-extension=txt',
287
288 #'-x','-s', # dbg
289
281 290 # We add --exe because of setuptools' imbecility (it
282 291 # blindly does chmod +x on ALL files). Nose does the
283 292 # right thing and it tries to avoid executables,
284 293 # setuptools unfortunately forces our hand here. This
285 294 # has been discussed on the distutils list and the
286 295 # setuptools devs refuse to fix this problem!
287 296 '--exe',
288 297 ]
289 298
290 299 # Detect if any tests were required by explicitly calling an IPython
291 300 # submodule or giving a specific path
292 301 has_tests = False
293 302 for arg in sys.argv:
294 303 if 'IPython' in arg or arg.endswith('.py') or \
295 304 (':' in arg and '.py' in arg):
296 305 has_tests = True
297 306 break
298 307
299 308 # If nothing was specifically requested, test full IPython
300 309 if not has_tests:
301 310 argv.append('IPython')
302 311
303 # Construct list of plugins, omitting the existing doctest plugin, which
304 # ours replaces (and extends).
305 EXCLUDE = make_exclude()
306 plugins = []
307 # plugins = [IPythonDoctest(EXCLUDE)]
312 ## # Construct list of plugins, omitting the existing doctest plugin, which
313 ## # ours replaces (and extends).
314 plugins = [IPythonDoctest(make_exclude())]
308 315 for p in nose.plugins.builtin.plugins:
309 316 plug = p()
310 317 if plug.name == 'doctest':
311 318 continue
312 319 plugins.append(plug)
313 320
321 # We need a global ipython running in this process
322 globalipapp.start_ipython()
323 # Now nose can run
314 324 TestProgram(argv=argv,plugins=plugins)
315 325
316 326
317 327 def run_iptestall():
318 328 """Run the entire IPython test suite by calling nose and trial.
319 329
320 330 This function constructs :class:`IPTester` instances for all IPython
321 331 modules and package and then runs each of them. This causes the modules
322 332 and packages of IPython to be tested each in their own subprocess using
323 333 nose or twisted.trial appropriately.
324 334 """
325 335
326 336 runners = make_runners()
327 337
328 338 # Run the test runners in a temporary dir so we can nuke it when finished
329 339 # to clean up any junk files left over by accident. This also makes it
330 340 # robust against being run in non-writeable directories by mistake, as the
331 341 # temp dir will always be user-writeable.
332 342 curdir = os.getcwd()
333 343 testdir = tempfile.gettempdir()
334 344 os.chdir(testdir)
335 345
336 346 # Run all test runners, tracking execution time
337 347 failed = {}
338 348 t_start = time.time()
339 349 try:
340 350 for name,runner in runners.iteritems():
341 351 print '*'*77
342 352 print 'IPython test group:',name
343 353 res = runner.run()
344 354 if res:
345 355 failed[name] = res
346 356 finally:
347 357 os.chdir(curdir)
348 358 t_end = time.time()
349 359 t_tests = t_end - t_start
350 360 nrunners = len(runners)
351 361 nfail = len(failed)
352 362 # summarize results
353 363 print
354 364 print '*'*77
355 365 print 'Ran %s test groups in %.3fs' % (nrunners, t_tests)
356 366 print
357 367 if not failed:
358 368 print 'OK'
359 369 else:
360 370 # If anything went wrong, point out what command to rerun manually to
361 371 # see the actual errors and individual summary
362 372 print 'ERROR - %s out of %s test groups failed.' % (nfail, nrunners)
363 373 for name in failed:
364 374 failed_runner = runners[name]
365 375 print '-'*40
366 376 print 'Runner failed:',name
367 377 print 'You may wish to rerun this one individually, with:'
368 378 print ' '.join(failed_runner.call_args)
369 379 print
370 380
371 381
372 382 def main():
373 383 if len(sys.argv) == 1:
374 384 run_iptestall()
375 385 else:
376 386 if sys.argv[1] == 'all':
377 387 run_iptestall()
378 388 else:
379 389 run_iptest()
380 390
381 391
382 392 if __name__ == '__main__':
383 393 main()
@@ -1,156 +1,188 b''
1 1 """Experimental code for cleaner support of IPython syntax with unittest.
2 2
3 3 In IPython up until 0.10, we've used very hacked up nose machinery for running
4 4 tests with IPython special syntax, and this has proved to be extremely slow.
5 5 This module provides decorators to try a different approach, stemming from a
6 6 conversation Brian and I (FP) had about this problem Sept/09.
7 7
8 8 The goal is to be able to easily write simple functions that can be seen by
9 9 unittest as tests, and ultimately for these to support doctests with full
10 10 IPython syntax. Nose already offers this based on naming conventions and our
11 11 hackish plugins, but we are seeking to move away from nose dependencies if
12 12 possible.
13 13
14 14 This module follows a different approach, based on decorators.
15 15
16 16 - A decorator called @ipdoctest can mark any function as having a docstring
17 17 that should be viewed as a doctest, but after syntax conversion.
18 18
19 19 Authors
20 20 -------
21 21
22 22 - Fernando Perez <Fernando.Perez@berkeley.edu>
23 23 """
24 24
25 from __future__ import absolute_import
26
25 27 #-----------------------------------------------------------------------------
26 28 # Copyright (C) 2009 The IPython Development Team
27 29 #
28 30 # Distributed under the terms of the BSD License. The full license is in
29 31 # the file COPYING, distributed as part of this software.
30 32 #-----------------------------------------------------------------------------
31 33
32 34
33 35 #-----------------------------------------------------------------------------
34 36 # Imports
35 37 #-----------------------------------------------------------------------------
36 38
37 39 # Stdlib
38 40 import re
39 41 import sys
40 42 import unittest
41 43 from doctest import DocTestFinder, DocTestRunner, TestResults
42 44
43 # Our own
44 import nosepatch
45 # Our own, a nose monkeypatch
46 from . import nosepatch
45 47
46 48 # We already have python3-compliant code for parametric tests
47 49 if sys.version[0]=='2':
48 from _paramtestpy2 import ParametricTestCase
50 from ._paramtestpy2 import ParametricTestCase
49 51 else:
50 from _paramtestpy3 import ParametricTestCase
52 from ._paramtestpy3 import ParametricTestCase
53
54 from . import globalipapp
51 55
52 56 #-----------------------------------------------------------------------------
53 57 # Classes and functions
54 58 #-----------------------------------------------------------------------------
55 59
56 60 def count_failures(runner):
57 61 """Count number of failures in a doctest runner.
58 62
59 63 Code modeled after the summarize() method in doctest.
60 64 """
61 65 return [TestResults(f, t) for f, t in runner._name2ft.values() if f > 0 ]
62 66
63 67
64 68 class IPython2PythonConverter(object):
65 69 """Convert IPython 'syntax' to valid Python.
66 70
67 71 Eventually this code may grow to be the full IPython syntax conversion
68 72 implementation, but for now it only does prompt convertion."""
69 73
70 74 def __init__(self):
71 self.ps1 = re.compile(r'In\ \[\d+\]: ')
72 self.ps2 = re.compile(r'\ \ \ \.\.\.+: ')
73 self.out = re.compile(r'Out\[\d+\]: \s*?\n?')
75 self.rps1 = re.compile(r'In\ \[\d+\]: ')
76 self.rps2 = re.compile(r'\ \ \ \.\.\.+: ')
77 self.rout = re.compile(r'Out\[\d+\]: \s*?\n?')
78 self.pyps1 = '>>> '
79 self.pyps2 = '... '
80 self.rpyps1 = re.compile ('(\s*%s)(.*)$' % self.pyps1)
81 self.rpyps2 = re.compile ('(\s*%s)(.*)$' % self.pyps2)
74 82
75 83 def __call__(self, ds):
76 84 """Convert IPython prompts to python ones in a string."""
77 85 pyps1 = '>>> '
78 86 pyps2 = '... '
79 87 pyout = ''
80 88
81 89 dnew = ds
82 dnew = self.ps1.sub(pyps1, dnew)
83 dnew = self.ps2.sub(pyps2, dnew)
84 dnew = self.out.sub(pyout, dnew)
85 return dnew
90 dnew = self.rps1.sub(pyps1, dnew)
91 dnew = self.rps2.sub(pyps2, dnew)
92 dnew = self.rout.sub(pyout, dnew)
93 ip = globalipapp.get_ipython()
94
95 # Convert input IPython source into valid Python.
96 out = []
97 newline = out.append
98 for line in dnew.splitlines():
99
100 mps1 = self.rpyps1.match(line)
101 if mps1 is not None:
102 prompt, text = mps1.groups()
103 newline(prompt+ip.prefilter(text, False))
104 continue
105
106 mps2 = self.rpyps2.match(line)
107 if mps2 is not None:
108 prompt, text = mps2.groups()
109 newline(prompt+ip.prefilter(text, True))
110 continue
111
112 newline(line)
113 newline('') # ensure a closing newline, needed by doctest
114 #print "PYSRC:", '\n'.join(out) # dbg
115 return '\n'.join(out)
116
117 #return dnew
86 118
87 119
88 120 class Doc2UnitTester(object):
89 121 """Class whose instances act as a decorator for docstring testing.
90 122
91 123 In practice we're only likely to need one instance ever, made below (though
92 124 no attempt is made at turning it into a singleton, there is no need for
93 125 that).
94 126 """
95 127 def __init__(self, verbose=False):
96 128 """New decorator.
97 129
98 130 Parameters
99 131 ----------
100 132
101 133 verbose : boolean, optional (False)
102 134 Passed to the doctest finder and runner to control verbosity.
103 135 """
104 136 self.verbose = verbose
105 137 # We can reuse the same finder for all instances
106 138 self.finder = DocTestFinder(verbose=verbose, recurse=False)
107 139
108 140 def __call__(self, func):
109 141 """Use as a decorator: doctest a function's docstring as a unittest.
110 142
111 143 This version runs normal doctests, but the idea is to make it later run
112 144 ipython syntax instead."""
113 145
114 146 # Capture the enclosing instance with a different name, so the new
115 147 # class below can see it without confusion regarding its own 'self'
116 148 # that will point to the test instance at runtime
117 149 d2u = self
118 150
119 151 # Rewrite the function's docstring to have python syntax
120 152 if func.__doc__ is not None:
121 153 func.__doc__ = ip2py(func.__doc__)
122 154
123 155 # Now, create a tester object that is a real unittest instance, so
124 156 # normal unittest machinery (or Nose, or Trial) can find it.
125 157 class Tester(unittest.TestCase):
126 158 def test(self):
127 159 # Make a new runner per function to be tested
128 160 runner = DocTestRunner(verbose=d2u.verbose)
129 161 map(runner.run, d2u.finder.find(func, func.__name__))
130 162 failed = count_failures(runner)
131 163 if failed:
132 164 # Since we only looked at a single function's docstring,
133 165 # failed should contain at most one item. More than that
134 166 # is a case we can't handle and should error out on
135 167 if len(failed) > 1:
136 168 err = "Invalid number of test results:" % failed
137 169 raise ValueError(err)
138 170 # Report a normal failure.
139 171 self.fail('failed doctests: %s' % str(failed[0]))
140 172
141 173 # Rename it so test reports have the original signature.
142 174 Tester.__name__ = func.__name__
143 175 return Tester
144 176
145 177
146 178 def ipdocstring(func):
147 179 """Change the function docstring via ip2py.
148 180 """
149 181 if func.__doc__ is not None:
150 182 func.__doc__ = ip2py(func.__doc__)
151 183 return func
152 184
153 185
154 186 # Make an instance of the classes for public use
155 187 ipdoctest = Doc2UnitTester()
156 188 ip2py = IPython2PythonConverter()
@@ -1,940 +1,779 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 54 log = logging.getLogger(__name__)
54 55
55 ###########################################################################
56 # *** HACK ***
57 # We must start our own ipython object and heavily muck with it so that all the
58 # modifications IPython makes to system behavior don't send the doctest
59 # machinery into a fit. This code should be considered a gross hack, but it
60 # gets the job done.
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.config import default
68 ipcdir = os.path.dirname(default.__file__)
69 ipconf = os.path.join(ipcdir,'ipython_config.py')
70 #print 'conf:',ipconf # dbg
71 return ['--colors=NoColor', '--no-term-title','--no-banner',
72 '--config-file=%s' % ipconf]
73
74
75 # Hack to modify the %run command so we can sync the user's namespace with the
76 # test globals. Once we move over to a clean magic system, this will be done
77 # with much less ugliness.
78
79 class py_file_finder(object):
80 def __init__(self,test_filename):
81 self.test_filename = test_filename
82
83 def __call__(self,name):
84 from IPython.utils.genutils import get_py_filename
85 try:
86 return get_py_filename(name)
87 except IOError:
88 test_dir = os.path.dirname(self.test_filename)
89 new_path = os.path.join(test_dir,name)
90 return get_py_filename(new_path)
91
92
93 def _run_ns_sync(self,arg_s,runner=None):
94 """Modified version of %run that syncs testing namespaces.
95
96 This is strictly needed for running doctests that call %run.
97 """
98
99 # When tests call %run directly (not via doctest) these function attributes
100 # are not set
101 try:
102 fname = _run_ns_sync.test_filename
103 except AttributeError:
104 fname = arg_s
105
106 finder = py_file_finder(fname)
107 out = _ip.magic_run_ori(arg_s,runner,finder)
108
109 # Simliarly, there is no test_globs when a test is NOT a doctest
110 if hasattr(_run_ns_sync,'test_globs'):
111 _run_ns_sync.test_globs.update(_ip.user_ns)
112 return out
113
114
115 class ipnsdict(dict):
116 """A special subclass of dict for use as an IPython namespace in doctests.
117
118 This subclass adds a simple checkpointing capability so that when testing
119 machinery clears it (we use it as the test execution context), it doesn't
120 get completely destroyed.
121 """
122
123 def __init__(self,*a):
124 dict.__init__(self,*a)
125 self._savedict = {}
126
127 def clear(self):
128 dict.clear(self)
129 self.update(self._savedict)
130
131 def _checkpoint(self):
132 self._savedict.clear()
133 self._savedict.update(self)
134
135 def update(self,other):
136 self._checkpoint()
137 dict.update(self,other)
138
139 # If '_' is in the namespace, python won't set it when executing code,
140 # and we have examples that test it. So we ensure that the namespace
141 # is always 'clean' of it before it's used for test code execution.
142 self.pop('_',None)
143
144 # The builtins namespace must *always* be the real __builtin__ module,
145 # else weird stuff happens. The main ipython code does have provisions
146 # to ensure this after %run, but since in this class we do some
147 # aggressive low-level cleaning of the execution namespace, we need to
148 # correct for that ourselves, to ensure consitency with the 'real'
149 # ipython.
150 self['__builtins__'] = __builtin__
151
152
153 def start_ipython():
154 """Start a global IPython shell, which we need for IPython-specific syntax.
155 """
156
157 # This function should only ever run once!
158 if hasattr(start_ipython,'already_called'):
159 return
160 start_ipython.already_called = True
161
162 # Ok, first time we're called, go ahead
163 import new
164
165 import IPython
166 from IPython.core import ipapp, iplib
167
168 def xsys(cmd):
169 """Execute a command and print its output.
170
171 This is just a convenience function to replace the IPython system call
172 with one that is more doctest-friendly.
173 """
174 cmd = _ip.var_expand(cmd,depth=1)
175 sys.stdout.write(commands.getoutput(cmd))
176 sys.stdout.flush()
177
178 # Store certain global objects that IPython modifies
179 _displayhook = sys.displayhook
180 _excepthook = sys.excepthook
181 _main = sys.modules.get('__main__')
182
183 argv = default_argv()
184
185 # Start IPython instance. We customize it to start with minimal frills.
186 user_ns,global_ns = iplib.make_user_namespaces(ipnsdict(),{})
187 ip = ipapp.IPythonApp(argv, user_ns=user_ns, user_global_ns=global_ns)
188 ip.initialize()
189 ip.shell.builtin_trap.set()
190
191 # Deactivate the various python system hooks added by ipython for
192 # interactive convenience so we don't confuse the doctest system
193 sys.modules['__main__'] = _main
194 sys.displayhook = _displayhook
195 sys.excepthook = _excepthook
196
197 # So that ipython magics and aliases can be doctested (they work by making
198 # a call into a global _ip object)
199 __builtin__._ip = ip.shell
200
201 # Modify the IPython system call with one that uses getoutput, so that we
202 # can capture subcommands and print them to Python's stdout, otherwise the
203 # doctest machinery would miss them.
204 ip.shell.system = xsys
205
206 # Also patch our %run function in.
207 im = new.instancemethod(_run_ns_sync,_ip, _ip.__class__)
208 ip.shell.magic_run_ori = _ip.magic_run
209 ip.shell.magic_run = im
210
211 # XXX - For some very bizarre reason, the loading of %history by default is
212 # failing. This needs to be fixed later, but for now at least this ensures
213 # that tests that use %hist run to completion.
214 from IPython.core import history
215 history.init_ipython(ip.shell)
216 if not hasattr(ip.shell,'magic_history'):
217 raise RuntimeError("Can't load magics, aborting")
218
219
220 # The start call MUST be made here. I'm not sure yet why it doesn't work if
221 # it is made later, at plugin initialization time, but in all my tests, that's
222 # the case.
223 start_ipython()
224
225 # *** END HACK ***
226 ###########################################################################
227 56
57 #-----------------------------------------------------------------------------
228 58 # Classes and functions
59 #-----------------------------------------------------------------------------
229 60
230 61 def is_extension_module(filename):
231 62 """Return whether the given filename is an extension module.
232 63
233 64 This simply checks that the extension is either .so or .pyd.
234 65 """
235 66 return os.path.splitext(filename)[1].lower() in ('.so','.pyd')
236 67
237 68
238 69 class DocTestSkip(object):
239 70 """Object wrapper for doctests to be skipped."""
240 71
241 72 ds_skip = """Doctest to skip.
242 73 >>> 1 #doctest: +SKIP
243 74 """
244 75
245 76 def __init__(self,obj):
246 77 self.obj = obj
247 78
248 79 def __getattribute__(self,key):
249 80 if key == '__doc__':
250 81 return DocTestSkip.ds_skip
251 82 else:
252 83 return getattr(object.__getattribute__(self,'obj'),key)
253 84
254 85 # Modified version of the one in the stdlib, that fixes a python bug (doctests
255 86 # not found in extension modules, http://bugs.python.org/issue3158)
256 87 class DocTestFinder(doctest.DocTestFinder):
257 88
258 89 def _from_module(self, module, object):
259 90 """
260 91 Return true if the given object is defined in the given
261 92 module.
262 93 """
263 94 if module is None:
264 95 return True
265 96 elif inspect.isfunction(object):
266 97 return module.__dict__ is object.func_globals
267 98 elif inspect.isbuiltin(object):
268 99 return module.__name__ == object.__module__
269 100 elif inspect.isclass(object):
270 101 return module.__name__ == object.__module__
271 102 elif inspect.ismethod(object):
272 103 # This one may be a bug in cython that fails to correctly set the
273 104 # __module__ attribute of methods, but since the same error is easy
274 105 # to make by extension code writers, having this safety in place
275 106 # isn't such a bad idea
276 107 return module.__name__ == object.im_class.__module__
277 108 elif inspect.getmodule(object) is not None:
278 109 return module is inspect.getmodule(object)
279 110 elif hasattr(object, '__module__'):
280 111 return module.__name__ == object.__module__
281 112 elif isinstance(object, property):
282 113 return True # [XX] no way not be sure.
283 114 else:
284 115 raise ValueError("object must be a class or function")
285 116
286 117 def _find(self, tests, obj, name, module, source_lines, globs, seen):
287 118 """
288 119 Find tests for the given object and any contained objects, and
289 120 add them to `tests`.
290 121 """
291
122 #print '_find for:', obj, name, module # dbg
292 123 if hasattr(obj,"skip_doctest"):
293 124 #print 'SKIPPING DOCTEST FOR:',obj # dbg
294 125 obj = DocTestSkip(obj)
295 126
296 127 doctest.DocTestFinder._find(self,tests, obj, name, module,
297 128 source_lines, globs, seen)
298 129
299 130 # Below we re-run pieces of the above method with manual modifications,
300 131 # because the original code is buggy and fails to correctly identify
301 132 # doctests in extension modules.
302 133
303 134 # Local shorthands
304 135 from inspect import isroutine, isclass, ismodule
305 136
306 137 # Look for tests in a module's contained objects.
307 138 if inspect.ismodule(obj) and self._recurse:
308 139 for valname, val in obj.__dict__.items():
309 140 valname1 = '%s.%s' % (name, valname)
310 141 if ( (isroutine(val) or isclass(val))
311 142 and self._from_module(module, val) ):
312 143
313 144 self._find(tests, val, valname1, module, source_lines,
314 145 globs, seen)
315 146
316 147 # Look for tests in a class's contained objects.
317 148 if inspect.isclass(obj) and self._recurse:
318 149 #print 'RECURSE into class:',obj # dbg
319 150 for valname, val in obj.__dict__.items():
320 151 # Special handling for staticmethod/classmethod.
321 152 if isinstance(val, staticmethod):
322 153 val = getattr(obj, valname)
323 154 if isinstance(val, classmethod):
324 155 val = getattr(obj, valname).im_func
325 156
326 157 # Recurse to methods, properties, and nested classes.
327 158 if ((inspect.isfunction(val) or inspect.isclass(val) or
328 159 inspect.ismethod(val) or
329 160 isinstance(val, property)) and
330 161 self._from_module(module, val)):
331 162 valname = '%s.%s' % (name, valname)
332 163 self._find(tests, val, valname, module, source_lines,
333 164 globs, seen)
334 165
335 166
336 167 class IPDoctestOutputChecker(doctest.OutputChecker):
337 168 """Second-chance checker with support for random tests.
338 169
339 170 If the default comparison doesn't pass, this checker looks in the expected
340 171 output string for flags that tell us to ignore the output.
341 172 """
342 173
343 174 random_re = re.compile(r'#\s*random\s+')
344 175
345 176 def check_output(self, want, got, optionflags):
346 177 """Check output, accepting special markers embedded in the output.
347 178
348 179 If the output didn't pass the default validation but the special string
349 180 '#random' is included, we accept it."""
350 181
351 182 # Let the original tester verify first, in case people have valid tests
352 183 # that happen to have a comment saying '#random' embedded in.
353 184 ret = doctest.OutputChecker.check_output(self, want, got,
354 185 optionflags)
355 186 if not ret and self.random_re.search(want):
356 187 #print >> sys.stderr, 'RANDOM OK:',want # dbg
357 188 return True
358 189
359 190 return ret
360 191
361 192
362 193 class DocTestCase(doctests.DocTestCase):
363 194 """Proxy for DocTestCase: provides an address() method that
364 195 returns the correct address for the doctest case. Otherwise
365 196 acts as a proxy to the test case. To provide hints for address(),
366 197 an obj may also be passed -- this will be used as the test object
367 198 for purposes of determining the test address, if it is provided.
368 199 """
369 200
370 201 # Note: this method was taken from numpy's nosetester module.
371 202
372 203 # Subclass nose.plugins.doctests.DocTestCase to work around a bug in
373 204 # its constructor that blocks non-default arguments from being passed
374 205 # down into doctest.DocTestCase
375 206
376 207 def __init__(self, test, optionflags=0, setUp=None, tearDown=None,
377 208 checker=None, obj=None, result_var='_'):
378 209 self._result_var = result_var
379 210 doctests.DocTestCase.__init__(self, test,
380 211 optionflags=optionflags,
381 212 setUp=setUp, tearDown=tearDown,
382 213 checker=checker)
383 214 # Now we must actually copy the original constructor from the stdlib
384 215 # doctest class, because we can't call it directly and a bug in nose
385 216 # means it never gets passed the right arguments.
386 217
387 218 self._dt_optionflags = optionflags
388 219 self._dt_checker = checker
389 220 self._dt_test = test
390 221 self._dt_setUp = setUp
391 222 self._dt_tearDown = tearDown
392 223
393 224 # XXX - store this runner once in the object!
394 225 runner = IPDocTestRunner(optionflags=optionflags,
395 226 checker=checker, verbose=False)
396 227 self._dt_runner = runner
397 228
398 229
399 # Each doctest should remember what directory it was loaded from...
400 self._ori_dir = os.getcwd()
230 # Each doctest should remember the directory it was loaded from, so
231 # things like %run work without too many contortions
232 self._ori_dir = os.path.dirname(test.filename)
401 233
402 234 # Modified runTest from the default stdlib
403 235 def runTest(self):
404 236 test = self._dt_test
405 237 runner = self._dt_runner
406 238
407 239 old = sys.stdout
408 240 new = StringIO()
409 241 optionflags = self._dt_optionflags
410 242
411 243 if not (optionflags & REPORTING_FLAGS):
412 244 # The option flags don't include any reporting flags,
413 245 # so add the default reporting flags
414 246 optionflags |= _unittest_reportflags
415 247
416 248 try:
417 249 # Save our current directory and switch out to the one where the
418 250 # test was originally created, in case another doctest did a
419 251 # directory change. We'll restore this in the finally clause.
420 252 curdir = os.getcwd()
253 #print 'runTest in dir:', self._ori_dir # dbg
421 254 os.chdir(self._ori_dir)
422 255
423 256 runner.DIVIDER = "-"*70
424 257 failures, tries = runner.run(test,out=new.write,
425 258 clear_globs=False)
426 259 finally:
427 260 sys.stdout = old
428 261 os.chdir(curdir)
429 262
430 263 if failures:
431 264 raise self.failureException(self.format_failure(new.getvalue()))
432 265
433 266 def setUp(self):
434 267 """Modified test setup that syncs with ipython namespace"""
435
268 #print "setUp test", self._dt_test.examples # dbg
436 269 if isinstance(self._dt_test.examples[0],IPExample):
437 270 # for IPython examples *only*, we swap the globals with the ipython
438 271 # namespace, after updating it with the globals (which doctest
439 272 # fills with the necessary info from the module being tested).
440 273 _ip.user_ns.update(self._dt_test.globs)
441 274 self._dt_test.globs = _ip.user_ns
442 275
443 276 super(DocTestCase, self).setUp()
444 277
445 278 def tearDown(self):
446 279 # XXX - fperez: I am not sure if this is truly a bug in nose 0.11, but
447 280 # it does look like one to me: its tearDown method tries to run
448 281 #
449 282 # delattr(__builtin__, self._result_var)
450 283 #
451 284 # without checking that the attribute really is there; it implicitly
452 285 # assumes it should have been set via displayhook. But if the
453 286 # displayhook was never called, this doesn't necessarily happen. I
454 287 # haven't been able to find a little self-contained example outside of
455 288 # ipython that would show the problem so I can report it to the nose
456 289 # team, but it does happen a lot in our code.
457 290 #
458 291 # So here, we just protect as narrowly as possible by trapping an
459 292 # attribute error whose message would be the name of self._result_var,
460 293 # and letting any other error propagate.
461 294 try:
462 295 super(DocTestCase, self).tearDown()
463 296 except AttributeError, exc:
464 297 if exc.args[0] != self._result_var:
465 298 raise
466 299
467 300
468 301 # A simple subclassing of the original with a different class name, so we can
469 302 # distinguish and treat differently IPython examples from pure python ones.
470 303 class IPExample(doctest.Example): pass
471 304
472 305
473 306 class IPExternalExample(doctest.Example):
474 307 """Doctest examples to be run in an external process."""
475 308
476 309 def __init__(self, source, want, exc_msg=None, lineno=0, indent=0,
477 310 options=None):
478 311 # Parent constructor
479 312 doctest.Example.__init__(self,source,want,exc_msg,lineno,indent,options)
480 313
481 314 # An EXTRA newline is needed to prevent pexpect hangs
482 315 self.source += '\n'
483 316
484 317
485 318 class IPDocTestParser(doctest.DocTestParser):
486 319 """
487 320 A class used to parse strings containing doctest examples.
488 321
489 322 Note: This is a version modified to properly recognize IPython input and
490 323 convert any IPython examples into valid Python ones.
491 324 """
492 325 # This regular expression is used to find doctest examples in a
493 326 # string. It defines three groups: `source` is the source code
494 327 # (including leading indentation and prompts); `indent` is the
495 328 # indentation of the first (PS1) line of the source code; and
496 329 # `want` is the expected output (including leading indentation).
497 330
498 331 # Classic Python prompts or default IPython ones
499 332 _PS1_PY = r'>>>'
500 333 _PS2_PY = r'\.\.\.'
501 334
502 335 _PS1_IP = r'In\ \[\d+\]:'
503 336 _PS2_IP = r'\ \ \ \.\.\.+:'
504 337
505 338 _RE_TPL = r'''
506 339 # Source consists of a PS1 line followed by zero or more PS2 lines.
507 340 (?P<source>
508 341 (?:^(?P<indent> [ ]*) (?P<ps1> %s) .*) # PS1 line
509 342 (?:\n [ ]* (?P<ps2> %s) .*)*) # PS2 lines
510 343 \n? # a newline
511 344 # Want consists of any non-blank lines that do not start with PS1.
512 345 (?P<want> (?:(?![ ]*$) # Not a blank line
513 346 (?![ ]*%s) # Not a line starting with PS1
514 347 (?![ ]*%s) # Not a line starting with PS2
515 348 .*$\n? # But any other line
516 349 )*)
517 350 '''
518 351
519 352 _EXAMPLE_RE_PY = re.compile( _RE_TPL % (_PS1_PY,_PS2_PY,_PS1_PY,_PS2_PY),
520 353 re.MULTILINE | re.VERBOSE)
521 354
522 355 _EXAMPLE_RE_IP = re.compile( _RE_TPL % (_PS1_IP,_PS2_IP,_PS1_IP,_PS2_IP),
523 356 re.MULTILINE | re.VERBOSE)
524 357
525 358 # Mark a test as being fully random. In this case, we simply append the
526 359 # random marker ('#random') to each individual example's output. This way
527 360 # we don't need to modify any other code.
528 361 _RANDOM_TEST = re.compile(r'#\s*all-random\s+')
529 362
530 363 # Mark tests to be executed in an external process - currently unsupported.
531 364 _EXTERNAL_IP = re.compile(r'#\s*ipdoctest:\s*EXTERNAL')
532 365
533 366 def ip2py(self,source):
534 367 """Convert input IPython source into valid Python."""
535 368 out = []
536 369 newline = out.append
537 370 #print 'IPSRC:\n',source,'\n###' # dbg
538 371 # The input source must be first stripped of all bracketing whitespace
539 372 # and turned into lines, so it looks to the parser like regular user
540 373 # input
541 374 for lnum,line in enumerate(source.strip().splitlines()):
542 375 newline(_ip.prefilter(line,lnum>0))
543 376 newline('') # ensure a closing newline, needed by doctest
544 377 #print "PYSRC:", '\n'.join(out) # dbg
545 378 return '\n'.join(out)
546 379
547 380 def parse(self, string, name='<string>'):
548 381 """
549 382 Divide the given string into examples and intervening text,
550 383 and return them as a list of alternating Examples and strings.
551 384 Line numbers for the Examples are 0-based. The optional
552 385 argument `name` is a name identifying this string, and is only
553 386 used for error messages.
554 387 """
555 388
556 389 #print 'Parse string:\n',string # dbg
557 390
558 391 string = string.expandtabs()
559 392 # If all lines begin with the same indentation, then strip it.
560 393 min_indent = self._min_indent(string)
561 394 if min_indent > 0:
562 395 string = '\n'.join([l[min_indent:] for l in string.split('\n')])
563 396
564 397 output = []
565 398 charno, lineno = 0, 0
566 399
567 400 # We make 'all random' tests by adding the '# random' mark to every
568 401 # block of output in the test.
569 402 if self._RANDOM_TEST.search(string):
570 403 random_marker = '\n# random'
571 404 else:
572 405 random_marker = ''
573 406
574 407 # Whether to convert the input from ipython to python syntax
575 408 ip2py = False
576 409 # Find all doctest examples in the string. First, try them as Python
577 410 # examples, then as IPython ones
578 411 terms = list(self._EXAMPLE_RE_PY.finditer(string))
579 412 if terms:
580 413 # Normal Python example
581 414 #print '-'*70 # dbg
582 415 #print 'PyExample, Source:\n',string # dbg
583 416 #print '-'*70 # dbg
584 417 Example = doctest.Example
585 418 else:
586 419 # It's an ipython example. Note that IPExamples are run
587 420 # in-process, so their syntax must be turned into valid python.
588 421 # IPExternalExamples are run out-of-process (via pexpect) so they
589 422 # don't need any filtering (a real ipython will be executing them).
590 423 terms = list(self._EXAMPLE_RE_IP.finditer(string))
591 424 if self._EXTERNAL_IP.search(string):
592 425 #print '-'*70 # dbg
593 426 #print 'IPExternalExample, Source:\n',string # dbg
594 427 #print '-'*70 # dbg
595 428 Example = IPExternalExample
596 429 else:
597 430 #print '-'*70 # dbg
598 431 #print 'IPExample, Source:\n',string # dbg
599 432 #print '-'*70 # dbg
600 433 Example = IPExample
601 434 ip2py = True
602 435
603 436 for m in terms:
604 437 # Add the pre-example text to `output`.
605 438 output.append(string[charno:m.start()])
606 439 # Update lineno (lines before this example)
607 440 lineno += string.count('\n', charno, m.start())
608 441 # Extract info from the regexp match.
609 442 (source, options, want, exc_msg) = \
610 443 self._parse_example(m, name, lineno,ip2py)
611 444
612 445 # Append the random-output marker (it defaults to empty in most
613 446 # cases, it's only non-empty for 'all-random' tests):
614 447 want += random_marker
615 448
616 449 if Example is IPExternalExample:
617 450 options[doctest.NORMALIZE_WHITESPACE] = True
618 451 want += '\n'
619 452
620 453 # Create an Example, and add it to the list.
621 454 if not self._IS_BLANK_OR_COMMENT(source):
622 455 output.append(Example(source, want, exc_msg,
623 456 lineno=lineno,
624 457 indent=min_indent+len(m.group('indent')),
625 458 options=options))
626 459 # Update lineno (lines inside this example)
627 460 lineno += string.count('\n', m.start(), m.end())
628 461 # Update charno.
629 462 charno = m.end()
630 463 # Add any remaining post-example text to `output`.
631 464 output.append(string[charno:])
632 465 return output
633 466
634 467 def _parse_example(self, m, name, lineno,ip2py=False):
635 468 """
636 469 Given a regular expression match from `_EXAMPLE_RE` (`m`),
637 470 return a pair `(source, want)`, where `source` is the matched
638 471 example's source code (with prompts and indentation stripped);
639 472 and `want` is the example's expected output (with indentation
640 473 stripped).
641 474
642 475 `name` is the string's name, and `lineno` is the line number
643 476 where the example starts; both are used for error messages.
644 477
645 478 Optional:
646 479 `ip2py`: if true, filter the input via IPython to convert the syntax
647 480 into valid python.
648 481 """
649 482
650 483 # Get the example's indentation level.
651 484 indent = len(m.group('indent'))
652 485
653 486 # Divide source into lines; check that they're properly
654 487 # indented; and then strip their indentation & prompts.
655 488 source_lines = m.group('source').split('\n')
656 489
657 490 # We're using variable-length input prompts
658 491 ps1 = m.group('ps1')
659 492 ps2 = m.group('ps2')
660 493 ps1_len = len(ps1)
661 494
662 495 self._check_prompt_blank(source_lines, indent, name, lineno,ps1_len)
663 496 if ps2:
664 497 self._check_prefix(source_lines[1:], ' '*indent + ps2, name, lineno)
665 498
666 499 source = '\n'.join([sl[indent+ps1_len+1:] for sl in source_lines])
667 500
668 501 if ip2py:
669 502 # Convert source input from IPython into valid Python syntax
670 503 source = self.ip2py(source)
671 504
672 505 # Divide want into lines; check that it's properly indented; and
673 506 # then strip the indentation. Spaces before the last newline should
674 507 # be preserved, so plain rstrip() isn't good enough.
675 508 want = m.group('want')
676 509 want_lines = want.split('\n')
677 510 if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]):
678 511 del want_lines[-1] # forget final newline & spaces after it
679 512 self._check_prefix(want_lines, ' '*indent, name,
680 513 lineno + len(source_lines))
681 514
682 515 # Remove ipython output prompt that might be present in the first line
683 516 want_lines[0] = re.sub(r'Out\[\d+\]: \s*?\n?','',want_lines[0])
684 517
685 518 want = '\n'.join([wl[indent:] for wl in want_lines])
686 519
687 520 # If `want` contains a traceback message, then extract it.
688 521 m = self._EXCEPTION_RE.match(want)
689 522 if m:
690 523 exc_msg = m.group('msg')
691 524 else:
692 525 exc_msg = None
693 526
694 527 # Extract options from the source.
695 528 options = self._find_options(source, name, lineno)
696 529
697 530 return source, options, want, exc_msg
698 531
699 532 def _check_prompt_blank(self, lines, indent, name, lineno, ps1_len):
700 533 """
701 534 Given the lines of a source string (including prompts and
702 535 leading indentation), check to make sure that every prompt is
703 536 followed by a space character. If any line is not followed by
704 537 a space character, then raise ValueError.
705 538
706 539 Note: IPython-modified version which takes the input prompt length as a
707 540 parameter, so that prompts of variable length can be dealt with.
708 541 """
709 542 space_idx = indent+ps1_len
710 543 min_len = space_idx+1
711 544 for i, line in enumerate(lines):
712 545 if len(line) >= min_len and line[space_idx] != ' ':
713 546 raise ValueError('line %r of the docstring for %s '
714 547 'lacks blank after %s: %r' %
715 548 (lineno+i+1, name,
716 549 line[indent:space_idx], line))
717 550
718 551
719 552 SKIP = doctest.register_optionflag('SKIP')
720 553
721 554
722 555 class IPDocTestRunner(doctest.DocTestRunner,object):
723 556 """Test runner that synchronizes the IPython namespace with test globals.
724 557 """
725 558
726 559 def run(self, test, compileflags=None, out=None, clear_globs=True):
727 560
728 561 # Hack: ipython needs access to the execution context of the example,
729 562 # so that it can propagate user variables loaded by %run into
730 563 # test.globs. We put them here into our modified %run as a function
731 564 # attribute. Our new %run will then only make the namespace update
732 565 # when called (rather than unconconditionally updating test.globs here
733 566 # for all examples, most of which won't be calling %run anyway).
734 _run_ns_sync.test_globs = test.globs
735 _run_ns_sync.test_filename = test.filename
567 #_ip._ipdoctest_test_globs = test.globs
568 #_ip._ipdoctest_test_filename = test.filename
569
570 test.globs.update(_ip.user_ns)
736 571
737 572 return super(IPDocTestRunner,self).run(test,
738 573 compileflags,out,clear_globs)
739 574
740 575
741 576 class DocFileCase(doctest.DocFileCase):
742 577 """Overrides to provide filename
743 578 """
744 579 def address(self):
745 580 return (self._dt_test.filename, None, None)
746 581
747 582
748 583 class ExtensionDoctest(doctests.Doctest):
749 584 """Nose Plugin that supports doctests in extension modules.
750 585 """
751 586 name = 'extdoctest' # call nosetests with --with-extdoctest
752 587 enabled = True
753 588
754 589 def __init__(self,exclude_patterns=None):
755 590 """Create a new ExtensionDoctest plugin.
756 591
757 592 Parameters
758 593 ----------
759 594
760 595 exclude_patterns : sequence of strings, optional
761 596 These patterns are compiled as regular expressions, subsequently used
762 597 to exclude any filename which matches them from inclusion in the test
763 598 suite (using pattern.search(), NOT pattern.match() ).
764 599 """
765 600
766 601 if exclude_patterns is None:
767 602 exclude_patterns = []
768 603 self.exclude_patterns = map(re.compile,exclude_patterns)
769 604 doctests.Doctest.__init__(self)
770 605
771 606 def options(self, parser, env=os.environ):
772 607 Plugin.options(self, parser, env)
773 608 parser.add_option('--doctest-tests', action='store_true',
774 609 dest='doctest_tests',
775 610 default=env.get('NOSE_DOCTEST_TESTS',True),
776 611 help="Also look for doctests in test modules. "
777 612 "Note that classes, methods and functions should "
778 613 "have either doctests or non-doctest tests, "
779 614 "not both. [NOSE_DOCTEST_TESTS]")
780 615 parser.add_option('--doctest-extension', action="append",
781 616 dest="doctestExtension",
782 617 help="Also look for doctests in files with "
783 618 "this extension [NOSE_DOCTEST_EXTENSION]")
784 619 # Set the default as a list, if given in env; otherwise
785 620 # an additional value set on the command line will cause
786 621 # an error.
787 622 env_setting = env.get('NOSE_DOCTEST_EXTENSION')
788 623 if env_setting is not None:
789 624 parser.set_defaults(doctestExtension=tolist(env_setting))
790 625
791 626
792 627 def configure(self, options, config):
793 628 Plugin.configure(self, options, config)
794 629 self.doctest_tests = options.doctest_tests
795 630 self.extension = tolist(options.doctestExtension)
796 631
797 632 self.parser = doctest.DocTestParser()
798 633 self.finder = DocTestFinder()
799 634 self.checker = IPDoctestOutputChecker()
800 635 self.globs = None
801 636 self.extraglobs = None
802 637
803 638
804 639 def loadTestsFromExtensionModule(self,filename):
805 640 bpath,mod = os.path.split(filename)
806 641 modname = os.path.splitext(mod)[0]
807 642 try:
808 643 sys.path.append(bpath)
809 644 module = __import__(modname)
810 645 tests = list(self.loadTestsFromModule(module))
811 646 finally:
812 647 sys.path.pop()
813 648 return tests
814 649
815 650 # NOTE: the method below is almost a copy of the original one in nose, with
816 651 # a few modifications to control output checking.
817 652
818 653 def loadTestsFromModule(self, module):
819 654 #print '*** ipdoctest - lTM',module # dbg
820 655
821 656 if not self.matches(module.__name__):
822 657 log.debug("Doctest doesn't want module %s", module)
823 658 return
824 659
825 660 tests = self.finder.find(module,globs=self.globs,
826 661 extraglobs=self.extraglobs)
827 662 if not tests:
828 663 return
829 664
830 665 # always use whitespace and ellipsis options
831 666 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
832 667
833 668 tests.sort()
834 669 module_file = module.__file__
835 670 if module_file[-4:] in ('.pyc', '.pyo'):
836 671 module_file = module_file[:-1]
837 672 for test in tests:
838 673 if not test.examples:
839 674 continue
840 675 if not test.filename:
841 676 test.filename = module_file
842 677
843 678 yield DocTestCase(test,
844 679 optionflags=optionflags,
845 680 checker=self.checker)
846 681
847 682
848 683 def loadTestsFromFile(self, filename):
684 #print "ipdoctest - from file", filename # dbg
849 685 if is_extension_module(filename):
850 686 for t in self.loadTestsFromExtensionModule(filename):
851 687 yield t
852 688 else:
853 689 if self.extension and anyp(filename.endswith, self.extension):
854 690 name = os.path.basename(filename)
855 691 dh = open(filename)
856 692 try:
857 693 doc = dh.read()
858 694 finally:
859 695 dh.close()
860 696 test = self.parser.get_doctest(
861 697 doc, globs={'__file__': filename}, name=name,
862 698 filename=filename, lineno=0)
863 699 if test.examples:
864 700 #print 'FileCase:',test.examples # dbg
865 701 yield DocFileCase(test)
866 702 else:
867 703 yield False # no tests to load
868 704
869 705 def wantFile(self,filename):
870 706 """Return whether the given filename should be scanned for tests.
871 707
872 708 Modified version that accepts extension modules as valid containers for
873 709 doctests.
874 710 """
875 # print '*** ipdoctest- wantFile:',filename # dbg
711 #print '*** ipdoctest- wantFile:',filename # dbg
876 712
877 713 for pat in self.exclude_patterns:
878 714 if pat.search(filename):
879 715 # print '###>>> SKIP:',filename # dbg
880 716 return False
881 717
882 718 if is_extension_module(filename):
883 719 return True
884 720 else:
885 721 return doctests.Doctest.wantFile(self,filename)
886 722
887 723
888 724 class IPythonDoctest(ExtensionDoctest):
889 725 """Nose Plugin that supports doctests in extension modules.
890 726 """
891 727 name = 'ipdoctest' # call nosetests with --with-ipdoctest
892 728 enabled = True
893
729
894 730 def makeTest(self, obj, parent):
895 731 """Look for doctests in the given object, which will be a
896 732 function, method or class.
897 733 """
734 #print 'Plugin analyzing:', obj, parent # dbg
898 735 # always use whitespace and ellipsis options
899 736 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
900 737
901 738 doctests = self.finder.find(obj, module=getmodule(parent))
902 739 if doctests:
903 740 for test in doctests:
904 741 if len(test.examples) == 0:
905 742 continue
906 743
907 744 yield DocTestCase(test, obj=obj,
908 745 optionflags=optionflags,
909 746 checker=self.checker)
910 747
911 748 def options(self, parser, env=os.environ):
749 #print "Options for nose plugin:", self.name # dbg
912 750 Plugin.options(self, parser, env)
913 751 parser.add_option('--ipdoctest-tests', action='store_true',
914 752 dest='ipdoctest_tests',
915 753 default=env.get('NOSE_IPDOCTEST_TESTS',True),
916 754 help="Also look for doctests in test modules. "
917 755 "Note that classes, methods and functions should "
918 756 "have either doctests or non-doctest tests, "
919 757 "not both. [NOSE_IPDOCTEST_TESTS]")
920 758 parser.add_option('--ipdoctest-extension', action="append",
921 759 dest="ipdoctest_extension",
922 760 help="Also look for doctests in files with "
923 761 "this extension [NOSE_IPDOCTEST_EXTENSION]")
924 762 # Set the default as a list, if given in env; otherwise
925 763 # an additional value set on the command line will cause
926 764 # an error.
927 765 env_setting = env.get('NOSE_IPDOCTEST_EXTENSION')
928 766 if env_setting is not None:
929 767 parser.set_defaults(ipdoctest_extension=tolist(env_setting))
930 768
931 769 def configure(self, options, config):
770 #print "Configuring nose plugin:", self.name # dbg
932 771 Plugin.configure(self, options, config)
933 772 self.doctest_tests = options.ipdoctest_tests
934 773 self.extension = tolist(options.ipdoctest_extension)
935 774
936 775 self.parser = IPDocTestParser()
937 776 self.finder = DocTestFinder(parser=self.parser)
938 777 self.checker = IPDoctestOutputChecker()
939 778 self.globs = None
940 779 self.extraglobs = None
@@ -1,132 +1,221 b''
1 1 """Generic testing tools that do NOT depend on Twisted.
2 2
3 3 In particular, this module exposes a set of top-level assert* functions that
4 4 can be used in place of nose.tools.assert* in method generators (the ones in
5 5 nose can not, at least as of nose 0.10.4).
6 6
7 7 Note: our testing package contains testing.util, which does depend on Twisted
8 8 and provides utilities for tests that manage Deferreds. All testing support
9 9 tools that only depend on nose, IPython or the standard library should go here
10 10 instead.
11 11
12 12
13 13 Authors
14 14 -------
15 15 - Fernando Perez <Fernando.Perez@berkeley.edu>
16 16 """
17 17
18 18 #*****************************************************************************
19 19 # Copyright (C) 2009 The IPython Development Team
20 20 #
21 21 # Distributed under the terms of the BSD License. The full license is in
22 22 # the file COPYING, distributed as part of this software.
23 23 #*****************************************************************************
24 24
25 25 #-----------------------------------------------------------------------------
26 26 # Required modules and packages
27 27 #-----------------------------------------------------------------------------
28 28
29 29 import os
30 30 import re
31 31 import sys
32 import tempfile
32 33
33 34 import nose.tools as nt
34 35
35 from IPython.utils import genutils
36 from IPython.utils import genutils, platutils
36 37
37 38 #-----------------------------------------------------------------------------
38 39 # Globals
39 40 #-----------------------------------------------------------------------------
40 41
41 42 # Make a bunch of nose.tools assert wrappers that can be used in test
42 43 # generators. This will expose an assert* function for each one in nose.tools.
43 44
44 45 _tpl = """
45 46 def %(name)s(*a,**kw):
46 47 return nt.%(name)s(*a,**kw)
47 48 """
48 49
49 50 for _x in [a for a in dir(nt) if a.startswith('assert')]:
50 51 exec _tpl % dict(name=_x)
51 52
52 53 #-----------------------------------------------------------------------------
53 54 # Functions and classes
54 55 #-----------------------------------------------------------------------------
55 56
56 57
57 58 def full_path(startPath,files):
58 59 """Make full paths for all the listed files, based on startPath.
59 60
60 61 Only the base part of startPath is kept, since this routine is typically
61 62 used with a script's __file__ variable as startPath. The base of startPath
62 63 is then prepended to all the listed files, forming the output list.
63 64
64 65 Parameters
65 66 ----------
66 67 startPath : string
67 68 Initial path to use as the base for the results. This path is split
68 69 using os.path.split() and only its first component is kept.
69 70
70 71 files : string or list
71 72 One or more files.
72 73
73 74 Examples
74 75 --------
75 76
76 77 >>> full_path('/foo/bar.py',['a.txt','b.txt'])
77 78 ['/foo/a.txt', '/foo/b.txt']
78 79
79 80 >>> full_path('/foo',['a.txt','b.txt'])
80 81 ['/a.txt', '/b.txt']
81 82
82 83 If a single file is given, the output is still a list:
83 84 >>> full_path('/foo','a.txt')
84 85 ['/a.txt']
85 86 """
86 87
87 88 files = genutils.list_strings(files)
88 89 base = os.path.split(startPath)[0]
89 90 return [ os.path.join(base,f) for f in files ]
90 91
91 92
92 93 def parse_test_output(txt):
93 94 """Parse the output of a test run and return errors, failures.
94 95
95 96 Parameters
96 97 ----------
97 98 txt : str
98 99 Text output of a test run, assumed to contain a line of one of the
99 100 following forms::
100 101 'FAILED (errors=1)'
101 102 'FAILED (failures=1)'
102 103 'FAILED (errors=1, failures=1)'
103 104
104 105 Returns
105 106 -------
106 107 nerr, nfail: number of errors and failures.
107 108 """
108 109
109 110 err_m = re.search(r'^FAILED \(errors=(\d+)\)', txt, re.MULTILINE)
110 111 if err_m:
111 112 nerr = int(err_m.group(1))
112 113 nfail = 0
113 114 return nerr, nfail
114 115
115 116 fail_m = re.search(r'^FAILED \(failures=(\d+)\)', txt, re.MULTILINE)
116 117 if fail_m:
117 118 nerr = 0
118 119 nfail = int(fail_m.group(1))
119 120 return nerr, nfail
120 121
121 122 both_m = re.search(r'^FAILED \(errors=(\d+), failures=(\d+)\)', txt,
122 123 re.MULTILINE)
123 124 if both_m:
124 125 nerr = int(both_m.group(1))
125 126 nfail = int(both_m.group(2))
126 127 return nerr, nfail
127 128
128 129 # If the input didn't match any of these forms, assume no error/failures
129 130 return 0, 0
130 131
132
131 133 # So nose doesn't think this is a test
132 134 parse_test_output.__test__ = False
135
136
137 def temp_pyfile(src, ext='.py'):
138 """Make a temporary python file, return filename and filehandle.
139
140 Parameters
141 ----------
142 src : string or list of strings (no need for ending newlines if list)
143 Source code to be written to the file.
144
145 ext : optional, string
146 Extension for the generated file.
147
148 Returns
149 -------
150 (filename, open filehandle)
151 It is the caller's responsibility to close the open file and unlink it.
152 """
153 fname = tempfile.mkstemp(ext)[1]
154 f = open(fname,'w')
155 f.write(src)
156 f.flush()
157 return fname, f
158
159
160 def default_argv():
161 """Return a valid default argv for creating testing instances of ipython"""
162
163 # Get the install directory for the user configuration and tell ipython to
164 # use the default profile from there.
165 from IPython.config import default
166 ipcdir = os.path.dirname(default.__file__)
167 ipconf = os.path.join(ipcdir,'ipython_config.py')
168 #print 'conf:',ipconf # dbg
169 return ['--colors=NoColor', '--no-term-title','--no-banner',
170 '--config-file=%s' % ipconf, '--autocall=0', '--quick']
171
172
173 def ipexec(fname):
174 """Utility to call 'ipython filename'.
175
176 Starts IPython witha minimal and safe configuration to make startup as fast
177 as possible.
178
179 Note that this starts IPython in a subprocess!
180
181 Parameters
182 ----------
183 fname : str
184 Name of file to be executed (should have .py or .ipy extension).
185
186 Returns
187 -------
188 (stdout, stderr) of ipython subprocess.
189 """
190 _ip = get_ipython()
191 test_dir = os.path.dirname(__file__)
192 full_fname = os.path.join(test_dir, fname)
193 ipython_cmd = platutils.find_cmd('ipython')
194 cmdargs = ' '.join(default_argv())
195 return genutils.getoutputerror('%s %s' % (ipython_cmd, full_fname))
196
197
198 def ipexec_validate(fname, expected_out, expected_err=None):
199 """Utility to call 'ipython filename' and validate output/error.
200
201 This function raises an AssertionError if the validation fails.
202
203 Note that this starts IPython in a subprocess!
204
205 Parameters
206 ----------
207 fname : str
208 Name of the file to be executed (should have .py or .ipy extension).
209
210 expected_out : str
211 Expected stdout of the process.
212
213 Returns
214 -------
215 None
216 """
217
218 out, err = ipexec(fname)
219 nt.assert_equals(out.strip(), expected_out.strip())
220 if expected_err:
221 nt.assert_equals(err.strip(), expected_err.strip())
General Comments 0
You need to be logged in to leave comments. Login now