first commit

This commit is contained in:
Ayxan
2022-05-23 00:16:32 +04:00
commit d660f2a4ca
24786 changed files with 4428337 additions and 0 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.)
# <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <- Cyrillic characters
u = '<EFBFBD><EFBFBD><EFBFBD><EFBFBD>'

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,33 @@
"""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, f"Mode = {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,66 @@
from IPython.utils.capture import capture_output
import pytest
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)
assert am.retrieve_alias(name) == cmd
assert (name, cmd) in 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]
assert result == [cmd]
finally:
_ip.system = orig_system
# Test removing the alias
am.undefine_alias(name)
assert not am.is_alias(name)
with pytest.raises(ValueError):
am.retrieve_alias(name)
assert (name, cmd) not in 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')
assert cap.stderr.split(":")[0] == "UsageError"
def test_alias_args_commented():
"""Check that alias correctly ignores 'commented out' args"""
_ip.run_line_magic("alias", "commentarg echo this is %%s a commented out arg")
with capture_output() as cap:
_ip.run_cell("commentarg")
# strip() is for pytest compat; testing via iptest patch IPython shell
# in testing.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)
assert thealias.nargs == 1

View File

@ -0,0 +1,70 @@
# coding: utf-8
"""Tests for IPython.core.application"""
import os
import tempfile
from tempfile import TemporaryDirectory
from traitlets import Unicode
from IPython.core.application import BaseIPythonApplication
from IPython.testing import decorators as dec
@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", encoding="utf-8") 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", encoding="utf-8") as f:
f.write("c.TestApp.test = 'config file'")
app = TestApp()
app.initialize(["--profile-dir", td])
assert app.test == "config file"
app = TestApp()
app.initialize(["--profile-dir", td, "--TestApp.test=cli"])
assert 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.
"""
import platform
from itertools import chain, repeat
from textwrap import dedent, indent
from unittest import TestCase
from IPython.testing.decorators import skip_without
import sys
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from IPython import get_ipython
ip = get_ipython()
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):
self.assertFalse(_should_be_async("False"))
self.assertTrue(_should_be_async("await bar()"))
self.assertTrue(_should_be_async("x = await bar()"))
self.assertFalse(
_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))')
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 in vals:
test_id = (context_name, test_name, val)
cell = nested_case.format(val=val)
with self.subTest(test_id):
if 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) and platform.python_implementation() != "PyPy":
# 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 self.assertRaises(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 self.assertRaises(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,71 @@
# 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 pytest
# Our own imports
from IPython.core import compilerop
#-----------------------------------------------------------------------------
# Test functions
#-----------------------------------------------------------------------------
def test_code_name():
code = 'x=1'
name = compilerop.code_name(code)
assert name.startswith("<ipython-input-0")
def test_code_name2():
code = 'x=1'
name = compilerop.code_name(code, 9)
assert 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')
assert 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.)
assert sys.getdefaultencoding() == "utf-8"
def test_cache_unicode():
cp = compilerop.CachingCompiler()
ncache = len(linecache.cache)
cp.cache(u"t = 'žćčšđ'")
assert 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()
assert any(
k.startswith("<ipython-input-99") for k in linecache.cache
), "Entry for input-99 missing from linecache"

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,193 @@
# -*- coding: utf-8 -*-
"""Tests for completerlib.
"""
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
import os
import shutil
import sys
import tempfile
import unittest
from os.path import join
from tempfile import TemporaryDirectory
from IPython.core.completerlib import magic_run_completer, module_completion, try_import
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", encoding="utf-8") 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", encoding="utf-8") 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", encoding="utf-8").close()
s = set( module_completion('import foo') )
intersection = s.intersection(invalid_module_names)
assert 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 ")
assert "puppies" in results
for r in results:
assert isinstance(r, str)
# bad_all doesn't contain submodules, but this completion
# should finish without raising an exception:
results = module_completion("import bad_all.")
assert results == []
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)
def test_valid_exported_submodules():
"""
Test checking exported (__all__) objects are submodules
"""
results = module_completion("import os.pa")
# ensure we get a valid submodule:
assert "os.path" in results
# ensure we don't get objects that aren't submodules:
assert "os.pathconf" not in results

View File

@ -0,0 +1,567 @@
"""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 sys
import platform
from tempfile import NamedTemporaryFile
from textwrap import dedent
from unittest.mock import patch
from IPython.core import debugger
from IPython.testing import IPYTHON_TESTING_TIMEOUT_SCALE
from IPython.testing.decorators import skip_win32
import pytest
#-----------------------------------------------------------------------------
# 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_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
assert called[0] == 1, "input() should only be called once!"
raise KeyboardInterrupt()
tracer_orig = sys.gettrace()
try:
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.
finally:
# restore the original trace function
sys.settrace(tracer_orig)
@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()
skip_decorators_blocks = (
"""
def helpers_helper():
pass # should not stop here except breakpoint
""",
"""
def helper_1():
helpers_helper() # should not stop here
""",
"""
def helper_2():
pass # should not stop here
""",
"""
def pdb_skipped_decorator2(function):
def wrapped_fn(*args, **kwargs):
__debuggerskip__ = True
helper_2()
__debuggerskip__ = False
result = function(*args, **kwargs)
__debuggerskip__ = True
helper_2()
return result
return wrapped_fn
""",
"""
def pdb_skipped_decorator(function):
def wrapped_fn(*args, **kwargs):
__debuggerskip__ = True
helper_1()
__debuggerskip__ = False
result = function(*args, **kwargs)
__debuggerskip__ = True
helper_2()
return result
return wrapped_fn
""",
"""
@pdb_skipped_decorator
@pdb_skipped_decorator2
def bar(x, y):
return x * y
""",
"""import IPython.terminal.debugger as ipdb""",
"""
def f():
ipdb.set_trace()
bar(3, 4)
""",
"""
f()
""",
)
def _decorator_skip_setup():
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.timeout = 5 * IPYTHON_TESTING_TIMEOUT_SCALE
dedented_blocks = [dedent(b).strip() for b in skip_decorators_blocks]
in_prompt_number = 1
for cblock in dedented_blocks:
child.expect_exact(f"In [{in_prompt_number}]:")
in_prompt_number += 1
for line in cblock.splitlines():
child.sendline(line)
child.expect_exact(line)
child.sendline("")
return child
@skip_win32
def test_decorator_skip():
"""test that decorator frames can be skipped."""
child = _decorator_skip_setup()
child.expect_exact("3 bar(3, 4)")
child.expect("ipdb>")
child.expect("ipdb>")
child.sendline("step")
child.expect_exact("step")
child.expect_exact("1 @pdb_skipped_decorator")
child.sendline("s")
child.expect_exact("return x * y")
child.close()
@pytest.mark.skipif(platform.python_implementation() == "PyPy", reason="issues on PyPy")
@skip_win32
def test_decorator_skip_disabled():
"""test that decorator frame skipping can be disabled"""
child = _decorator_skip_setup()
child.expect_exact("3 bar(3, 4)")
for input_, expected in [
("skip_predicates debuggerskip False", ""),
("skip_predicates", "debuggerskip : False"),
("step", "---> 2 def wrapped_fn"),
("step", "----> 3 __debuggerskip__"),
("step", "----> 4 helper_1()"),
("step", "---> 1 def helper_1():"),
("next", "----> 2 helpers_helper()"),
("next", "--Return--"),
("next", "----> 5 __debuggerskip__ = False"),
]:
child.expect("ipdb>")
child.sendline(input_)
child.expect_exact(input_)
child.expect_exact(expected)
child.close()
@pytest.mark.skipif(platform.python_implementation() == "PyPy", reason="issues on PyPy")
@skip_win32
def test_decorator_skip_with_breakpoint():
"""test that decorator frame skipping can be disabled"""
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.timeout = 5 * IPYTHON_TESTING_TIMEOUT_SCALE
### we need a filename, so we need to exec the full block with a filename
with NamedTemporaryFile(suffix=".py", dir=".", delete=True) as tf:
name = tf.name[:-3].split("/")[-1]
tf.write("\n".join([dedent(x) for x in skip_decorators_blocks[:-1]]).encode())
tf.flush()
codeblock = f"from {name} import f"
dedented_blocks = [
codeblock,
"f()",
]
in_prompt_number = 1
for cblock in dedented_blocks:
child.expect_exact(f"In [{in_prompt_number}]:")
in_prompt_number += 1
for line in cblock.splitlines():
child.sendline(line)
child.expect_exact(line)
child.sendline("")
# as the filename does not exists, we'll rely on the filename prompt
child.expect_exact("47 bar(3, 4)")
for input_, expected in [
(f"b {name}.py:3", ""),
("step", "1---> 3 pass # should not stop here except"),
("step", "---> 38 @pdb_skipped_decorator"),
("continue", ""),
]:
child.expect("ipdb>")
child.sendline(input_)
child.expect_exact(input_)
child.expect_exact(expected)
child.close()
@skip_win32
def test_where_erase_value():
"""Test that `where` does not access f_locals and erase values."""
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 simple_f():
myvar = 1
print(myvar)
1/0
print(myvar)
simple_f() """
)
for line in block.splitlines():
child.sendline(line)
child.expect_exact(line)
child.expect_exact("ZeroDivisionError")
child.expect_exact("In [2]:")
child.sendline("%debug")
##
child.expect("ipdb>")
child.sendline("myvar")
child.expect("1")
##
child.expect("ipdb>")
child.sendline("myvar = 2")
##
child.expect_exact("ipdb>")
child.sendline("myvar")
child.expect_exact("2")
##
child.expect("ipdb>")
child.sendline("where")
##
child.expect("ipdb>")
child.sendline("myvar")
child.expect_exact("2")
child.expect("ipdb>")
child.close()

