Uploaded Test files

This commit is contained in:
Batuhan Berk Başoğlu 2020-11-12 11:05:57 -05:00
parent f584ad9d97
commit 2e81cb7d99
16627 changed files with 2065359 additions and 102444 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 B

View file

@ -0,0 +1,14 @@
"""Module with bad __all__
To test https://github.com/ipython/ipython/issues/9678
"""
def evil():
pass
def puppies():
pass
__all__ = [evil, # Bad
'puppies', # Good
]

View file

@ -0,0 +1,12 @@
# -*- coding: utf-8 -*-
"""
Useless IPython extension to test installing and loading extensions.
"""
some_vars = {'arq': 185}
def load_ipython_extension(ip):
# set up simplified quantity input
ip.push(some_vars)
def unload_ipython_extension(ip):
ip.drop_by_id(some_vars)

View file

@ -0,0 +1,4 @@
# coding: iso-8859-5
# (Unlikely to be the default encoding for most testers.)
# ±¶ÿàáâãäåæçèéêëìíîï <- Cyrillic characters
u = '®âðÄ'

View file

@ -0,0 +1,4 @@
# coding: iso-8859-5
# (Unlikely to be the default encoding for most testers.)
# БЖџрстуфхцчшщъыьэюя <- Cyrillic characters
'Ўт№Ф'

View file

@ -0,0 +1,2 @@
import sys
print(sys.argv[1:])

View file

@ -0,0 +1,46 @@
"""Minimal script to reproduce our nasty reference counting bug.
The problem is related to https://github.com/ipython/ipython/issues/141
The original fix for that appeared to work, but John D. Hunter found a
matplotlib example which, when run twice in a row, would break. The problem
were references held by open figures to internals of Tkinter.
This code reproduces the problem that John saw, without matplotlib.
This script is meant to be called by other parts of the test suite that call it
via %run as if it were executed interactively by the user. As of 2011-05-29,
test_run.py calls it.
"""
#-----------------------------------------------------------------------------
# Module imports
#-----------------------------------------------------------------------------
from IPython import get_ipython
#-----------------------------------------------------------------------------
# Globals
#-----------------------------------------------------------------------------
# This needs to be here because nose and other test runners will import
# this module. Importing this module has potential side effects that we
# want to prevent.
if __name__ == '__main__':
ip = get_ipython()
if not '_refbug_cache' in ip.user_ns:
ip.user_ns['_refbug_cache'] = []
aglobal = 'Hello'
def f():
return aglobal
cache = ip.user_ns['_refbug_cache']
cache.append(f)
def call_f():
for func in cache:
print('lowercased:',func().lower())

View file

@ -0,0 +1,32 @@
"""Error script. DO NOT EDIT FURTHER! It will break exception doctests!!!"""
import sys
def div0():
"foo"
x = 1
y = 0
x/y
def sysexit(stat, mode):
raise SystemExit(stat, 'Mode = %s' % mode)
def bar(mode):
"bar"
if mode=='div':
div0()
elif mode=='exit':
try:
stat = int(sys.argv[2])
except:
stat = 1
sysexit(stat, mode)
else:
raise ValueError('Unknown mode')
if __name__ == '__main__':
try:
mode = sys.argv[1]
except IndexError:
mode = 'div'
bar(mode)

View file

@ -0,0 +1,34 @@
"""Simple script to be run *twice*, to check reference counting bugs.
See test_run for details."""
import sys
# We want to ensure that while objects remain available for immediate access,
# objects from *previous* runs of the same script get collected, to avoid
# accumulating massive amounts of old references.
class C(object):
def __init__(self,name):
self.name = name
self.p = print
self.flush_stdout = sys.stdout.flush
def __del__(self):
self.p('tclass.py: deleting object:',self.name)
self.flush_stdout()
try:
name = sys.argv[1]
except IndexError:
pass
else:
if name.startswith('C'):
c = C(name)
#print >> sys.stderr, "ARGV:", sys.argv # dbg
# This next print statement is NOT debugging, we're making the check on a
# completely separate process so we verify by capturing stdout:
print('ARGV 1-:', sys.argv[1:])
sys.stdout.flush()

View file

@ -0,0 +1,65 @@
from IPython.utils.capture import capture_output
import nose.tools as nt
def test_alias_lifecycle():
name = 'test_alias1'
cmd = 'echo "Hello"'
am = _ip.alias_manager
am.clear_aliases()
am.define_alias(name, cmd)
assert am.is_alias(name)
nt.assert_equal(am.retrieve_alias(name), cmd)
nt.assert_in((name, cmd), am.aliases)
# Test running the alias
orig_system = _ip.system
result = []
_ip.system = result.append
try:
_ip.run_cell('%{}'.format(name))
result = [c.strip() for c in result]
nt.assert_equal(result, [cmd])
finally:
_ip.system = orig_system
# Test removing the alias
am.undefine_alias(name)
assert not am.is_alias(name)
with nt.assert_raises(ValueError):
am.retrieve_alias(name)
nt.assert_not_in((name, cmd), am.aliases)
def test_alias_args_error():
"""Error expanding with wrong number of arguments"""
_ip.alias_manager.define_alias('parts', 'echo first %s second %s')
# capture stderr:
with capture_output() as cap:
_ip.run_cell('parts 1')
nt.assert_equal(cap.stderr.split(':')[0], 'UsageError')
def test_alias_args_commented():
"""Check that alias correctly ignores 'commented out' args"""
_ip.magic('alias commetarg echo this is %%s a commented out arg')
with capture_output() as cap:
_ip.run_cell('commetarg')
# strip() is for pytest compat; testing via iptest patch IPython shell
# in testin.globalipapp and replace the system call which messed up the
# \r\n
assert cap.stdout.strip() == 'this is %s a commented out arg'
def test_alias_args_commented_nargs():
"""Check that alias correctly counts args, excluding those commented out"""
am = _ip.alias_manager
alias_name = 'comargcount'
cmd = 'echo this is %%s a commented out arg and this is not %s'
am.define_alias(alias_name, cmd)
assert am.is_alias(alias_name)
thealias = am.get_alias(alias_name)
nt.assert_equal(thealias.nargs, 1)

View file

@ -0,0 +1,73 @@
# coding: utf-8
"""Tests for IPython.core.application"""
import os
import tempfile
import nose.tools as nt
from traitlets import Unicode
from IPython.core.application import BaseIPythonApplication
from IPython.testing import decorators as dec
from IPython.utils.tempdir import TemporaryDirectory
@dec.onlyif_unicode_paths
def test_unicode_cwd():
"""Check that IPython starts with non-ascii characters in the path."""
wd = tempfile.mkdtemp(suffix=u"")
old_wd = os.getcwd()
os.chdir(wd)
#raise Exception(repr(os.getcwd()))
try:
app = BaseIPythonApplication()
# The lines below are copied from Application.initialize()
app.init_profile_dir()
app.init_config_files()
app.load_config_file(suppress_errors=False)
finally:
os.chdir(old_wd)
@dec.onlyif_unicode_paths
def test_unicode_ipdir():
"""Check that IPython starts with non-ascii characters in the IP dir."""
ipdir = tempfile.mkdtemp(suffix=u"")
# Create the config file, so it tries to load it.
with open(os.path.join(ipdir, 'ipython_config.py'), "w") as f:
pass
old_ipdir1 = os.environ.pop("IPYTHONDIR", None)
old_ipdir2 = os.environ.pop("IPYTHON_DIR", None)
os.environ["IPYTHONDIR"] = ipdir
try:
app = BaseIPythonApplication()
# The lines below are copied from Application.initialize()
app.init_profile_dir()
app.init_config_files()
app.load_config_file(suppress_errors=False)
finally:
if old_ipdir1:
os.environ["IPYTHONDIR"] = old_ipdir1
if old_ipdir2:
os.environ["IPYTHONDIR"] = old_ipdir2
def test_cli_priority():
with TemporaryDirectory() as td:
class TestApp(BaseIPythonApplication):
test = Unicode().tag(config=True)
# Create the config file, so it tries to load it.
with open(os.path.join(td, 'ipython_config.py'), "w") as f:
f.write("c.TestApp.test = 'config file'")
app = TestApp()
app.initialize(['--profile-dir', td])
nt.assert_equal(app.test, 'config file')
app = TestApp()
app.initialize(['--profile-dir', td, '--TestApp.test=cli'])
nt.assert_equal(app.test, 'cli')

View file

@ -0,0 +1,316 @@
"""
Test for async helpers.
Should only trigger on python 3.5+ or will have syntax errors.
"""
from itertools import chain, repeat
import nose.tools as nt
from textwrap import dedent, indent
from unittest import TestCase
from IPython.testing.decorators import skip_without
import sys
iprc = lambda x: ip.run_cell(dedent(x)).raise_error()
iprc_nr = lambda x: ip.run_cell(dedent(x))
from IPython.core.async_helpers import _should_be_async
class AsyncTest(TestCase):
def test_should_be_async(self):
nt.assert_false(_should_be_async("False"))
nt.assert_true(_should_be_async("await bar()"))
nt.assert_true(_should_be_async("x = await bar()"))
nt.assert_false(
_should_be_async(
dedent(
"""
async def awaitable():
pass
"""
)
)
)
def _get_top_level_cases(self):
# These are test cases that should be valid in a function
# but invalid outside of a function.
test_cases = []
test_cases.append(('basic', "{val}"))
# Note, in all conditional cases, I use True instead of
# False so that the peephole optimizer won't optimize away
# the return, so CPython will see this as a syntax error:
#
# while True:
# break
# return
#
# But not this:
#
# while False:
# return
#
# See https://bugs.python.org/issue1875
test_cases.append(('if', dedent("""
if True:
{val}
""")))
test_cases.append(('while', dedent("""
while True:
{val}
break
""")))
test_cases.append(('try', dedent("""
try:
{val}
except:
pass
""")))
test_cases.append(('except', dedent("""
try:
pass
except:
{val}
""")))
test_cases.append(('finally', dedent("""
try:
pass
except:
pass
finally:
{val}
""")))
test_cases.append(('for', dedent("""
for _ in range(4):
{val}
""")))
test_cases.append(('nested', dedent("""
if True:
while True:
{val}
break
""")))
test_cases.append(('deep-nested', dedent("""
if True:
while True:
break
for x in range(3):
if True:
while True:
for x in range(3):
{val}
""")))
return test_cases
def _get_ry_syntax_errors(self):
# This is a mix of tests that should be a syntax error if
# return or yield whether or not they are in a function
test_cases = []
test_cases.append(('class', dedent("""
class V:
{val}
""")))
test_cases.append(('nested-class', dedent("""
class V:
class C:
{val}
""")))
return test_cases
def test_top_level_return_error(self):
tl_err_test_cases = self._get_top_level_cases()
tl_err_test_cases.extend(self._get_ry_syntax_errors())
vals = ('return', 'yield', 'yield from (_ for _ in range(3))',
dedent('''
def f():
pass
return
'''),
)
for test_name, test_case in tl_err_test_cases:
# This example should work if 'pass' is used as the value
with self.subTest((test_name, 'pass')):
iprc(test_case.format(val='pass'))
# It should fail with all the values
for val in vals:
with self.subTest((test_name, val)):
msg = "Syntax error not raised for %s, %s" % (test_name, val)
with self.assertRaises(SyntaxError, msg=msg):
iprc(test_case.format(val=val))
def test_in_func_no_error(self):
# Test that the implementation of top-level return/yield
# detection isn't *too* aggressive, and works inside a function
func_contexts = []
func_contexts.append(('func', False, dedent("""
def f():""")))
func_contexts.append(('method', False, dedent("""
class MyClass:
def __init__(self):
""")))
func_contexts.append(('async-func', True, dedent("""
async def f():""")))
func_contexts.append(('async-method', True, dedent("""
class MyClass:
async def f(self):""")))
func_contexts.append(('closure', False, dedent("""
def f():
def g():
""")))
def nest_case(context, case):
# Detect indentation
lines = context.strip().splitlines()
prefix_len = 0
for c in lines[-1]:
if c != ' ':
break
prefix_len += 1
indented_case = indent(case, ' ' * (prefix_len + 4))
return context + '\n' + indented_case
# Gather and run the tests
# yield is allowed in async functions, starting in Python 3.6,
# and yield from is not allowed in any version
vals = ('return', 'yield', 'yield from (_ for _ in range(3))')
async_safe = (True,
True,
False)
vals = tuple(zip(vals, async_safe))
success_tests = zip(self._get_top_level_cases(), repeat(False))
failure_tests = zip(self._get_ry_syntax_errors(), repeat(True))
tests = chain(success_tests, failure_tests)
for context_name, async_func, context in func_contexts:
for (test_name, test_case), should_fail in tests:
nested_case = nest_case(context, test_case)
for val, async_safe in vals:
val_should_fail = (should_fail or
(async_func and not async_safe))
test_id = (context_name, test_name, val)
cell = nested_case.format(val=val)
with self.subTest(test_id):
if val_should_fail:
msg = ("SyntaxError not raised for %s" %
str(test_id))
with self.assertRaises(SyntaxError, msg=msg):
iprc(cell)
print(cell)
else:
iprc(cell)
def test_nonlocal(self):
# fails if outer scope is not a function scope or if var not defined
with self.assertRaises(SyntaxError):
iprc("nonlocal x")
iprc("""
x = 1
def f():
nonlocal x
x = 10000
yield x
""")
iprc("""
def f():
def g():
nonlocal x
x = 10000
yield x
""")
# works if outer scope is a function scope and var exists
iprc("""
def f():
x = 20
def g():
nonlocal x
x = 10000
yield x
""")
def test_execute(self):
iprc("""
import asyncio
await asyncio.sleep(0.001)
"""
)
def test_autoawait(self):
iprc("%autoawait False")
iprc("%autoawait True")
iprc("""
from asyncio import sleep
await sleep(0.1)
"""
)
if sys.version_info < (3,9):
# new pgen parser in 3.9 does not raise MemoryError on too many nested
# parens anymore
def test_memory_error(self):
with self.assertRaises(MemoryError):
iprc("(" * 200 + ")" * 200)
@skip_without('curio')
def test_autoawait_curio(self):
iprc("%autoawait curio")
@skip_without('trio')
def test_autoawait_trio(self):
iprc("%autoawait trio")
@skip_without('trio')
def test_autoawait_trio_wrong_sleep(self):
iprc("%autoawait trio")
res = iprc_nr("""
import asyncio
await asyncio.sleep(0)
""")
with nt.assert_raises(TypeError):
res.raise_error()
@skip_without('trio')
def test_autoawait_asyncio_wrong_sleep(self):
iprc("%autoawait asyncio")
res = iprc_nr("""
import trio
await trio.sleep(0)
""")
with nt.assert_raises(RuntimeError):
res.raise_error()
def tearDown(self):
ip.loop_runner = "asyncio"

View file

@ -0,0 +1,66 @@
"""These kinds of tests are less than ideal, but at least they run.
This was an old test that was being run interactively in the top-level tests/
directory, which we are removing. For now putting this here ensures at least
we do run the test, though ultimately this functionality should all be tested
with better-isolated tests that don't rely on the global instance in iptest.
"""
from IPython.core.splitinput import LineInfo
from IPython.core.prefilter import AutocallChecker
def doctest_autocall():
"""
In [1]: def f1(a,b,c):
...: return a+b+c
...:
In [2]: def f2(a):
...: return a + a
...:
In [3]: def r(x):
...: return True
...:
In [4]: ;f2 a b c
Out[4]: 'a b ca b c'
In [5]: assert _ == "a b ca b c"
In [6]: ,f1 a b c
Out[6]: 'abc'
In [7]: assert _ == 'abc'
In [8]: print(_)
abc
In [9]: /f1 1,2,3
Out[9]: 6
In [10]: assert _ == 6
In [11]: /f2 4
Out[11]: 8
In [12]: assert _ == 8
In [12]: del f1, f2
In [13]: ,r a
Out[13]: True
In [14]: assert _ == True
In [15]: r'a'
Out[15]: 'a'
In [16]: assert _ == 'a'
"""
def test_autocall_should_ignore_raw_strings():
line_info = LineInfo("r'a'")
pm = ip.prefilter_manager
ac = AutocallChecker(shell=pm.shell, prefilter_manager=pm, config=pm.config)
assert ac.check(line_info) is None

View file

@ -0,0 +1,73 @@
# coding: utf-8
"""Tests for the compilerop module.
"""
#-----------------------------------------------------------------------------
# Copyright (C) 2010-2011 The IPython Development Team.
#
# Distributed under the terms of the BSD License.
#
# The full license is in the file COPYING.txt, distributed with this software.
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
# Stdlib imports
import linecache
import sys
# Third-party imports
import nose.tools as nt
# Our own imports
from IPython.core import compilerop
#-----------------------------------------------------------------------------
# Test functions
#-----------------------------------------------------------------------------
def test_code_name():
code = 'x=1'
name = compilerop.code_name(code)
nt.assert_true(name.startswith('<ipython-input-0'))
def test_code_name2():
code = 'x=1'
name = compilerop.code_name(code, 9)
nt.assert_true(name.startswith('<ipython-input-9'))
def test_cache():
"""Test the compiler correctly compiles and caches inputs
"""
cp = compilerop.CachingCompiler()
ncache = len(linecache.cache)
cp.cache('x=1')
nt.assert_true(len(linecache.cache) > ncache)
def test_proper_default_encoding():
# Check we're in a proper Python 2 environment (some imports, such
# as GTK, can change the default encoding, which can hide bugs.)
nt.assert_equal(sys.getdefaultencoding(), "utf-8")
def test_cache_unicode():
cp = compilerop.CachingCompiler()
ncache = len(linecache.cache)
cp.cache(u"t = 'žćčšđ'")
nt.assert_true(len(linecache.cache) > ncache)
def test_compiler_check_cache():
"""Test the compiler properly manages the cache.
"""
# Rather simple-minded tests that just exercise the API
cp = compilerop.CachingCompiler()
cp.cache('x=1', 99)
# Ensure now that after clearing the cache, our entries survive
linecache.checkcache()
for k in linecache.cache:
if k.startswith('<ipython-input-99'):
break
else:
raise AssertionError('Entry for input-99 missing from linecache')

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,178 @@
# -*- coding: utf-8 -*-
"""Tests for completerlib.
"""
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
import os
import shutil
import sys
import tempfile
import unittest
from os.path import join
import nose.tools as nt
from IPython.core.completerlib import magic_run_completer, module_completion, try_import
from IPython.utils.tempdir import TemporaryDirectory
from IPython.testing.decorators import onlyif_unicode_paths
class MockEvent(object):
def __init__(self, line):
self.line = line
#-----------------------------------------------------------------------------
# Test functions begin
#-----------------------------------------------------------------------------
class Test_magic_run_completer(unittest.TestCase):
files = [u"aao.py", u"a.py", u"b.py", u"aao.txt"]
dirs = [u"adir/", "bdir/"]
def setUp(self):
self.BASETESTDIR = tempfile.mkdtemp()
for fil in self.files:
with open(join(self.BASETESTDIR, fil), "w") as sfile:
sfile.write("pass\n")
for d in self.dirs:
os.mkdir(join(self.BASETESTDIR, d))
self.oldpath = os.getcwd()
os.chdir(self.BASETESTDIR)
def tearDown(self):
os.chdir(self.oldpath)
shutil.rmtree(self.BASETESTDIR)
def test_1(self):
"""Test magic_run_completer, should match two alternatives
"""
event = MockEvent(u"%run a")
mockself = None
match = set(magic_run_completer(mockself, event))
self.assertEqual(match, {u"a.py", u"aao.py", u"adir/"})
def test_2(self):
"""Test magic_run_completer, should match one alternative
"""
event = MockEvent(u"%run aa")
mockself = None
match = set(magic_run_completer(mockself, event))
self.assertEqual(match, {u"aao.py"})
def test_3(self):
"""Test magic_run_completer with unterminated " """
event = MockEvent(u'%run "a')
mockself = None
match = set(magic_run_completer(mockself, event))
self.assertEqual(match, {u"a.py", u"aao.py", u"adir/"})
def test_completion_more_args(self):
event = MockEvent(u'%run a.py ')
match = set(magic_run_completer(None, event))
self.assertEqual(match, set(self.files + self.dirs))
def test_completion_in_dir(self):
# Github issue #3459
event = MockEvent(u'%run a.py {}'.format(join(self.BASETESTDIR, 'a')))
print(repr(event.line))
match = set(magic_run_completer(None, event))
# We specifically use replace here rather than normpath, because
# at one point there were duplicates 'adir' and 'adir/', and normpath
# would hide the failure for that.
self.assertEqual(match, {join(self.BASETESTDIR, f).replace('\\','/')
for f in (u'a.py', u'aao.py', u'aao.txt', u'adir/')})
class Test_magic_run_completer_nonascii(unittest.TestCase):
@onlyif_unicode_paths
def setUp(self):
self.BASETESTDIR = tempfile.mkdtemp()
for fil in [u"aaø.py", u"a.py", u"b.py"]:
with open(join(self.BASETESTDIR, fil), "w") as sfile:
sfile.write("pass\n")
self.oldpath = os.getcwd()
os.chdir(self.BASETESTDIR)
def tearDown(self):
os.chdir(self.oldpath)
shutil.rmtree(self.BASETESTDIR)
@onlyif_unicode_paths
def test_1(self):
"""Test magic_run_completer, should match two alternatives
"""
event = MockEvent(u"%run a")
mockself = None
match = set(magic_run_completer(mockself, event))
self.assertEqual(match, {u"a.py", u"aaø.py"})
@onlyif_unicode_paths
def test_2(self):
"""Test magic_run_completer, should match one alternative
"""
event = MockEvent(u"%run aa")
mockself = None
match = set(magic_run_completer(mockself, event))
self.assertEqual(match, {u"aaø.py"})
@onlyif_unicode_paths
def test_3(self):
"""Test magic_run_completer with unterminated " """
event = MockEvent(u'%run "a')
mockself = None
match = set(magic_run_completer(mockself, event))
self.assertEqual(match, {u"a.py", u"aaø.py"})
# module_completer:
def test_import_invalid_module():
"""Testing of issue https://github.com/ipython/ipython/issues/1107"""
invalid_module_names = {'foo-bar', 'foo:bar', '10foo'}
valid_module_names = {'foobar'}
with TemporaryDirectory() as tmpdir:
sys.path.insert( 0, tmpdir )
for name in invalid_module_names | valid_module_names:
filename = os.path.join(tmpdir, name + '.py')
open(filename, 'w').close()
s = set( module_completion('import foo') )
intersection = s.intersection(invalid_module_names)
nt.assert_equal(intersection, set())
assert valid_module_names.issubset(s), valid_module_names.intersection(s)
def test_bad_module_all():
"""Test module with invalid __all__
https://github.com/ipython/ipython/issues/9678
"""
testsdir = os.path.dirname(__file__)
sys.path.insert(0, testsdir)
try:
results = module_completion('from bad_all import ')
nt.assert_in('puppies', results)
for r in results:
nt.assert_is_instance(r, str)
finally:
sys.path.remove(testsdir)
def test_module_without_init():
"""
Test module without __init__.py.
https://github.com/ipython/ipython/issues/11226
"""
fake_module_name = "foo"
with TemporaryDirectory() as tmpdir:
sys.path.insert(0, tmpdir)
try:
os.makedirs(os.path.join(tmpdir, fake_module_name))
s = try_import(mod=fake_module_name)
assert s == []
finally:
sys.path.remove(tmpdir)

View file

@ -0,0 +1,326 @@
"""Tests for debugging machinery.
"""
# Copyright (c) IPython Development Team.
# Distributed under the terms of the Modified BSD License.
import bdb
import builtins
import os
import signal
import subprocess
import sys
import time
import warnings
from subprocess import PIPE, CalledProcessError, check_output
from tempfile import NamedTemporaryFile
from textwrap import dedent
from unittest.mock import patch
import nose.tools as nt
from IPython.core import debugger
from IPython.testing import IPYTHON_TESTING_TIMEOUT_SCALE
from IPython.testing.decorators import skip_win32
#-----------------------------------------------------------------------------
# Helper classes, from CPython's Pdb test suite
#-----------------------------------------------------------------------------
class _FakeInput(object):
"""
A fake input stream for pdb's interactive debugger. Whenever a
line is read, print it (to simulate the user typing it), and then
return it. The set of lines to return is specified in the
constructor; they should not have trailing newlines.
"""
def __init__(self, lines):
self.lines = iter(lines)
def readline(self):
line = next(self.lines)
print(line)
return line+'\n'
class PdbTestInput(object):
"""Context manager that makes testing Pdb in doctests easier."""
def __init__(self, input):
self.input = input
def __enter__(self):
self.real_stdin = sys.stdin
sys.stdin = _FakeInput(self.input)
def __exit__(self, *exc):
sys.stdin = self.real_stdin
#-----------------------------------------------------------------------------
# Tests
#-----------------------------------------------------------------------------
def test_longer_repr():
try:
from reprlib import repr as trepr # Py 3
except ImportError:
from repr import repr as trepr # Py 2
a = '1234567890'* 7
ar = "'1234567890123456789012345678901234567890123456789012345678901234567890'"
a_trunc = "'123456789012...8901234567890'"
nt.assert_equal(trepr(a), a_trunc)
# The creation of our tracer modifies the repr module's repr function
# in-place, since that global is used directly by the stdlib's pdb module.
with warnings.catch_warnings():
warnings.simplefilter('ignore', DeprecationWarning)
debugger.Tracer()
nt.assert_equal(trepr(a), ar)
def test_ipdb_magics():
'''Test calling some IPython magics from ipdb.
First, set up some test functions and classes which we can inspect.
>>> class ExampleClass(object):
... """Docstring for ExampleClass."""
... def __init__(self):
... """Docstring for ExampleClass.__init__"""
... pass
... def __str__(self):
... return "ExampleClass()"
>>> def example_function(x, y, z="hello"):
... """Docstring for example_function."""
... pass
>>> old_trace = sys.gettrace()
Create a function which triggers ipdb.
>>> def trigger_ipdb():
... a = ExampleClass()
... debugger.Pdb().set_trace()
>>> with PdbTestInput([
... 'pdef example_function',
... 'pdoc ExampleClass',
... 'up',
... 'down',
... 'list',
... 'pinfo a',
... 'll',
... 'continue',
... ]):
... trigger_ipdb()
--Return--
None
> <doctest ...>(3)trigger_ipdb()
1 def trigger_ipdb():
2 a = ExampleClass()
----> 3 debugger.Pdb().set_trace()
<BLANKLINE>
ipdb> pdef example_function
example_function(x, y, z='hello')
ipdb> pdoc ExampleClass
Class docstring:
Docstring for ExampleClass.
Init docstring:
Docstring for ExampleClass.__init__
ipdb> up
> <doctest ...>(11)<module>()
7 'pinfo a',
8 'll',
9 'continue',
10 ]):
---> 11 trigger_ipdb()
<BLANKLINE>
ipdb> down
None
> <doctest ...>(3)trigger_ipdb()
1 def trigger_ipdb():
2 a = ExampleClass()
----> 3 debugger.Pdb().set_trace()
<BLANKLINE>
ipdb> list
1 def trigger_ipdb():
2 a = ExampleClass()
----> 3 debugger.Pdb().set_trace()
<BLANKLINE>
ipdb> pinfo a
Type: ExampleClass
String form: ExampleClass()
Namespace: Local...
Docstring: Docstring for ExampleClass.
Init docstring: Docstring for ExampleClass.__init__
ipdb> ll
1 def trigger_ipdb():
2 a = ExampleClass()
----> 3 debugger.Pdb().set_trace()
<BLANKLINE>
ipdb> continue
Restore previous trace function, e.g. for coverage.py
>>> sys.settrace(old_trace)
'''
def test_ipdb_magics2():
'''Test ipdb with a very short function.
>>> old_trace = sys.gettrace()
>>> def bar():
... pass
Run ipdb.
>>> with PdbTestInput([
... 'continue',
... ]):
... debugger.Pdb().runcall(bar)
> <doctest ...>(2)bar()
1 def bar():
----> 2 pass
<BLANKLINE>
ipdb> continue
Restore previous trace function, e.g. for coverage.py
>>> sys.settrace(old_trace)
'''
def can_quit():
'''Test that quit work in ipydb
>>> old_trace = sys.gettrace()
>>> def bar():
... pass
>>> with PdbTestInput([
... 'quit',
... ]):
... debugger.Pdb().runcall(bar)
> <doctest ...>(2)bar()
1 def bar():
----> 2 pass
<BLANKLINE>
ipdb> quit
Restore previous trace function, e.g. for coverage.py
>>> sys.settrace(old_trace)
'''
def can_exit():
'''Test that quit work in ipydb
>>> old_trace = sys.gettrace()
>>> def bar():
... pass
>>> with PdbTestInput([
... 'exit',
... ]):
... debugger.Pdb().runcall(bar)
> <doctest ...>(2)bar()
1 def bar():
----> 2 pass
<BLANKLINE>
ipdb> exit
Restore previous trace function, e.g. for coverage.py
>>> sys.settrace(old_trace)
'''
def test_interruptible_core_debugger():
"""The debugger can be interrupted.
The presumption is there is some mechanism that causes a KeyboardInterrupt
(this is implemented in ipykernel). We want to ensure the
KeyboardInterrupt cause debugging to cease.
"""
def raising_input(msg="", called=[0]):
called[0] += 1
if called[0] == 1:
raise KeyboardInterrupt()
else:
raise AssertionError("input() should only be called once!")
with patch.object(builtins, "input", raising_input):
debugger.InterruptiblePdb().set_trace()
# The way this test will fail is by set_trace() never exiting,
# resulting in a timeout by the test runner. The alternative
# implementation would involve a subprocess, but that adds issues with
# interrupting subprocesses that are rather complex, so it's simpler
# just to do it this way.
@skip_win32
def test_xmode_skip():
"""that xmode skip frames
Not as a doctest as pytest does not run doctests.
"""
import pexpect
env = os.environ.copy()
env["IPY_TEST_SIMPLE_PROMPT"] = "1"
child = pexpect.spawn(
sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
)
child.timeout = 15 * IPYTHON_TESTING_TIMEOUT_SCALE
child.expect("IPython")
child.expect("\n")
child.expect_exact("In [1]")
block = dedent(
"""
def f():
__tracebackhide__ = True
g()
def g():
raise ValueError
f()
"""
)
for line in block.splitlines():
child.sendline(line)
child.expect_exact(line)
child.expect_exact("skipping")
block = dedent(
"""
def f():
__tracebackhide__ = True
g()
def g():
from IPython.core.debugger import set_trace
set_trace()
f()
"""
)
for line in block.splitlines():
child.sendline(line)
child.expect_exact(line)
child.expect("ipdb>")
child.sendline("w")
child.expect("hidden")
child.expect("ipdb>")
child.sendline("skip_hidden false")
child.sendline("w")
child.expect("__traceba")
child.expect("ipdb>")
child.close()

