##// END OF EJS Templates
Remove remaining references held by test suite, so that xdel test passes.
Thomas Kluyver -
Show More
@@ -1,456 +1,471 b''
1 1 """Tests for various magic functions.
2 2
3 3 Needs to be run by nose (to make ipython session available).
4 4 """
5 5 from __future__ import absolute_import
6 6
7 7 #-----------------------------------------------------------------------------
8 8 # Imports
9 9 #-----------------------------------------------------------------------------
10 10
11 11 import os
12 12 import sys
13 13 import tempfile
14 14 import types
15 15 from cStringIO import StringIO
16 16
17 17 import nose.tools as nt
18 18
19 19 from IPython.utils.path import get_long_path_name
20 20 from IPython.testing import decorators as dec
21 21 from IPython.testing import tools as tt
22 22
23 23 #-----------------------------------------------------------------------------
24 24 # Test functions begin
25 25 #-----------------------------------------------------------------------------
26 26 def test_rehashx():
27 27 # clear up everything
28 28 _ip = get_ipython()
29 29 _ip.alias_manager.alias_table.clear()
30 30 del _ip.db['syscmdlist']
31 31
32 32 _ip.magic('rehashx')
33 33 # Practically ALL ipython development systems will have more than 10 aliases
34 34
35 35 yield (nt.assert_true, len(_ip.alias_manager.alias_table) > 10)
36 36 for key, val in _ip.alias_manager.alias_table.iteritems():
37 37 # we must strip dots from alias names
38 38 nt.assert_true('.' not in key)
39 39
40 40 # rehashx must fill up syscmdlist
41 41 scoms = _ip.db['syscmdlist']
42 42 yield (nt.assert_true, len(scoms) > 10)
43 43
44 44
45 45 def test_magic_parse_options():
46 46 """Test that we don't mangle paths when parsing magic options."""
47 47 ip = get_ipython()
48 48 path = 'c:\\x'
49 49 opts = ip.parse_options('-f %s' % path,'f:')[0]
50 50 # argv splitting is os-dependent
51 51 if os.name == 'posix':
52 52 expected = 'c:x'
53 53 else:
54 54 expected = path
55 55 nt.assert_equals(opts['f'], expected)
56 56
57 57
58 58 def doctest_hist_f():
59 59 """Test %hist -f with temporary filename.
60 60
61 61 In [9]: import tempfile
62 62
63 63 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
64 64
65 65 In [11]: %hist -nl -f $tfile 3
66 66
67 67 In [13]: import os; os.unlink(tfile)
68 68 """
69 69
70 70
71 71 def doctest_hist_r():
72 72 """Test %hist -r
73 73
74 74 XXX - This test is not recording the output correctly. For some reason, in
75 75 testing mode the raw history isn't getting populated. No idea why.
76 76 Disabling the output checking for now, though at least we do run it.
77 77
78 78 In [1]: 'hist' in _ip.lsmagic()
79 79 Out[1]: True
80 80
81 81 In [2]: x=1
82 82
83 83 In [3]: %hist -rl 2
84 84 x=1 # random
85 85 %hist -r 2
86 86 """
87 87
88 88 def doctest_hist_op():
89 89 """Test %hist -op
90 90
91 91 In [1]: class b:
92 92 ...: pass
93 93 ...:
94 94
95 95 In [2]: class s(b):
96 96 ...: def __str__(self):
97 97 ...: return 's'
98 98 ...:
99 99
100 100 In [3]:
101 101
102 102 In [4]: class r(b):
103 103 ...: def __repr__(self):
104 104 ...: return 'r'
105 105 ...:
106 106
107 107 In [5]: class sr(s,r): pass
108 108 ...:
109 109
110 110 In [6]:
111 111
112 112 In [7]: bb=b()
113 113
114 114 In [8]: ss=s()
115 115
116 116 In [9]: rr=r()
117 117
118 118 In [10]: ssrr=sr()
119 119
120 120 In [11]: bb
121 121 Out[11]: <...b instance at ...>
122 122
123 123 In [12]: ss
124 124 Out[12]: <...s instance at ...>
125 125
126 126 In [13]:
127 127
128 128 In [14]: %hist -op
129 129 >>> class b:
130 130 ... pass
131 131 ...
132 132 >>> class s(b):
133 133 ... def __str__(self):
134 134 ... return 's'
135 135 ...
136 136 >>>
137 137 >>> class r(b):
138 138 ... def __repr__(self):
139 139 ... return 'r'
140 140 ...
141 141 >>> class sr(s,r): pass
142 142 >>>
143 143 >>> bb=b()
144 144 >>> ss=s()
145 145 >>> rr=r()
146 146 >>> ssrr=sr()
147 147 >>> bb
148 148 <...b instance at ...>
149 149 >>> ss
150 150 <...s instance at ...>
151 151 >>>
152 152 """
153 153
154 154 def test_macro():
155 155 ip = get_ipython()
156 156 ip.history_manager.reset() # Clear any existing history.
157 157 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
158 158 for i, cmd in enumerate(cmds, start=1):
159 159 ip.history_manager.store_inputs(i, cmd)
160 160 ip.magic("macro test 1-3")
161 161 nt.assert_equal(ip.user_ns["test"].value, "\n".join(cmds)+"\n")
162 162
163 163 # List macros.
164 164 assert "test" in ip.magic("macro")
165 165
166 166 def test_macro_run():
167 167 """Test that we can run a multi-line macro successfully."""
168 168 ip = get_ipython()
169 169 ip.history_manager.reset()
170 170 cmds = ["a=10", "a+=1", "print a", "%macro test 2-3"]
171 171 for cmd in cmds:
172 172 ip.run_cell(cmd)
173 173 nt.assert_equal(ip.user_ns["test"].value, "a+=1\nprint a\n")
174 174 original_stdout = sys.stdout
175 175 new_stdout = StringIO()
176 176 sys.stdout = new_stdout
177 177 try:
178 178 ip.run_cell("test")
179 179 nt.assert_true("12" in new_stdout.getvalue())
180 180 ip.run_cell("test")
181 181 nt.assert_true("13" in new_stdout.getvalue())
182 182 finally:
183 183 sys.stdout = original_stdout
184 184 new_stdout.close()
185 185
186 186
187 187 # XXX failing for now, until we get clearcmd out of quarantine. But we should
188 188 # fix this and revert the skip to happen only if numpy is not around.
189 189 #@dec.skipif_not_numpy
190 190 @dec.skip_known_failure
191 191 def test_numpy_clear_array_undec():
192 192 from IPython.extensions import clearcmd
193 193
194 194 _ip.ex('import numpy as np')
195 195 _ip.ex('a = np.empty(2)')
196 196 yield (nt.assert_true, 'a' in _ip.user_ns)
197 197 _ip.magic('clear array')
198 198 yield (nt.assert_false, 'a' in _ip.user_ns)
199 199
200 200
201 201 # Multiple tests for clipboard pasting
202 202 @dec.parametric
203 203 def test_paste():
204 204 _ip = get_ipython()
205 205 def paste(txt, flags='-q'):
206 206 """Paste input text, by default in quiet mode"""
207 207 hooks.clipboard_get = lambda : txt
208 208 _ip.magic('paste '+flags)
209 209
210 210 # Inject fake clipboard hook but save original so we can restore it later
211 211 hooks = _ip.hooks
212 212 user_ns = _ip.user_ns
213 213 original_clip = hooks.clipboard_get
214 214
215 215 try:
216 216 # This try/except with an emtpy except clause is here only because
217 217 # try/yield/finally is invalid syntax in Python 2.4. This will be
218 218 # removed when we drop 2.4-compatibility, and the emtpy except below
219 219 # will be changed to a finally.
220 220
221 221 # Run tests with fake clipboard function
222 222 user_ns.pop('x', None)
223 223 paste('x=1')
224 224 yield nt.assert_equal(user_ns['x'], 1)
225 225
226 226 user_ns.pop('x', None)
227 227 paste('>>> x=2')
228 228 yield nt.assert_equal(user_ns['x'], 2)
229 229
230 230 paste("""
231 231 >>> x = [1,2,3]
232 232 >>> y = []
233 233 >>> for i in x:
234 234 ... y.append(i**2)
235 235 ...
236 236 """)
237 237 yield nt.assert_equal(user_ns['x'], [1,2,3])
238 238 yield nt.assert_equal(user_ns['y'], [1,4,9])
239 239
240 240 # Now, test that paste -r works
241 241 user_ns.pop('x', None)
242 242 yield nt.assert_false('x' in user_ns)
243 243 _ip.magic('paste -r')
244 244 yield nt.assert_equal(user_ns['x'], [1,2,3])
245 245
246 246 # Also test paste echoing, by temporarily faking the writer
247 247 w = StringIO()
248 248 writer = _ip.write
249 249 _ip.write = w.write
250 250 code = """
251 251 a = 100
252 252 b = 200"""
253 253 try:
254 254 paste(code,'')
255 255 out = w.getvalue()
256 256 finally:
257 257 _ip.write = writer
258 258 yield nt.assert_equal(user_ns['a'], 100)
259 259 yield nt.assert_equal(user_ns['b'], 200)
260 260 yield nt.assert_equal(out, code+"\n## -- End pasted text --\n")
261 261
262 262 finally:
263 263 # This should be in a finally clause, instead of the bare except above.
264 264 # Restore original hook
265 265 hooks.clipboard_get = original_clip
266 266
267 267
268 268 def test_time():
269 269 _ip.magic('time None')
270 270
271 271
272 272 def doctest_time():
273 273 """
274 274 In [10]: %time None
275 275 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
276 276 Wall time: 0.00 s
277 277
278 278 In [11]: def f(kmjy):
279 279 ....: %time print 2*kmjy
280 280
281 281 In [12]: f(3)
282 282 6
283 283 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
284 284 Wall time: 0.00 s
285 285 """
286 286
287 287
288 288 def test_doctest_mode():
289 289 "Toggle doctest_mode twice, it should be a no-op and run without error"
290 290 _ip.magic('doctest_mode')
291 291 _ip.magic('doctest_mode')
292 292
293 293
294 294 def test_parse_options():
295 295 """Tests for basic options parsing in magics."""
296 296 # These are only the most minimal of tests, more should be added later. At
297 297 # the very least we check that basic text/unicode calls work OK.
298 298 nt.assert_equal(_ip.parse_options('foo', '')[1], 'foo')
299 299 nt.assert_equal(_ip.parse_options(u'foo', '')[1], u'foo')
300 300
301 301
302 302 def test_dirops():
303 303 """Test various directory handling operations."""
304 304 curpath = lambda :os.path.splitdrive(os.getcwdu())[1].replace('\\','/')
305 305
306 306 startdir = os.getcwdu()
307 307 ipdir = _ip.ipython_dir
308 308 try:
309 309 _ip.magic('cd "%s"' % ipdir)
310 310 nt.assert_equal(curpath(), ipdir)
311 311 _ip.magic('cd -')
312 312 nt.assert_equal(curpath(), startdir)
313 313 _ip.magic('pushd "%s"' % ipdir)
314 314 nt.assert_equal(curpath(), ipdir)
315 315 _ip.magic('popd')
316 316 nt.assert_equal(curpath(), startdir)
317 317 finally:
318 318 os.chdir(startdir)
319 319
320 320
321 321 def check_cpaste(code, should_fail=False):
322 322 """Execute code via 'cpaste' and ensure it was executed, unless
323 323 should_fail is set.
324 324 """
325 325 _ip.user_ns['code_ran'] = False
326 326
327 327 src = StringIO()
328 328 src.write('\n')
329 329 src.write(code)
330 330 src.write('\n--\n')
331 331 src.seek(0)
332 332
333 333 stdin_save = sys.stdin
334 334 sys.stdin = src
335 335
336 336 try:
337 337 _ip.magic('cpaste')
338 338 except:
339 339 if not should_fail:
340 340 raise AssertionError("Failure not expected : '%s'" %
341 341 code)
342 342 else:
343 343 assert _ip.user_ns['code_ran']
344 344 if should_fail:
345 345 raise AssertionError("Failure expected : '%s'" % code)
346 346 finally:
347 347 sys.stdin = stdin_save
348 348
349 349
350 350 def test_cpaste():
351 351 """Test cpaste magic"""
352 352
353 353 def run():
354 354 """Marker function: sets a flag when executed.
355 355 """
356 356 _ip.user_ns['code_ran'] = True
357 357 return 'run' # return string so '+ run()' doesn't result in success
358 358
359 359 tests = {'pass': ["> > > run()",
360 360 ">>> > run()",
361 361 "+++ run()",
362 362 "++ run()",
363 363 " >>> run()"],
364 364
365 365 'fail': ["+ + run()",
366 366 " ++ run()"]}
367 367
368 368 _ip.user_ns['run'] = run
369 369
370 370 for code in tests['pass']:
371 371 check_cpaste(code)
372 372
373 373 for code in tests['fail']:
374 374 check_cpaste(code, should_fail=True)
375 375
376 376 def test_xmode():
377 377 # Calling xmode three times should be a no-op
378 378 xmode = _ip.InteractiveTB.mode
379 379 for i in range(3):
380 380 _ip.magic("xmode")
381 381 nt.assert_equal(_ip.InteractiveTB.mode, xmode)
382 382
383 383 def test_reset_hard():
384 384 monitor = []
385 385 class A(object):
386 386 def __del__(self):
387 387 monitor.append(1)
388 388 def __repr__(self):
389 389 return "<A instance>"
390 390
391 391 _ip.user_ns["a"] = A()
392 392 _ip.run_cell("a")
393 393
394 394 nt.assert_equal(monitor, [])
395 395 _ip.magic_reset("-f")
396 396 nt.assert_equal(monitor, [1])
397 397
398 398 class TestXdel(tt.TempFileMixin):
399 399 def test_xdel(self):
400 400 """Test that references from %run are cleared by xdel."""
401 401 src = ("class A(object):\n"
402 402 " monitor = []\n"
403 403 " def __del__(self):\n"
404 404 " self.monitor.append(1)\n"
405 405 "a = A()\n")
406 406 self.mktmp(src)
407 # %run creates some hidden references...
407 408 _ip.magic("run %s" % self.fname)
409 # ... as does the displayhook.
408 410 _ip.run_cell("a")
411 a = _ip.user_ns["a"]
409 412 monitor = _ip.user_ns["A"].monitor
410 413 nt.assert_equal(monitor, [])
411 414 _ip.magic("xdel a")
415
416 # The testing framework stores extra references - we kill those
417 # here. See IPython.testing.globalipapp.ipnsdict.
418 _ip.user_ns.killrefs(a)
419 del a
420
421 # For some reason the test doesn't pass if this is removed.
422 # TODO: Work out why, and improve the test.
423 f = sys._getframe()
424 print f.f_locals
425
426 # Check that a's __del__ method has been called.
412 427 nt.assert_equal(monitor, [1])
413 428
414 429 def doctest_who():
415 430 """doctest for %who
416 431
417 432 In [1]: %reset -f
418 433
419 434 In [2]: alpha = 123
420 435
421 436 In [3]: beta = 'beta'
422 437
423 438 In [4]: %who int
424 439 alpha
425 440
426 441 In [5]: %who str
427 442 beta
428 443
429 444 In [6]: %whos
430 445 Variable Type Data/Info
431 446 ----------------------------
432 447 alpha int 123
433 448 beta str beta
434 449
435 450 In [7]: %who_ls
436 451 Out[7]: ['alpha', 'beta']
437 452 """
438 453
439 454 def doctest_precision():
440 455 """doctest for %precision
441 456
442 457 In [1]: f = get_ipython().shell.display_formatter.formatters['text/plain']
443 458
444 459 In [2]: %precision 5
445 460 Out[2]: '%.5f'
446 461
447 462 In [3]: f.float_format
448 463 Out[3]: '%.5f'
449 464
450 465 In [4]: %precision %e
451 466 Out[4]: '%e'
452 467
453 468 In [5]: f(3.1415927)
454 469 Out[5]: '3.141593e+00'
455 470 """
456 471
@@ -1,220 +1,229 b''
1 1 """Global IPython app to support test running.
2 2
3 3 We must start our own ipython object and heavily muck with it so that all the
4 4 modifications IPython makes to system behavior don't send the doctest machinery
5 5 into a fit. This code should be considered a gross hack, but it gets the job
6 6 done.
7 7 """
8 8 from __future__ import absolute_import
9 9 from __future__ import print_function
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Copyright (C) 2009-2010 The IPython Development Team
13 13 #
14 14 # Distributed under the terms of the BSD License. The full license is in
15 15 # the file COPYING, distributed as part of this software.
16 16 #-----------------------------------------------------------------------------
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Imports
20 20 #-----------------------------------------------------------------------------
21 21
22 22 # stdlib
23 23 import __builtin__
24 24 import os
25 25 import sys
26 26 from types import MethodType
27 27
28 28 # our own
29 29 from . import tools
30 30
31 31 from IPython.utils import io
32 32 from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
33 33
34 34 #-----------------------------------------------------------------------------
35 35 # Functions
36 36 #-----------------------------------------------------------------------------
37 37
38 38 class StreamProxy(io.IOStream):
39 39 """Proxy for sys.stdout/err. This will request the stream *at call time*
40 40 allowing for nose's Capture plugin's redirection of sys.stdout/err.
41 41
42 42 Parameters
43 43 ----------
44 44 name : str
45 45 The name of the stream. This will be requested anew at every call
46 46 """
47 47
48 48 def __init__(self, name):
49 49 self.name=name
50 50
51 51 @property
52 52 def stream(self):
53 53 return getattr(sys, self.name)
54 54
55 55 def flush(self):
56 56 self.stream.flush()
57 57
58 58 # Hack to modify the %run command so we can sync the user's namespace with the
59 59 # test globals. Once we move over to a clean magic system, this will be done
60 60 # with much less ugliness.
61 61
62 62 class py_file_finder(object):
63 63 def __init__(self,test_filename):
64 64 self.test_filename = test_filename
65 65
66 66 def __call__(self,name):
67 67 from IPython.utils.path import get_py_filename
68 68 try:
69 69 return get_py_filename(name)
70 70 except IOError:
71 71 test_dir = os.path.dirname(self.test_filename)
72 72 new_path = os.path.join(test_dir,name)
73 73 return get_py_filename(new_path)
74 74
75 75
76 76 def _run_ns_sync(self,arg_s,runner=None):
77 77 """Modified version of %run that syncs testing namespaces.
78 78
79 79 This is strictly needed for running doctests that call %run.
80 80 """
81 81 #print('in run_ns_sync', arg_s, file=sys.stderr) # dbg
82 82 finder = py_file_finder(arg_s)
83 83 return get_ipython().magic_run_ori(arg_s, runner, finder)
84 84
85 85
86 86 class ipnsdict(dict):
87 87 """A special subclass of dict for use as an IPython namespace in doctests.
88 88
89 89 This subclass adds a simple checkpointing capability so that when testing
90 90 machinery clears it (we use it as the test execution context), it doesn't
91 91 get completely destroyed.
92 92
93 93 In addition, it can handle the presence of the '_' key in a special manner,
94 94 which is needed because of how Python's doctest machinery operates with
95 95 '_'. See constructor and :meth:`update` for details.
96 96 """
97 97
98 98 def __init__(self,*a):
99 99 dict.__init__(self,*a)
100 100 self._savedict = {}
101 101 # If this flag is True, the .update() method will unconditionally
102 102 # remove a key named '_'. This is so that such a dict can be used as a
103 103 # namespace in doctests that call '_'.
104 104 self.protect_underscore = False
105 105
106 106 def clear(self):
107 107 dict.clear(self)
108 108 self.update(self._savedict)
109 109
110 110 def _checkpoint(self):
111 111 self._savedict.clear()
112 112 self._savedict.update(self)
113 113
114 114 def update(self,other):
115 115 self._checkpoint()
116 116 dict.update(self,other)
117 117
118 118 if self.protect_underscore:
119 119 # If '_' is in the namespace, python won't set it when executing
120 120 # code *in doctests*, and we have multiple doctests that use '_'.
121 121 # So we ensure that the namespace is always 'clean' of it before
122 122 # it's used for test code execution.
123 123 # This flag is only turned on by the doctest machinery, so that
124 124 # normal test code can assume the _ key is updated like any other
125 125 # key and can test for its presence after cell executions.
126 126 self.pop('_', None)
127 127
128 128 # The builtins namespace must *always* be the real __builtin__ module,
129 129 # else weird stuff happens. The main ipython code does have provisions
130 130 # to ensure this after %run, but since in this class we do some
131 131 # aggressive low-level cleaning of the execution namespace, we need to
132 132 # correct for that ourselves, to ensure consitency with the 'real'
133 133 # ipython.
134 134 self['__builtins__'] = __builtin__
135
136 def killrefs(self, obj):
137 """For part of the testing, we need to be able to remove
138 references to an object, which would otherwise be kept in
139 _savedict."""
140 todel = [n for n, o in self._savedict.iteritems() if o is obj]
141 for n in todel:
142 del self._savedict[n]
143
135 144
136 145
137 146 def get_ipython():
138 147 # This will get replaced by the real thing once we start IPython below
139 148 return start_ipython()
140 149
141 150
142 151 # A couple of methods to override those in the running IPython to interact
143 152 # better with doctest (doctest captures on raw stdout, so we need to direct
144 153 # various types of output there otherwise it will miss them).
145 154
146 155 def xsys(self, cmd):
147 156 """Replace the default system call with a capturing one for doctest.
148 157 """
149 158 # We use getoutput, but we need to strip it because pexpect captures
150 159 # the trailing newline differently from commands.getoutput
151 160 print(self.getoutput(cmd, split=False).rstrip(), end='', file=sys.stdout)
152 161 sys.stdout.flush()
153 162
154 163
155 164 def _showtraceback(self, etype, evalue, stb):
156 165 """Print the traceback purely on stdout for doctest to capture it.
157 166 """
158 167 print(self.InteractiveTB.stb2text(stb), file=sys.stdout)
159 168
160 169
161 170 def start_ipython():
162 171 """Start a global IPython shell, which we need for IPython-specific syntax.
163 172 """
164 173 global get_ipython
165 174
166 175 # This function should only ever run once!
167 176 if hasattr(start_ipython, 'already_called'):
168 177 return
169 178 start_ipython.already_called = True
170 179
171 180 # Store certain global objects that IPython modifies
172 181 _displayhook = sys.displayhook
173 182 _excepthook = sys.excepthook
174 183 _main = sys.modules.get('__main__')
175 184
176 185 # Create custom argv and namespaces for our IPython to be test-friendly
177 186 config = tools.default_config()
178 187
179 188 # Create and initialize our test-friendly IPython instance.
180 189 shell = TerminalInteractiveShell.instance(config=config,
181 190 user_ns=ipnsdict(),
182 191 user_global_ns={}
183 192 )
184 193
185 194 # A few more tweaks needed for playing nicely with doctests...
186 195
187 196 # These traps are normally only active for interactive use, set them
188 197 # permanently since we'll be mocking interactive sessions.
189 198 shell.builtin_trap.activate()
190 199
191 200 # Modify the IPython system call with one that uses getoutput, so that we
192 201 # can capture subcommands and print them to Python's stdout, otherwise the
193 202 # doctest machinery would miss them.
194 203 shell.system = MethodType(xsys, shell, TerminalInteractiveShell)
195 204
196 205
197 206 shell._showtraceback = MethodType(_showtraceback, shell,
198 207 TerminalInteractiveShell)
199 208
200 209 # IPython is ready, now clean up some global state...
201 210
202 211 # Deactivate the various python system hooks added by ipython for
203 212 # interactive convenience so we don't confuse the doctest system
204 213 sys.modules['__main__'] = _main
205 214 sys.displayhook = _displayhook
206 215 sys.excepthook = _excepthook
207 216
208 217 # So that ipython magics and aliases can be doctested (they work by making
209 218 # a call into a global _ip object). Also make the top-level get_ipython
210 219 # now return this without recursively calling here again.
211 220 _ip = shell
212 221 get_ipython = _ip.get_ipython
213 222 __builtin__._ip = _ip
214 223 __builtin__.get_ipython = get_ipython
215 224
216 225 # To avoid extra IPython messages during testing, suppress io.stdout/stderr
217 226 io.stdout = StreamProxy('stdout')
218 227 io.stderr = StreamProxy('stderr')
219 228
220 229 return _ip
General Comments 0
You need to be logged in to leave comments. Login now