View File

@ -0,0 +1,513 @@
# 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 pytest
from IPython 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)
assert '<img src="%s" width="200" height="200"/>' % (thisurl) == img._repr_html_()
img = display.Image(url=thisurl, metadata={'width':200, 'height':200})
assert '<img src="%s" width="200" height="200"/>' % (thisurl) == img._repr_html_()
img = display.Image(url=thisurl, width=200)
assert '<img src="%s" width="200"/>' % (thisurl) == img._repr_html_()
img = display.Image(url=thisurl)
assert '<img src="%s"/>' % (thisurl) == img._repr_html_()
img = display.Image(url=thisurl, unconfined=True)
assert '<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)
assert 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,
},
)
assert "<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)
assert img.height == 1
assert img.width == 1
data, md = img._repr_png_()
assert md["width"] == 1
assert 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)
assert svg._repr_svg_().startswith("<svg") is True
svg = display.SVG(url=url + "z")
assert svg._repr_svg_().startswith("<svg") is True
def test_retina_jpeg():
here = os.path.dirname(__file__)
img = display.Image(os.path.join(here, "2x2.jpg"), retina=True)
assert img.height == 1
assert img.width == 1
data, md = img._repr_jpeg_()
assert md["width"] == 1
assert 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()
pytest.raises(
ValueError,
display.Image,
filename=os.path.join(tpath, "testing/tests/badformat.zip"),
embed=True,
)
pytest.raises(ValueError, display.Image)
pytest.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)
assert "png" == img.format
assert img._repr_png_() is not None
img = display.Image(
filename=os.path.join(tpath, "testing/tests/logo.jpg"), embed=False
)
assert "jpeg" == img.format
assert img._repr_jpeg_() is None
def _get_inline_config():
from matplotlib_inline.config import InlineBackend
return InlineBackend.instance()
@dec.skip_without("matplotlib")
def test_set_matplotlib_close():
cfg = _get_inline_config()
cfg.close_figures = False
with pytest.deprecated_call():
display.set_matplotlib_close()
assert cfg.close_figures
with pytest.deprecated_call():
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}
with pytest.deprecated_call():
display.set_matplotlib_formats(*formats)
for mime, f in formatters.items():
if mime in active_mimes:
assert Figure in f
else:
assert Figure not in 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(dpi=150)
with pytest.deprecated_call():
display.set_matplotlib_formats("png", **kwargs)
formatter = ip.display_formatter.formatters["image/png"]
f = formatter.lookup_by_type(Figure)
formatter_kwargs = f.keywords
expected = kwargs
expected["base64"] = True
expected["fmt"] = "png"
expected.update(cfg.print_figure_kwargs)
assert formatter_kwargs == 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")
assert repr(p) == "<IPython.core.display.Pretty object>"
assert p.data == "This is a simple test"
p._show_mem_addr = True
assert repr(p) == object.__repr__(p)
def test_displayobject_repr():
h = display.HTML("<br />")
assert repr(h) == "<IPython.core.display.HTML object>"
h._show_mem_addr = True
assert repr(h) == object.__repr__(h)
h._show_mem_addr = False
assert repr(h) == "<IPython.core.display.HTML object>"
j = display.Javascript("")
assert repr(j) == "<IPython.core.display.Javascript object>"
j._show_mem_addr = True
assert repr(j) == object.__repr__(j)
j._show_mem_addr = False
assert 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)
assert "0/10" in repr(p)
p.html_width = "100%"
p.progress = 5
assert (
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
assert "{0}/5".format(i) in out
out = captured.stdout
assert "5/5" in 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):
assert j._repr_json_() == (d, md)
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
j = display.JSON(json.dumps(d))
assert len(w) == 1
assert 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):
assert j._repr_json_() == (lis, md)
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
j = display.JSON(json.dumps(lis))
assert len(w) == 1
assert 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_()
assert 'src="data:' not in html
assert 'src="http://ignored"' in html
with pytest.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_()
assert 'src="data:' not in html
v = display.Video(f.name, embed=True)
html = v._repr_html_()
assert 'src="data:video/mp4;base64,YWJj"' in html
v = display.Video(f.name, embed=True, mimetype='video/other')
html = v._repr_html_()
assert 'src="data:video/other;base64,YWJj"' in html
v = display.Video(b'abc', embed=True, mimetype='video/mp4')
html = v._repr_html_()
assert 'src="data:video/mp4;base64,YWJj"' in html
v = display.Video(u'YWJj', embed=True, mimetype='video/xyz')
html = v._repr_html_()
assert 'src="data:video/xyz;base64,YWJj"' in html
def test_html_metadata():
s = "<h1>Test</h1>"
h = display.HTML(s, metadata={"isolated": True})
assert 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')
assert handle is None
handle = display.display('y', display_id='secret')
assert isinstance(handle, display.DisplayHandle)
handle2 = display.display('z', display_id=True)
assert isinstance(handle2, display.DisplayHandle)
assert handle.display_id != handle2.display_id
assert pub.call_count == 3
args, kwargs = pub.call_args_list[0]
assert args == ()
assert kwargs == {
'data': {
'text/plain': repr('x')
},
'metadata': {},
}
args, kwargs = pub.call_args_list[1]
assert args == ()
assert kwargs == {
'data': {
'text/plain': repr('y')
},
'metadata': {},
'transient': {
'display_id': handle.display_id,
},
}
args, kwargs = pub.call_args_list[2]
assert args == ()
assert 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 pytest.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]
assert args == ()
assert kwargs == {
'data': {
'text/plain': repr('x')
},
'metadata': {},
'transient': {
'display_id': '1',
},
'update': True,
}
args, kwargs = pub.call_args_list[1]
assert args == ()
assert kwargs == {
'data': {
'text/plain': repr('y')
},
'metadata': {},
'transient': {
'display_id': '2',
},
'update': True,
}
def test_display_handle():
ip = get_ipython()
handle = display.DisplayHandle()
assert isinstance(handle.display_id, str)
handle = display.DisplayHandle("my-id")
assert 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]
assert args == ()
assert kwargs == {
'data': {
'text/plain': repr('x')
},
'metadata': {},
'transient': {
'display_id': handle.display_id,
}
}
args, kwargs = pub.call_args_list[1]
assert args == ()
assert kwargs == {
'data': {
'text/plain': repr('y')
},
'metadata': {},
'transient': {
'display_id': handle.display_id,
},
'update': True,
}
def test_image_alt_tag():
"""Simple test for display.Image(args, alt=x,)"""
thisurl = "http://example.com/image.png"
img = display.Image(url=thisurl, alt="an image")
assert '<img src="%s" alt="an image"/>' % (thisurl) == img._repr_html_()
img = display.Image(url=thisurl, unconfined=True, alt="an image")
assert (
'<img src="%s" class="unconfined" alt="an image"/>' % (thisurl)
== img._repr_html_()
)
img = display.Image(url=thisurl, alt='>"& <')
assert '<img src="%s" alt="&gt;&quot;&amp; &lt;"/>' % (thisurl) == img._repr_html_()
img = display.Image(url=thisurl, metadata={"alt": "an image"})
assert img.alt == "an image"
here = os.path.dirname(__file__)
img = display.Image(os.path.join(here, "2x2.png"), alt="an image")
assert img.alt == "an image"
_, md = img._repr_png_()
assert md["alt"] == "an image"
def test_image_bad_filename_raises_proper_exception():
with pytest.raises(FileNotFoundError):
display.Image("/this/file/does/not/exist/")._repr_png_()

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,91 @@
import unittest
from unittest.mock import Mock
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)
self.assertRaises(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,95 @@
import os.path
from tempfile import TemporaryDirectory
import IPython.testing.tools as tt
from IPython.utils.syspathcontext import prepended_to_syspath
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", encoding="utf-8") as f:
f.write(ext1_content)
ext2 = os.path.join(td, "ext2.py")
with open(ext2, "w", encoding="utf-8") 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", encoding="utf-8") 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
assert em.load_extension("sys") == "no load function"

View File

@ -0,0 +1,532 @@
"""Tests for the Formatters."""
import warnings
from math import pi
try:
import numpy
except:
numpy = None
import pytest
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)
assert f(A()) == "foo"
assert f(B()) == "B()"
assert f(GoodPretty()) == "foo"
# Just don't raise an exception for the following:
f(BadPretty())
f.pprint = False
assert f(A()) == "A()"
assert f(B()) == "B()"
assert f(GoodPretty()) == "GoodPretty()"
def test_deferred():
f = PlainTextFormatter()
def test_precision():
"""test various values for float_precision."""
f = PlainTextFormatter()
assert f(pi) == repr(pi)
f.float_precision = 0
if numpy:
po = numpy.get_printoptions()
assert po["precision"] == 0
assert f(pi) == "3"
f.float_precision = 2
if numpy:
po = numpy.get_printoptions()
assert po["precision"] == 2
assert f(pi) == "3.14"
f.float_precision = "%g"
if numpy:
po = numpy.get_printoptions()
assert po["precision"] == 2
assert f(pi) == "3.14159"
f.float_precision = "%e"
assert f(pi) == "3.141593e+00"
f.float_precision = ""
if numpy:
po = numpy.get_printoptions()
assert po["precision"] == 8
assert 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
pytest.raises(ValueError, set_fp, "%")
pytest.raises(ValueError, set_fp, "%.3f%i")
pytest.raises(ValueError, set_fp, "foo")
pytest.raises(ValueError, set_fp, -1)
def test_for_type():
f = PlainTextFormatter()
# initial return, None
assert f.for_type(C, foo_printer) is None
# no func queries
assert f.for_type(C) is foo_printer
# shouldn't change anything
assert f.for_type(C) is foo_printer
# None should do the same
assert f.for_type(C, None) is foo_printer
assert f.for_type(C, None) is foo_printer
def test_for_type_string():
f = PlainTextFormatter()
type_str = '%s.%s' % (C.__module__, 'C')
# initial return, None
assert f.for_type(type_str, foo_printer) is None
# no func queries
assert f.for_type(type_str) is foo_printer
assert _mod_name_key(C) in f.deferred_printers
assert f.for_type(C) is foo_printer
assert _mod_name_key(C) not in f.deferred_printers
assert C in f.type_printers
def test_for_type_by_name():
f = PlainTextFormatter()
mod = C.__module__
# initial return, None
assert f.for_type_by_name(mod, "C", foo_printer) is None
# no func queries
assert f.for_type_by_name(mod, "C") is foo_printer
# shouldn't change anything
assert f.for_type_by_name(mod, "C") is foo_printer
# None should do the same
assert f.for_type_by_name(mod, "C", None) is foo_printer
assert f.for_type_by_name(mod, "C", None) is foo_printer
def test_lookup():
f = PlainTextFormatter()
f.for_type(C, foo_printer)
assert f.lookup(C()) is foo_printer
with pytest.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)
assert f.lookup(C()) is foo_printer
# should move from deferred to imported dict
assert _mod_name_key(C) not in f.deferred_printers
assert C in f.type_printers
def test_lookup_by_type():
f = PlainTextFormatter()
f.for_type(C, foo_printer)
assert f.lookup_by_type(C) is foo_printer
with pytest.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
assert _mod_name_key(C) in f.deferred_printers
assert C not in f.type_printers
assert f.lookup_by_type(type_str) is foo_printer
# lookup by string doesn't cause import
assert _mod_name_key(C) in f.deferred_printers
assert C not in f.type_printers
assert f.lookup_by_type(C) is foo_printer
# should move from deferred to imported dict
assert _mod_name_key(C) not in f.deferred_printers
assert C in f.type_printers
def test_in_formatter():
f = PlainTextFormatter()
f.for_type(C, foo_printer)
type_str = '%s.%s' % (C.__module__, 'C')
assert C in f
assert type_str in f
def test_string_in_formatter():
f = PlainTextFormatter()
type_str = '%s.%s' % (C.__module__, 'C')
f.for_type(type_str, foo_printer)
assert type_str in f
assert C in f
def test_pop():
f = PlainTextFormatter()
f.for_type(C, foo_printer)
assert f.lookup_by_type(C) is foo_printer
assert f.pop(C, None) is foo_printer
f.for_type(C, foo_printer)
assert f.pop(C) is foo_printer
with pytest.raises(KeyError):
f.lookup_by_type(C)
with pytest.raises(KeyError):
f.pop(C)
with pytest.raises(KeyError):
f.pop(A)
assert f.pop(A, None) is None
def test_pop_string():
f = PlainTextFormatter()
type_str = '%s.%s' % (C.__module__, 'C')
with pytest.raises(KeyError):
f.pop(type_str)
f.for_type(type_str, foo_printer)
f.pop(type_str)
with pytest.raises(KeyError):
f.lookup_by_type(C)
with pytest.raises(KeyError):
f.pop(type_str)
f.for_type(C, foo_printer)
assert f.pop(type_str, None) is foo_printer
with pytest.raises(KeyError):
f.lookup_by_type(C)
with pytest.raises(KeyError):
f.pop(type_str)
assert f.pop(type_str, None) is 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)
assert result is None
assert "Traceback" in captured.stdout
assert "Bad HTML" in captured.stdout
assert "_repr_html_" in 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)
assert result is None
assert "" == captured.stderr
assert "" == 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)
assert result is None
assert "Traceback" in captured.stdout
assert "NameError" in captured.stdout
assert "name_error" in 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)
assert result is None
assert "Traceback" in captured.stdout
assert "_repr_pretty_" in captured.stdout
assert "given" in captured.stdout
assert "argument" in captured.stdout
def test_bad_repr_traceback():
f = PlainTextFormatter()
bad = BadRepr()
with capture_output() as captured:
result = f(bad)
# catches error, returns None
assert result is None
assert "Traceback" in captured.stdout
assert "__repr__" in captured.stdout
assert "ValueError" in captured.stdout
class MakePDF(object):
def _repr_pdf_(self):
return 'PDF'
def test_pdf_formatter():
pdf = MakePDF()
f = PDFFormatter()
assert 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)
assert result is None
assert "FormatterWarning" not in captured.stderr
with capture_output() as captured:
result = f(MyHTML())
assert result == "hello"
assert captured.stderr == ""
def test_print_method_weird():
class TextMagicHat(object):
def __getattr__(self, key):
return key
f = HTMLFormatter()
text_hat = TextMagicHat()
assert text_hat._repr_html_ == "_repr_html_"
with capture_output() as captured:
result = f(text_hat)
assert result is None
assert "FormatterWarning" not in captured.stderr
class CallableMagicHat(object):
def __getattr__(self, key):
return lambda : key
call_hat = CallableMagicHat()
with capture_output() as captured:
result = f(call_hat)
assert result is None
class BadReprArgs(object):
def _repr_html_(self, extra, args):
return "html"
bad = BadReprArgs()
with capture_output() as captured:
result = f(bad)
assert result is None
assert "FormatterWarning" not in 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)
assert result is None
assert captured.stderr == ""
with capture_output() as captured:
result = f(Config)
assert result is None
assert captured.stderr == ""
def test_pretty_max_seq_length():
f = PlainTextFormatter(max_seq_length=1)
lis = list(range(3))
text = f(lis)
assert text == "[0, ...]"
f.max_seq_length = 0
text = f(lis)
assert text == "[0, 1, 2]"
text = f(list(range(1024)))
lines = text.splitlines()
assert 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)
assert d == {"text/plain": repr(no)}
assert md == {}
assert catcher == []
d, md = f.format(yes)
assert d == {}
assert md == {}
assert catcher == [yes]
f.ipython_display_formatter.enabled = save_enabled
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
assert sorted(d) == [
"application/json+test.v2",
"image/png",
"plain/text",
"text/html",
"text/plain",
]
assert md == {}
d, md = f.format(obj, include={"image/png"})
assert list(d.keys()) == [
"image/png"
], "Include should filter out even things from repr_mimebundle"
assert 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)
assert sorted(d) == ["image/png", "text/plain"]
assert 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)
assert "text/plain" in d