View file

@ -0,0 +1,455 @@
# Copyright (c) IPython Development Team.
# Distributed under the terms of the Modified BSD License.
import json
import os
import warnings
from unittest import mock
import nose.tools as nt
from IPython.core import display
from IPython.core.getipython import get_ipython
from IPython.utils.io import capture_output
from IPython.utils.tempdir import NamedFileInTemporaryDirectory
from IPython import paths as ipath
from IPython.testing.tools import AssertNotPrints
import IPython.testing.decorators as dec
def test_image_size():
"""Simple test for display.Image(args, width=x,height=y)"""
thisurl = 'http://www.google.fr/images/srpr/logo3w.png'
img = display.Image(url=thisurl, width=200, height=200)
nt.assert_equal(u'<img src="%s" width="200" height="200"/>' % (thisurl), img._repr_html_())
img = display.Image(url=thisurl, metadata={'width':200, 'height':200})
nt.assert_equal(u'<img src="%s" width="200" height="200"/>' % (thisurl), img._repr_html_())
img = display.Image(url=thisurl, width=200)
nt.assert_equal(u'<img src="%s" width="200"/>' % (thisurl), img._repr_html_())
img = display.Image(url=thisurl)
nt.assert_equal(u'<img src="%s"/>' % (thisurl), img._repr_html_())
img = display.Image(url=thisurl, unconfined=True)
nt.assert_equal(u'<img src="%s" class="unconfined"/>' % (thisurl), img._repr_html_())
def test_image_mimes():
fmt = get_ipython().display_formatter.format
for format in display.Image._ACCEPTABLE_EMBEDDINGS:
mime = display.Image._MIMETYPES[format]
img = display.Image(b'garbage', format=format)
data, metadata = fmt(img)
nt.assert_equal(sorted(data), sorted([mime, 'text/plain']))
def test_geojson():
gj = display.GeoJSON(data={
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-81.327, 296.038]
},
"properties": {
"name": "Inca City"
}
},
url_template="http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/{basemap_id}/{z}/{x}/{y}.png",
layer_options={
"basemap_id": "celestia_mars-shaded-16k_global",
"attribution": "Celestia/praesepe",
"minZoom": 0,
"maxZoom": 18,
})
nt.assert_equal(u'<IPython.core.display.GeoJSON object>', str(gj))
def test_retina_png():
here = os.path.dirname(__file__)
img = display.Image(os.path.join(here, "2x2.png"), retina=True)
nt.assert_equal(img.height, 1)
nt.assert_equal(img.width, 1)
data, md = img._repr_png_()
nt.assert_equal(md['width'], 1)
nt.assert_equal(md['height'], 1)
def test_embed_svg_url():
import gzip
from io import BytesIO
svg_data = b'<svg><circle x="0" y="0" r="1"/></svg>'
url = 'http://test.com/circle.svg'
gzip_svg = BytesIO()
with gzip.open(gzip_svg, 'wb') as fp:
fp.write(svg_data)
gzip_svg = gzip_svg.getvalue()
def mocked_urlopen(*args, **kwargs):
class MockResponse:
def __init__(self, svg):
self._svg_data = svg
self.headers = {'content-type': 'image/svg+xml'}
def read(self):
return self._svg_data
if args[0] == url:
return MockResponse(svg_data)
elif args[0] == url + 'z':
ret= MockResponse(gzip_svg)
ret.headers['content-encoding']= 'gzip'
return ret
return MockResponse(None)
with mock.patch('urllib.request.urlopen', side_effect=mocked_urlopen):
svg = display.SVG(url=url)
nt.assert_true(svg._repr_svg_().startswith('<svg'))
svg = display.SVG(url=url + 'z')
nt.assert_true(svg._repr_svg_().startswith('<svg'))
def test_retina_jpeg():
here = os.path.dirname(__file__)
img = display.Image(os.path.join(here, "2x2.jpg"), retina=True)
nt.assert_equal(img.height, 1)
nt.assert_equal(img.width, 1)
data, md = img._repr_jpeg_()
nt.assert_equal(md['width'], 1)
nt.assert_equal(md['height'], 1)
def test_base64image():
display.Image("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB94BCRQnOqNu0b4AAAAKSURBVAjXY2AAAAACAAHiIbwzAAAAAElFTkSuQmCC")
def test_image_filename_defaults():
'''test format constraint, and validity of jpeg and png'''
tpath = ipath.get_ipython_package_dir()
nt.assert_raises(ValueError, display.Image, filename=os.path.join(tpath, 'testing/tests/badformat.zip'),
embed=True)
nt.assert_raises(ValueError, display.Image)
nt.assert_raises(ValueError, display.Image, data='this is not an image', format='badformat', embed=True)
# check boths paths to allow packages to test at build and install time
imgfile = os.path.join(tpath, 'core/tests/2x2.png')
img = display.Image(filename=imgfile)
nt.assert_equal('png', img.format)
nt.assert_is_not_none(img._repr_png_())
img = display.Image(filename=os.path.join(tpath, 'testing/tests/logo.jpg'), embed=False)
nt.assert_equal('jpeg', img.format)
nt.assert_is_none(img._repr_jpeg_())
def _get_inline_config():
from ipykernel.pylab.config import InlineBackend
return InlineBackend.instance()
@dec.skip_without('matplotlib')
def test_set_matplotlib_close():
cfg = _get_inline_config()
cfg.close_figures = False
display.set_matplotlib_close()
assert cfg.close_figures
display.set_matplotlib_close(False)
assert not cfg.close_figures
_fmt_mime_map = {
'png': 'image/png',
'jpeg': 'image/jpeg',
'pdf': 'application/pdf',
'retina': 'image/png',
'svg': 'image/svg+xml',
}
@dec.skip_without('matplotlib')
def test_set_matplotlib_formats():
from matplotlib.figure import Figure
formatters = get_ipython().display_formatter.formatters
for formats in [
('png',),
('pdf', 'svg'),
('jpeg', 'retina', 'png'),
(),
]:
active_mimes = {_fmt_mime_map[fmt] for fmt in formats}
display.set_matplotlib_formats(*formats)
for mime, f in formatters.items():
if mime in active_mimes:
nt.assert_in(Figure, f)
else:
nt.assert_not_in(Figure, f)
@dec.skip_without('matplotlib')
def test_set_matplotlib_formats_kwargs():
from matplotlib.figure import Figure
ip = get_ipython()
cfg = _get_inline_config()
cfg.print_figure_kwargs.update(dict(foo='bar'))
kwargs = dict(quality=10)
display.set_matplotlib_formats('png', **kwargs)
formatter = ip.display_formatter.formatters['image/png']
f = formatter.lookup_by_type(Figure)
cell = f.__closure__[0].cell_contents
expected = kwargs
expected.update(cfg.print_figure_kwargs)
nt.assert_equal(cell, expected)
def test_display_available():
"""
Test that display is available without import
We don't really care if it's in builtin or anything else, but it should
always be available.
"""
ip = get_ipython()
with AssertNotPrints('NameError'):
ip.run_cell('display')
try:
ip.run_cell('del display')
except NameError:
pass # it's ok, it might be in builtins
# even if deleted it should be back
with AssertNotPrints('NameError'):
ip.run_cell('display')
def test_textdisplayobj_pretty_repr():
p = display.Pretty("This is a simple test")
nt.assert_equal(repr(p), '<IPython.core.display.Pretty object>')
nt.assert_equal(p.data, 'This is a simple test')
p._show_mem_addr = True
nt.assert_equal(repr(p), object.__repr__(p))
def test_displayobject_repr():
h = display.HTML('<br />')
nt.assert_equal(repr(h), '<IPython.core.display.HTML object>')
h._show_mem_addr = True
nt.assert_equal(repr(h), object.__repr__(h))
h._show_mem_addr = False
nt.assert_equal(repr(h), '<IPython.core.display.HTML object>')
j = display.Javascript('')
nt.assert_equal(repr(j), '<IPython.core.display.Javascript object>')
j._show_mem_addr = True
nt.assert_equal(repr(j), object.__repr__(j))
j._show_mem_addr = False
nt.assert_equal(repr(j), '<IPython.core.display.Javascript object>')
@mock.patch('warnings.warn')
def test_encourage_iframe_over_html(m_warn):
display.HTML()
m_warn.assert_not_called()
display.HTML('<br />')
m_warn.assert_not_called()
display.HTML('<html><p>Lots of content here</p><iframe src="http://a.com"></iframe>')
m_warn.assert_not_called()
display.HTML('<iframe src="http://a.com"></iframe>')
m_warn.assert_called_with('Consider using IPython.display.IFrame instead')
m_warn.reset_mock()
display.HTML('<IFRAME SRC="http://a.com"></IFRAME>')
m_warn.assert_called_with('Consider using IPython.display.IFrame instead')
def test_progress():
p = display.ProgressBar(10)
nt.assert_in('0/10',repr(p))
p.html_width = '100%'
p.progress = 5
nt.assert_equal(p._repr_html_(), "<progress style='width:100%' max='10' value='5'></progress>")
def test_progress_iter():
with capture_output(display=False) as captured:
for i in display.ProgressBar(5):
out = captured.stdout
nt.assert_in('{0}/5'.format(i), out)
out = captured.stdout
nt.assert_in('5/5', out)
def test_json():
d = {'a': 5}
lis = [d]
metadata = [
{'expanded': False, 'root': 'root'},
{'expanded': True, 'root': 'root'},
{'expanded': False, 'root': 'custom'},
{'expanded': True, 'root': 'custom'},
]
json_objs = [
display.JSON(d),
display.JSON(d, expanded=True),
display.JSON(d, root='custom'),
display.JSON(d, expanded=True, root='custom'),
]
for j, md in zip(json_objs, metadata):
nt.assert_equal(j._repr_json_(), (d, md))
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
j = display.JSON(json.dumps(d))
nt.assert_equal(len(w), 1)
nt.assert_equal(j._repr_json_(), (d, metadata[0]))
json_objs = [
display.JSON(lis),
display.JSON(lis, expanded=True),
display.JSON(lis, root='custom'),
display.JSON(lis, expanded=True, root='custom'),
]
for j, md in zip(json_objs, metadata):
nt.assert_equal(j._repr_json_(), (lis, md))
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
j = display.JSON(json.dumps(lis))
nt.assert_equal(len(w), 1)
nt.assert_equal(j._repr_json_(), (lis, metadata[0]))
def test_video_embedding():
"""use a tempfile, with dummy-data, to ensure that video embedding doesn't crash"""
v = display.Video("http://ignored")
assert not v.embed
html = v._repr_html_()
nt.assert_not_in('src="data:', html)
nt.assert_in('src="http://ignored"', html)
with nt.assert_raises(ValueError):
v = display.Video(b'abc')
with NamedFileInTemporaryDirectory('test.mp4') as f:
f.write(b'abc')
f.close()
v = display.Video(f.name)
assert not v.embed
html = v._repr_html_()
nt.assert_not_in('src="data:', html)
v = display.Video(f.name, embed=True)
html = v._repr_html_()
nt.assert_in('src="data:video/mp4;base64,YWJj"',html)
v = display.Video(f.name, embed=True, mimetype='video/other')
html = v._repr_html_()
nt.assert_in('src="data:video/other;base64,YWJj"',html)
v = display.Video(b'abc', embed=True, mimetype='video/mp4')
html = v._repr_html_()
nt.assert_in('src="data:video/mp4;base64,YWJj"',html)
v = display.Video(u'YWJj', embed=True, mimetype='video/xyz')
html = v._repr_html_()
nt.assert_in('src="data:video/xyz;base64,YWJj"',html)
def test_html_metadata():
s = "<h1>Test</h1>"
h = display.HTML(s, metadata={"isolated": True})
nt.assert_equal(h._repr_html_(), (s, {"isolated": True}))
def test_display_id():
ip = get_ipython()
with mock.patch.object(ip.display_pub, 'publish') as pub:
handle = display.display('x')
nt.assert_is(handle, None)
handle = display.display('y', display_id='secret')
nt.assert_is_instance(handle, display.DisplayHandle)
handle2 = display.display('z', display_id=True)
nt.assert_is_instance(handle2, display.DisplayHandle)
nt.assert_not_equal(handle.display_id, handle2.display_id)
nt.assert_equal(pub.call_count, 3)
args, kwargs = pub.call_args_list[0]
nt.assert_equal(args, ())
nt.assert_equal(kwargs, {
'data': {
'text/plain': repr('x')
},
'metadata': {},
})
args, kwargs = pub.call_args_list[1]
nt.assert_equal(args, ())
nt.assert_equal(kwargs, {
'data': {
'text/plain': repr('y')
},
'metadata': {},
'transient': {
'display_id': handle.display_id,
},
})
args, kwargs = pub.call_args_list[2]
nt.assert_equal(args, ())
nt.assert_equal(kwargs, {
'data': {
'text/plain': repr('z')
},
'metadata': {},
'transient': {
'display_id': handle2.display_id,
},
})
def test_update_display():
ip = get_ipython()
with mock.patch.object(ip.display_pub, 'publish') as pub:
with nt.assert_raises(TypeError):
display.update_display('x')
display.update_display('x', display_id='1')
display.update_display('y', display_id='2')
args, kwargs = pub.call_args_list[0]
nt.assert_equal(args, ())
nt.assert_equal(kwargs, {
'data': {
'text/plain': repr('x')
},
'metadata': {},
'transient': {
'display_id': '1',
},
'update': True,
})
args, kwargs = pub.call_args_list[1]
nt.assert_equal(args, ())
nt.assert_equal(kwargs, {
'data': {
'text/plain': repr('y')
},
'metadata': {},
'transient': {
'display_id': '2',
},
'update': True,
})
def test_display_handle():
ip = get_ipython()
handle = display.DisplayHandle()
nt.assert_is_instance(handle.display_id, str)
handle = display.DisplayHandle('my-id')
nt.assert_equal(handle.display_id, 'my-id')
with mock.patch.object(ip.display_pub, 'publish') as pub:
handle.display('x')
handle.update('y')
args, kwargs = pub.call_args_list[0]
nt.assert_equal(args, ())
nt.assert_equal(kwargs, {
'data': {
'text/plain': repr('x')
},
'metadata': {},
'transient': {
'display_id': handle.display_id,
}
})
args, kwargs = pub.call_args_list[1]
nt.assert_equal(args, ())
nt.assert_equal(kwargs, {
'data': {
'text/plain': repr('y')
},
'metadata': {},
'transient': {
'display_id': handle.display_id,
},
'update': True,
})

View file

@ -0,0 +1,112 @@
import sys
from IPython.testing.tools import AssertPrints, AssertNotPrints
from IPython.core.displayhook import CapturingDisplayHook
from IPython.utils.capture import CapturedIO
def test_output_displayed():
"""Checking to make sure that output is displayed"""
with AssertPrints('2'):
ip.run_cell('1+1', store_history=True)
with AssertPrints('2'):
ip.run_cell('1+1 # comment with a semicolon;', store_history=True)
with AssertPrints('2'):
ip.run_cell('1+1\n#commented_out_function();', store_history=True)
def test_output_quiet():
"""Checking to make sure that output is quiet"""
with AssertNotPrints('2'):
ip.run_cell('1+1;', store_history=True)
with AssertNotPrints('2'):
ip.run_cell('1+1; # comment with a semicolon', store_history=True)
with AssertNotPrints('2'):
ip.run_cell('1+1;\n#commented_out_function()', store_history=True)
def test_underscore_no_overrite_user():
ip.run_cell('_ = 42', store_history=True)
ip.run_cell('1+1', store_history=True)
with AssertPrints('42'):
ip.run_cell('print(_)', store_history=True)
ip.run_cell('del _', store_history=True)
ip.run_cell('6+6', store_history=True)
with AssertPrints('12'):
ip.run_cell('_', store_history=True)
def test_underscore_no_overrite_builtins():
ip.run_cell("import gettext ; gettext.install('foo')", store_history=True)
ip.run_cell('3+3', store_history=True)
with AssertPrints('gettext'):
ip.run_cell('print(_)', store_history=True)
ip.run_cell('_ = "userset"', store_history=True)
with AssertPrints('userset'):
ip.run_cell('print(_)', store_history=True)
ip.run_cell('import builtins; del builtins._')
def test_interactivehooks_ast_modes():
"""
Test that ast nodes can be triggered with different modes
"""
saved_mode = ip.ast_node_interactivity
ip.ast_node_interactivity = 'last_expr_or_assign'
try:
with AssertPrints('2'):
ip.run_cell('a = 1+1', store_history=True)
with AssertPrints('9'):
ip.run_cell('b = 1+8 # comment with a semicolon;', store_history=False)
with AssertPrints('7'):
ip.run_cell('c = 1+6\n#commented_out_function();', store_history=True)
ip.run_cell('d = 11', store_history=True)
with AssertPrints('12'):
ip.run_cell('d += 1', store_history=True)
with AssertNotPrints('42'):
ip.run_cell('(u,v) = (41+1, 43-1)')
finally:
ip.ast_node_interactivity = saved_mode
def test_interactivehooks_ast_modes_semi_suppress():
"""
Test that ast nodes can be triggered with different modes and suppressed
by semicolon
"""
saved_mode = ip.ast_node_interactivity
ip.ast_node_interactivity = 'last_expr_or_assign'
try:
with AssertNotPrints('2'):
ip.run_cell('x = 1+1;', store_history=True)
with AssertNotPrints('7'):
ip.run_cell('y = 1+6; # comment with a semicolon', store_history=True)
with AssertNotPrints('9'):
ip.run_cell('z = 1+8;\n#commented_out_function()', store_history=True)
finally:
ip.ast_node_interactivity = saved_mode
def test_capture_display_hook_format():
"""Tests that the capture display hook conforms to the CapturedIO output format"""
hook = CapturingDisplayHook(ip)
hook({"foo": "bar"})
captured = CapturedIO(sys.stdout, sys.stderr, hook.outputs)
# Should not raise with RichOutput transformation error
captured.outputs

View file

@ -0,0 +1,92 @@
import unittest
from unittest.mock import Mock
import nose.tools as nt
from IPython.core import events
import IPython.testing.tools as tt
@events._define_event
def ping_received():
pass
@events._define_event
def event_with_argument(argument):
pass
class CallbackTests(unittest.TestCase):
def setUp(self):
self.em = events.EventManager(get_ipython(),
{'ping_received': ping_received,
'event_with_argument': event_with_argument})
def test_register_unregister(self):
cb = Mock()
self.em.register('ping_received', cb)
self.em.trigger('ping_received')
self.assertEqual(cb.call_count, 1)
self.em.unregister('ping_received', cb)
self.em.trigger('ping_received')
self.assertEqual(cb.call_count, 1)
def test_bare_function_missed_unregister(self):
def cb1():
...
def cb2():
...
self.em.register('ping_received', cb1)
nt.assert_raises(ValueError, self.em.unregister, 'ping_received', cb2)
self.em.unregister('ping_received', cb1)
def test_cb_error(self):
cb = Mock(side_effect=ValueError)
self.em.register('ping_received', cb)
with tt.AssertPrints("Error in callback"):
self.em.trigger('ping_received')
def test_cb_keyboard_interrupt(self):
cb = Mock(side_effect=KeyboardInterrupt)
self.em.register('ping_received', cb)
with tt.AssertPrints("Error in callback"):
self.em.trigger('ping_received')
def test_unregister_during_callback(self):
invoked = [False] * 3
def func1(*_):
invoked[0] = True
self.em.unregister('ping_received', func1)
self.em.register('ping_received', func3)
def func2(*_):
invoked[1] = True
self.em.unregister('ping_received', func2)
def func3(*_):
invoked[2] = True
self.em.register('ping_received', func1)
self.em.register('ping_received', func2)
self.em.trigger('ping_received')
self.assertEqual([True, True, False], invoked)
self.assertEqual([func3], self.em.callbacks['ping_received'])
def test_ignore_event_arguments_if_no_argument_required(self):
call_count = [0]
def event_with_no_argument():
call_count[0] += 1
self.em.register('event_with_argument', event_with_no_argument)
self.em.trigger('event_with_argument', 'the argument')
self.assertEqual(call_count[0], 1)
self.em.unregister('event_with_argument', event_with_no_argument)
self.em.trigger('ping_received')
self.assertEqual(call_count[0], 1)

View file

@ -0,0 +1,96 @@
import os.path
import nose.tools as nt
import IPython.testing.tools as tt
from IPython.utils.syspathcontext import prepended_to_syspath
from IPython.utils.tempdir import TemporaryDirectory
ext1_content = """
def load_ipython_extension(ip):
print("Running ext1 load")
def unload_ipython_extension(ip):
print("Running ext1 unload")
"""
ext2_content = """
def load_ipython_extension(ip):
print("Running ext2 load")
"""
ext3_content = """
def load_ipython_extension(ip):
ip2 = get_ipython()
print(ip is ip2)
"""
def test_extension_loading():
em = get_ipython().extension_manager
with TemporaryDirectory() as td:
ext1 = os.path.join(td, 'ext1.py')
with open(ext1, 'w') as f:
f.write(ext1_content)
ext2 = os.path.join(td, 'ext2.py')
with open(ext2, 'w') as f:
f.write(ext2_content)
with prepended_to_syspath(td):
assert 'ext1' not in em.loaded
assert 'ext2' not in em.loaded
# Load extension
with tt.AssertPrints("Running ext1 load"):
assert em.load_extension('ext1') is None
assert 'ext1' in em.loaded
# Should refuse to load it again
with tt.AssertNotPrints("Running ext1 load"):
assert em.load_extension('ext1') == 'already loaded'
# Reload
with tt.AssertPrints("Running ext1 unload"):
with tt.AssertPrints("Running ext1 load", suppress=False):
em.reload_extension('ext1')
# Unload
with tt.AssertPrints("Running ext1 unload"):
assert em.unload_extension('ext1') is None
# Can't unload again
with tt.AssertNotPrints("Running ext1 unload"):
assert em.unload_extension('ext1') == 'not loaded'
assert em.unload_extension('ext2') == 'not loaded'
# Load extension 2
with tt.AssertPrints("Running ext2 load"):
assert em.load_extension('ext2') is None
# Can't unload this
assert em.unload_extension('ext2') == 'no unload function'
# But can reload it
with tt.AssertPrints("Running ext2 load"):
em.reload_extension('ext2')
def test_extension_builtins():
em = get_ipython().extension_manager
with TemporaryDirectory() as td:
ext3 = os.path.join(td, 'ext3.py')
with open(ext3, 'w') as f:
f.write(ext3_content)
assert 'ext3' not in em.loaded
with prepended_to_syspath(td):
# Load extension
with tt.AssertPrints("True"):
assert em.load_extension('ext3') is None
assert 'ext3' in em.loaded
def test_non_extension():
em = get_ipython().extension_manager
nt.assert_equal(em.load_extension('sys'), "no load function")

View file

