##// END OF EJS Templates
MAINT: Move `InputRejected` to `IPython.core.error`.
Scott Sanderson -
Show More

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

@@ -1,53 +1,60 b''
1 1 # encoding: utf-8
2 2 """
3 3 Global exception classes for IPython.core.
4 4
5 5 Authors:
6 6
7 7 * Brian Granger
8 8 * Fernando Perez
9 9 * Min Ragan-Kelley
10 10
11 11 Notes
12 12 -----
13 13 """
14 14
15 15 #-----------------------------------------------------------------------------
16 16 # Copyright (C) 2008 The IPython Development Team
17 17 #
18 18 # Distributed under the terms of the BSD License. The full license is in
19 19 # the file COPYING, distributed as part of this software.
20 20 #-----------------------------------------------------------------------------
21 21
22 22 #-----------------------------------------------------------------------------
23 23 # Imports
24 24 #-----------------------------------------------------------------------------
25 25
26 26 #-----------------------------------------------------------------------------
27 27 # Exception classes
28 28 #-----------------------------------------------------------------------------
29 29
30 30 class IPythonCoreError(Exception):
31 31 pass
32 32
33 33
34 34 class TryNext(IPythonCoreError):
35 35 """Try next hook exception.
36 36
37 37 Raise this in your hook function to indicate that the next hook handler
38 38 should be used to handle the operation.
39 39 """
40 40
41 41 class UsageError(IPythonCoreError):
42 42 """Error in magic function arguments, etc.
43 43
44 44 Something that probably won't warrant a full traceback, but should
45 45 nevertheless interrupt a macro / batch file.
46 46 """
47 47
48 48 class StdinNotImplementedError(IPythonCoreError, NotImplementedError):
49 49 """raw_input was requested in a context where it is not supported
50 50
51 51 For use in IPython kernels, where only some frontends may support
52 52 stdin requests.
53 53 """
54
55 class InputRejected(Exception):
56 """Input rejected by ast transformer.
57
58 Raise this in your NodeTransformer to indicate that InteractiveShell should
59 not execute the supplied input.
60 """
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
@@ -1,842 +1,842 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Tests for the key interactiveshell module.
3 3
4 4 Historically the main classes in interactiveshell have been under-tested. This
5 5 module should grow as many single-method tests as possible to trap many of the
6 6 recurring bugs we seem to encounter with high-level interaction.
7 7 """
8 8
9 9 # Copyright (c) IPython Development Team.
10 10 # Distributed under the terms of the Modified BSD License.
11 11
12 12 import ast
13 13 import os
14 14 import signal
15 15 import shutil
16 16 import sys
17 17 import tempfile
18 18 import unittest
19 19 try:
20 20 from unittest import mock
21 21 except ImportError:
22 22 import mock
23 23 from os.path import join
24 24
25 25 import nose.tools as nt
26 26
27 from IPython.core.error import InputRejected
27 28 from IPython.core.inputtransformer import InputTransformer
28 from IPython.lib.security import InputRejected
29 29 from IPython.testing.decorators import (
30 30 skipif, skip_win32, onlyif_unicode_paths, onlyif_cmds_exist,
31 31 )
32 32 from IPython.testing import tools as tt
33 33 from IPython.utils import io
34 34 from IPython.utils.process import find_cmd
35 35 from IPython.utils import py3compat
36 36 from IPython.utils.py3compat import unicode_type, PY3
37 37
38 38 if PY3:
39 39 from io import StringIO
40 40 else:
41 41 from StringIO import StringIO
42 42
43 43 #-----------------------------------------------------------------------------
44 44 # Globals
45 45 #-----------------------------------------------------------------------------
46 46 # This is used by every single test, no point repeating it ad nauseam
47 47 ip = get_ipython()
48 48
49 49 #-----------------------------------------------------------------------------
50 50 # Tests
51 51 #-----------------------------------------------------------------------------
52 52
53 53 class InteractiveShellTestCase(unittest.TestCase):
54 54 def test_naked_string_cells(self):
55 55 """Test that cells with only naked strings are fully executed"""
56 56 # First, single-line inputs
57 57 ip.run_cell('"a"\n')
58 58 self.assertEqual(ip.user_ns['_'], 'a')
59 59 # And also multi-line cells
60 60 ip.run_cell('"""a\nb"""\n')
61 61 self.assertEqual(ip.user_ns['_'], 'a\nb')
62 62
63 63 def test_run_empty_cell(self):
64 64 """Just make sure we don't get a horrible error with a blank
65 65 cell of input. Yes, I did overlook that."""
66 66 old_xc = ip.execution_count
67 67 ip.run_cell('')
68 68 self.assertEqual(ip.execution_count, old_xc)
69 69
70 70 def test_run_cell_multiline(self):
71 71 """Multi-block, multi-line cells must execute correctly.
72 72 """
73 73 src = '\n'.join(["x=1",
74 74 "y=2",
75 75 "if 1:",
76 76 " x += 1",
77 77 " y += 1",])
78 78 ip.run_cell(src)
79 79 self.assertEqual(ip.user_ns['x'], 2)
80 80 self.assertEqual(ip.user_ns['y'], 3)
81 81
82 82 def test_multiline_string_cells(self):
83 83 "Code sprinkled with multiline strings should execute (GH-306)"
84 84 ip.run_cell('tmp=0')
85 85 self.assertEqual(ip.user_ns['tmp'], 0)
86 86 ip.run_cell('tmp=1;"""a\nb"""\n')
87 87 self.assertEqual(ip.user_ns['tmp'], 1)
88 88
89 89 def test_dont_cache_with_semicolon(self):
90 90 "Ending a line with semicolon should not cache the returned object (GH-307)"
91 91 oldlen = len(ip.user_ns['Out'])
92 92 for cell in ['1;', '1;1;']:
93 93 ip.run_cell(cell, store_history=True)
94 94 newlen = len(ip.user_ns['Out'])
95 95 self.assertEqual(oldlen, newlen)
96 96 i = 0
97 97 #also test the default caching behavior
98 98 for cell in ['1', '1;1']:
99 99 ip.run_cell(cell, store_history=True)
100 100 newlen = len(ip.user_ns['Out'])
101 101 i += 1
102 102 self.assertEqual(oldlen+i, newlen)
103 103
104 104 def test_In_variable(self):
105 105 "Verify that In variable grows with user input (GH-284)"
106 106 oldlen = len(ip.user_ns['In'])
107 107 ip.run_cell('1;', store_history=True)
108 108 newlen = len(ip.user_ns['In'])
109 109 self.assertEqual(oldlen+1, newlen)
110 110 self.assertEqual(ip.user_ns['In'][-1],'1;')
111 111
112 112 def test_magic_names_in_string(self):
113 113 ip.run_cell('a = """\n%exit\n"""')
114 114 self.assertEqual(ip.user_ns['a'], '\n%exit\n')
115 115
116 116 def test_trailing_newline(self):
117 117 """test that running !(command) does not raise a SyntaxError"""
118 118 ip.run_cell('!(true)\n', False)
119 119 ip.run_cell('!(true)\n\n\n', False)
120 120
121 121 def test_gh_597(self):
122 122 """Pretty-printing lists of objects with non-ascii reprs may cause
123 123 problems."""
124 124 class Spam(object):
125 125 def __repr__(self):
126 126 return "\xe9"*50
127 127 import IPython.core.formatters
128 128 f = IPython.core.formatters.PlainTextFormatter()
129 129 f([Spam(),Spam()])
130 130
131 131
132 132 def test_future_flags(self):
133 133 """Check that future flags are used for parsing code (gh-777)"""
134 134 ip.run_cell('from __future__ import print_function')
135 135 try:
136 136 ip.run_cell('prfunc_return_val = print(1,2, sep=" ")')
137 137 assert 'prfunc_return_val' in ip.user_ns
138 138 finally:
139 139 # Reset compiler flags so we don't mess up other tests.
140 140 ip.compile.reset_compiler_flags()
141 141
142 142 def test_future_unicode(self):
143 143 """Check that unicode_literals is imported from __future__ (gh #786)"""
144 144 try:
145 145 ip.run_cell(u'byte_str = "a"')
146 146 assert isinstance(ip.user_ns['byte_str'], str) # string literals are byte strings by default
147 147 ip.run_cell('from __future__ import unicode_literals')
148 148 ip.run_cell(u'unicode_str = "a"')
149 149 assert isinstance(ip.user_ns['unicode_str'], unicode_type) # strings literals are now unicode
150 150 finally:
151 151 # Reset compiler flags so we don't mess up other tests.
152 152 ip.compile.reset_compiler_flags()
153 153
154 154 def test_can_pickle(self):
155 155 "Can we pickle objects defined interactively (GH-29)"
156 156 ip = get_ipython()
157 157 ip.reset()
158 158 ip.run_cell(("class Mylist(list):\n"
159 159 " def __init__(self,x=[]):\n"
160 160 " list.__init__(self,x)"))
161 161 ip.run_cell("w=Mylist([1,2,3])")
162 162
163 163 from pickle import dumps
164 164
165 165 # We need to swap in our main module - this is only necessary
166 166 # inside the test framework, because IPython puts the interactive module
167 167 # in place (but the test framework undoes this).
168 168 _main = sys.modules['__main__']
169 169 sys.modules['__main__'] = ip.user_module
170 170 try:
171 171 res = dumps(ip.user_ns["w"])
172 172 finally:
173 173 sys.modules['__main__'] = _main
174 174 self.assertTrue(isinstance(res, bytes))
175 175
176 176 def test_global_ns(self):
177 177 "Code in functions must be able to access variables outside them."
178 178 ip = get_ipython()
179 179 ip.run_cell("a = 10")
180 180 ip.run_cell(("def f(x):\n"
181 181 " return x + a"))
182 182 ip.run_cell("b = f(12)")
183 183 self.assertEqual(ip.user_ns["b"], 22)
184 184
185 185 def test_bad_custom_tb(self):
186 186 """Check that InteractiveShell is protected from bad custom exception handlers"""
187 187 from IPython.utils import io
188 188 save_stderr = io.stderr
189 189 try:
190 190 # capture stderr
191 191 io.stderr = StringIO()
192 192 ip.set_custom_exc((IOError,), lambda etype,value,tb: 1/0)
193 193 self.assertEqual(ip.custom_exceptions, (IOError,))
194 194 ip.run_cell(u'raise IOError("foo")')
195 195 self.assertEqual(ip.custom_exceptions, ())
196 196 self.assertTrue("Custom TB Handler failed" in io.stderr.getvalue())
197 197 finally:
198 198 io.stderr = save_stderr
199 199
200 200 def test_bad_custom_tb_return(self):
201 201 """Check that InteractiveShell is protected from bad return types in custom exception handlers"""
202 202 from IPython.utils import io
203 203 save_stderr = io.stderr
204 204 try:
205 205 # capture stderr
206 206 io.stderr = StringIO()
207 207 ip.set_custom_exc((NameError,),lambda etype,value,tb, tb_offset=None: 1)
208 208 self.assertEqual(ip.custom_exceptions, (NameError,))
209 209 ip.run_cell(u'a=abracadabra')
210 210 self.assertEqual(ip.custom_exceptions, ())
211 211 self.assertTrue("Custom TB Handler failed" in io.stderr.getvalue())
212 212 finally:
213 213 io.stderr = save_stderr
214 214
215 215 def test_drop_by_id(self):
216 216 myvars = {"a":object(), "b":object(), "c": object()}
217 217 ip.push(myvars, interactive=False)
218 218 for name in myvars:
219 219 assert name in ip.user_ns, name
220 220 assert name in ip.user_ns_hidden, name
221 221 ip.user_ns['b'] = 12
222 222 ip.drop_by_id(myvars)
223 223 for name in ["a", "c"]:
224 224 assert name not in ip.user_ns, name
225 225 assert name not in ip.user_ns_hidden, name
226 226 assert ip.user_ns['b'] == 12
227 227 ip.reset()
228 228
229 229 def test_var_expand(self):
230 230 ip.user_ns['f'] = u'Ca\xf1o'
231 231 self.assertEqual(ip.var_expand(u'echo $f'), u'echo Ca\xf1o')
232 232 self.assertEqual(ip.var_expand(u'echo {f}'), u'echo Ca\xf1o')
233 233 self.assertEqual(ip.var_expand(u'echo {f[:-1]}'), u'echo Ca\xf1')
234 234 self.assertEqual(ip.var_expand(u'echo {1*2}'), u'echo 2')
235 235
236 236 ip.user_ns['f'] = b'Ca\xc3\xb1o'
237 237 # This should not raise any exception:
238 238 ip.var_expand(u'echo $f')
239 239
240 240 def test_var_expand_local(self):
241 241 """Test local variable expansion in !system and %magic calls"""
242 242 # !system
243 243 ip.run_cell('def test():\n'
244 244 ' lvar = "ttt"\n'
245 245 ' ret = !echo {lvar}\n'
246 246 ' return ret[0]\n')
247 247 res = ip.user_ns['test']()
248 248 nt.assert_in('ttt', res)
249 249
250 250 # %magic
251 251 ip.run_cell('def makemacro():\n'
252 252 ' macroname = "macro_var_expand_locals"\n'
253 253 ' %macro {macroname} codestr\n')
254 254 ip.user_ns['codestr'] = "str(12)"
255 255 ip.run_cell('makemacro()')
256 256 nt.assert_in('macro_var_expand_locals', ip.user_ns)
257 257
258 258 def test_var_expand_self(self):
259 259 """Test variable expansion with the name 'self', which was failing.
260 260
261 261 See https://github.com/ipython/ipython/issues/1878#issuecomment-7698218
262 262 """
263 263 ip.run_cell('class cTest:\n'
264 264 ' classvar="see me"\n'
265 265 ' def test(self):\n'
266 266 ' res = !echo Variable: {self.classvar}\n'
267 267 ' return res[0]\n')
268 268 nt.assert_in('see me', ip.user_ns['cTest']().test())
269 269
270 270 def test_bad_var_expand(self):
271 271 """var_expand on invalid formats shouldn't raise"""
272 272 # SyntaxError
273 273 self.assertEqual(ip.var_expand(u"{'a':5}"), u"{'a':5}")
274 274 # NameError
275 275 self.assertEqual(ip.var_expand(u"{asdf}"), u"{asdf}")
276 276 # ZeroDivisionError
277 277 self.assertEqual(ip.var_expand(u"{1/0}"), u"{1/0}")
278 278
279 279 def test_silent_postexec(self):
280 280 """run_cell(silent=True) doesn't invoke pre/post_run_cell callbacks"""
281 281 pre_explicit = mock.Mock()
282 282 pre_always = mock.Mock()
283 283 post_explicit = mock.Mock()
284 284 post_always = mock.Mock()
285 285
286 286 ip.events.register('pre_run_cell', pre_explicit)
287 287 ip.events.register('pre_execute', pre_always)
288 288 ip.events.register('post_run_cell', post_explicit)
289 289 ip.events.register('post_execute', post_always)
290 290
291 291 try:
292 292 ip.run_cell("1", silent=True)
293 293 assert pre_always.called
294 294 assert not pre_explicit.called
295 295 assert post_always.called
296 296 assert not post_explicit.called
297 297 # double-check that non-silent exec did what we expected
298 298 # silent to avoid
299 299 ip.run_cell("1")
300 300 assert pre_explicit.called
301 301 assert post_explicit.called
302 302 finally:
303 303 # remove post-exec
304 304 ip.events.reset_all()
305 305
306 306 def test_silent_noadvance(self):
307 307 """run_cell(silent=True) doesn't advance execution_count"""
308 308 ec = ip.execution_count
309 309 # silent should force store_history=False
310 310 ip.run_cell("1", store_history=True, silent=True)
311 311
312 312 self.assertEqual(ec, ip.execution_count)
313 313 # double-check that non-silent exec did what we expected
314 314 # silent to avoid
315 315 ip.run_cell("1", store_history=True)
316 316 self.assertEqual(ec+1, ip.execution_count)
317 317
318 318 def test_silent_nodisplayhook(self):
319 319 """run_cell(silent=True) doesn't trigger displayhook"""
320 320 d = dict(called=False)
321 321
322 322 trap = ip.display_trap
323 323 save_hook = trap.hook
324 324
325 325 def failing_hook(*args, **kwargs):
326 326 d['called'] = True
327 327
328 328 try:
329 329 trap.hook = failing_hook
330 330 ip.run_cell("1", silent=True)
331 331 self.assertFalse(d['called'])
332 332 # double-check that non-silent exec did what we expected
333 333 # silent to avoid
334 334 ip.run_cell("1")
335 335 self.assertTrue(d['called'])
336 336 finally:
337 337 trap.hook = save_hook
338 338
339 339 @skipif(sys.version_info[0] >= 3, "softspace removed in py3")
340 340 def test_print_softspace(self):
341 341 """Verify that softspace is handled correctly when executing multiple
342 342 statements.
343 343
344 344 In [1]: print 1; print 2
345 345 1
346 346 2
347 347
348 348 In [2]: print 1,; print 2
349 349 1 2
350 350 """
351 351
352 352 def test_ofind_line_magic(self):
353 353 from IPython.core.magic import register_line_magic
354 354
355 355 @register_line_magic
356 356 def lmagic(line):
357 357 "A line magic"
358 358
359 359 # Get info on line magic
360 360 lfind = ip._ofind('lmagic')
361 361 info = dict(found=True, isalias=False, ismagic=True,
362 362 namespace = 'IPython internal', obj= lmagic.__wrapped__,
363 363 parent = None)
364 364 nt.assert_equal(lfind, info)
365 365
366 366 def test_ofind_cell_magic(self):
367 367 from IPython.core.magic import register_cell_magic
368 368
369 369 @register_cell_magic
370 370 def cmagic(line, cell):
371 371 "A cell magic"
372 372
373 373 # Get info on cell magic
374 374 find = ip._ofind('cmagic')
375 375 info = dict(found=True, isalias=False, ismagic=True,
376 376 namespace = 'IPython internal', obj= cmagic.__wrapped__,
377 377 parent = None)
378 378 nt.assert_equal(find, info)
379 379
380 380 def test_ofind_property_with_error(self):
381 381 class A(object):
382 382 @property
383 383 def foo(self):
384 384 raise NotImplementedError()
385 385 a = A()
386 386
387 387 found = ip._ofind('a.foo', [('locals', locals())])
388 388 info = dict(found=True, isalias=False, ismagic=False,
389 389 namespace='locals', obj=A.foo, parent=a)
390 390 nt.assert_equal(found, info)
391 391
392 392 def test_ofind_multiple_attribute_lookups(self):
393 393 class A(object):
394 394 @property
395 395 def foo(self):
396 396 raise NotImplementedError()
397 397
398 398 a = A()
399 399 a.a = A()
400 400 a.a.a = A()
401 401
402 402 found = ip._ofind('a.a.a.foo', [('locals', locals())])
403 403 info = dict(found=True, isalias=False, ismagic=False,
404 404 namespace='locals', obj=A.foo, parent=a.a.a)
405 405 nt.assert_equal(found, info)
406 406
407 407 def test_ofind_slotted_attributes(self):
408 408 class A(object):
409 409 __slots__ = ['foo']
410 410 def __init__(self):
411 411 self.foo = 'bar'
412 412
413 413 a = A()
414 414 found = ip._ofind('a.foo', [('locals', locals())])
415 415 info = dict(found=True, isalias=False, ismagic=False,
416 416 namespace='locals', obj=a.foo, parent=a)
417 417 nt.assert_equal(found, info)
418 418
419 419 found = ip._ofind('a.bar', [('locals', locals())])
420 420 info = dict(found=False, isalias=False, ismagic=False,
421 421 namespace=None, obj=None, parent=a)
422 422 nt.assert_equal(found, info)
423 423
424 424 def test_ofind_prefers_property_to_instance_level_attribute(self):
425 425 class A(object):
426 426 @property
427 427 def foo(self):
428 428 return 'bar'
429 429 a = A()
430 430 a.__dict__['foo'] = 'baz'
431 431 nt.assert_equal(a.foo, 'bar')
432 432 found = ip._ofind('a.foo', [('locals', locals())])
433 433 nt.assert_is(found['obj'], A.foo)
434 434
435 435 def test_custom_exception(self):
436 436 called = []
437 437 def my_handler(shell, etype, value, tb, tb_offset=None):
438 438 called.append(etype)
439 439 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
440 440
441 441 ip.set_custom_exc((ValueError,), my_handler)
442 442 try:
443 443 ip.run_cell("raise ValueError('test')")
444 444 # Check that this was called, and only once.
445 445 self.assertEqual(called, [ValueError])
446 446 finally:
447 447 # Reset the custom exception hook
448 448 ip.set_custom_exc((), None)
449 449
450 450 @skipif(sys.version_info[0] >= 3, "no differences with __future__ in py3")
451 451 def test_future_environment(self):
452 452 "Can we run code with & without the shell's __future__ imports?"
453 453 ip.run_cell("from __future__ import division")
454 454 ip.run_cell("a = 1/2", shell_futures=True)
455 455 self.assertEqual(ip.user_ns['a'], 0.5)
456 456 ip.run_cell("b = 1/2", shell_futures=False)
457 457 self.assertEqual(ip.user_ns['b'], 0)
458 458
459 459 ip.compile.reset_compiler_flags()
460 460 # This shouldn't leak to the shell's compiler
461 461 ip.run_cell("from __future__ import division \nc=1/2", shell_futures=False)
462 462 self.assertEqual(ip.user_ns['c'], 0.5)
463 463 ip.run_cell("d = 1/2", shell_futures=True)
464 464 self.assertEqual(ip.user_ns['d'], 0)
465 465
466 466 def test_mktempfile(self):
467 467 filename = ip.mktempfile()
468 468 # Check that we can open the file again on Windows
469 469 with open(filename, 'w') as f:
470 470 f.write('abc')
471 471
472 472 filename = ip.mktempfile(data='blah')
473 473 with open(filename, 'r') as f:
474 474 self.assertEqual(f.read(), 'blah')
475 475
476 476 def test_new_main_mod(self):
477 477 # Smoketest to check that this accepts a unicode module name
478 478 name = u'jiefmw'
479 479 mod = ip.new_main_mod(u'%s.py' % name, name)
480 480 self.assertEqual(mod.__name__, name)
481 481
482 482 class TestSafeExecfileNonAsciiPath(unittest.TestCase):
483 483
484 484 @onlyif_unicode_paths
485 485 def setUp(self):
486 486 self.BASETESTDIR = tempfile.mkdtemp()
487 487 self.TESTDIR = join(self.BASETESTDIR, u"Γ₯Àâ")
488 488 os.mkdir(self.TESTDIR)
489 489 with open(join(self.TESTDIR, u"Γ₯Àâtestscript.py"), "w") as sfile:
490 490 sfile.write("pass\n")
491 491 self.oldpath = py3compat.getcwd()
492 492 os.chdir(self.TESTDIR)
493 493 self.fname = u"Γ₯Àâtestscript.py"
494 494
495 495 def tearDown(self):
496 496 os.chdir(self.oldpath)
497 497 shutil.rmtree(self.BASETESTDIR)
498 498
499 499 @onlyif_unicode_paths
500 500 def test_1(self):
501 501 """Test safe_execfile with non-ascii path
502 502 """
503 503 ip.safe_execfile(self.fname, {}, raise_exceptions=True)
504 504
505 505 class ExitCodeChecks(tt.TempFileMixin):
506 506 def test_exit_code_ok(self):
507 507 self.system('exit 0')
508 508 self.assertEqual(ip.user_ns['_exit_code'], 0)
509 509
510 510 def test_exit_code_error(self):
511 511 self.system('exit 1')
512 512 self.assertEqual(ip.user_ns['_exit_code'], 1)
513 513
514 514 @skipif(not hasattr(signal, 'SIGALRM'))
515 515 def test_exit_code_signal(self):
516 516 self.mktmp("import signal, time\n"
517 517 "signal.setitimer(signal.ITIMER_REAL, 0.1)\n"
518 518 "time.sleep(1)\n")
519 519 self.system("%s %s" % (sys.executable, self.fname))
520 520 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGALRM)
521 521
522 522 @onlyif_cmds_exist("csh")
523 523 def test_exit_code_signal_csh(self):
524 524 SHELL = os.environ.get('SHELL', None)
525 525 os.environ['SHELL'] = find_cmd("csh")
526 526 try:
527 527 self.test_exit_code_signal()
528 528 finally:
529 529 if SHELL is not None:
530 530 os.environ['SHELL'] = SHELL
531 531 else:
532 532 del os.environ['SHELL']
533 533
534 534 class TestSystemRaw(unittest.TestCase, ExitCodeChecks):
535 535 system = ip.system_raw
536 536
537 537 @onlyif_unicode_paths
538 538 def test_1(self):
539 539 """Test system_raw with non-ascii cmd
540 540 """
541 541 cmd = u'''python -c "'Γ₯Àâ'" '''
542 542 ip.system_raw(cmd)
543 543
544 544 # TODO: Exit codes are currently ignored on Windows.
545 545 class TestSystemPipedExitCode(unittest.TestCase, ExitCodeChecks):
546 546 system = ip.system_piped
547 547
548 548 @skip_win32
549 549 def test_exit_code_ok(self):
550 550 ExitCodeChecks.test_exit_code_ok(self)
551 551
552 552 @skip_win32
553 553 def test_exit_code_error(self):
554 554 ExitCodeChecks.test_exit_code_error(self)
555 555
556 556 @skip_win32
557 557 def test_exit_code_signal(self):
558 558 ExitCodeChecks.test_exit_code_signal(self)
559 559
560 560 class TestModules(unittest.TestCase, tt.TempFileMixin):
561 561 def test_extraneous_loads(self):
562 562 """Test we're not loading modules on startup that we shouldn't.
563 563 """
564 564 self.mktmp("import sys\n"
565 565 "print('numpy' in sys.modules)\n"
566 566 "print('IPython.parallel' in sys.modules)\n"
567 567 "print('IPython.kernel.zmq' in sys.modules)\n"
568 568 )
569 569 out = "False\nFalse\nFalse\n"
570 570 tt.ipexec_validate(self.fname, out)
571 571
572 572 class Negator(ast.NodeTransformer):
573 573 """Negates all number literals in an AST."""
574 574 def visit_Num(self, node):
575 575 node.n = -node.n
576 576 return node
577 577
578 578 class TestAstTransform(unittest.TestCase):
579 579 def setUp(self):
580 580 self.negator = Negator()
581 581 ip.ast_transformers.append(self.negator)
582 582
583 583 def tearDown(self):
584 584 ip.ast_transformers.remove(self.negator)
585 585
586 586 def test_run_cell(self):
587 587 with tt.AssertPrints('-34'):
588 588 ip.run_cell('print (12 + 22)')
589 589
590 590 # A named reference to a number shouldn't be transformed.
591 591 ip.user_ns['n'] = 55
592 592 with tt.AssertNotPrints('-55'):
593 593 ip.run_cell('print (n)')
594 594
595 595 def test_timeit(self):
596 596 called = set()
597 597 def f(x):
598 598 called.add(x)
599 599 ip.push({'f':f})
600 600
601 601 with tt.AssertPrints("best of "):
602 602 ip.run_line_magic("timeit", "-n1 f(1)")
603 603 self.assertEqual(called, set([-1]))
604 604 called.clear()
605 605
606 606 with tt.AssertPrints("best of "):
607 607 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
608 608 self.assertEqual(called, set([-2, -3]))
609 609
610 610 def test_time(self):
611 611 called = []
612 612 def f(x):
613 613 called.append(x)
614 614 ip.push({'f':f})
615 615
616 616 # Test with an expression
617 617 with tt.AssertPrints("Wall time: "):
618 618 ip.run_line_magic("time", "f(5+9)")
619 619 self.assertEqual(called, [-14])
620 620 called[:] = []
621 621
622 622 # Test with a statement (different code path)
623 623 with tt.AssertPrints("Wall time: "):
624 624 ip.run_line_magic("time", "a = f(-3 + -2)")
625 625 self.assertEqual(called, [5])
626 626
627 627 def test_macro(self):
628 628 ip.push({'a':10})
629 629 # The AST transformation makes this do a+=-1
630 630 ip.define_macro("amacro", "a+=1\nprint(a)")
631 631
632 632 with tt.AssertPrints("9"):
633 633 ip.run_cell("amacro")
634 634 with tt.AssertPrints("8"):
635 635 ip.run_cell("amacro")
636 636
637 637 class IntegerWrapper(ast.NodeTransformer):
638 638 """Wraps all integers in a call to Integer()"""
639 639 def visit_Num(self, node):
640 640 if isinstance(node.n, int):
641 641 return ast.Call(func=ast.Name(id='Integer', ctx=ast.Load()),
642 642 args=[node], keywords=[])
643 643 return node
644 644
645 645 class TestAstTransform2(unittest.TestCase):
646 646 def setUp(self):
647 647 self.intwrapper = IntegerWrapper()
648 648 ip.ast_transformers.append(self.intwrapper)
649 649
650 650 self.calls = []
651 651 def Integer(*args):
652 652 self.calls.append(args)
653 653 return args
654 654 ip.push({"Integer": Integer})
655 655
656 656 def tearDown(self):
657 657 ip.ast_transformers.remove(self.intwrapper)
658 658 del ip.user_ns['Integer']
659 659
660 660 def test_run_cell(self):
661 661 ip.run_cell("n = 2")
662 662 self.assertEqual(self.calls, [(2,)])
663 663
664 664 # This shouldn't throw an error
665 665 ip.run_cell("o = 2.0")
666 666 self.assertEqual(ip.user_ns['o'], 2.0)
667 667
668 668 def test_timeit(self):
669 669 called = set()
670 670 def f(x):
671 671 called.add(x)
672 672 ip.push({'f':f})
673 673
674 674 with tt.AssertPrints("best of "):
675 675 ip.run_line_magic("timeit", "-n1 f(1)")
676 676 self.assertEqual(called, set([(1,)]))
677 677 called.clear()
678 678
679 679 with tt.AssertPrints("best of "):
680 680 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
681 681 self.assertEqual(called, set([(2,), (3,)]))
682 682
683 683 class ErrorTransformer(ast.NodeTransformer):
684 684 """Throws an error when it sees a number."""
685 685 def visit_Num(self, node):
686 686 raise ValueError("test")
687 687
688 688 class TestAstTransformError(unittest.TestCase):
689 689 def test_unregistering(self):
690 690 err_transformer = ErrorTransformer()
691 691 ip.ast_transformers.append(err_transformer)
692 692
693 693 with tt.AssertPrints("unregister", channel='stderr'):
694 694 ip.run_cell("1 + 2")
695 695
696 696 # This should have been removed.
697 697 nt.assert_not_in(err_transformer, ip.ast_transformers)
698 698
699 699
700 700 class StringRejector(ast.NodeTransformer):
701 701 """Throws an InputRejected when it sees a string literal.
702 702
703 703 Used to verify that NodeTransformers can signal that a piece of code should
704 704 not be executed by throwing an InputRejected.
705 705 """
706 706
707 707 def visit_Str(self, node):
708 708 raise InputRejected("test")
709 709
710 710
711 711 class TestAstTransformInputRejection(unittest.TestCase):
712 712
713 713 def setUp(self):
714 714 self.transformer = StringRejector()
715 715 ip.ast_transformers.append(self.transformer)
716 716
717 717 def tearDown(self):
718 718 ip.ast_transformers.remove(self.transformer)
719 719
720 720 def test_input_rejection(self):
721 721 """Check that NodeTransformers can reject input."""
722 722
723 723 expect_exception_tb = tt.AssertPrints("InputRejected: test")
724 724 expect_no_cell_output = tt.AssertNotPrints("'unsafe'", suppress=False)
725 725
726 726 # Run the same check twice to verify that the transformer is not
727 727 # disabled after raising.
728 728 with expect_exception_tb, expect_no_cell_output:
729 729 ip.run_cell("'unsafe'")
730 730
731 731 with expect_exception_tb, expect_no_cell_output:
732 732 ip.run_cell("'unsafe'")
733 733
734 734 def test__IPYTHON__():
735 735 # This shouldn't raise a NameError, that's all
736 736 __IPYTHON__
737 737
738 738
739 739 class DummyRepr(object):
740 740 def __repr__(self):
741 741 return "DummyRepr"
742 742
743 743 def _repr_html_(self):
744 744 return "<b>dummy</b>"
745 745
746 746 def _repr_javascript_(self):
747 747 return "console.log('hi');", {'key': 'value'}
748 748
749 749
750 750 def test_user_variables():
751 751 # enable all formatters
752 752 ip.display_formatter.active_types = ip.display_formatter.format_types
753 753
754 754 ip.user_ns['dummy'] = d = DummyRepr()
755 755 keys = set(['dummy', 'doesnotexist'])
756 756 r = ip.user_expressions({ key:key for key in keys})
757 757
758 758 nt.assert_equal(keys, set(r.keys()))
759 759 dummy = r['dummy']
760 760 nt.assert_equal(set(['status', 'data', 'metadata']), set(dummy.keys()))
761 761 nt.assert_equal(dummy['status'], 'ok')
762 762 data = dummy['data']
763 763 metadata = dummy['metadata']
764 764 nt.assert_equal(data.get('text/html'), d._repr_html_())
765 765 js, jsmd = d._repr_javascript_()
766 766 nt.assert_equal(data.get('application/javascript'), js)
767 767 nt.assert_equal(metadata.get('application/javascript'), jsmd)
768 768
769 769 dne = r['doesnotexist']
770 770 nt.assert_equal(dne['status'], 'error')
771 771 nt.assert_equal(dne['ename'], 'NameError')
772 772
773 773 # back to text only
774 774 ip.display_formatter.active_types = ['text/plain']
775 775
776 776 def test_user_expression():
777 777 # enable all formatters
778 778 ip.display_formatter.active_types = ip.display_formatter.format_types
779 779 query = {
780 780 'a' : '1 + 2',
781 781 'b' : '1/0',
782 782 }
783 783 r = ip.user_expressions(query)
784 784 import pprint
785 785 pprint.pprint(r)
786 786 nt.assert_equal(set(r.keys()), set(query.keys()))
787 787 a = r['a']
788 788 nt.assert_equal(set(['status', 'data', 'metadata']), set(a.keys()))
789 789 nt.assert_equal(a['status'], 'ok')
790 790 data = a['data']
791 791 metadata = a['metadata']
792 792 nt.assert_equal(data.get('text/plain'), '3')
793 793
794 794 b = r['b']
795 795 nt.assert_equal(b['status'], 'error')
796 796 nt.assert_equal(b['ename'], 'ZeroDivisionError')
797 797
798 798 # back to text only
799 799 ip.display_formatter.active_types = ['text/plain']
800 800
801 801
802 802
803 803
804 804
805 805 class TestSyntaxErrorTransformer(unittest.TestCase):
806 806 """Check that SyntaxError raised by an input transformer is handled by run_cell()"""
807 807
808 808 class SyntaxErrorTransformer(InputTransformer):
809 809
810 810 def push(self, line):
811 811 pos = line.find('syntaxerror')
812 812 if pos >= 0:
813 813 e = SyntaxError('input contains "syntaxerror"')
814 814 e.text = line
815 815 e.offset = pos + 1
816 816 raise e
817 817 return line
818 818
819 819 def reset(self):
820 820 pass
821 821
822 822 def setUp(self):
823 823 self.transformer = TestSyntaxErrorTransformer.SyntaxErrorTransformer()
824 824 ip.input_splitter.python_line_transforms.append(self.transformer)
825 825 ip.input_transformer_manager.python_line_transforms.append(self.transformer)
826 826
827 827 def tearDown(self):
828 828 ip.input_splitter.python_line_transforms.remove(self.transformer)
829 829 ip.input_transformer_manager.python_line_transforms.remove(self.transformer)
830 830
831 831 def test_syntaxerror_input_transformer(self):
832 832 with tt.AssertPrints('1234'):
833 833 ip.run_cell('1234')
834 834 with tt.AssertPrints('SyntaxError: invalid syntax'):
835 835 ip.run_cell('1 2 3') # plain python syntax error
836 836 with tt.AssertPrints('SyntaxError: input contains "syntaxerror"'):
837 837 ip.run_cell('2345 # syntaxerror') # input transformer syntax error
838 838 with tt.AssertPrints('3456'):
839 839 ip.run_cell('3456')
840 840
841 841
842 842
@@ -1,126 +1,116 b''
1 1 """
2 2 Password generation for the IPython notebook.
3 3 """
4 4 #-----------------------------------------------------------------------------
5 5 # Imports
6 6 #-----------------------------------------------------------------------------
7 7 # Stdlib
8 8 import getpass
9 9 import hashlib
10 10 import random
11 11
12 12 # Our own
13 13 from IPython.core.error import UsageError
14 14 from IPython.testing.skipdoctest import skip_doctest
15 15 from IPython.utils.py3compat import cast_bytes, str_to_bytes
16 16
17 17 #-----------------------------------------------------------------------------
18 18 # Globals
19 19 #-----------------------------------------------------------------------------
20 20
21 21 # Length of the salt in nr of hex chars, which implies salt_len * 4
22 22 # bits of randomness.
23 23 salt_len = 12
24 24
25 25 #-----------------------------------------------------------------------------
26 26 # Functions
27 27 #-----------------------------------------------------------------------------
28 28
29 29 @skip_doctest
30 30 def passwd(passphrase=None, algorithm='sha1'):
31 31 """Generate hashed password and salt for use in notebook configuration.
32 32
33 33 In the notebook configuration, set `c.NotebookApp.password` to
34 34 the generated string.
35 35
36 36 Parameters
37 37 ----------
38 38 passphrase : str
39 39 Password to hash. If unspecified, the user is asked to input
40 40 and verify a password.
41 41 algorithm : str
42 42 Hashing algorithm to use (e.g, 'sha1' or any argument supported
43 43 by :func:`hashlib.new`).
44 44
45 45 Returns
46 46 -------
47 47 hashed_passphrase : str
48 48 Hashed password, in the format 'hash_algorithm:salt:passphrase_hash'.
49 49
50 50 Examples
51 51 --------
52 52 >>> passwd('mypassword')
53 53 'sha1:7cf3:b7d6da294ea9592a9480c8f52e63cd42cfb9dd12'
54 54
55 55 """
56 56 if passphrase is None:
57 57 for i in range(3):
58 58 p0 = getpass.getpass('Enter password: ')
59 59 p1 = getpass.getpass('Verify password: ')
60 60 if p0 == p1:
61 61 passphrase = p0
62 62 break
63 63 else:
64 64 print('Passwords do not match.')
65 65 else:
66 66 raise UsageError('No matching passwords found. Giving up.')
67 67
68 68 h = hashlib.new(algorithm)
69 69 salt = ('%0' + str(salt_len) + 'x') % random.getrandbits(4 * salt_len)
70 70 h.update(cast_bytes(passphrase, 'utf-8') + str_to_bytes(salt, 'ascii'))
71 71
72 72 return ':'.join((algorithm, salt, h.hexdigest()))
73 73
74 74
75 75 def passwd_check(hashed_passphrase, passphrase):
76 76 """Verify that a given passphrase matches its hashed version.
77 77
78 78 Parameters
79 79 ----------
80 80 hashed_passphrase : str
81 81 Hashed password, in the format returned by `passwd`.
82 82 passphrase : str
83 83 Passphrase to validate.
84 84
85 85 Returns
86 86 -------
87 87 valid : bool
88 88 True if the passphrase matches the hash.
89 89
90 90 Examples
91 91 --------
92 92 >>> from IPython.lib.security import passwd_check
93 93 >>> passwd_check('sha1:0e112c3ddfce:a68df677475c2b47b6e86d0467eec97ac5f4b85a',
94 94 ... 'mypassword')
95 95 True
96 96
97 97 >>> passwd_check('sha1:0e112c3ddfce:a68df677475c2b47b6e86d0467eec97ac5f4b85a',
98 98 ... 'anotherpassword')
99 99 False
100 100 """
101 101 try:
102 102 algorithm, salt, pw_digest = hashed_passphrase.split(':', 2)
103 103 except (ValueError, TypeError):
104 104 return False
105 105
106 106 try:
107 107 h = hashlib.new(algorithm)
108 108 except ValueError:
109 109 return False
110 110
111 111 if len(pw_digest) == 0:
112 112 return False
113 113
114 114 h.update(cast_bytes(passphrase, 'utf-8') + cast_bytes(salt, 'ascii'))
115 115
116 116 return h.hexdigest() == pw_digest
117
118 #-----------------------------------------------------------------------------
119 # Exception classes
120 #-----------------------------------------------------------------------------
121 class InputRejected(Exception):
122 """Input rejected by ast transformer.
123
124 To be raised by user-supplied ast.NodeTransformers when an input should not
125 be executed.
126 """
General Comments 0
You need to be logged in to leave comments. Login now