View File

@ -0,0 +1,97 @@
"""Tests for input handlers.
"""
#-----------------------------------------------------------------------------
# Module imports
#-----------------------------------------------------------------------------
# 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.run_line_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.run_line_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.run_line_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.run_line_magic("autocall", "1")
assert failures == []

View File

@ -0,0 +1,229 @@
# coding: utf-8
"""Tests for the IPython tab-completion machinery.
"""
#-----------------------------------------------------------------------------
# Module imports
#-----------------------------------------------------------------------------
# stdlib
import io
import sqlite3
import sys
import tempfile
from datetime import datetime
from pathlib import Path
from tempfile import TemporaryDirectory
# our own packages
from traitlets.config.loader import Config
from IPython.core.history import HistoryManager, extract_hist_ranges
def test_proper_default_encoding():
assert sys.getdefaultencoding() == "utf-8"
def test_history():
ip = get_ipython()
with TemporaryDirectory() as tmpdir:
tmp_path = Path(tmpdir)
hist_manager_ori = ip.history_manager
hist_file = tmp_path / "history.sqlite"
try:
ip.history_manager = HistoryManager(shell=ip, hist_file=hist_file)
hist = ["a=1", "def f():\n test = 1\n return test", "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)
assert ip.history_manager.input_hist_raw == [""] + hist
# Detailed tests for _get_range_session
grs = ip.history_manager._get_range_session
assert list(grs(start=2, stop=-1)) == list(zip([0], [2], hist[1:-1]))
assert list(grs(start=-2)) == list(zip([0, 0], [2, 3], hist[-2:]))
assert 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.run_line_magic("hist", "2-500")
# Check that we can write non-ascii characters to a file
ip.run_line_magic("hist", "-f %s" % (tmp_path / "test1"))
ip.run_line_magic("hist", "-pf %s" % (tmp_path / "test2"))
ip.run_line_magic("hist", "-nf %s" % (tmp_path / "test3"))
ip.run_line_magic("save", "%s 1-10" % (tmp_path / "test4"))
# New session
ip.history_manager.reset()
newcmds = ["z=5", "class X(object):\n pass", "k='p'", "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)
assert list(gothist) == list(zip([0, 0, 0], [1, 2, 3], newcmds))
# Previous session:
gothist = ip.history_manager.get_range(-1, 1, 4)
assert 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]
assert list(gothist) == expected
gothist = ip.history_manager.get_tail(2)
expected = newhist[-3:-1]
assert list(gothist) == expected
# Check get_hist_search
gothist = ip.history_manager.search("*test*")
assert list(gothist) == [(1, 2, hist[1])]
gothist = ip.history_manager.search("*=*")
assert 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)
assert list(gothist) == [
(1, 3, hist[2]),
newhist[0],
newhist[2],
newhist[3],
]
gothist = ip.history_manager.search("*=*", unique=True)
assert 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)
assert list(gothist) == [(1, 3, hist[2]), newhist[2], newhist[3]]
gothist = ip.history_manager.search("b*", output=True)
assert list(gothist) == [(1, 3, (hist[2], "spam"))]
# Cross testing: check that magic %save can get previous session.
testfilename = (tmp_path / "test.py").resolve()
ip.run_line_magic("save", str(testfilename) + " ~1/1-3")
with io.open(testfilename, encoding="utf-8") as testfile:
assert testfile.read() == "# coding: utf-8\n" + "\n".join(hist) + "\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()
assert ip.history_manager.session_number == 3
# Check that session and line values are not just max values
sessid, lineno, entry = newhist[-1]
assert lineno > 1
ip.history_manager.reset()
lineno = 1
ip.history_manager.store_inputs(lineno, entry)
gothist = ip.history_manager.search("*=*", unique=True)
hist = list(gothist)[-1]
assert sessid < hist[0]
assert hist[1:] == (lineno, entry)
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))
assert actual == expected
def test_extract_hist_ranges_empty_str():
instr = ""
expected = [(0, 1, None)] # 0 == current session, None == to end
actual = list(extract_hist_ranges(instr))
assert 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)
assert ip.user_ns["a"] == 11
ip.run_cell("%rerun", store_history=True)
assert ip.user_ns["a"] == 12
def test_timestamp_type():
ip = get_ipython()
info = ip.history_manager.get_session_info()
assert isinstance(info[1], datetime)
def test_hist_file_config():
cfg = Config()
tfile = tempfile.NamedTemporaryFile(delete=False)
cfg.HistoryManager.hist_file = Path(tfile.name)
try:
hm = HistoryManager(shell=get_ipython(), config=cfg)
assert hm.hist_file == cfg.HistoryManager.hist_file
finally:
try:
Path(tfile.name).unlink()
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 = Path(tmpdir) / "history.sqlite"
cfg.HistoryManager.hist_file = hist_file
try:
ip.history_manager = HistoryManager(shell=ip, config=cfg)
hist = ["a=1", "def f():\n test = 1\n return test", "b='€Æ¾÷ß'"]
for i, h in enumerate(hist, start=1):
ip.history_manager.store_inputs(i, h)
assert 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
assert hist_file.exists() is False