@ -0,0 +1,533 @@
"""Tests for the Formatters."""
import warnings
from math import pi
try:
import numpy
except:
numpy = None
import nose.tools as nt
from IPython import get_ipython
from traitlets.config import Config
from IPython.core.formatters import (
PlainTextFormatter, HTMLFormatter, PDFFormatter, _mod_name_key,
DisplayFormatter, JSONFormatter,
)
from IPython.utils.io import capture_output
class A(object):
def __repr__(self):
return 'A()'
class B(A):
def __repr__(self):
return 'B()'
class C:
pass
class BadRepr(object):
def __repr__(self):
raise ValueError("bad repr")
class BadPretty(object):
_repr_pretty_ = None
class GoodPretty(object):
def _repr_pretty_(self, pp, cycle):
pp.text('foo')
def __repr__(self):
return 'GoodPretty()'
def foo_printer(obj, pp, cycle):
pp.text('foo')
def test_pretty():
f = PlainTextFormatter()
f.for_type(A, foo_printer)
nt.assert_equal(f(A()), 'foo')
nt.assert_equal(f(B()), 'B()')
nt.assert_equal(f(GoodPretty()), 'foo')
# Just don't raise an exception for the following:
f(BadPretty())
f.pprint = False
nt.assert_equal(f(A()), 'A()')
nt.assert_equal(f(B()), 'B()')
nt.assert_equal(f(GoodPretty()), 'GoodPretty()')
def test_deferred():
f = PlainTextFormatter()
def test_precision():
"""test various values for float_precision."""
f = PlainTextFormatter()
nt.assert_equal(f(pi), repr(pi))
f.float_precision = 0
if numpy:
po = numpy.get_printoptions()
nt.assert_equal(po['precision'], 0)
nt.assert_equal(f(pi), '3')
f.float_precision = 2
if numpy:
po = numpy.get_printoptions()
nt.assert_equal(po['precision'], 2)
nt.assert_equal(f(pi), '3.14')
f.float_precision = '%g'
if numpy:
po = numpy.get_printoptions()
nt.assert_equal(po['precision'], 2)
nt.assert_equal(f(pi), '3.14159')
f.float_precision = '%e'
nt.assert_equal(f(pi), '3.141593e+00')
f.float_precision = ''
if numpy:
po = numpy.get_printoptions()
nt.assert_equal(po['precision'], 8)
nt.assert_equal(f(pi), repr(pi))
def test_bad_precision():
"""test various invalid values for float_precision."""
f = PlainTextFormatter()
def set_fp(p):
f.float_precision=p
nt.assert_raises(ValueError, set_fp, '%')
nt.assert_raises(ValueError, set_fp, '%.3f%i')
nt.assert_raises(ValueError, set_fp, 'foo')
nt.assert_raises(ValueError, set_fp, -1)
def test_for_type():
f = PlainTextFormatter()
# initial return, None
nt.assert_is(f.for_type(C, foo_printer), None)
# no func queries
nt.assert_is(f.for_type(C), foo_printer)
# shouldn't change anything
nt.assert_is(f.for_type(C), foo_printer)
# None should do the same
nt.assert_is(f.for_type(C, None), foo_printer)
nt.assert_is(f.for_type(C, None), foo_printer)
def test_for_type_string():
f = PlainTextFormatter()
type_str = '%s.%s' % (C.__module__, 'C')
# initial return, None
nt.assert_is(f.for_type(type_str, foo_printer), None)
# no func queries
nt.assert_is(f.for_type(type_str), foo_printer)
nt.assert_in(_mod_name_key(C), f.deferred_printers)
nt.assert_is(f.for_type(C), foo_printer)
nt.assert_not_in(_mod_name_key(C), f.deferred_printers)
nt.assert_in(C, f.type_printers)
def test_for_type_by_name():
f = PlainTextFormatter()
mod = C.__module__
# initial return, None
nt.assert_is(f.for_type_by_name(mod, 'C', foo_printer), None)
# no func queries
nt.assert_is(f.for_type_by_name(mod, 'C'), foo_printer)
# shouldn't change anything
nt.assert_is(f.for_type_by_name(mod, 'C'), foo_printer)
# None should do the same
nt.assert_is(f.for_type_by_name(mod, 'C', None), foo_printer)
nt.assert_is(f.for_type_by_name(mod, 'C', None), foo_printer)
def test_lookup():
f = PlainTextFormatter()
f.for_type(C, foo_printer)
nt.assert_is(f.lookup(C()), foo_printer)
with nt.assert_raises(KeyError):
f.lookup(A())
def test_lookup_string():
f = PlainTextFormatter()
type_str = '%s.%s' % (C.__module__, 'C')
f.for_type(type_str, foo_printer)
nt.assert_is(f.lookup(C()), foo_printer)
# should move from deferred to imported dict
nt.assert_not_in(_mod_name_key(C), f.deferred_printers)
nt.assert_in(C, f.type_printers)
def test_lookup_by_type():
f = PlainTextFormatter()
f.for_type(C, foo_printer)
nt.assert_is(f.lookup_by_type(C), foo_printer)
with nt.assert_raises(KeyError):
f.lookup_by_type(A)
def test_lookup_by_type_string():
f = PlainTextFormatter()
type_str = '%s.%s' % (C.__module__, 'C')
f.for_type(type_str, foo_printer)
# verify insertion
nt.assert_in(_mod_name_key(C), f.deferred_printers)
nt.assert_not_in(C, f.type_printers)
nt.assert_is(f.lookup_by_type(type_str), foo_printer)
# lookup by string doesn't cause import
nt.assert_in(_mod_name_key(C), f.deferred_printers)
nt.assert_not_in(C, f.type_printers)
nt.assert_is(f.lookup_by_type(C), foo_printer)
# should move from deferred to imported dict
nt.assert_not_in(_mod_name_key(C), f.deferred_printers)
nt.assert_in(C, f.type_printers)
def test_in_formatter():
f = PlainTextFormatter()
f.for_type(C, foo_printer)
type_str = '%s.%s' % (C.__module__, 'C')
nt.assert_in(C, f)
nt.assert_in(type_str, f)
def test_string_in_formatter():
f = PlainTextFormatter()
type_str = '%s.%s' % (C.__module__, 'C')
f.for_type(type_str, foo_printer)
nt.assert_in(type_str, f)
nt.assert_in(C, f)
def test_pop():
f = PlainTextFormatter()
f.for_type(C, foo_printer)
nt.assert_is(f.lookup_by_type(C), foo_printer)
nt.assert_is(f.pop(C, None), foo_printer)
f.for_type(C, foo_printer)
nt.assert_is(f.pop(C), foo_printer)
with nt.assert_raises(KeyError):
f.lookup_by_type(C)
with nt.assert_raises(KeyError):
f.pop(C)
with nt.assert_raises(KeyError):
f.pop(A)
nt.assert_is(f.pop(A, None), None)
def test_pop_string():
f = PlainTextFormatter()
type_str = '%s.%s' % (C.__module__, 'C')
with nt.assert_raises(KeyError):
f.pop(type_str)
f.for_type(type_str, foo_printer)
f.pop(type_str)
with nt.assert_raises(KeyError):
f.lookup_by_type(C)
with nt.assert_raises(KeyError):
f.pop(type_str)
f.for_type(C, foo_printer)
nt.assert_is(f.pop(type_str, None), foo_printer)
with nt.assert_raises(KeyError):
f.lookup_by_type(C)
with nt.assert_raises(KeyError):
f.pop(type_str)
nt.assert_is(f.pop(type_str, None), None)
def test_error_method():
f = HTMLFormatter()
class BadHTML(object):
def _repr_html_(self):
raise ValueError("Bad HTML")
bad = BadHTML()
with capture_output() as captured:
result = f(bad)
nt.assert_is(result, None)
nt.assert_in("Traceback", captured.stdout)
nt.assert_in("Bad HTML", captured.stdout)
nt.assert_in("_repr_html_", captured.stdout)
def test_nowarn_notimplemented():
f = HTMLFormatter()
class HTMLNotImplemented(object):
def _repr_html_(self):
raise NotImplementedError
h = HTMLNotImplemented()
with capture_output() as captured:
result = f(h)
nt.assert_is(result, None)
nt.assert_equal("", captured.stderr)
nt.assert_equal("", captured.stdout)
def test_warn_error_for_type():
f = HTMLFormatter()
f.for_type(int, lambda i: name_error)
with capture_output() as captured:
result = f(5)
nt.assert_is(result, None)
nt.assert_in("Traceback", captured.stdout)
nt.assert_in("NameError", captured.stdout)
nt.assert_in("name_error", captured.stdout)
def test_error_pretty_method():
f = PlainTextFormatter()
class BadPretty(object):
def _repr_pretty_(self):
return "hello"
bad = BadPretty()
with capture_output() as captured:
result = f(bad)
nt.assert_is(result, None)
nt.assert_in("Traceback", captured.stdout)
nt.assert_in("_repr_pretty_", captured.stdout)
nt.assert_in("given", captured.stdout)
nt.assert_in("argument", captured.stdout)
def test_bad_repr_traceback():
f = PlainTextFormatter()
bad = BadRepr()
with capture_output() as captured:
result = f(bad)
# catches error, returns None
nt.assert_is(result, None)
nt.assert_in("Traceback", captured.stdout)
nt.assert_in("__repr__", captured.stdout)
nt.assert_in("ValueError", captured.stdout)
class MakePDF(object):
def _repr_pdf_(self):
return 'PDF'
def test_pdf_formatter():
pdf = MakePDF()
f = PDFFormatter()
nt.assert_equal(f(pdf), 'PDF')
def test_print_method_bound():
f = HTMLFormatter()
class MyHTML(object):
def _repr_html_(self):
return "hello"
with capture_output() as captured:
result = f(MyHTML)
nt.assert_is(result, None)
nt.assert_not_in("FormatterWarning", captured.stderr)
with capture_output() as captured:
result = f(MyHTML())
nt.assert_equal(result, "hello")
nt.assert_equal(captured.stderr, "")
def test_print_method_weird():
class TextMagicHat(object):
def __getattr__(self, key):
return key
f = HTMLFormatter()
text_hat = TextMagicHat()
nt.assert_equal(text_hat._repr_html_, '_repr_html_')
with capture_output() as captured:
result = f(text_hat)
nt.assert_is(result, None)
nt.assert_not_in("FormatterWarning", captured.stderr)
class CallableMagicHat(object):
def __getattr__(self, key):
return lambda : key
call_hat = CallableMagicHat()
with capture_output() as captured:
result = f(call_hat)
nt.assert_equal(result, None)
class BadReprArgs(object):
def _repr_html_(self, extra, args):
return "html"
bad = BadReprArgs()
with capture_output() as captured:
result = f(bad)
nt.assert_is(result, None)
nt.assert_not_in("FormatterWarning", captured.stderr)
def test_format_config():
"""config objects don't pretend to support fancy reprs with lazy attrs"""
f = HTMLFormatter()
cfg = Config()
with capture_output() as captured:
result = f(cfg)
nt.assert_is(result, None)
nt.assert_equal(captured.stderr, "")
with capture_output() as captured:
result = f(Config)
nt.assert_is(result, None)
nt.assert_equal(captured.stderr, "")
def test_pretty_max_seq_length():
f = PlainTextFormatter(max_seq_length=1)
lis = list(range(3))
text = f(lis)
nt.assert_equal(text, '[0, ...]')
f.max_seq_length = 0
text = f(lis)
nt.assert_equal(text, '[0, 1, 2]')
text = f(list(range(1024)))
lines = text.splitlines()
nt.assert_equal(len(lines), 1024)
def test_ipython_display_formatter():
"""Objects with _ipython_display_ defined bypass other formatters"""
f = get_ipython().display_formatter
catcher = []
class SelfDisplaying(object):
def _ipython_display_(self):
catcher.append(self)
class NotSelfDisplaying(object):
def __repr__(self):
return "NotSelfDisplaying"
def _ipython_display_(self):
raise NotImplementedError
save_enabled = f.ipython_display_formatter.enabled
f.ipython_display_formatter.enabled = True
yes = SelfDisplaying()
no = NotSelfDisplaying()
d, md = f.format(no)
nt.assert_equal(d, {'text/plain': repr(no)})
nt.assert_equal(md, {})
nt.assert_equal(catcher, [])
d, md = f.format(yes)
nt.assert_equal(d, {})
nt.assert_equal(md, {})
nt.assert_equal(catcher, [yes])
f.ipython_display_formatter.enabled = save_enabled
def test_json_as_string_deprecated():
class JSONString(object):
def _repr_json_(self):
return '{}'
f = JSONFormatter()
with warnings.catch_warnings(record=True) as w:
d = f(JSONString())
nt.assert_equal(d, {})
nt.assert_equal(len(w), 1)
def test_repr_mime():
class HasReprMime(object):
def _repr_mimebundle_(self, include=None, exclude=None):
return {
'application/json+test.v2': {
'x': 'y'
},
'plain/text' : '<HasReprMime>',
'image/png' : 'i-overwrite'
}
def _repr_png_(self):
return 'should-be-overwritten'
def _repr_html_(self):
return '<b>hi!</b>'
f = get_ipython().display_formatter
html_f = f.formatters['text/html']
save_enabled = html_f.enabled
html_f.enabled = True
obj = HasReprMime()
d, md = f.format(obj)
html_f.enabled = save_enabled
nt.assert_equal(sorted(d), ['application/json+test.v2',
'image/png',
'plain/text',
'text/html',
'text/plain'])
nt.assert_equal(md, {})
d, md = f.format(obj, include={'image/png'})
nt.assert_equal(list(d.keys()), ['image/png'],
'Include should filter out even things from repr_mimebundle')
nt.assert_equal(d['image/png'], 'i-overwrite', '_repr_mimebundle_ take precedence')
def test_pass_correct_include_exclude():
class Tester(object):
def __init__(self, include=None, exclude=None):
self.include = include
self.exclude = exclude
def _repr_mimebundle_(self, include, exclude, **kwargs):
if include and (include != self.include):
raise ValueError('include got modified: display() may be broken.')
if exclude and (exclude != self.exclude):
raise ValueError('exclude got modified: display() may be broken.')
return None
include = {'a', 'b', 'c'}
exclude = {'c', 'e' , 'f'}
f = get_ipython().display_formatter
f.format(Tester(include=include, exclude=exclude), include=include, exclude=exclude)
f.format(Tester(exclude=exclude), exclude=exclude)
f.format(Tester(include=include), include=include)
def test_repr_mime_meta():
class HasReprMimeMeta(object):
def _repr_mimebundle_(self, include=None, exclude=None):
data = {
'image/png': 'base64-image-data',
}
metadata = {
'image/png': {
'width': 5,
'height': 10,
}
}
return (data, metadata)
f = get_ipython().display_formatter
obj = HasReprMimeMeta()
d, md = f.format(obj)
nt.assert_equal(sorted(d), ['image/png', 'text/plain'])
nt.assert_equal(md, {
'image/png': {
'width': 5,
'height': 10,
}
})
def test_repr_mime_failure():
class BadReprMime(object):
def _repr_mimebundle_(self, include=None, exclude=None):
raise RuntimeError
f = get_ipython().display_formatter
obj = BadReprMime()
d, md = f.format(obj)
nt.assert_in('text/plain', d)

View file

@ -0,0 +1,94 @@
"""Tests for input handlers.
"""
#-----------------------------------------------------------------------------
# Module imports
#-----------------------------------------------------------------------------
# third party
import nose.tools as nt
# our own packages
from IPython.core import autocall
from IPython.testing import tools as tt
#-----------------------------------------------------------------------------
# Globals
#-----------------------------------------------------------------------------
# Get the public instance of IPython
failures = []
num_tests = 0
#-----------------------------------------------------------------------------
# Test functions
#-----------------------------------------------------------------------------
class CallableIndexable(object):
def __getitem__(self, idx): return True
def __call__(self, *args, **kws): return True
class Autocallable(autocall.IPyAutocall):
def __call__(self):
return "called"
def run(tests):
"""Loop through a list of (pre, post) inputs, where pre is the string
handed to ipython, and post is how that string looks after it's been
transformed (i.e. ipython's notion of _i)"""
tt.check_pairs(ip.prefilter_manager.prefilter_lines, tests)
def test_handlers():
call_idx = CallableIndexable()
ip.user_ns['call_idx'] = call_idx
# For many of the below, we're also checking that leading whitespace
# turns off the esc char, which it should unless there is a continuation
# line.
run(
[('"no change"', '"no change"'), # normal
(u"lsmagic", "get_ipython().run_line_magic('lsmagic', '')"), # magic
#("a = b # PYTHON-MODE", '_i'), # emacs -- avoids _in cache
])
# Objects which are instances of IPyAutocall are *always* autocalled
autocallable = Autocallable()
ip.user_ns['autocallable'] = autocallable
# auto
ip.magic('autocall 0')
# Only explicit escapes or instances of IPyAutocallable should get
# expanded
run([
('len "abc"', 'len "abc"'),
('autocallable', 'autocallable()'),
# Don't add extra brackets (gh-1117)
('autocallable()', 'autocallable()'),
])
ip.magic('autocall 1')
run([
('len "abc"', 'len("abc")'),
('len "abc";', 'len("abc");'), # ; is special -- moves out of parens
# Autocall is turned off if first arg is [] and the object
# is both callable and indexable. Like so:
('len [1,2]', 'len([1,2])'), # len doesn't support __getitem__...
('call_idx [1]', 'call_idx [1]'), # call_idx *does*..
('call_idx 1', 'call_idx(1)'),
('len', 'len'), # only at 2 does it auto-call on single args
])
ip.magic('autocall 2')
run([
('len "abc"', 'len("abc")'),
('len "abc";', 'len("abc");'),
('len [1,2]', 'len([1,2])'),
('call_idx [1]', 'call_idx [1]'),
('call_idx 1', 'call_idx(1)'),
# This is what's different:
('len', 'len()'), # only at 2 does it auto-call on single args
])
ip.magic('autocall 1')
nt.assert_equal(failures, [])

View file

@ -0,0 +1,214 @@
# coding: utf-8
"""Tests for the IPython tab-completion machinery.
"""
#-----------------------------------------------------------------------------
# Module imports
#-----------------------------------------------------------------------------
# stdlib
import io
import os
import sys
import tempfile
from datetime import datetime
import sqlite3
# third party
import nose.tools as nt
# our own packages
from traitlets.config.loader import Config
from IPython.utils.tempdir import TemporaryDirectory
from IPython.core.history import HistoryManager, extract_hist_ranges
from IPython.testing.decorators import skipif
def test_proper_default_encoding():
nt.assert_equal(sys.getdefaultencoding(), "utf-8")
@skipif(sqlite3.sqlite_version_info > (3,24,0))
def test_history():
ip = get_ipython()
with TemporaryDirectory() as tmpdir:
hist_manager_ori = ip.history_manager
hist_file = os.path.join(tmpdir, 'history.sqlite')
try:
ip.history_manager = HistoryManager(shell=ip, hist_file=hist_file)
hist = [u'a=1', u'def f():\n test = 1\n return test', u"b='€Æ¾÷ß'"]
for i, h in enumerate(hist, start=1):
ip.history_manager.store_inputs(i, h)
ip.history_manager.db_log_output = True
# Doesn't match the input, but we'll just check it's stored.
ip.history_manager.output_hist_reprs[3] = "spam"
ip.history_manager.store_output(3)
nt.assert_equal(ip.history_manager.input_hist_raw, [''] + hist)
# Detailed tests for _get_range_session
grs = ip.history_manager._get_range_session
nt.assert_equal(list(grs(start=2,stop=-1)), list(zip([0], [2], hist[1:-1])))
nt.assert_equal(list(grs(start=-2)), list(zip([0,0], [2,3], hist[-2:])))
nt.assert_equal(list(grs(output=True)), list(zip([0,0,0], [1,2,3], zip(hist, [None,None,'spam']))))
# Check whether specifying a range beyond the end of the current
# session results in an error (gh-804)
ip.magic('%hist 2-500')
# Check that we can write non-ascii characters to a file
ip.magic("%%hist -f %s" % os.path.join(tmpdir, "test1"))
ip.magic("%%hist -pf %s" % os.path.join(tmpdir, "test2"))
ip.magic("%%hist -nf %s" % os.path.join(tmpdir, "test3"))
ip.magic("%%save %s 1-10" % os.path.join(tmpdir, "test4"))
# New session
ip.history_manager.reset()
newcmds = [u"z=5",
u"class X(object):\n pass",
u"k='p'",
u"z=5"]
for i, cmd in enumerate(newcmds, start=1):
ip.history_manager.store_inputs(i, cmd)
gothist = ip.history_manager.get_range(start=1, stop=4)
nt.assert_equal(list(gothist), list(zip([0,0,0],[1,2,3], newcmds)))
# Previous session:
gothist = ip.history_manager.get_range(-1, 1, 4)
nt.assert_equal(list(gothist), list(zip([1,1,1],[1,2,3], hist)))
newhist = [(2, i, c) for (i, c) in enumerate(newcmds, 1)]
# Check get_hist_tail
gothist = ip.history_manager.get_tail(5, output=True,
include_latest=True)
expected = [(1, 3, (hist[-1], "spam"))] \
+ [(s, n, (c, None)) for (s, n, c) in newhist]
nt.assert_equal(list(gothist), expected)
gothist = ip.history_manager.get_tail(2)
expected = newhist[-3:-1]
nt.assert_equal(list(gothist), expected)
# Check get_hist_search
gothist = ip.history_manager.search("*test*")
nt.assert_equal(list(gothist), [(1,2,hist[1])] )
gothist = ip.history_manager.search("*=*")
nt.assert_equal(list(gothist),
[(1, 1, hist[0]),
(1, 2, hist[1]),
(1, 3, hist[2]),
newhist[0],
newhist[2],
newhist[3]])
gothist = ip.history_manager.search("*=*", n=4)
nt.assert_equal(list(gothist),
[(1, 3, hist[2]),
newhist[0],
newhist[2],
newhist[3]])
gothist = ip.history_manager.search("*=*", unique=True)
nt.assert_equal(list(gothist),
[(1, 1, hist[0]),
(1, 2, hist[1]),
(1, 3, hist[2]),
newhist[2],
newhist[3]])
gothist = ip.history_manager.search("*=*", unique=True, n=3)
nt.assert_equal(list(gothist),
[(1, 3, hist[2]),
newhist[2],
newhist[3]])
gothist = ip.history_manager.search("b*", output=True)
nt.assert_equal(list(gothist), [(1,3,(hist[2],"spam"))] )
# Cross testing: check that magic %save can get previous session.
testfilename = os.path.realpath(os.path.join(tmpdir, "test.py"))
ip.magic("save " + testfilename + " ~1/1-3")
with io.open(testfilename, encoding='utf-8') as testfile:
nt.assert_equal(testfile.read(),
u"# coding: utf-8\n" + u"\n".join(hist)+u"\n")
# Duplicate line numbers - check that it doesn't crash, and
# gets a new session
ip.history_manager.store_inputs(1, "rogue")
ip.history_manager.writeout_cache()
nt.assert_equal(ip.history_manager.session_number, 3)
finally:
# Ensure saving thread is shut down before we try to clean up the files
ip.history_manager.save_thread.stop()
# Forcibly close database rather than relying on garbage collection
ip.history_manager.db.close()
# Restore history manager
ip.history_manager = hist_manager_ori
def test_extract_hist_ranges():
instr = "1 2/3 ~4/5-6 ~4/7-~4/9 ~9/2-~7/5 ~10/"
expected = [(0, 1, 2), # 0 == current session
(2, 3, 4),
(-4, 5, 7),
(-4, 7, 10),
(-9, 2, None), # None == to end
(-8, 1, None),
(-7, 1, 6),
(-10, 1, None)]
actual = list(extract_hist_ranges(instr))
nt.assert_equal(actual, expected)
def test_magic_rerun():
"""Simple test for %rerun (no args -> rerun last line)"""
ip = get_ipython()
ip.run_cell("a = 10", store_history=True)
ip.run_cell("a += 1", store_history=True)
nt.assert_equal(ip.user_ns["a"], 11)
ip.run_cell("%rerun", store_history=True)
nt.assert_equal(ip.user_ns["a"], 12)
def test_timestamp_type():
ip = get_ipython()
info = ip.history_manager.get_session_info()
nt.assert_true(isinstance(info[1], datetime))
def test_hist_file_config():
cfg = Config()
tfile = tempfile.NamedTemporaryFile(delete=False)
cfg.HistoryManager.hist_file = tfile.name
try:
hm = HistoryManager(shell=get_ipython(), config=cfg)
nt.assert_equal(hm.hist_file, cfg.HistoryManager.hist_file)
finally:
try:
os.remove(tfile.name)
except OSError:
# same catch as in testing.tools.TempFileMixin
# On Windows, even though we close the file, we still can't
# delete it. I have no clue why
pass
def test_histmanager_disabled():
"""Ensure that disabling the history manager doesn't create a database."""
cfg = Config()
cfg.HistoryAccessor.enabled = False
ip = get_ipython()
with TemporaryDirectory() as tmpdir:
hist_manager_ori = ip.history_manager
hist_file = os.path.join(tmpdir, 'history.sqlite')
cfg.HistoryManager.hist_file = hist_file
try:
ip.history_manager = HistoryManager(shell=ip, config=cfg)
hist = [u'a=1', u'def f():\n test = 1\n return test', u"b='€Æ¾÷ß'"]
for i, h in enumerate(hist, start=1):
ip.history_manager.store_inputs(i, h)
nt.assert_equal(ip.history_manager.input_hist_raw, [''] + hist)
ip.history_manager.reset()
ip.history_manager.end_session()
finally:
ip.history_manager = hist_manager_ori
# hist_file should not be created
nt.assert_false(os.path.exists(hist_file))

View file

@ -0,0 +1,80 @@
# -*- coding: utf-8 -*-
"""Tests for CommandChainDispatcher."""
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
import nose.tools as nt
from IPython.core.error import TryNext
from IPython.core.hooks import CommandChainDispatcher
#-----------------------------------------------------------------------------
# Local utilities
#-----------------------------------------------------------------------------
# Define two classes, one which succeeds and one which raises TryNext. Each
# sets the attribute `called` to True when it is called.
class Okay(object):
def __init__(self, message):
self.message = message
self.called = False
def __call__(self):
self.called = True
return self.message
class Fail(object):
def __init__(self, message):
self.message = message
self.called = False
def __call__(self):
self.called = True
raise TryNext(self.message)
#-----------------------------------------------------------------------------
# Test functions
#-----------------------------------------------------------------------------
def test_command_chain_dispatcher_ff():
"""Test two failing hooks"""
fail1 = Fail(u'fail1')
fail2 = Fail(u'fail2')
dp = CommandChainDispatcher([(0, fail1),
(10, fail2)])
try:
dp()
except TryNext as e:
nt.assert_equal(str(e), u'fail2')
else:
assert False, "Expected exception was not raised."
nt.assert_true(fail1.called)
nt.assert_true(fail2.called)
def test_command_chain_dispatcher_fofo():
"""Test a mixture of failing and succeeding hooks."""
fail1 = Fail(u'fail1')
fail2 = Fail(u'fail2')
okay1 = Okay(u'okay1')
okay2 = Okay(u'okay2')
dp = CommandChainDispatcher([(0, fail1),
# (5, okay1), # add this later
(10, fail2),
(15, okay2)])
dp.add(okay1, 5)
nt.assert_equal(dp(), u'okay1')
nt.assert_true(fail1.called)
nt.assert_true(okay1.called)
nt.assert_false(fail2.called)
nt.assert_false(okay2.called)
def test_command_chain_dispatcher_eq_priority():
okay1 = Okay(u'okay1')
okay2 = Okay(u'okay2')
dp = CommandChainDispatcher([(1, okay1)])
dp.add(okay2, 1)

View file

@ -0,0 +1,52 @@
# encoding: utf-8
def test_import_completer():
from IPython.core import completer
def test_import_crashhandler():
from IPython.core import crashhandler
def test_import_debugger():
from IPython.core import debugger
def test_import_excolors():
from IPython.core import excolors
def test_import_history():
from IPython.core import history
def test_import_hooks():
from IPython.core import hooks
def test_import_getipython():
from IPython.core import getipython
def test_import_interactiveshell():
from IPython.core import interactiveshell
def test_import_logger():
from IPython.core import logger
def test_import_macro():
from IPython.core import macro
def test_import_magic():
from IPython.core import magic
def test_import_oinspect():
from IPython.core import oinspect
def test_import_prefilter():
from IPython.core import prefilter
def test_import_prompts():
from IPython.core import prompts
def test_import_release():
from IPython.core import release
def test_import_ultratb():
from IPython.core import ultratb
def test_import_usage():
from IPython.core import usage

View file

