##// END OF EJS Templates
Don't exit the event loop when a toolkit event loop exits.
Don't exit the event loop when a toolkit event loop exits.

File last commit:

r7874:4a6836ce
r7944:6d627f5f
Show More
test_interactiveshell.py
407 lines | 14.5 KiB | text/x-python | PythonLexer
/ IPython / core / tests / test_interactiveshell.py
# -*- coding: utf-8 -*-
"""Tests for the key interactiveshell module.
Historically the main classes in interactiveshell have been under-tested. This
module should grow as many single-method tests as possible to trap many of the
recurring bugs we seem to encounter with high-level interaction.
Authors
-------
* Fernando Perez
"""
#-----------------------------------------------------------------------------
# Copyright (C) 2011 The IPython Development Team
#
# Distributed under the terms of the BSD License. The full license is in
# the file COPYING, distributed as part of this software.
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
# stdlib
import os
import shutil
import sys
import tempfile
import unittest
from os.path import join
from StringIO import StringIO
# third-party
import nose.tools as nt
# Our own
from IPython.testing.decorators import skipif
from IPython.utils import io
#-----------------------------------------------------------------------------
# Globals
#-----------------------------------------------------------------------------
# This is used by every single test, no point repeating it ad nauseam
ip = get_ipython()
#-----------------------------------------------------------------------------
# Tests
#-----------------------------------------------------------------------------
class InteractiveShellTestCase(unittest.TestCase):
def test_naked_string_cells(self):
"""Test that cells with only naked strings are fully executed"""
# First, single-line inputs
ip.run_cell('"a"\n')
self.assertEqual(ip.user_ns['_'], 'a')
# And also multi-line cells
ip.run_cell('"""a\nb"""\n')
self.assertEqual(ip.user_ns['_'], 'a\nb')
def test_run_empty_cell(self):
"""Just make sure we don't get a horrible error with a blank
cell of input. Yes, I did overlook that."""
old_xc = ip.execution_count
ip.run_cell('')
self.assertEqual(ip.execution_count, old_xc)
def test_run_cell_multiline(self):
"""Multi-block, multi-line cells must execute correctly.
"""
src = '\n'.join(["x=1",
"y=2",
"if 1:",
" x += 1",
" y += 1",])
ip.run_cell(src)
self.assertEqual(ip.user_ns['x'], 2)
self.assertEqual(ip.user_ns['y'], 3)
def test_multiline_string_cells(self):
"Code sprinkled with multiline strings should execute (GH-306)"
ip.run_cell('tmp=0')
self.assertEqual(ip.user_ns['tmp'], 0)
ip.run_cell('tmp=1;"""a\nb"""\n')
self.assertEqual(ip.user_ns['tmp'], 1)
def test_dont_cache_with_semicolon(self):
"Ending a line with semicolon should not cache the returned object (GH-307)"
oldlen = len(ip.user_ns['Out'])
a = ip.run_cell('1;', store_history=True)
newlen = len(ip.user_ns['Out'])
self.assertEqual(oldlen, newlen)
#also test the default caching behavior
ip.run_cell('1', store_history=True)
newlen = len(ip.user_ns['Out'])
self.assertEqual(oldlen+1, newlen)
def test_In_variable(self):
"Verify that In variable grows with user input (GH-284)"
oldlen = len(ip.user_ns['In'])
ip.run_cell('1;', store_history=True)
newlen = len(ip.user_ns['In'])
self.assertEqual(oldlen+1, newlen)
self.assertEqual(ip.user_ns['In'][-1],'1;')
def test_magic_names_in_string(self):
ip.run_cell('a = """\n%exit\n"""')
self.assertEqual(ip.user_ns['a'], '\n%exit\n')
def test_alias_crash(self):
"""Errors in prefilter can't crash IPython"""
ip.run_cell('%alias parts echo first %s second %s')
# capture stderr:
save_err = io.stderr
io.stderr = StringIO()
ip.run_cell('parts 1')
err = io.stderr.getvalue()
io.stderr = save_err
self.assertEqual(err.split(':')[0], 'ERROR')
def test_trailing_newline(self):
"""test that running !(command) does not raise a SyntaxError"""
ip.run_cell('!(true)\n', False)
ip.run_cell('!(true)\n\n\n', False)
def test_gh_597(self):
"""Pretty-printing lists of objects with non-ascii reprs may cause
problems."""
class Spam(object):
def __repr__(self):
return "\xe9"*50
import IPython.core.formatters
f = IPython.core.formatters.PlainTextFormatter()
f([Spam(),Spam()])
def test_future_flags(self):
"""Check that future flags are used for parsing code (gh-777)"""
ip.run_cell('from __future__ import print_function')
try:
ip.run_cell('prfunc_return_val = print(1,2, sep=" ")')
assert 'prfunc_return_val' in ip.user_ns
finally:
# Reset compiler flags so we don't mess up other tests.
ip.compile.reset_compiler_flags()
def test_future_unicode(self):
"""Check that unicode_literals is imported from __future__ (gh #786)"""
try:
ip.run_cell(u'byte_str = "a"')
assert isinstance(ip.user_ns['byte_str'], str) # string literals are byte strings by default
ip.run_cell('from __future__ import unicode_literals')
ip.run_cell(u'unicode_str = "a"')
assert isinstance(ip.user_ns['unicode_str'], unicode) # strings literals are now unicode
finally:
# Reset compiler flags so we don't mess up other tests.
ip.compile.reset_compiler_flags()
def test_can_pickle(self):
"Can we pickle objects defined interactively (GH-29)"
ip = get_ipython()
ip.reset()
ip.run_cell(("class Mylist(list):\n"
" def __init__(self,x=[]):\n"
" list.__init__(self,x)"))
ip.run_cell("w=Mylist([1,2,3])")
from cPickle import dumps
# We need to swap in our main module - this is only necessary
# inside the test framework, because IPython puts the interactive module
# in place (but the test framework undoes this).
_main = sys.modules['__main__']
sys.modules['__main__'] = ip.user_module
try:
res = dumps(ip.user_ns["w"])
finally:
sys.modules['__main__'] = _main
self.assertTrue(isinstance(res, bytes))
def test_global_ns(self):
"Code in functions must be able to access variables outside them."
ip = get_ipython()
ip.run_cell("a = 10")
ip.run_cell(("def f(x):\n"
" return x + a"))
ip.run_cell("b = f(12)")
self.assertEqual(ip.user_ns["b"], 22)
def test_bad_custom_tb(self):
"""Check that InteractiveShell is protected from bad custom exception handlers"""
from IPython.utils import io
save_stderr = io.stderr
try:
# capture stderr
io.stderr = StringIO()
ip.set_custom_exc((IOError,), lambda etype,value,tb: 1/0)
self.assertEqual(ip.custom_exceptions, (IOError,))
ip.run_cell(u'raise IOError("foo")')
self.assertEqual(ip.custom_exceptions, ())
self.assertTrue("Custom TB Handler failed" in io.stderr.getvalue())
finally:
io.stderr = save_stderr
def test_bad_custom_tb_return(self):
"""Check that InteractiveShell is protected from bad return types in custom exception handlers"""
from IPython.utils import io
save_stderr = io.stderr
try:
# capture stderr
io.stderr = StringIO()
ip.set_custom_exc((NameError,),lambda etype,value,tb, tb_offset=None: 1)
self.assertEqual(ip.custom_exceptions, (NameError,))
ip.run_cell(u'a=abracadabra')
self.assertEqual(ip.custom_exceptions, ())
self.assertTrue("Custom TB Handler failed" in io.stderr.getvalue())
finally:
io.stderr = save_stderr
def test_drop_by_id(self):
myvars = {"a":object(), "b":object(), "c": object()}
ip.push(myvars, interactive=False)
for name in myvars:
assert name in ip.user_ns, name
assert name in ip.user_ns_hidden, name
ip.user_ns['b'] = 12
ip.drop_by_id(myvars)
for name in ["a", "c"]:
assert name not in ip.user_ns, name
assert name not in ip.user_ns_hidden, name
assert ip.user_ns['b'] == 12
ip.reset()
def test_var_expand(self):
ip.user_ns['f'] = u'Ca\xf1o'
self.assertEqual(ip.var_expand(u'echo $f'), u'echo Ca\xf1o')
self.assertEqual(ip.var_expand(u'echo {f}'), u'echo Ca\xf1o')
self.assertEqual(ip.var_expand(u'echo {f[:-1]}'), u'echo Ca\xf1')
self.assertEqual(ip.var_expand(u'echo {1*2}'), u'echo 2')
ip.user_ns['f'] = b'Ca\xc3\xb1o'
# This should not raise any exception:
ip.var_expand(u'echo $f')
def test_var_expand_local(self):
"""Test local variable expansion in !system and %magic calls"""
# !system
ip.run_cell('def test():\n'
' lvar = "ttt"\n'
' ret = !echo {lvar}\n'
' return ret[0]\n')
res = ip.user_ns['test']()
nt.assert_in('ttt', res)
# %magic
ip.run_cell('def makemacro():\n'
' macroname = "macro_var_expand_locals"\n'
' %macro {macroname} codestr\n')
ip.user_ns['codestr'] = "str(12)"
ip.run_cell('makemacro()')
nt.assert_in('macro_var_expand_locals', ip.user_ns)
def test_bad_var_expand(self):
"""var_expand on invalid formats shouldn't raise"""
# SyntaxError
self.assertEqual(ip.var_expand(u"{'a':5}"), u"{'a':5}")
# NameError
self.assertEqual(ip.var_expand(u"{asdf}"), u"{asdf}")
# ZeroDivisionError
self.assertEqual(ip.var_expand(u"{1/0}"), u"{1/0}")
def test_silent_nopostexec(self):
"""run_cell(silent=True) doesn't invoke post-exec funcs"""
d = dict(called=False)
def set_called():
d['called'] = True
ip.register_post_execute(set_called)
ip.run_cell("1", silent=True)
self.assertFalse(d['called'])
# double-check that non-silent exec did what we expected
# silent to avoid
ip.run_cell("1")
self.assertTrue(d['called'])
# remove post-exec
ip._post_execute.pop(set_called)
def test_silent_noadvance(self):
"""run_cell(silent=True) doesn't advance execution_count"""
ec = ip.execution_count
# silent should force store_history=False
ip.run_cell("1", store_history=True, silent=True)
self.assertEqual(ec, ip.execution_count)
# double-check that non-silent exec did what we expected
# silent to avoid
ip.run_cell("1", store_history=True)
self.assertEqual(ec+1, ip.execution_count)
def test_silent_nodisplayhook(self):
"""run_cell(silent=True) doesn't trigger displayhook"""
d = dict(called=False)
trap = ip.display_trap
save_hook = trap.hook
def failing_hook(*args, **kwargs):
d['called'] = True
try:
trap.hook = failing_hook
ip.run_cell("1", silent=True)
self.assertFalse(d['called'])
# double-check that non-silent exec did what we expected
# silent to avoid
ip.run_cell("1")
self.assertTrue(d['called'])
finally:
trap.hook = save_hook
@skipif(sys.version_info[0] >= 3, "softspace removed in py3")
def test_print_softspace(self):
"""Verify that softspace is handled correctly when executing multiple
statements.
In [1]: print 1; print 2
1
2
In [2]: print 1,; print 2
1 2
"""
def test_ofind_line_magic(self):
from IPython.core.magic import register_line_magic
@register_line_magic
def lmagic(line):
"A line magic"
# Get info on line magic
lfind = ip._ofind('lmagic')
info = dict(found=True, isalias=False, ismagic=True,
namespace = 'IPython internal', obj= lmagic.__wrapped__,
parent = None)
nt.assert_equal(lfind, info)
def test_ofind_cell_magic(self):
from IPython.core.magic import register_cell_magic
@register_cell_magic
def cmagic(line, cell):
"A cell magic"
# Get info on cell magic
find = ip._ofind('cmagic')
info = dict(found=True, isalias=False, ismagic=True,
namespace = 'IPython internal', obj= cmagic.__wrapped__,
parent = None)
nt.assert_equal(find, info)
def test_custom_exception(self):
called = []
def my_handler(shell, etype, value, tb, tb_offset=None):
called.append(etype)
shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
ip.set_custom_exc((ValueError,), my_handler)
try:
ip.run_cell("raise ValueError('test')")
# Check that this was called, and only once.
self.assertEqual(called, [ValueError])
finally:
# Reset the custom exception hook
ip.set_custom_exc((), None)
class TestSafeExecfileNonAsciiPath(unittest.TestCase):
def setUp(self):
self.BASETESTDIR = tempfile.mkdtemp()
self.TESTDIR = join(self.BASETESTDIR, u"åäö")
os.mkdir(self.TESTDIR)
with open(join(self.TESTDIR, u"åäötestscript.py"), "w") as sfile:
sfile.write("pass\n")
self.oldpath = os.getcwdu()
os.chdir(self.TESTDIR)
self.fname = u"åäötestscript.py"
def tearDown(self):
os.chdir(self.oldpath)
shutil.rmtree(self.BASETESTDIR)
def test_1(self):
"""Test safe_execfile with non-ascii path
"""
ip.safe_execfile(self.fname, {}, raise_exceptions=True)
class TestSystemRaw(unittest.TestCase):
def test_1(self):
"""Test system_raw with non-ascii cmd
"""
cmd = ur'''python -c "'åäö'" '''
ip.system_raw(cmd)
def test__IPYTHON__():
# This shouldn't raise a NameError, that's all
__IPYTHON__