View File

@ -0,0 +1,76 @@
# -*- coding: utf-8 -*-
"""Tests for CommandChainDispatcher."""
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
import pytest
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("fail1")
fail2 = Fail("fail2")
dp = CommandChainDispatcher([(0, fail1), (10, fail2)])
with pytest.raises(TryNext) as e:
dp()
assert str(e.value) == "fail2"
assert fail1.called is True
assert fail2.called is True
def test_command_chain_dispatcher_fofo():
"""Test a mixture of failing and succeeding hooks."""
fail1 = Fail("fail1")
fail2 = Fail("fail2")
okay1 = Okay("okay1")
okay2 = Okay("okay2")
dp = CommandChainDispatcher([(0, fail1),
# (5, okay1), # add this later
(10, fail2),
(15, okay2)])
dp.add(okay1, 5)
assert dp() == "okay1"
assert fail1.called is True
assert okay1.called is True
assert fail2.called is False
assert okay2.called is False
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,642 @@
# -*- 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 pytest
import sys
with pytest.warns(DeprecationWarning, match="inputsplitter"):
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 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()
assert isinstance(encoding, str)
# simple-minded check that at least encoding a simple string works with the
# encoding we got.
assert "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'")
@pytest.mark.xfail(
reason="Bug in python 3.9.8  bpo 45738",
condition=sys.version_info in [(3, 9, 8, "final", 0), (3, 11, 0, "alpha", 2)],
raises=SystemError,
strict=True,
)
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():
assert isp.last_blank("") is False
assert isp.last_blank("abc") is False
assert isp.last_blank("abc\n") is False
assert isp.last_blank("abc\na") is False
assert isp.last_blank("\n") is True
assert isp.last_blank("\n ") is True
assert isp.last_blank("abc\n ") is True
assert isp.last_blank("abc\n\n") is True
assert isp.last_blank("abc\nd\n\n") is True
assert isp.last_blank("abc\nd\ne\n\n") is True
assert isp.last_blank("abc \n \n \n\n") is True
def test_last_two_blanks():
assert isp.last_two_blanks("") is False
assert isp.last_two_blanks("abc") is False
assert isp.last_two_blanks("abc\n") is False
assert isp.last_two_blanks("abc\n\na") is False
assert isp.last_two_blanks("abc\n \n") is False
assert isp.last_two_blanks("abc\n\n") is False
assert isp.last_two_blanks("\n\n") is True
assert isp.last_two_blanks("\n\n ") is True
assert isp.last_two_blanks("\n \n") is True
assert isp.last_two_blanks("abc\n\n ") is True
assert isp.last_two_blanks("abc\n\n\n") is True
assert isp.last_two_blanks("abc\n\n \n") is True
assert isp.last_two_blanks("abc\n\n \n ") is True
assert isp.last_two_blanks("abc\n\n \n \n") is True
assert isp.last_two_blanks("abc\nd\n\n\n") is True
assert isp.last_two_blanks("abc\nd\ne\nf\n\n\n") is True
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"
assert out == ref
def test_cellmagic_help(self):
self.sp.push('%%cellm?')
assert self.sp.push_accepts_more() is False
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")
assert sp.push_accepts_more() is True # 1
sp.push("line2\n")
assert sp.push_accepts_more() is True # 2
sp.push("\n")
# This should accept a blank line and carry on until the cell is reset
assert sp.push_accepts_more() is True # 3
def test_no_strip_coding(self):
src = '\n'.join([
'%%writefile foo.py',
'# coding: utf-8',
'print(u"üñîçø∂é")',
])
out = self.sp.transform_cell(src)
assert "# coding: utf-8" in 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")
assert sp.push_accepts_more() is True # 1
sp.push("\n")
# In this case, a blank line should end the cell magic
assert sp.push_accepts_more() is False # 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,469 @@
import tokenize
from IPython.testing import tools as tt
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)
assert 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 =
[('a =! ls', "a = get_ipython().getoutput('ls')"),
('b = !ls', "b = get_ipython().getoutput('ls')"),
('c= !ls', "c = get_ipython().getoutput('ls')"),
('d == !ls', 'd == !ls'), # Invalid syntax, but we leave == alone.
('x=1', 'x=1'), # normal input is unmodified
(' ',' '), # blank lines are kept intact
# Tuple unpacking
("a, b = !echo 'a\\nb'", "a, b = get_ipython().getoutput(\"echo 'a\\\\nb'\")"),
("a,= !echo 'a'", "a, = get_ipython().getoutput(\"echo 'a'\")"),
("a, *bc = !echo 'a\\nb\\nc'", "a, *bc = get_ipython().getoutput(\"echo 'a\\\\nb\\\\nc'\")"),
# Tuple unpacking with regular Python expressions, not our syntax.
("a, b = range(2)", "a, b = range(2)"),
("a, = range(1)", "a, = range(1)"),
("a, *bc = range(3)", "a, *bc = range(3)"),
],
assign_magic =
[('a =% who', "a = get_ipython().run_line_magic('who', '')"),
('b = %who', "b = get_ipython().run_line_magic('who', '')"),
('c= %ls', "c = get_ipython().run_line_magic('ls', '')"),
('d == %ls', 'd == %ls'), # Invalid syntax, but we leave == alone.
('x=1', 'x=1'), # normal input is unmodified
(' ',' '), # blank lines are kept intact
("a, b = %foo", "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=[
("!ls", "get_ipython().system('ls')"),
# Double-escape shell, this means to capture the output of the
# subprocess and return it
("!!ls", "get_ipython().getoutput('ls')"),
],
# Help/object info
escaped_help=[
("?", "get_ipython().show_usage()"),
("?x1", "get_ipython().run_line_magic('pinfo', 'x1')"),
("??x2", "get_ipython().run_line_magic('pinfo2', 'x2')"),
("?a.*s", "get_ipython().run_line_magic('psearch', 'a.*s')"),
("?%hist1", "get_ipython().run_line_magic('pinfo', '%hist1')"),
("?%%hist2", "get_ipython().run_line_magic('pinfo', '%%hist2')"),
("?abc = qwe", "get_ipython().run_line_magic('pinfo', 'abc')"),
],
end_help=[
("x3?", "get_ipython().run_line_magic('pinfo', 'x3')"),
("x4??", "get_ipython().run_line_magic('pinfo2', 'x4')"),
("%hist1?", "get_ipython().run_line_magic('pinfo', '%hist1')"),
("%hist2??", "get_ipython().run_line_magic('pinfo2', '%hist2')"),
("%%hist3?", "get_ipython().run_line_magic('pinfo', '%%hist3')"),
("%%hist4??", "get_ipython().run_line_magic('pinfo2', '%%hist4')"),
("π.foo?", "get_ipython().run_line_magic('pinfo', 'π.foo')"),
("f*?", "get_ipython().run_line_magic('psearch', 'f*')"),
("ax.*aspe*?", "get_ipython().run_line_magic('psearch', 'ax.*aspe*')"),
("a = abc?", "get_ipython().run_line_magic('pinfo', 'abc')"),
("a = abc.qe??", "get_ipython().run_line_magic('pinfo2', 'abc.qe')"),
("a = *.items?", "get_ipython().run_line_magic('psearch', '*.items')"),
("plot(a?", "get_ipython().run_line_magic('pinfo', 'a')"),
("a*2 #comment?", "a*2 #comment?"),
],
# Explicit magic calls
escaped_magic=[
("%cd", "get_ipython().run_line_magic('cd', '')"),
("%cd /home", "get_ipython().run_line_magic('cd', '/home')"),
# Backslashes need to be escaped.
("%cd C:\\User", "get_ipython().run_line_magic('cd', 'C:\\\\User')"),
(" %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=[
("In [1]: %lsmagic", "get_ipython().run_line_magic('lsmagic', '')"),
(">>> %lsmagic", "get_ipython().run_line_magic('lsmagic', '')"),
("In [2]: !ls", "get_ipython().system('ls')"),
("In [3]: abs?", "get_ipython().run_line_magic('pinfo', 'abs')"),
("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 =
[ [('%%foo a', None),
(None, "get_ipython().run_cell_magic('foo', 'a', '')"),
],
[('%%bar 123', None),
('hello', None),
(None , "get_ipython().run_cell_magic('bar', '123', 'hello')"),
],
[('a=5', 'a=5'),
('%%cellmagic', '%%cellmagic'),
],
],
escaped =
[ [('%abc def \\', None),
('ghi', "get_ipython().run_line_magic('abc', 'def ghi')"),
],
[('%abc def \\', None),
('ghi\\', None),
(None, "get_ipython().run_line_magic('abc', 'def ghi')"),
],
],
assign_magic =
[ [('a = %bc de \\', None),
('fg', "a = get_ipython().run_line_magic('bc', 'de fg')"),
],
[('a = %bc de \\', None),
('fg\\', None),
(None, "a = get_ipython().run_line_magic('bc', 'de fg')"),
],
],
assign_system =
[ [('a = !bc de \\', None),
('fg', "a = get_ipython().getoutput('bc de fg')"),
],
[('a = !bc de \\', None),
('fg\\', None),
(None, "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([
('%foo', '%foo'),
('>>> 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([
('%%foo', '%%foo'),
('In [1]: bar', 'In [1]: bar'),
], ipt.ipy_prompt)
def test_assemble_logical_lines():
tests = \
[ [("a = \\", None),
("123", "a = 123"),
],
[("a = \\", None), # Test resetting when within a multi-line string
("12 *\\", None),
(None, "a = 12 *"),
],
[("# foo\\", "# 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 = \
[ [("a = '''", None),
("abc'''", "a = '''\nabc'''"),
],
[("a = '''", None), # Test resetting when within a multi-line string
("def", None),
(None, "a = '''\ndef"),
],
[("a = [1,", None),
("2]", "a = [1,\n2]"),
],
[("a = [1,", None), # Test resetting when within a multi-line string
("2,", None),
(None, "a = [1,\n2,"),
],
[("a = '''", None), # Test line continuation within a multi-line string
("abc\\", None),
("def", None),
("'''", "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 = [('%%bar 123', None),
('hello', None),
('' , "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
yield from [
(tokenize.NAME, 'Decimal'),
(tokenize.OP, '('),
(tokenize.STRING, repr(tokval)),
(tokenize.OP, ')')
]
else:
yield (toknum, tokval)
def test_token_input_transformer():
tests = [('1.2', "Decimal ('1.2')"),
('"1.2"', '"1.2"'),
]
tt.check_pairs(transform_and_reset(decistmt), tests)
ml_tests = \
[ [("a = 1.2; b = '''x", None),
("y'''", "a =Decimal ('1.2');b ='''x\ny'''"),
],
[("a = [1.2,", None),
("3]", "a =[Decimal ('1.2'),\n3 ]"),
],
[("a = '''foo", None), # Test resetting when within a multi-line string
("bar", None),
(None, "a = '''foo\nbar"),
],
]
for example in ml_tests:
transform_checker(example, decistmt)

View File

@ -0,0 +1,443 @@
"""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 platform
import string
import sys
from textwrap import dedent
import pytest
from IPython.core import inputtransformer2 as ipt2
from IPython.core.inputtransformer2 import _find_assign_op, make_tokens_by_line
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
),
)
CRLF_MAGIC = (
["a = f()\n", "%ls\r\n", "g()\n"],
(2, 0),
["a = f()\n", "get_ipython().run_line_magic('ls', '')\n", "g()\n"],
)
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().run_line_magic('pinfo', 'c')\n"],
)
HELP_CONTINUED_LINE = (
"""\
a = \\
zip?
""".splitlines(
keepends=True
),
(1, 0),
[r"get_ipython().run_line_magic('pinfo', 'zip')" + "\n"],
)
HELP_MULTILINE = (
"""\
(a,
b) = zip?
""".splitlines(
keepends=True
),
(1, 0),
[r"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 test_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:
assert make_tokens_by_line(c)[-1] != []
for k in printable:
assert 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
assert (res.start_line + 1, res.start_col) == expected_start
return res
else:
assert res is None
def check_transform(transformer_cls, case):
lines, start, expected = case
transformer = transformer_cls(start)
assert transformer.transform(lines) == expected
def test_continued_line():
lines = MULTILINE_MAGIC_ASSIGN[0]
assert ipt2.find_end_of_continued_line(lines, 1) == 2
assert 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)
check_transform(ipt2.EscapedCommand, CRLF_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)
assert tf.q_line == 1
assert tf.q_col == 3
tf = check_find(ipt2.HelpEnd, HELP_MULTILINE)
assert tf.q_line == 1
assert 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))
assert tf.transform(HELP_IN_EXPR[0]) == HELP_IN_EXPR[2]
tf = ipt2.HelpEnd((1, 0), (2, 3))
assert tf.transform(HELP_CONTINUED_LINE[0]) == HELP_CONTINUED_LINE[2]
tf = ipt2.HelpEnd((1, 0), (2, 8))
assert tf.transform(HELP_MULTILINE[0]) == HELP_MULTILINE[2]
tf = ipt2.HelpEnd((1, 0), (1, 0))
assert 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
assert _find_assign_op([Tk(s) for s in ("", "a", "=", "b")]) == 2
assert (
_find_assign_op([Tk(s) for s in ("", "(", "a", "=", "b", ")", "=", "5")]) == 6
)
examples = [
pytest.param("a = 1", "complete", None),
pytest.param("for a in range(5):", "incomplete", 4),
pytest.param("for a in range(5):\n if a > 0:", "incomplete", 8),
pytest.param("raise = 2", "invalid", None),
pytest.param("a = [1,\n2,", "incomplete", 0),
pytest.param("(\n))", "incomplete", 0),
pytest.param("\\\r\n", "incomplete", 0),
pytest.param("a = '''\n hi", "incomplete", 3),
pytest.param("def a():\n x=1\n global x", "invalid", None),
pytest.param(
"a \\ ",
"invalid",
None,
marks=pytest.mark.xfail(
reason="Bug in python 3.9.8  bpo 45738",
condition=sys.version_info
in [(3, 9, 8, "final", 0), (3, 11, 0, "alpha", 2)],
raises=SystemError,
strict=True,
),
), # Nothing allowed after backslash,
pytest.param("1\\\n+2", "complete", None),
]
@pytest.mark.parametrize("code, expected, number", examples)
def test_check_complete_param(code, expected, number):
cc = ipt2.TransformerManager().check_complete
assert cc(code) == (expected, number)
@pytest.mark.xfail(platform.python_implementation() == "PyPy", reason="fail on pypy")
@pytest.mark.xfail(
reason="Bug in python 3.9.8  bpo 45738",
condition=sys.version_info in [(3, 9, 8, "final", 0), (3, 11, 0, "alpha", 2)],
raises=SystemError,
strict=True,
)
def test_check_complete():
cc = ipt2.TransformerManager().check_complete
example = dedent(
"""
if True:
a=1"""
)
assert cc(example) == ("incomplete", 4)
assert cc(example + "\n") == ("complete", None)
assert 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)
assert cc("def f():\n x=0\n \\\n ") == ("incomplete", 2)
@pytest.mark.xfail(platform.python_implementation() == "PyPy", reason="fail on pypy")
@pytest.mark.parametrize(
"value, expected",
[
('''def foo():\n """''', ("incomplete", 4)),
("""async with example:\n pass""", ("incomplete", 4)),
("""async with example:\n pass\n """, ("complete", None)),
],
)
def test_check_complete_II(value, expected):
"""
Test that multiple line strings are properly handled.
Separate test function for convenience
"""
cc = ipt2.TransformerManager().check_complete
assert cc(value) == expected
@pytest.mark.parametrize(
"value, expected",
[
(")", ("invalid", None)),
("]", ("invalid", None)),
("}", ("invalid", None)),
(")(", ("invalid", None)),
("][", ("invalid", None)),
("}{", ("invalid", None)),
("]()(", ("invalid", None)),
("())(", ("invalid", None)),
(")[](", ("invalid", None)),
("()](", ("invalid", None)),
],
)
def test_check_complete_invalidates_sunken_brackets(value, expected):
"""
Test that a single line with more closing brackets than the opening ones is
interpreted as invalid
"""
cc = ipt2.TransformerManager().check_complete
assert cc(value) == expected
def test_null_cleanup_transformer():
manager = ipt2.TransformerManager()
manager.cleanup_transforms.insert(0, null_cleanup_transformer)
assert manager.transform_cell("") == ""
def test_side_effects_I():
count = 0
def counter(lines):
nonlocal count
count += 1
return lines
counter.has_side_effects = True
manager = ipt2.TransformerManager()
manager.cleanup_transforms.insert(0, counter)
assert manager.check_complete("a=1\n") == ("complete", None)
assert count == 0
def test_side_effects_II():
count = 0
def counter(lines):
nonlocal count
count += 1
return lines
counter.has_side_effects = True
manager = ipt2.TransformerManager()
manager.line_transforms.insert(0, counter)
assert manager.check_complete("b=1\n") == ("complete", None)
assert count == 0

View File

@ -0,0 +1,168 @@
"""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 pytest
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]:
assert 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]:
assert 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)
""")
IPYTHON_PROMPT_VI_INS = (
"""\
[ins] In [11]: def a():
...: 123
...:
...: 123
""",
"""\
def a():
123
123
""",
)
IPYTHON_PROMPT_VI_NAV = (
"""\
[nav] In [11]: def a():
...: 123
...:
...: 123
""",
"""\
def a():
123
123
""",
)
def test_ipython_prompt():
for sample, expected in [
IPYTHON_PROMPT,
IPYTHON_PROMPT_L2,
IPYTHON_PROMPT_VI_INS,
IPYTHON_PROMPT_VI_NAV,
]:
assert 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]:
assert 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]:
assert ipt2.leading_empty_lines(
sample.splitlines(keepends=True)
) == expected.splitlines(keepends=True)
CRLF_MAGIC = ([
"%%ls\r\n"
], [
"get_ipython().run_cell_magic('ls', '', '')\n"
])
def test_crlf_magic():
for sample, expected in [CRLF_MAGIC]:
assert ipt2.cell_magic(sample) == expected

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,250 @@
"""Tests for the key interactiveshell module, where the main ipython class is defined.
"""
#-----------------------------------------------------------------------------
# Module imports
#-----------------------------------------------------------------------------
# third party
import pytest
# 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:
assert len(ip.user_ns) == nvars_user_ns
assert 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):
File ...:... in <module>
bar(mode)
File ...:... in bar
div0()
File ...:... 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 except IndexError:
31 mode = 'div'
---> 33 bar(mode)
<BLANKLINE>
... in bar(mode)
15 "bar"
16 if mode=='div':
---> 17 div0()
18 elif mode=='exit':
19 try:
<BLANKLINE>
... in div0()
6 x = 1
7 y = 0
----> 8 x/y
<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 except IndexError:
31 mode = 'div'
---> 33 bar(mode)
mode = 'div'
<BLANKLINE>
... in bar(mode='div')
15 "bar"
16 if mode=='div':
---> 17 div0()
18 elif mode=='exit':
19 try:
<BLANKLINE>
... in div0()
6 x = 1
7 y = 0
----> 8 x/y
x = 1
y = 0
<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 execfile
exec(compiler(f.read(), fname, "exec"), glob, loc)
File ...:... in <module>
bar(mode)
File ...:... in bar
sysexit(stat, mode)
File ...:... in sysexit
raise SystemExit(stat, f"Mode = {mode}")
SystemExit: (2, 'Mode = exit')
In [21]: %xmode context
Exception reporting mode: Context
In [22]: %tb
---------------------------------------------------------------------------
SystemExit Traceback (most recent call last)
File ..., in execfile(fname, glob, loc, compiler)
... with open(fname, "rb") as f:
... compiler = compiler or compile
---> ... exec(compiler(f.read(), fname, "exec"), glob, loc)
...<module>
30 except IndexError:
31 mode = 'div'
---> 33 bar(mode)
<BLANKLINE>
...bar(mode)
21 except:
22 stat = 1
---> 23 sysexit(stat, mode)
24 else:
25 raise ValueError('Unknown mode')
<BLANKLINE>
...sysexit(stat, mode)
10 def sysexit(stat, mode):
---> 11 raise SystemExit(stat, f"Mode = {mode}")
<BLANKLINE>
SystemExit: (2, 'Mode = exit')
"""
def doctest_tb_sysexit_verbose():
"""
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 [23]: %xmode verbose
Exception reporting mode: Verbose
In [24]: %tb
---------------------------------------------------------------------------
SystemExit Traceback (most recent call last)
<BLANKLINE>
... in <module>
30 except IndexError:
31 mode = 'div'
---> 33 bar(mode)
mode = 'exit'
<BLANKLINE>
... in bar(mode='exit')
... except:
... stat = 1
---> ... sysexit(stat, mode)
mode = 'exit'
stat = 2
... else:
... raise ValueError('Unknown mode')
<BLANKLINE>
... in sysexit(stat=2, mode='exit')
10 def sysexit(stat, mode):
---> 11 raise SystemExit(stat, f"Mode = {mode}")
stat = 2
<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")
assert 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
assert ip.db["__unittest_"] == 12
del ip.db["__unittest_"]
assert "__unittest_" not in ip.db

View File

@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-
"""Test IPython.core.logger"""
import os.path
import pytest
from tempfile import TemporaryDirectory
def test_logstart_inaccessible_file():
with pytest.raises(IOError):
_ip.logger.logstart(logfname="/") # Opening that filename will fail.
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,140 @@
#-----------------------------------------------------------------------------
# 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
import sys
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():
# “optional arguments” was replaced with “options” in argparse help
# https://docs.python.org/3/whatsnew/3.10.html#argparse
# https://bugs.python.org/issue9694
options = "optional arguments" if sys.version_info < (3, 10) else "options"
assert (
magic_foo1.__doc__
== f"::\n\n %foo1 [-f FOO]\n\n A docstring.\n\n{options}:\n -f FOO, --foo FOO an argument\n"
)
assert getattr(magic_foo1, "argcmd_name", None) == None
assert real_name(magic_foo1) == "foo1"
assert magic_foo1(None, "") == argparse.Namespace(foo=None)
assert hasattr(magic_foo1, "has_arguments")
assert magic_foo2.__doc__ == "::\n\n %foo2\n\n A docstring.\n"
assert getattr(magic_foo2, "argcmd_name", None) == None
assert real_name(magic_foo2) == "foo2"
assert magic_foo2(None, "") == argparse.Namespace()
assert hasattr(magic_foo2, "has_arguments")
assert (
magic_foo3.__doc__
== f"::\n\n %foo3 [-f FOO] [-b BAR] [-z BAZ]\n\n A docstring.\n\n{options}:\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 getattr(magic_foo3, "argcmd_name", None) == None
assert real_name(magic_foo3) == "foo3"
assert magic_foo3(None, "") == argparse.Namespace(bar=None, baz=None, foo=None)
assert hasattr(magic_foo3, "has_arguments")
assert (
magic_foo4.__doc__
== f"::\n\n %foo4 [-f FOO]\n\n A docstring.\n\n{options}:\n -f FOO, --foo FOO an argument\n"
)
assert getattr(magic_foo4, "argcmd_name", None) == None
assert real_name(magic_foo4) == "foo4"
assert magic_foo4(None, "") == argparse.Namespace()
assert hasattr(magic_foo4, "has_arguments")
assert (
magic_foo5.__doc__
== f"::\n\n %frobnicate [-f FOO]\n\n A docstring.\n\n{options}:\n -f FOO, --foo FOO an argument\n"
)
assert getattr(magic_foo5, "argcmd_name", None) == "frobnicate"
assert real_name(magic_foo5) == "frobnicate"
assert magic_foo5(None, "") == argparse.Namespace(foo=None)
assert hasattr(magic_foo5, "has_arguments")
assert (
magic_magic_foo.__doc__
== f"::\n\n %magic_foo [-f FOO]\n\n A docstring.\n\n{options}:\n -f FOO, --foo FOO an argument\n"
)
assert getattr(magic_magic_foo, "argcmd_name", None) == None
assert real_name(magic_magic_foo) == "magic_foo"
assert magic_magic_foo(None, "") == argparse.Namespace(foo=None)
assert hasattr(magic_magic_foo, "has_arguments")
assert (
foo.__doc__
== f"::\n\n %foo [-f FOO]\n\n A docstring.\n\n{options}:\n -f FOO, --foo FOO an argument\n"
)
assert getattr(foo, "argcmd_name", None) == None
assert real_name(foo) == "foo"
assert foo(None, "") == argparse.Namespace(foo=None)
assert hasattr(foo, "has_arguments")

View File

@ -0,0 +1,216 @@
"""Tests for various magic functions specific to the terminal frontend."""
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
import sys
from io import StringIO
from unittest import TestCase
from IPython.testing import tools as tt
#-----------------------------------------------------------------------------
# Test functions begin
#-----------------------------------------------------------------------------
MINIMAL_LAZY_MAGIC = """
from IPython.core.magic import (
Magics,
magics_class,
line_magic,
cell_magic,
)
@magics_class
class LazyMagics(Magics):
@line_magic
def lazy_line(self, line):
print("Lazy Line")
@cell_magic
def lazy_cell(self, line, cell):
print("Lazy Cell")
def load_ipython_extension(ipython):
ipython.register_magics(LazyMagics)
"""
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()
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.run_line_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.run_line_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")
self.assertEqual(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")
self.assertEqual(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)
...
"""
)
self.assertEqual(ip.user_ns["x"], [1, 2, 3])
self.assertEqual(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()
self.assertEqual(ip.user_ns.pop("x"), [1, 2, 3])
self.assertEqual(ip.user_ns.pop("y"), [1, 4, 9])
self.assertFalse("x" in ip.user_ns)
ip.run_line_magic("paste", "-r")
self.assertEqual(ip.user_ns["x"], [1, 2, 3])
self.assertEqual(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)"""
)
self.assertEqual(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) """
)
self.assertEqual(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) """
)
self.assertEqual(ip.user_ns["zz"], 3.5)
def test_paste_echo(self):
"Also test self.paste echoing, by temporarily faking the writer"
w = StringIO()
old_write = sys.stdout.write
sys.stdout.write = w.write
code = """
a = 100
b = 200"""
try:
self.paste(code,'')
out = w.getvalue()
finally:
sys.stdout.write = old_write
self.assertEqual(ip.user_ns["a"], 100)
self.assertEqual(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")
self.assertIn("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)
self.assertEqual(ip.user_ns["funcfoo"](), "fooresult")

View File

@ -0,0 +1,476 @@
"""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 inspect
import os
import pytest
import re
import sys
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()
class SourceModuleMainTest:
__module__ = "__main__"
#-----------------------------------------------------------------------------
# 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 = 46 # Put here the actual number of this line
def test_find_source_lines():
assert oinspect.find_source_lines(test_find_source_lines) == THIS_LINE_NUMBER + 3
assert oinspect.find_source_lines(type) is None
assert oinspect.find_source_lines(SourceModuleMainTest) is None
assert oinspect.find_source_lines(SourceModuleMainTest()) is None
def test_getsource():
assert oinspect.getsource(type) is None
assert oinspect.getsource(SourceModuleMainTest) is None
assert oinspect.getsource(SourceModuleMainTest()) is None
def test_inspect_getfile_raises_exception():
"""Check oinspect.find_file/getsource/find_source_lines expectations"""
with pytest.raises(TypeError):
inspect.getfile(type)
with pytest.raises(OSError if sys.version_info >= (3, 10) else TypeError):
inspect.getfile(SourceModuleMainTest)
# 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):
assert pyfile(f1) == pyfile(f2)
def test_find_file():
match_pyfiles(oinspect.find_file(test_find_file), os.path.abspath(__file__))
assert oinspect.find_file(type) is None
assert oinspect.find_file(SourceModuleMainTest) is None
assert oinspect.find_file(SourceModuleMainTest()) is None
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__))
assert 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__))
assert f.__doc__ == "My docstring 2"
def test_find_file_magic():
run = ip.find_line_magic('run')
assert oinspect.find_file(run) is not 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")
assert i["type_name"] == "type"
expected_class = str(type(type)) # <class 'type'> (Python 3) or <type 'type'>
assert i["base_class"] == expected_class
assert re.search(
"<class 'IPython.core.tests.test_oinspect.Call'( at 0x[0-9a-f]{1,9})?>",
i["string_form"],
)
fname = __file__
if fname.endswith(".pyc"):
fname = fname[:-1]
# case-insensitive comparison needed on some filesystems
# e.g. Windows:
assert i["file"].lower() == compress_user(fname).lower()
assert i["definition"] == None
assert i["docstring"] == Call.__doc__
assert i["source"] == None
assert i["isclass"] is True
assert i["init_definition"] == "Call(x, y=1)"
assert i["init_docstring"] == Call.__init__.__doc__
i = inspector.info(Call, detail_level=1)
assert i["source"] is not None
assert i["docstring"] == None
c = Call(1)
c.__doc__ = "Modified instance docstring"
i = inspector.info(c)
assert i["type_name"] == "Call"
assert i["docstring"] == "Modified instance docstring"
assert i["class_docstring"] == Call.__doc__
assert i["init_docstring"] == Call.__init__.__doc__
assert i["call_docstring"] == Call.__call__.__doc__
def test_class_signature():
info = inspector.info(HasSignature, "HasSignature")
assert info["init_definition"] == "HasSignature(test)"
assert 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
assert 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)
assert i["call_def"] is None
def f_kwarg(pos, *, kwonly):
pass
def test_definition_kwonlyargs():
i = inspector.info(f_kwarg, oname="f_kwarg") # analysis:ignore
assert 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()
assert oinspect.getdoc(a) == "standard docstring"
assert oinspect.getdoc(b) == "custom docstring"
assert oinspect.getdoc(c) == "standard docstring"
def test_empty_property_has_no_source():
i = inspector.info(property(), detail_level=1)
assert i["source"] is None
def test_property_sources():
# 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(oinspect.getdoc)
adder = property(simple_add)
i = inspector.info(A.foo, detail_level=1)
assert "def foo(self):" in i["source"]
assert "lambda self, v:" in i["source"]
i = inspector.info(A.dname, detail_level=1)
assert "def getdoc(obj)" in i["source"]
i = inspector.info(A.adder, detail_level=1)
assert "def simple_add(a, b)" in 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()
assert (
"This is `foobar` property."
== ip.object_inspect("a_obj.foobar", detail_level=0)["docstring"]
)
ip.user_ns["a_cls"] = A
assert (
"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"]
assert "[0m" not in init_def
def test_builtin_init():
info = inspector.info(list)
init_def = info['init_definition']
assert init_def is not None
def test_render_signature_short():
def short_fun(a=1): pass
sig = oinspect._render_signature(
signature(short_fun),
short_fun.__name__,
)
assert 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__,
)
assert sig in [
# 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,201 @@
import errno
import os
import shutil
import sys
import tempfile
import warnings
from unittest.mock import patch
from tempfile import TemporaryDirectory
from testpath import assert_isdir, assert_isfile, modified_env
from IPython import paths
from IPython.testing.decorators import skip_win32
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()
assert 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()
assert ipdir == os.path.join("someplace", ".ipython")
def test_get_ipython_dir_3():
"""test_get_ipython_dir_3, use XDG if defined and exists, 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()
assert ipdir == os.path.join(tmphome.name, XDG_TEST_DIR, "ipython")
assert len(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()
assert len(w) == 1
assert "Ignoring" in 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()
assert 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()
assert ipdir == os.path.join(HOME_TEST_DIR, ".ipython")
assert 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()
assert ipdir == os.path.join(home_dir, "somewhere")
@skip_win32
def test_get_ipython_dir_8():
"""test_get_ipython_dir_8, test / home directory"""
if not os.access("/", os.W_OK):
# test only when HOME directory actually writable
return
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": "/",
}
):
assert paths.get_ipython_dir() == "/.ipython"
def test_get_ipython_cache_dir():
with modified_env({'HOME': HOME_TEST_DIR}):
if os.name == "posix":
# test default
os.makedirs(os.path.join(HOME_TEST_DIR, ".cache"))
with modified_env({'XDG_CACHE_HOME': None}):
ipdir = paths.get_ipython_cache_dir()
assert 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)
assert ipdir == os.path.join(XDG_CACHE_DIR, "ipython")
else:
assert 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 pytest
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:
assert 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")
assert 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")
assert 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:
assert ip.prefilter("f 1") == "f(1)"
for t in ["f +1", "f -1"]:
assert 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()
assert ip.prefilter("f -1") == "f(-1)"
assert 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
assert 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:
assert ip.prefilter("π 3") == "π(3)"
finally:
ip.magic('autocall 0')
del ip.user_ns['π']

View File

@ -0,0 +1,155 @@
# 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 shutil
import sys
import tempfile
from pathlib import Path
from unittest import TestCase
from tempfile import TemporaryDirectory
from IPython.core.profileapp import list_bundled_profiles, list_profiles_in
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
#-----------------------------------------------------------------------------
# Globals
#-----------------------------------------------------------------------------
TMP_TEST_DIR = Path(tempfile.mkdtemp())
HOME_TEST_DIR = TMP_TEST_DIR / "home_test_dir"
IP_TEST_DIR = 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...
(Path.cwd() / IP_TEST_DIR).mkdir(parents=True)
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
#-----------------------------------------------------------------------------
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 = 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(Path(self.pd.startup_dir) / startup_file, "w", encoding="utf-8") as f:
f.write(startup)
# write simple test file, to check that the startup file was run
with open(self.fname, "w", encoding="utf-8") as f:
f.write(test)
def validate(self, output):
tt.ipexec_validate(self.fname, output, "", options=self.options)
def test_startup_py(self):
self.init('00-start.py', 'zzz=123\n', 'print(zzz)\n')
self.validate('123')
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 = Path(tempfile.mkdtemp(dir=TMP_TEST_DIR))
for name in ("profile_foo", "profile_hello", "not_a_profile"):
Path(td / name).mkdir(parents=True)
if dec.unicode_paths:
Path(td / "profile_ünicode").mkdir(parents=True)
with open(td / "profile_file", "w", encoding="utf-8") 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:
assert found_unicode is True
assert 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())
assert 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 = Path(td) / "profile_foo"
assert Path(profile_dir).exists()
ipython_config = profile_dir / "ipython_config.py"
assert Path(ipython_config).exists()

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,274 @@
"""Tests for pylab tools module.
"""
# Copyright (c) IPython Development Team.
# Distributed under the terms of the Modified BSD License.
from binascii import a2b_base64
from io import BytesIO
import pytest
matplotlib = pytest.importorskip("matplotlib")
matplotlib.use('Agg')
from matplotlib.figure import Figure
from matplotlib import pyplot as plt
from matplotlib_inline import backend_inline
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()
assert pt.print_figure(fig, "svg") is 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()
assert "doctype svg" in 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 pytest.skip("PIL can't write JPEG to BytesIO: %s: %s" % (ename, e)) from 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()
assert 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)
assert "width" in md
assert "height" in 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:
assert Figure in f
else:
assert Figure not in f
def test_select_figure_formats_kwargs():
ip = get_ipython()
kwargs = dict(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.keywords
expected = kwargs
expected["base64"] = True
expected["fmt"] = "png"
assert cell == expected
# 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 isinstance(png, str)
png_bytes = a2b_base64(png)
assert png_bytes.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:
assert Figure in f
else:
assert Figure not in f
def test_select_figure_formats_bad():
ip = get_ipython()
with pytest.raises(ValueError):
pt.select_figure_formats(ip, 'foo')
with pytest.raises(ValueError):
pt.select_figure_formats(ip, {'png', 'foo'})
with pytest.raises(ValueError):
pt.select_figure_formats(ip, ['retina', 'pdf', 'bar', 'bad'])
def test_import_pylab():
ns = {}
pt.import_pylab(ns, import_all=False)
assert "plt" in ns
assert ns["np"] == np
from traitlets.config import Config
class TestPylabSwitch(object):
class Shell(InteractiveShell):
def init_history(self):
"""Sets up the command history, and starts regular autosaves."""
self.config.HistoryManager.hist_file = ":memory:"
super().init_history()
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 = backend_inline.configure_inline_support
backend_inline.configure_inline_support = lambda *a, **kw: None
def teardown(self):
pt.activate_matplotlib = self._save_am
pt.import_pylab = self._save_ip
backend_inline.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)
assert gui == "qt"
assert s.pylab_gui_select == "qt"
gui, backend = s.enable_matplotlib("inline")
assert gui == "inline"
assert s.pylab_gui_select == "qt"
gui, backend = s.enable_matplotlib("qt")
assert gui == "qt"
assert s.pylab_gui_select == "qt"
gui, backend = s.enable_matplotlib("inline")
assert gui == "inline"
assert s.pylab_gui_select == "qt"
gui, backend = s.enable_matplotlib()
assert gui == "qt"
assert s.pylab_gui_select == "qt"
def test_inline(self):
s = self.Shell()
gui, backend = s.enable_matplotlib("inline")
assert gui == "inline"
assert s.pylab_gui_select == None
gui, backend = s.enable_matplotlib("inline")
assert gui == "inline"
assert s.pylab_gui_select == None
gui, backend = s.enable_matplotlib("qt")
assert gui == "qt"
assert 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")
assert 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")
assert gui == "inline"
for mime, f in ip.display_formatter.formatters.items():
if mime in active_mimes:
assert Figure in f
else:
assert Figure not in f
def test_qt_gtk(self):
s = self.Shell()
gui, backend = s.enable_matplotlib("qt")
assert gui == "qt"
assert s.pylab_gui_select == "qt"
gui, backend = s.enable_matplotlib("gtk")
assert gui == "qt"
assert 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,622 @@
# 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
import platform
import random
import string
import sys
import textwrap
import unittest
from os.path import join as pjoin
from unittest.mock import patch
import pytest
from tempfile import TemporaryDirectory
from IPython.core import debugger
from IPython.testing import decorators as dec
from IPython.testing import tools as tt
from IPython.utils.io import capture_output
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', encoding='utf-8')
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']
"""
doctest_run_option_parser_for_posix.__skip_doctest__ = sys.platform == "win32"
@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'"]
"""
doctest_run_option_parser_for_windows.__skip_doctest__ = sys.platform != "win32"
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(); import gc; x = gc.collect(0)
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__'])
assert 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()
assert 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)")
assert _ip.user_ns["t"] is True
@pytest.mark.xfail(
platform.python_implementation() == "PyPy",
reason="expecting __del__ call on exit is unreliable and doesn't happen on PyPy",
)
def test_obj_del(self):
"""Test that object's __del__ methods are called on exit."""
src = ("class A(object):\n"
" def __del__(self):\n"
" print('object A deleted')\n"
"a = A()\n")
self.mktmp(src)
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()")
assert _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)
assert _ip.user_ns["afunc"]() == 1
def test_tclass(self):
mydir = os.path.dirname(__file__)
tc = os.path.join(mydir, "tclass")
src = f"""\
import gc
%run "{tc}" C-first
gc.collect(0)
%run "{tc}" C-second
gc.collect(0)
%run "{tc}" C-third
gc.collect(0)
%reset -f
"""
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
"""
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)
assert _ip.user_ns["yy"] == 23
finally:
_ip.magic('reset -f')
_ip.run_cell("zz = 23")
try:
_ip.magic("run -i %s" % self.fname)
assert _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)
assert _ip.user_ns["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.
assert _ip.user_ns["t"] == self.fname
# Check that __file__ was not leaked back into user_ns.
assert 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.
assert _ip.user_ns["t"] == self.fname
# Check that __file__ was not leaked back into user_ns.
assert 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"""
pytest.importorskip("nbformat")
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)
assert _ip.user_ns["answer"] == 42
def test_run_nb_error(self):
"""Test %run notebook.ipynb error"""
pytest.importorskip("nbformat")
from nbformat import v4, writes
# %run when a file name isn't provided
pytest.raises(Exception, _ip.magic, "run")
# %run when a file doesn't exist
pytest.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')
pytest.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))
assert _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", encoding="utf-8") 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))
assert _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))
assert _ip.user_ns["a"] == test_opts
def test_run__name__():
with TemporaryDirectory() as td:
path = pjoin(td, "foo.py")
with open(path, "w", encoding="utf-8") as f:
f.write("q = __name__")
_ip.user_ns.pop("q", None)
_ip.magic("run {}".format(path))
assert _ip.user_ns.pop("q") == "__main__"
_ip.magic("run -n {}".format(path))
assert _ip.user_ns.pop("q") == "foo"
try:
_ip.magic("run -i -n {}".format(path))
assert _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", encoding="utf-8") 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
assert "execfile" not in out
assert "RuntimeError" in out
assert 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 we need to temporarily set it to None to test
the issue.
"""
with TemporaryDirectory() as td:
mpm = sys.modules.get('__mp_main__')
sys.modules['__mp_main__'] = None
try:
path = pjoin(td, "test.py")
with open(path, "w", encoding="utf-8") 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
assert "hoy" in out
assert "AttributeError" not in out
assert "NameError" in out
assert out.count("---->") == 1
except:
raise
finally:
sys.modules['__mp_main__'] = mpm
def test_script_tb():
"""Test traceback offset in `ipython script.py`"""
with TemporaryDirectory() as td:
path = pjoin(td, "foo.py")
with open(path, "w", encoding="utf-8") as f:
f.write(
"\n".join(
[
"def foo():",
" return bar()",
"def bar():",
" raise RuntimeError('hello!')",
"foo()",
]
)
)
out, err = tt.ipexec(path)
assert "execfile" not in out
assert "RuntimeError" in out
assert out.count("---->") == 3

View File

@ -0,0 +1,56 @@
# -*- 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
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 = 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 = 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()"],
)
assert "False" in out, f"Subprocess stderr:\n{err}\n-----"

View File

@ -0,0 +1,38 @@
# coding: utf-8
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(("Pérez Fernando", ("", "", "Pérez", "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")
assert str(linfo) == "LineInfo [ |%|cd|/home]"

View File

@ -0,0 +1,409 @@
# encoding: utf-8
"""Tests for IPython.core.ultratb
"""
import io
import logging
import os.path
import platform
import re
import sys
import traceback
import unittest
from textwrap import dedent
from tempfile import TemporaryDirectory
from IPython.core.ultratb import ColorTB, VerboseTB
from IPython.testing import tools as tt
from IPython.testing.decorators import onlyif_unicode_paths
from IPython.utils.syspathcontext import prepended_to_syspath
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):
rl = sys.getrecursionlimit()
sys.setrecursionlimit(frames)
try:
return test_function(*args, **kwargs)
finally:
sys.setrecursionlimit(rl)
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", encoding="utf-8") 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", encoding="utf-8") 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", encoding="utf-8") 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", encoding="utf-8") 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_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", encoding="utf-8") as f:
f.write(se_file_1)
with tt.AssertPrints(["7/", "SyntaxError"]):
ip.magic("run " + fname)
# Modify the file
with open(fname, "w", encoding="utf-8") 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) and platform.python_implementation() != "PyPy":
"""
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("skipping similar frames"):
ip.run_cell("non_recurs()")
@recursionlimit(200)
def test_recursion_one_frame(self):
with tt.AssertPrints(re.compile(
r"\[\.\.\. skipping similar frames: r1 at line 5 \(\d{2,3} times\)\]")
):
ip.run_cell("r1()")
@recursionlimit(160)
def test_recursion_three_frames(self):
with tt.AssertPrints("[... skipping similar frames: "), \
tt.AssertPrints(re.compile(r"r3a at line 8 \(\d{2} times\)"), suppress=False), \
tt.AssertPrints(re.compile(r"r3b at line 11 \(\d{2} times\)"), suppress=False), \
tt.AssertPrints(re.compile(r"r3c at line 14 \(\d{2} times\)"), suppress=False):
ip.run_cell("r3o2()")
#----------------------------------------------------------------------------
# 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('')