@ -0,0 +1,639 @@
# -*- coding: utf-8 -*-
"""Tests for the inputsplitter module."""
# Copyright (c) IPython Development Team.
# Distributed under the terms of the Modified BSD License.
import unittest
import sys
import nose.tools as nt
from IPython.core import inputsplitter as isp
from IPython.core.inputtransformer import InputTransformer
from IPython.core.tests.test_inputtransformer import syntax, syntax_ml
from IPython.testing import tools as tt
#-----------------------------------------------------------------------------
# Semi-complete examples (also used as tests)
#-----------------------------------------------------------------------------
# Note: at the bottom, there's a slightly more complete version of this that
# can be useful during development of code here.
def mini_interactive_loop(input_func):
"""Minimal example of the logic of an interactive interpreter loop.
This serves as an example, and it is used by the test system with a fake
raw_input that simulates interactive input."""
from IPython.core.inputsplitter import InputSplitter
isp = InputSplitter()
# In practice, this input loop would be wrapped in an outside loop to read
# input indefinitely, until some exit/quit command was issued. Here we
# only illustrate the basic inner loop.
while isp.push_accepts_more():
indent = ' '*isp.get_indent_spaces()
prompt = '>>> ' + indent
line = indent + input_func(prompt)
isp.push(line)
# Here we just return input so we can use it in a test suite, but a real
# interpreter would instead send it for execution somewhere.
src = isp.source_reset()
#print 'Input source was:\n', src # dbg
return src
#-----------------------------------------------------------------------------
# Test utilities, just for local use
#-----------------------------------------------------------------------------
def assemble(block):
"""Assemble a block into multi-line sub-blocks."""
return ['\n'.join(sub_block)+'\n' for sub_block in block]
def pseudo_input(lines):
"""Return a function that acts like raw_input but feeds the input list."""
ilines = iter(lines)
def raw_in(prompt):
try:
return next(ilines)
except StopIteration:
return ''
return raw_in
#-----------------------------------------------------------------------------
# Tests
#-----------------------------------------------------------------------------
def test_spaces():
tests = [('', 0),
(' ', 1),
('\n', 0),
(' \n', 1),
('x', 0),
(' x', 1),
(' x',2),
(' x',4),
# Note: tabs are counted as a single whitespace!
('\tx', 1),
('\t x', 2),
]
tt.check_pairs(isp.num_ini_spaces, tests)
def test_remove_comments():
tests = [('text', 'text'),
('text # comment', 'text '),
('text # comment\n', 'text \n'),
('text # comment \n', 'text \n'),
('line # c \nline\n','line \nline\n'),
('line # c \nline#c2 \nline\nline #c\n\n',
'line \nline\nline\nline \n\n'),
]
tt.check_pairs(isp.remove_comments, tests)
def test_get_input_encoding():
encoding = isp.get_input_encoding()
nt.assert_true(isinstance(encoding, str))
# simple-minded check that at least encoding a simple string works with the
# encoding we got.
nt.assert_equal(u'test'.encode(encoding), b'test')
class NoInputEncodingTestCase(unittest.TestCase):
def setUp(self):
self.old_stdin = sys.stdin
class X: pass
fake_stdin = X()
sys.stdin = fake_stdin
def test(self):
# Verify that if sys.stdin has no 'encoding' attribute we do the right
# thing
enc = isp.get_input_encoding()
self.assertEqual(enc, 'ascii')
def tearDown(self):
sys.stdin = self.old_stdin
class InputSplitterTestCase(unittest.TestCase):
def setUp(self):
self.isp = isp.InputSplitter()
def test_reset(self):
isp = self.isp
isp.push('x=1')
isp.reset()
self.assertEqual(isp._buffer, [])
self.assertEqual(isp.get_indent_spaces(), 0)
self.assertEqual(isp.source, '')
self.assertEqual(isp.code, None)
self.assertEqual(isp._is_complete, False)
def test_source(self):
self.isp._store('1')
self.isp._store('2')
self.assertEqual(self.isp.source, '1\n2\n')
self.assertEqual(len(self.isp._buffer)>0, True)
self.assertEqual(self.isp.source_reset(), '1\n2\n')
self.assertEqual(self.isp._buffer, [])
self.assertEqual(self.isp.source, '')
def test_indent(self):
isp = self.isp # shorthand
isp.push('x=1')
self.assertEqual(isp.get_indent_spaces(), 0)
isp.push('if 1:\n x=1')
self.assertEqual(isp.get_indent_spaces(), 4)
isp.push('y=2\n')
self.assertEqual(isp.get_indent_spaces(), 0)
def test_indent2(self):
isp = self.isp
isp.push('if 1:')
self.assertEqual(isp.get_indent_spaces(), 4)
isp.push(' x=1')
self.assertEqual(isp.get_indent_spaces(), 4)
# Blank lines shouldn't change the indent level
isp.push(' '*2)
self.assertEqual(isp.get_indent_spaces(), 4)
def test_indent3(self):
isp = self.isp
# When a multiline statement contains parens or multiline strings, we
# shouldn't get confused.
isp.push("if 1:")
isp.push(" x = (1+\n 2)")
self.assertEqual(isp.get_indent_spaces(), 4)
def test_indent4(self):
isp = self.isp
# whitespace after ':' should not screw up indent level
isp.push('if 1: \n x=1')
self.assertEqual(isp.get_indent_spaces(), 4)
isp.push('y=2\n')
self.assertEqual(isp.get_indent_spaces(), 0)
isp.push('if 1:\t\n x=1')
self.assertEqual(isp.get_indent_spaces(), 4)
isp.push('y=2\n')
self.assertEqual(isp.get_indent_spaces(), 0)
def test_dedent_pass(self):
isp = self.isp # shorthand
# should NOT cause dedent
isp.push('if 1:\n passes = 5')
self.assertEqual(isp.get_indent_spaces(), 4)
isp.push('if 1:\n pass')
self.assertEqual(isp.get_indent_spaces(), 0)
isp.push('if 1:\n pass ')
self.assertEqual(isp.get_indent_spaces(), 0)
def test_dedent_break(self):
isp = self.isp # shorthand
# should NOT cause dedent
isp.push('while 1:\n breaks = 5')
self.assertEqual(isp.get_indent_spaces(), 4)
isp.push('while 1:\n break')
self.assertEqual(isp.get_indent_spaces(), 0)
isp.push('while 1:\n break ')
self.assertEqual(isp.get_indent_spaces(), 0)
def test_dedent_continue(self):
isp = self.isp # shorthand
# should NOT cause dedent
isp.push('while 1:\n continues = 5')
self.assertEqual(isp.get_indent_spaces(), 4)
isp.push('while 1:\n continue')
self.assertEqual(isp.get_indent_spaces(), 0)
isp.push('while 1:\n continue ')
self.assertEqual(isp.get_indent_spaces(), 0)
def test_dedent_raise(self):
isp = self.isp # shorthand
# should NOT cause dedent
isp.push('if 1:\n raised = 4')
self.assertEqual(isp.get_indent_spaces(), 4)
isp.push('if 1:\n raise TypeError()')
self.assertEqual(isp.get_indent_spaces(), 0)
isp.push('if 1:\n raise')
self.assertEqual(isp.get_indent_spaces(), 0)
isp.push('if 1:\n raise ')
self.assertEqual(isp.get_indent_spaces(), 0)
def test_dedent_return(self):
isp = self.isp # shorthand
# should NOT cause dedent
isp.push('if 1:\n returning = 4')
self.assertEqual(isp.get_indent_spaces(), 4)
isp.push('if 1:\n return 5 + 493')
self.assertEqual(isp.get_indent_spaces(), 0)
isp.push('if 1:\n return')
self.assertEqual(isp.get_indent_spaces(), 0)
isp.push('if 1:\n return ')
self.assertEqual(isp.get_indent_spaces(), 0)
isp.push('if 1:\n return(0)')
self.assertEqual(isp.get_indent_spaces(), 0)
def test_push(self):
isp = self.isp
self.assertEqual(isp.push('x=1'), True)
def test_push2(self):
isp = self.isp
self.assertEqual(isp.push('if 1:'), False)
for line in [' x=1', '# a comment', ' y=2']:
print(line)
self.assertEqual(isp.push(line), True)
def test_push3(self):
isp = self.isp
isp.push('if True:')
isp.push(' a = 1')
self.assertEqual(isp.push('b = [1,'), False)
def test_push_accepts_more(self):
isp = self.isp
isp.push('x=1')
self.assertEqual(isp.push_accepts_more(), False)
def test_push_accepts_more2(self):
isp = self.isp
isp.push('if 1:')
self.assertEqual(isp.push_accepts_more(), True)
isp.push(' x=1')
self.assertEqual(isp.push_accepts_more(), True)
isp.push('')
self.assertEqual(isp.push_accepts_more(), False)
def test_push_accepts_more3(self):
isp = self.isp
isp.push("x = (2+\n3)")
self.assertEqual(isp.push_accepts_more(), False)
def test_push_accepts_more4(self):
isp = self.isp
# When a multiline statement contains parens or multiline strings, we
# shouldn't get confused.
# FIXME: we should be able to better handle de-dents in statements like
# multiline strings and multiline expressions (continued with \ or
# parens). Right now we aren't handling the indentation tracking quite
# correctly with this, though in practice it may not be too much of a
# problem. We'll need to see.
isp.push("if 1:")
isp.push(" x = (2+")
isp.push(" 3)")
self.assertEqual(isp.push_accepts_more(), True)
isp.push(" y = 3")
self.assertEqual(isp.push_accepts_more(), True)
isp.push('')
self.assertEqual(isp.push_accepts_more(), False)
def test_push_accepts_more5(self):
isp = self.isp
isp.push('try:')
isp.push(' a = 5')
isp.push('except:')
isp.push(' raise')
# We want to be able to add an else: block at this point, so it should
# wait for a blank line.
self.assertEqual(isp.push_accepts_more(), True)
def test_continuation(self):
isp = self.isp
isp.push("import os, \\")
self.assertEqual(isp.push_accepts_more(), True)
isp.push("sys")
self.assertEqual(isp.push_accepts_more(), False)
def test_syntax_error(self):
isp = self.isp
# Syntax errors immediately produce a 'ready' block, so the invalid
# Python can be sent to the kernel for evaluation with possible ipython
# special-syntax conversion.
isp.push('run foo')
self.assertEqual(isp.push_accepts_more(), False)
def test_unicode(self):
self.isp.push(u"Pérez")
self.isp.push(u'\xc3\xa9')
self.isp.push(u"u'\xc3\xa9'")
def test_line_continuation(self):
""" Test issue #2108."""
isp = self.isp
# A blank line after a line continuation should not accept more
isp.push("1 \\\n\n")
self.assertEqual(isp.push_accepts_more(), False)
# Whitespace after a \ is a SyntaxError. The only way to test that
# here is to test that push doesn't accept more (as with
# test_syntax_error() above).
isp.push(r"1 \ ")
self.assertEqual(isp.push_accepts_more(), False)
# Even if the line is continuable (c.f. the regular Python
# interpreter)
isp.push(r"(1 \ ")
self.assertEqual(isp.push_accepts_more(), False)
def test_check_complete(self):
isp = self.isp
self.assertEqual(isp.check_complete("a = 1"), ('complete', None))
self.assertEqual(isp.check_complete("for a in range(5):"), ('incomplete', 4))
self.assertEqual(isp.check_complete("raise = 2"), ('invalid', None))
self.assertEqual(isp.check_complete("a = [1,\n2,"), ('incomplete', 0))
self.assertEqual(isp.check_complete("def a():\n x=1\n global x"), ('invalid', None))
class InteractiveLoopTestCase(unittest.TestCase):
"""Tests for an interactive loop like a python shell.
"""
def check_ns(self, lines, ns):
"""Validate that the given input lines produce the resulting namespace.
Note: the input lines are given exactly as they would be typed in an
auto-indenting environment, as mini_interactive_loop above already does
auto-indenting and prepends spaces to the input.
"""
src = mini_interactive_loop(pseudo_input(lines))
test_ns = {}
exec(src, test_ns)
# We can't check that the provided ns is identical to the test_ns,
# because Python fills test_ns with extra keys (copyright, etc). But
# we can check that the given dict is *contained* in test_ns
for k,v in ns.items():
self.assertEqual(test_ns[k], v)
def test_simple(self):
self.check_ns(['x=1'], dict(x=1))
def test_simple2(self):
self.check_ns(['if 1:', 'x=2'], dict(x=2))
def test_xy(self):
self.check_ns(['x=1; y=2'], dict(x=1, y=2))
def test_abc(self):
self.check_ns(['if 1:','a=1','b=2','c=3'], dict(a=1, b=2, c=3))
def test_multi(self):
self.check_ns(['x =(1+','1+','2)'], dict(x=4))
class IPythonInputTestCase(InputSplitterTestCase):
"""By just creating a new class whose .isp is a different instance, we
re-run the same test battery on the new input splitter.
In addition, this runs the tests over the syntax and syntax_ml dicts that
were tested by individual functions, as part of the OO interface.
It also makes some checks on the raw buffer storage.
"""
def setUp(self):
self.isp = isp.IPythonInputSplitter()
def test_syntax(self):
"""Call all single-line syntax tests from the main object"""
isp = self.isp
for example in syntax.values():
for raw, out_t in example:
if raw.startswith(' '):
continue
isp.push(raw+'\n')
out_raw = isp.source_raw
out = isp.source_reset()
self.assertEqual(out.rstrip(), out_t,
tt.pair_fail_msg.format("inputsplitter",raw, out_t, out))
self.assertEqual(out_raw.rstrip(), raw.rstrip())
def test_syntax_multiline(self):
isp = self.isp
for example in syntax_ml.values():
for line_pairs in example:
out_t_parts = []
raw_parts = []
for lraw, out_t_part in line_pairs:
if out_t_part is not None:
out_t_parts.append(out_t_part)
if lraw is not None:
isp.push(lraw)
raw_parts.append(lraw)
out_raw = isp.source_raw
out = isp.source_reset()
out_t = '\n'.join(out_t_parts).rstrip()
raw = '\n'.join(raw_parts).rstrip()
self.assertEqual(out.rstrip(), out_t)
self.assertEqual(out_raw.rstrip(), raw)
def test_syntax_multiline_cell(self):
isp = self.isp
for example in syntax_ml.values():
out_t_parts = []
for line_pairs in example:
raw = '\n'.join(r for r, _ in line_pairs if r is not None)
out_t = '\n'.join(t for _,t in line_pairs if t is not None)
out = isp.transform_cell(raw)
# Match ignoring trailing whitespace
self.assertEqual(out.rstrip(), out_t.rstrip())
def test_cellmagic_preempt(self):
isp = self.isp
for raw, name, line, cell in [
("%%cellm a\nIn[1]:", u'cellm', u'a', u'In[1]:'),
("%%cellm \nline\n>>> hi", u'cellm', u'', u'line\n>>> hi'),
(">>> %%cellm \nline\n>>> hi", u'cellm', u'', u'line\nhi'),
("%%cellm \n>>> hi", u'cellm', u'', u'>>> hi'),
("%%cellm \nline1\nline2", u'cellm', u'', u'line1\nline2'),
("%%cellm \nline1\\\\\nline2", u'cellm', u'', u'line1\\\\\nline2'),
]:
expected = "get_ipython().run_cell_magic(%r, %r, %r)" % (
name, line, cell
)
out = isp.transform_cell(raw)
self.assertEqual(out.rstrip(), expected.rstrip())
def test_multiline_passthrough(self):
isp = self.isp
class CommentTransformer(InputTransformer):
def __init__(self):
self._lines = []
def push(self, line):
self._lines.append(line + '#')
def reset(self):
text = '\n'.join(self._lines)
self._lines = []
return text
isp.physical_line_transforms.insert(0, CommentTransformer())
for raw, expected in [
("a=5", "a=5#"),
("%ls foo", "get_ipython().run_line_magic(%r, %r)" % (u'ls', u'foo#')),
("!ls foo\n%ls bar", "get_ipython().system(%r)\nget_ipython().run_line_magic(%r, %r)" % (
u'ls foo#', u'ls', u'bar#'
)),
("1\n2\n3\n%ls foo\n4\n5", "1#\n2#\n3#\nget_ipython().run_line_magic(%r, %r)\n4#\n5#" % (u'ls', u'foo#')),
]:
out = isp.transform_cell(raw)
self.assertEqual(out.rstrip(), expected.rstrip())
#-----------------------------------------------------------------------------
# Main - use as a script, mostly for developer experiments
#-----------------------------------------------------------------------------
if __name__ == '__main__':
# A simple demo for interactive experimentation. This code will not get
# picked up by any test suite.
from IPython.core.inputsplitter import IPythonInputSplitter
# configure here the syntax to use, prompt and whether to autoindent
#isp, start_prompt = InputSplitter(), '>>> '
isp, start_prompt = IPythonInputSplitter(), 'In> '
autoindent = True
#autoindent = False
try:
while True:
prompt = start_prompt
while isp.push_accepts_more():
indent = ' '*isp.get_indent_spaces()
if autoindent:
line = indent + input(prompt+indent)
else:
line = input(prompt)
isp.push(line)
prompt = '... '
# Here we just return input so we can use it in a test suite, but a
# real interpreter would instead send it for execution somewhere.
#src = isp.source; raise EOFError # dbg
raw = isp.source_raw
src = isp.source_reset()
print('Input source was:\n', src)
print('Raw source was:\n', raw)
except EOFError:
print('Bye')
# Tests for cell magics support
def test_last_blank():
nt.assert_false(isp.last_blank(''))
nt.assert_false(isp.last_blank('abc'))
nt.assert_false(isp.last_blank('abc\n'))
nt.assert_false(isp.last_blank('abc\na'))
nt.assert_true(isp.last_blank('\n'))
nt.assert_true(isp.last_blank('\n '))
nt.assert_true(isp.last_blank('abc\n '))
nt.assert_true(isp.last_blank('abc\n\n'))
nt.assert_true(isp.last_blank('abc\nd\n\n'))
nt.assert_true(isp.last_blank('abc\nd\ne\n\n'))
nt.assert_true(isp.last_blank('abc \n \n \n\n'))
def test_last_two_blanks():
nt.assert_false(isp.last_two_blanks(''))
nt.assert_false(isp.last_two_blanks('abc'))
nt.assert_false(isp.last_two_blanks('abc\n'))
nt.assert_false(isp.last_two_blanks('abc\n\na'))
nt.assert_false(isp.last_two_blanks('abc\n \n'))
nt.assert_false(isp.last_two_blanks('abc\n\n'))
nt.assert_true(isp.last_two_blanks('\n\n'))
nt.assert_true(isp.last_two_blanks('\n\n '))
nt.assert_true(isp.last_two_blanks('\n \n'))
nt.assert_true(isp.last_two_blanks('abc\n\n '))
nt.assert_true(isp.last_two_blanks('abc\n\n\n'))
nt.assert_true(isp.last_two_blanks('abc\n\n \n'))
nt.assert_true(isp.last_two_blanks('abc\n\n \n '))
nt.assert_true(isp.last_two_blanks('abc\n\n \n \n'))
nt.assert_true(isp.last_two_blanks('abc\nd\n\n\n'))
nt.assert_true(isp.last_two_blanks('abc\nd\ne\nf\n\n\n'))
class CellMagicsCommon(object):
def test_whole_cell(self):
src = "%%cellm line\nbody\n"
out = self.sp.transform_cell(src)
ref = "get_ipython().run_cell_magic('cellm', 'line', 'body')\n"
nt.assert_equal(out, ref)
def test_cellmagic_help(self):
self.sp.push('%%cellm?')
nt.assert_false(self.sp.push_accepts_more())
def tearDown(self):
self.sp.reset()
class CellModeCellMagics(CellMagicsCommon, unittest.TestCase):
sp = isp.IPythonInputSplitter(line_input_checker=False)
def test_incremental(self):
sp = self.sp
sp.push('%%cellm firstline\n')
nt.assert_true(sp.push_accepts_more()) #1
sp.push('line2\n')
nt.assert_true(sp.push_accepts_more()) #2
sp.push('\n')
# This should accept a blank line and carry on until the cell is reset
nt.assert_true(sp.push_accepts_more()) #3
def test_no_strip_coding(self):
src = '\n'.join([
'%%writefile foo.py',
'# coding: utf-8',
'print(u"üñîçø∂é")',
])
out = self.sp.transform_cell(src)
nt.assert_in('# coding: utf-8', out)
class LineModeCellMagics(CellMagicsCommon, unittest.TestCase):
sp = isp.IPythonInputSplitter(line_input_checker=True)
def test_incremental(self):
sp = self.sp
sp.push('%%cellm line2\n')
nt.assert_true(sp.push_accepts_more()) #1
sp.push('\n')
# In this case, a blank line should end the cell magic
nt.assert_false(sp.push_accepts_more()) #2
indentation_samples = [
('a = 1', 0),
('for a in b:', 4),
('def f():', 4),
('def f(): #comment', 4),
('a = ":#not a comment"', 0),
('def f():\n a = 1', 4),
('def f():\n return 1', 0),
('for a in b:\n'
' if a < 0:'
' continue', 3),
('a = {', 4),
('a = {\n'
' 1,', 5),
('b = """123', 0),
('', 0),
('def f():\n pass', 0),
('class Bar:\n def f():\n pass', 4),
('class Bar:\n def f():\n raise', 4),
]
def test_find_next_indent():
for code, exp in indentation_samples:
res = isp.find_next_indent(code)
msg = "{!r} != {!r} (expected)\n Code: {!r}".format(res, exp, code)
assert res == exp, msg

View file

@ -0,0 +1,495 @@
import tokenize
import nose.tools as nt
from IPython.testing import tools as tt
from IPython.utils import py3compat
u_fmt = py3compat.u_format
from IPython.core import inputtransformer as ipt
def transform_and_reset(transformer):
transformer = transformer()
def transform(inp):
try:
return transformer.push(inp)
finally:
transformer.reset()
return transform
# Transformer tests
def transform_checker(tests, transformer, **kwargs):
"""Utility to loop over test inputs"""
transformer = transformer(**kwargs)
try:
for inp, tr in tests:
if inp is None:
out = transformer.reset()
else:
out = transformer.push(inp)
nt.assert_equal(out, tr)
finally:
transformer.reset()
# Data for all the syntax tests in the form of lists of pairs of
# raw/transformed input. We store it here as a global dict so that we can use
# it both within single-function tests and also to validate the behavior of the
# larger objects
syntax = \
dict(assign_system =
[(i,py3compat.u_format(o)) for i,o in \
[(u'a =! ls', "a = get_ipython().getoutput('ls')"),
(u'b = !ls', "b = get_ipython().getoutput('ls')"),
(u'c= !ls', "c = get_ipython().getoutput('ls')"),
(u'd == !ls', u'd == !ls'), # Invalid syntax, but we leave == alone.
('x=1', 'x=1'), # normal input is unmodified
(' ',' '), # blank lines are kept intact
# Tuple unpacking
(u"a, b = !echo 'a\\nb'", u"a, b = get_ipython().getoutput(\"echo 'a\\\\nb'\")"),
(u"a,= !echo 'a'", u"a, = get_ipython().getoutput(\"echo 'a'\")"),
(u"a, *bc = !echo 'a\\nb\\nc'", u"a, *bc = get_ipython().getoutput(\"echo 'a\\\\nb\\\\nc'\")"),
# Tuple unpacking with regular Python expressions, not our syntax.
(u"a, b = range(2)", u"a, b = range(2)"),
(u"a, = range(1)", u"a, = range(1)"),
(u"a, *bc = range(3)", u"a, *bc = range(3)"),
]],
assign_magic =
[(i,py3compat.u_format(o)) for i,o in \
[(u'a =% who', "a = get_ipython().run_line_magic('who', '')"),
(u'b = %who', "b = get_ipython().run_line_magic('who', '')"),
(u'c= %ls', "c = get_ipython().run_line_magic('ls', '')"),
(u'd == %ls', u'd == %ls'), # Invalid syntax, but we leave == alone.
('x=1', 'x=1'), # normal input is unmodified
(' ',' '), # blank lines are kept intact
(u"a, b = %foo", u"a, b = get_ipython().run_line_magic('foo', '')"),
]],
classic_prompt =
[('>>> x=1', 'x=1'),
('x=1', 'x=1'), # normal input is unmodified
(' ', ' '), # blank lines are kept intact
],
ipy_prompt =
[('In [1]: x=1', 'x=1'),
('x=1', 'x=1'), # normal input is unmodified
(' ',' '), # blank lines are kept intact
],
# Tests for the escape transformer to leave normal code alone
escaped_noesc =
[ (' ', ' '),
('x=1', 'x=1'),
],
# System calls
escaped_shell =
[(i,py3compat.u_format(o)) for i,o in \
[ (u'!ls', "get_ipython().system('ls')"),
# Double-escape shell, this means to capture the output of the
# subprocess and return it
(u'!!ls', "get_ipython().getoutput('ls')"),
]],
# Help/object info
escaped_help =
[(i,py3compat.u_format(o)) for i,o in \
[ (u'?', 'get_ipython().show_usage()'),
(u'?x1', "get_ipython().run_line_magic('pinfo', 'x1')"),
(u'??x2', "get_ipython().run_line_magic('pinfo2', 'x2')"),
(u'?a.*s', "get_ipython().run_line_magic('psearch', 'a.*s')"),
(u'?%hist1', "get_ipython().run_line_magic('pinfo', '%hist1')"),
(u'?%%hist2', "get_ipython().run_line_magic('pinfo', '%%hist2')"),
(u'?abc = qwe', "get_ipython().run_line_magic('pinfo', 'abc')"),
]],
end_help =
[(i,py3compat.u_format(o)) for i,o in \
[ (u'x3?', "get_ipython().run_line_magic('pinfo', 'x3')"),
(u'x4??', "get_ipython().run_line_magic('pinfo2', 'x4')"),
(u'%hist1?', "get_ipython().run_line_magic('pinfo', '%hist1')"),
(u'%hist2??', "get_ipython().run_line_magic('pinfo2', '%hist2')"),
(u'%%hist3?', "get_ipython().run_line_magic('pinfo', '%%hist3')"),
(u'%%hist4??', "get_ipython().run_line_magic('pinfo2', '%%hist4')"),
(u'π.foo?', "get_ipython().run_line_magic('pinfo', 'π.foo')"),
(u'f*?', "get_ipython().run_line_magic('psearch', 'f*')"),
(u'ax.*aspe*?', "get_ipython().run_line_magic('psearch', 'ax.*aspe*')"),
(u'a = abc?', "get_ipython().set_next_input('a = abc');"
"get_ipython().run_line_magic('pinfo', 'abc')"),
(u'a = abc.qe??', "get_ipython().set_next_input('a = abc.qe');"
"get_ipython().run_line_magic('pinfo2', 'abc.qe')"),
(u'a = *.items?', "get_ipython().set_next_input('a = *.items');"
"get_ipython().run_line_magic('psearch', '*.items')"),
(u'plot(a?', "get_ipython().set_next_input('plot(a');"
"get_ipython().run_line_magic('pinfo', 'a')"),
(u'a*2 #comment?', 'a*2 #comment?'),
]],
# Explicit magic calls
escaped_magic =
[(i,py3compat.u_format(o)) for i,o in \
[ (u'%cd', "get_ipython().run_line_magic('cd', '')"),
(u'%cd /home', "get_ipython().run_line_magic('cd', '/home')"),
# Backslashes need to be escaped.
(u'%cd C:\\User', "get_ipython().run_line_magic('cd', 'C:\\\\User')"),
(u' %magic', " get_ipython().run_line_magic('magic', '')"),
]],
# Quoting with separate arguments
escaped_quote =
[ (',f', 'f("")'),
(',f x', 'f("x")'),
(' ,f y', ' f("y")'),
(',f a b', 'f("a", "b")'),
],
# Quoting with single argument
escaped_quote2 =
[ (';f', 'f("")'),
(';f x', 'f("x")'),
(' ;f y', ' f("y")'),
(';f a b', 'f("a b")'),
],
# Simply apply parens
escaped_paren =
[ ('/f', 'f()'),
('/f x', 'f(x)'),
(' /f y', ' f(y)'),
('/f a b', 'f(a, b)'),
],
# Check that we transform prompts before other transforms
mixed =
[(i,py3compat.u_format(o)) for i,o in \
[ (u'In [1]: %lsmagic', "get_ipython().run_line_magic('lsmagic', '')"),
(u'>>> %lsmagic', "get_ipython().run_line_magic('lsmagic', '')"),
(u'In [2]: !ls', "get_ipython().system('ls')"),
(u'In [3]: abs?', "get_ipython().run_line_magic('pinfo', 'abs')"),
(u'In [4]: b = %who', "b = get_ipython().run_line_magic('who', '')"),
]],
)
# multiline syntax examples. Each of these should be a list of lists, with
# each entry itself having pairs of raw/transformed input. The union (with
# '\n'.join() of the transformed inputs is what the splitter should produce
# when fed the raw lines one at a time via push.
syntax_ml = \
dict(classic_prompt =
[ [('>>> for i in range(10):','for i in range(10):'),
('... print i',' print i'),
('... ', ''),
],
[('>>> a="""','a="""'),
('... 123"""','123"""'),
],
[('a="""','a="""'),
('... 123','123'),
('... 456"""','456"""'),
],
[('a="""','a="""'),
('>>> 123','123'),
('... 456"""','456"""'),
],
[('a="""','a="""'),
('123','123'),
('... 456"""','... 456"""'),
],
[('....__class__','....__class__'),
],
[('a=5', 'a=5'),
('...', ''),
],
[('>>> def f(x):', 'def f(x):'),
('...', ''),
('... return x', ' return x'),
],
[('board = """....', 'board = """....'),
('....', '....'),
('...."""', '...."""'),
],
],
ipy_prompt =
[ [('In [24]: for i in range(10):','for i in range(10):'),
(' ....: print i',' print i'),
(' ....: ', ''),
],
[('In [24]: for i in range(10):','for i in range(10):'),
# Qt console prompts expand with spaces, not dots
(' ...: print i',' print i'),
(' ...: ', ''),
],
[('In [24]: for i in range(10):','for i in range(10):'),
# Sometimes whitespace preceding '...' has been removed
('...: print i',' print i'),
('...: ', ''),
],
[('In [24]: for i in range(10):','for i in range(10):'),
# Space after last continuation prompt has been removed (issue #6674)
('...: print i',' print i'),
('...:', ''),
],
[('In [2]: a="""','a="""'),
(' ...: 123"""','123"""'),
],
[('a="""','a="""'),
(' ...: 123','123'),
(' ...: 456"""','456"""'),
],
[('a="""','a="""'),
('In [1]: 123','123'),
(' ...: 456"""','456"""'),
],
[('a="""','a="""'),
('123','123'),
(' ...: 456"""',' ...: 456"""'),
],
],
multiline_datastructure_prompt =
[ [('>>> a = [1,','a = [1,'),
('... 2]','2]'),
],
],
multiline_datastructure =
[ [('b = ("%s"', None),
('# comment', None),
('%foo )', 'b = ("%s"\n# comment\n%foo )'),
],
],
multiline_string =
[ [("'''foo?", None),
("bar'''", "'''foo?\nbar'''"),
],
],
leading_indent =
[ [(' print "hi"','print "hi"'),
],
[(' for a in range(5):','for a in range(5):'),
(' a*2',' a*2'),
],
[(' a="""','a="""'),
(' 123"""','123"""'),
],
[('a="""','a="""'),
(' 123"""',' 123"""'),
],
],
cellmagic =
[ [(u'%%foo a', None),
(None, u_fmt("get_ipython().run_cell_magic('foo', 'a', '')")),
],
[(u'%%bar 123', None),
(u'hello', None),
(None , u_fmt("get_ipython().run_cell_magic('bar', '123', 'hello')")),
],
[(u'a=5', 'a=5'),
(u'%%cellmagic', '%%cellmagic'),
],
],
escaped =
[ [('%abc def \\', None),
('ghi', u_fmt("get_ipython().run_line_magic('abc', 'def ghi')")),
],
[('%abc def \\', None),
('ghi\\', None),
(None, u_fmt("get_ipython().run_line_magic('abc', 'def ghi')")),
],
],
assign_magic =
[ [(u'a = %bc de \\', None),
(u'fg', u_fmt("a = get_ipython().run_line_magic('bc', 'de fg')")),
],
[(u'a = %bc de \\', None),
(u'fg\\', None),
(None, u_fmt("a = get_ipython().run_line_magic('bc', 'de fg')")),
],
],
assign_system =
[ [(u'a = !bc de \\', None),
(u'fg', u_fmt("a = get_ipython().getoutput('bc de fg')")),
],
[(u'a = !bc de \\', None),
(u'fg\\', None),
(None, u_fmt("a = get_ipython().getoutput('bc de fg')")),
],
],
)
def test_assign_system():
tt.check_pairs(transform_and_reset(ipt.assign_from_system), syntax['assign_system'])
def test_assign_magic():
tt.check_pairs(transform_and_reset(ipt.assign_from_magic), syntax['assign_magic'])
def test_classic_prompt():
tt.check_pairs(transform_and_reset(ipt.classic_prompt), syntax['classic_prompt'])
for example in syntax_ml['classic_prompt']:
transform_checker(example, ipt.classic_prompt)
for example in syntax_ml['multiline_datastructure_prompt']:
transform_checker(example, ipt.classic_prompt)
# Check that we don't transform the second line if the first is obviously
# IPython syntax
transform_checker([
(u'%foo', '%foo'),
(u'>>> bar', '>>> bar'),
], ipt.classic_prompt)
def test_ipy_prompt():
tt.check_pairs(transform_and_reset(ipt.ipy_prompt), syntax['ipy_prompt'])
for example in syntax_ml['ipy_prompt']:
transform_checker(example, ipt.ipy_prompt)
# Check that we don't transform the second line if we're inside a cell magic
transform_checker([
(u'%%foo', '%%foo'),
(u'In [1]: bar', 'In [1]: bar'),
], ipt.ipy_prompt)
def test_assemble_logical_lines():
tests = \
[ [(u"a = \\", None),
(u"123", u"a = 123"),
],
[(u"a = \\", None), # Test resetting when within a multi-line string
(u"12 *\\", None),
(None, u"a = 12 *"),
],
[(u"# foo\\", u"# foo\\"), # Comments can't be continued like this
],
]
for example in tests:
transform_checker(example, ipt.assemble_logical_lines)
def test_assemble_python_lines():
tests = \
[ [(u"a = '''", None),
(u"abc'''", u"a = '''\nabc'''"),
],
[(u"a = '''", None), # Test resetting when within a multi-line string
(u"def", None),
(None, u"a = '''\ndef"),
],
[(u"a = [1,", None),
(u"2]", u"a = [1,\n2]"),
],
[(u"a = [1,", None), # Test resetting when within a multi-line string
(u"2,", None),
(None, u"a = [1,\n2,"),
],
[(u"a = '''", None), # Test line continuation within a multi-line string
(u"abc\\", None),
(u"def", None),
(u"'''", u"a = '''\nabc\\\ndef\n'''"),
],
] + syntax_ml['multiline_datastructure']
for example in tests:
transform_checker(example, ipt.assemble_python_lines)
def test_help_end():
tt.check_pairs(transform_and_reset(ipt.help_end), syntax['end_help'])
def test_escaped_noesc():
tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_noesc'])
def test_escaped_shell():
tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_shell'])
def test_escaped_help():
tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_help'])
def test_escaped_magic():
tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_magic'])
def test_escaped_quote():
tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_quote'])
def test_escaped_quote2():
tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_quote2'])
def test_escaped_paren():
tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_paren'])
def test_cellmagic():
for example in syntax_ml['cellmagic']:
transform_checker(example, ipt.cellmagic)
line_example = [(u'%%bar 123', None),
(u'hello', None),
(u'' , u_fmt("get_ipython().run_cell_magic('bar', '123', 'hello')")),
]
transform_checker(line_example, ipt.cellmagic, end_on_blank_line=True)
def test_has_comment():
tests = [('text', False),
('text #comment', True),
('text #comment\n', True),
('#comment', True),
('#comment\n', True),
('a = "#string"', False),
('a = "#string" # comment', True),
('a #comment not "string"', True),
]
tt.check_pairs(ipt.has_comment, tests)
@ipt.TokenInputTransformer.wrap
def decistmt(tokens):
"""Substitute Decimals for floats in a string of statements.
Based on an example from the tokenize module docs.
"""
result = []
for toknum, tokval, _, _, _ in tokens:
if toknum == tokenize.NUMBER and '.' in tokval: # replace NUMBER tokens
for newtok in [
(tokenize.NAME, 'Decimal'),
(tokenize.OP, '('),
(tokenize.STRING, repr(tokval)),
(tokenize.OP, ')')
]:
yield newtok
else:
yield (toknum, tokval)
def test_token_input_transformer():
tests = [(u'1.2', u_fmt(u"Decimal ('1.2')")),
(u'"1.2"', u'"1.2"'),
]
tt.check_pairs(transform_and_reset(decistmt), tests)
ml_tests = \
[ [(u"a = 1.2; b = '''x", None),
(u"y'''", u_fmt(u"a =Decimal ('1.2');b ='''x\ny'''")),
],
[(u"a = [1.2,", None),
(u"3]", u_fmt(u"a =[Decimal ('1.2'),\n3 ]")),
],
[(u"a = '''foo", None), # Test resetting when within a multi-line string
(u"bar", None),
(None, u"a = '''foo\nbar"),
],
]
for example in ml_tests:
transform_checker(example, decistmt)

View file

@ -0,0 +1,292 @@
"""Tests for the token-based transformers in IPython.core.inputtransformer2
Line-based transformers are the simpler ones; token-based transformers are
more complex. See test_inputtransformer2_line for tests for line-based
transformations.
"""
import nose.tools as nt
import string
from IPython.core import inputtransformer2 as ipt2
from IPython.core.inputtransformer2 import make_tokens_by_line, _find_assign_op
from textwrap import dedent
MULTILINE_MAGIC = ("""\
a = f()
%foo \\
bar
g()
""".splitlines(keepends=True), (2, 0), """\
a = f()
get_ipython().run_line_magic('foo', ' bar')
g()
""".splitlines(keepends=True))
INDENTED_MAGIC = ("""\
for a in range(5):
%ls
""".splitlines(keepends=True), (2, 4), """\
for a in range(5):
get_ipython().run_line_magic('ls', '')
""".splitlines(keepends=True))
MULTILINE_MAGIC_ASSIGN = ("""\
a = f()
b = %foo \\
bar
g()
""".splitlines(keepends=True), (2, 4), """\
a = f()
b = get_ipython().run_line_magic('foo', ' bar')
g()
""".splitlines(keepends=True))
MULTILINE_SYSTEM_ASSIGN = ("""\
a = f()
b = !foo \\
bar
g()
""".splitlines(keepends=True), (2, 4), """\
a = f()
b = get_ipython().getoutput('foo bar')
g()
""".splitlines(keepends=True))
#####
MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT = ("""\
def test():
for i in range(1):
print(i)
res =! ls
""".splitlines(keepends=True), (4, 7), '''\
def test():
for i in range(1):
print(i)
res =get_ipython().getoutput(\' ls\')
'''.splitlines(keepends=True))
######
AUTOCALL_QUOTE = (
[",f 1 2 3\n"], (1, 0),
['f("1", "2", "3")\n']
)
AUTOCALL_QUOTE2 = (
[";f 1 2 3\n"], (1, 0),
['f("1 2 3")\n']
)
AUTOCALL_PAREN = (
["/f 1 2 3\n"], (1, 0),
['f(1, 2, 3)\n']
)
SIMPLE_HELP = (
["foo?\n"], (1, 0),
["get_ipython().run_line_magic('pinfo', 'foo')\n"]
)
DETAILED_HELP = (
["foo??\n"], (1, 0),
["get_ipython().run_line_magic('pinfo2', 'foo')\n"]
)
MAGIC_HELP = (
["%foo?\n"], (1, 0),
["get_ipython().run_line_magic('pinfo', '%foo')\n"]
)
HELP_IN_EXPR = (
["a = b + c?\n"], (1, 0),
["get_ipython().set_next_input('a = b + c');"
"get_ipython().run_line_magic('pinfo', 'c')\n"]
)
HELP_CONTINUED_LINE = ("""\
a = \\
zip?
""".splitlines(keepends=True), (1, 0),
[r"get_ipython().set_next_input('a = \\\nzip');get_ipython().run_line_magic('pinfo', 'zip')" + "\n"]
)
HELP_MULTILINE = ("""\
(a,
b) = zip?
""".splitlines(keepends=True), (1, 0),
[r"get_ipython().set_next_input('(a,\nb) = zip');get_ipython().run_line_magic('pinfo', 'zip')" + "\n"]
)
HELP_UNICODE = (
["π.foo?\n"], (1, 0),
["get_ipython().run_line_magic('pinfo', 'π.foo')\n"]
)
def null_cleanup_transformer(lines):
"""
A cleanup transform that returns an empty list.
"""
return []
def check_make_token_by_line_never_ends_empty():
"""
Check that not sequence of single or double characters ends up leading to en empty list of tokens
"""
from string import printable
for c in printable:
nt.assert_not_equal(make_tokens_by_line(c)[-1], [])
for k in printable:
nt.assert_not_equal(make_tokens_by_line(c+k)[-1], [])
def check_find(transformer, case, match=True):
sample, expected_start, _ = case
tbl = make_tokens_by_line(sample)
res = transformer.find(tbl)
if match:
# start_line is stored 0-indexed, expected values are 1-indexed
nt.assert_equal((res.start_line+1, res.start_col), expected_start)
return res
else:
nt.assert_is(res, None)
def check_transform(transformer_cls, case):
lines, start, expected = case
transformer = transformer_cls(start)
nt.assert_equal(transformer.transform(lines), expected)
def test_continued_line():
lines = MULTILINE_MAGIC_ASSIGN[0]
nt.assert_equal(ipt2.find_end_of_continued_line(lines, 1), 2)
nt.assert_equal(ipt2.assemble_continued_line(lines, (1, 5), 2), "foo bar")
def test_find_assign_magic():
check_find(ipt2.MagicAssign, MULTILINE_MAGIC_ASSIGN)
check_find(ipt2.MagicAssign, MULTILINE_SYSTEM_ASSIGN, match=False)
check_find(ipt2.MagicAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT, match=False)
def test_transform_assign_magic():
check_transform(ipt2.MagicAssign, MULTILINE_MAGIC_ASSIGN)
def test_find_assign_system():
check_find(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN)
check_find(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT)
check_find(ipt2.SystemAssign, (["a = !ls\n"], (1, 5), None))
check_find(ipt2.SystemAssign, (["a=!ls\n"], (1, 2), None))
check_find(ipt2.SystemAssign, MULTILINE_MAGIC_ASSIGN, match=False)
def test_transform_assign_system():
check_transform(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN)
check_transform(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT)
def test_find_magic_escape():
check_find(ipt2.EscapedCommand, MULTILINE_MAGIC)
check_find(ipt2.EscapedCommand, INDENTED_MAGIC)
check_find(ipt2.EscapedCommand, MULTILINE_MAGIC_ASSIGN, match=False)
def test_transform_magic_escape():
check_transform(ipt2.EscapedCommand, MULTILINE_MAGIC)
check_transform(ipt2.EscapedCommand, INDENTED_MAGIC)
def test_find_autocalls():
for case in [AUTOCALL_QUOTE, AUTOCALL_QUOTE2, AUTOCALL_PAREN]:
print("Testing %r" % case[0])
check_find(ipt2.EscapedCommand, case)
def test_transform_autocall():
for case in [AUTOCALL_QUOTE, AUTOCALL_QUOTE2, AUTOCALL_PAREN]:
print("Testing %r" % case[0])
check_transform(ipt2.EscapedCommand, case)
def test_find_help():
for case in [SIMPLE_HELP, DETAILED_HELP, MAGIC_HELP, HELP_IN_EXPR]:
check_find(ipt2.HelpEnd, case)
tf = check_find(ipt2.HelpEnd, HELP_CONTINUED_LINE)
nt.assert_equal(tf.q_line, 1)
nt.assert_equal(tf.q_col, 3)
tf = check_find(ipt2.HelpEnd, HELP_MULTILINE)
nt.assert_equal(tf.q_line, 1)
nt.assert_equal(tf.q_col, 8)
# ? in a comment does not trigger help
check_find(ipt2.HelpEnd, (["foo # bar?\n"], None, None), match=False)
# Nor in a string
check_find(ipt2.HelpEnd, (["foo = '''bar?\n"], None, None), match=False)
def test_transform_help():
tf = ipt2.HelpEnd((1, 0), (1, 9))
nt.assert_equal(tf.transform(HELP_IN_EXPR[0]), HELP_IN_EXPR[2])
tf = ipt2.HelpEnd((1, 0), (2, 3))
nt.assert_equal(tf.transform(HELP_CONTINUED_LINE[0]), HELP_CONTINUED_LINE[2])
tf = ipt2.HelpEnd((1, 0), (2, 8))
nt.assert_equal(tf.transform(HELP_MULTILINE[0]), HELP_MULTILINE[2])
tf = ipt2.HelpEnd((1, 0), (1, 0))
nt.assert_equal(tf.transform(HELP_UNICODE[0]), HELP_UNICODE[2])
def test_find_assign_op_dedent():
"""
be careful that empty token like dedent are not counted as parens
"""
class Tk:
def __init__(self, s):
self.string = s
nt.assert_equal(_find_assign_op([Tk(s) for s in ('','a','=','b')]), 2)
nt.assert_equal(_find_assign_op([Tk(s) for s in ('','(', 'a','=','b', ')', '=' ,'5')]), 6)
def test_check_complete():
cc = ipt2.TransformerManager().check_complete
nt.assert_equal(cc("a = 1"), ('complete', None))
nt.assert_equal(cc("for a in range(5):"), ('incomplete', 4))
nt.assert_equal(cc("for a in range(5):\n if a > 0:"), ('incomplete', 8))
nt.assert_equal(cc("raise = 2"), ('invalid', None))
nt.assert_equal(cc("a = [1,\n2,"), ('incomplete', 0))
nt.assert_equal(cc(")"), ('incomplete', 0))
nt.assert_equal(cc("\\\r\n"), ('incomplete', 0))
nt.assert_equal(cc("a = '''\n hi"), ('incomplete', 3))
nt.assert_equal(cc("def a():\n x=1\n global x"), ('invalid', None))
nt.assert_equal(cc("a \\ "), ('invalid', None)) # Nothing allowed after backslash
nt.assert_equal(cc("1\\\n+2"), ('complete', None))
nt.assert_equal(cc("exit"), ('complete', None))
example = dedent("""
if True:
a=1""" )
nt.assert_equal(cc(example), ('incomplete', 4))
nt.assert_equal(cc(example+'\n'), ('complete', None))
nt.assert_equal(cc(example+'\n '), ('complete', None))
# no need to loop on all the letters/numbers.
short = '12abAB'+string.printable[62:]
for c in short:
# test does not raise:
cc(c)
for k in short:
cc(c+k)
nt.assert_equal(cc("def f():\n x=0\n \\\n "), ('incomplete', 2))
def test_check_complete_II():
"""
Test that multiple line strings are properly handled.
Separate test function for convenience
"""
cc = ipt2.TransformerManager().check_complete
nt.assert_equal(cc('''def foo():\n """'''), ('incomplete', 4))
def test_null_cleanup_transformer():
manager = ipt2.TransformerManager()
manager.cleanup_transforms.insert(0, null_cleanup_transformer)
nt.assert_is(manager.transform_cell(""), "")

View file

@ -0,0 +1,116 @@
"""Tests for the line-based transformers in IPython.core.inputtransformer2
Line-based transformers are the simpler ones; token-based transformers are
more complex. See test_inputtransformer2 for tests for token-based transformers.
"""
import nose.tools as nt
from IPython.core import inputtransformer2 as ipt2
CELL_MAGIC = ("""\
%%foo arg
body 1
body 2
""", """\
get_ipython().run_cell_magic('foo', 'arg', 'body 1\\nbody 2\\n')
""")
def test_cell_magic():
for sample, expected in [CELL_MAGIC]:
nt.assert_equal(ipt2.cell_magic(sample.splitlines(keepends=True)),
expected.splitlines(keepends=True))
CLASSIC_PROMPT = ("""\
>>> for a in range(5):
... print(a)
""", """\
for a in range(5):
print(a)
""")
CLASSIC_PROMPT_L2 = ("""\
for a in range(5):
... print(a)
... print(a ** 2)
""", """\
for a in range(5):
print(a)
print(a ** 2)
""")
def test_classic_prompt():
for sample, expected in [CLASSIC_PROMPT, CLASSIC_PROMPT_L2]:
nt.assert_equal(ipt2.classic_prompt(sample.splitlines(keepends=True)),
expected.splitlines(keepends=True))
IPYTHON_PROMPT = ("""\
In [1]: for a in range(5):
...: print(a)
""", """\
for a in range(5):
print(a)
""")
IPYTHON_PROMPT_L2 = ("""\
for a in range(5):
...: print(a)
...: print(a ** 2)
""", """\
for a in range(5):
print(a)
print(a ** 2)
""")
def test_ipython_prompt():
for sample, expected in [IPYTHON_PROMPT, IPYTHON_PROMPT_L2]:
nt.assert_equal(ipt2.ipython_prompt(sample.splitlines(keepends=True)),
expected.splitlines(keepends=True))
INDENT_SPACES = ("""\
if True:
a = 3
""", """\
if True:
a = 3
""")
INDENT_TABS = ("""\
\tif True:
\t\tb = 4
""", """\
if True:
\tb = 4
""")
def test_leading_indent():
for sample, expected in [INDENT_SPACES, INDENT_TABS]:
nt.assert_equal(ipt2.leading_indent(sample.splitlines(keepends=True)),
expected.splitlines(keepends=True))
LEADING_EMPTY_LINES = ("""\
\t
if True:
a = 3
b = 4
""", """\
if True:
a = 3
b = 4
""")
ONLY_EMPTY_LINES = ("""\
\t
""", """\
\t
""")
def test_leading_empty_lines():
for sample, expected in [LEADING_EMPTY_LINES, ONLY_EMPTY_LINES]:
nt.assert_equal(
ipt2.leading_empty_lines(sample.splitlines(keepends=True)),
expected.splitlines(keepends=True))

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,246 @@
"""Tests for the key interactiveshell module, where the main ipython class is defined.
"""
#-----------------------------------------------------------------------------
# Module imports
#-----------------------------------------------------------------------------
# third party
import nose.tools as nt
# our own packages
#-----------------------------------------------------------------------------
# Test functions
#-----------------------------------------------------------------------------
def test_reset():
"""reset must clear most namespaces."""
# Check that reset runs without error
ip.reset()
# Once we've reset it (to clear of any junk that might have been there from
# other tests, we can count how many variables are in the user's namespace
nvars_user_ns = len(ip.user_ns)
nvars_hidden = len(ip.user_ns_hidden)
# Now add a few variables to user_ns, and check that reset clears them
ip.user_ns['x'] = 1
ip.user_ns['y'] = 1
ip.reset()
# Finally, check that all namespaces have only as many variables as we
# expect to find in them:
nt.assert_equal(len(ip.user_ns), nvars_user_ns)
nt.assert_equal(len(ip.user_ns_hidden), nvars_hidden)
# Tests for reporting of exceptions in various modes, handling of SystemExit,
# and %tb functionality. This is really a mix of testing ultraTB and interactiveshell.
def doctest_tb_plain():
"""
In [18]: xmode plain
Exception reporting mode: Plain
In [19]: run simpleerr.py
Traceback (most recent call last):
...line 32, in <module>
bar(mode)
...line 16, in bar
div0()
...line 8, in div0
x/y
ZeroDivisionError: ...
"""
def doctest_tb_context():
"""
In [3]: xmode context
Exception reporting mode: Context
In [4]: run simpleerr.py
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
<BLANKLINE>
... in <module>
30 mode = 'div'
31
---> 32 bar(mode)
<BLANKLINE>
... in bar(mode)
14 "bar"
15 if mode=='div':
---> 16 div0()
17 elif mode=='exit':
18 try:
<BLANKLINE>
... in div0()
6 x = 1
7 y = 0
----> 8 x/y
9
10 def sysexit(stat, mode):
<BLANKLINE>
ZeroDivisionError: ...
"""
def doctest_tb_verbose():
"""
In [5]: xmode verbose
Exception reporting mode: Verbose
In [6]: run simpleerr.py
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
<BLANKLINE>
... in <module>
30 mode = 'div'
31
---> 32 bar(mode)
global bar = <function bar at ...>
global mode = 'div'
<BLANKLINE>
... in bar(mode='div')
14 "bar"
15 if mode=='div':
---> 16 div0()
global div0 = <function div0 at ...>
17 elif mode=='exit':
18 try:
<BLANKLINE>
... in div0()
6 x = 1
7 y = 0
----> 8 x/y
x = 1
y = 0
9
10 def sysexit(stat, mode):
<BLANKLINE>
ZeroDivisionError: ...
"""
def doctest_tb_sysexit():
"""
In [17]: %xmode plain
Exception reporting mode: Plain
In [18]: %run simpleerr.py exit
An exception has occurred, use %tb to see the full traceback.
SystemExit: (1, 'Mode = exit')
In [19]: %run simpleerr.py exit 2
An exception has occurred, use %tb to see the full traceback.
SystemExit: (2, 'Mode = exit')
In [20]: %tb
Traceback (most recent call last):
File ... in <module>
bar(mode)
File ... line 22, in bar
sysexit(stat, mode)
File ... line 11, in sysexit
raise SystemExit(stat, 'Mode = %s' % mode)
SystemExit: (2, 'Mode = exit')
In [21]: %xmode context
Exception reporting mode: Context
In [22]: %tb
---------------------------------------------------------------------------
SystemExit Traceback (most recent call last)
<BLANKLINE>
...<module>
30 mode = 'div'
31
---> 32 bar(mode)
<BLANKLINE>
...bar(mode)
20 except:
21 stat = 1
---> 22 sysexit(stat, mode)
23 else:
24 raise ValueError('Unknown mode')
<BLANKLINE>
...sysexit(stat, mode)
9
10 def sysexit(stat, mode):
---> 11 raise SystemExit(stat, 'Mode = %s' % mode)
12
13 def bar(mode):
<BLANKLINE>
SystemExit: (2, 'Mode = exit')
In [23]: %xmode verbose
Exception reporting mode: Verbose
In [24]: %tb
---------------------------------------------------------------------------
SystemExit Traceback (most recent call last)
<BLANKLINE>
... in <module>
30 mode = 'div'
31
---> 32 bar(mode)
global bar = <function bar at ...>
global mode = 'exit'
<BLANKLINE>
... in bar(mode='exit')
20 except:
21 stat = 1
---> 22 sysexit(stat, mode)
global sysexit = <function sysexit at ...>
stat = 2
mode = 'exit'
23 else:
24 raise ValueError('Unknown mode')
<BLANKLINE>
... in sysexit(stat=2, mode='exit')
9
10 def sysexit(stat, mode):
---> 11 raise SystemExit(stat, 'Mode = %s' % mode)
global SystemExit = undefined
stat = 2
mode = 'exit'
12
13 def bar(mode):
<BLANKLINE>
SystemExit: (2, 'Mode = exit')
"""
def test_run_cell():
import textwrap
ip.run_cell('a = 10\na+=1')
ip.run_cell('assert a == 11\nassert 1')
nt.assert_equal(ip.user_ns['a'], 11)
complex = textwrap.dedent("""
if 1:
print "hello"
if 1:
print "world"
if 2:
print "foo"
if 3:
print "bar"
if 4:
print "bar"
""")
# Simply verifies that this kind of input is run
ip.run_cell(complex)
def test_db():
"""Test the internal database used for variable persistence."""
ip.db['__unittest_'] = 12
nt.assert_equal(ip.db['__unittest_'], 12)
del ip.db['__unittest_']
assert '__unittest_' not in ip.db

View file

@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
"""Test IPython.core.logger"""
import os.path
import nose.tools as nt
from IPython.utils.tempdir import TemporaryDirectory
def test_logstart_inaccessible_file():
try:
_ip.logger.logstart(logfname="/") # Opening that filename will fail.
except IOError:
pass
else:
nt.assert_true(False) # The try block should never pass.
try:
_ip.run_cell("a=1") # Check it doesn't try to log this
finally:
_ip.logger.log_active = False # If this fails, don't let later tests fail
def test_logstart_unicode():
with TemporaryDirectory() as tdir:
logfname = os.path.join(tdir, "test_unicode.log")
_ip.run_cell("'abc€'")
try:
_ip.magic("logstart -to %s" % logfname)
_ip.run_cell("'abc€'")
finally:
_ip.logger.logstop()

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,118 @@
#-----------------------------------------------------------------------------
# Copyright (C) 2010-2011, IPython Development Team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file COPYING.txt, distributed with this software.
#-----------------------------------------------------------------------------
import argparse
from nose.tools import assert_equal
from IPython.core.magic_arguments import (argument, argument_group, kwds,
magic_arguments, parse_argstring, real_name)
@magic_arguments()
@argument('-f', '--foo', help="an argument")
def magic_foo1(self, args):
""" A docstring.
"""
return parse_argstring(magic_foo1, args)
@magic_arguments()
def magic_foo2(self, args):
""" A docstring.
"""
return parse_argstring(magic_foo2, args)
@magic_arguments()
@argument('-f', '--foo', help="an argument")
@argument_group('Group')
@argument('-b', '--bar', help="a grouped argument")
@argument_group('Second Group')
@argument('-z', '--baz', help="another grouped argument")
def magic_foo3(self, args):
""" A docstring.
"""
return parse_argstring(magic_foo3, args)
@magic_arguments()
@kwds(argument_default=argparse.SUPPRESS)
@argument('-f', '--foo', help="an argument")
def magic_foo4(self, args):
""" A docstring.
"""
return parse_argstring(magic_foo4, args)
@magic_arguments('frobnicate')
@argument('-f', '--foo', help="an argument")
def magic_foo5(self, args):
""" A docstring.
"""
return parse_argstring(magic_foo5, args)
@magic_arguments()
@argument('-f', '--foo', help="an argument")
def magic_magic_foo(self, args):
""" A docstring.
"""
return parse_argstring(magic_magic_foo, args)
@magic_arguments()
@argument('-f', '--foo', help="an argument")
def foo(self, args):
""" A docstring.
"""
return parse_argstring(foo, args)
def test_magic_arguments():
assert_equal(magic_foo1.__doc__, '::\n\n %foo1 [-f FOO]\n\n A docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n')
assert_equal(getattr(magic_foo1, 'argcmd_name', None), None)
assert_equal(real_name(magic_foo1), 'foo1')
assert_equal(magic_foo1(None, ''), argparse.Namespace(foo=None))
assert hasattr(magic_foo1, 'has_arguments')
assert_equal(magic_foo2.__doc__, '::\n\n %foo2\n\n A docstring.\n')
assert_equal(getattr(magic_foo2, 'argcmd_name', None), None)
assert_equal(real_name(magic_foo2), 'foo2')
assert_equal(magic_foo2(None, ''), argparse.Namespace())
assert hasattr(magic_foo2, 'has_arguments')
assert_equal(magic_foo3.__doc__, '::\n\n %foo3 [-f FOO] [-b BAR] [-z BAZ]\n\n A docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n\nGroup:\n -b BAR, --bar BAR a grouped argument\n\nSecond Group:\n -z BAZ, --baz BAZ another grouped argument\n')
assert_equal(getattr(magic_foo3, 'argcmd_name', None), None)
assert_equal(real_name(magic_foo3), 'foo3')
assert_equal(magic_foo3(None, ''),
argparse.Namespace(bar=None, baz=None, foo=None))
assert hasattr(magic_foo3, 'has_arguments')
assert_equal(magic_foo4.__doc__, '::\n\n %foo4 [-f FOO]\n\n A docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n')
assert_equal(getattr(magic_foo4, 'argcmd_name', None), None)
assert_equal(real_name(magic_foo4), 'foo4')
assert_equal(magic_foo4(None, ''), argparse.Namespace())
assert hasattr(magic_foo4, 'has_arguments')
assert_equal(magic_foo5.__doc__, '::\n\n %frobnicate [-f FOO]\n\n A docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n')
assert_equal(getattr(magic_foo5, 'argcmd_name', None), 'frobnicate')
assert_equal(real_name(magic_foo5), 'frobnicate')
assert_equal(magic_foo5(None, ''), argparse.Namespace(foo=None))
assert hasattr(magic_foo5, 'has_arguments')
assert_equal(magic_magic_foo.__doc__, '::\n\n %magic_foo [-f FOO]\n\n A docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n')
assert_equal(getattr(magic_magic_foo, 'argcmd_name', None), None)
assert_equal(real_name(magic_magic_foo), 'magic_foo')
assert_equal(magic_magic_foo(None, ''), argparse.Namespace(foo=None))
assert hasattr(magic_magic_foo, 'has_arguments')
assert_equal(foo.__doc__, '::\n\n %foo [-f FOO]\n\n A docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n')
assert_equal(getattr(foo, 'argcmd_name', None), None)
assert_equal(real_name(foo), 'foo')
assert_equal(foo(None, ''), argparse.Namespace(foo=None))
assert hasattr(foo, 'has_arguments')

View file

@ -0,0 +1,192 @@
"""Tests for various magic functions specific to the terminal frontend.
Needs to be run by nose (to make ipython session available).
"""
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
import sys
from io import StringIO
from unittest import TestCase
import nose.tools as nt
from IPython.testing import tools as tt
#-----------------------------------------------------------------------------
# Test functions begin
#-----------------------------------------------------------------------------
def check_cpaste(code, should_fail=False):
"""Execute code via 'cpaste' and ensure it was executed, unless
should_fail is set.
"""
ip.user_ns['code_ran'] = False
src = StringIO()
if not hasattr(src, 'encoding'):
# IPython expects stdin to have an encoding attribute
src.encoding = None
src.write(code)
src.write('\n--\n')
src.seek(0)
stdin_save = sys.stdin
sys.stdin = src
try:
context = tt.AssertPrints if should_fail else tt.AssertNotPrints
with context("Traceback (most recent call last)"):
ip.magic('cpaste')
if not should_fail:
assert ip.user_ns['code_ran'], "%r failed" % code
finally:
sys.stdin = stdin_save
def test_cpaste():
"""Test cpaste magic"""
def runf():
"""Marker function: sets a flag when executed.
"""
ip.user_ns['code_ran'] = True
return 'runf' # return string so '+ runf()' doesn't result in success
tests = {'pass': ["runf()",
"In [1]: runf()",
"In [1]: if 1:\n ...: runf()",
"> > > runf()",
">>> runf()",
" >>> runf()",
],
'fail': ["1 + runf()",
"++ runf()",
]}
ip.user_ns['runf'] = runf
for code in tests['pass']:
check_cpaste(code)
for code in tests['fail']:
check_cpaste(code, should_fail=True)
class PasteTestCase(TestCase):
"""Multiple tests for clipboard pasting"""
def paste(self, txt, flags='-q'):
"""Paste input text, by default in quiet mode"""
ip.hooks.clipboard_get = lambda : txt
ip.magic('paste '+flags)
def setUp(self):
# Inject fake clipboard hook but save original so we can restore it later
self.original_clip = ip.hooks.clipboard_get
def tearDown(self):
# Restore original hook
ip.hooks.clipboard_get = self.original_clip
def test_paste(self):
ip.user_ns.pop('x', None)
self.paste('x = 1')
nt.assert_equal(ip.user_ns['x'], 1)
ip.user_ns.pop('x')
def test_paste_pyprompt(self):
ip.user_ns.pop('x', None)
self.paste('>>> x=2')
nt.assert_equal(ip.user_ns['x'], 2)
ip.user_ns.pop('x')
def test_paste_py_multi(self):
self.paste("""
>>> x = [1,2,3]
>>> y = []
>>> for i in x:
... y.append(i**2)
...
""")
nt.assert_equal(ip.user_ns['x'], [1,2,3])
nt.assert_equal(ip.user_ns['y'], [1,4,9])
def test_paste_py_multi_r(self):
"Now, test that self.paste -r works"
self.test_paste_py_multi()
nt.assert_equal(ip.user_ns.pop('x'), [1,2,3])
nt.assert_equal(ip.user_ns.pop('y'), [1,4,9])
nt.assert_false('x' in ip.user_ns)
ip.magic('paste -r')
nt.assert_equal(ip.user_ns['x'], [1,2,3])
nt.assert_equal(ip.user_ns['y'], [1,4,9])
def test_paste_email(self):
"Test pasting of email-quoted contents"
self.paste("""\
>> def foo(x):
>> return x + 1
>> xx = foo(1.1)""")
nt.assert_equal(ip.user_ns['xx'], 2.1)
def test_paste_email2(self):
"Email again; some programs add a space also at each quoting level"
self.paste("""\
> > def foo(x):
> > return x + 1
> > yy = foo(2.1) """)
nt.assert_equal(ip.user_ns['yy'], 3.1)
def test_paste_email_py(self):
"Email quoting of interactive input"
self.paste("""\
>> >>> def f(x):
>> ... return x+1
>> ...
>> >>> zz = f(2.5) """)
nt.assert_equal(ip.user_ns['zz'], 3.5)
def test_paste_echo(self):
"Also test self.paste echoing, by temporarily faking the writer"
w = StringIO()
writer = ip.write
ip.write = w.write
code = """
a = 100
b = 200"""
try:
self.paste(code,'')
out = w.getvalue()
finally:
ip.write = writer
nt.assert_equal(ip.user_ns['a'], 100)
nt.assert_equal(ip.user_ns['b'], 200)
assert out == code+"\n## -- End pasted text --\n"
def test_paste_leading_commas(self):
"Test multiline strings with leading commas"
tm = ip.magics_manager.registry['TerminalMagics']
s = '''\
a = """
,1,2,3
"""'''
ip.user_ns.pop('foo', None)
tm.store_or_execute(s, 'foo')
nt.assert_in('foo', ip.user_ns)
def test_paste_trailing_question(self):
"Test pasting sources with trailing question marks"
tm = ip.magics_manager.registry['TerminalMagics']
s = '''\
def funcfoo():
if True: #am i true?
return 'fooresult'
'''
ip.user_ns.pop('funcfoo', None)
self.paste(s)
nt.assert_equal(ip.user_ns['funcfoo'](), 'fooresult')

View file

@ -0,0 +1,447 @@
"""Tests for the object inspection functionality.
"""
# Copyright (c) IPython Development Team.
# Distributed under the terms of the Modified BSD License.
from inspect import signature, Signature, Parameter
import os
import re
import nose.tools as nt
from .. import oinspect
from decorator import decorator
from IPython.testing.tools import AssertPrints, AssertNotPrints
from IPython.utils.path import compress_user
#-----------------------------------------------------------------------------
# Globals and constants
#-----------------------------------------------------------------------------
inspector = None
def setup_module():
global inspector
inspector = oinspect.Inspector()
#-----------------------------------------------------------------------------
# Local utilities
#-----------------------------------------------------------------------------
# WARNING: since this test checks the line number where a function is
# defined, if any code is inserted above, the following line will need to be
# updated. Do NOT insert any whitespace between the next line and the function
# definition below.
THIS_LINE_NUMBER = 41 # Put here the actual number of this line
from unittest import TestCase
class Test(TestCase):
def test_find_source_lines(self):
self.assertEqual(oinspect.find_source_lines(Test.test_find_source_lines),
THIS_LINE_NUMBER+6)
# A couple of utilities to ensure these tests work the same from a source or a
# binary install
def pyfile(fname):
return os.path.normcase(re.sub('.py[co]$', '.py', fname))
def match_pyfiles(f1, f2):
nt.assert_equal(pyfile(f1), pyfile(f2))
def test_find_file():
match_pyfiles(oinspect.find_file(test_find_file), os.path.abspath(__file__))
def test_find_file_decorated1():
@decorator
def noop1(f):
def wrapper(*a, **kw):
return f(*a, **kw)
return wrapper
@noop1
def f(x):
"My docstring"
match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
nt.assert_equal(f.__doc__, "My docstring")
def test_find_file_decorated2():
@decorator
def noop2(f, *a, **kw):
return f(*a, **kw)
@noop2
@noop2
@noop2
def f(x):
"My docstring 2"
match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
nt.assert_equal(f.__doc__, "My docstring 2")
def test_find_file_magic():
run = ip.find_line_magic('run')
nt.assert_not_equal(oinspect.find_file(run), None)
# A few generic objects we can then inspect in the tests below
class Call(object):
"""This is the class docstring."""
def __init__(self, x, y=1):
"""This is the constructor docstring."""
def __call__(self, *a, **kw):
"""This is the call docstring."""
def method(self, x, z=2):
"""Some method's docstring"""
class HasSignature(object):
"""This is the class docstring."""
__signature__ = Signature([Parameter('test', Parameter.POSITIONAL_OR_KEYWORD)])
def __init__(self, *args):
"""This is the init docstring"""
class SimpleClass(object):
def method(self, x, z=2):
"""Some method's docstring"""
class Awkward(object):
def __getattr__(self, name):
raise Exception(name)
class NoBoolCall:
"""
callable with `__bool__` raising should still be inspect-able.
"""
def __call__(self):
"""does nothing"""
pass
def __bool__(self):
"""just raise NotImplemented"""
raise NotImplementedError('Must be implemented')
class SerialLiar(object):
"""Attribute accesses always get another copy of the same class.
unittest.mock.call does something similar, but it's not ideal for testing
as the failure mode is to eat all your RAM. This gives up after 10k levels.
"""
def __init__(self, max_fibbing_twig, lies_told=0):
if lies_told > 10000:
raise RuntimeError('Nose too long, honesty is the best policy')
self.max_fibbing_twig = max_fibbing_twig
self.lies_told = lies_told
max_fibbing_twig[0] = max(max_fibbing_twig[0], lies_told)
def __getattr__(self, item):
return SerialLiar(self.max_fibbing_twig, self.lies_told + 1)
#-----------------------------------------------------------------------------
# Tests
#-----------------------------------------------------------------------------
def test_info():
"Check that Inspector.info fills out various fields as expected."
i = inspector.info(Call, oname='Call')
nt.assert_equal(i['type_name'], 'type')
expted_class = str(type(type)) # <class 'type'> (Python 3) or <type 'type'>
nt.assert_equal(i['base_class'], expted_class)
nt.assert_regex(i['string_form'], "<class 'IPython.core.tests.test_oinspect.Call'( at 0x[0-9a-f]{1,9})?>")
fname = __file__
if fname.endswith(".pyc"):
fname = fname[:-1]
# case-insensitive comparison needed on some filesystems
# e.g. Windows:
nt.assert_equal(i['file'].lower(), compress_user(fname).lower())
nt.assert_equal(i['definition'], None)
nt.assert_equal(i['docstring'], Call.__doc__)
nt.assert_equal(i['source'], None)
nt.assert_true(i['isclass'])
nt.assert_equal(i['init_definition'], "Call(x, y=1)")
nt.assert_equal(i['init_docstring'], Call.__init__.__doc__)
i = inspector.info(Call, detail_level=1)
nt.assert_not_equal(i['source'], None)
nt.assert_equal(i['docstring'], None)
c = Call(1)
c.__doc__ = "Modified instance docstring"
i = inspector.info(c)
nt.assert_equal(i['type_name'], 'Call')
nt.assert_equal(i['docstring'], "Modified instance docstring")
nt.assert_equal(i['class_docstring'], Call.__doc__)
nt.assert_equal(i['init_docstring'], Call.__init__.__doc__)
nt.assert_equal(i['call_docstring'], Call.__call__.__doc__)
def test_class_signature():
info = inspector.info(HasSignature, 'HasSignature')
nt.assert_equal(info['init_definition'], "HasSignature(test)")
nt.assert_equal(info['init_docstring'], HasSignature.__init__.__doc__)
def test_info_awkward():
# Just test that this doesn't throw an error.
inspector.info(Awkward())
def test_bool_raise():
inspector.info(NoBoolCall())
def test_info_serialliar():
fib_tracker = [0]
inspector.info(SerialLiar(fib_tracker))
# Nested attribute access should be cut off at 100 levels deep to avoid
# infinite loops: https://github.com/ipython/ipython/issues/9122
nt.assert_less(fib_tracker[0], 9000)
def support_function_one(x, y=2, *a, **kw):
"""A simple function."""
def test_calldef_none():
# We should ignore __call__ for all of these.
for obj in [support_function_one, SimpleClass().method, any, str.upper]:
i = inspector.info(obj)
nt.assert_is(i['call_def'], None)
def f_kwarg(pos, *, kwonly):
pass
def test_definition_kwonlyargs():
i = inspector.info(f_kwarg, oname='f_kwarg') # analysis:ignore
nt.assert_equal(i['definition'], "f_kwarg(pos, *, kwonly)")
def test_getdoc():
class A(object):
"""standard docstring"""
pass
class B(object):
"""standard docstring"""
def getdoc(self):
return "custom docstring"
class C(object):
"""standard docstring"""
def getdoc(self):
return None
a = A()
b = B()
c = C()
nt.assert_equal(oinspect.getdoc(a), "standard docstring")
nt.assert_equal(oinspect.getdoc(b), "custom docstring")
nt.assert_equal(oinspect.getdoc(c), "standard docstring")
def test_empty_property_has_no_source():
i = inspector.info(property(), detail_level=1)
nt.assert_is(i['source'], None)
def test_property_sources():
import posixpath
# A simple adder whose source and signature stays
# the same across Python distributions
def simple_add(a, b):
"Adds two numbers"
return a + b
class A(object):
@property
def foo(self):
return 'bar'
foo = foo.setter(lambda self, v: setattr(self, 'bar', v))
dname = property(posixpath.dirname)
adder = property(simple_add)
i = inspector.info(A.foo, detail_level=1)
nt.assert_in('def foo(self):', i['source'])
nt.assert_in('lambda self, v:', i['source'])
i = inspector.info(A.dname, detail_level=1)
nt.assert_in('def dirname(p)', i['source'])
i = inspector.info(A.adder, detail_level=1)
nt.assert_in('def simple_add(a, b)', i['source'])
def test_property_docstring_is_in_info_for_detail_level_0():
class A(object):
@property
def foobar(self):
"""This is `foobar` property."""
pass
ip.user_ns['a_obj'] = A()
nt.assert_equal(
'This is `foobar` property.',
ip.object_inspect('a_obj.foobar', detail_level=0)['docstring'])
ip.user_ns['a_cls'] = A
nt.assert_equal(
'This is `foobar` property.',
ip.object_inspect('a_cls.foobar', detail_level=0)['docstring'])
def test_pdef():
# See gh-1914
def foo(): pass
inspector.pdef(foo, 'foo')
def test_pinfo_nonascii():
# See gh-1177
from . import nonascii2
ip.user_ns['nonascii2'] = nonascii2
ip._inspect('pinfo', 'nonascii2', detail_level=1)
def test_pinfo_type():
"""
type can fail in various edge case, for example `type.__subclass__()`
"""
ip._inspect('pinfo', 'type')
def test_pinfo_docstring_no_source():
"""Docstring should be included with detail_level=1 if there is no source"""
with AssertPrints('Docstring:'):
ip._inspect('pinfo', 'str.format', detail_level=0)
with AssertPrints('Docstring:'):
ip._inspect('pinfo', 'str.format', detail_level=1)
def test_pinfo_no_docstring_if_source():
"""Docstring should not be included with detail_level=1 if source is found"""
def foo():
"""foo has a docstring"""
ip.user_ns['foo'] = foo
with AssertPrints('Docstring:'):
ip._inspect('pinfo', 'foo', detail_level=0)
with AssertPrints('Source:'):
ip._inspect('pinfo', 'foo', detail_level=1)
with AssertNotPrints('Docstring:'):
ip._inspect('pinfo', 'foo', detail_level=1)
def test_pinfo_docstring_if_detail_and_no_source():
""" Docstring should be displayed if source info not available """
obj_def = '''class Foo(object):
""" This is a docstring for Foo """
def bar(self):
""" This is a docstring for Foo.bar """
pass
'''
ip.run_cell(obj_def)
ip.run_cell('foo = Foo()')
with AssertNotPrints("Source:"):
with AssertPrints('Docstring:'):
ip._inspect('pinfo', 'foo', detail_level=0)
with AssertPrints('Docstring:'):
ip._inspect('pinfo', 'foo', detail_level=1)
with AssertPrints('Docstring:'):
ip._inspect('pinfo', 'foo.bar', detail_level=0)
with AssertNotPrints('Docstring:'):
with AssertPrints('Source:'):
ip._inspect('pinfo', 'foo.bar', detail_level=1)
def test_pinfo_magic():
with AssertPrints('Docstring:'):
ip._inspect('pinfo', 'lsmagic', detail_level=0)
with AssertPrints('Source:'):
ip._inspect('pinfo', 'lsmagic', detail_level=1)
def test_init_colors():
# ensure colors are not present in signature info
info = inspector.info(HasSignature)
init_def = info['init_definition']
nt.assert_not_in('[0m', init_def)
def test_builtin_init():
info = inspector.info(list)
init_def = info['init_definition']
nt.assert_is_not_none(init_def)
def test_render_signature_short():
def short_fun(a=1): pass
sig = oinspect._render_signature(
signature(short_fun),
short_fun.__name__,
)
nt.assert_equal(sig, 'short_fun(a=1)')
def test_render_signature_long():
from typing import Optional
def long_function(
a_really_long_parameter: int,
and_another_long_one: bool = False,
let_us_make_sure_this_is_looong: Optional[str] = None,
) -> bool: pass
sig = oinspect._render_signature(
signature(long_function),
long_function.__name__,
)
nt.assert_in(sig, [
# Python >=3.9
'''\
long_function(
a_really_long_parameter: int,
and_another_long_one: bool = False,
let_us_make_sure_this_is_looong: Optional[str] = None,
) -> bool\
''',
# Python >=3.7
'''\
long_function(
a_really_long_parameter: int,
and_another_long_one: bool = False,
let_us_make_sure_this_is_looong: Union[str, NoneType] = None,
) -> bool\
''', # Python <=3.6
'''\
long_function(
a_really_long_parameter:int,
and_another_long_one:bool=False,
let_us_make_sure_this_is_looong:Union[str, NoneType]=None,
) -> bool\
''',
])

View file

@ -0,0 +1,20 @@
#-----------------------------------------------------------------------------
# Copyright (C) 2010-2011 The IPython Development Team.
#
# Distributed under the terms of the BSD License.
#
# The full license is in the file COPYING.txt, distributed with this software.
#-----------------------------------------------------------------------------
import io
# N.B. For the test suite, page.page is overridden (see IPython.testing.globalipapp)
from IPython.core import page
def test_detect_screen_size():
"""Simple smoketest for page._detect_screen_size."""
try:
page._detect_screen_size(True, 25)
except (TypeError, io.UnsupportedOperation):
# This can happen in the test suite, because stdout may not have a
# fileno.
pass

View file

@ -0,0 +1,200 @@
import errno
import os
import shutil
import sys
import tempfile
import warnings
from unittest.mock import patch
import nose.tools as nt
from testpath import modified_env, assert_isdir, assert_isfile
from IPython import paths
from IPython.testing.decorators import skip_win32
from IPython.utils.tempdir import TemporaryDirectory
TMP_TEST_DIR = os.path.realpath(tempfile.mkdtemp())
HOME_TEST_DIR = os.path.join(TMP_TEST_DIR, "home_test_dir")
XDG_TEST_DIR = os.path.join(HOME_TEST_DIR, "xdg_test_dir")
XDG_CACHE_DIR = os.path.join(HOME_TEST_DIR, "xdg_cache_dir")
IP_TEST_DIR = os.path.join(HOME_TEST_DIR,'.ipython')
def setup_module():
"""Setup testenvironment for the module:
- Adds dummy home dir tree
"""
# Do not mask exceptions here. In particular, catching WindowsError is a
# problem because that exception is only defined on Windows...
os.makedirs(IP_TEST_DIR)
os.makedirs(os.path.join(XDG_TEST_DIR, 'ipython'))
os.makedirs(os.path.join(XDG_CACHE_DIR, 'ipython'))
def teardown_module():
"""Teardown testenvironment for the module:
- Remove dummy home dir tree
"""
# Note: we remove the parent test dir, which is the root of all test
# subdirs we may have created. Use shutil instead of os.removedirs, so
# that non-empty directories are all recursively removed.
shutil.rmtree(TMP_TEST_DIR)
def patch_get_home_dir(dirpath):
return patch.object(paths, 'get_home_dir', return_value=dirpath)
def test_get_ipython_dir_1():
"""test_get_ipython_dir_1, Testcase to see if we can call get_ipython_dir without Exceptions."""
env_ipdir = os.path.join("someplace", ".ipython")
with patch.object(paths, '_writable_dir', return_value=True), \
modified_env({'IPYTHONDIR': env_ipdir}):
ipdir = paths.get_ipython_dir()
nt.assert_equal(ipdir, env_ipdir)
def test_get_ipython_dir_2():
"""test_get_ipython_dir_2, Testcase to see if we can call get_ipython_dir without Exceptions."""
with patch_get_home_dir('someplace'), \
patch.object(paths, 'get_xdg_dir', return_value=None), \
patch.object(paths, '_writable_dir', return_value=True), \
patch('os.name', "posix"), \
modified_env({'IPYTHON_DIR': None,
'IPYTHONDIR': None,
'XDG_CONFIG_HOME': None
}):
ipdir = paths.get_ipython_dir()
nt.assert_equal(ipdir, os.path.join("someplace", ".ipython"))
def test_get_ipython_dir_3():
"""test_get_ipython_dir_3, move XDG if defined, and .ipython doesn't exist."""
tmphome = TemporaryDirectory()
try:
with patch_get_home_dir(tmphome.name), \
patch('os.name', 'posix'), \
modified_env({
'IPYTHON_DIR': None,
'IPYTHONDIR': None,
'XDG_CONFIG_HOME': XDG_TEST_DIR,
}), warnings.catch_warnings(record=True) as w:
ipdir = paths.get_ipython_dir()
nt.assert_equal(ipdir, os.path.join(tmphome.name, ".ipython"))
if sys.platform != 'darwin':
nt.assert_equal(len(w), 1)
nt.assert_in('Moving', str(w[0]))
finally:
tmphome.cleanup()
def test_get_ipython_dir_4():
"""test_get_ipython_dir_4, warn if XDG and home both exist."""
with patch_get_home_dir(HOME_TEST_DIR), \
patch('os.name', 'posix'):
try:
os.mkdir(os.path.join(XDG_TEST_DIR, 'ipython'))
except OSError as e:
if e.errno != errno.EEXIST:
raise
with modified_env({
'IPYTHON_DIR': None,
'IPYTHONDIR': None,
'XDG_CONFIG_HOME': XDG_TEST_DIR,
}), warnings.catch_warnings(record=True) as w:
ipdir = paths.get_ipython_dir()
nt.assert_equal(ipdir, os.path.join(HOME_TEST_DIR, ".ipython"))
if sys.platform != 'darwin':
nt.assert_equal(len(w), 1)
nt.assert_in('Ignoring', str(w[0]))
def test_get_ipython_dir_5():
"""test_get_ipython_dir_5, use .ipython if exists and XDG defined, but doesn't exist."""
with patch_get_home_dir(HOME_TEST_DIR), \
patch('os.name', 'posix'):
try:
os.rmdir(os.path.join(XDG_TEST_DIR, 'ipython'))
except OSError as e:
if e.errno != errno.ENOENT:
raise
with modified_env({
'IPYTHON_DIR': None,
'IPYTHONDIR': None,
'XDG_CONFIG_HOME': XDG_TEST_DIR,
}):
ipdir = paths.get_ipython_dir()
nt.assert_equal(ipdir, IP_TEST_DIR)
def test_get_ipython_dir_6():
"""test_get_ipython_dir_6, use home over XDG if defined and neither exist."""
xdg = os.path.join(HOME_TEST_DIR, 'somexdg')
os.mkdir(xdg)
shutil.rmtree(os.path.join(HOME_TEST_DIR, '.ipython'))
print(paths._writable_dir)
with patch_get_home_dir(HOME_TEST_DIR), \
patch.object(paths, 'get_xdg_dir', return_value=xdg), \
patch('os.name', 'posix'), \
modified_env({
'IPYTHON_DIR': None,
'IPYTHONDIR': None,
'XDG_CONFIG_HOME': None,
}), warnings.catch_warnings(record=True) as w:
ipdir = paths.get_ipython_dir()
nt.assert_equal(ipdir, os.path.join(HOME_TEST_DIR, '.ipython'))
nt.assert_equal(len(w), 0)
def test_get_ipython_dir_7():
"""test_get_ipython_dir_7, test home directory expansion on IPYTHONDIR"""
home_dir = os.path.normpath(os.path.expanduser('~'))
with modified_env({'IPYTHONDIR': os.path.join('~', 'somewhere')}), \
patch.object(paths, '_writable_dir', return_value=True):
ipdir = paths.get_ipython_dir()
nt.assert_equal(ipdir, os.path.join(home_dir, 'somewhere'))
@skip_win32
def test_get_ipython_dir_8():
"""test_get_ipython_dir_8, test / home directory"""
with patch.object(paths, '_writable_dir', lambda path: bool(path)), \
patch.object(paths, 'get_xdg_dir', return_value=None), \
modified_env({
'IPYTHON_DIR': None,
'IPYTHONDIR': None,
'HOME': '/',
}):
nt.assert_equal(paths.get_ipython_dir(), '/.ipython')
def test_get_ipython_cache_dir():
with modified_env({'HOME': HOME_TEST_DIR}):
if os.name == 'posix' and sys.platform != 'darwin':
# test default
os.makedirs(os.path.join(HOME_TEST_DIR, ".cache"))
with modified_env({'XDG_CACHE_HOME': None}):
ipdir = paths.get_ipython_cache_dir()
nt.assert_equal(os.path.join(HOME_TEST_DIR, ".cache", "ipython"),
ipdir)
assert_isdir(ipdir)
# test env override
with modified_env({"XDG_CACHE_HOME": XDG_CACHE_DIR}):
ipdir = paths.get_ipython_cache_dir()
assert_isdir(ipdir)
nt.assert_equal(ipdir, os.path.join(XDG_CACHE_DIR, "ipython"))
else:
nt.assert_equal(paths.get_ipython_cache_dir(),
paths.get_ipython_dir())
def test_get_ipython_package_dir():
ipdir = paths.get_ipython_package_dir()
assert_isdir(ipdir)
def test_get_ipython_module_path():
ipapp_path = paths.get_ipython_module_path('IPython.terminal.ipapp')
assert_isfile(ipapp_path)

View file

@ -0,0 +1,127 @@
"""Tests for input manipulation machinery."""
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
import nose.tools as nt
from IPython.core.prefilter import AutocallChecker
#-----------------------------------------------------------------------------
# Tests
#-----------------------------------------------------------------------------
def test_prefilter():
"""Test user input conversions"""
# pairs of (raw, expected correct) input
pairs = [ ('2+2','2+2'),
]
for raw, correct in pairs:
nt.assert_equal(ip.prefilter(raw), correct)
def test_prefilter_shadowed():
def dummy_magic(line): pass
prev_automagic_state = ip.automagic
ip.automagic = True
ip.autocall = 0
try:
# These should not be transformed - they are shadowed by other names
for name in ['if', 'zip', 'get_ipython']: # keyword, builtin, global
ip.register_magic_function(dummy_magic, magic_name=name)
res = ip.prefilter(name+' foo')
nt.assert_equal(res, name+' foo')
del ip.magics_manager.magics['line'][name]
# These should be transformed
for name in ['fi', 'piz', 'nohtypi_teg']:
ip.register_magic_function(dummy_magic, magic_name=name)
res = ip.prefilter(name+' foo')
nt.assert_not_equal(res, name+' foo')
del ip.magics_manager.magics['line'][name]
finally:
ip.automagic = prev_automagic_state
def test_autocall_binops():
"""See https://github.com/ipython/ipython/issues/81"""
ip.magic('autocall 2')
f = lambda x: x
ip.user_ns['f'] = f
try:
nt.assert_equal(ip.prefilter('f 1'),'f(1)')
for t in ['f +1', 'f -1']:
nt.assert_equal(ip.prefilter(t), t)
# Run tests again with a more permissive exclude_regexp, which will
# allow transformation of binary operations ('f -1' -> 'f(-1)').
pm = ip.prefilter_manager
ac = AutocallChecker(shell=pm.shell, prefilter_manager=pm,
config=pm.config)
try:
ac.priority = 1
ac.exclude_regexp = r'^[,&^\|\*/]|^is |^not |^in |^and |^or '
pm.sort_checkers()
nt.assert_equal(ip.prefilter('f -1'), 'f(-1)')
nt.assert_equal(ip.prefilter('f +1'), 'f(+1)')
finally:
pm.unregister_checker(ac)
finally:
ip.magic('autocall 0')
del ip.user_ns['f']
def test_issue_114():
"""Check that multiline string literals don't expand as magic
see http://github.com/ipython/ipython/issues/114"""
template = '"""\n%s\n"""'
# Store the current value of multi_line_specials and turn it off before
# running test, since it could be true (case in which the test doesn't make
# sense, as multiline string literals *will* expand as magic in that case).
msp = ip.prefilter_manager.multi_line_specials
ip.prefilter_manager.multi_line_specials = False
try:
for mgk in ip.magics_manager.lsmagic()['line']:
raw = template % mgk
nt.assert_equal(ip.prefilter(raw), raw)
finally:
ip.prefilter_manager.multi_line_specials = msp
def test_prefilter_attribute_errors():
"""Capture exceptions thrown by user objects on attribute access.
See http://github.com/ipython/ipython/issues/988."""
class X(object):
def __getattr__(self, k):
raise ValueError('broken object')
def __call__(self, x):
return x
# Create a callable broken object
ip.user_ns['x'] = X()
ip.magic('autocall 2')
try:
# Even if x throws an attribute error when looking at its rewrite
# attribute, we should not crash. So the test here is simply making
# the prefilter call and not having an exception.
ip.prefilter('x 1')
finally:
del ip.user_ns['x']
ip.magic('autocall 0')
def test_autocall_should_support_unicode():
ip.magic('autocall 2')
ip.user_ns['π'] = lambda x: x
try:
nt.assert_equal(ip.prefilter('π 3'),'π(3)')
finally:
ip.magic('autocall 0')
del ip.user_ns['π']

View file

@ -0,0 +1,161 @@
# coding: utf-8
"""Tests for profile-related functions.
Currently only the startup-dir functionality is tested, but more tests should
be added for:
* ipython profile create
* ipython profile list
* ipython profile create --parallel
* security dir permissions
Authors
-------
* MinRK
"""
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
import os
import shutil
import sys
import tempfile
from unittest import TestCase
import nose.tools as nt
from IPython.core.profileapp import list_profiles_in, list_bundled_profiles
from IPython.core.profiledir import ProfileDir
from IPython.testing import decorators as dec
from IPython.testing import tools as tt
from IPython.utils.process import getoutput
from IPython.utils.tempdir import TemporaryDirectory
#-----------------------------------------------------------------------------
# Globals
#-----------------------------------------------------------------------------
TMP_TEST_DIR = tempfile.mkdtemp()
HOME_TEST_DIR = os.path.join(TMP_TEST_DIR, "home_test_dir")
IP_TEST_DIR = os.path.join(HOME_TEST_DIR,'.ipython')
#
# Setup/teardown functions/decorators
#
def setup_module():
"""Setup test environment for the module:
- Adds dummy home dir tree
"""
# Do not mask exceptions here. In particular, catching WindowsError is a
# problem because that exception is only defined on Windows...
os.makedirs(IP_TEST_DIR)
def teardown_module():
"""Teardown test environment for the module:
- Remove dummy home dir tree
"""
# Note: we remove the parent test dir, which is the root of all test
# subdirs we may have created. Use shutil instead of os.removedirs, so
# that non-empty directories are all recursively removed.
shutil.rmtree(TMP_TEST_DIR)
#-----------------------------------------------------------------------------
# Test functions
#-----------------------------------------------------------------------------
def win32_without_pywin32():
if sys.platform == 'win32':
try:
import pywin32
except ImportError:
return True
return False
class ProfileStartupTest(TestCase):
def setUp(self):
# create profile dir
self.pd = ProfileDir.create_profile_dir_by_name(IP_TEST_DIR, 'test')
self.options = ['--ipython-dir', IP_TEST_DIR, '--profile', 'test']
self.fname = os.path.join(TMP_TEST_DIR, 'test.py')
def tearDown(self):
# We must remove this profile right away so its presence doesn't
# confuse other tests.
shutil.rmtree(self.pd.location)
def init(self, startup_file, startup, test):
# write startup python file
with open(os.path.join(self.pd.startup_dir, startup_file), 'w') as f:
f.write(startup)
# write simple test file, to check that the startup file was run
with open(self.fname, 'w') as f:
f.write(test)
def validate(self, output):
tt.ipexec_validate(self.fname, output, '', options=self.options)
@dec.skipif(win32_without_pywin32(), "Test requires pywin32 on Windows")
def test_startup_py(self):
self.init('00-start.py', 'zzz=123\n', 'print(zzz)\n')
self.validate('123')
@dec.skipif(win32_without_pywin32(), "Test requires pywin32 on Windows")
def test_startup_ipy(self):
self.init('00-start.ipy', '%xmode plain\n', '')
self.validate('Exception reporting mode: Plain')
def test_list_profiles_in():
# No need to remove these directories and files, as they will get nuked in
# the module-level teardown.
td = tempfile.mkdtemp(dir=TMP_TEST_DIR)
for name in ('profile_foo', 'profile_hello', 'not_a_profile'):
os.mkdir(os.path.join(td, name))
if dec.unicode_paths:
os.mkdir(os.path.join(td, u'profile_ünicode'))
with open(os.path.join(td, 'profile_file'), 'w') as f:
f.write("I am not a profile directory")
profiles = list_profiles_in(td)
# unicode normalization can turn u'ünicode' into u'u\0308nicode',
# so only check for *nicode, and that creating a ProfileDir from the
# name remains valid
found_unicode = False
for p in list(profiles):
if p.endswith('nicode'):
pd = ProfileDir.find_profile_dir_by_name(td, p)
profiles.remove(p)
found_unicode = True
break
if dec.unicode_paths:
nt.assert_true(found_unicode)
nt.assert_equal(set(profiles), {'foo', 'hello'})
def test_list_bundled_profiles():
# This variable will need to be updated when a new profile gets bundled
bundled = sorted(list_bundled_profiles())
nt.assert_equal(bundled, [])
def test_profile_create_ipython_dir():
"""ipython profile create respects --ipython-dir"""
with TemporaryDirectory() as td:
getoutput([sys.executable, '-m', 'IPython', 'profile', 'create',
'foo', '--ipython-dir=%s' % td])
profile_dir = os.path.join(td, 'profile_foo')
assert os.path.exists(profile_dir)
ipython_config = os.path.join(profile_dir, 'ipython_config.py')
assert os.path.exists(ipython_config)

View file

@ -0,0 +1,30 @@
# -*- coding: utf-8
"""Tests for prompt generation."""
import unittest
from IPython.core.prompts import LazyEvaluate
class PromptTests(unittest.TestCase):
def test_lazy_eval_unicode(self):
u = u'ünicødé'
lz = LazyEvaluate(lambda : u)
self.assertEqual(str(lz), u)
self.assertEqual(format(lz), u)
def test_lazy_eval_nonascii_bytes(self):
u = u'ünicødé'
b = u.encode('utf8')
lz = LazyEvaluate(lambda : b)
# unicode(lz) would fail
self.assertEqual(str(lz), str(b))
self.assertEqual(format(lz), str(b))
def test_lazy_eval_float(self):
f = 0.503
lz = LazyEvaluate(lambda : f)
self.assertEqual(str(lz), str(f))
self.assertEqual(format(lz), str(f))
self.assertEqual(format(lz, '.1'), '0.5')

View file

@ -0,0 +1,256 @@
"""Tests for pylab tools module.
"""
# Copyright (c) IPython Development Team.
# Distributed under the terms of the Modified BSD License.
from io import UnsupportedOperation, BytesIO
import matplotlib
matplotlib.use('Agg')
from matplotlib.figure import Figure
from nose import SkipTest
import nose.tools as nt
from matplotlib import pyplot as plt
import numpy as np
from IPython.core.getipython import get_ipython
from IPython.core.interactiveshell import InteractiveShell
from IPython.core.display import _PNG, _JPEG
from .. import pylabtools as pt
from IPython.testing import decorators as dec
def test_figure_to_svg():
# simple empty-figure test
fig = plt.figure()
nt.assert_equal(pt.print_figure(fig, 'svg'), None)
plt.close('all')
# simple check for at least svg-looking output
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.plot([1,2,3])
plt.draw()
svg = pt.print_figure(fig, 'svg')[:100].lower()
nt.assert_in(u'doctype svg', svg)
def _check_pil_jpeg_bytes():
"""Skip if PIL can't write JPEGs to BytesIO objects"""
# PIL's JPEG plugin can't write to BytesIO objects
# Pillow fixes this
from PIL import Image
buf = BytesIO()
img = Image.new("RGB", (4,4))
try:
img.save(buf, 'jpeg')
except Exception as e:
ename = e.__class__.__name__
raise SkipTest("PIL can't write JPEG to BytesIO: %s: %s" % (ename, e))
@dec.skip_without("PIL.Image")
def test_figure_to_jpeg():
_check_pil_jpeg_bytes()
# simple check for at least jpeg-looking output
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.plot([1,2,3])
plt.draw()
jpeg = pt.print_figure(fig, 'jpeg', pil_kwargs={'optimize': 50})[:100].lower()
assert jpeg.startswith(_JPEG)
def test_retina_figure():
# simple empty-figure test
fig = plt.figure()
nt.assert_equal(pt.retina_figure(fig), None)
plt.close('all')
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.plot([1,2,3])
plt.draw()
png, md = pt.retina_figure(fig)
assert png.startswith(_PNG)
nt.assert_in('width', md)
nt.assert_in('height', md)
_fmt_mime_map = {
'png': 'image/png',
'jpeg': 'image/jpeg',
'pdf': 'application/pdf',
'retina': 'image/png',
'svg': 'image/svg+xml',
}
def test_select_figure_formats_str():
ip = get_ipython()
for fmt, active_mime in _fmt_mime_map.items():
pt.select_figure_formats(ip, fmt)
for mime, f in ip.display_formatter.formatters.items():
if mime == active_mime:
nt.assert_in(Figure, f)
else:
nt.assert_not_in(Figure, f)
def test_select_figure_formats_kwargs():
ip = get_ipython()
kwargs = dict(quality=10, bbox_inches='tight')
pt.select_figure_formats(ip, 'png', **kwargs)
formatter = ip.display_formatter.formatters['image/png']
f = formatter.lookup_by_type(Figure)
cell = f.__closure__[0].cell_contents
nt.assert_equal(cell, kwargs)
# check that the formatter doesn't raise
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.plot([1,2,3])
plt.draw()
formatter.enabled = True
png = formatter(fig)
assert png.startswith(_PNG)
def test_select_figure_formats_set():
ip = get_ipython()
for fmts in [
{'png', 'svg'},
['png'],
('jpeg', 'pdf', 'retina'),
{'svg'},
]:
active_mimes = {_fmt_mime_map[fmt] for fmt in fmts}
pt.select_figure_formats(ip, fmts)
for mime, f in ip.display_formatter.formatters.items():
if mime in active_mimes:
nt.assert_in(Figure, f)
else:
nt.assert_not_in(Figure, f)
def test_select_figure_formats_bad():
ip = get_ipython()
with nt.assert_raises(ValueError):
pt.select_figure_formats(ip, 'foo')
with nt.assert_raises(ValueError):
pt.select_figure_formats(ip, {'png', 'foo'})
with nt.assert_raises(ValueError):
pt.select_figure_formats(ip, ['retina', 'pdf', 'bar', 'bad'])
def test_import_pylab():
ns = {}
pt.import_pylab(ns, import_all=False)
nt.assert_true('plt' in ns)
nt.assert_equal(ns['np'], np)
class TestPylabSwitch(object):
class Shell(InteractiveShell):
def enable_gui(self, gui):
pass
def setup(self):
import matplotlib
def act_mpl(backend):
matplotlib.rcParams['backend'] = backend
# Save rcParams since they get modified
self._saved_rcParams = matplotlib.rcParams
self._saved_rcParamsOrig = matplotlib.rcParamsOrig
matplotlib.rcParams = dict(backend='Qt4Agg')
matplotlib.rcParamsOrig = dict(backend='Qt4Agg')
# Mock out functions
self._save_am = pt.activate_matplotlib
pt.activate_matplotlib = act_mpl
self._save_ip = pt.import_pylab
pt.import_pylab = lambda *a,**kw:None
self._save_cis = pt.configure_inline_support
pt.configure_inline_support = lambda *a,**kw:None
def teardown(self):
pt.activate_matplotlib = self._save_am
pt.import_pylab = self._save_ip
pt.configure_inline_support = self._save_cis
import matplotlib
matplotlib.rcParams = self._saved_rcParams
matplotlib.rcParamsOrig = self._saved_rcParamsOrig
def test_qt(self):
s = self.Shell()
gui, backend = s.enable_matplotlib(None)
nt.assert_equal(gui, 'qt')
nt.assert_equal(s.pylab_gui_select, 'qt')
gui, backend = s.enable_matplotlib('inline')
nt.assert_equal(gui, 'inline')
nt.assert_equal(s.pylab_gui_select, 'qt')
gui, backend = s.enable_matplotlib('qt')
nt.assert_equal(gui, 'qt')
nt.assert_equal(s.pylab_gui_select, 'qt')
gui, backend = s.enable_matplotlib('inline')
nt.assert_equal(gui, 'inline')
nt.assert_equal(s.pylab_gui_select, 'qt')
gui, backend = s.enable_matplotlib()
nt.assert_equal(gui, 'qt')
nt.assert_equal(s.pylab_gui_select, 'qt')
def test_inline(self):
s = self.Shell()
gui, backend = s.enable_matplotlib('inline')
nt.assert_equal(gui, 'inline')
nt.assert_equal(s.pylab_gui_select, None)
gui, backend = s.enable_matplotlib('inline')
nt.assert_equal(gui, 'inline')
nt.assert_equal(s.pylab_gui_select, None)
gui, backend = s.enable_matplotlib('qt')
nt.assert_equal(gui, 'qt')
nt.assert_equal(s.pylab_gui_select, 'qt')
def test_inline_twice(self):
"Using '%matplotlib inline' twice should not reset formatters"
ip = self.Shell()
gui, backend = ip.enable_matplotlib('inline')
nt.assert_equal(gui, 'inline')
fmts = {'png'}
active_mimes = {_fmt_mime_map[fmt] for fmt in fmts}
pt.select_figure_formats(ip, fmts)
gui, backend = ip.enable_matplotlib('inline')
nt.assert_equal(gui, 'inline')
for mime, f in ip.display_formatter.formatters.items():
if mime in active_mimes:
nt.assert_in(Figure, f)
else:
nt.assert_not_in(Figure, f)
def test_qt_gtk(self):
s = self.Shell()
gui, backend = s.enable_matplotlib('qt')
nt.assert_equal(gui, 'qt')
nt.assert_equal(s.pylab_gui_select, 'qt')
gui, backend = s.enable_matplotlib('gtk')
nt.assert_equal(gui, 'qt')
nt.assert_equal(s.pylab_gui_select, 'qt')
def test_no_gui_backends():
for k in ['agg', 'svg', 'pdf', 'ps']:
assert k not in pt.backend2gui
def test_figure_no_canvas():
fig = Figure()
fig.canvas = None
pt.print_figure(fig)

View file

@ -0,0 +1,607 @@
# encoding: utf-8
"""Tests for code execution (%run and related), which is particularly tricky.
Because of how %run manages namespaces, and the fact that we are trying here to
verify subtle object deletion and reference counting issues, the %run tests
will be kept in this separate file. This makes it easier to aggregate in one
place the tricks needed to handle it; most other magics are much easier to test
and we do so in a common test_magic file.
Note that any test using `run -i` should make sure to do a `reset` afterwards,
as otherwise it may influence later tests.
"""
# Copyright (c) IPython Development Team.
# Distributed under the terms of the Modified BSD License.
import functools
import os
from os.path import join as pjoin
import random
import string
import sys
import textwrap
import unittest
from unittest.mock import patch
import nose.tools as nt
from nose import SkipTest
from IPython.testing import decorators as dec
from IPython.testing import tools as tt
from IPython.utils.io import capture_output
from IPython.utils.tempdir import TemporaryDirectory
from IPython.core import debugger
def doctest_refbug():
"""Very nasty problem with references held by multiple runs of a script.
See: https://github.com/ipython/ipython/issues/141
In [1]: _ip.clear_main_mod_cache()
# random
In [2]: %run refbug
In [3]: call_f()
lowercased: hello
In [4]: %run refbug
In [5]: call_f()
lowercased: hello
lowercased: hello
"""
def doctest_run_builtins():
r"""Check that %run doesn't damage __builtins__.
In [1]: import tempfile
In [2]: bid1 = id(__builtins__)
In [3]: fname = tempfile.mkstemp('.py')[1]
In [3]: f = open(fname,'w')
In [4]: dummy= f.write('pass\n')
In [5]: f.flush()
In [6]: t1 = type(__builtins__)
In [7]: %run $fname
In [7]: f.close()
In [8]: bid2 = id(__builtins__)
In [9]: t2 = type(__builtins__)
In [10]: t1 == t2
Out[10]: True
In [10]: bid1 == bid2
Out[10]: True
In [12]: try:
....: os.unlink(fname)
....: except:
....: pass
....:
"""
def doctest_run_option_parser():
r"""Test option parser in %run.
In [1]: %run print_argv.py
[]
In [2]: %run print_argv.py print*.py
['print_argv.py']
In [3]: %run -G print_argv.py print*.py
['print*.py']
"""
@dec.skip_win32
def doctest_run_option_parser_for_posix():
r"""Test option parser in %run (Linux/OSX specific).
You need double quote to escape glob in POSIX systems:
In [1]: %run print_argv.py print\\*.py
['print*.py']
You can't use quote to escape glob in POSIX systems:
In [2]: %run print_argv.py 'print*.py'
['print_argv.py']
"""
@dec.skip_if_not_win32
def doctest_run_option_parser_for_windows():
r"""Test option parser in %run (Windows specific).
In Windows, you can't escape ``*` `by backslash:
In [1]: %run print_argv.py print\\*.py
['print\\*.py']
You can use quote to escape glob:
In [2]: %run print_argv.py 'print*.py'
['print*.py']
"""
def doctest_reset_del():
"""Test that resetting doesn't cause errors in __del__ methods.
In [2]: class A(object):
...: def __del__(self):
...: print(str("Hi"))
...:
In [3]: a = A()
In [4]: get_ipython().reset()
Hi
In [5]: 1+1
Out[5]: 2
"""
# For some tests, it will be handy to organize them in a class with a common
# setup that makes a temp file
class TestMagicRunPass(tt.TempFileMixin):
def setUp(self):
content = "a = [1,2,3]\nb = 1"
self.mktmp(content)
def run_tmpfile(self):
_ip = get_ipython()
# This fails on Windows if self.tmpfile.name has spaces or "~" in it.
# See below and ticket https://bugs.launchpad.net/bugs/366353
_ip.magic('run %s' % self.fname)
def run_tmpfile_p(self):
_ip = get_ipython()
# This fails on Windows if self.tmpfile.name has spaces or "~" in it.
# See below and ticket https://bugs.launchpad.net/bugs/366353
_ip.magic('run -p %s' % self.fname)
def test_builtins_id(self):
"""Check that %run doesn't damage __builtins__ """
_ip = get_ipython()
# Test that the id of __builtins__ is not modified by %run
bid1 = id(_ip.user_ns['__builtins__'])
self.run_tmpfile()
bid2 = id(_ip.user_ns['__builtins__'])
nt.assert_equal(bid1, bid2)
def test_builtins_type(self):
"""Check that the type of __builtins__ doesn't change with %run.
However, the above could pass if __builtins__ was already modified to
be a dict (it should be a module) by a previous use of %run. So we
also check explicitly that it really is a module:
"""
_ip = get_ipython()
self.run_tmpfile()
nt.assert_equal(type(_ip.user_ns['__builtins__']),type(sys))
def test_run_profile( self ):
"""Test that the option -p, which invokes the profiler, do not
crash by invoking execfile"""
self.run_tmpfile_p()
def test_run_debug_twice(self):
# https://github.com/ipython/ipython/issues/10028
_ip = get_ipython()
with tt.fake_input(['c']):
_ip.magic('run -d %s' % self.fname)
with tt.fake_input(['c']):
_ip.magic('run -d %s' % self.fname)
def test_run_debug_twice_with_breakpoint(self):
"""Make a valid python temp file."""
_ip = get_ipython()
with tt.fake_input(['b 2', 'c', 'c']):
_ip.magic('run -d %s' % self.fname)
with tt.fake_input(['c']):
with tt.AssertNotPrints('KeyError'):
_ip.magic('run -d %s' % self.fname)
class TestMagicRunSimple(tt.TempFileMixin):
def test_simpledef(self):
"""Test that simple class definitions work."""
src = ("class foo: pass\n"
"def f(): return foo()")
self.mktmp(src)
_ip.magic('run %s' % self.fname)
_ip.run_cell('t = isinstance(f(), foo)')
nt.assert_true(_ip.user_ns['t'])
def test_obj_del(self):
"""Test that object's __del__ methods are called on exit."""
if sys.platform == 'win32':
try:
import win32api
except ImportError:
raise SkipTest("Test requires pywin32")
src = ("class A(object):\n"
" def __del__(self):\n"
" print('object A deleted')\n"
"a = A()\n")
self.mktmp(src)
if dec.module_not_available('sqlite3'):
err = 'WARNING: IPython History requires SQLite, your history will not be saved\n'
else:
err = None
tt.ipexec_validate(self.fname, 'object A deleted', err)
def test_aggressive_namespace_cleanup(self):
"""Test that namespace cleanup is not too aggressive GH-238
Returning from another run magic deletes the namespace"""
# see ticket https://github.com/ipython/ipython/issues/238
with tt.TempFileMixin() as empty:
empty.mktmp('')
# On Windows, the filename will have \users in it, so we need to use the
# repr so that the \u becomes \\u.
src = ("ip = get_ipython()\n"
"for i in range(5):\n"
" try:\n"
" ip.magic(%r)\n"
" except NameError as e:\n"
" print(i)\n"
" break\n" % ('run ' + empty.fname))
self.mktmp(src)
_ip.magic('run %s' % self.fname)
_ip.run_cell('ip == get_ipython()')
nt.assert_equal(_ip.user_ns['i'], 4)
def test_run_second(self):
"""Test that running a second file doesn't clobber the first, gh-3547
"""
self.mktmp("avar = 1\n"
"def afunc():\n"
" return avar\n")
with tt.TempFileMixin() as empty:
empty.mktmp("")
_ip.magic('run %s' % self.fname)
_ip.magic('run %s' % empty.fname)
nt.assert_equal(_ip.user_ns['afunc'](), 1)
@dec.skip_win32
def test_tclass(self):
mydir = os.path.dirname(__file__)
tc = os.path.join(mydir, 'tclass')
src = ("%%run '%s' C-first\n"
"%%run '%s' C-second\n"
"%%run '%s' C-third\n") % (tc, tc, tc)
self.mktmp(src, '.ipy')
out = """\
ARGV 1-: ['C-first']
ARGV 1-: ['C-second']
tclass.py: deleting object: C-first
ARGV 1-: ['C-third']
tclass.py: deleting object: C-second
tclass.py: deleting object: C-third
"""
if dec.module_not_available('sqlite3'):
err = 'WARNING: IPython History requires SQLite, your history will not be saved\n'
else:
err = None
tt.ipexec_validate(self.fname, out, err)
def test_run_i_after_reset(self):
"""Check that %run -i still works after %reset (gh-693)"""
src = "yy = zz\n"
self.mktmp(src)
_ip.run_cell("zz = 23")
try:
_ip.magic('run -i %s' % self.fname)
nt.assert_equal(_ip.user_ns['yy'], 23)
finally:
_ip.magic('reset -f')
_ip.run_cell("zz = 23")
try:
_ip.magic('run -i %s' % self.fname)
nt.assert_equal(_ip.user_ns['yy'], 23)
finally:
_ip.magic('reset -f')
def test_unicode(self):
"""Check that files in odd encodings are accepted."""
mydir = os.path.dirname(__file__)
na = os.path.join(mydir, 'nonascii.py')
_ip.magic('run "%s"' % na)
nt.assert_equal(_ip.user_ns['u'], u'Ўт№Ф')
def test_run_py_file_attribute(self):
"""Test handling of `__file__` attribute in `%run <file>.py`."""
src = "t = __file__\n"
self.mktmp(src)
_missing = object()
file1 = _ip.user_ns.get('__file__', _missing)
_ip.magic('run %s' % self.fname)
file2 = _ip.user_ns.get('__file__', _missing)
# Check that __file__ was equal to the filename in the script's
# namespace.
nt.assert_equal(_ip.user_ns['t'], self.fname)
# Check that __file__ was not leaked back into user_ns.
nt.assert_equal(file1, file2)
def test_run_ipy_file_attribute(self):
"""Test handling of `__file__` attribute in `%run <file.ipy>`."""
src = "t = __file__\n"
self.mktmp(src, ext='.ipy')
_missing = object()
file1 = _ip.user_ns.get('__file__', _missing)
_ip.magic('run %s' % self.fname)
file2 = _ip.user_ns.get('__file__', _missing)
# Check that __file__ was equal to the filename in the script's
# namespace.
nt.assert_equal(_ip.user_ns['t'], self.fname)
# Check that __file__ was not leaked back into user_ns.
nt.assert_equal(file1, file2)
def test_run_formatting(self):
""" Test that %run -t -N<N> does not raise a TypeError for N > 1."""
src = "pass"
self.mktmp(src)
_ip.magic('run -t -N 1 %s' % self.fname)
_ip.magic('run -t -N 10 %s' % self.fname)
def test_ignore_sys_exit(self):
"""Test the -e option to ignore sys.exit()"""
src = "import sys; sys.exit(1)"
self.mktmp(src)
with tt.AssertPrints('SystemExit'):
_ip.magic('run %s' % self.fname)
with tt.AssertNotPrints('SystemExit'):
_ip.magic('run -e %s' % self.fname)
def test_run_nb(self):
"""Test %run notebook.ipynb"""
from nbformat import v4, writes
nb = v4.new_notebook(
cells=[
v4.new_markdown_cell("The Ultimate Question of Everything"),
v4.new_code_cell("answer=42")
]
)
src = writes(nb, version=4)
self.mktmp(src, ext='.ipynb')
_ip.magic("run %s" % self.fname)
nt.assert_equal(_ip.user_ns['answer'], 42)
def test_run_nb_error(self):
"""Test %run notebook.ipynb error"""
from nbformat import v4, writes
# %run when a file name isn't provided
nt.assert_raises(Exception, _ip.magic, "run")
# %run when a file doesn't exist
nt.assert_raises(Exception, _ip.magic, "run foobar.ipynb")
# %run on a notebook with an error
nb = v4.new_notebook(
cells=[
v4.new_code_cell("0/0")
]
)
src = writes(nb, version=4)
self.mktmp(src, ext='.ipynb')
nt.assert_raises(Exception, _ip.magic, "run %s" % self.fname)
def test_file_options(self):
src = ('import sys\n'
'a = " ".join(sys.argv[1:])\n')
self.mktmp(src)
test_opts = '-x 3 --verbose'
_ip.run_line_magic("run", '{0} {1}'.format(self.fname, test_opts))
nt.assert_equal(_ip.user_ns['a'], test_opts)
class TestMagicRunWithPackage(unittest.TestCase):
def writefile(self, name, content):
path = os.path.join(self.tempdir.name, name)
d = os.path.dirname(path)
if not os.path.isdir(d):
os.makedirs(d)
with open(path, 'w') as f:
f.write(textwrap.dedent(content))
def setUp(self):
self.package = package = 'tmp{0}'.format(''.join([random.choice(string.ascii_letters) for i in range(10)]))
"""Temporary (probably) valid python package name."""
self.value = int(random.random() * 10000)
self.tempdir = TemporaryDirectory()
self.__orig_cwd = os.getcwd()
sys.path.insert(0, self.tempdir.name)
self.writefile(os.path.join(package, '__init__.py'), '')
self.writefile(os.path.join(package, 'sub.py'), """
x = {0!r}
""".format(self.value))
self.writefile(os.path.join(package, 'relative.py'), """
from .sub import x
""")
self.writefile(os.path.join(package, 'absolute.py'), """
from {0}.sub import x
""".format(package))
self.writefile(os.path.join(package, 'args.py'), """
import sys
a = " ".join(sys.argv[1:])
""".format(package))
def tearDown(self):
os.chdir(self.__orig_cwd)
sys.path[:] = [p for p in sys.path if p != self.tempdir.name]
self.tempdir.cleanup()
def check_run_submodule(self, submodule, opts=''):
_ip.user_ns.pop('x', None)
_ip.magic('run {2} -m {0}.{1}'.format(self.package, submodule, opts))
self.assertEqual(_ip.user_ns['x'], self.value,
'Variable `x` is not loaded from module `{0}`.'
.format(submodule))
def test_run_submodule_with_absolute_import(self):
self.check_run_submodule('absolute')
def test_run_submodule_with_relative_import(self):
"""Run submodule that has a relative import statement (#2727)."""
self.check_run_submodule('relative')
def test_prun_submodule_with_absolute_import(self):
self.check_run_submodule('absolute', '-p')
def test_prun_submodule_with_relative_import(self):
self.check_run_submodule('relative', '-p')
def with_fake_debugger(func):
@functools.wraps(func)
def wrapper(*args, **kwds):
with patch.object(debugger.Pdb, 'run', staticmethod(eval)):
return func(*args, **kwds)
return wrapper
@with_fake_debugger
def test_debug_run_submodule_with_absolute_import(self):
self.check_run_submodule('absolute', '-d')
@with_fake_debugger
def test_debug_run_submodule_with_relative_import(self):
self.check_run_submodule('relative', '-d')
def test_module_options(self):
_ip.user_ns.pop('a', None)
test_opts = '-x abc -m test'
_ip.run_line_magic('run', '-m {0}.args {1}'.format(self.package, test_opts))
nt.assert_equal(_ip.user_ns['a'], test_opts)
def test_module_options_with_separator(self):
_ip.user_ns.pop('a', None)
test_opts = '-x abc -m test'
_ip.run_line_magic('run', '-m {0}.args -- {1}'.format(self.package, test_opts))
nt.assert_equal(_ip.user_ns['a'], test_opts)
def test_run__name__():
with TemporaryDirectory() as td:
path = pjoin(td, 'foo.py')
with open(path, 'w') as f:
f.write("q = __name__")
_ip.user_ns.pop('q', None)
_ip.magic('run {}'.format(path))
nt.assert_equal(_ip.user_ns.pop('q'), '__main__')
_ip.magic('run -n {}'.format(path))
nt.assert_equal(_ip.user_ns.pop('q'), 'foo')
try:
_ip.magic('run -i -n {}'.format(path))
nt.assert_equal(_ip.user_ns.pop('q'), 'foo')
finally:
_ip.magic('reset -f')
def test_run_tb():
"""Test traceback offset in %run"""
with TemporaryDirectory() as td:
path = pjoin(td, 'foo.py')
with open(path, 'w') as f:
f.write('\n'.join([
"def foo():",
" return bar()",
"def bar():",
" raise RuntimeError('hello!')",
"foo()",
]))
with capture_output() as io:
_ip.magic('run {}'.format(path))
out = io.stdout
nt.assert_not_in("execfile", out)
nt.assert_in("RuntimeError", out)
nt.assert_equal(out.count("---->"), 3)
del ip.user_ns['bar']
del ip.user_ns['foo']
def test_multiprocessing_run():
"""Set we can run mutiprocesgin without messing up up main namespace
Note that import `nose.tools as nt` mdify the value s
sys.module['__mp_main__'] so wee need to temporarily set it to None to test
the issue.
"""
with TemporaryDirectory() as td:
mpm = sys.modules.get('__mp_main__')
assert mpm is not None
sys.modules['__mp_main__'] = None
try:
path = pjoin(td, 'test.py')
with open(path, 'w') as f:
f.write("import multiprocessing\nprint('hoy')")
with capture_output() as io:
_ip.run_line_magic('run', path)
_ip.run_cell("i_m_undefined")
out = io.stdout
nt.assert_in("hoy", out)
nt.assert_not_in("AttributeError", out)
nt.assert_in("NameError", out)
nt.assert_equal(out.count("---->"), 1)
except:
raise
finally:
sys.modules['__mp_main__'] = mpm
@dec.knownfailureif(sys.platform == 'win32', "writes to io.stdout aren't captured on Windows")
def test_script_tb():
"""Test traceback offset in `ipython script.py`"""
with TemporaryDirectory() as td:
path = pjoin(td, 'foo.py')
with open(path, 'w') as f:
f.write('\n'.join([
"def foo():",
" return bar()",
"def bar():",
" raise RuntimeError('hello!')",
"foo()",
]))
out, err = tt.ipexec(path)
nt.assert_not_in("execfile", out)
nt.assert_in("RuntimeError", out)
nt.assert_equal(out.count("---->"), 3)

View file

@ -0,0 +1,60 @@
# -*- coding: utf-8 -*-
"""Tests for shellapp module.
Authors
-------
* Bradley Froehle
"""
#-----------------------------------------------------------------------------
# Copyright (C) 2012 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
#-----------------------------------------------------------------------------
import unittest
from IPython.testing import decorators as dec
from IPython.testing import tools as tt
sqlite_err_maybe = dec.module_not_available('sqlite3')
SQLITE_NOT_AVAILABLE_ERROR = ('WARNING: IPython History requires SQLite,'
' your history will not be saved\n')
class TestFileToRun(tt.TempFileMixin, unittest.TestCase):
"""Test the behavior of the file_to_run parameter."""
def test_py_script_file_attribute(self):
"""Test that `__file__` is set when running `ipython file.py`"""
src = "print(__file__)\n"
self.mktmp(src)
err = SQLITE_NOT_AVAILABLE_ERROR if sqlite_err_maybe else None
tt.ipexec_validate(self.fname, self.fname, err)
def test_ipy_script_file_attribute(self):
"""Test that `__file__` is set when running `ipython file.ipy`"""
src = "print(__file__)\n"
self.mktmp(src, ext='.ipy')
err = SQLITE_NOT_AVAILABLE_ERROR if sqlite_err_maybe else None
tt.ipexec_validate(self.fname, self.fname, err)
# The commands option to ipexec_validate doesn't work on Windows, and it
# doesn't seem worth fixing
@dec.skip_win32
def test_py_script_file_attribute_interactively(self):
"""Test that `__file__` is not set after `ipython -i file.py`"""
src = "True\n"
self.mktmp(src)
out, err = tt.ipexec(self.fname, options=['-i'],
commands=['"__file__" in globals()', 'print(123)', 'exit()'])
if 'False' not in out:
print("Subprocess stderr:")
print(err)
print('-----')
raise AssertionError("'False' not found in %r" % out)

View file

@ -0,0 +1,38 @@
# coding: utf-8
import nose.tools as nt
from IPython.core.splitinput import split_user_input, LineInfo
from IPython.testing import tools as tt
tests = [
('x=1', ('', '', 'x', '=1')),
('?', ('', '?', '', '')),
('??', ('', '??', '', '')),
(' ?', (' ', '?', '', '')),
(' ??', (' ', '??', '', '')),
('??x', ('', '??', 'x', '')),
('?x=1', ('', '?', 'x', '=1')),
('!ls', ('', '!', 'ls', '')),
(' !ls', (' ', '!', 'ls', '')),
('!!ls', ('', '!!', 'ls', '')),
(' !!ls', (' ', '!!', 'ls', '')),
(',ls', ('', ',', 'ls', '')),
(';ls', ('', ';', 'ls', '')),
(' ;ls', (' ', ';', 'ls', '')),
('f.g(x)', ('', '', 'f.g', '(x)')),
('f.g (x)', ('', '', 'f.g', '(x)')),
('?%hist1', ('', '?', '%hist1', '')),
('?%%hist2', ('', '?', '%%hist2', '')),
('??%hist3', ('', '??', '%hist3', '')),
('??%%hist4', ('', '??', '%%hist4', '')),
('?x*', ('', '?', 'x*', '')),
]
tests.append((u"Pérez Fernando", (u'', u'', u'Pérez', u'Fernando')))
def test_split_user_input():
return tt.check_pairs(split_user_input, tests)
def test_LineInfo():
"""Simple test for LineInfo construction and str()"""
linfo = LineInfo(' %cd /home')
nt.assert_equal(str(linfo), 'LineInfo [ |%|cd|/home]')

View file

@ -0,0 +1,470 @@
# encoding: utf-8
"""Tests for IPython.core.ultratb
"""
import io
import logging
import sys
import os.path
from textwrap import dedent
import traceback
import unittest
from unittest import mock
import IPython.core.ultratb as ultratb
from IPython.core.ultratb import ColorTB, VerboseTB, find_recursion
from IPython.testing import tools as tt
from IPython.testing.decorators import onlyif_unicode_paths
from IPython.utils.syspathcontext import prepended_to_syspath
from IPython.utils.tempdir import TemporaryDirectory
file_1 = """1
2
3
def f():
1/0
"""
file_2 = """def f():
1/0
"""
def recursionlimit(frames):
"""
decorator to set the recursion limit temporarily
"""
def inner(test_function):
def wrapper(*args, **kwargs):
_orig_rec_limit = ultratb._FRAME_RECURSION_LIMIT
ultratb._FRAME_RECURSION_LIMIT = 50
rl = sys.getrecursionlimit()
sys.setrecursionlimit(frames)
try:
return test_function(*args, **kwargs)
finally:
sys.setrecursionlimit(rl)
ultratb._FRAME_RECURSION_LIMIT = _orig_rec_limit
return wrapper
return inner
class ChangedPyFileTest(unittest.TestCase):
def test_changing_py_file(self):
"""Traceback produced if the line where the error occurred is missing?
https://github.com/ipython/ipython/issues/1456
"""
with TemporaryDirectory() as td:
fname = os.path.join(td, "foo.py")
with open(fname, "w") as f:
f.write(file_1)
with prepended_to_syspath(td):
ip.run_cell("import foo")
with tt.AssertPrints("ZeroDivisionError"):
ip.run_cell("foo.f()")
# Make the file shorter, so the line of the error is missing.
with open(fname, "w") as f:
f.write(file_2)
# For some reason, this was failing on the *second* call after
# changing the file, so we call f() twice.
with tt.AssertNotPrints("Internal Python error", channel='stderr'):
with tt.AssertPrints("ZeroDivisionError"):
ip.run_cell("foo.f()")
with tt.AssertPrints("ZeroDivisionError"):
ip.run_cell("foo.f()")
iso_8859_5_file = u'''# coding: iso-8859-5
def fail():
"""дбИЖ"""
1/0 # дбИЖ
'''
class NonAsciiTest(unittest.TestCase):
@onlyif_unicode_paths
def test_nonascii_path(self):
# Non-ascii directory name as well.
with TemporaryDirectory(suffix=u'é') as td:
fname = os.path.join(td, u"fooé.py")
with open(fname, "w") as f:
f.write(file_1)
with prepended_to_syspath(td):
ip.run_cell("import foo")
with tt.AssertPrints("ZeroDivisionError"):
ip.run_cell("foo.f()")
def test_iso8859_5(self):
with TemporaryDirectory() as td:
fname = os.path.join(td, 'dfghjkl.py')
with io.open(fname, 'w', encoding='iso-8859-5') as f:
f.write(iso_8859_5_file)
with prepended_to_syspath(td):
ip.run_cell("from dfghjkl import fail")
with tt.AssertPrints("ZeroDivisionError"):
with tt.AssertPrints(u'дбИЖ', suppress=False):
ip.run_cell('fail()')
def test_nonascii_msg(self):
cell = u"raise Exception('é')"
expected = u"Exception('é')"
ip.run_cell("%xmode plain")
with tt.AssertPrints(expected):
ip.run_cell(cell)
ip.run_cell("%xmode verbose")
with tt.AssertPrints(expected):
ip.run_cell(cell)
ip.run_cell("%xmode context")
with tt.AssertPrints(expected):
ip.run_cell(cell)
ip.run_cell("%xmode minimal")
with tt.AssertPrints(u"Exception: é"):
ip.run_cell(cell)
# Put this back into Context mode for later tests.
ip.run_cell("%xmode context")
class NestedGenExprTestCase(unittest.TestCase):
"""
Regression test for the following issues:
https://github.com/ipython/ipython/issues/8293
https://github.com/ipython/ipython/issues/8205
"""
def test_nested_genexpr(self):
code = dedent(
"""\
class SpecificException(Exception):
pass
def foo(x):
raise SpecificException("Success!")
sum(sum(foo(x) for _ in [0]) for x in [0])
"""
)
with tt.AssertPrints('SpecificException: Success!', suppress=False):
ip.run_cell(code)
indentationerror_file = """if True:
zoon()
"""
class IndentationErrorTest(unittest.TestCase):
def test_indentationerror_shows_line(self):
# See issue gh-2398
with tt.AssertPrints("IndentationError"):
with tt.AssertPrints("zoon()", suppress=False):
ip.run_cell(indentationerror_file)
with TemporaryDirectory() as td:
fname = os.path.join(td, "foo.py")
with open(fname, "w") as f:
f.write(indentationerror_file)
with tt.AssertPrints("IndentationError"):
with tt.AssertPrints("zoon()", suppress=False):
ip.magic('run %s' % fname)
se_file_1 = """1
2
7/
"""
se_file_2 = """7/
"""
class SyntaxErrorTest(unittest.TestCase):
def test_syntaxerror_without_lineno(self):
with tt.AssertNotPrints("TypeError"):
with tt.AssertPrints("line unknown"):
ip.run_cell("raise SyntaxError()")
def test_syntaxerror_no_stacktrace_at_compile_time(self):
syntax_error_at_compile_time = """
def foo():
..
"""
with tt.AssertPrints("SyntaxError"):
ip.run_cell(syntax_error_at_compile_time)
with tt.AssertNotPrints("foo()"):
ip.run_cell(syntax_error_at_compile_time)
def test_syntaxerror_stacktrace_when_running_compiled_code(self):
syntax_error_at_runtime = """
def foo():
eval("..")
def bar():
foo()
bar()
"""
with tt.AssertPrints("SyntaxError"):
ip.run_cell(syntax_error_at_runtime)
# Assert syntax error during runtime generate stacktrace
with tt.AssertPrints(["foo()", "bar()"]):
ip.run_cell(syntax_error_at_runtime)
del ip.user_ns['bar']
del ip.user_ns['foo']
def test_changing_py_file(self):
with TemporaryDirectory() as td:
fname = os.path.join(td, "foo.py")
with open(fname, 'w') as f:
f.write(se_file_1)
with tt.AssertPrints(["7/", "SyntaxError"]):
ip.magic("run " + fname)
# Modify the file
with open(fname, 'w') as f:
f.write(se_file_2)
# The SyntaxError should point to the correct line
with tt.AssertPrints(["7/", "SyntaxError"]):
ip.magic("run " + fname)
def test_non_syntaxerror(self):
# SyntaxTB may be called with an error other than a SyntaxError
# See e.g. gh-4361
try:
raise ValueError('QWERTY')
except ValueError:
with tt.AssertPrints('QWERTY'):
ip.showsyntaxerror()
import sys
if sys.version_info < (3,9):
"""
New 3.9 Pgen Parser does not raise Memory error, except on failed malloc.
"""
class MemoryErrorTest(unittest.TestCase):
def test_memoryerror(self):
memoryerror_code = "(" * 200 + ")" * 200
with tt.AssertPrints("MemoryError"):
ip.run_cell(memoryerror_code)
class Python3ChainedExceptionsTest(unittest.TestCase):
DIRECT_CAUSE_ERROR_CODE = """
try:
x = 1 + 2
print(not_defined_here)
except Exception as e:
x += 55
x - 1
y = {}
raise KeyError('uh') from e
"""
EXCEPTION_DURING_HANDLING_CODE = """
try:
x = 1 + 2
print(not_defined_here)
except Exception as e:
x += 55
x - 1
y = {}
raise KeyError('uh')
"""
SUPPRESS_CHAINING_CODE = """
try:
1/0
except Exception:
raise ValueError("Yikes") from None
"""
def test_direct_cause_error(self):
with tt.AssertPrints(["KeyError", "NameError", "direct cause"]):
ip.run_cell(self.DIRECT_CAUSE_ERROR_CODE)
def test_exception_during_handling_error(self):
with tt.AssertPrints(["KeyError", "NameError", "During handling"]):
ip.run_cell(self.EXCEPTION_DURING_HANDLING_CODE)
def test_suppress_exception_chaining(self):
with tt.AssertNotPrints("ZeroDivisionError"), \
tt.AssertPrints("ValueError", suppress=False):
ip.run_cell(self.SUPPRESS_CHAINING_CODE)
def test_plain_direct_cause_error(self):
with tt.AssertPrints(["KeyError", "NameError", "direct cause"]):
ip.run_cell("%xmode Plain")
ip.run_cell(self.DIRECT_CAUSE_ERROR_CODE)
ip.run_cell("%xmode Verbose")
def test_plain_exception_during_handling_error(self):
with tt.AssertPrints(["KeyError", "NameError", "During handling"]):
ip.run_cell("%xmode Plain")
ip.run_cell(self.EXCEPTION_DURING_HANDLING_CODE)
ip.run_cell("%xmode Verbose")
def test_plain_suppress_exception_chaining(self):
with tt.AssertNotPrints("ZeroDivisionError"), \
tt.AssertPrints("ValueError", suppress=False):
ip.run_cell("%xmode Plain")
ip.run_cell(self.SUPPRESS_CHAINING_CODE)
ip.run_cell("%xmode Verbose")
class RecursionTest(unittest.TestCase):
DEFINITIONS = """
def non_recurs():
1/0
def r1():
r1()
def r3a():
r3b()
def r3b():
r3c()
def r3c():
r3a()
def r3o1():
r3a()
def r3o2():
r3o1()
"""
def setUp(self):
ip.run_cell(self.DEFINITIONS)
def test_no_recursion(self):
with tt.AssertNotPrints("frames repeated"):
ip.run_cell("non_recurs()")
@recursionlimit(150)
def test_recursion_one_frame(self):
with tt.AssertPrints("1 frames repeated"):
ip.run_cell("r1()")
@recursionlimit(150)
def test_recursion_three_frames(self):
with tt.AssertPrints("3 frames repeated"):
ip.run_cell("r3o2()")
@recursionlimit(150)
def test_find_recursion(self):
captured = []
def capture_exc(*args, **kwargs):
captured.append(sys.exc_info())
with mock.patch.object(ip, 'showtraceback', capture_exc):
ip.run_cell("r3o2()")
self.assertEqual(len(captured), 1)
etype, evalue, tb = captured[0]
self.assertIn("recursion", str(evalue))
records = ip.InteractiveTB.get_records(tb, 3, ip.InteractiveTB.tb_offset)
for r in records[:10]:
print(r[1:4])
# The outermost frames should be:
# 0: the 'cell' that was running when the exception came up
# 1: r3o2()
# 2: r3o1()
# 3: r3a()
# Then repeating r3b, r3c, r3a
last_unique, repeat_length = find_recursion(etype, evalue, records)
self.assertEqual(last_unique, 2)
self.assertEqual(repeat_length, 3)
#----------------------------------------------------------------------------
# module testing (minimal)
def test_handlers():
def spam(c, d_e):
(d, e) = d_e
x = c + d
y = c * d
foo(x, y)
def foo(a, b, bar=1):
eggs(a, b + bar)
def eggs(f, g, z=globals()):
h = f + g
i = f - g
return h / i
buff = io.StringIO()
buff.write('')
buff.write('*** Before ***')
try:
buff.write(spam(1, (2, 3)))
except:
traceback.print_exc(file=buff)
handler = ColorTB(ostream=buff)
buff.write('*** ColorTB ***')
try:
buff.write(spam(1, (2, 3)))
except:
handler(*sys.exc_info())
buff.write('')
handler = VerboseTB(ostream=buff)
buff.write('*** VerboseTB ***')
try:
buff.write(spam(1, (2, 3)))
except:
handler(*sys.exc_info())
buff.write('')
from IPython.testing.decorators import skipif
class TokenizeFailureTest(unittest.TestCase):
"""Tests related to https://github.com/ipython/ipython/issues/6864."""
# that appear to test that we are handling an exception that can be thrown
# by the tokenizer due to a bug that seem to have been fixed in 3.8, though
# I'm unsure if other sequences can make it raise this error. Let's just
# skip in 3.8 for now
@skipif(sys.version_info > (3,8))
def testLogging(self):
message = "An unexpected error occurred while tokenizing input"
cell = 'raise ValueError("""a\nb""")'
stream = io.StringIO()
handler = logging.StreamHandler(stream)
logger = logging.getLogger()
loglevel = logger.level
logger.addHandler(handler)
self.addCleanup(lambda: logger.removeHandler(handler))
self.addCleanup(lambda: logger.setLevel(loglevel))
logger.setLevel(logging.INFO)
with tt.AssertNotPrints(message):
ip.run_cell(cell)
self.assertNotIn(message, stream.getvalue())
logger.setLevel(logging.DEBUG)
with tt.AssertNotPrints(message):
ip.run_cell(cell)
self.assertIn(message, stream.getvalue())