##// END OF EJS Templates
Merge pull request #13206 from sgaist/nose_cleanup_first_step...
Matthias Bussonnier -
r26949:24290cb1 merge
parent child Browse files
Show More

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

@@ -0,0 +1,16 b''
1 # See https://pre-commit.com for more information
2 # See https://pre-commit.com/hooks.html for more hooks
3 repos:
4 - repo: https://github.com/pre-commit/pre-commit-hooks
5 rev: v3.2.0
6 hooks:
7 - id: trailing-whitespace
8 - id: end-of-file-fixer
9 - id: check-yaml
10 - id: check-added-large-files
11
12 - repo: https://github.com/akaihola/darker
13 rev: 1.3.1
14 hooks:
15 - id: darker
16
@@ -1,73 +1,70 b''
1 # coding: utf-8
1 # coding: utf-8
2 """Tests for IPython.core.application"""
2 """Tests for IPython.core.application"""
3
3
4 import os
4 import os
5 import tempfile
5 import tempfile
6
6
7 import nose.tools as nt
8
9 from traitlets import Unicode
7 from traitlets import Unicode
10
8
11 from IPython.core.application import BaseIPythonApplication
9 from IPython.core.application import BaseIPythonApplication
12 from IPython.testing import decorators as dec
10 from IPython.testing import decorators as dec
13 from IPython.utils.tempdir import TemporaryDirectory
11 from IPython.utils.tempdir import TemporaryDirectory
14
12
15
13
16 @dec.onlyif_unicode_paths
14 @dec.onlyif_unicode_paths
17 def test_unicode_cwd():
15 def test_unicode_cwd():
18 """Check that IPython starts with non-ascii characters in the path."""
16 """Check that IPython starts with non-ascii characters in the path."""
19 wd = tempfile.mkdtemp(suffix=u"€")
17 wd = tempfile.mkdtemp(suffix=u"€")
20
18
21 old_wd = os.getcwd()
19 old_wd = os.getcwd()
22 os.chdir(wd)
20 os.chdir(wd)
23 #raise Exception(repr(os.getcwd()))
21 #raise Exception(repr(os.getcwd()))
24 try:
22 try:
25 app = BaseIPythonApplication()
23 app = BaseIPythonApplication()
26 # The lines below are copied from Application.initialize()
24 # The lines below are copied from Application.initialize()
27 app.init_profile_dir()
25 app.init_profile_dir()
28 app.init_config_files()
26 app.init_config_files()
29 app.load_config_file(suppress_errors=False)
27 app.load_config_file(suppress_errors=False)
30 finally:
28 finally:
31 os.chdir(old_wd)
29 os.chdir(old_wd)
32
30
33 @dec.onlyif_unicode_paths
31 @dec.onlyif_unicode_paths
34 def test_unicode_ipdir():
32 def test_unicode_ipdir():
35 """Check that IPython starts with non-ascii characters in the IP dir."""
33 """Check that IPython starts with non-ascii characters in the IP dir."""
36 ipdir = tempfile.mkdtemp(suffix=u"€")
34 ipdir = tempfile.mkdtemp(suffix=u"€")
37
35
38 # Create the config file, so it tries to load it.
36 # Create the config file, so it tries to load it.
39 with open(os.path.join(ipdir, 'ipython_config.py'), "w") as f:
37 with open(os.path.join(ipdir, 'ipython_config.py'), "w") as f:
40 pass
38 pass
41
39
42 old_ipdir1 = os.environ.pop("IPYTHONDIR", None)
40 old_ipdir1 = os.environ.pop("IPYTHONDIR", None)
43 old_ipdir2 = os.environ.pop("IPYTHON_DIR", None)
41 old_ipdir2 = os.environ.pop("IPYTHON_DIR", None)
44 os.environ["IPYTHONDIR"] = ipdir
42 os.environ["IPYTHONDIR"] = ipdir
45 try:
43 try:
46 app = BaseIPythonApplication()
44 app = BaseIPythonApplication()
47 # The lines below are copied from Application.initialize()
45 # The lines below are copied from Application.initialize()
48 app.init_profile_dir()
46 app.init_profile_dir()
49 app.init_config_files()
47 app.init_config_files()
50 app.load_config_file(suppress_errors=False)
48 app.load_config_file(suppress_errors=False)
51 finally:
49 finally:
52 if old_ipdir1:
50 if old_ipdir1:
53 os.environ["IPYTHONDIR"] = old_ipdir1
51 os.environ["IPYTHONDIR"] = old_ipdir1
54 if old_ipdir2:
52 if old_ipdir2:
55 os.environ["IPYTHONDIR"] = old_ipdir2
53 os.environ["IPYTHONDIR"] = old_ipdir2
56
54
57 def test_cli_priority():
55 def test_cli_priority():
58 with TemporaryDirectory() as td:
56 with TemporaryDirectory() as td:
59
57
60 class TestApp(BaseIPythonApplication):
58 class TestApp(BaseIPythonApplication):
61 test = Unicode().tag(config=True)
59 test = Unicode().tag(config=True)
62
60
63 # Create the config file, so it tries to load it.
61 # Create the config file, so it tries to load it.
64 with open(os.path.join(td, 'ipython_config.py'), "w") as f:
62 with open(os.path.join(td, 'ipython_config.py'), "w") as f:
65 f.write("c.TestApp.test = 'config file'")
63 f.write("c.TestApp.test = 'config file'")
66
64
67 app = TestApp()
65 app = TestApp()
68 app.initialize(['--profile-dir', td])
66 app.initialize(["--profile-dir", td])
69 nt.assert_equal(app.test, 'config file')
67 assert app.test == "config file"
70 app = TestApp()
68 app = TestApp()
71 app.initialize(['--profile-dir', td, '--TestApp.test=cli'])
69 app.initialize(["--profile-dir", td, "--TestApp.test=cli"])
72 nt.assert_equal(app.test, 'cli')
70 assert app.test == "cli"
73
@@ -1,316 +1,315 b''
1 """
1 """
2 Test for async helpers.
2 Test for async helpers.
3
3
4 Should only trigger on python 3.5+ or will have syntax errors.
4 Should only trigger on python 3.5+ or will have syntax errors.
5 """
5 """
6 from itertools import chain, repeat
6 from itertools import chain, repeat
7 import nose.tools as nt
8 from textwrap import dedent, indent
7 from textwrap import dedent, indent
9 from unittest import TestCase
8 from unittest import TestCase
10 from IPython.testing.decorators import skip_without
9 from IPython.testing.decorators import skip_without
11 import sys
10 import sys
12 from typing import TYPE_CHECKING
11 from typing import TYPE_CHECKING
13
12
14 if TYPE_CHECKING:
13 if TYPE_CHECKING:
15 from IPython import get_ipython
14 from IPython import get_ipython
16
15
17 ip = get_ipython()
16 ip = get_ipython()
18
17
19
18
20 iprc = lambda x: ip.run_cell(dedent(x)).raise_error()
19 iprc = lambda x: ip.run_cell(dedent(x)).raise_error()
21 iprc_nr = lambda x: ip.run_cell(dedent(x))
20 iprc_nr = lambda x: ip.run_cell(dedent(x))
22
21
23 from IPython.core.async_helpers import _should_be_async
22 from IPython.core.async_helpers import _should_be_async
24
23
25 class AsyncTest(TestCase):
24 class AsyncTest(TestCase):
26 def test_should_be_async(self):
25 def test_should_be_async(self):
27 nt.assert_false(_should_be_async("False"))
26 self.assertFalse(_should_be_async("False"))
28 nt.assert_true(_should_be_async("await bar()"))
27 self.assertTrue(_should_be_async("await bar()"))
29 nt.assert_true(_should_be_async("x = await bar()"))
28 self.assertTrue(_should_be_async("x = await bar()"))
30 nt.assert_false(
29 self.assertFalse(
31 _should_be_async(
30 _should_be_async(
32 dedent(
31 dedent(
33 """
32 """
34 async def awaitable():
33 async def awaitable():
35 pass
34 pass
36 """
35 """
37 )
36 )
38 )
37 )
39 )
38 )
40
39
41 def _get_top_level_cases(self):
40 def _get_top_level_cases(self):
42 # These are test cases that should be valid in a function
41 # These are test cases that should be valid in a function
43 # but invalid outside of a function.
42 # but invalid outside of a function.
44 test_cases = []
43 test_cases = []
45 test_cases.append(('basic', "{val}"))
44 test_cases.append(('basic', "{val}"))
46
45
47 # Note, in all conditional cases, I use True instead of
46 # Note, in all conditional cases, I use True instead of
48 # False so that the peephole optimizer won't optimize away
47 # False so that the peephole optimizer won't optimize away
49 # the return, so CPython will see this as a syntax error:
48 # the return, so CPython will see this as a syntax error:
50 #
49 #
51 # while True:
50 # while True:
52 # break
51 # break
53 # return
52 # return
54 #
53 #
55 # But not this:
54 # But not this:
56 #
55 #
57 # while False:
56 # while False:
58 # return
57 # return
59 #
58 #
60 # See https://bugs.python.org/issue1875
59 # See https://bugs.python.org/issue1875
61
60
62 test_cases.append(('if', dedent("""
61 test_cases.append(('if', dedent("""
63 if True:
62 if True:
64 {val}
63 {val}
65 """)))
64 """)))
66
65
67 test_cases.append(('while', dedent("""
66 test_cases.append(('while', dedent("""
68 while True:
67 while True:
69 {val}
68 {val}
70 break
69 break
71 """)))
70 """)))
72
71
73 test_cases.append(('try', dedent("""
72 test_cases.append(('try', dedent("""
74 try:
73 try:
75 {val}
74 {val}
76 except:
75 except:
77 pass
76 pass
78 """)))
77 """)))
79
78
80 test_cases.append(('except', dedent("""
79 test_cases.append(('except', dedent("""
81 try:
80 try:
82 pass
81 pass
83 except:
82 except:
84 {val}
83 {val}
85 """)))
84 """)))
86
85
87 test_cases.append(('finally', dedent("""
86 test_cases.append(('finally', dedent("""
88 try:
87 try:
89 pass
88 pass
90 except:
89 except:
91 pass
90 pass
92 finally:
91 finally:
93 {val}
92 {val}
94 """)))
93 """)))
95
94
96 test_cases.append(('for', dedent("""
95 test_cases.append(('for', dedent("""
97 for _ in range(4):
96 for _ in range(4):
98 {val}
97 {val}
99 """)))
98 """)))
100
99
101
100
102 test_cases.append(('nested', dedent("""
101 test_cases.append(('nested', dedent("""
103 if True:
102 if True:
104 while True:
103 while True:
105 {val}
104 {val}
106 break
105 break
107 """)))
106 """)))
108
107
109 test_cases.append(('deep-nested', dedent("""
108 test_cases.append(('deep-nested', dedent("""
110 if True:
109 if True:
111 while True:
110 while True:
112 break
111 break
113 for x in range(3):
112 for x in range(3):
114 if True:
113 if True:
115 while True:
114 while True:
116 for x in range(3):
115 for x in range(3):
117 {val}
116 {val}
118 """)))
117 """)))
119
118
120 return test_cases
119 return test_cases
121
120
122 def _get_ry_syntax_errors(self):
121 def _get_ry_syntax_errors(self):
123 # This is a mix of tests that should be a syntax error if
122 # This is a mix of tests that should be a syntax error if
124 # return or yield whether or not they are in a function
123 # return or yield whether or not they are in a function
125
124
126 test_cases = []
125 test_cases = []
127
126
128 test_cases.append(('class', dedent("""
127 test_cases.append(('class', dedent("""
129 class V:
128 class V:
130 {val}
129 {val}
131 """)))
130 """)))
132
131
133 test_cases.append(('nested-class', dedent("""
132 test_cases.append(('nested-class', dedent("""
134 class V:
133 class V:
135 class C:
134 class C:
136 {val}
135 {val}
137 """)))
136 """)))
138
137
139 return test_cases
138 return test_cases
140
139
141
140
142 def test_top_level_return_error(self):
141 def test_top_level_return_error(self):
143 tl_err_test_cases = self._get_top_level_cases()
142 tl_err_test_cases = self._get_top_level_cases()
144 tl_err_test_cases.extend(self._get_ry_syntax_errors())
143 tl_err_test_cases.extend(self._get_ry_syntax_errors())
145
144
146 vals = ('return', 'yield', 'yield from (_ for _ in range(3))',
145 vals = ('return', 'yield', 'yield from (_ for _ in range(3))',
147 dedent('''
146 dedent('''
148 def f():
147 def f():
149 pass
148 pass
150 return
149 return
151 '''),
150 '''),
152 )
151 )
153
152
154 for test_name, test_case in tl_err_test_cases:
153 for test_name, test_case in tl_err_test_cases:
155 # This example should work if 'pass' is used as the value
154 # This example should work if 'pass' is used as the value
156 with self.subTest((test_name, 'pass')):
155 with self.subTest((test_name, 'pass')):
157 iprc(test_case.format(val='pass'))
156 iprc(test_case.format(val='pass'))
158
157
159 # It should fail with all the values
158 # It should fail with all the values
160 for val in vals:
159 for val in vals:
161 with self.subTest((test_name, val)):
160 with self.subTest((test_name, val)):
162 msg = "Syntax error not raised for %s, %s" % (test_name, val)
161 msg = "Syntax error not raised for %s, %s" % (test_name, val)
163 with self.assertRaises(SyntaxError, msg=msg):
162 with self.assertRaises(SyntaxError, msg=msg):
164 iprc(test_case.format(val=val))
163 iprc(test_case.format(val=val))
165
164
166 def test_in_func_no_error(self):
165 def test_in_func_no_error(self):
167 # Test that the implementation of top-level return/yield
166 # Test that the implementation of top-level return/yield
168 # detection isn't *too* aggressive, and works inside a function
167 # detection isn't *too* aggressive, and works inside a function
169 func_contexts = []
168 func_contexts = []
170
169
171 func_contexts.append(('func', False, dedent("""
170 func_contexts.append(('func', False, dedent("""
172 def f():""")))
171 def f():""")))
173
172
174 func_contexts.append(('method', False, dedent("""
173 func_contexts.append(('method', False, dedent("""
175 class MyClass:
174 class MyClass:
176 def __init__(self):
175 def __init__(self):
177 """)))
176 """)))
178
177
179 func_contexts.append(('async-func', True, dedent("""
178 func_contexts.append(('async-func', True, dedent("""
180 async def f():""")))
179 async def f():""")))
181
180
182 func_contexts.append(('async-method', True, dedent("""
181 func_contexts.append(('async-method', True, dedent("""
183 class MyClass:
182 class MyClass:
184 async def f(self):""")))
183 async def f(self):""")))
185
184
186 func_contexts.append(('closure', False, dedent("""
185 func_contexts.append(('closure', False, dedent("""
187 def f():
186 def f():
188 def g():
187 def g():
189 """)))
188 """)))
190
189
191 def nest_case(context, case):
190 def nest_case(context, case):
192 # Detect indentation
191 # Detect indentation
193 lines = context.strip().splitlines()
192 lines = context.strip().splitlines()
194 prefix_len = 0
193 prefix_len = 0
195 for c in lines[-1]:
194 for c in lines[-1]:
196 if c != ' ':
195 if c != ' ':
197 break
196 break
198 prefix_len += 1
197 prefix_len += 1
199
198
200 indented_case = indent(case, ' ' * (prefix_len + 4))
199 indented_case = indent(case, ' ' * (prefix_len + 4))
201 return context + '\n' + indented_case
200 return context + '\n' + indented_case
202
201
203 # Gather and run the tests
202 # Gather and run the tests
204
203
205 # yield is allowed in async functions, starting in Python 3.6,
204 # yield is allowed in async functions, starting in Python 3.6,
206 # and yield from is not allowed in any version
205 # and yield from is not allowed in any version
207 vals = ('return', 'yield', 'yield from (_ for _ in range(3))')
206 vals = ('return', 'yield', 'yield from (_ for _ in range(3))')
208
207
209 success_tests = zip(self._get_top_level_cases(), repeat(False))
208 success_tests = zip(self._get_top_level_cases(), repeat(False))
210 failure_tests = zip(self._get_ry_syntax_errors(), repeat(True))
209 failure_tests = zip(self._get_ry_syntax_errors(), repeat(True))
211
210
212 tests = chain(success_tests, failure_tests)
211 tests = chain(success_tests, failure_tests)
213
212
214 for context_name, async_func, context in func_contexts:
213 for context_name, async_func, context in func_contexts:
215 for (test_name, test_case), should_fail in tests:
214 for (test_name, test_case), should_fail in tests:
216 nested_case = nest_case(context, test_case)
215 nested_case = nest_case(context, test_case)
217
216
218 for val in vals:
217 for val in vals:
219 test_id = (context_name, test_name, val)
218 test_id = (context_name, test_name, val)
220 cell = nested_case.format(val=val)
219 cell = nested_case.format(val=val)
221
220
222 with self.subTest(test_id):
221 with self.subTest(test_id):
223 if should_fail:
222 if should_fail:
224 msg = ("SyntaxError not raised for %s" %
223 msg = ("SyntaxError not raised for %s" %
225 str(test_id))
224 str(test_id))
226 with self.assertRaises(SyntaxError, msg=msg):
225 with self.assertRaises(SyntaxError, msg=msg):
227 iprc(cell)
226 iprc(cell)
228
227
229 print(cell)
228 print(cell)
230 else:
229 else:
231 iprc(cell)
230 iprc(cell)
232
231
233 def test_nonlocal(self):
232 def test_nonlocal(self):
234 # fails if outer scope is not a function scope or if var not defined
233 # fails if outer scope is not a function scope or if var not defined
235 with self.assertRaises(SyntaxError):
234 with self.assertRaises(SyntaxError):
236 iprc("nonlocal x")
235 iprc("nonlocal x")
237 iprc("""
236 iprc("""
238 x = 1
237 x = 1
239 def f():
238 def f():
240 nonlocal x
239 nonlocal x
241 x = 10000
240 x = 10000
242 yield x
241 yield x
243 """)
242 """)
244 iprc("""
243 iprc("""
245 def f():
244 def f():
246 def g():
245 def g():
247 nonlocal x
246 nonlocal x
248 x = 10000
247 x = 10000
249 yield x
248 yield x
250 """)
249 """)
251
250
252 # works if outer scope is a function scope and var exists
251 # works if outer scope is a function scope and var exists
253 iprc("""
252 iprc("""
254 def f():
253 def f():
255 x = 20
254 x = 20
256 def g():
255 def g():
257 nonlocal x
256 nonlocal x
258 x = 10000
257 x = 10000
259 yield x
258 yield x
260 """)
259 """)
261
260
262
261
263 def test_execute(self):
262 def test_execute(self):
264 iprc("""
263 iprc("""
265 import asyncio
264 import asyncio
266 await asyncio.sleep(0.001)
265 await asyncio.sleep(0.001)
267 """
266 """
268 )
267 )
269
268
270 def test_autoawait(self):
269 def test_autoawait(self):
271 iprc("%autoawait False")
270 iprc("%autoawait False")
272 iprc("%autoawait True")
271 iprc("%autoawait True")
273 iprc("""
272 iprc("""
274 from asyncio import sleep
273 from asyncio import sleep
275 await sleep(0.1)
274 await sleep(0.1)
276 """
275 """
277 )
276 )
278
277
279 if sys.version_info < (3,9):
278 if sys.version_info < (3,9):
280 # new pgen parser in 3.9 does not raise MemoryError on too many nested
279 # new pgen parser in 3.9 does not raise MemoryError on too many nested
281 # parens anymore
280 # parens anymore
282 def test_memory_error(self):
281 def test_memory_error(self):
283 with self.assertRaises(MemoryError):
282 with self.assertRaises(MemoryError):
284 iprc("(" * 200 + ")" * 200)
283 iprc("(" * 200 + ")" * 200)
285
284
286 @skip_without('curio')
285 @skip_without('curio')
287 def test_autoawait_curio(self):
286 def test_autoawait_curio(self):
288 iprc("%autoawait curio")
287 iprc("%autoawait curio")
289
288
290 @skip_without('trio')
289 @skip_without('trio')
291 def test_autoawait_trio(self):
290 def test_autoawait_trio(self):
292 iprc("%autoawait trio")
291 iprc("%autoawait trio")
293
292
294 @skip_without('trio')
293 @skip_without('trio')
295 def test_autoawait_trio_wrong_sleep(self):
294 def test_autoawait_trio_wrong_sleep(self):
296 iprc("%autoawait trio")
295 iprc("%autoawait trio")
297 res = iprc_nr("""
296 res = iprc_nr("""
298 import asyncio
297 import asyncio
299 await asyncio.sleep(0)
298 await asyncio.sleep(0)
300 """)
299 """)
301 with nt.assert_raises(TypeError):
300 with self.assertRaises(TypeError):
302 res.raise_error()
301 res.raise_error()
303
302
304 @skip_without('trio')
303 @skip_without('trio')
305 def test_autoawait_asyncio_wrong_sleep(self):
304 def test_autoawait_asyncio_wrong_sleep(self):
306 iprc("%autoawait asyncio")
305 iprc("%autoawait asyncio")
307 res = iprc_nr("""
306 res = iprc_nr("""
308 import trio
307 import trio
309 await trio.sleep(0)
308 await trio.sleep(0)
310 """)
309 """)
311 with nt.assert_raises(RuntimeError):
310 with self.assertRaises(RuntimeError):
312 res.raise_error()
311 res.raise_error()
313
312
314
313
315 def tearDown(self):
314 def tearDown(self):
316 ip.loop_runner = "asyncio"
315 ip.loop_runner = "asyncio"
@@ -1,1278 +1,1274 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """Tests for the IPython tab-completion machinery."""
2 """Tests for the IPython tab-completion machinery."""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7 import os
7 import os
8 import sys
8 import sys
9 import textwrap
9 import textwrap
10 import unittest
10 import unittest
11
11
12 from contextlib import contextmanager
12 from contextlib import contextmanager
13
13
14 import nose.tools as nt
15
16 from traitlets.config.loader import Config
14 from traitlets.config.loader import Config
17 from IPython import get_ipython
15 from IPython import get_ipython
18 from IPython.core import completer
16 from IPython.core import completer
19 from IPython.external import decorators
17 from IPython.external import decorators
20 from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory
18 from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory
21 from IPython.utils.generics import complete_object
19 from IPython.utils.generics import complete_object
22 from IPython.testing import decorators as dec
20 from IPython.testing import decorators as dec
23
21
24 from IPython.core.completer import (
22 from IPython.core.completer import (
25 Completion,
23 Completion,
26 provisionalcompleter,
24 provisionalcompleter,
27 match_dict_keys,
25 match_dict_keys,
28 _deduplicate_completions,
26 _deduplicate_completions,
29 )
27 )
30 from nose.tools import assert_in, assert_not_in
31
28
32 # -----------------------------------------------------------------------------
29 # -----------------------------------------------------------------------------
33 # Test functions
30 # Test functions
34 # -----------------------------------------------------------------------------
31 # -----------------------------------------------------------------------------
35
32
36 def recompute_unicode_ranges():
33 def recompute_unicode_ranges():
37 """
34 """
38 utility to recompute the largest unicode range without any characters
35 utility to recompute the largest unicode range without any characters
39
36
40 use to recompute the gap in the global _UNICODE_RANGES of completer.py
37 use to recompute the gap in the global _UNICODE_RANGES of completer.py
41 """
38 """
42 import itertools
39 import itertools
43 import unicodedata
40 import unicodedata
44 valid = []
41 valid = []
45 for c in range(0,0x10FFFF + 1):
42 for c in range(0,0x10FFFF + 1):
46 try:
43 try:
47 unicodedata.name(chr(c))
44 unicodedata.name(chr(c))
48 except ValueError:
45 except ValueError:
49 continue
46 continue
50 valid.append(c)
47 valid.append(c)
51
48
52 def ranges(i):
49 def ranges(i):
53 for a, b in itertools.groupby(enumerate(i), lambda pair: pair[1] - pair[0]):
50 for a, b in itertools.groupby(enumerate(i), lambda pair: pair[1] - pair[0]):
54 b = list(b)
51 b = list(b)
55 yield b[0][1], b[-1][1]
52 yield b[0][1], b[-1][1]
56
53
57 rg = list(ranges(valid))
54 rg = list(ranges(valid))
58 lens = []
55 lens = []
59 gap_lens = []
56 gap_lens = []
60 pstart, pstop = 0,0
57 pstart, pstop = 0,0
61 for start, stop in rg:
58 for start, stop in rg:
62 lens.append(stop-start)
59 lens.append(stop-start)
63 gap_lens.append((start - pstop, hex(pstop), hex(start), f'{round((start - pstop)/0xe01f0*100)}%'))
60 gap_lens.append((start - pstop, hex(pstop), hex(start), f'{round((start - pstop)/0xe01f0*100)}%'))
64 pstart, pstop = start, stop
61 pstart, pstop = start, stop
65
62
66 return sorted(gap_lens)[-1]
63 return sorted(gap_lens)[-1]
67
64
68
65
69
66
70 def test_unicode_range():
67 def test_unicode_range():
71 """
68 """
72 Test that the ranges we test for unicode names give the same number of
69 Test that the ranges we test for unicode names give the same number of
73 results than testing the full length.
70 results than testing the full length.
74 """
71 """
75 from IPython.core.completer import _unicode_name_compute, _UNICODE_RANGES
72 from IPython.core.completer import _unicode_name_compute, _UNICODE_RANGES
76
73
77 expected_list = _unicode_name_compute([(0, 0x110000)])
74 expected_list = _unicode_name_compute([(0, 0x110000)])
78 test = _unicode_name_compute(_UNICODE_RANGES)
75 test = _unicode_name_compute(_UNICODE_RANGES)
79 len_exp = len(expected_list)
76 len_exp = len(expected_list)
80 len_test = len(test)
77 len_test = len(test)
81
78
82 # do not inline the len() or on error pytest will try to print the 130 000 +
79 # do not inline the len() or on error pytest will try to print the 130 000 +
83 # elements.
80 # elements.
84 message = None
81 message = None
85 if len_exp != len_test or len_exp > 131808:
82 if len_exp != len_test or len_exp > 131808:
86 size, start, stop, prct = recompute_unicode_ranges()
83 size, start, stop, prct = recompute_unicode_ranges()
87 message = f"""_UNICODE_RANGES likely wrong and need updating. This is
84 message = f"""_UNICODE_RANGES likely wrong and need updating. This is
88 likely due to a new release of Python. We've find that the biggest gap
85 likely due to a new release of Python. We've find that the biggest gap
89 in unicode characters has reduces in size to be {size} characters
86 in unicode characters has reduces in size to be {size} characters
90 ({prct}), from {start}, to {stop}. In completer.py likely update to
87 ({prct}), from {start}, to {stop}. In completer.py likely update to
91
88
92 _UNICODE_RANGES = [(32, {start}), ({stop}, 0xe01f0)]
89 _UNICODE_RANGES = [(32, {start}), ({stop}, 0xe01f0)]
93
90
94 And update the assertion below to use
91 And update the assertion below to use
95
92
96 len_exp <= {len_exp}
93 len_exp <= {len_exp}
97 """
94 """
98 assert len_exp == len_test, message
95 assert len_exp == len_test, message
99
96
100 # fail if new unicode symbols have been added.
97 # fail if new unicode symbols have been added.
101 assert len_exp <= 137714, message
98 assert len_exp <= 137714, message
102
99
103
100
104 @contextmanager
101 @contextmanager
105 def greedy_completion():
102 def greedy_completion():
106 ip = get_ipython()
103 ip = get_ipython()
107 greedy_original = ip.Completer.greedy
104 greedy_original = ip.Completer.greedy
108 try:
105 try:
109 ip.Completer.greedy = True
106 ip.Completer.greedy = True
110 yield
107 yield
111 finally:
108 finally:
112 ip.Completer.greedy = greedy_original
109 ip.Completer.greedy = greedy_original
113
110
114
111
115 def test_protect_filename():
112 def test_protect_filename():
116 if sys.platform == "win32":
113 if sys.platform == "win32":
117 pairs = [
114 pairs = [
118 ("abc", "abc"),
115 ("abc", "abc"),
119 (" abc", '" abc"'),
116 (" abc", '" abc"'),
120 ("a bc", '"a bc"'),
117 ("a bc", '"a bc"'),
121 ("a bc", '"a bc"'),
118 ("a bc", '"a bc"'),
122 (" bc", '" bc"'),
119 (" bc", '" bc"'),
123 ]
120 ]
124 else:
121 else:
125 pairs = [
122 pairs = [
126 ("abc", "abc"),
123 ("abc", "abc"),
127 (" abc", r"\ abc"),
124 (" abc", r"\ abc"),
128 ("a bc", r"a\ bc"),
125 ("a bc", r"a\ bc"),
129 ("a bc", r"a\ \ bc"),
126 ("a bc", r"a\ \ bc"),
130 (" bc", r"\ \ bc"),
127 (" bc", r"\ \ bc"),
131 # On posix, we also protect parens and other special characters.
128 # On posix, we also protect parens and other special characters.
132 ("a(bc", r"a\(bc"),
129 ("a(bc", r"a\(bc"),
133 ("a)bc", r"a\)bc"),
130 ("a)bc", r"a\)bc"),
134 ("a( )bc", r"a\(\ \)bc"),
131 ("a( )bc", r"a\(\ \)bc"),
135 ("a[1]bc", r"a\[1\]bc"),
132 ("a[1]bc", r"a\[1\]bc"),
136 ("a{1}bc", r"a\{1\}bc"),
133 ("a{1}bc", r"a\{1\}bc"),
137 ("a#bc", r"a\#bc"),
134 ("a#bc", r"a\#bc"),
138 ("a?bc", r"a\?bc"),
135 ("a?bc", r"a\?bc"),
139 ("a=bc", r"a\=bc"),
136 ("a=bc", r"a\=bc"),
140 ("a\\bc", r"a\\bc"),
137 ("a\\bc", r"a\\bc"),
141 ("a|bc", r"a\|bc"),
138 ("a|bc", r"a\|bc"),
142 ("a;bc", r"a\;bc"),
139 ("a;bc", r"a\;bc"),
143 ("a:bc", r"a\:bc"),
140 ("a:bc", r"a\:bc"),
144 ("a'bc", r"a\'bc"),
141 ("a'bc", r"a\'bc"),
145 ("a*bc", r"a\*bc"),
142 ("a*bc", r"a\*bc"),
146 ('a"bc', r"a\"bc"),
143 ('a"bc', r"a\"bc"),
147 ("a^bc", r"a\^bc"),
144 ("a^bc", r"a\^bc"),
148 ("a&bc", r"a\&bc"),
145 ("a&bc", r"a\&bc"),
149 ]
146 ]
150 # run the actual tests
147 # run the actual tests
151 for s1, s2 in pairs:
148 for s1, s2 in pairs:
152 s1p = completer.protect_filename(s1)
149 s1p = completer.protect_filename(s1)
153 nt.assert_equal(s1p, s2)
150 assert s1p == s2
154
151
155
152
156 def check_line_split(splitter, test_specs):
153 def check_line_split(splitter, test_specs):
157 for part1, part2, split in test_specs:
154 for part1, part2, split in test_specs:
158 cursor_pos = len(part1)
155 cursor_pos = len(part1)
159 line = part1 + part2
156 line = part1 + part2
160 out = splitter.split_line(line, cursor_pos)
157 out = splitter.split_line(line, cursor_pos)
161 nt.assert_equal(out, split)
158 assert out == split
162
159
163
160
164 def test_line_split():
161 def test_line_split():
165 """Basic line splitter test with default specs."""
162 """Basic line splitter test with default specs."""
166 sp = completer.CompletionSplitter()
163 sp = completer.CompletionSplitter()
167 # The format of the test specs is: part1, part2, expected answer. Parts 1
164 # The format of the test specs is: part1, part2, expected answer. Parts 1
168 # and 2 are joined into the 'line' sent to the splitter, as if the cursor
165 # and 2 are joined into the 'line' sent to the splitter, as if the cursor
169 # was at the end of part1. So an empty part2 represents someone hitting
166 # was at the end of part1. So an empty part2 represents someone hitting
170 # tab at the end of the line, the most common case.
167 # tab at the end of the line, the most common case.
171 t = [
168 t = [
172 ("run some/scrip", "", "some/scrip"),
169 ("run some/scrip", "", "some/scrip"),
173 ("run scripts/er", "ror.py foo", "scripts/er"),
170 ("run scripts/er", "ror.py foo", "scripts/er"),
174 ("echo $HOM", "", "HOM"),
171 ("echo $HOM", "", "HOM"),
175 ("print sys.pa", "", "sys.pa"),
172 ("print sys.pa", "", "sys.pa"),
176 ("print(sys.pa", "", "sys.pa"),
173 ("print(sys.pa", "", "sys.pa"),
177 ("execfile('scripts/er", "", "scripts/er"),
174 ("execfile('scripts/er", "", "scripts/er"),
178 ("a[x.", "", "x."),
175 ("a[x.", "", "x."),
179 ("a[x.", "y", "x."),
176 ("a[x.", "y", "x."),
180 ('cd "some_file/', "", "some_file/"),
177 ('cd "some_file/', "", "some_file/"),
181 ]
178 ]
182 check_line_split(sp, t)
179 check_line_split(sp, t)
183 # Ensure splitting works OK with unicode by re-running the tests with
180 # Ensure splitting works OK with unicode by re-running the tests with
184 # all inputs turned into unicode
181 # all inputs turned into unicode
185 check_line_split(sp, [map(str, p) for p in t])
182 check_line_split(sp, [map(str, p) for p in t])
186
183
187
184
188 class NamedInstanceMetaclass(type):
185 class NamedInstanceMetaclass(type):
189 def __getitem__(cls, item):
186 def __getitem__(cls, item):
190 return cls.get_instance(item)
187 return cls.get_instance(item)
191
188
192
189
193 class NamedInstanceClass(metaclass=NamedInstanceMetaclass):
190 class NamedInstanceClass(metaclass=NamedInstanceMetaclass):
194 def __init__(self, name):
191 def __init__(self, name):
195 if not hasattr(self.__class__, "instances"):
192 if not hasattr(self.__class__, "instances"):
196 self.__class__.instances = {}
193 self.__class__.instances = {}
197 self.__class__.instances[name] = self
194 self.__class__.instances[name] = self
198
195
199 @classmethod
196 @classmethod
200 def _ipython_key_completions_(cls):
197 def _ipython_key_completions_(cls):
201 return cls.instances.keys()
198 return cls.instances.keys()
202
199
203 @classmethod
200 @classmethod
204 def get_instance(cls, name):
201 def get_instance(cls, name):
205 return cls.instances[name]
202 return cls.instances[name]
206
203
207
204
208 class KeyCompletable:
205 class KeyCompletable:
209 def __init__(self, things=()):
206 def __init__(self, things=()):
210 self.things = things
207 self.things = things
211
208
212 def _ipython_key_completions_(self):
209 def _ipython_key_completions_(self):
213 return list(self.things)
210 return list(self.things)
214
211
215
212
216 class TestCompleter(unittest.TestCase):
213 class TestCompleter(unittest.TestCase):
217 def setUp(self):
214 def setUp(self):
218 """
215 """
219 We want to silence all PendingDeprecationWarning when testing the completer
216 We want to silence all PendingDeprecationWarning when testing the completer
220 """
217 """
221 self._assertwarns = self.assertWarns(PendingDeprecationWarning)
218 self._assertwarns = self.assertWarns(PendingDeprecationWarning)
222 self._assertwarns.__enter__()
219 self._assertwarns.__enter__()
223
220
224 def tearDown(self):
221 def tearDown(self):
225 try:
222 try:
226 self._assertwarns.__exit__(None, None, None)
223 self._assertwarns.__exit__(None, None, None)
227 except AssertionError:
224 except AssertionError:
228 pass
225 pass
229
226
230 def test_custom_completion_error(self):
227 def test_custom_completion_error(self):
231 """Test that errors from custom attribute completers are silenced."""
228 """Test that errors from custom attribute completers are silenced."""
232 ip = get_ipython()
229 ip = get_ipython()
233
230
234 class A:
231 class A:
235 pass
232 pass
236
233
237 ip.user_ns["x"] = A()
234 ip.user_ns["x"] = A()
238
235
239 @complete_object.register(A)
236 @complete_object.register(A)
240 def complete_A(a, existing_completions):
237 def complete_A(a, existing_completions):
241 raise TypeError("this should be silenced")
238 raise TypeError("this should be silenced")
242
239
243 ip.complete("x.")
240 ip.complete("x.")
244
241
245 def test_custom_completion_ordering(self):
242 def test_custom_completion_ordering(self):
246 """Test that errors from custom attribute completers are silenced."""
243 """Test that errors from custom attribute completers are silenced."""
247 ip = get_ipython()
244 ip = get_ipython()
248
245
249 _, matches = ip.complete('in')
246 _, matches = ip.complete('in')
250 assert matches.index('input') < matches.index('int')
247 assert matches.index('input') < matches.index('int')
251
248
252 def complete_example(a):
249 def complete_example(a):
253 return ['example2', 'example1']
250 return ['example2', 'example1']
254
251
255 ip.Completer.custom_completers.add_re('ex*', complete_example)
252 ip.Completer.custom_completers.add_re('ex*', complete_example)
256 _, matches = ip.complete('ex')
253 _, matches = ip.complete('ex')
257 assert matches.index('example2') < matches.index('example1')
254 assert matches.index('example2') < matches.index('example1')
258
255
259 def test_unicode_completions(self):
256 def test_unicode_completions(self):
260 ip = get_ipython()
257 ip = get_ipython()
261 # Some strings that trigger different types of completion. Check them both
258 # Some strings that trigger different types of completion. Check them both
262 # in str and unicode forms
259 # in str and unicode forms
263 s = ["ru", "%ru", "cd /", "floa", "float(x)/"]
260 s = ["ru", "%ru", "cd /", "floa", "float(x)/"]
264 for t in s + list(map(str, s)):
261 for t in s + list(map(str, s)):
265 # We don't need to check exact completion values (they may change
262 # We don't need to check exact completion values (they may change
266 # depending on the state of the namespace, but at least no exceptions
263 # depending on the state of the namespace, but at least no exceptions
267 # should be thrown and the return value should be a pair of text, list
264 # should be thrown and the return value should be a pair of text, list
268 # values.
265 # values.
269 text, matches = ip.complete(t)
266 text, matches = ip.complete(t)
270 nt.assert_true(isinstance(text, str))
267 self.assertIsInstance(text, str)
271 nt.assert_true(isinstance(matches, list))
268 self.assertIsInstance(matches, list)
272
269
273 def test_latex_completions(self):
270 def test_latex_completions(self):
274 from IPython.core.latex_symbols import latex_symbols
271 from IPython.core.latex_symbols import latex_symbols
275 import random
272 import random
276
273
277 ip = get_ipython()
274 ip = get_ipython()
278 # Test some random unicode symbols
275 # Test some random unicode symbols
279 keys = random.sample(latex_symbols.keys(), 10)
276 keys = random.sample(latex_symbols.keys(), 10)
280 for k in keys:
277 for k in keys:
281 text, matches = ip.complete(k)
278 text, matches = ip.complete(k)
282 nt.assert_equal(text, k)
279 self.assertEqual(text, k)
283 nt.assert_equal(matches, [latex_symbols[k]])
280 self.assertEqual(matches, [latex_symbols[k]])
284 # Test a more complex line
281 # Test a more complex line
285 text, matches = ip.complete("print(\\alpha")
282 text, matches = ip.complete("print(\\alpha")
286 nt.assert_equal(text, "\\alpha")
283 self.assertEqual(text, "\\alpha")
287 nt.assert_equal(matches[0], latex_symbols["\\alpha"])
284 self.assertEqual(matches[0], latex_symbols["\\alpha"])
288 # Test multiple matching latex symbols
285 # Test multiple matching latex symbols
289 text, matches = ip.complete("\\al")
286 text, matches = ip.complete("\\al")
290 nt.assert_in("\\alpha", matches)
287 self.assertIn("\\alpha", matches)
291 nt.assert_in("\\aleph", matches)
288 self.assertIn("\\aleph", matches)
292
289
293 def test_latex_no_results(self):
290 def test_latex_no_results(self):
294 """
291 """
295 forward latex should really return nothing in either field if nothing is found.
292 forward latex should really return nothing in either field if nothing is found.
296 """
293 """
297 ip = get_ipython()
294 ip = get_ipython()
298 text, matches = ip.Completer.latex_matches("\\really_i_should_match_nothing")
295 text, matches = ip.Completer.latex_matches("\\really_i_should_match_nothing")
299 nt.assert_equal(text, "")
296 self.assertEqual(text, "")
300 nt.assert_equal(matches, ())
297 self.assertEqual(matches, ())
301
298
302 def test_back_latex_completion(self):
299 def test_back_latex_completion(self):
303 ip = get_ipython()
300 ip = get_ipython()
304
301
305 # do not return more than 1 matches for \beta, only the latex one.
302 # do not return more than 1 matches for \beta, only the latex one.
306 name, matches = ip.complete("\\β")
303 name, matches = ip.complete("\\β")
307 nt.assert_equal(matches, ['\\beta'])
304 self.assertEqual(matches, ["\\beta"])
308
305
309 def test_back_unicode_completion(self):
306 def test_back_unicode_completion(self):
310 ip = get_ipython()
307 ip = get_ipython()
311
308
312 name, matches = ip.complete("\\Ⅴ")
309 name, matches = ip.complete("\\Ⅴ")
313 nt.assert_equal(matches, ("\\ROMAN NUMERAL FIVE",))
310 self.assertEqual(matches, ("\\ROMAN NUMERAL FIVE",))
314
311
315 def test_forward_unicode_completion(self):
312 def test_forward_unicode_completion(self):
316 ip = get_ipython()
313 ip = get_ipython()
317
314
318 name, matches = ip.complete("\\ROMAN NUMERAL FIVE")
315 name, matches = ip.complete("\\ROMAN NUMERAL FIVE")
319 nt.assert_equal(matches, ["Ⅴ"] ) # This is not a V
316 self.assertEqual(matches, ["Ⅴ"]) # This is not a V
320 nt.assert_equal(matches, ["\u2164"] ) # same as above but explicit.
317 self.assertEqual(matches, ["\u2164"]) # same as above but explicit.
321
318
322 @nt.nottest # now we have a completion for \jmath
319 @unittest.skip("now we have a completion for \jmath")
323 @decorators.knownfailureif(
320 @decorators.knownfailureif(
324 sys.platform == "win32", "Fails if there is a C:\\j... path"
321 sys.platform == "win32", "Fails if there is a C:\\j... path"
325 )
322 )
326 def test_no_ascii_back_completion(self):
323 def test_no_ascii_back_completion(self):
327 ip = get_ipython()
324 ip = get_ipython()
328 with TemporaryWorkingDirectory(): # Avoid any filename completions
325 with TemporaryWorkingDirectory(): # Avoid any filename completions
329 # single ascii letter that don't have yet completions
326 # single ascii letter that don't have yet completions
330 for letter in "jJ":
327 for letter in "jJ":
331 name, matches = ip.complete("\\" + letter)
328 name, matches = ip.complete("\\" + letter)
332 nt.assert_equal(matches, [])
329 self.assertEqual(matches, [])
333
330
334 class CompletionSplitterTestCase(unittest.TestCase):
331 class CompletionSplitterTestCase(unittest.TestCase):
335 def setUp(self):
332 def setUp(self):
336 self.sp = completer.CompletionSplitter()
333 self.sp = completer.CompletionSplitter()
337
334
338 def test_delim_setting(self):
335 def test_delim_setting(self):
339 self.sp.delims = " "
336 self.sp.delims = " "
340 nt.assert_equal(self.sp.delims, " ")
337 self.assertEqual(self.sp.delims, " ")
341 nt.assert_equal(self.sp._delim_expr, r"[\ ]")
338 self.assertEqual(self.sp._delim_expr, r"[\ ]")
342
339
343 def test_spaces(self):
340 def test_spaces(self):
344 """Test with only spaces as split chars."""
341 """Test with only spaces as split chars."""
345 self.sp.delims = " "
342 self.sp.delims = " "
346 t = [("foo", "", "foo"), ("run foo", "", "foo"), ("run foo", "bar", "foo")]
343 t = [("foo", "", "foo"), ("run foo", "", "foo"), ("run foo", "bar", "foo")]
347 check_line_split(self.sp, t)
344 check_line_split(self.sp, t)
348
345
349 def test_has_open_quotes1(self):
346 def test_has_open_quotes1(self):
350 for s in ["'", "'''", "'hi' '"]:
347 for s in ["'", "'''", "'hi' '"]:
351 nt.assert_equal(completer.has_open_quotes(s), "'")
348 self.assertEqual(completer.has_open_quotes(s), "'")
352
349
353 def test_has_open_quotes2(self):
350 def test_has_open_quotes2(self):
354 for s in ['"', '"""', '"hi" "']:
351 for s in ['"', '"""', '"hi" "']:
355 nt.assert_equal(completer.has_open_quotes(s), '"')
352 self.assertEqual(completer.has_open_quotes(s), '"')
356
353
357 def test_has_open_quotes3(self):
354 def test_has_open_quotes3(self):
358 for s in ["''", "''' '''", "'hi' 'ipython'"]:
355 for s in ["''", "''' '''", "'hi' 'ipython'"]:
359 nt.assert_false(completer.has_open_quotes(s))
356 self.assertFalse(completer.has_open_quotes(s))
360
357
361 def test_has_open_quotes4(self):
358 def test_has_open_quotes4(self):
362 for s in ['""', '""" """', '"hi" "ipython"']:
359 for s in ['""', '""" """', '"hi" "ipython"']:
363 nt.assert_false(completer.has_open_quotes(s))
360 self.assertFalse(completer.has_open_quotes(s))
364
361
365 @decorators.knownfailureif(
362 @decorators.knownfailureif(
366 sys.platform == "win32", "abspath completions fail on Windows"
363 sys.platform == "win32", "abspath completions fail on Windows"
367 )
364 )
368 def test_abspath_file_completions(self):
365 def test_abspath_file_completions(self):
369 ip = get_ipython()
366 ip = get_ipython()
370 with TemporaryDirectory() as tmpdir:
367 with TemporaryDirectory() as tmpdir:
371 prefix = os.path.join(tmpdir, "foo")
368 prefix = os.path.join(tmpdir, "foo")
372 suffixes = ["1", "2"]
369 suffixes = ["1", "2"]
373 names = [prefix + s for s in suffixes]
370 names = [prefix + s for s in suffixes]
374 for n in names:
371 for n in names:
375 open(n, "w").close()
372 open(n, "w").close()
376
373
377 # Check simple completion
374 # Check simple completion
378 c = ip.complete(prefix)[1]
375 c = ip.complete(prefix)[1]
379 nt.assert_equal(c, names)
376 self.assertEqual(c, names)
380
377
381 # Now check with a function call
378 # Now check with a function call
382 cmd = 'a = f("%s' % prefix
379 cmd = 'a = f("%s' % prefix
383 c = ip.complete(prefix, cmd)[1]
380 c = ip.complete(prefix, cmd)[1]
384 comp = [prefix + s for s in suffixes]
381 comp = [prefix + s for s in suffixes]
385 nt.assert_equal(c, comp)
382 self.assertEqual(c, comp)
386
383
387 def test_local_file_completions(self):
384 def test_local_file_completions(self):
388 ip = get_ipython()
385 ip = get_ipython()
389 with TemporaryWorkingDirectory():
386 with TemporaryWorkingDirectory():
390 prefix = "./foo"
387 prefix = "./foo"
391 suffixes = ["1", "2"]
388 suffixes = ["1", "2"]
392 names = [prefix + s for s in suffixes]
389 names = [prefix + s for s in suffixes]
393 for n in names:
390 for n in names:
394 open(n, "w").close()
391 open(n, "w").close()
395
392
396 # Check simple completion
393 # Check simple completion
397 c = ip.complete(prefix)[1]
394 c = ip.complete(prefix)[1]
398 nt.assert_equal(c, names)
395 self.assertEqual(c, names)
399
396
400 # Now check with a function call
397 # Now check with a function call
401 cmd = 'a = f("%s' % prefix
398 cmd = 'a = f("%s' % prefix
402 c = ip.complete(prefix, cmd)[1]
399 c = ip.complete(prefix, cmd)[1]
403 comp = {prefix + s for s in suffixes}
400 comp = {prefix + s for s in suffixes}
404 nt.assert_true(comp.issubset(set(c)))
401 self.assertTrue(comp.issubset(set(c)))
405
402
406 def test_quoted_file_completions(self):
403 def test_quoted_file_completions(self):
407 ip = get_ipython()
404 ip = get_ipython()
408 with TemporaryWorkingDirectory():
405 with TemporaryWorkingDirectory():
409 name = "foo'bar"
406 name = "foo'bar"
410 open(name, "w").close()
407 open(name, "w").close()
411
408
412 # Don't escape Windows
409 # Don't escape Windows
413 escaped = name if sys.platform == "win32" else "foo\\'bar"
410 escaped = name if sys.platform == "win32" else "foo\\'bar"
414
411
415 # Single quote matches embedded single quote
412 # Single quote matches embedded single quote
416 text = "open('foo"
413 text = "open('foo"
417 c = ip.Completer._complete(
414 c = ip.Completer._complete(
418 cursor_line=0, cursor_pos=len(text), full_text=text
415 cursor_line=0, cursor_pos=len(text), full_text=text
419 )[1]
416 )[1]
420 nt.assert_equal(c, [escaped])
417 self.assertEqual(c, [escaped])
421
418
422 # Double quote requires no escape
419 # Double quote requires no escape
423 text = 'open("foo'
420 text = 'open("foo'
424 c = ip.Completer._complete(
421 c = ip.Completer._complete(
425 cursor_line=0, cursor_pos=len(text), full_text=text
422 cursor_line=0, cursor_pos=len(text), full_text=text
426 )[1]
423 )[1]
427 nt.assert_equal(c, [name])
424 self.assertEqual(c, [name])
428
425
429 # No quote requires an escape
426 # No quote requires an escape
430 text = "%ls foo"
427 text = "%ls foo"
431 c = ip.Completer._complete(
428 c = ip.Completer._complete(
432 cursor_line=0, cursor_pos=len(text), full_text=text
429 cursor_line=0, cursor_pos=len(text), full_text=text
433 )[1]
430 )[1]
434 nt.assert_equal(c, [escaped])
431 self.assertEqual(c, [escaped])
435
432
436 def test_all_completions_dups(self):
433 def test_all_completions_dups(self):
437 """
434 """
438 Make sure the output of `IPCompleter.all_completions` does not have
435 Make sure the output of `IPCompleter.all_completions` does not have
439 duplicated prefixes.
436 duplicated prefixes.
440 """
437 """
441 ip = get_ipython()
438 ip = get_ipython()
442 c = ip.Completer
439 c = ip.Completer
443 ip.ex("class TestClass():\n\ta=1\n\ta1=2")
440 ip.ex("class TestClass():\n\ta=1\n\ta1=2")
444 for jedi_status in [True, False]:
441 for jedi_status in [True, False]:
445 with provisionalcompleter():
442 with provisionalcompleter():
446 ip.Completer.use_jedi = jedi_status
443 ip.Completer.use_jedi = jedi_status
447 matches = c.all_completions("TestCl")
444 matches = c.all_completions("TestCl")
448 assert matches == ['TestClass'], jedi_status
445 assert matches == ['TestClass'], jedi_status
449 matches = c.all_completions("TestClass.")
446 matches = c.all_completions("TestClass.")
450 assert len(matches) > 2, jedi_status
447 assert len(matches) > 2, jedi_status
451 matches = c.all_completions("TestClass.a")
448 matches = c.all_completions("TestClass.a")
452 assert matches == ['TestClass.a', 'TestClass.a1'], jedi_status
449 assert matches == ['TestClass.a', 'TestClass.a1'], jedi_status
453
450
454 def test_jedi(self):
451 def test_jedi(self):
455 """
452 """
456 A couple of issue we had with Jedi
453 A couple of issue we had with Jedi
457 """
454 """
458 ip = get_ipython()
455 ip = get_ipython()
459
456
460 def _test_complete(reason, s, comp, start=None, end=None):
457 def _test_complete(reason, s, comp, start=None, end=None):
461 l = len(s)
458 l = len(s)
462 start = start if start is not None else l
459 start = start if start is not None else l
463 end = end if end is not None else l
460 end = end if end is not None else l
464 with provisionalcompleter():
461 with provisionalcompleter():
465 ip.Completer.use_jedi = True
462 ip.Completer.use_jedi = True
466 completions = set(ip.Completer.completions(s, l))
463 completions = set(ip.Completer.completions(s, l))
467 ip.Completer.use_jedi = False
464 ip.Completer.use_jedi = False
468 assert_in(Completion(start, end, comp), completions, reason)
465 assert_in(Completion(start, end, comp), completions, reason)
469
466
470 def _test_not_complete(reason, s, comp):
467 def _test_not_complete(reason, s, comp):
471 l = len(s)
468 l = len(s)
472 with provisionalcompleter():
469 with provisionalcompleter():
473 ip.Completer.use_jedi = True
470 ip.Completer.use_jedi = True
474 completions = set(ip.Completer.completions(s, l))
471 completions = set(ip.Completer.completions(s, l))
475 ip.Completer.use_jedi = False
472 ip.Completer.use_jedi = False
476 assert_not_in(Completion(l, l, comp), completions, reason)
473 assert_not_in(Completion(l, l, comp), completions, reason)
477
474
478 import jedi
475 import jedi
479
476
480 jedi_version = tuple(int(i) for i in jedi.__version__.split(".")[:3])
477 jedi_version = tuple(int(i) for i in jedi.__version__.split(".")[:3])
481 if jedi_version > (0, 10):
478 if jedi_version > (0, 10):
482 yield _test_complete, "jedi >0.9 should complete and not crash", "a=1;a.", "real"
479 yield _test_complete, "jedi >0.9 should complete and not crash", "a=1;a.", "real"
483 yield _test_complete, "can infer first argument", 'a=(1,"foo");a[0].', "real"
480 yield _test_complete, "can infer first argument", 'a=(1,"foo");a[0].', "real"
484 yield _test_complete, "can infer second argument", 'a=(1,"foo");a[1].', "capitalize"
481 yield _test_complete, "can infer second argument", 'a=(1,"foo");a[1].', "capitalize"
485 yield _test_complete, "cover duplicate completions", "im", "import", 0, 2
482 yield _test_complete, "cover duplicate completions", "im", "import", 0, 2
486
483
487 yield _test_not_complete, "does not mix types", 'a=(1,"foo");a[0].', "capitalize"
484 yield _test_not_complete, "does not mix types", 'a=(1,"foo");a[0].', "capitalize"
488
485
489 def test_completion_have_signature(self):
486 def test_completion_have_signature(self):
490 """
487 """
491 Lets make sure jedi is capable of pulling out the signature of the function we are completing.
488 Lets make sure jedi is capable of pulling out the signature of the function we are completing.
492 """
489 """
493 ip = get_ipython()
490 ip = get_ipython()
494 with provisionalcompleter():
491 with provisionalcompleter():
495 ip.Completer.use_jedi = True
492 ip.Completer.use_jedi = True
496 completions = ip.Completer.completions("ope", 3)
493 completions = ip.Completer.completions("ope", 3)
497 c = next(completions) # should be `open`
494 c = next(completions) # should be `open`
498 ip.Completer.use_jedi = False
495 ip.Completer.use_jedi = False
499 assert "file" in c.signature, "Signature of function was not found by completer"
496 assert "file" in c.signature, "Signature of function was not found by completer"
500 assert (
497 assert (
501 "encoding" in c.signature
498 "encoding" in c.signature
502 ), "Signature of function was not found by completer"
499 ), "Signature of function was not found by completer"
503
500
504 def test_deduplicate_completions(self):
501 def test_deduplicate_completions(self):
505 """
502 """
506 Test that completions are correctly deduplicated (even if ranges are not the same)
503 Test that completions are correctly deduplicated (even if ranges are not the same)
507 """
504 """
508 ip = get_ipython()
505 ip = get_ipython()
509 ip.ex(
506 ip.ex(
510 textwrap.dedent(
507 textwrap.dedent(
511 """
508 """
512 class Z:
509 class Z:
513 zoo = 1
510 zoo = 1
514 """
511 """
515 )
512 )
516 )
513 )
517 with provisionalcompleter():
514 with provisionalcompleter():
518 ip.Completer.use_jedi = True
515 ip.Completer.use_jedi = True
519 l = list(
516 l = list(
520 _deduplicate_completions("Z.z", ip.Completer.completions("Z.z", 3))
517 _deduplicate_completions("Z.z", ip.Completer.completions("Z.z", 3))
521 )
518 )
522 ip.Completer.use_jedi = False
519 ip.Completer.use_jedi = False
523
520
524 assert len(l) == 1, "Completions (Z.z<tab>) correctly deduplicate: %s " % l
521 assert len(l) == 1, "Completions (Z.z<tab>) correctly deduplicate: %s " % l
525 assert l[0].text == "zoo" # and not `it.accumulate`
522 assert l[0].text == "zoo" # and not `it.accumulate`
526
523
527 def test_greedy_completions(self):
524 def test_greedy_completions(self):
528 """
525 """
529 Test the capability of the Greedy completer.
526 Test the capability of the Greedy completer.
530
527
531 Most of the test here does not really show off the greedy completer, for proof
528 Most of the test here does not really show off the greedy completer, for proof
532 each of the text below now pass with Jedi. The greedy completer is capable of more.
529 each of the text below now pass with Jedi. The greedy completer is capable of more.
533
530
534 See the :any:`test_dict_key_completion_contexts`
531 See the :any:`test_dict_key_completion_contexts`
535
532
536 """
533 """
537 ip = get_ipython()
534 ip = get_ipython()
538 ip.ex("a=list(range(5))")
535 ip.ex("a=list(range(5))")
539 _, c = ip.complete(".", line="a[0].")
536 _, c = ip.complete(".", line="a[0].")
540 nt.assert_false(".real" in c, "Shouldn't have completed on a[0]: %s" % c)
537 self.assertFalse(".real" in c, "Shouldn't have completed on a[0]: %s" % c)
541
538
542 def _(line, cursor_pos, expect, message, completion):
539 def _(line, cursor_pos, expect, message, completion):
543 with greedy_completion(), provisionalcompleter():
540 with greedy_completion(), provisionalcompleter():
544 ip.Completer.use_jedi = False
541 ip.Completer.use_jedi = False
545 _, c = ip.complete(".", line=line, cursor_pos=cursor_pos)
542 _, c = ip.complete(".", line=line, cursor_pos=cursor_pos)
546 nt.assert_in(expect, c, message % c)
543 self.assertIn(expect, c, message % c)
547
544
548 ip.Completer.use_jedi = True
545 ip.Completer.use_jedi = True
549 with provisionalcompleter():
546 with provisionalcompleter():
550 completions = ip.Completer.completions(line, cursor_pos)
547 completions = ip.Completer.completions(line, cursor_pos)
551 nt.assert_in(completion, completions)
548 self.assertIn(completion, completions)
552
549
553 with provisionalcompleter():
550 with provisionalcompleter():
554 yield _, "a[0].", 5, "a[0].real", "Should have completed on a[0].: %s", Completion(
551 yield _, "a[0].", 5, "a[0].real", "Should have completed on a[0].: %s", Completion(
555 5, 5, "real"
552 5, 5, "real"
556 )
553 )
557 yield _, "a[0].r", 6, "a[0].real", "Should have completed on a[0].r: %s", Completion(
554 yield _, "a[0].r", 6, "a[0].real", "Should have completed on a[0].r: %s", Completion(
558 5, 6, "real"
555 5, 6, "real"
559 )
556 )
560
557
561 yield _, "a[0].from_", 10, "a[0].from_bytes", "Should have completed on a[0].from_: %s", Completion(
558 yield _, "a[0].from_", 10, "a[0].from_bytes", "Should have completed on a[0].from_: %s", Completion(
562 5, 10, "from_bytes"
559 5, 10, "from_bytes"
563 )
560 )
564
561
565 def test_omit__names(self):
562 def test_omit__names(self):
566 # also happens to test IPCompleter as a configurable
563 # also happens to test IPCompleter as a configurable
567 ip = get_ipython()
564 ip = get_ipython()
568 ip._hidden_attr = 1
565 ip._hidden_attr = 1
569 ip._x = {}
566 ip._x = {}
570 c = ip.Completer
567 c = ip.Completer
571 ip.ex("ip=get_ipython()")
568 ip.ex("ip=get_ipython()")
572 cfg = Config()
569 cfg = Config()
573 cfg.IPCompleter.omit__names = 0
570 cfg.IPCompleter.omit__names = 0
574 c.update_config(cfg)
571 c.update_config(cfg)
575 with provisionalcompleter():
572 with provisionalcompleter():
576 c.use_jedi = False
573 c.use_jedi = False
577 s, matches = c.complete("ip.")
574 s, matches = c.complete("ip.")
578 nt.assert_in("ip.__str__", matches)
575 self.assertIn("ip.__str__", matches)
579 nt.assert_in("ip._hidden_attr", matches)
576 self.assertIn("ip._hidden_attr", matches)
580
577
581 # c.use_jedi = True
578 # c.use_jedi = True
582 # completions = set(c.completions('ip.', 3))
579 # completions = set(c.completions('ip.', 3))
583 # nt.assert_in(Completion(3, 3, '__str__'), completions)
580 # self.assertIn(Completion(3, 3, '__str__'), completions)
584 # nt.assert_in(Completion(3,3, "_hidden_attr"), completions)
581 # self.assertIn(Completion(3,3, "_hidden_attr"), completions)
585
582
586 cfg = Config()
583 cfg = Config()
587 cfg.IPCompleter.omit__names = 1
584 cfg.IPCompleter.omit__names = 1
588 c.update_config(cfg)
585 c.update_config(cfg)
589 with provisionalcompleter():
586 with provisionalcompleter():
590 c.use_jedi = False
587 c.use_jedi = False
591 s, matches = c.complete("ip.")
588 s, matches = c.complete("ip.")
592 nt.assert_not_in("ip.__str__", matches)
589 self.assertNotIn("ip.__str__", matches)
593 # nt.assert_in('ip._hidden_attr', matches)
590 # self.assertIn('ip._hidden_attr', matches)
594
591
595 # c.use_jedi = True
592 # c.use_jedi = True
596 # completions = set(c.completions('ip.', 3))
593 # completions = set(c.completions('ip.', 3))
597 # nt.assert_not_in(Completion(3,3,'__str__'), completions)
594 # self.assertNotIn(Completion(3,3,'__str__'), completions)
598 # nt.assert_in(Completion(3,3, "_hidden_attr"), completions)
595 # self.assertIn(Completion(3,3, "_hidden_attr"), completions)
599
596
600 cfg = Config()
597 cfg = Config()
601 cfg.IPCompleter.omit__names = 2
598 cfg.IPCompleter.omit__names = 2
602 c.update_config(cfg)
599 c.update_config(cfg)
603 with provisionalcompleter():
600 with provisionalcompleter():
604 c.use_jedi = False
601 c.use_jedi = False
605 s, matches = c.complete("ip.")
602 s, matches = c.complete("ip.")
606 nt.assert_not_in("ip.__str__", matches)
603 self.assertNotIn("ip.__str__", matches)
607 nt.assert_not_in("ip._hidden_attr", matches)
604 self.assertNotIn("ip._hidden_attr", matches)
608
605
609 # c.use_jedi = True
606 # c.use_jedi = True
610 # completions = set(c.completions('ip.', 3))
607 # completions = set(c.completions('ip.', 3))
611 # nt.assert_not_in(Completion(3,3,'__str__'), completions)
608 # self.assertNotIn(Completion(3,3,'__str__'), completions)
612 # nt.assert_not_in(Completion(3,3, "_hidden_attr"), completions)
609 # self.assertNotIn(Completion(3,3, "_hidden_attr"), completions)
613
610
614 with provisionalcompleter():
611 with provisionalcompleter():
615 c.use_jedi = False
612 c.use_jedi = False
616 s, matches = c.complete("ip._x.")
613 s, matches = c.complete("ip._x.")
617 nt.assert_in("ip._x.keys", matches)
614 self.assertIn("ip._x.keys", matches)
618
615
619 # c.use_jedi = True
616 # c.use_jedi = True
620 # completions = set(c.completions('ip._x.', 6))
617 # completions = set(c.completions('ip._x.', 6))
621 # nt.assert_in(Completion(6,6, "keys"), completions)
618 # self.assertIn(Completion(6,6, "keys"), completions)
622
619
623 del ip._hidden_attr
620 del ip._hidden_attr
624 del ip._x
621 del ip._x
625
622
626 def test_limit_to__all__False_ok(self):
623 def test_limit_to__all__False_ok(self):
627 """
624 """
628 Limit to all is deprecated, once we remove it this test can go away.
625 Limit to all is deprecated, once we remove it this test can go away.
629 """
626 """
630 ip = get_ipython()
627 ip = get_ipython()
631 c = ip.Completer
628 c = ip.Completer
632 c.use_jedi = False
629 c.use_jedi = False
633 ip.ex("class D: x=24")
630 ip.ex("class D: x=24")
634 ip.ex("d=D()")
631 ip.ex("d=D()")
635 cfg = Config()
632 cfg = Config()
636 cfg.IPCompleter.limit_to__all__ = False
633 cfg.IPCompleter.limit_to__all__ = False
637 c.update_config(cfg)
634 c.update_config(cfg)
638 s, matches = c.complete("d.")
635 s, matches = c.complete("d.")
639 nt.assert_in("d.x", matches)
636 self.assertIn("d.x", matches)
640
637
641 def test_get__all__entries_ok(self):
638 def test_get__all__entries_ok(self):
642 class A:
639 class A:
643 __all__ = ["x", 1]
640 __all__ = ["x", 1]
644
641
645 words = completer.get__all__entries(A())
642 words = completer.get__all__entries(A())
646 nt.assert_equal(words, ["x"])
643 self.assertEqual(words, ["x"])
647
644
648 def test_get__all__entries_no__all__ok(self):
645 def test_get__all__entries_no__all__ok(self):
649 class A:
646 class A:
650 pass
647 pass
651
648
652 words = completer.get__all__entries(A())
649 words = completer.get__all__entries(A())
653 nt.assert_equal(words, [])
650 self.assertEqual(words, [])
654
651
655 def test_func_kw_completions(self):
652 def test_func_kw_completions(self):
656 ip = get_ipython()
653 ip = get_ipython()
657 c = ip.Completer
654 c = ip.Completer
658 c.use_jedi = False
655 c.use_jedi = False
659 ip.ex("def myfunc(a=1,b=2): return a+b")
656 ip.ex("def myfunc(a=1,b=2): return a+b")
660 s, matches = c.complete(None, "myfunc(1,b")
657 s, matches = c.complete(None, "myfunc(1,b")
661 nt.assert_in("b=", matches)
658 self.assertIn("b=", matches)
662 # Simulate completing with cursor right after b (pos==10):
659 # Simulate completing with cursor right after b (pos==10):
663 s, matches = c.complete(None, "myfunc(1,b)", 10)
660 s, matches = c.complete(None, "myfunc(1,b)", 10)
664 nt.assert_in("b=", matches)
661 self.assertIn("b=", matches)
665 s, matches = c.complete(None, 'myfunc(a="escaped\\")string",b')
662 s, matches = c.complete(None, 'myfunc(a="escaped\\")string",b')
666 nt.assert_in("b=", matches)
663 self.assertIn("b=", matches)
667 # builtin function
664 # builtin function
668 s, matches = c.complete(None, "min(k, k")
665 s, matches = c.complete(None, "min(k, k")
669 nt.assert_in("key=", matches)
666 self.assertIn("key=", matches)
670
667
671 def test_default_arguments_from_docstring(self):
668 def test_default_arguments_from_docstring(self):
672 ip = get_ipython()
669 ip = get_ipython()
673 c = ip.Completer
670 c = ip.Completer
674 kwd = c._default_arguments_from_docstring("min(iterable[, key=func]) -> value")
671 kwd = c._default_arguments_from_docstring("min(iterable[, key=func]) -> value")
675 nt.assert_equal(kwd, ["key"])
672 self.assertEqual(kwd, ["key"])
676 # with cython type etc
673 # with cython type etc
677 kwd = c._default_arguments_from_docstring(
674 kwd = c._default_arguments_from_docstring(
678 "Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)\n"
675 "Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)\n"
679 )
676 )
680 nt.assert_equal(kwd, ["ncall", "resume", "nsplit"])
677 self.assertEqual(kwd, ["ncall", "resume", "nsplit"])
681 # white spaces
678 # white spaces
682 kwd = c._default_arguments_from_docstring(
679 kwd = c._default_arguments_from_docstring(
683 "\n Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)\n"
680 "\n Minuit.migrad(self, int ncall=10000, resume=True, int nsplit=1)\n"
684 )
681 )
685 nt.assert_equal(kwd, ["ncall", "resume", "nsplit"])
682 self.assertEqual(kwd, ["ncall", "resume", "nsplit"])
686
683
687 def test_line_magics(self):
684 def test_line_magics(self):
688 ip = get_ipython()
685 ip = get_ipython()
689 c = ip.Completer
686 c = ip.Completer
690 s, matches = c.complete(None, "lsmag")
687 s, matches = c.complete(None, "lsmag")
691 nt.assert_in("%lsmagic", matches)
688 self.assertIn("%lsmagic", matches)
692 s, matches = c.complete(None, "%lsmag")
689 s, matches = c.complete(None, "%lsmag")
693 nt.assert_in("%lsmagic", matches)
690 self.assertIn("%lsmagic", matches)
694
691
695 def test_cell_magics(self):
692 def test_cell_magics(self):
696 from IPython.core.magic import register_cell_magic
693 from IPython.core.magic import register_cell_magic
697
694
698 @register_cell_magic
695 @register_cell_magic
699 def _foo_cellm(line, cell):
696 def _foo_cellm(line, cell):
700 pass
697 pass
701
698
702 ip = get_ipython()
699 ip = get_ipython()
703 c = ip.Completer
700 c = ip.Completer
704
701
705 s, matches = c.complete(None, "_foo_ce")
702 s, matches = c.complete(None, "_foo_ce")
706 nt.assert_in("%%_foo_cellm", matches)
703 self.assertIn("%%_foo_cellm", matches)
707 s, matches = c.complete(None, "%%_foo_ce")
704 s, matches = c.complete(None, "%%_foo_ce")
708 nt.assert_in("%%_foo_cellm", matches)
705 self.assertIn("%%_foo_cellm", matches)
709
706
710 def test_line_cell_magics(self):
707 def test_line_cell_magics(self):
711 from IPython.core.magic import register_line_cell_magic
708 from IPython.core.magic import register_line_cell_magic
712
709
713 @register_line_cell_magic
710 @register_line_cell_magic
714 def _bar_cellm(line, cell):
711 def _bar_cellm(line, cell):
715 pass
712 pass
716
713
717 ip = get_ipython()
714 ip = get_ipython()
718 c = ip.Completer
715 c = ip.Completer
719
716
720 # The policy here is trickier, see comments in completion code. The
717 # The policy here is trickier, see comments in completion code. The
721 # returned values depend on whether the user passes %% or not explicitly,
718 # returned values depend on whether the user passes %% or not explicitly,
722 # and this will show a difference if the same name is both a line and cell
719 # and this will show a difference if the same name is both a line and cell
723 # magic.
720 # magic.
724 s, matches = c.complete(None, "_bar_ce")
721 s, matches = c.complete(None, "_bar_ce")
725 nt.assert_in("%_bar_cellm", matches)
722 self.assertIn("%_bar_cellm", matches)
726 nt.assert_in("%%_bar_cellm", matches)
723 self.assertIn("%%_bar_cellm", matches)
727 s, matches = c.complete(None, "%_bar_ce")
724 s, matches = c.complete(None, "%_bar_ce")
728 nt.assert_in("%_bar_cellm", matches)
725 self.assertIn("%_bar_cellm", matches)
729 nt.assert_in("%%_bar_cellm", matches)
726 self.assertIn("%%_bar_cellm", matches)
730 s, matches = c.complete(None, "%%_bar_ce")
727 s, matches = c.complete(None, "%%_bar_ce")
731 nt.assert_not_in("%_bar_cellm", matches)
728 self.assertNotIn("%_bar_cellm", matches)
732 nt.assert_in("%%_bar_cellm", matches)
729 self.assertIn("%%_bar_cellm", matches)
733
730
734 def test_magic_completion_order(self):
731 def test_magic_completion_order(self):
735 ip = get_ipython()
732 ip = get_ipython()
736 c = ip.Completer
733 c = ip.Completer
737
734
738 # Test ordering of line and cell magics.
735 # Test ordering of line and cell magics.
739 text, matches = c.complete("timeit")
736 text, matches = c.complete("timeit")
740 nt.assert_equal(matches, ["%timeit", "%%timeit"])
737 self.assertEqual(matches, ["%timeit", "%%timeit"])
741
738
742 def test_magic_completion_shadowing(self):
739 def test_magic_completion_shadowing(self):
743 ip = get_ipython()
740 ip = get_ipython()
744 c = ip.Completer
741 c = ip.Completer
745 c.use_jedi = False
742 c.use_jedi = False
746
743
747 # Before importing matplotlib, %matplotlib magic should be the only option.
744 # Before importing matplotlib, %matplotlib magic should be the only option.
748 text, matches = c.complete("mat")
745 text, matches = c.complete("mat")
749 nt.assert_equal(matches, ["%matplotlib"])
746 self.assertEqual(matches, ["%matplotlib"])
750
747
751 # The newly introduced name should shadow the magic.
748 # The newly introduced name should shadow the magic.
752 ip.run_cell("matplotlib = 1")
749 ip.run_cell("matplotlib = 1")
753 text, matches = c.complete("mat")
750 text, matches = c.complete("mat")
754 nt.assert_equal(matches, ["matplotlib"])
751 self.assertEqual(matches, ["matplotlib"])
755
752
756 # After removing matplotlib from namespace, the magic should again be
753 # After removing matplotlib from namespace, the magic should again be
757 # the only option.
754 # the only option.
758 del ip.user_ns["matplotlib"]
755 del ip.user_ns["matplotlib"]
759 text, matches = c.complete("mat")
756 text, matches = c.complete("mat")
760 nt.assert_equal(matches, ["%matplotlib"])
757 self.assertEqual(matches, ["%matplotlib"])
761
758
762 def test_magic_completion_shadowing_explicit(self):
759 def test_magic_completion_shadowing_explicit(self):
763 """
760 """
764 If the user try to complete a shadowed magic, and explicit % start should
761 If the user try to complete a shadowed magic, and explicit % start should
765 still return the completions.
762 still return the completions.
766 """
763 """
767 ip = get_ipython()
764 ip = get_ipython()
768 c = ip.Completer
765 c = ip.Completer
769
766
770 # Before importing matplotlib, %matplotlib magic should be the only option.
767 # Before importing matplotlib, %matplotlib magic should be the only option.
771 text, matches = c.complete("%mat")
768 text, matches = c.complete("%mat")
772 nt.assert_equal(matches, ["%matplotlib"])
769 self.assertEqual(matches, ["%matplotlib"])
773
770
774 ip.run_cell("matplotlib = 1")
771 ip.run_cell("matplotlib = 1")
775
772
776 # After removing matplotlib from namespace, the magic should still be
773 # After removing matplotlib from namespace, the magic should still be
777 # the only option.
774 # the only option.
778 text, matches = c.complete("%mat")
775 text, matches = c.complete("%mat")
779 nt.assert_equal(matches, ["%matplotlib"])
776 self.assertEqual(matches, ["%matplotlib"])
780
777
781 def test_magic_config(self):
778 def test_magic_config(self):
782 ip = get_ipython()
779 ip = get_ipython()
783 c = ip.Completer
780 c = ip.Completer
784
781
785 s, matches = c.complete(None, "conf")
782 s, matches = c.complete(None, "conf")
786 nt.assert_in("%config", matches)
783 self.assertIn("%config", matches)
787 s, matches = c.complete(None, "conf")
784 s, matches = c.complete(None, "conf")
788 nt.assert_not_in("AliasManager", matches)
785 self.assertNotIn("AliasManager", matches)
789 s, matches = c.complete(None, "config ")
786 s, matches = c.complete(None, "config ")
790 nt.assert_in("AliasManager", matches)
787 self.assertIn("AliasManager", matches)
791 s, matches = c.complete(None, "%config ")
788 s, matches = c.complete(None, "%config ")
792 nt.assert_in("AliasManager", matches)
789 self.assertIn("AliasManager", matches)
793 s, matches = c.complete(None, "config Ali")
790 s, matches = c.complete(None, "config Ali")
794 nt.assert_list_equal(["AliasManager"], matches)
791 self.assertListEqual(["AliasManager"], matches)
795 s, matches = c.complete(None, "%config Ali")
792 s, matches = c.complete(None, "%config Ali")
796 nt.assert_list_equal(["AliasManager"], matches)
793 self.assertListEqual(["AliasManager"], matches)
797 s, matches = c.complete(None, "config AliasManager")
794 s, matches = c.complete(None, "config AliasManager")
798 nt.assert_list_equal(["AliasManager"], matches)
795 self.assertListEqual(["AliasManager"], matches)
799 s, matches = c.complete(None, "%config AliasManager")
796 s, matches = c.complete(None, "%config AliasManager")
800 nt.assert_list_equal(["AliasManager"], matches)
797 self.assertListEqual(["AliasManager"], matches)
801 s, matches = c.complete(None, "config AliasManager.")
798 s, matches = c.complete(None, "config AliasManager.")
802 nt.assert_in("AliasManager.default_aliases", matches)
799 self.assertIn("AliasManager.default_aliases", matches)
803 s, matches = c.complete(None, "%config AliasManager.")
800 s, matches = c.complete(None, "%config AliasManager.")
804 nt.assert_in("AliasManager.default_aliases", matches)
801 self.assertIn("AliasManager.default_aliases", matches)
805 s, matches = c.complete(None, "config AliasManager.de")
802 s, matches = c.complete(None, "config AliasManager.de")
806 nt.assert_list_equal(["AliasManager.default_aliases"], matches)
803 self.assertListEqual(["AliasManager.default_aliases"], matches)
807 s, matches = c.complete(None, "config AliasManager.de")
804 s, matches = c.complete(None, "config AliasManager.de")
808 nt.assert_list_equal(["AliasManager.default_aliases"], matches)
805 self.assertListEqual(["AliasManager.default_aliases"], matches)
809
806
810 def test_magic_color(self):
807 def test_magic_color(self):
811 ip = get_ipython()
808 ip = get_ipython()
812 c = ip.Completer
809 c = ip.Completer
813
810
814 s, matches = c.complete(None, "colo")
811 s, matches = c.complete(None, "colo")
815 nt.assert_in("%colors", matches)
812 self.assertIn("%colors", matches)
816 s, matches = c.complete(None, "colo")
813 s, matches = c.complete(None, "colo")
817 nt.assert_not_in("NoColor", matches)
814 self.assertNotIn("NoColor", matches)
818 s, matches = c.complete(None, "%colors") # No trailing space
815 s, matches = c.complete(None, "%colors") # No trailing space
819 nt.assert_not_in("NoColor", matches)
816 self.assertNotIn("NoColor", matches)
820 s, matches = c.complete(None, "colors ")
817 s, matches = c.complete(None, "colors ")
821 nt.assert_in("NoColor", matches)
818 self.assertIn("NoColor", matches)
822 s, matches = c.complete(None, "%colors ")
819 s, matches = c.complete(None, "%colors ")
823 nt.assert_in("NoColor", matches)
820 self.assertIn("NoColor", matches)
824 s, matches = c.complete(None, "colors NoCo")
821 s, matches = c.complete(None, "colors NoCo")
825 nt.assert_list_equal(["NoColor"], matches)
822 self.assertListEqual(["NoColor"], matches)
826 s, matches = c.complete(None, "%colors NoCo")
823 s, matches = c.complete(None, "%colors NoCo")
827 nt.assert_list_equal(["NoColor"], matches)
824 self.assertListEqual(["NoColor"], matches)
828
825
829 def test_match_dict_keys(self):
826 def test_match_dict_keys(self):
830 """
827 """
831 Test that match_dict_keys works on a couple of use case does return what
828 Test that match_dict_keys works on a couple of use case does return what
832 expected, and does not crash
829 expected, and does not crash
833 """
830 """
834 delims = " \t\n`!@#$^&*()=+[{]}\\|;:'\",<>?"
831 delims = " \t\n`!@#$^&*()=+[{]}\\|;:'\",<>?"
835
832
836 keys = ["foo", b"far"]
833 keys = ["foo", b"far"]
837 assert match_dict_keys(keys, "b'", delims=delims) == ("'", 2, ["far"])
834 assert match_dict_keys(keys, "b'", delims=delims) == ("'", 2, ["far"])
838 assert match_dict_keys(keys, "b'f", delims=delims) == ("'", 2, ["far"])
835 assert match_dict_keys(keys, "b'f", delims=delims) == ("'", 2, ["far"])
839 assert match_dict_keys(keys, 'b"', delims=delims) == ('"', 2, ["far"])
836 assert match_dict_keys(keys, 'b"', delims=delims) == ('"', 2, ["far"])
840 assert match_dict_keys(keys, 'b"f', delims=delims) == ('"', 2, ["far"])
837 assert match_dict_keys(keys, 'b"f', delims=delims) == ('"', 2, ["far"])
841
838
842 assert match_dict_keys(keys, "'", delims=delims) == ("'", 1, ["foo"])
839 assert match_dict_keys(keys, "'", delims=delims) == ("'", 1, ["foo"])
843 assert match_dict_keys(keys, "'f", delims=delims) == ("'", 1, ["foo"])
840 assert match_dict_keys(keys, "'f", delims=delims) == ("'", 1, ["foo"])
844 assert match_dict_keys(keys, '"', delims=delims) == ('"', 1, ["foo"])
841 assert match_dict_keys(keys, '"', delims=delims) == ('"', 1, ["foo"])
845 assert match_dict_keys(keys, '"f', delims=delims) == ('"', 1, ["foo"])
842 assert match_dict_keys(keys, '"f', delims=delims) == ('"', 1, ["foo"])
846
843
847 match_dict_keys
844 match_dict_keys
848
845
849 def test_match_dict_keys_tuple(self):
846 def test_match_dict_keys_tuple(self):
850 """
847 """
851 Test that match_dict_keys called with extra prefix works on a couple of use case,
848 Test that match_dict_keys called with extra prefix works on a couple of use case,
852 does return what expected, and does not crash.
849 does return what expected, and does not crash.
853 """
850 """
854 delims = " \t\n`!@#$^&*()=+[{]}\\|;:'\",<>?"
851 delims = " \t\n`!@#$^&*()=+[{]}\\|;:'\",<>?"
855
852
856 keys = [("foo", "bar"), ("foo", "oof"), ("foo", b"bar"), ('other', 'test')]
853 keys = [("foo", "bar"), ("foo", "oof"), ("foo", b"bar"), ('other', 'test')]
857
854
858 # Completion on first key == "foo"
855 # Completion on first key == "foo"
859 assert match_dict_keys(keys, "'", delims=delims, extra_prefix=("foo",)) == ("'", 1, ["bar", "oof"])
856 assert match_dict_keys(keys, "'", delims=delims, extra_prefix=("foo",)) == ("'", 1, ["bar", "oof"])
860 assert match_dict_keys(keys, "\"", delims=delims, extra_prefix=("foo",)) == ("\"", 1, ["bar", "oof"])
857 assert match_dict_keys(keys, "\"", delims=delims, extra_prefix=("foo",)) == ("\"", 1, ["bar", "oof"])
861 assert match_dict_keys(keys, "'o", delims=delims, extra_prefix=("foo",)) == ("'", 1, ["oof"])
858 assert match_dict_keys(keys, "'o", delims=delims, extra_prefix=("foo",)) == ("'", 1, ["oof"])
862 assert match_dict_keys(keys, "\"o", delims=delims, extra_prefix=("foo",)) == ("\"", 1, ["oof"])
859 assert match_dict_keys(keys, "\"o", delims=delims, extra_prefix=("foo",)) == ("\"", 1, ["oof"])
863 assert match_dict_keys(keys, "b'", delims=delims, extra_prefix=("foo",)) == ("'", 2, ["bar"])
860 assert match_dict_keys(keys, "b'", delims=delims, extra_prefix=("foo",)) == ("'", 2, ["bar"])
864 assert match_dict_keys(keys, "b\"", delims=delims, extra_prefix=("foo",)) == ("\"", 2, ["bar"])
861 assert match_dict_keys(keys, "b\"", delims=delims, extra_prefix=("foo",)) == ("\"", 2, ["bar"])
865 assert match_dict_keys(keys, "b'b", delims=delims, extra_prefix=("foo",)) == ("'", 2, ["bar"])
862 assert match_dict_keys(keys, "b'b", delims=delims, extra_prefix=("foo",)) == ("'", 2, ["bar"])
866 assert match_dict_keys(keys, "b\"b", delims=delims, extra_prefix=("foo",)) == ("\"", 2, ["bar"])
863 assert match_dict_keys(keys, "b\"b", delims=delims, extra_prefix=("foo",)) == ("\"", 2, ["bar"])
867
864
868 # No Completion
865 # No Completion
869 assert match_dict_keys(keys, "'", delims=delims, extra_prefix=("no_foo",)) == ("'", 1, [])
866 assert match_dict_keys(keys, "'", delims=delims, extra_prefix=("no_foo",)) == ("'", 1, [])
870 assert match_dict_keys(keys, "'", delims=delims, extra_prefix=("fo",)) == ("'", 1, [])
867 assert match_dict_keys(keys, "'", delims=delims, extra_prefix=("fo",)) == ("'", 1, [])
871
868
872 keys = [('foo1', 'foo2', 'foo3', 'foo4'), ('foo1', 'foo2', 'bar', 'foo4')]
869 keys = [('foo1', 'foo2', 'foo3', 'foo4'), ('foo1', 'foo2', 'bar', 'foo4')]
873 assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1',)) == ("'", 1, ["foo2", "foo2"])
870 assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1',)) == ("'", 1, ["foo2", "foo2"])
874 assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1', 'foo2')) == ("'", 1, ["foo3"])
871 assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1', 'foo2')) == ("'", 1, ["foo3"])
875 assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1', 'foo2', 'foo3')) == ("'", 1, ["foo4"])
872 assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1', 'foo2', 'foo3')) == ("'", 1, ["foo4"])
876 assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1', 'foo2', 'foo3', 'foo4')) == ("'", 1, [])
873 assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1', 'foo2', 'foo3', 'foo4')) == ("'", 1, [])
877
874
878 def test_dict_key_completion_string(self):
875 def test_dict_key_completion_string(self):
879 """Test dictionary key completion for string keys"""
876 """Test dictionary key completion for string keys"""
880 ip = get_ipython()
877 ip = get_ipython()
881 complete = ip.Completer.complete
878 complete = ip.Completer.complete
882
879
883 ip.user_ns["d"] = {"abc": None}
880 ip.user_ns["d"] = {"abc": None}
884
881
885 # check completion at different stages
882 # check completion at different stages
886 _, matches = complete(line_buffer="d[")
883 _, matches = complete(line_buffer="d[")
887 nt.assert_in("'abc'", matches)
884 self.assertIn("'abc'", matches)
888 nt.assert_not_in("'abc']", matches)
885 self.assertNotIn("'abc']", matches)
889
886
890 _, matches = complete(line_buffer="d['")
887 _, matches = complete(line_buffer="d['")
891 nt.assert_in("abc", matches)
888 self.assertIn("abc", matches)
892 nt.assert_not_in("abc']", matches)
889 self.assertNotIn("abc']", matches)
893
890
894 _, matches = complete(line_buffer="d['a")
891 _, matches = complete(line_buffer="d['a")
895 nt.assert_in("abc", matches)
892 self.assertIn("abc", matches)
896 nt.assert_not_in("abc']", matches)
893 self.assertNotIn("abc']", matches)
897
894
898 # check use of different quoting
895 # check use of different quoting
899 _, matches = complete(line_buffer='d["')
896 _, matches = complete(line_buffer='d["')
900 nt.assert_in("abc", matches)
897 self.assertIn("abc", matches)
901 nt.assert_not_in('abc"]', matches)
898 self.assertNotIn('abc"]', matches)
902
899
903 _, matches = complete(line_buffer='d["a')
900 _, matches = complete(line_buffer='d["a')
904 nt.assert_in("abc", matches)
901 self.assertIn("abc", matches)
905 nt.assert_not_in('abc"]', matches)
902 self.assertNotIn('abc"]', matches)
906
903
907 # check sensitivity to following context
904 # check sensitivity to following context
908 _, matches = complete(line_buffer="d[]", cursor_pos=2)
905 _, matches = complete(line_buffer="d[]", cursor_pos=2)
909 nt.assert_in("'abc'", matches)
906 self.assertIn("'abc'", matches)
910
907
911 _, matches = complete(line_buffer="d['']", cursor_pos=3)
908 _, matches = complete(line_buffer="d['']", cursor_pos=3)
912 nt.assert_in("abc", matches)
909 self.assertIn("abc", matches)
913 nt.assert_not_in("abc'", matches)
910 self.assertNotIn("abc'", matches)
914 nt.assert_not_in("abc']", matches)
911 self.assertNotIn("abc']", matches)
915
912
916 # check multiple solutions are correctly returned and that noise is not
913 # check multiple solutions are correctly returned and that noise is not
917 ip.user_ns["d"] = {
914 ip.user_ns["d"] = {
918 "abc": None,
915 "abc": None,
919 "abd": None,
916 "abd": None,
920 "bad": None,
917 "bad": None,
921 object(): None,
918 object(): None,
922 5: None,
919 5: None,
923 ("abe", None): None,
920 ("abe", None): None,
924 (None, "abf"): None
921 (None, "abf"): None
925 }
922 }
926
923
927 _, matches = complete(line_buffer="d['a")
924 _, matches = complete(line_buffer="d['a")
928 nt.assert_in("abc", matches)
925 self.assertIn("abc", matches)
929 nt.assert_in("abd", matches)
926 self.assertIn("abd", matches)
930 nt.assert_not_in("bad", matches)
927 self.assertNotIn("bad", matches)
931 nt.assert_not_in("abe", matches)
928 self.assertNotIn("abe", matches)
932 nt.assert_not_in("abf", matches)
929 self.assertNotIn("abf", matches)
933 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
930 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
934
931
935 # check escaping and whitespace
932 # check escaping and whitespace
936 ip.user_ns["d"] = {"a\nb": None, "a'b": None, 'a"b': None, "a word": None}
933 ip.user_ns["d"] = {"a\nb": None, "a'b": None, 'a"b': None, "a word": None}
937 _, matches = complete(line_buffer="d['a")
934 _, matches = complete(line_buffer="d['a")
938 nt.assert_in("a\\nb", matches)
935 self.assertIn("a\\nb", matches)
939 nt.assert_in("a\\'b", matches)
936 self.assertIn("a\\'b", matches)
940 nt.assert_in('a"b', matches)
937 self.assertIn('a"b', matches)
941 nt.assert_in("a word", matches)
938 self.assertIn("a word", matches)
942 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
939 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
943
940
944 # - can complete on non-initial word of the string
941 # - can complete on non-initial word of the string
945 _, matches = complete(line_buffer="d['a w")
942 _, matches = complete(line_buffer="d['a w")
946 nt.assert_in("word", matches)
943 self.assertIn("word", matches)
947
944
948 # - understands quote escaping
945 # - understands quote escaping
949 _, matches = complete(line_buffer="d['a\\'")
946 _, matches = complete(line_buffer="d['a\\'")
950 nt.assert_in("b", matches)
947 self.assertIn("b", matches)
951
948
952 # - default quoting should work like repr
949 # - default quoting should work like repr
953 _, matches = complete(line_buffer="d[")
950 _, matches = complete(line_buffer="d[")
954 nt.assert_in('"a\'b"', matches)
951 self.assertIn('"a\'b"', matches)
955
952
956 # - when opening quote with ", possible to match with unescaped apostrophe
953 # - when opening quote with ", possible to match with unescaped apostrophe
957 _, matches = complete(line_buffer="d[\"a'")
954 _, matches = complete(line_buffer="d[\"a'")
958 nt.assert_in("b", matches)
955 self.assertIn("b", matches)
959
956
960 # need to not split at delims that readline won't split at
957 # need to not split at delims that readline won't split at
961 if "-" not in ip.Completer.splitter.delims:
958 if "-" not in ip.Completer.splitter.delims:
962 ip.user_ns["d"] = {"before-after": None}
959 ip.user_ns["d"] = {"before-after": None}
963 _, matches = complete(line_buffer="d['before-af")
960 _, matches = complete(line_buffer="d['before-af")
964 nt.assert_in("before-after", matches)
961 self.assertIn("before-after", matches)
965
962
966 # check completion on tuple-of-string keys at different stage - on first key
963 # check completion on tuple-of-string keys at different stage - on first key
967 ip.user_ns["d"] = {('foo', 'bar'): None}
964 ip.user_ns["d"] = {('foo', 'bar'): None}
968 _, matches = complete(line_buffer="d[")
965 _, matches = complete(line_buffer="d[")
969 nt.assert_in("'foo'", matches)
966 self.assertIn("'foo'", matches)
970 nt.assert_not_in("'foo']", matches)
967 self.assertNotIn("'foo']", matches)
971 nt.assert_not_in("'bar'", matches)
968 self.assertNotIn("'bar'", matches)
972 nt.assert_not_in("foo", matches)
969 self.assertNotIn("foo", matches)
973 nt.assert_not_in("bar", matches)
970 self.assertNotIn("bar", matches)
974
971
975 # - match the prefix
972 # - match the prefix
976 _, matches = complete(line_buffer="d['f")
973 _, matches = complete(line_buffer="d['f")
977 nt.assert_in("foo", matches)
974 self.assertIn("foo", matches)
978 nt.assert_not_in("foo']", matches)
975 self.assertNotIn("foo']", matches)
979 nt.assert_not_in("foo\"]", matches)
976 self.assertNotIn('foo"]', matches)
980 _, matches = complete(line_buffer="d['foo")
977 _, matches = complete(line_buffer="d['foo")
981 nt.assert_in("foo", matches)
978 self.assertIn("foo", matches)
982
979
983 # - can complete on second key
980 # - can complete on second key
984 _, matches = complete(line_buffer="d['foo', ")
981 _, matches = complete(line_buffer="d['foo', ")
985 nt.assert_in("'bar'", matches)
982 self.assertIn("'bar'", matches)
986 _, matches = complete(line_buffer="d['foo', 'b")
983 _, matches = complete(line_buffer="d['foo', 'b")
987 nt.assert_in("bar", matches)
984 self.assertIn("bar", matches)
988 nt.assert_not_in("foo", matches)
985 self.assertNotIn("foo", matches)
989
986
990 # - does not propose missing keys
987 # - does not propose missing keys
991 _, matches = complete(line_buffer="d['foo', 'f")
988 _, matches = complete(line_buffer="d['foo', 'f")
992 nt.assert_not_in("bar", matches)
989 self.assertNotIn("bar", matches)
993 nt.assert_not_in("foo", matches)
990 self.assertNotIn("foo", matches)
994
991
995 # check sensitivity to following context
992 # check sensitivity to following context
996 _, matches = complete(line_buffer="d['foo',]", cursor_pos=8)
993 _, matches = complete(line_buffer="d['foo',]", cursor_pos=8)
997 nt.assert_in("'bar'", matches)
994 self.assertIn("'bar'", matches)
998 nt.assert_not_in("bar", matches)
995 self.assertNotIn("bar", matches)
999 nt.assert_not_in("'foo'", matches)
996 self.assertNotIn("'foo'", matches)
1000 nt.assert_not_in("foo", matches)
997 self.assertNotIn("foo", matches)
1001
998
1002 _, matches = complete(line_buffer="d['']", cursor_pos=3)
999 _, matches = complete(line_buffer="d['']", cursor_pos=3)
1003 nt.assert_in("foo", matches)
1000 self.assertIn("foo", matches)
1004 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
1001 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
1005
1002
1006 _, matches = complete(line_buffer='d[""]', cursor_pos=3)
1003 _, matches = complete(line_buffer='d[""]', cursor_pos=3)
1007 nt.assert_in("foo", matches)
1004 self.assertIn("foo", matches)
1008 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
1005 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
1009
1006
1010 _, matches = complete(line_buffer='d["foo","]', cursor_pos=9)
1007 _, matches = complete(line_buffer='d["foo","]', cursor_pos=9)
1011 nt.assert_in("bar", matches)
1008 self.assertIn("bar", matches)
1012 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
1009 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
1013
1010
1014 _, matches = complete(line_buffer='d["foo",]', cursor_pos=8)
1011 _, matches = complete(line_buffer='d["foo",]', cursor_pos=8)
1015 nt.assert_in("'bar'", matches)
1012 self.assertIn("'bar'", matches)
1016 nt.assert_not_in("bar", matches)
1013 self.assertNotIn("bar", matches)
1017
1014
1018 # Can complete with longer tuple keys
1015 # Can complete with longer tuple keys
1019 ip.user_ns["d"] = {('foo', 'bar', 'foobar'): None}
1016 ip.user_ns["d"] = {('foo', 'bar', 'foobar'): None}
1020
1017
1021 # - can complete second key
1018 # - can complete second key
1022 _, matches = complete(line_buffer="d['foo', 'b")
1019 _, matches = complete(line_buffer="d['foo', 'b")
1023 nt.assert_in('bar', matches)
1020 self.assertIn("bar", matches)
1024 nt.assert_not_in('foo', matches)
1021 self.assertNotIn("foo", matches)
1025 nt.assert_not_in('foobar', matches)
1022 self.assertNotIn("foobar", matches)
1026
1023
1027 # - can complete third key
1024 # - can complete third key
1028 _, matches = complete(line_buffer="d['foo', 'bar', 'fo")
1025 _, matches = complete(line_buffer="d['foo', 'bar', 'fo")
1029 nt.assert_in('foobar', matches)
1026 self.assertIn("foobar", matches)
1030 nt.assert_not_in('foo', matches)
1027 self.assertNotIn("foo", matches)
1031 nt.assert_not_in('bar', matches)
1028 self.assertNotIn("bar", matches)
1032
1033
1029
1034 def test_dict_key_completion_contexts(self):
1030 def test_dict_key_completion_contexts(self):
1035 """Test expression contexts in which dict key completion occurs"""
1031 """Test expression contexts in which dict key completion occurs"""
1036 ip = get_ipython()
1032 ip = get_ipython()
1037 complete = ip.Completer.complete
1033 complete = ip.Completer.complete
1038 d = {"abc": None}
1034 d = {"abc": None}
1039 ip.user_ns["d"] = d
1035 ip.user_ns["d"] = d
1040
1036
1041 class C:
1037 class C:
1042 data = d
1038 data = d
1043
1039
1044 ip.user_ns["C"] = C
1040 ip.user_ns["C"] = C
1045 ip.user_ns["get"] = lambda: d
1041 ip.user_ns["get"] = lambda: d
1046
1042
1047 def assert_no_completion(**kwargs):
1043 def assert_no_completion(**kwargs):
1048 _, matches = complete(**kwargs)
1044 _, matches = complete(**kwargs)
1049 nt.assert_not_in("abc", matches)
1045 self.assertNotIn("abc", matches)
1050 nt.assert_not_in("abc'", matches)
1046 self.assertNotIn("abc'", matches)
1051 nt.assert_not_in("abc']", matches)
1047 self.assertNotIn("abc']", matches)
1052 nt.assert_not_in("'abc'", matches)
1048 self.assertNotIn("'abc'", matches)
1053 nt.assert_not_in("'abc']", matches)
1049 self.assertNotIn("'abc']", matches)
1054
1050
1055 def assert_completion(**kwargs):
1051 def assert_completion(**kwargs):
1056 _, matches = complete(**kwargs)
1052 _, matches = complete(**kwargs)
1057 nt.assert_in("'abc'", matches)
1053 self.assertIn("'abc'", matches)
1058 nt.assert_not_in("'abc']", matches)
1054 self.assertNotIn("'abc']", matches)
1059
1055
1060 # no completion after string closed, even if reopened
1056 # no completion after string closed, even if reopened
1061 assert_no_completion(line_buffer="d['a'")
1057 assert_no_completion(line_buffer="d['a'")
1062 assert_no_completion(line_buffer='d["a"')
1058 assert_no_completion(line_buffer='d["a"')
1063 assert_no_completion(line_buffer="d['a' + ")
1059 assert_no_completion(line_buffer="d['a' + ")
1064 assert_no_completion(line_buffer="d['a' + '")
1060 assert_no_completion(line_buffer="d['a' + '")
1065
1061
1066 # completion in non-trivial expressions
1062 # completion in non-trivial expressions
1067 assert_completion(line_buffer="+ d[")
1063 assert_completion(line_buffer="+ d[")
1068 assert_completion(line_buffer="(d[")
1064 assert_completion(line_buffer="(d[")
1069 assert_completion(line_buffer="C.data[")
1065 assert_completion(line_buffer="C.data[")
1070
1066
1071 # greedy flag
1067 # greedy flag
1072 def assert_completion(**kwargs):
1068 def assert_completion(**kwargs):
1073 _, matches = complete(**kwargs)
1069 _, matches = complete(**kwargs)
1074 nt.assert_in("get()['abc']", matches)
1070 self.assertIn("get()['abc']", matches)
1075
1071
1076 assert_no_completion(line_buffer="get()[")
1072 assert_no_completion(line_buffer="get()[")
1077 with greedy_completion():
1073 with greedy_completion():
1078 assert_completion(line_buffer="get()[")
1074 assert_completion(line_buffer="get()[")
1079 assert_completion(line_buffer="get()['")
1075 assert_completion(line_buffer="get()['")
1080 assert_completion(line_buffer="get()['a")
1076 assert_completion(line_buffer="get()['a")
1081 assert_completion(line_buffer="get()['ab")
1077 assert_completion(line_buffer="get()['ab")
1082 assert_completion(line_buffer="get()['abc")
1078 assert_completion(line_buffer="get()['abc")
1083
1079
1084 def test_dict_key_completion_bytes(self):
1080 def test_dict_key_completion_bytes(self):
1085 """Test handling of bytes in dict key completion"""
1081 """Test handling of bytes in dict key completion"""
1086 ip = get_ipython()
1082 ip = get_ipython()
1087 complete = ip.Completer.complete
1083 complete = ip.Completer.complete
1088
1084
1089 ip.user_ns["d"] = {"abc": None, b"abd": None}
1085 ip.user_ns["d"] = {"abc": None, b"abd": None}
1090
1086
1091 _, matches = complete(line_buffer="d[")
1087 _, matches = complete(line_buffer="d[")
1092 nt.assert_in("'abc'", matches)
1088 self.assertIn("'abc'", matches)
1093 nt.assert_in("b'abd'", matches)
1089 self.assertIn("b'abd'", matches)
1094
1090
1095 if False: # not currently implemented
1091 if False: # not currently implemented
1096 _, matches = complete(line_buffer="d[b")
1092 _, matches = complete(line_buffer="d[b")
1097 nt.assert_in("b'abd'", matches)
1093 self.assertIn("b'abd'", matches)
1098 nt.assert_not_in("b'abc'", matches)
1094 self.assertNotIn("b'abc'", matches)
1099
1095
1100 _, matches = complete(line_buffer="d[b'")
1096 _, matches = complete(line_buffer="d[b'")
1101 nt.assert_in("abd", matches)
1097 self.assertIn("abd", matches)
1102 nt.assert_not_in("abc", matches)
1098 self.assertNotIn("abc", matches)
1103
1099
1104 _, matches = complete(line_buffer="d[B'")
1100 _, matches = complete(line_buffer="d[B'")
1105 nt.assert_in("abd", matches)
1101 self.assertIn("abd", matches)
1106 nt.assert_not_in("abc", matches)
1102 self.assertNotIn("abc", matches)
1107
1103
1108 _, matches = complete(line_buffer="d['")
1104 _, matches = complete(line_buffer="d['")
1109 nt.assert_in("abc", matches)
1105 self.assertIn("abc", matches)
1110 nt.assert_not_in("abd", matches)
1106 self.assertNotIn("abd", matches)
1111
1107
1112 def test_dict_key_completion_unicode_py3(self):
1108 def test_dict_key_completion_unicode_py3(self):
1113 """Test handling of unicode in dict key completion"""
1109 """Test handling of unicode in dict key completion"""
1114 ip = get_ipython()
1110 ip = get_ipython()
1115 complete = ip.Completer.complete
1111 complete = ip.Completer.complete
1116
1112
1117 ip.user_ns["d"] = {"a\u05d0": None}
1113 ip.user_ns["d"] = {"a\u05d0": None}
1118
1114
1119 # query using escape
1115 # query using escape
1120 if sys.platform != "win32":
1116 if sys.platform != "win32":
1121 # Known failure on Windows
1117 # Known failure on Windows
1122 _, matches = complete(line_buffer="d['a\\u05d0")
1118 _, matches = complete(line_buffer="d['a\\u05d0")
1123 nt.assert_in("u05d0", matches) # tokenized after \\
1119 self.assertIn("u05d0", matches) # tokenized after \\
1124
1120
1125 # query using character
1121 # query using character
1126 _, matches = complete(line_buffer="d['a\u05d0")
1122 _, matches = complete(line_buffer="d['a\u05d0")
1127 nt.assert_in("a\u05d0", matches)
1123 self.assertIn("a\u05d0", matches)
1128
1124
1129 with greedy_completion():
1125 with greedy_completion():
1130 # query using escape
1126 # query using escape
1131 _, matches = complete(line_buffer="d['a\\u05d0")
1127 _, matches = complete(line_buffer="d['a\\u05d0")
1132 nt.assert_in("d['a\\u05d0']", matches) # tokenized after \\
1128 self.assertIn("d['a\\u05d0']", matches) # tokenized after \\
1133
1129
1134 # query using character
1130 # query using character
1135 _, matches = complete(line_buffer="d['a\u05d0")
1131 _, matches = complete(line_buffer="d['a\u05d0")
1136 nt.assert_in("d['a\u05d0']", matches)
1132 self.assertIn("d['a\u05d0']", matches)
1137
1133
1138 @dec.skip_without("numpy")
1134 @dec.skip_without("numpy")
1139 def test_struct_array_key_completion(self):
1135 def test_struct_array_key_completion(self):
1140 """Test dict key completion applies to numpy struct arrays"""
1136 """Test dict key completion applies to numpy struct arrays"""
1141 import numpy
1137 import numpy
1142
1138
1143 ip = get_ipython()
1139 ip = get_ipython()
1144 complete = ip.Completer.complete
1140 complete = ip.Completer.complete
1145 ip.user_ns["d"] = numpy.array([], dtype=[("hello", "f"), ("world", "f")])
1141 ip.user_ns["d"] = numpy.array([], dtype=[("hello", "f"), ("world", "f")])
1146 _, matches = complete(line_buffer="d['")
1142 _, matches = complete(line_buffer="d['")
1147 nt.assert_in("hello", matches)
1143 self.assertIn("hello", matches)
1148 nt.assert_in("world", matches)
1144 self.assertIn("world", matches)
1149 # complete on the numpy struct itself
1145 # complete on the numpy struct itself
1150 dt = numpy.dtype(
1146 dt = numpy.dtype(
1151 [("my_head", [("my_dt", ">u4"), ("my_df", ">u4")]), ("my_data", ">f4", 5)]
1147 [("my_head", [("my_dt", ">u4"), ("my_df", ">u4")]), ("my_data", ">f4", 5)]
1152 )
1148 )
1153 x = numpy.zeros(2, dtype=dt)
1149 x = numpy.zeros(2, dtype=dt)
1154 ip.user_ns["d"] = x[1]
1150 ip.user_ns["d"] = x[1]
1155 _, matches = complete(line_buffer="d['")
1151 _, matches = complete(line_buffer="d['")
1156 nt.assert_in("my_head", matches)
1152 self.assertIn("my_head", matches)
1157 nt.assert_in("my_data", matches)
1153 self.assertIn("my_data", matches)
1158 # complete on a nested level
1154 # complete on a nested level
1159 with greedy_completion():
1155 with greedy_completion():
1160 ip.user_ns["d"] = numpy.zeros(2, dtype=dt)
1156 ip.user_ns["d"] = numpy.zeros(2, dtype=dt)
1161 _, matches = complete(line_buffer="d[1]['my_head']['")
1157 _, matches = complete(line_buffer="d[1]['my_head']['")
1162 nt.assert_true(any(["my_dt" in m for m in matches]))
1158 self.assertTrue(any(["my_dt" in m for m in matches]))
1163 nt.assert_true(any(["my_df" in m for m in matches]))
1159 self.assertTrue(any(["my_df" in m for m in matches]))
1164
1160
1165 @dec.skip_without("pandas")
1161 @dec.skip_without("pandas")
1166 def test_dataframe_key_completion(self):
1162 def test_dataframe_key_completion(self):
1167 """Test dict key completion applies to pandas DataFrames"""
1163 """Test dict key completion applies to pandas DataFrames"""
1168 import pandas
1164 import pandas
1169
1165
1170 ip = get_ipython()
1166 ip = get_ipython()
1171 complete = ip.Completer.complete
1167 complete = ip.Completer.complete
1172 ip.user_ns["d"] = pandas.DataFrame({"hello": [1], "world": [2]})
1168 ip.user_ns["d"] = pandas.DataFrame({"hello": [1], "world": [2]})
1173 _, matches = complete(line_buffer="d['")
1169 _, matches = complete(line_buffer="d['")
1174 nt.assert_in("hello", matches)
1170 self.assertIn("hello", matches)
1175 nt.assert_in("world", matches)
1171 self.assertIn("world", matches)
1176
1172
1177 def test_dict_key_completion_invalids(self):
1173 def test_dict_key_completion_invalids(self):
1178 """Smoke test cases dict key completion can't handle"""
1174 """Smoke test cases dict key completion can't handle"""
1179 ip = get_ipython()
1175 ip = get_ipython()
1180 complete = ip.Completer.complete
1176 complete = ip.Completer.complete
1181
1177
1182 ip.user_ns["no_getitem"] = None
1178 ip.user_ns["no_getitem"] = None
1183 ip.user_ns["no_keys"] = []
1179 ip.user_ns["no_keys"] = []
1184 ip.user_ns["cant_call_keys"] = dict
1180 ip.user_ns["cant_call_keys"] = dict
1185 ip.user_ns["empty"] = {}
1181 ip.user_ns["empty"] = {}
1186 ip.user_ns["d"] = {"abc": 5}
1182 ip.user_ns["d"] = {"abc": 5}
1187
1183
1188 _, matches = complete(line_buffer="no_getitem['")
1184 _, matches = complete(line_buffer="no_getitem['")
1189 _, matches = complete(line_buffer="no_keys['")
1185 _, matches = complete(line_buffer="no_keys['")
1190 _, matches = complete(line_buffer="cant_call_keys['")
1186 _, matches = complete(line_buffer="cant_call_keys['")
1191 _, matches = complete(line_buffer="empty['")
1187 _, matches = complete(line_buffer="empty['")
1192 _, matches = complete(line_buffer="name_error['")
1188 _, matches = complete(line_buffer="name_error['")
1193 _, matches = complete(line_buffer="d['\\") # incomplete escape
1189 _, matches = complete(line_buffer="d['\\") # incomplete escape
1194
1190
1195 def test_object_key_completion(self):
1191 def test_object_key_completion(self):
1196 ip = get_ipython()
1192 ip = get_ipython()
1197 ip.user_ns["key_completable"] = KeyCompletable(["qwerty", "qwick"])
1193 ip.user_ns["key_completable"] = KeyCompletable(["qwerty", "qwick"])
1198
1194
1199 _, matches = ip.Completer.complete(line_buffer="key_completable['qw")
1195 _, matches = ip.Completer.complete(line_buffer="key_completable['qw")
1200 nt.assert_in("qwerty", matches)
1196 self.assertIn("qwerty", matches)
1201 nt.assert_in("qwick", matches)
1197 self.assertIn("qwick", matches)
1202
1198
1203 def test_class_key_completion(self):
1199 def test_class_key_completion(self):
1204 ip = get_ipython()
1200 ip = get_ipython()
1205 NamedInstanceClass("qwerty")
1201 NamedInstanceClass("qwerty")
1206 NamedInstanceClass("qwick")
1202 NamedInstanceClass("qwick")
1207 ip.user_ns["named_instance_class"] = NamedInstanceClass
1203 ip.user_ns["named_instance_class"] = NamedInstanceClass
1208
1204
1209 _, matches = ip.Completer.complete(line_buffer="named_instance_class['qw")
1205 _, matches = ip.Completer.complete(line_buffer="named_instance_class['qw")
1210 nt.assert_in("qwerty", matches)
1206 self.assertIn("qwerty", matches)
1211 nt.assert_in("qwick", matches)
1207 self.assertIn("qwick", matches)
1212
1208
1213 def test_tryimport(self):
1209 def test_tryimport(self):
1214 """
1210 """
1215 Test that try-import don't crash on trailing dot, and import modules before
1211 Test that try-import don't crash on trailing dot, and import modules before
1216 """
1212 """
1217 from IPython.core.completerlib import try_import
1213 from IPython.core.completerlib import try_import
1218
1214
1219 assert try_import("IPython.")
1215 assert try_import("IPython.")
1220
1216
1221 def test_aimport_module_completer(self):
1217 def test_aimport_module_completer(self):
1222 ip = get_ipython()
1218 ip = get_ipython()
1223 _, matches = ip.complete("i", "%aimport i")
1219 _, matches = ip.complete("i", "%aimport i")
1224 nt.assert_in("io", matches)
1220 self.assertIn("io", matches)
1225 nt.assert_not_in("int", matches)
1221 self.assertNotIn("int", matches)
1226
1222
1227 def test_nested_import_module_completer(self):
1223 def test_nested_import_module_completer(self):
1228 ip = get_ipython()
1224 ip = get_ipython()
1229 _, matches = ip.complete(None, "import IPython.co", 17)
1225 _, matches = ip.complete(None, "import IPython.co", 17)
1230 nt.assert_in("IPython.core", matches)
1226 self.assertIn("IPython.core", matches)
1231 nt.assert_not_in("import IPython.core", matches)
1227 self.assertNotIn("import IPython.core", matches)
1232 nt.assert_not_in("IPython.display", matches)
1228 self.assertNotIn("IPython.display", matches)
1233
1229
1234 def test_import_module_completer(self):
1230 def test_import_module_completer(self):
1235 ip = get_ipython()
1231 ip = get_ipython()
1236 _, matches = ip.complete("i", "import i")
1232 _, matches = ip.complete("i", "import i")
1237 nt.assert_in("io", matches)
1233 self.assertIn("io", matches)
1238 nt.assert_not_in("int", matches)
1234 self.assertNotIn("int", matches)
1239
1235
1240 def test_from_module_completer(self):
1236 def test_from_module_completer(self):
1241 ip = get_ipython()
1237 ip = get_ipython()
1242 _, matches = ip.complete("B", "from io import B", 16)
1238 _, matches = ip.complete("B", "from io import B", 16)
1243 nt.assert_in("BytesIO", matches)
1239 self.assertIn("BytesIO", matches)
1244 nt.assert_not_in("BaseException", matches)
1240 self.assertNotIn("BaseException", matches)
1245
1241
1246 def test_snake_case_completion(self):
1242 def test_snake_case_completion(self):
1247 ip = get_ipython()
1243 ip = get_ipython()
1248 ip.Completer.use_jedi = False
1244 ip.Completer.use_jedi = False
1249 ip.user_ns["some_three"] = 3
1245 ip.user_ns["some_three"] = 3
1250 ip.user_ns["some_four"] = 4
1246 ip.user_ns["some_four"] = 4
1251 _, matches = ip.complete("s_", "print(s_f")
1247 _, matches = ip.complete("s_", "print(s_f")
1252 nt.assert_in("some_three", matches)
1248 self.assertIn("some_three", matches)
1253 nt.assert_in("some_four", matches)
1249 self.assertIn("some_four", matches)
1254
1250
1255 def test_mix_terms(self):
1251 def test_mix_terms(self):
1256 ip = get_ipython()
1252 ip = get_ipython()
1257 from textwrap import dedent
1253 from textwrap import dedent
1258
1254
1259 ip.Completer.use_jedi = False
1255 ip.Completer.use_jedi = False
1260 ip.ex(
1256 ip.ex(
1261 dedent(
1257 dedent(
1262 """
1258 """
1263 class Test:
1259 class Test:
1264 def meth(self, meth_arg1):
1260 def meth(self, meth_arg1):
1265 print("meth")
1261 print("meth")
1266
1262
1267 def meth_1(self, meth1_arg1, meth1_arg2):
1263 def meth_1(self, meth1_arg1, meth1_arg2):
1268 print("meth1")
1264 print("meth1")
1269
1265
1270 def meth_2(self, meth2_arg1, meth2_arg2):
1266 def meth_2(self, meth2_arg1, meth2_arg2):
1271 print("meth2")
1267 print("meth2")
1272 test = Test()
1268 test = Test()
1273 """
1269 """
1274 )
1270 )
1275 )
1271 )
1276 _, matches = ip.complete(None, "test.meth(")
1272 _, matches = ip.complete(None, "test.meth(")
1277 nt.assert_in("meth_arg1=", matches)
1273 self.assertIn("meth_arg1=", matches)
1278 nt.assert_not_in("meth2_arg1=", matches)
1274 self.assertNotIn("meth2_arg1=", matches)
@@ -1,194 +1,192 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for completerlib.
2 """Tests for completerlib.
3
3
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Imports
7 # Imports
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9
9
10 import os
10 import os
11 import shutil
11 import shutil
12 import sys
12 import sys
13 import tempfile
13 import tempfile
14 import unittest
14 import unittest
15 from os.path import join
15 from os.path import join
16
16
17 import nose.tools as nt
18
19 from IPython.core.completerlib import magic_run_completer, module_completion, try_import
17 from IPython.core.completerlib import magic_run_completer, module_completion, try_import
20 from IPython.utils.tempdir import TemporaryDirectory
18 from IPython.utils.tempdir import TemporaryDirectory
21 from IPython.testing.decorators import onlyif_unicode_paths
19 from IPython.testing.decorators import onlyif_unicode_paths
22
20
23
21
24 class MockEvent(object):
22 class MockEvent(object):
25 def __init__(self, line):
23 def __init__(self, line):
26 self.line = line
24 self.line = line
27
25
28 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
29 # Test functions begin
27 # Test functions begin
30 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
31 class Test_magic_run_completer(unittest.TestCase):
29 class Test_magic_run_completer(unittest.TestCase):
32 files = [u"aao.py", u"a.py", u"b.py", u"aao.txt"]
30 files = [u"aao.py", u"a.py", u"b.py", u"aao.txt"]
33 dirs = [u"adir/", "bdir/"]
31 dirs = [u"adir/", "bdir/"]
34
32
35 def setUp(self):
33 def setUp(self):
36 self.BASETESTDIR = tempfile.mkdtemp()
34 self.BASETESTDIR = tempfile.mkdtemp()
37 for fil in self.files:
35 for fil in self.files:
38 with open(join(self.BASETESTDIR, fil), "w") as sfile:
36 with open(join(self.BASETESTDIR, fil), "w") as sfile:
39 sfile.write("pass\n")
37 sfile.write("pass\n")
40 for d in self.dirs:
38 for d in self.dirs:
41 os.mkdir(join(self.BASETESTDIR, d))
39 os.mkdir(join(self.BASETESTDIR, d))
42
40
43 self.oldpath = os.getcwd()
41 self.oldpath = os.getcwd()
44 os.chdir(self.BASETESTDIR)
42 os.chdir(self.BASETESTDIR)
45
43
46 def tearDown(self):
44 def tearDown(self):
47 os.chdir(self.oldpath)
45 os.chdir(self.oldpath)
48 shutil.rmtree(self.BASETESTDIR)
46 shutil.rmtree(self.BASETESTDIR)
49
47
50 def test_1(self):
48 def test_1(self):
51 """Test magic_run_completer, should match two alternatives
49 """Test magic_run_completer, should match two alternatives
52 """
50 """
53 event = MockEvent(u"%run a")
51 event = MockEvent(u"%run a")
54 mockself = None
52 mockself = None
55 match = set(magic_run_completer(mockself, event))
53 match = set(magic_run_completer(mockself, event))
56 self.assertEqual(match, {u"a.py", u"aao.py", u"adir/"})
54 self.assertEqual(match, {u"a.py", u"aao.py", u"adir/"})
57
55
58 def test_2(self):
56 def test_2(self):
59 """Test magic_run_completer, should match one alternative
57 """Test magic_run_completer, should match one alternative
60 """
58 """
61 event = MockEvent(u"%run aa")
59 event = MockEvent(u"%run aa")
62 mockself = None
60 mockself = None
63 match = set(magic_run_completer(mockself, event))
61 match = set(magic_run_completer(mockself, event))
64 self.assertEqual(match, {u"aao.py"})
62 self.assertEqual(match, {u"aao.py"})
65
63
66 def test_3(self):
64 def test_3(self):
67 """Test magic_run_completer with unterminated " """
65 """Test magic_run_completer with unterminated " """
68 event = MockEvent(u'%run "a')
66 event = MockEvent(u'%run "a')
69 mockself = None
67 mockself = None
70 match = set(magic_run_completer(mockself, event))
68 match = set(magic_run_completer(mockself, event))
71 self.assertEqual(match, {u"a.py", u"aao.py", u"adir/"})
69 self.assertEqual(match, {u"a.py", u"aao.py", u"adir/"})
72
70
73 def test_completion_more_args(self):
71 def test_completion_more_args(self):
74 event = MockEvent(u'%run a.py ')
72 event = MockEvent(u'%run a.py ')
75 match = set(magic_run_completer(None, event))
73 match = set(magic_run_completer(None, event))
76 self.assertEqual(match, set(self.files + self.dirs))
74 self.assertEqual(match, set(self.files + self.dirs))
77
75
78 def test_completion_in_dir(self):
76 def test_completion_in_dir(self):
79 # Github issue #3459
77 # Github issue #3459
80 event = MockEvent(u'%run a.py {}'.format(join(self.BASETESTDIR, 'a')))
78 event = MockEvent(u'%run a.py {}'.format(join(self.BASETESTDIR, 'a')))
81 print(repr(event.line))
79 print(repr(event.line))
82 match = set(magic_run_completer(None, event))
80 match = set(magic_run_completer(None, event))
83 # We specifically use replace here rather than normpath, because
81 # We specifically use replace here rather than normpath, because
84 # at one point there were duplicates 'adir' and 'adir/', and normpath
82 # at one point there were duplicates 'adir' and 'adir/', and normpath
85 # would hide the failure for that.
83 # would hide the failure for that.
86 self.assertEqual(match, {join(self.BASETESTDIR, f).replace('\\','/')
84 self.assertEqual(match, {join(self.BASETESTDIR, f).replace('\\','/')
87 for f in (u'a.py', u'aao.py', u'aao.txt', u'adir/')})
85 for f in (u'a.py', u'aao.py', u'aao.txt', u'adir/')})
88
86
89 class Test_magic_run_completer_nonascii(unittest.TestCase):
87 class Test_magic_run_completer_nonascii(unittest.TestCase):
90 @onlyif_unicode_paths
88 @onlyif_unicode_paths
91 def setUp(self):
89 def setUp(self):
92 self.BASETESTDIR = tempfile.mkdtemp()
90 self.BASETESTDIR = tempfile.mkdtemp()
93 for fil in [u"aaø.py", u"a.py", u"b.py"]:
91 for fil in [u"aaø.py", u"a.py", u"b.py"]:
94 with open(join(self.BASETESTDIR, fil), "w") as sfile:
92 with open(join(self.BASETESTDIR, fil), "w") as sfile:
95 sfile.write("pass\n")
93 sfile.write("pass\n")
96 self.oldpath = os.getcwd()
94 self.oldpath = os.getcwd()
97 os.chdir(self.BASETESTDIR)
95 os.chdir(self.BASETESTDIR)
98
96
99 def tearDown(self):
97 def tearDown(self):
100 os.chdir(self.oldpath)
98 os.chdir(self.oldpath)
101 shutil.rmtree(self.BASETESTDIR)
99 shutil.rmtree(self.BASETESTDIR)
102
100
103 @onlyif_unicode_paths
101 @onlyif_unicode_paths
104 def test_1(self):
102 def test_1(self):
105 """Test magic_run_completer, should match two alternatives
103 """Test magic_run_completer, should match two alternatives
106 """
104 """
107 event = MockEvent(u"%run a")
105 event = MockEvent(u"%run a")
108 mockself = None
106 mockself = None
109 match = set(magic_run_completer(mockself, event))
107 match = set(magic_run_completer(mockself, event))
110 self.assertEqual(match, {u"a.py", u"aaø.py"})
108 self.assertEqual(match, {u"a.py", u"aaø.py"})
111
109
112 @onlyif_unicode_paths
110 @onlyif_unicode_paths
113 def test_2(self):
111 def test_2(self):
114 """Test magic_run_completer, should match one alternative
112 """Test magic_run_completer, should match one alternative
115 """
113 """
116 event = MockEvent(u"%run aa")
114 event = MockEvent(u"%run aa")
117 mockself = None
115 mockself = None
118 match = set(magic_run_completer(mockself, event))
116 match = set(magic_run_completer(mockself, event))
119 self.assertEqual(match, {u"aaø.py"})
117 self.assertEqual(match, {u"aaø.py"})
120
118
121 @onlyif_unicode_paths
119 @onlyif_unicode_paths
122 def test_3(self):
120 def test_3(self):
123 """Test magic_run_completer with unterminated " """
121 """Test magic_run_completer with unterminated " """
124 event = MockEvent(u'%run "a')
122 event = MockEvent(u'%run "a')
125 mockself = None
123 mockself = None
126 match = set(magic_run_completer(mockself, event))
124 match = set(magic_run_completer(mockself, event))
127 self.assertEqual(match, {u"a.py", u"aaø.py"})
125 self.assertEqual(match, {u"a.py", u"aaø.py"})
128
126
129 # module_completer:
127 # module_completer:
130
128
131 def test_import_invalid_module():
129 def test_import_invalid_module():
132 """Testing of issue https://github.com/ipython/ipython/issues/1107"""
130 """Testing of issue https://github.com/ipython/ipython/issues/1107"""
133 invalid_module_names = {'foo-bar', 'foo:bar', '10foo'}
131 invalid_module_names = {'foo-bar', 'foo:bar', '10foo'}
134 valid_module_names = {'foobar'}
132 valid_module_names = {'foobar'}
135 with TemporaryDirectory() as tmpdir:
133 with TemporaryDirectory() as tmpdir:
136 sys.path.insert( 0, tmpdir )
134 sys.path.insert( 0, tmpdir )
137 for name in invalid_module_names | valid_module_names:
135 for name in invalid_module_names | valid_module_names:
138 filename = os.path.join(tmpdir, name + '.py')
136 filename = os.path.join(tmpdir, name + '.py')
139 open(filename, 'w').close()
137 open(filename, 'w').close()
140
138
141 s = set( module_completion('import foo') )
139 s = set( module_completion('import foo') )
142 intersection = s.intersection(invalid_module_names)
140 intersection = s.intersection(invalid_module_names)
143 nt.assert_equal(intersection, set())
141 assert intersection == set()
144
142
145 assert valid_module_names.issubset(s), valid_module_names.intersection(s)
143 assert valid_module_names.issubset(s), valid_module_names.intersection(s)
146
144
147
145
148 def test_bad_module_all():
146 def test_bad_module_all():
149 """Test module with invalid __all__
147 """Test module with invalid __all__
150
148
151 https://github.com/ipython/ipython/issues/9678
149 https://github.com/ipython/ipython/issues/9678
152 """
150 """
153 testsdir = os.path.dirname(__file__)
151 testsdir = os.path.dirname(__file__)
154 sys.path.insert(0, testsdir)
152 sys.path.insert(0, testsdir)
155 try:
153 try:
156 results = module_completion('from bad_all import ')
154 results = module_completion("from bad_all import ")
157 nt.assert_in('puppies', results)
155 assert "puppies" in results
158 for r in results:
156 for r in results:
159 nt.assert_is_instance(r, str)
157 assert isinstance(r, str)
160
158
161 # bad_all doesn't contain submodules, but this completion
159 # bad_all doesn't contain submodules, but this completion
162 # should finish without raising an exception:
160 # should finish without raising an exception:
163 results = module_completion("import bad_all.")
161 results = module_completion("import bad_all.")
164 nt.assert_equal(results, [])
162 assert results == []
165 finally:
163 finally:
166 sys.path.remove(testsdir)
164 sys.path.remove(testsdir)
167
165
168
166
169 def test_module_without_init():
167 def test_module_without_init():
170 """
168 """
171 Test module without __init__.py.
169 Test module without __init__.py.
172
170
173 https://github.com/ipython/ipython/issues/11226
171 https://github.com/ipython/ipython/issues/11226
174 """
172 """
175 fake_module_name = "foo"
173 fake_module_name = "foo"
176 with TemporaryDirectory() as tmpdir:
174 with TemporaryDirectory() as tmpdir:
177 sys.path.insert(0, tmpdir)
175 sys.path.insert(0, tmpdir)
178 try:
176 try:
179 os.makedirs(os.path.join(tmpdir, fake_module_name))
177 os.makedirs(os.path.join(tmpdir, fake_module_name))
180 s = try_import(mod=fake_module_name)
178 s = try_import(mod=fake_module_name)
181 assert s == []
179 assert s == []
182 finally:
180 finally:
183 sys.path.remove(tmpdir)
181 sys.path.remove(tmpdir)
184
182
185
183
186 def test_valid_exported_submodules():
184 def test_valid_exported_submodules():
187 """
185 """
188 Test checking exported (__all__) objects are submodules
186 Test checking exported (__all__) objects are submodules
189 """
187 """
190 results = module_completion("import os.pa")
188 results = module_completion("import os.pa")
191 # ensure we get a valid submodule:
189 # ensure we get a valid submodule:
192 nt.assert_in("os.path", results)
190 assert "os.path" in results
193 # ensure we don't get objects that aren't submodules:
191 # ensure we don't get objects that aren't submodules:
194 nt.assert_not_in("os.pathconf", results)
192 assert "os.pathconf" not in results
@@ -1,576 +1,574 b''
1 """Tests for debugging machinery.
1 """Tests for debugging machinery.
2 """
2 """
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7 import bdb
7 import bdb
8 import builtins
8 import builtins
9 import os
9 import os
10 import signal
10 import signal
11 import subprocess
11 import subprocess
12 import sys
12 import sys
13 import time
13 import time
14 import warnings
14 import warnings
15
15
16 from subprocess import PIPE, CalledProcessError, check_output
16 from subprocess import PIPE, CalledProcessError, check_output
17 from tempfile import NamedTemporaryFile
17 from tempfile import NamedTemporaryFile
18 from textwrap import dedent
18 from textwrap import dedent
19 from unittest.mock import patch
19 from unittest.mock import patch
20
20
21 import nose.tools as nt
22
23 from IPython.core import debugger
21 from IPython.core import debugger
24 from IPython.testing import IPYTHON_TESTING_TIMEOUT_SCALE
22 from IPython.testing import IPYTHON_TESTING_TIMEOUT_SCALE
25 from IPython.testing.decorators import skip_win32
23 from IPython.testing.decorators import skip_win32
26
24
27 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
28 # Helper classes, from CPython's Pdb test suite
26 # Helper classes, from CPython's Pdb test suite
29 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
30
28
31 class _FakeInput(object):
29 class _FakeInput(object):
32 """
30 """
33 A fake input stream for pdb's interactive debugger. Whenever a
31 A fake input stream for pdb's interactive debugger. Whenever a
34 line is read, print it (to simulate the user typing it), and then
32 line is read, print it (to simulate the user typing it), and then
35 return it. The set of lines to return is specified in the
33 return it. The set of lines to return is specified in the
36 constructor; they should not have trailing newlines.
34 constructor; they should not have trailing newlines.
37 """
35 """
38 def __init__(self, lines):
36 def __init__(self, lines):
39 self.lines = iter(lines)
37 self.lines = iter(lines)
40
38
41 def readline(self):
39 def readline(self):
42 line = next(self.lines)
40 line = next(self.lines)
43 print(line)
41 print(line)
44 return line+'\n'
42 return line+'\n'
45
43
46 class PdbTestInput(object):
44 class PdbTestInput(object):
47 """Context manager that makes testing Pdb in doctests easier."""
45 """Context manager that makes testing Pdb in doctests easier."""
48
46
49 def __init__(self, input):
47 def __init__(self, input):
50 self.input = input
48 self.input = input
51
49
52 def __enter__(self):
50 def __enter__(self):
53 self.real_stdin = sys.stdin
51 self.real_stdin = sys.stdin
54 sys.stdin = _FakeInput(self.input)
52 sys.stdin = _FakeInput(self.input)
55
53
56 def __exit__(self, *exc):
54 def __exit__(self, *exc):
57 sys.stdin = self.real_stdin
55 sys.stdin = self.real_stdin
58
56
59 #-----------------------------------------------------------------------------
57 #-----------------------------------------------------------------------------
60 # Tests
58 # Tests
61 #-----------------------------------------------------------------------------
59 #-----------------------------------------------------------------------------
62
60
63 def test_longer_repr():
61 def test_longer_repr():
64 from reprlib import repr as trepr
62 from reprlib import repr as trepr
65
63
66 a = '1234567890'* 7
64 a = '1234567890'* 7
67 ar = "'1234567890123456789012345678901234567890123456789012345678901234567890'"
65 ar = "'1234567890123456789012345678901234567890123456789012345678901234567890'"
68 a_trunc = "'123456789012...8901234567890'"
66 a_trunc = "'123456789012...8901234567890'"
69 nt.assert_equal(trepr(a), a_trunc)
67 assert trepr(a) == a_trunc
70 # The creation of our tracer modifies the repr module's repr function
68 # The creation of our tracer modifies the repr module's repr function
71 # in-place, since that global is used directly by the stdlib's pdb module.
69 # in-place, since that global is used directly by the stdlib's pdb module.
72 with warnings.catch_warnings():
70 with warnings.catch_warnings():
73 warnings.simplefilter('ignore', DeprecationWarning)
71 warnings.simplefilter('ignore', DeprecationWarning)
74 debugger.Tracer()
72 debugger.Tracer()
75 nt.assert_equal(trepr(a), ar)
73 assert trepr(a) == ar
76
74
77 def test_ipdb_magics():
75 def test_ipdb_magics():
78 '''Test calling some IPython magics from ipdb.
76 '''Test calling some IPython magics from ipdb.
79
77
80 First, set up some test functions and classes which we can inspect.
78 First, set up some test functions and classes which we can inspect.
81
79
82 >>> class ExampleClass(object):
80 >>> class ExampleClass(object):
83 ... """Docstring for ExampleClass."""
81 ... """Docstring for ExampleClass."""
84 ... def __init__(self):
82 ... def __init__(self):
85 ... """Docstring for ExampleClass.__init__"""
83 ... """Docstring for ExampleClass.__init__"""
86 ... pass
84 ... pass
87 ... def __str__(self):
85 ... def __str__(self):
88 ... return "ExampleClass()"
86 ... return "ExampleClass()"
89
87
90 >>> def example_function(x, y, z="hello"):
88 >>> def example_function(x, y, z="hello"):
91 ... """Docstring for example_function."""
89 ... """Docstring for example_function."""
92 ... pass
90 ... pass
93
91
94 >>> old_trace = sys.gettrace()
92 >>> old_trace = sys.gettrace()
95
93
96 Create a function which triggers ipdb.
94 Create a function which triggers ipdb.
97
95
98 >>> def trigger_ipdb():
96 >>> def trigger_ipdb():
99 ... a = ExampleClass()
97 ... a = ExampleClass()
100 ... debugger.Pdb().set_trace()
98 ... debugger.Pdb().set_trace()
101
99
102 >>> with PdbTestInput([
100 >>> with PdbTestInput([
103 ... 'pdef example_function',
101 ... 'pdef example_function',
104 ... 'pdoc ExampleClass',
102 ... 'pdoc ExampleClass',
105 ... 'up',
103 ... 'up',
106 ... 'down',
104 ... 'down',
107 ... 'list',
105 ... 'list',
108 ... 'pinfo a',
106 ... 'pinfo a',
109 ... 'll',
107 ... 'll',
110 ... 'continue',
108 ... 'continue',
111 ... ]):
109 ... ]):
112 ... trigger_ipdb()
110 ... trigger_ipdb()
113 --Return--
111 --Return--
114 None
112 None
115 > <doctest ...>(3)trigger_ipdb()
113 > <doctest ...>(3)trigger_ipdb()
116 1 def trigger_ipdb():
114 1 def trigger_ipdb():
117 2 a = ExampleClass()
115 2 a = ExampleClass()
118 ----> 3 debugger.Pdb().set_trace()
116 ----> 3 debugger.Pdb().set_trace()
119 <BLANKLINE>
117 <BLANKLINE>
120 ipdb> pdef example_function
118 ipdb> pdef example_function
121 example_function(x, y, z='hello')
119 example_function(x, y, z='hello')
122 ipdb> pdoc ExampleClass
120 ipdb> pdoc ExampleClass
123 Class docstring:
121 Class docstring:
124 Docstring for ExampleClass.
122 Docstring for ExampleClass.
125 Init docstring:
123 Init docstring:
126 Docstring for ExampleClass.__init__
124 Docstring for ExampleClass.__init__
127 ipdb> up
125 ipdb> up
128 > <doctest ...>(11)<module>()
126 > <doctest ...>(11)<module>()
129 7 'pinfo a',
127 7 'pinfo a',
130 8 'll',
128 8 'll',
131 9 'continue',
129 9 'continue',
132 10 ]):
130 10 ]):
133 ---> 11 trigger_ipdb()
131 ---> 11 trigger_ipdb()
134 <BLANKLINE>
132 <BLANKLINE>
135 ipdb> down
133 ipdb> down
136 None
134 None
137 > <doctest ...>(3)trigger_ipdb()
135 > <doctest ...>(3)trigger_ipdb()
138 1 def trigger_ipdb():
136 1 def trigger_ipdb():
139 2 a = ExampleClass()
137 2 a = ExampleClass()
140 ----> 3 debugger.Pdb().set_trace()
138 ----> 3 debugger.Pdb().set_trace()
141 <BLANKLINE>
139 <BLANKLINE>
142 ipdb> list
140 ipdb> list
143 1 def trigger_ipdb():
141 1 def trigger_ipdb():
144 2 a = ExampleClass()
142 2 a = ExampleClass()
145 ----> 3 debugger.Pdb().set_trace()
143 ----> 3 debugger.Pdb().set_trace()
146 <BLANKLINE>
144 <BLANKLINE>
147 ipdb> pinfo a
145 ipdb> pinfo a
148 Type: ExampleClass
146 Type: ExampleClass
149 String form: ExampleClass()
147 String form: ExampleClass()
150 Namespace: Local...
148 Namespace: Local...
151 Docstring: Docstring for ExampleClass.
149 Docstring: Docstring for ExampleClass.
152 Init docstring: Docstring for ExampleClass.__init__
150 Init docstring: Docstring for ExampleClass.__init__
153 ipdb> ll
151 ipdb> ll
154 1 def trigger_ipdb():
152 1 def trigger_ipdb():
155 2 a = ExampleClass()
153 2 a = ExampleClass()
156 ----> 3 debugger.Pdb().set_trace()
154 ----> 3 debugger.Pdb().set_trace()
157 <BLANKLINE>
155 <BLANKLINE>
158 ipdb> continue
156 ipdb> continue
159
157
160 Restore previous trace function, e.g. for coverage.py
158 Restore previous trace function, e.g. for coverage.py
161
159
162 >>> sys.settrace(old_trace)
160 >>> sys.settrace(old_trace)
163 '''
161 '''
164
162
165 def test_ipdb_magics2():
163 def test_ipdb_magics2():
166 '''Test ipdb with a very short function.
164 '''Test ipdb with a very short function.
167
165
168 >>> old_trace = sys.gettrace()
166 >>> old_trace = sys.gettrace()
169
167
170 >>> def bar():
168 >>> def bar():
171 ... pass
169 ... pass
172
170
173 Run ipdb.
171 Run ipdb.
174
172
175 >>> with PdbTestInput([
173 >>> with PdbTestInput([
176 ... 'continue',
174 ... 'continue',
177 ... ]):
175 ... ]):
178 ... debugger.Pdb().runcall(bar)
176 ... debugger.Pdb().runcall(bar)
179 > <doctest ...>(2)bar()
177 > <doctest ...>(2)bar()
180 1 def bar():
178 1 def bar():
181 ----> 2 pass
179 ----> 2 pass
182 <BLANKLINE>
180 <BLANKLINE>
183 ipdb> continue
181 ipdb> continue
184
182
185 Restore previous trace function, e.g. for coverage.py
183 Restore previous trace function, e.g. for coverage.py
186
184
187 >>> sys.settrace(old_trace)
185 >>> sys.settrace(old_trace)
188 '''
186 '''
189
187
190 def can_quit():
188 def can_quit():
191 '''Test that quit work in ipydb
189 '''Test that quit work in ipydb
192
190
193 >>> old_trace = sys.gettrace()
191 >>> old_trace = sys.gettrace()
194
192
195 >>> def bar():
193 >>> def bar():
196 ... pass
194 ... pass
197
195
198 >>> with PdbTestInput([
196 >>> with PdbTestInput([
199 ... 'quit',
197 ... 'quit',
200 ... ]):
198 ... ]):
201 ... debugger.Pdb().runcall(bar)
199 ... debugger.Pdb().runcall(bar)
202 > <doctest ...>(2)bar()
200 > <doctest ...>(2)bar()
203 1 def bar():
201 1 def bar():
204 ----> 2 pass
202 ----> 2 pass
205 <BLANKLINE>
203 <BLANKLINE>
206 ipdb> quit
204 ipdb> quit
207
205
208 Restore previous trace function, e.g. for coverage.py
206 Restore previous trace function, e.g. for coverage.py
209
207
210 >>> sys.settrace(old_trace)
208 >>> sys.settrace(old_trace)
211 '''
209 '''
212
210
213
211
214 def can_exit():
212 def can_exit():
215 '''Test that quit work in ipydb
213 '''Test that quit work in ipydb
216
214
217 >>> old_trace = sys.gettrace()
215 >>> old_trace = sys.gettrace()
218
216
219 >>> def bar():
217 >>> def bar():
220 ... pass
218 ... pass
221
219
222 >>> with PdbTestInput([
220 >>> with PdbTestInput([
223 ... 'exit',
221 ... 'exit',
224 ... ]):
222 ... ]):
225 ... debugger.Pdb().runcall(bar)
223 ... debugger.Pdb().runcall(bar)
226 > <doctest ...>(2)bar()
224 > <doctest ...>(2)bar()
227 1 def bar():
225 1 def bar():
228 ----> 2 pass
226 ----> 2 pass
229 <BLANKLINE>
227 <BLANKLINE>
230 ipdb> exit
228 ipdb> exit
231
229
232 Restore previous trace function, e.g. for coverage.py
230 Restore previous trace function, e.g. for coverage.py
233
231
234 >>> sys.settrace(old_trace)
232 >>> sys.settrace(old_trace)
235 '''
233 '''
236
234
237
235
238 def test_interruptible_core_debugger():
236 def test_interruptible_core_debugger():
239 """The debugger can be interrupted.
237 """The debugger can be interrupted.
240
238
241 The presumption is there is some mechanism that causes a KeyboardInterrupt
239 The presumption is there is some mechanism that causes a KeyboardInterrupt
242 (this is implemented in ipykernel). We want to ensure the
240 (this is implemented in ipykernel). We want to ensure the
243 KeyboardInterrupt cause debugging to cease.
241 KeyboardInterrupt cause debugging to cease.
244 """
242 """
245 def raising_input(msg="", called=[0]):
243 def raising_input(msg="", called=[0]):
246 called[0] += 1
244 called[0] += 1
247 if called[0] == 1:
245 if called[0] == 1:
248 raise KeyboardInterrupt()
246 raise KeyboardInterrupt()
249 else:
247 else:
250 raise AssertionError("input() should only be called once!")
248 raise AssertionError("input() should only be called once!")
251
249
252 with patch.object(builtins, "input", raising_input):
250 with patch.object(builtins, "input", raising_input):
253 debugger.InterruptiblePdb().set_trace()
251 debugger.InterruptiblePdb().set_trace()
254 # The way this test will fail is by set_trace() never exiting,
252 # The way this test will fail is by set_trace() never exiting,
255 # resulting in a timeout by the test runner. The alternative
253 # resulting in a timeout by the test runner. The alternative
256 # implementation would involve a subprocess, but that adds issues with
254 # implementation would involve a subprocess, but that adds issues with
257 # interrupting subprocesses that are rather complex, so it's simpler
255 # interrupting subprocesses that are rather complex, so it's simpler
258 # just to do it this way.
256 # just to do it this way.
259
257
260 @skip_win32
258 @skip_win32
261 def test_xmode_skip():
259 def test_xmode_skip():
262 """that xmode skip frames
260 """that xmode skip frames
263
261
264 Not as a doctest as pytest does not run doctests.
262 Not as a doctest as pytest does not run doctests.
265 """
263 """
266 import pexpect
264 import pexpect
267 env = os.environ.copy()
265 env = os.environ.copy()
268 env["IPY_TEST_SIMPLE_PROMPT"] = "1"
266 env["IPY_TEST_SIMPLE_PROMPT"] = "1"
269
267
270 child = pexpect.spawn(
268 child = pexpect.spawn(
271 sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
269 sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
272 )
270 )
273 child.timeout = 15 * IPYTHON_TESTING_TIMEOUT_SCALE
271 child.timeout = 15 * IPYTHON_TESTING_TIMEOUT_SCALE
274
272
275 child.expect("IPython")
273 child.expect("IPython")
276 child.expect("\n")
274 child.expect("\n")
277 child.expect_exact("In [1]")
275 child.expect_exact("In [1]")
278
276
279 block = dedent(
277 block = dedent(
280 """
278 """
281 def f():
279 def f():
282 __tracebackhide__ = True
280 __tracebackhide__ = True
283 g()
281 g()
284
282
285 def g():
283 def g():
286 raise ValueError
284 raise ValueError
287
285
288 f()
286 f()
289 """
287 """
290 )
288 )
291
289
292 for line in block.splitlines():
290 for line in block.splitlines():
293 child.sendline(line)
291 child.sendline(line)
294 child.expect_exact(line)
292 child.expect_exact(line)
295 child.expect_exact("skipping")
293 child.expect_exact("skipping")
296
294
297 block = dedent(
295 block = dedent(
298 """
296 """
299 def f():
297 def f():
300 __tracebackhide__ = True
298 __tracebackhide__ = True
301 g()
299 g()
302
300
303 def g():
301 def g():
304 from IPython.core.debugger import set_trace
302 from IPython.core.debugger import set_trace
305 set_trace()
303 set_trace()
306
304
307 f()
305 f()
308 """
306 """
309 )
307 )
310
308
311 for line in block.splitlines():
309 for line in block.splitlines():
312 child.sendline(line)
310 child.sendline(line)
313 child.expect_exact(line)
311 child.expect_exact(line)
314
312
315 child.expect("ipdb>")
313 child.expect("ipdb>")
316 child.sendline("w")
314 child.sendline("w")
317 child.expect("hidden")
315 child.expect("hidden")
318 child.expect("ipdb>")
316 child.expect("ipdb>")
319 child.sendline("skip_hidden false")
317 child.sendline("skip_hidden false")
320 child.sendline("w")
318 child.sendline("w")
321 child.expect("__traceba")
319 child.expect("__traceba")
322 child.expect("ipdb>")
320 child.expect("ipdb>")
323
321
324 child.close()
322 child.close()
325
323
326
324
327 skip_decorators_blocks = (
325 skip_decorators_blocks = (
328 """
326 """
329 def helpers_helper():
327 def helpers_helper():
330 pass # should not stop here except breakpoint
328 pass # should not stop here except breakpoint
331 """,
329 """,
332 """
330 """
333 def helper_1():
331 def helper_1():
334 helpers_helper() # should not stop here
332 helpers_helper() # should not stop here
335 """,
333 """,
336 """
334 """
337 def helper_2():
335 def helper_2():
338 pass # should not stop here
336 pass # should not stop here
339 """,
337 """,
340 """
338 """
341 def pdb_skipped_decorator2(function):
339 def pdb_skipped_decorator2(function):
342 def wrapped_fn(*args, **kwargs):
340 def wrapped_fn(*args, **kwargs):
343 __debuggerskip__ = True
341 __debuggerskip__ = True
344 helper_2()
342 helper_2()
345 __debuggerskip__ = False
343 __debuggerskip__ = False
346 result = function(*args, **kwargs)
344 result = function(*args, **kwargs)
347 __debuggerskip__ = True
345 __debuggerskip__ = True
348 helper_2()
346 helper_2()
349 return result
347 return result
350 return wrapped_fn
348 return wrapped_fn
351 """,
349 """,
352 """
350 """
353 def pdb_skipped_decorator(function):
351 def pdb_skipped_decorator(function):
354 def wrapped_fn(*args, **kwargs):
352 def wrapped_fn(*args, **kwargs):
355 __debuggerskip__ = True
353 __debuggerskip__ = True
356 helper_1()
354 helper_1()
357 __debuggerskip__ = False
355 __debuggerskip__ = False
358 result = function(*args, **kwargs)
356 result = function(*args, **kwargs)
359 __debuggerskip__ = True
357 __debuggerskip__ = True
360 helper_2()
358 helper_2()
361 return result
359 return result
362 return wrapped_fn
360 return wrapped_fn
363 """,
361 """,
364 """
362 """
365 @pdb_skipped_decorator
363 @pdb_skipped_decorator
366 @pdb_skipped_decorator2
364 @pdb_skipped_decorator2
367 def bar(x, y):
365 def bar(x, y):
368 return x * y
366 return x * y
369 """,
367 """,
370 """import IPython.terminal.debugger as ipdb""",
368 """import IPython.terminal.debugger as ipdb""",
371 """
369 """
372 def f():
370 def f():
373 ipdb.set_trace()
371 ipdb.set_trace()
374 bar(3, 4)
372 bar(3, 4)
375 """,
373 """,
376 """
374 """
377 f()
375 f()
378 """,
376 """,
379 )
377 )
380
378
381
379
382 def _decorator_skip_setup():
380 def _decorator_skip_setup():
383 import pexpect
381 import pexpect
384
382
385 env = os.environ.copy()
383 env = os.environ.copy()
386 env["IPY_TEST_SIMPLE_PROMPT"] = "1"
384 env["IPY_TEST_SIMPLE_PROMPT"] = "1"
387
385
388 child = pexpect.spawn(
386 child = pexpect.spawn(
389 sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
387 sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
390 )
388 )
391 child.timeout = 5 * IPYTHON_TESTING_TIMEOUT_SCALE
389 child.timeout = 5 * IPYTHON_TESTING_TIMEOUT_SCALE
392
390
393 child.expect("IPython")
391 child.expect("IPython")
394 child.expect("\n")
392 child.expect("\n")
395
393
396 dedented_blocks = [dedent(b).strip() for b in skip_decorators_blocks]
394 dedented_blocks = [dedent(b).strip() for b in skip_decorators_blocks]
397 in_prompt_number = 1
395 in_prompt_number = 1
398 for cblock in dedented_blocks:
396 for cblock in dedented_blocks:
399 child.expect_exact(f"In [{in_prompt_number}]:")
397 child.expect_exact(f"In [{in_prompt_number}]:")
400 in_prompt_number += 1
398 in_prompt_number += 1
401 for line in cblock.splitlines():
399 for line in cblock.splitlines():
402 child.sendline(line)
400 child.sendline(line)
403 child.expect_exact(line)
401 child.expect_exact(line)
404 child.sendline("")
402 child.sendline("")
405 return child
403 return child
406
404
407
405
408 @skip_win32
406 @skip_win32
409 def test_decorator_skip():
407 def test_decorator_skip():
410 """test that decorator frames can be skipped."""
408 """test that decorator frames can be skipped."""
411
409
412 child = _decorator_skip_setup()
410 child = _decorator_skip_setup()
413
411
414 child.expect_exact("3 bar(3, 4)")
412 child.expect_exact("3 bar(3, 4)")
415 child.expect("ipdb>")
413 child.expect("ipdb>")
416
414
417 child.expect("ipdb>")
415 child.expect("ipdb>")
418 child.sendline("step")
416 child.sendline("step")
419 child.expect_exact("step")
417 child.expect_exact("step")
420
418
421 child.expect_exact("1 @pdb_skipped_decorator")
419 child.expect_exact("1 @pdb_skipped_decorator")
422
420
423 child.sendline("s")
421 child.sendline("s")
424 child.expect_exact("return x * y")
422 child.expect_exact("return x * y")
425
423
426 child.close()
424 child.close()
427
425
428
426
429 @skip_win32
427 @skip_win32
430 def test_decorator_skip_disabled():
428 def test_decorator_skip_disabled():
431 """test that decorator frame skipping can be disabled"""
429 """test that decorator frame skipping can be disabled"""
432
430
433 child = _decorator_skip_setup()
431 child = _decorator_skip_setup()
434
432
435 child.expect_exact("3 bar(3, 4)")
433 child.expect_exact("3 bar(3, 4)")
436
434
437 for input_, expected in [
435 for input_, expected in [
438 ("skip_predicates debuggerskip False", ""),
436 ("skip_predicates debuggerskip False", ""),
439 ("skip_predicates", "debuggerskip : False"),
437 ("skip_predicates", "debuggerskip : False"),
440 ("step", "---> 2 def wrapped_fn"),
438 ("step", "---> 2 def wrapped_fn"),
441 ("step", "----> 3 __debuggerskip__"),
439 ("step", "----> 3 __debuggerskip__"),
442 ("step", "----> 4 helper_1()"),
440 ("step", "----> 4 helper_1()"),
443 ("step", "---> 1 def helper_1():"),
441 ("step", "---> 1 def helper_1():"),
444 ("next", "----> 2 helpers_helper()"),
442 ("next", "----> 2 helpers_helper()"),
445 ("next", "--Return--"),
443 ("next", "--Return--"),
446 ("next", "----> 5 __debuggerskip__ = False"),
444 ("next", "----> 5 __debuggerskip__ = False"),
447 ]:
445 ]:
448 child.expect("ipdb>")
446 child.expect("ipdb>")
449 child.sendline(input_)
447 child.sendline(input_)
450 child.expect_exact(input_)
448 child.expect_exact(input_)
451 child.expect_exact(expected)
449 child.expect_exact(expected)
452
450
453 child.close()
451 child.close()
454
452
455
453
456 @skip_win32
454 @skip_win32
457 def test_decorator_skip_with_breakpoint():
455 def test_decorator_skip_with_breakpoint():
458 """test that decorator frame skipping can be disabled"""
456 """test that decorator frame skipping can be disabled"""
459
457
460 import pexpect
458 import pexpect
461
459
462 env = os.environ.copy()
460 env = os.environ.copy()
463 env["IPY_TEST_SIMPLE_PROMPT"] = "1"
461 env["IPY_TEST_SIMPLE_PROMPT"] = "1"
464
462
465 child = pexpect.spawn(
463 child = pexpect.spawn(
466 sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
464 sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
467 )
465 )
468 child.timeout = 5 * IPYTHON_TESTING_TIMEOUT_SCALE
466 child.timeout = 5 * IPYTHON_TESTING_TIMEOUT_SCALE
469
467
470 child.expect("IPython")
468 child.expect("IPython")
471 child.expect("\n")
469 child.expect("\n")
472
470
473 ### we need a filename, so we need to exec the full block with a filename
471 ### we need a filename, so we need to exec the full block with a filename
474 with NamedTemporaryFile(suffix=".py", dir=".", delete=True) as tf:
472 with NamedTemporaryFile(suffix=".py", dir=".", delete=True) as tf:
475
473
476 name = tf.name[:-3].split("/")[-1]
474 name = tf.name[:-3].split("/")[-1]
477 tf.write("\n".join([dedent(x) for x in skip_decorators_blocks[:-1]]).encode())
475 tf.write("\n".join([dedent(x) for x in skip_decorators_blocks[:-1]]).encode())
478 tf.flush()
476 tf.flush()
479 codeblock = f"from {name} import f"
477 codeblock = f"from {name} import f"
480
478
481 dedented_blocks = [
479 dedented_blocks = [
482 codeblock,
480 codeblock,
483 "f()",
481 "f()",
484 ]
482 ]
485
483
486 in_prompt_number = 1
484 in_prompt_number = 1
487 for cblock in dedented_blocks:
485 for cblock in dedented_blocks:
488 child.expect_exact(f"In [{in_prompt_number}]:")
486 child.expect_exact(f"In [{in_prompt_number}]:")
489 in_prompt_number += 1
487 in_prompt_number += 1
490 for line in cblock.splitlines():
488 for line in cblock.splitlines():
491 child.sendline(line)
489 child.sendline(line)
492 child.expect_exact(line)
490 child.expect_exact(line)
493 child.sendline("")
491 child.sendline("")
494
492
495 # as the filename does not exists, we'll rely on the filename prompt
493 # as the filename does not exists, we'll rely on the filename prompt
496 child.expect_exact("47 bar(3, 4)")
494 child.expect_exact("47 bar(3, 4)")
497
495
498 for input_, expected in [
496 for input_, expected in [
499 (f"b {name}.py:3", ""),
497 (f"b {name}.py:3", ""),
500 ("step", "1---> 3 pass # should not stop here except"),
498 ("step", "1---> 3 pass # should not stop here except"),
501 ("step", "---> 38 @pdb_skipped_decorator"),
499 ("step", "---> 38 @pdb_skipped_decorator"),
502 ("continue", ""),
500 ("continue", ""),
503 ]:
501 ]:
504 child.expect("ipdb>")
502 child.expect("ipdb>")
505 child.sendline(input_)
503 child.sendline(input_)
506 child.expect_exact(input_)
504 child.expect_exact(input_)
507 child.expect_exact(expected)
505 child.expect_exact(expected)
508
506
509 child.close()
507 child.close()
510
508
511
509
512 @skip_win32
510 @skip_win32
513 def test_where_erase_value():
511 def test_where_erase_value():
514 """Test that `where` does not access f_locals and erase values."""
512 """Test that `where` does not access f_locals and erase values."""
515 import pexpect
513 import pexpect
516
514
517 env = os.environ.copy()
515 env = os.environ.copy()
518 env["IPY_TEST_SIMPLE_PROMPT"] = "1"
516 env["IPY_TEST_SIMPLE_PROMPT"] = "1"
519
517
520 child = pexpect.spawn(
518 child = pexpect.spawn(
521 sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
519 sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
522 )
520 )
523 child.timeout = 15 * IPYTHON_TESTING_TIMEOUT_SCALE
521 child.timeout = 15 * IPYTHON_TESTING_TIMEOUT_SCALE
524
522
525 child.expect("IPython")
523 child.expect("IPython")
526 child.expect("\n")
524 child.expect("\n")
527 child.expect_exact("In [1]")
525 child.expect_exact("In [1]")
528
526
529 block = dedent(
527 block = dedent(
530 """
528 """
531 def simple_f():
529 def simple_f():
532 myvar = 1
530 myvar = 1
533 print(myvar)
531 print(myvar)
534 1/0
532 1/0
535 print(myvar)
533 print(myvar)
536 simple_f() """
534 simple_f() """
537 )
535 )
538
536
539 for line in block.splitlines():
537 for line in block.splitlines():
540 child.sendline(line)
538 child.sendline(line)
541 child.expect_exact(line)
539 child.expect_exact(line)
542 child.expect_exact("ZeroDivisionError")
540 child.expect_exact("ZeroDivisionError")
543 child.expect_exact("In [2]:")
541 child.expect_exact("In [2]:")
544
542
545 child.sendline("%debug")
543 child.sendline("%debug")
546
544
547 ##
545 ##
548 child.expect("ipdb>")
546 child.expect("ipdb>")
549
547
550 child.sendline("myvar")
548 child.sendline("myvar")
551 child.expect("1")
549 child.expect("1")
552
550
553 ##
551 ##
554 child.expect("ipdb>")
552 child.expect("ipdb>")
555
553
556 child.sendline("myvar = 2")
554 child.sendline("myvar = 2")
557
555
558 ##
556 ##
559 child.expect_exact("ipdb>")
557 child.expect_exact("ipdb>")
560
558
561 child.sendline("myvar")
559 child.sendline("myvar")
562
560
563 child.expect_exact("2")
561 child.expect_exact("2")
564
562
565 ##
563 ##
566 child.expect("ipdb>")
564 child.expect("ipdb>")
567 child.sendline("where")
565 child.sendline("where")
568
566
569 ##
567 ##
570 child.expect("ipdb>")
568 child.expect("ipdb>")
571 child.sendline("myvar")
569 child.sendline("myvar")
572
570
573 child.expect_exact("2")
571 child.expect_exact("2")
574 child.expect("ipdb>")
572 child.expect("ipdb>")
575
573
576 child.close()
574 child.close()
@@ -1,490 +1,511 b''
1 # Copyright (c) IPython Development Team.
1 # Copyright (c) IPython Development Team.
2 # Distributed under the terms of the Modified BSD License.
2 # Distributed under the terms of the Modified BSD License.
3
3
4 import json
4 import json
5 import os
5 import os
6 import warnings
6 import warnings
7
7
8 from unittest import mock
8 from unittest import mock
9
9
10 import nose.tools as nt
10 import pytest
11
11
12 from IPython import display
12 from IPython import display
13 from IPython.core.getipython import get_ipython
13 from IPython.core.getipython import get_ipython
14 from IPython.utils.io import capture_output
14 from IPython.utils.io import capture_output
15 from IPython.utils.tempdir import NamedFileInTemporaryDirectory
15 from IPython.utils.tempdir import NamedFileInTemporaryDirectory
16 from IPython import paths as ipath
16 from IPython import paths as ipath
17 from IPython.testing.tools import AssertNotPrints
17 from IPython.testing.tools import AssertNotPrints
18
18
19 import IPython.testing.decorators as dec
19 import IPython.testing.decorators as dec
20
20
21 def test_image_size():
21 def test_image_size():
22 """Simple test for display.Image(args, width=x,height=y)"""
22 """Simple test for display.Image(args, width=x,height=y)"""
23 thisurl = 'http://www.google.fr/images/srpr/logo3w.png'
23 thisurl = 'http://www.google.fr/images/srpr/logo3w.png'
24 img = display.Image(url=thisurl, width=200, height=200)
24 img = display.Image(url=thisurl, width=200, height=200)
25 nt.assert_equal(u'<img src="%s" width="200" height="200"/>' % (thisurl), img._repr_html_())
25 assert '<img src="%s" width="200" height="200"/>' % (thisurl) == img._repr_html_()
26 img = display.Image(url=thisurl, metadata={'width':200, 'height':200})
26 img = display.Image(url=thisurl, metadata={'width':200, 'height':200})
27 nt.assert_equal(u'<img src="%s" width="200" height="200"/>' % (thisurl), img._repr_html_())
27 assert '<img src="%s" width="200" height="200"/>' % (thisurl) == img._repr_html_()
28 img = display.Image(url=thisurl, width=200)
28 img = display.Image(url=thisurl, width=200)
29 nt.assert_equal(u'<img src="%s" width="200"/>' % (thisurl), img._repr_html_())
29 assert '<img src="%s" width="200"/>' % (thisurl) == img._repr_html_()
30 img = display.Image(url=thisurl)
30 img = display.Image(url=thisurl)
31 nt.assert_equal(u'<img src="%s"/>' % (thisurl), img._repr_html_())
31 assert '<img src="%s"/>' % (thisurl) == img._repr_html_()
32 img = display.Image(url=thisurl, unconfined=True)
32 img = display.Image(url=thisurl, unconfined=True)
33 nt.assert_equal(u'<img src="%s" class="unconfined"/>' % (thisurl), img._repr_html_())
33 assert '<img src="%s" class="unconfined"/>' % (thisurl) == img._repr_html_()
34
34
35
35
36 def test_image_mimes():
36 def test_image_mimes():
37 fmt = get_ipython().display_formatter.format
37 fmt = get_ipython().display_formatter.format
38 for format in display.Image._ACCEPTABLE_EMBEDDINGS:
38 for format in display.Image._ACCEPTABLE_EMBEDDINGS:
39 mime = display.Image._MIMETYPES[format]
39 mime = display.Image._MIMETYPES[format]
40 img = display.Image(b'garbage', format=format)
40 img = display.Image(b'garbage', format=format)
41 data, metadata = fmt(img)
41 data, metadata = fmt(img)
42 nt.assert_equal(sorted(data), sorted([mime, 'text/plain']))
42 assert sorted(data) == sorted([mime, "text/plain"])
43
43
44
44
45 def test_geojson():
45 def test_geojson():
46
46
47 gj = display.GeoJSON(data={
47 gj = display.GeoJSON(data={
48 "type": "Feature",
48 "type": "Feature",
49 "geometry": {
49 "geometry": {
50 "type": "Point",
50 "type": "Point",
51 "coordinates": [-81.327, 296.038]
51 "coordinates": [-81.327, 296.038]
52 },
52 },
53 "properties": {
53 "properties": {
54 "name": "Inca City"
54 "name": "Inca City"
55 }
55 }
56 },
56 },
57 url_template="http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/{basemap_id}/{z}/{x}/{y}.png",
57 url_template="http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/{basemap_id}/{z}/{x}/{y}.png",
58 layer_options={
58 layer_options={
59 "basemap_id": "celestia_mars-shaded-16k_global",
59 "basemap_id": "celestia_mars-shaded-16k_global",
60 "attribution": "Celestia/praesepe",
60 "attribution": "Celestia/praesepe",
61 "minZoom": 0,
61 "minZoom": 0,
62 "maxZoom": 18,
62 "maxZoom": 18,
63 })
63 },
64 nt.assert_equal(u'<IPython.core.display.GeoJSON object>', str(gj))
64 )
65 assert "<IPython.core.display.GeoJSON object>" == str(gj)
66
65
67
66 def test_retina_png():
68 def test_retina_png():
67 here = os.path.dirname(__file__)
69 here = os.path.dirname(__file__)
68 img = display.Image(os.path.join(here, "2x2.png"), retina=True)
70 img = display.Image(os.path.join(here, "2x2.png"), retina=True)
69 nt.assert_equal(img.height, 1)
71 assert img.height == 1
70 nt.assert_equal(img.width, 1)
72 assert img.width == 1
71 data, md = img._repr_png_()
73 data, md = img._repr_png_()
72 nt.assert_equal(md['width'], 1)
74 assert md["width"] == 1
73 nt.assert_equal(md['height'], 1)
75 assert md["height"] == 1
76
74
77
75 def test_embed_svg_url():
78 def test_embed_svg_url():
76 import gzip
79 import gzip
77 from io import BytesIO
80 from io import BytesIO
78 svg_data = b'<svg><circle x="0" y="0" r="1"/></svg>'
81 svg_data = b'<svg><circle x="0" y="0" r="1"/></svg>'
79 url = 'http://test.com/circle.svg'
82 url = 'http://test.com/circle.svg'
80
83
81 gzip_svg = BytesIO()
84 gzip_svg = BytesIO()
82 with gzip.open(gzip_svg, 'wb') as fp:
85 with gzip.open(gzip_svg, 'wb') as fp:
83 fp.write(svg_data)
86 fp.write(svg_data)
84 gzip_svg = gzip_svg.getvalue()
87 gzip_svg = gzip_svg.getvalue()
85
88
86 def mocked_urlopen(*args, **kwargs):
89 def mocked_urlopen(*args, **kwargs):
87 class MockResponse:
90 class MockResponse:
88 def __init__(self, svg):
91 def __init__(self, svg):
89 self._svg_data = svg
92 self._svg_data = svg
90 self.headers = {'content-type': 'image/svg+xml'}
93 self.headers = {'content-type': 'image/svg+xml'}
91
94
92 def read(self):
95 def read(self):
93 return self._svg_data
96 return self._svg_data
94
97
95 if args[0] == url:
98 if args[0] == url:
96 return MockResponse(svg_data)
99 return MockResponse(svg_data)
97 elif args[0] == url + "z":
100 elif args[0] == url + "z":
98 ret = MockResponse(gzip_svg)
101 ret = MockResponse(gzip_svg)
99 ret.headers["content-encoding"] = "gzip"
102 ret.headers["content-encoding"] = "gzip"
100 return ret
103 return ret
101 return MockResponse(None)
104 return MockResponse(None)
102
105
103 with mock.patch('urllib.request.urlopen', side_effect=mocked_urlopen):
106 with mock.patch('urllib.request.urlopen', side_effect=mocked_urlopen):
104 svg = display.SVG(url=url)
107 svg = display.SVG(url=url)
105 nt.assert_true(svg._repr_svg_().startswith('<svg'))
108 assert svg._repr_svg_().startswith("<svg") is True
106 svg = display.SVG(url=url + 'z')
109 svg = display.SVG(url=url + "z")
107 nt.assert_true(svg._repr_svg_().startswith('<svg'))
110 assert svg._repr_svg_().startswith("<svg") is True
111
108
112
109 def test_retina_jpeg():
113 def test_retina_jpeg():
110 here = os.path.dirname(__file__)
114 here = os.path.dirname(__file__)
111 img = display.Image(os.path.join(here, "2x2.jpg"), retina=True)
115 img = display.Image(os.path.join(here, "2x2.jpg"), retina=True)
112 nt.assert_equal(img.height, 1)
116 assert img.height == 1
113 nt.assert_equal(img.width, 1)
117 assert img.width == 1
114 data, md = img._repr_jpeg_()
118 data, md = img._repr_jpeg_()
115 nt.assert_equal(md['width'], 1)
119 assert md["width"] == 1
116 nt.assert_equal(md['height'], 1)
120 assert md["height"] == 1
121
117
122
118 def test_base64image():
123 def test_base64image():
119 display.Image("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB94BCRQnOqNu0b4AAAAKSURBVAjXY2AAAAACAAHiIbwzAAAAAElFTkSuQmCC")
124 display.Image("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB94BCRQnOqNu0b4AAAAKSURBVAjXY2AAAAACAAHiIbwzAAAAAElFTkSuQmCC")
120
125
121 def test_image_filename_defaults():
126 def test_image_filename_defaults():
122 '''test format constraint, and validity of jpeg and png'''
127 '''test format constraint, and validity of jpeg and png'''
123 tpath = ipath.get_ipython_package_dir()
128 tpath = ipath.get_ipython_package_dir()
124 nt.assert_raises(ValueError, display.Image, filename=os.path.join(tpath, 'testing/tests/badformat.zip'),
129 pytest.raises(
125 embed=True)
130 ValueError,
126 nt.assert_raises(ValueError, display.Image)
131 display.Image,
127 nt.assert_raises(ValueError, display.Image, data='this is not an image', format='badformat', embed=True)
132 filename=os.path.join(tpath, "testing/tests/badformat.zip"),
128 # check both paths to allow packages to test at build and install time
133 embed=True,
134 )
135 pytest.raises(ValueError, display.Image)
136 pytest.raises(
137 ValueError,
138 display.Image,
139 data="this is not an image",
140 format="badformat",
141 embed=True,
142 )
143 # check boths paths to allow packages to test at build and install time
129 imgfile = os.path.join(tpath, 'core/tests/2x2.png')
144 imgfile = os.path.join(tpath, 'core/tests/2x2.png')
130 img = display.Image(filename=imgfile)
145 img = display.Image(filename=imgfile)
131 nt.assert_equal('png', img.format)
146 assert "png" == img.format
132 nt.assert_is_not_none(img._repr_png_())
147 assert img._repr_png_() is not None
133 img = display.Image(filename=os.path.join(tpath, 'testing/tests/logo.jpg'), embed=False)
148 img = display.Image(
134 nt.assert_equal('jpeg', img.format)
149 filename=os.path.join(tpath, "testing/tests/logo.jpg"), embed=False
135 nt.assert_is_none(img._repr_jpeg_())
150 )
151 assert "jpeg" == img.format
152 assert img._repr_jpeg_() is None
136
153
137 def _get_inline_config():
154 def _get_inline_config():
138 from matplotlib_inline.config import InlineBackend
155 from matplotlib_inline.config import InlineBackend
139 return InlineBackend.instance()
156 return InlineBackend.instance()
140
157
141
158
142 @dec.skip_without("ipykernel")
159 @dec.skip_without("ipykernel")
143 @dec.skip_without("matplotlib")
160 @dec.skip_without("matplotlib")
144 def test_set_matplotlib_close():
161 def test_set_matplotlib_close():
145 cfg = _get_inline_config()
162 cfg = _get_inline_config()
146 cfg.close_figures = False
163 cfg.close_figures = False
147 display.set_matplotlib_close()
164 display.set_matplotlib_close()
148 assert cfg.close_figures
165 assert cfg.close_figures
149 display.set_matplotlib_close(False)
166 display.set_matplotlib_close(False)
150 assert not cfg.close_figures
167 assert not cfg.close_figures
151
168
152 _fmt_mime_map = {
169 _fmt_mime_map = {
153 'png': 'image/png',
170 'png': 'image/png',
154 'jpeg': 'image/jpeg',
171 'jpeg': 'image/jpeg',
155 'pdf': 'application/pdf',
172 'pdf': 'application/pdf',
156 'retina': 'image/png',
173 'retina': 'image/png',
157 'svg': 'image/svg+xml',
174 'svg': 'image/svg+xml',
158 }
175 }
159
176
160 @dec.skip_without('matplotlib')
177 @dec.skip_without('matplotlib')
161 def test_set_matplotlib_formats():
178 def test_set_matplotlib_formats():
162 from matplotlib.figure import Figure
179 from matplotlib.figure import Figure
163 formatters = get_ipython().display_formatter.formatters
180 formatters = get_ipython().display_formatter.formatters
164 for formats in [
181 for formats in [
165 ('png',),
182 ('png',),
166 ('pdf', 'svg'),
183 ('pdf', 'svg'),
167 ('jpeg', 'retina', 'png'),
184 ('jpeg', 'retina', 'png'),
168 (),
185 (),
169 ]:
186 ]:
170 active_mimes = {_fmt_mime_map[fmt] for fmt in formats}
187 active_mimes = {_fmt_mime_map[fmt] for fmt in formats}
171 display.set_matplotlib_formats(*formats)
188 display.set_matplotlib_formats(*formats)
172 for mime, f in formatters.items():
189 for mime, f in formatters.items():
173 if mime in active_mimes:
190 if mime in active_mimes:
174 nt.assert_in(Figure, f)
191 assert Figure in f
175 else:
192 else:
176 nt.assert_not_in(Figure, f)
193 assert Figure not in f
177
194
178
195
179 @dec.skip_without("ipykernel")
196 @dec.skip_without("ipykernel")
180 @dec.skip_without("matplotlib")
197 @dec.skip_without("matplotlib")
181 def test_set_matplotlib_formats_kwargs():
198 def test_set_matplotlib_formats_kwargs():
182 from matplotlib.figure import Figure
199 from matplotlib.figure import Figure
183 ip = get_ipython()
200 ip = get_ipython()
184 cfg = _get_inline_config()
201 cfg = _get_inline_config()
185 cfg.print_figure_kwargs.update(dict(foo='bar'))
202 cfg.print_figure_kwargs.update(dict(foo='bar'))
186 kwargs = dict(dpi=150)
203 kwargs = dict(dpi=150)
187 display.set_matplotlib_formats('png', **kwargs)
204 display.set_matplotlib_formats('png', **kwargs)
188 formatter = ip.display_formatter.formatters['image/png']
205 formatter = ip.display_formatter.formatters['image/png']
189 f = formatter.lookup_by_type(Figure)
206 f = formatter.lookup_by_type(Figure)
190 formatter_kwargs = f.keywords
207 formatter_kwargs = f.keywords
191 expected = kwargs
208 expected = kwargs
192 expected["base64"] = True
209 expected["base64"] = True
193 expected["fmt"] = "png"
210 expected["fmt"] = "png"
194 expected.update(cfg.print_figure_kwargs)
211 expected.update(cfg.print_figure_kwargs)
195 nt.assert_equal(formatter_kwargs, expected)
212 assert formatter_kwargs == expected
196
213
197 def test_display_available():
214 def test_display_available():
198 """
215 """
199 Test that display is available without import
216 Test that display is available without import
200
217
201 We don't really care if it's in builtin or anything else, but it should
218 We don't really care if it's in builtin or anything else, but it should
202 always be available.
219 always be available.
203 """
220 """
204 ip = get_ipython()
221 ip = get_ipython()
205 with AssertNotPrints('NameError'):
222 with AssertNotPrints('NameError'):
206 ip.run_cell('display')
223 ip.run_cell('display')
207 try:
224 try:
208 ip.run_cell('del display')
225 ip.run_cell('del display')
209 except NameError:
226 except NameError:
210 pass # it's ok, it might be in builtins
227 pass # it's ok, it might be in builtins
211 # even if deleted it should be back
228 # even if deleted it should be back
212 with AssertNotPrints('NameError'):
229 with AssertNotPrints('NameError'):
213 ip.run_cell('display')
230 ip.run_cell('display')
214
231
215 def test_textdisplayobj_pretty_repr():
232 def test_textdisplayobj_pretty_repr():
216 p = display.Pretty("This is a simple test")
233 p = display.Pretty("This is a simple test")
217 nt.assert_equal(repr(p), '<IPython.core.display.Pretty object>')
234 assert repr(p) == "<IPython.core.display.Pretty object>"
218 nt.assert_equal(p.data, 'This is a simple test')
235 assert p.data == "This is a simple test"
236
237 p._show_mem_addr = True
238 assert repr(p) == object.__repr__(p)
219
239
220 p._show_mem_addr = True
221 nt.assert_equal(repr(p), object.__repr__(p))
222
240
223 def test_displayobject_repr():
241 def test_displayobject_repr():
224 h = display.HTML('<br />')
242 h = display.HTML("<br />")
225 nt.assert_equal(repr(h), '<IPython.core.display.HTML object>')
243 assert repr(h) == "<IPython.core.display.HTML object>"
226 h._show_mem_addr = True
244 h._show_mem_addr = True
227 nt.assert_equal(repr(h), object.__repr__(h))
245 assert repr(h) == object.__repr__(h)
228 h._show_mem_addr = False
246 h._show_mem_addr = False
229 nt.assert_equal(repr(h), '<IPython.core.display.HTML object>')
247 assert repr(h) == "<IPython.core.display.HTML object>"
230
248
231 j = display.Javascript('')
249 j = display.Javascript("")
232 nt.assert_equal(repr(j), '<IPython.core.display.Javascript object>')
250 assert repr(j) == "<IPython.core.display.Javascript object>"
233 j._show_mem_addr = True
251 j._show_mem_addr = True
234 nt.assert_equal(repr(j), object.__repr__(j))
252 assert repr(j) == object.__repr__(j)
235 j._show_mem_addr = False
253 j._show_mem_addr = False
236 nt.assert_equal(repr(j), '<IPython.core.display.Javascript object>')
254 assert repr(j) == "<IPython.core.display.Javascript object>"
237
255
238 @mock.patch('warnings.warn')
256 @mock.patch('warnings.warn')
239 def test_encourage_iframe_over_html(m_warn):
257 def test_encourage_iframe_over_html(m_warn):
240 display.HTML()
258 display.HTML()
241 m_warn.assert_not_called()
259 m_warn.assert_not_called()
242
260
243 display.HTML('<br />')
261 display.HTML('<br />')
244 m_warn.assert_not_called()
262 m_warn.assert_not_called()
245
263
246 display.HTML('<html><p>Lots of content here</p><iframe src="http://a.com"></iframe>')
264 display.HTML('<html><p>Lots of content here</p><iframe src="http://a.com"></iframe>')
247 m_warn.assert_not_called()
265 m_warn.assert_not_called()
248
266
249 display.HTML('<iframe src="http://a.com"></iframe>')
267 display.HTML('<iframe src="http://a.com"></iframe>')
250 m_warn.assert_called_with('Consider using IPython.display.IFrame instead')
268 m_warn.assert_called_with('Consider using IPython.display.IFrame instead')
251
269
252 m_warn.reset_mock()
270 m_warn.reset_mock()
253 display.HTML('<IFRAME SRC="http://a.com"></IFRAME>')
271 display.HTML('<IFRAME SRC="http://a.com"></IFRAME>')
254 m_warn.assert_called_with('Consider using IPython.display.IFrame instead')
272 m_warn.assert_called_with('Consider using IPython.display.IFrame instead')
255
273
256 def test_progress():
274 def test_progress():
257 p = display.ProgressBar(10)
275 p = display.ProgressBar(10)
258 nt.assert_in('0/10',repr(p))
276 assert "0/10" in repr(p)
259 p.html_width = '100%'
277 p.html_width = "100%"
260 p.progress = 5
278 p.progress = 5
261 nt.assert_equal(p._repr_html_(), "<progress style='width:100%' max='10' value='5'></progress>")
279 assert (
280 p._repr_html_() == "<progress style='width:100%' max='10' value='5'></progress>"
281 )
282
262
283
263 def test_progress_iter():
284 def test_progress_iter():
264 with capture_output(display=False) as captured:
285 with capture_output(display=False) as captured:
265 for i in display.ProgressBar(5):
286 for i in display.ProgressBar(5):
266 out = captured.stdout
287 out = captured.stdout
267 nt.assert_in('{0}/5'.format(i), out)
288 assert "{0}/5".format(i) in out
268 out = captured.stdout
289 out = captured.stdout
269 nt.assert_in('5/5', out)
290 assert "5/5" in out
291
270
292
271 def test_json():
293 def test_json():
272 d = {'a': 5}
294 d = {'a': 5}
273 lis = [d]
295 lis = [d]
274 metadata = [
296 metadata = [
275 {'expanded': False, 'root': 'root'},
297 {'expanded': False, 'root': 'root'},
276 {'expanded': True, 'root': 'root'},
298 {'expanded': True, 'root': 'root'},
277 {'expanded': False, 'root': 'custom'},
299 {'expanded': False, 'root': 'custom'},
278 {'expanded': True, 'root': 'custom'},
300 {'expanded': True, 'root': 'custom'},
279 ]
301 ]
280 json_objs = [
302 json_objs = [
281 display.JSON(d),
303 display.JSON(d),
282 display.JSON(d, expanded=True),
304 display.JSON(d, expanded=True),
283 display.JSON(d, root='custom'),
305 display.JSON(d, root='custom'),
284 display.JSON(d, expanded=True, root='custom'),
306 display.JSON(d, expanded=True, root='custom'),
285 ]
307 ]
286 for j, md in zip(json_objs, metadata):
308 for j, md in zip(json_objs, metadata):
287 nt.assert_equal(j._repr_json_(), (d, md))
309 assert j._repr_json_() == (d, md)
288
310
289 with warnings.catch_warnings(record=True) as w:
311 with warnings.catch_warnings(record=True) as w:
290 warnings.simplefilter("always")
312 warnings.simplefilter("always")
291 j = display.JSON(json.dumps(d))
313 j = display.JSON(json.dumps(d))
292 nt.assert_equal(len(w), 1)
314 assert len(w) == 1
293 nt.assert_equal(j._repr_json_(), (d, metadata[0]))
315 assert j._repr_json_() == (d, metadata[0])
294
316
295 json_objs = [
317 json_objs = [
296 display.JSON(lis),
318 display.JSON(lis),
297 display.JSON(lis, expanded=True),
319 display.JSON(lis, expanded=True),
298 display.JSON(lis, root='custom'),
320 display.JSON(lis, root='custom'),
299 display.JSON(lis, expanded=True, root='custom'),
321 display.JSON(lis, expanded=True, root='custom'),
300 ]
322 ]
301 for j, md in zip(json_objs, metadata):
323 for j, md in zip(json_objs, metadata):
302 nt.assert_equal(j._repr_json_(), (lis, md))
324 assert j._repr_json_() == (lis, md)
303
325
304 with warnings.catch_warnings(record=True) as w:
326 with warnings.catch_warnings(record=True) as w:
305 warnings.simplefilter("always")
327 warnings.simplefilter("always")
306 j = display.JSON(json.dumps(lis))
328 j = display.JSON(json.dumps(lis))
307 nt.assert_equal(len(w), 1)
329 assert len(w) == 1
308 nt.assert_equal(j._repr_json_(), (lis, metadata[0]))
330 assert j._repr_json_() == (lis, metadata[0])
331
309
332
310 def test_video_embedding():
333 def test_video_embedding():
311 """use a tempfile, with dummy-data, to ensure that video embedding doesn't crash"""
334 """use a tempfile, with dummy-data, to ensure that video embedding doesn't crash"""
312 v = display.Video("http://ignored")
335 v = display.Video("http://ignored")
313 assert not v.embed
336 assert not v.embed
314 html = v._repr_html_()
337 html = v._repr_html_()
315 nt.assert_not_in('src="data:', html)
338 assert 'src="data:' not in html
316 nt.assert_in('src="http://ignored"', html)
339 assert 'src="http://ignored"' in html
317
340
318 with nt.assert_raises(ValueError):
341 with pytest.raises(ValueError):
319 v = display.Video(b'abc')
342 v = display.Video(b'abc')
320
343
321 with NamedFileInTemporaryDirectory('test.mp4') as f:
344 with NamedFileInTemporaryDirectory('test.mp4') as f:
322 f.write(b'abc')
345 f.write(b'abc')
323 f.close()
346 f.close()
324
347
325 v = display.Video(f.name)
348 v = display.Video(f.name)
326 assert not v.embed
349 assert not v.embed
327 html = v._repr_html_()
350 html = v._repr_html_()
328 nt.assert_not_in('src="data:', html)
351 assert 'src="data:' not in html
329
352
330 v = display.Video(f.name, embed=True)
353 v = display.Video(f.name, embed=True)
331 html = v._repr_html_()
354 html = v._repr_html_()
332 nt.assert_in('src="data:video/mp4;base64,YWJj"',html)
355 assert 'src="data:video/mp4;base64,YWJj"' in html
333
356
334 v = display.Video(f.name, embed=True, mimetype='video/other')
357 v = display.Video(f.name, embed=True, mimetype='video/other')
335 html = v._repr_html_()
358 html = v._repr_html_()
336 nt.assert_in('src="data:video/other;base64,YWJj"',html)
359 assert 'src="data:video/other;base64,YWJj"' in html
337
360
338 v = display.Video(b'abc', embed=True, mimetype='video/mp4')
361 v = display.Video(b'abc', embed=True, mimetype='video/mp4')
339 html = v._repr_html_()
362 html = v._repr_html_()
340 nt.assert_in('src="data:video/mp4;base64,YWJj"',html)
363 assert 'src="data:video/mp4;base64,YWJj"' in html
341
364
342 v = display.Video(u'YWJj', embed=True, mimetype='video/xyz')
365 v = display.Video(u'YWJj', embed=True, mimetype='video/xyz')
343 html = v._repr_html_()
366 html = v._repr_html_()
344 nt.assert_in('src="data:video/xyz;base64,YWJj"',html)
367 assert 'src="data:video/xyz;base64,YWJj"' in html
345
368
346 def test_html_metadata():
369 def test_html_metadata():
347 s = "<h1>Test</h1>"
370 s = "<h1>Test</h1>"
348 h = display.HTML(s, metadata={"isolated": True})
371 h = display.HTML(s, metadata={"isolated": True})
349 nt.assert_equal(h._repr_html_(), (s, {"isolated": True}))
372 assert h._repr_html_() == (s, {"isolated": True})
373
350
374
351 def test_display_id():
375 def test_display_id():
352 ip = get_ipython()
376 ip = get_ipython()
353 with mock.patch.object(ip.display_pub, 'publish') as pub:
377 with mock.patch.object(ip.display_pub, 'publish') as pub:
354 handle = display.display('x')
378 handle = display.display('x')
355 nt.assert_is(handle, None)
379 assert handle is None
356 handle = display.display('y', display_id='secret')
380 handle = display.display('y', display_id='secret')
357 nt.assert_is_instance(handle, display.DisplayHandle)
381 assert isinstance(handle, display.DisplayHandle)
358 handle2 = display.display('z', display_id=True)
382 handle2 = display.display('z', display_id=True)
359 nt.assert_is_instance(handle2, display.DisplayHandle)
383 assert isinstance(handle2, display.DisplayHandle)
360 nt.assert_not_equal(handle.display_id, handle2.display_id)
384 assert handle.display_id != handle2.display_id
361
385
362 nt.assert_equal(pub.call_count, 3)
386 assert pub.call_count == 3
363 args, kwargs = pub.call_args_list[0]
387 args, kwargs = pub.call_args_list[0]
364 nt.assert_equal(args, ())
388 assert args == ()
365 nt.assert_equal(kwargs, {
389 assert kwargs == {
366 'data': {
390 'data': {
367 'text/plain': repr('x')
391 'text/plain': repr('x')
368 },
392 },
369 'metadata': {},
393 'metadata': {},
370 })
394 }
371 args, kwargs = pub.call_args_list[1]
395 args, kwargs = pub.call_args_list[1]
372 nt.assert_equal(args, ())
396 assert args == ()
373 nt.assert_equal(kwargs, {
397 assert kwargs == {
374 'data': {
398 'data': {
375 'text/plain': repr('y')
399 'text/plain': repr('y')
376 },
400 },
377 'metadata': {},
401 'metadata': {},
378 'transient': {
402 'transient': {
379 'display_id': handle.display_id,
403 'display_id': handle.display_id,
380 },
404 },
381 })
405 }
382 args, kwargs = pub.call_args_list[2]
406 args, kwargs = pub.call_args_list[2]
383 nt.assert_equal(args, ())
407 assert args == ()
384 nt.assert_equal(kwargs, {
408 assert kwargs == {
385 'data': {
409 'data': {
386 'text/plain': repr('z')
410 'text/plain': repr('z')
387 },
411 },
388 'metadata': {},
412 'metadata': {},
389 'transient': {
413 'transient': {
390 'display_id': handle2.display_id,
414 'display_id': handle2.display_id,
391 },
415 },
392 })
416 }
393
417
394
418
395 def test_update_display():
419 def test_update_display():
396 ip = get_ipython()
420 ip = get_ipython()
397 with mock.patch.object(ip.display_pub, 'publish') as pub:
421 with mock.patch.object(ip.display_pub, 'publish') as pub:
398 with nt.assert_raises(TypeError):
422 with pytest.raises(TypeError):
399 display.update_display('x')
423 display.update_display('x')
400 display.update_display('x', display_id='1')
424 display.update_display('x', display_id='1')
401 display.update_display('y', display_id='2')
425 display.update_display('y', display_id='2')
402 args, kwargs = pub.call_args_list[0]
426 args, kwargs = pub.call_args_list[0]
403 nt.assert_equal(args, ())
427 assert args == ()
404 nt.assert_equal(kwargs, {
428 assert kwargs == {
405 'data': {
429 'data': {
406 'text/plain': repr('x')
430 'text/plain': repr('x')
407 },
431 },
408 'metadata': {},
432 'metadata': {},
409 'transient': {
433 'transient': {
410 'display_id': '1',
434 'display_id': '1',
411 },
435 },
412 'update': True,
436 'update': True,
413 })
437 }
414 args, kwargs = pub.call_args_list[1]
438 args, kwargs = pub.call_args_list[1]
415 nt.assert_equal(args, ())
439 assert args == ()
416 nt.assert_equal(kwargs, {
440 assert kwargs == {
417 'data': {
441 'data': {
418 'text/plain': repr('y')
442 'text/plain': repr('y')
419 },
443 },
420 'metadata': {},
444 'metadata': {},
421 'transient': {
445 'transient': {
422 'display_id': '2',
446 'display_id': '2',
423 },
447 },
424 'update': True,
448 'update': True,
425 })
449 }
426
450
427
451
428 def test_display_handle():
452 def test_display_handle():
429 ip = get_ipython()
453 ip = get_ipython()
430 handle = display.DisplayHandle()
454 handle = display.DisplayHandle()
431 nt.assert_is_instance(handle.display_id, str)
455 assert isinstance(handle.display_id, str)
432 handle = display.DisplayHandle('my-id')
456 handle = display.DisplayHandle("my-id")
433 nt.assert_equal(handle.display_id, 'my-id')
457 assert handle.display_id == "my-id"
434 with mock.patch.object(ip.display_pub, 'publish') as pub:
458 with mock.patch.object(ip.display_pub, "publish") as pub:
435 handle.display('x')
459 handle.display("x")
436 handle.update('y')
460 handle.update("y")
437
461
438 args, kwargs = pub.call_args_list[0]
462 args, kwargs = pub.call_args_list[0]
439 nt.assert_equal(args, ())
463 assert args == ()
440 nt.assert_equal(kwargs, {
464 assert kwargs == {
441 'data': {
465 'data': {
442 'text/plain': repr('x')
466 'text/plain': repr('x')
443 },
467 },
444 'metadata': {},
468 'metadata': {},
445 'transient': {
469 'transient': {
446 'display_id': handle.display_id,
470 'display_id': handle.display_id,
447 }
471 }
448 })
472 }
449 args, kwargs = pub.call_args_list[1]
473 args, kwargs = pub.call_args_list[1]
450 nt.assert_equal(args, ())
474 assert args == ()
451 nt.assert_equal(kwargs, {
475 assert kwargs == {
452 'data': {
476 'data': {
453 'text/plain': repr('y')
477 'text/plain': repr('y')
454 },
478 },
455 'metadata': {},
479 'metadata': {},
456 'transient': {
480 'transient': {
457 'display_id': handle.display_id,
481 'display_id': handle.display_id,
458 },
482 },
459 'update': True,
483 'update': True,
460 })
484 }
461
485
462
486
463 def test_image_alt_tag():
487 def test_image_alt_tag():
464 """Simple test for display.Image(args, alt=x,)"""
488 """Simple test for display.Image(args, alt=x,)"""
465 thisurl = "http://example.com/image.png"
489 thisurl = "http://example.com/image.png"
466 img = display.Image(url=thisurl, alt="an image")
490 img = display.Image(url=thisurl, alt="an image")
467 nt.assert_equal(u'<img src="%s" alt="an image"/>' % (thisurl), img._repr_html_())
491 assert '<img src="%s" alt="an image"/>' % (thisurl) == img._repr_html_()
468 img = display.Image(url=thisurl, unconfined=True, alt="an image")
492 img = display.Image(url=thisurl, unconfined=True, alt="an image")
469 nt.assert_equal(
493 assert (
470 u'<img src="%s" class="unconfined" alt="an image"/>' % (thisurl),
494 '<img src="%s" class="unconfined" alt="an image"/>' % (thisurl)
471 img._repr_html_(),
495 == img._repr_html_()
472 )
496 )
473 img = display.Image(url=thisurl, alt='>"& <')
497 img = display.Image(url=thisurl, alt='>"& <')
474 nt.assert_equal(
498 assert '<img src="%s" alt="&gt;&quot;&amp; &lt;"/>' % (thisurl) == img._repr_html_()
475 u'<img src="%s" alt="&gt;&quot;&amp; &lt;"/>' % (thisurl), img._repr_html_()
476 )
477
499
478 img = display.Image(url=thisurl, metadata={"alt": "an image"})
500 img = display.Image(url=thisurl, metadata={"alt": "an image"})
479 nt.assert_equal(img.alt, "an image")
501 assert img.alt == "an image"
480
481 here = os.path.dirname(__file__)
502 here = os.path.dirname(__file__)
482 img = display.Image(os.path.join(here, "2x2.png"), alt="an image")
503 img = display.Image(os.path.join(here, "2x2.png"), alt="an image")
483 nt.assert_equal(img.alt, "an image")
504 assert img.alt == "an image"
484 _, md = img._repr_png_()
505 _, md = img._repr_png_()
485 nt.assert_equal(md["alt"], "an image")
506 assert md["alt"] == "an image"
486
507
487
508
488 @nt.raises(FileNotFoundError)
489 def test_image_bad_filename_raises_proper_exception():
509 def test_image_bad_filename_raises_proper_exception():
490 display.Image("/this/file/does/not/exist/")._repr_png_()
510 with pytest.raises(FileNotFoundError):
511 display.Image("/this/file/does/not/exist/")._repr_png_()
@@ -1,92 +1,91 b''
1 import unittest
1 import unittest
2 from unittest.mock import Mock
2 from unittest.mock import Mock
3 import nose.tools as nt
4
3
5 from IPython.core import events
4 from IPython.core import events
6 import IPython.testing.tools as tt
5 import IPython.testing.tools as tt
7
6
8
7
9 @events._define_event
8 @events._define_event
10 def ping_received():
9 def ping_received():
11 pass
10 pass
12
11
13
12
14 @events._define_event
13 @events._define_event
15 def event_with_argument(argument):
14 def event_with_argument(argument):
16 pass
15 pass
17
16
18
17
19 class CallbackTests(unittest.TestCase):
18 class CallbackTests(unittest.TestCase):
20 def setUp(self):
19 def setUp(self):
21 self.em = events.EventManager(get_ipython(),
20 self.em = events.EventManager(get_ipython(),
22 {'ping_received': ping_received,
21 {'ping_received': ping_received,
23 'event_with_argument': event_with_argument})
22 'event_with_argument': event_with_argument})
24
23
25 def test_register_unregister(self):
24 def test_register_unregister(self):
26 cb = Mock()
25 cb = Mock()
27
26
28 self.em.register('ping_received', cb)
27 self.em.register('ping_received', cb)
29 self.em.trigger('ping_received')
28 self.em.trigger('ping_received')
30 self.assertEqual(cb.call_count, 1)
29 self.assertEqual(cb.call_count, 1)
31
30
32 self.em.unregister('ping_received', cb)
31 self.em.unregister('ping_received', cb)
33 self.em.trigger('ping_received')
32 self.em.trigger('ping_received')
34 self.assertEqual(cb.call_count, 1)
33 self.assertEqual(cb.call_count, 1)
35
34
36 def test_bare_function_missed_unregister(self):
35 def test_bare_function_missed_unregister(self):
37 def cb1():
36 def cb1():
38 ...
37 ...
39
38
40 def cb2():
39 def cb2():
41 ...
40 ...
42
41
43 self.em.register('ping_received', cb1)
42 self.em.register("ping_received", cb1)
44 nt.assert_raises(ValueError, self.em.unregister, 'ping_received', cb2)
43 self.assertRaises(ValueError, self.em.unregister, "ping_received", cb2)
45 self.em.unregister('ping_received', cb1)
44 self.em.unregister("ping_received", cb1)
46
45
47 def test_cb_error(self):
46 def test_cb_error(self):
48 cb = Mock(side_effect=ValueError)
47 cb = Mock(side_effect=ValueError)
49 self.em.register('ping_received', cb)
48 self.em.register('ping_received', cb)
50 with tt.AssertPrints("Error in callback"):
49 with tt.AssertPrints("Error in callback"):
51 self.em.trigger('ping_received')
50 self.em.trigger('ping_received')
52
51
53 def test_cb_keyboard_interrupt(self):
52 def test_cb_keyboard_interrupt(self):
54 cb = Mock(side_effect=KeyboardInterrupt)
53 cb = Mock(side_effect=KeyboardInterrupt)
55 self.em.register('ping_received', cb)
54 self.em.register('ping_received', cb)
56 with tt.AssertPrints("Error in callback"):
55 with tt.AssertPrints("Error in callback"):
57 self.em.trigger('ping_received')
56 self.em.trigger('ping_received')
58
57
59 def test_unregister_during_callback(self):
58 def test_unregister_during_callback(self):
60 invoked = [False] * 3
59 invoked = [False] * 3
61
60
62 def func1(*_):
61 def func1(*_):
63 invoked[0] = True
62 invoked[0] = True
64 self.em.unregister('ping_received', func1)
63 self.em.unregister('ping_received', func1)
65 self.em.register('ping_received', func3)
64 self.em.register('ping_received', func3)
66
65
67 def func2(*_):
66 def func2(*_):
68 invoked[1] = True
67 invoked[1] = True
69 self.em.unregister('ping_received', func2)
68 self.em.unregister('ping_received', func2)
70
69
71 def func3(*_):
70 def func3(*_):
72 invoked[2] = True
71 invoked[2] = True
73
72
74 self.em.register('ping_received', func1)
73 self.em.register('ping_received', func1)
75 self.em.register('ping_received', func2)
74 self.em.register('ping_received', func2)
76
75
77 self.em.trigger('ping_received')
76 self.em.trigger('ping_received')
78 self.assertEqual([True, True, False], invoked)
77 self.assertEqual([True, True, False], invoked)
79 self.assertEqual([func3], self.em.callbacks['ping_received'])
78 self.assertEqual([func3], self.em.callbacks['ping_received'])
80
79
81 def test_ignore_event_arguments_if_no_argument_required(self):
80 def test_ignore_event_arguments_if_no_argument_required(self):
82 call_count = [0]
81 call_count = [0]
83 def event_with_no_argument():
82 def event_with_no_argument():
84 call_count[0] += 1
83 call_count[0] += 1
85
84
86 self.em.register('event_with_argument', event_with_no_argument)
85 self.em.register('event_with_argument', event_with_no_argument)
87 self.em.trigger('event_with_argument', 'the argument')
86 self.em.trigger('event_with_argument', 'the argument')
88 self.assertEqual(call_count[0], 1)
87 self.assertEqual(call_count[0], 1)
89
88
90 self.em.unregister('event_with_argument', event_with_no_argument)
89 self.em.unregister('event_with_argument', event_with_no_argument)
91 self.em.trigger('ping_received')
90 self.em.trigger('ping_received')
92 self.assertEqual(call_count[0], 1)
91 self.assertEqual(call_count[0], 1)
@@ -1,96 +1,94 b''
1 import os.path
1 import os.path
2
2
3 import nose.tools as nt
4
5 import IPython.testing.tools as tt
3 import IPython.testing.tools as tt
6 from IPython.utils.syspathcontext import prepended_to_syspath
4 from IPython.utils.syspathcontext import prepended_to_syspath
7 from IPython.utils.tempdir import TemporaryDirectory
5 from IPython.utils.tempdir import TemporaryDirectory
8
6
9 ext1_content = """
7 ext1_content = """
10 def load_ipython_extension(ip):
8 def load_ipython_extension(ip):
11 print("Running ext1 load")
9 print("Running ext1 load")
12
10
13 def unload_ipython_extension(ip):
11 def unload_ipython_extension(ip):
14 print("Running ext1 unload")
12 print("Running ext1 unload")
15 """
13 """
16
14
17 ext2_content = """
15 ext2_content = """
18 def load_ipython_extension(ip):
16 def load_ipython_extension(ip):
19 print("Running ext2 load")
17 print("Running ext2 load")
20 """
18 """
21
19
22 ext3_content = """
20 ext3_content = """
23 def load_ipython_extension(ip):
21 def load_ipython_extension(ip):
24 ip2 = get_ipython()
22 ip2 = get_ipython()
25 print(ip is ip2)
23 print(ip is ip2)
26 """
24 """
27
25
28 def test_extension_loading():
26 def test_extension_loading():
29 em = get_ipython().extension_manager
27 em = get_ipython().extension_manager
30 with TemporaryDirectory() as td:
28 with TemporaryDirectory() as td:
31 ext1 = os.path.join(td, 'ext1.py')
29 ext1 = os.path.join(td, 'ext1.py')
32 with open(ext1, 'w') as f:
30 with open(ext1, 'w') as f:
33 f.write(ext1_content)
31 f.write(ext1_content)
34
32
35 ext2 = os.path.join(td, 'ext2.py')
33 ext2 = os.path.join(td, 'ext2.py')
36 with open(ext2, 'w') as f:
34 with open(ext2, 'w') as f:
37 f.write(ext2_content)
35 f.write(ext2_content)
38
36
39 with prepended_to_syspath(td):
37 with prepended_to_syspath(td):
40 assert 'ext1' not in em.loaded
38 assert 'ext1' not in em.loaded
41 assert 'ext2' not in em.loaded
39 assert 'ext2' not in em.loaded
42
40
43 # Load extension
41 # Load extension
44 with tt.AssertPrints("Running ext1 load"):
42 with tt.AssertPrints("Running ext1 load"):
45 assert em.load_extension('ext1') is None
43 assert em.load_extension('ext1') is None
46 assert 'ext1' in em.loaded
44 assert 'ext1' in em.loaded
47
45
48 # Should refuse to load it again
46 # Should refuse to load it again
49 with tt.AssertNotPrints("Running ext1 load"):
47 with tt.AssertNotPrints("Running ext1 load"):
50 assert em.load_extension('ext1') == 'already loaded'
48 assert em.load_extension('ext1') == 'already loaded'
51
49
52 # Reload
50 # Reload
53 with tt.AssertPrints("Running ext1 unload"):
51 with tt.AssertPrints("Running ext1 unload"):
54 with tt.AssertPrints("Running ext1 load", suppress=False):
52 with tt.AssertPrints("Running ext1 load", suppress=False):
55 em.reload_extension('ext1')
53 em.reload_extension('ext1')
56
54
57 # Unload
55 # Unload
58 with tt.AssertPrints("Running ext1 unload"):
56 with tt.AssertPrints("Running ext1 unload"):
59 assert em.unload_extension('ext1') is None
57 assert em.unload_extension('ext1') is None
60
58
61 # Can't unload again
59 # Can't unload again
62 with tt.AssertNotPrints("Running ext1 unload"):
60 with tt.AssertNotPrints("Running ext1 unload"):
63 assert em.unload_extension('ext1') == 'not loaded'
61 assert em.unload_extension('ext1') == 'not loaded'
64 assert em.unload_extension('ext2') == 'not loaded'
62 assert em.unload_extension('ext2') == 'not loaded'
65
63
66 # Load extension 2
64 # Load extension 2
67 with tt.AssertPrints("Running ext2 load"):
65 with tt.AssertPrints("Running ext2 load"):
68 assert em.load_extension('ext2') is None
66 assert em.load_extension('ext2') is None
69
67
70 # Can't unload this
68 # Can't unload this
71 assert em.unload_extension('ext2') == 'no unload function'
69 assert em.unload_extension('ext2') == 'no unload function'
72
70
73 # But can reload it
71 # But can reload it
74 with tt.AssertPrints("Running ext2 load"):
72 with tt.AssertPrints("Running ext2 load"):
75 em.reload_extension('ext2')
73 em.reload_extension('ext2')
76
74
77
75
78 def test_extension_builtins():
76 def test_extension_builtins():
79 em = get_ipython().extension_manager
77 em = get_ipython().extension_manager
80 with TemporaryDirectory() as td:
78 with TemporaryDirectory() as td:
81 ext3 = os.path.join(td, 'ext3.py')
79 ext3 = os.path.join(td, 'ext3.py')
82 with open(ext3, 'w') as f:
80 with open(ext3, 'w') as f:
83 f.write(ext3_content)
81 f.write(ext3_content)
84
82
85 assert 'ext3' not in em.loaded
83 assert 'ext3' not in em.loaded
86
84
87 with prepended_to_syspath(td):
85 with prepended_to_syspath(td):
88 # Load extension
86 # Load extension
89 with tt.AssertPrints("True"):
87 with tt.AssertPrints("True"):
90 assert em.load_extension('ext3') is None
88 assert em.load_extension('ext3') is None
91 assert 'ext3' in em.loaded
89 assert 'ext3' in em.loaded
92
90
93
91
94 def test_non_extension():
92 def test_non_extension():
95 em = get_ipython().extension_manager
93 em = get_ipython().extension_manager
96 nt.assert_equal(em.load_extension('sys'), "no load function")
94 assert em.load_extension("sys") == "no load function"
@@ -1,542 +1,544 b''
1 """Tests for the Formatters."""
1 """Tests for the Formatters."""
2
2
3 import warnings
3 import warnings
4 from math import pi
4 from math import pi
5
5
6 try:
6 try:
7 import numpy
7 import numpy
8 except:
8 except:
9 numpy = None
9 numpy = None
10 import nose.tools as nt
10 import pytest
11
11
12 from IPython import get_ipython
12 from IPython import get_ipython
13 from traitlets.config import Config
13 from traitlets.config import Config
14 from IPython.core.formatters import (
14 from IPython.core.formatters import (
15 PlainTextFormatter, HTMLFormatter, PDFFormatter, _mod_name_key,
15 PlainTextFormatter, HTMLFormatter, PDFFormatter, _mod_name_key,
16 DisplayFormatter, JSONFormatter,
16 DisplayFormatter, JSONFormatter,
17 )
17 )
18 from IPython.utils.io import capture_output
18 from IPython.utils.io import capture_output
19
19
20 class A(object):
20 class A(object):
21 def __repr__(self):
21 def __repr__(self):
22 return 'A()'
22 return 'A()'
23
23
24 class B(A):
24 class B(A):
25 def __repr__(self):
25 def __repr__(self):
26 return 'B()'
26 return 'B()'
27
27
28 class C:
28 class C:
29 pass
29 pass
30
30
31 class BadRepr(object):
31 class BadRepr(object):
32 def __repr__(self):
32 def __repr__(self):
33 raise ValueError("bad repr")
33 raise ValueError("bad repr")
34
34
35 class BadPretty(object):
35 class BadPretty(object):
36 _repr_pretty_ = None
36 _repr_pretty_ = None
37
37
38 class GoodPretty(object):
38 class GoodPretty(object):
39 def _repr_pretty_(self, pp, cycle):
39 def _repr_pretty_(self, pp, cycle):
40 pp.text('foo')
40 pp.text('foo')
41
41
42 def __repr__(self):
42 def __repr__(self):
43 return 'GoodPretty()'
43 return 'GoodPretty()'
44
44
45 def foo_printer(obj, pp, cycle):
45 def foo_printer(obj, pp, cycle):
46 pp.text('foo')
46 pp.text('foo')
47
47
48 def test_pretty():
48 def test_pretty():
49 f = PlainTextFormatter()
49 f = PlainTextFormatter()
50 f.for_type(A, foo_printer)
50 f.for_type(A, foo_printer)
51 assert f(A()) == "foo"
51 assert f(A()) == "foo"
52 assert f(B()) == "B()"
52 assert f(B()) == "B()"
53 assert f(GoodPretty()) == "foo"
53 assert f(GoodPretty()) == "foo"
54 # Just don't raise an exception for the following:
54 # Just don't raise an exception for the following:
55 f(BadPretty())
55 f(BadPretty())
56
56
57 f.pprint = False
57 f.pprint = False
58 assert f(A()) == "A()"
58 assert f(A()) == "A()"
59 assert f(B()) == "B()"
59 assert f(B()) == "B()"
60 assert f(GoodPretty()) == "GoodPretty()"
60 assert f(GoodPretty()) == "GoodPretty()"
61
61
62
62
63 def test_deferred():
63 def test_deferred():
64 f = PlainTextFormatter()
64 f = PlainTextFormatter()
65
65
66 def test_precision():
66 def test_precision():
67 """test various values for float_precision."""
67 """test various values for float_precision."""
68 f = PlainTextFormatter()
68 f = PlainTextFormatter()
69 assert f(pi) == repr(pi)
69 assert f(pi) == repr(pi)
70 f.float_precision = 0
70 f.float_precision = 0
71 if numpy:
71 if numpy:
72 po = numpy.get_printoptions()
72 po = numpy.get_printoptions()
73 assert po["precision"] == 0
73 assert po["precision"] == 0
74 assert f(pi) == "3"
74 assert f(pi) == "3"
75 f.float_precision = 2
75 f.float_precision = 2
76 if numpy:
76 if numpy:
77 po = numpy.get_printoptions()
77 po = numpy.get_printoptions()
78 assert po["precision"] == 2
78 assert po["precision"] == 2
79 assert f(pi) == "3.14"
79 assert f(pi) == "3.14"
80 f.float_precision = "%g"
80 f.float_precision = "%g"
81 if numpy:
81 if numpy:
82 po = numpy.get_printoptions()
82 po = numpy.get_printoptions()
83 assert po["precision"] == 2
83 assert po["precision"] == 2
84 assert f(pi) == "3.14159"
84 assert f(pi) == "3.14159"
85 f.float_precision = "%e"
85 f.float_precision = "%e"
86 assert f(pi) == "3.141593e+00"
86 assert f(pi) == "3.141593e+00"
87 f.float_precision = ""
87 f.float_precision = ""
88 if numpy:
88 if numpy:
89 po = numpy.get_printoptions()
89 po = numpy.get_printoptions()
90 assert po["precision"] == 8
90 assert po["precision"] == 8
91 assert f(pi) == repr(pi)
91 assert f(pi) == repr(pi)
92
92
93
93
94 def test_bad_precision():
94 def test_bad_precision():
95 """test various invalid values for float_precision."""
95 """test various invalid values for float_precision."""
96 f = PlainTextFormatter()
96 f = PlainTextFormatter()
97 def set_fp(p):
97 def set_fp(p):
98 f.float_precision=p
98 f.float_precision = p
99 nt.assert_raises(ValueError, set_fp, '%')
99
100 nt.assert_raises(ValueError, set_fp, '%.3f%i')
100 pytest.raises(ValueError, set_fp, "%")
101 nt.assert_raises(ValueError, set_fp, 'foo')
101 pytest.raises(ValueError, set_fp, "%.3f%i")
102 nt.assert_raises(ValueError, set_fp, -1)
102 pytest.raises(ValueError, set_fp, "foo")
103 pytest.raises(ValueError, set_fp, -1)
103
104
104 def test_for_type():
105 def test_for_type():
105 f = PlainTextFormatter()
106 f = PlainTextFormatter()
106
107
107 # initial return, None
108 # initial return, None
108 nt.assert_is(f.for_type(C, foo_printer), None)
109 assert f.for_type(C, foo_printer) is None
109 # no func queries
110 # no func queries
110 nt.assert_is(f.for_type(C), foo_printer)
111 assert f.for_type(C) is foo_printer
111 # shouldn't change anything
112 # shouldn't change anything
112 nt.assert_is(f.for_type(C), foo_printer)
113 assert f.for_type(C) is foo_printer
113 # None should do the same
114 # None should do the same
114 nt.assert_is(f.for_type(C, None), foo_printer)
115 assert f.for_type(C, None) is foo_printer
115 nt.assert_is(f.for_type(C, None), foo_printer)
116 assert f.for_type(C, None) is foo_printer
116
117
117 def test_for_type_string():
118 def test_for_type_string():
118 f = PlainTextFormatter()
119 f = PlainTextFormatter()
119
120
120 type_str = '%s.%s' % (C.__module__, 'C')
121 type_str = '%s.%s' % (C.__module__, 'C')
121
122
122 # initial return, None
123 # initial return, None
123 nt.assert_is(f.for_type(type_str, foo_printer), None)
124 assert f.for_type(type_str, foo_printer) is None
124 # no func queries
125 # no func queries
125 nt.assert_is(f.for_type(type_str), foo_printer)
126 assert f.for_type(type_str) is foo_printer
126 nt.assert_in(_mod_name_key(C), f.deferred_printers)
127 assert _mod_name_key(C) in f.deferred_printers
127 nt.assert_is(f.for_type(C), foo_printer)
128 assert f.for_type(C) is foo_printer
128 nt.assert_not_in(_mod_name_key(C), f.deferred_printers)
129 assert _mod_name_key(C) not in f.deferred_printers
129 nt.assert_in(C, f.type_printers)
130 assert C in f.type_printers
130
131
131 def test_for_type_by_name():
132 def test_for_type_by_name():
132 f = PlainTextFormatter()
133 f = PlainTextFormatter()
133
134
134 mod = C.__module__
135 mod = C.__module__
135
136
136 # initial return, None
137 # initial return, None
137 nt.assert_is(f.for_type_by_name(mod, 'C', foo_printer), None)
138 assert f.for_type_by_name(mod, "C", foo_printer) is None
138 # no func queries
139 # no func queries
139 nt.assert_is(f.for_type_by_name(mod, 'C'), foo_printer)
140 assert f.for_type_by_name(mod, "C") is foo_printer
140 # shouldn't change anything
141 # shouldn't change anything
141 nt.assert_is(f.for_type_by_name(mod, 'C'), foo_printer)
142 assert f.for_type_by_name(mod, "C") is foo_printer
142 # None should do the same
143 # None should do the same
143 nt.assert_is(f.for_type_by_name(mod, 'C', None), foo_printer)
144 assert f.for_type_by_name(mod, "C", None) is foo_printer
144 nt.assert_is(f.for_type_by_name(mod, 'C', None), foo_printer)
145 assert f.for_type_by_name(mod, "C", None) is foo_printer
146
145
147
146 def test_lookup():
148 def test_lookup():
147 f = PlainTextFormatter()
149 f = PlainTextFormatter()
148
150
149 f.for_type(C, foo_printer)
151 f.for_type(C, foo_printer)
150 nt.assert_is(f.lookup(C()), foo_printer)
152 assert f.lookup(C()) is foo_printer
151 with nt.assert_raises(KeyError):
153 with pytest.raises(KeyError):
152 f.lookup(A())
154 f.lookup(A())
153
155
154 def test_lookup_string():
156 def test_lookup_string():
155 f = PlainTextFormatter()
157 f = PlainTextFormatter()
156 type_str = '%s.%s' % (C.__module__, 'C')
158 type_str = '%s.%s' % (C.__module__, 'C')
157
159
158 f.for_type(type_str, foo_printer)
160 f.for_type(type_str, foo_printer)
159 nt.assert_is(f.lookup(C()), foo_printer)
161 assert f.lookup(C()) is foo_printer
160 # should move from deferred to imported dict
162 # should move from deferred to imported dict
161 nt.assert_not_in(_mod_name_key(C), f.deferred_printers)
163 assert _mod_name_key(C) not in f.deferred_printers
162 nt.assert_in(C, f.type_printers)
164 assert C in f.type_printers
163
165
164 def test_lookup_by_type():
166 def test_lookup_by_type():
165 f = PlainTextFormatter()
167 f = PlainTextFormatter()
166 f.for_type(C, foo_printer)
168 f.for_type(C, foo_printer)
167 nt.assert_is(f.lookup_by_type(C), foo_printer)
169 assert f.lookup_by_type(C) is foo_printer
168 with nt.assert_raises(KeyError):
170 with pytest.raises(KeyError):
169 f.lookup_by_type(A)
171 f.lookup_by_type(A)
170
172
171 def test_lookup_by_type_string():
173 def test_lookup_by_type_string():
172 f = PlainTextFormatter()
174 f = PlainTextFormatter()
173 type_str = '%s.%s' % (C.__module__, 'C')
175 type_str = '%s.%s' % (C.__module__, 'C')
174 f.for_type(type_str, foo_printer)
176 f.for_type(type_str, foo_printer)
175
177
176 # verify insertion
178 # verify insertion
177 nt.assert_in(_mod_name_key(C), f.deferred_printers)
179 assert _mod_name_key(C) in f.deferred_printers
178 nt.assert_not_in(C, f.type_printers)
180 assert C not in f.type_printers
179
181
180 nt.assert_is(f.lookup_by_type(type_str), foo_printer)
182 assert f.lookup_by_type(type_str) is foo_printer
181 # lookup by string doesn't cause import
183 # lookup by string doesn't cause import
182 nt.assert_in(_mod_name_key(C), f.deferred_printers)
184 assert _mod_name_key(C) in f.deferred_printers
183 nt.assert_not_in(C, f.type_printers)
185 assert C not in f.type_printers
184
186
185 nt.assert_is(f.lookup_by_type(C), foo_printer)
187 assert f.lookup_by_type(C) is foo_printer
186 # should move from deferred to imported dict
188 # should move from deferred to imported dict
187 nt.assert_not_in(_mod_name_key(C), f.deferred_printers)
189 assert _mod_name_key(C) not in f.deferred_printers
188 nt.assert_in(C, f.type_printers)
190 assert C in f.type_printers
189
191
190 def test_in_formatter():
192 def test_in_formatter():
191 f = PlainTextFormatter()
193 f = PlainTextFormatter()
192 f.for_type(C, foo_printer)
194 f.for_type(C, foo_printer)
193 type_str = '%s.%s' % (C.__module__, 'C')
195 type_str = '%s.%s' % (C.__module__, 'C')
194 nt.assert_in(C, f)
196 assert C in f
195 nt.assert_in(type_str, f)
197 assert type_str in f
196
198
197 def test_string_in_formatter():
199 def test_string_in_formatter():
198 f = PlainTextFormatter()
200 f = PlainTextFormatter()
199 type_str = '%s.%s' % (C.__module__, 'C')
201 type_str = '%s.%s' % (C.__module__, 'C')
200 f.for_type(type_str, foo_printer)
202 f.for_type(type_str, foo_printer)
201 nt.assert_in(type_str, f)
203 assert type_str in f
202 nt.assert_in(C, f)
204 assert C in f
203
205
204 def test_pop():
206 def test_pop():
205 f = PlainTextFormatter()
207 f = PlainTextFormatter()
206 f.for_type(C, foo_printer)
208 f.for_type(C, foo_printer)
207 nt.assert_is(f.lookup_by_type(C), foo_printer)
209 assert f.lookup_by_type(C) is foo_printer
208 nt.assert_is(f.pop(C, None), foo_printer)
210 assert f.pop(C, None) is foo_printer
209 f.for_type(C, foo_printer)
211 f.for_type(C, foo_printer)
210 nt.assert_is(f.pop(C), foo_printer)
212 assert f.pop(C) is foo_printer
211 with nt.assert_raises(KeyError):
213 with pytest.raises(KeyError):
212 f.lookup_by_type(C)
214 f.lookup_by_type(C)
213 with nt.assert_raises(KeyError):
215 with pytest.raises(KeyError):
214 f.pop(C)
216 f.pop(C)
215 with nt.assert_raises(KeyError):
217 with pytest.raises(KeyError):
216 f.pop(A)
218 f.pop(A)
217 nt.assert_is(f.pop(A, None), None)
219 assert f.pop(A, None) is None
218
220
219 def test_pop_string():
221 def test_pop_string():
220 f = PlainTextFormatter()
222 f = PlainTextFormatter()
221 type_str = '%s.%s' % (C.__module__, 'C')
223 type_str = '%s.%s' % (C.__module__, 'C')
222
224
223 with nt.assert_raises(KeyError):
225 with pytest.raises(KeyError):
224 f.pop(type_str)
226 f.pop(type_str)
225
227
226 f.for_type(type_str, foo_printer)
228 f.for_type(type_str, foo_printer)
227 f.pop(type_str)
229 f.pop(type_str)
228 with nt.assert_raises(KeyError):
230 with pytest.raises(KeyError):
229 f.lookup_by_type(C)
231 f.lookup_by_type(C)
230 with nt.assert_raises(KeyError):
232 with pytest.raises(KeyError):
231 f.pop(type_str)
233 f.pop(type_str)
232
234
233 f.for_type(C, foo_printer)
235 f.for_type(C, foo_printer)
234 nt.assert_is(f.pop(type_str, None), foo_printer)
236 assert f.pop(type_str, None) is foo_printer
235 with nt.assert_raises(KeyError):
237 with pytest.raises(KeyError):
236 f.lookup_by_type(C)
238 f.lookup_by_type(C)
237 with nt.assert_raises(KeyError):
239 with pytest.raises(KeyError):
238 f.pop(type_str)
240 f.pop(type_str)
239 nt.assert_is(f.pop(type_str, None), None)
241 assert f.pop(type_str, None) is None
240
242
241
243
242 def test_error_method():
244 def test_error_method():
243 f = HTMLFormatter()
245 f = HTMLFormatter()
244 class BadHTML(object):
246 class BadHTML(object):
245 def _repr_html_(self):
247 def _repr_html_(self):
246 raise ValueError("Bad HTML")
248 raise ValueError("Bad HTML")
247 bad = BadHTML()
249 bad = BadHTML()
248 with capture_output() as captured:
250 with capture_output() as captured:
249 result = f(bad)
251 result = f(bad)
250 nt.assert_is(result, None)
252 assert result is None
251 nt.assert_in("Traceback", captured.stdout)
253 assert "Traceback" in captured.stdout
252 nt.assert_in("Bad HTML", captured.stdout)
254 assert "Bad HTML" in captured.stdout
253 nt.assert_in("_repr_html_", captured.stdout)
255 assert "_repr_html_" in captured.stdout
254
256
255 def test_nowarn_notimplemented():
257 def test_nowarn_notimplemented():
256 f = HTMLFormatter()
258 f = HTMLFormatter()
257 class HTMLNotImplemented(object):
259 class HTMLNotImplemented(object):
258 def _repr_html_(self):
260 def _repr_html_(self):
259 raise NotImplementedError
261 raise NotImplementedError
260 h = HTMLNotImplemented()
262 h = HTMLNotImplemented()
261 with capture_output() as captured:
263 with capture_output() as captured:
262 result = f(h)
264 result = f(h)
263 nt.assert_is(result, None)
265 assert result is None
264 assert "" == captured.stderr
266 assert "" == captured.stderr
265 assert "" == captured.stdout
267 assert "" == captured.stdout
266
268
267
269
268 def test_warn_error_for_type():
270 def test_warn_error_for_type():
269 f = HTMLFormatter()
271 f = HTMLFormatter()
270 f.for_type(int, lambda i: name_error)
272 f.for_type(int, lambda i: name_error)
271 with capture_output() as captured:
273 with capture_output() as captured:
272 result = f(5)
274 result = f(5)
273 nt.assert_is(result, None)
275 assert result is None
274 nt.assert_in("Traceback", captured.stdout)
276 assert "Traceback" in captured.stdout
275 nt.assert_in("NameError", captured.stdout)
277 assert "NameError" in captured.stdout
276 nt.assert_in("name_error", captured.stdout)
278 assert "name_error" in captured.stdout
277
279
278 def test_error_pretty_method():
280 def test_error_pretty_method():
279 f = PlainTextFormatter()
281 f = PlainTextFormatter()
280 class BadPretty(object):
282 class BadPretty(object):
281 def _repr_pretty_(self):
283 def _repr_pretty_(self):
282 return "hello"
284 return "hello"
283 bad = BadPretty()
285 bad = BadPretty()
284 with capture_output() as captured:
286 with capture_output() as captured:
285 result = f(bad)
287 result = f(bad)
286 nt.assert_is(result, None)
288 assert result is None
287 nt.assert_in("Traceback", captured.stdout)
289 assert "Traceback" in captured.stdout
288 nt.assert_in("_repr_pretty_", captured.stdout)
290 assert "_repr_pretty_" in captured.stdout
289 nt.assert_in("given", captured.stdout)
291 assert "given" in captured.stdout
290 nt.assert_in("argument", captured.stdout)
292 assert "argument" in captured.stdout
291
293
292
294
293 def test_bad_repr_traceback():
295 def test_bad_repr_traceback():
294 f = PlainTextFormatter()
296 f = PlainTextFormatter()
295 bad = BadRepr()
297 bad = BadRepr()
296 with capture_output() as captured:
298 with capture_output() as captured:
297 result = f(bad)
299 result = f(bad)
298 # catches error, returns None
300 # catches error, returns None
299 nt.assert_is(result, None)
301 assert result is None
300 nt.assert_in("Traceback", captured.stdout)
302 assert "Traceback" in captured.stdout
301 nt.assert_in("__repr__", captured.stdout)
303 assert "__repr__" in captured.stdout
302 nt.assert_in("ValueError", captured.stdout)
304 assert "ValueError" in captured.stdout
303
305
304
306
305 class MakePDF(object):
307 class MakePDF(object):
306 def _repr_pdf_(self):
308 def _repr_pdf_(self):
307 return 'PDF'
309 return 'PDF'
308
310
309 def test_pdf_formatter():
311 def test_pdf_formatter():
310 pdf = MakePDF()
312 pdf = MakePDF()
311 f = PDFFormatter()
313 f = PDFFormatter()
312 assert f(pdf) == "PDF"
314 assert f(pdf) == "PDF"
313
315
314
316
315 def test_print_method_bound():
317 def test_print_method_bound():
316 f = HTMLFormatter()
318 f = HTMLFormatter()
317 class MyHTML(object):
319 class MyHTML(object):
318 def _repr_html_(self):
320 def _repr_html_(self):
319 return "hello"
321 return "hello"
320 with capture_output() as captured:
322 with capture_output() as captured:
321 result = f(MyHTML)
323 result = f(MyHTML)
322 nt.assert_is(result, None)
324 assert result is None
323 nt.assert_not_in("FormatterWarning", captured.stderr)
325 assert "FormatterWarning" not in captured.stderr
324
326
325 with capture_output() as captured:
327 with capture_output() as captured:
326 result = f(MyHTML())
328 result = f(MyHTML())
327 assert result == "hello"
329 assert result == "hello"
328 assert captured.stderr == ""
330 assert captured.stderr == ""
329
331
330
332
331 def test_print_method_weird():
333 def test_print_method_weird():
332
334
333 class TextMagicHat(object):
335 class TextMagicHat(object):
334 def __getattr__(self, key):
336 def __getattr__(self, key):
335 return key
337 return key
336
338
337 f = HTMLFormatter()
339 f = HTMLFormatter()
338
340
339 text_hat = TextMagicHat()
341 text_hat = TextMagicHat()
340 assert text_hat._repr_html_ == "_repr_html_"
342 assert text_hat._repr_html_ == "_repr_html_"
341 with capture_output() as captured:
343 with capture_output() as captured:
342 result = f(text_hat)
344 result = f(text_hat)
343
345
344 nt.assert_is(result, None)
346 assert result is None
345 nt.assert_not_in("FormatterWarning", captured.stderr)
347 assert "FormatterWarning" not in captured.stderr
346
348
347 class CallableMagicHat(object):
349 class CallableMagicHat(object):
348 def __getattr__(self, key):
350 def __getattr__(self, key):
349 return lambda : key
351 return lambda : key
350
352
351 call_hat = CallableMagicHat()
353 call_hat = CallableMagicHat()
352 with capture_output() as captured:
354 with capture_output() as captured:
353 result = f(call_hat)
355 result = f(call_hat)
354
356
355 assert result is None
357 assert result is None
356
358
357 class BadReprArgs(object):
359 class BadReprArgs(object):
358 def _repr_html_(self, extra, args):
360 def _repr_html_(self, extra, args):
359 return "html"
361 return "html"
360
362
361 bad = BadReprArgs()
363 bad = BadReprArgs()
362 with capture_output() as captured:
364 with capture_output() as captured:
363 result = f(bad)
365 result = f(bad)
364
366
365 nt.assert_is(result, None)
367 assert result is None
366 nt.assert_not_in("FormatterWarning", captured.stderr)
368 assert "FormatterWarning" not in captured.stderr
367
369
368
370
369 def test_format_config():
371 def test_format_config():
370 """config objects don't pretend to support fancy reprs with lazy attrs"""
372 """config objects don't pretend to support fancy reprs with lazy attrs"""
371 f = HTMLFormatter()
373 f = HTMLFormatter()
372 cfg = Config()
374 cfg = Config()
373 with capture_output() as captured:
375 with capture_output() as captured:
374 result = f(cfg)
376 result = f(cfg)
375 nt.assert_is(result, None)
377 assert result is None
376 assert captured.stderr == ""
378 assert captured.stderr == ""
377
379
378 with capture_output() as captured:
380 with capture_output() as captured:
379 result = f(Config)
381 result = f(Config)
380 nt.assert_is(result, None)
382 assert result is None
381 assert captured.stderr == ""
383 assert captured.stderr == ""
382
384
383
385
384 def test_pretty_max_seq_length():
386 def test_pretty_max_seq_length():
385 f = PlainTextFormatter(max_seq_length=1)
387 f = PlainTextFormatter(max_seq_length=1)
386 lis = list(range(3))
388 lis = list(range(3))
387 text = f(lis)
389 text = f(lis)
388 assert text == "[0, ...]"
390 assert text == "[0, ...]"
389 f.max_seq_length = 0
391 f.max_seq_length = 0
390 text = f(lis)
392 text = f(lis)
391 assert text == "[0, 1, 2]"
393 assert text == "[0, 1, 2]"
392 text = f(list(range(1024)))
394 text = f(list(range(1024)))
393 lines = text.splitlines()
395 lines = text.splitlines()
394 assert len(lines) == 1024
396 assert len(lines) == 1024
395
397
396
398
397 def test_ipython_display_formatter():
399 def test_ipython_display_formatter():
398 """Objects with _ipython_display_ defined bypass other formatters"""
400 """Objects with _ipython_display_ defined bypass other formatters"""
399 f = get_ipython().display_formatter
401 f = get_ipython().display_formatter
400 catcher = []
402 catcher = []
401 class SelfDisplaying(object):
403 class SelfDisplaying(object):
402 def _ipython_display_(self):
404 def _ipython_display_(self):
403 catcher.append(self)
405 catcher.append(self)
404
406
405 class NotSelfDisplaying(object):
407 class NotSelfDisplaying(object):
406 def __repr__(self):
408 def __repr__(self):
407 return "NotSelfDisplaying"
409 return "NotSelfDisplaying"
408
410
409 def _ipython_display_(self):
411 def _ipython_display_(self):
410 raise NotImplementedError
412 raise NotImplementedError
411
413
412 save_enabled = f.ipython_display_formatter.enabled
414 save_enabled = f.ipython_display_formatter.enabled
413 f.ipython_display_formatter.enabled = True
415 f.ipython_display_formatter.enabled = True
414
416
415 yes = SelfDisplaying()
417 yes = SelfDisplaying()
416 no = NotSelfDisplaying()
418 no = NotSelfDisplaying()
417
419
418 d, md = f.format(no)
420 d, md = f.format(no)
419 assert d == {"text/plain": repr(no)}
421 assert d == {"text/plain": repr(no)}
420 assert md == {}
422 assert md == {}
421 assert catcher == []
423 assert catcher == []
422
424
423 d, md = f.format(yes)
425 d, md = f.format(yes)
424 assert d == {}
426 assert d == {}
425 assert md == {}
427 assert md == {}
426 assert catcher == [yes]
428 assert catcher == [yes]
427
429
428 f.ipython_display_formatter.enabled = save_enabled
430 f.ipython_display_formatter.enabled = save_enabled
429
431
430
432
431 def test_json_as_string_deprecated():
433 def test_json_as_string_deprecated():
432 class JSONString(object):
434 class JSONString(object):
433 def _repr_json_(self):
435 def _repr_json_(self):
434 return '{}'
436 return '{}'
435
437
436 f = JSONFormatter()
438 f = JSONFormatter()
437 with warnings.catch_warnings(record=True) as w:
439 with warnings.catch_warnings(record=True) as w:
438 d = f(JSONString())
440 d = f(JSONString())
439 assert d == {}
441 assert d == {}
440 assert len(w) == 1
442 assert len(w) == 1
441
443
442
444
443 def test_repr_mime():
445 def test_repr_mime():
444 class HasReprMime(object):
446 class HasReprMime(object):
445 def _repr_mimebundle_(self, include=None, exclude=None):
447 def _repr_mimebundle_(self, include=None, exclude=None):
446 return {
448 return {
447 'application/json+test.v2': {
449 'application/json+test.v2': {
448 'x': 'y'
450 'x': 'y'
449 },
451 },
450 'plain/text' : '<HasReprMime>',
452 'plain/text' : '<HasReprMime>',
451 'image/png' : 'i-overwrite'
453 'image/png' : 'i-overwrite'
452 }
454 }
453
455
454 def _repr_png_(self):
456 def _repr_png_(self):
455 return 'should-be-overwritten'
457 return 'should-be-overwritten'
456 def _repr_html_(self):
458 def _repr_html_(self):
457 return '<b>hi!</b>'
459 return '<b>hi!</b>'
458
460
459 f = get_ipython().display_formatter
461 f = get_ipython().display_formatter
460 html_f = f.formatters['text/html']
462 html_f = f.formatters['text/html']
461 save_enabled = html_f.enabled
463 save_enabled = html_f.enabled
462 html_f.enabled = True
464 html_f.enabled = True
463 obj = HasReprMime()
465 obj = HasReprMime()
464 d, md = f.format(obj)
466 d, md = f.format(obj)
465 html_f.enabled = save_enabled
467 html_f.enabled = save_enabled
466
468
467 assert sorted(d) == [
469 assert sorted(d) == [
468 "application/json+test.v2",
470 "application/json+test.v2",
469 "image/png",
471 "image/png",
470 "plain/text",
472 "plain/text",
471 "text/html",
473 "text/html",
472 "text/plain",
474 "text/plain",
473 ]
475 ]
474 assert md == {}
476 assert md == {}
475
477
476 d, md = f.format(obj, include={"image/png"})
478 d, md = f.format(obj, include={"image/png"})
477 assert list(d.keys()) == [
479 assert list(d.keys()) == [
478 "image/png"
480 "image/png"
479 ], "Include should filter out even things from repr_mimebundle"
481 ], "Include should filter out even things from repr_mimebundle"
480
482
481 assert d["image/png"] == "i-overwrite", "_repr_mimebundle_ take precedence"
483 assert d["image/png"] == "i-overwrite", "_repr_mimebundle_ take precedence"
482
484
483
485
484 def test_pass_correct_include_exclude():
486 def test_pass_correct_include_exclude():
485 class Tester(object):
487 class Tester(object):
486
488
487 def __init__(self, include=None, exclude=None):
489 def __init__(self, include=None, exclude=None):
488 self.include = include
490 self.include = include
489 self.exclude = exclude
491 self.exclude = exclude
490
492
491 def _repr_mimebundle_(self, include, exclude, **kwargs):
493 def _repr_mimebundle_(self, include, exclude, **kwargs):
492 if include and (include != self.include):
494 if include and (include != self.include):
493 raise ValueError('include got modified: display() may be broken.')
495 raise ValueError('include got modified: display() may be broken.')
494 if exclude and (exclude != self.exclude):
496 if exclude and (exclude != self.exclude):
495 raise ValueError('exclude got modified: display() may be broken.')
497 raise ValueError('exclude got modified: display() may be broken.')
496
498
497 return None
499 return None
498
500
499 include = {'a', 'b', 'c'}
501 include = {'a', 'b', 'c'}
500 exclude = {'c', 'e' , 'f'}
502 exclude = {'c', 'e' , 'f'}
501
503
502 f = get_ipython().display_formatter
504 f = get_ipython().display_formatter
503 f.format(Tester(include=include, exclude=exclude), include=include, exclude=exclude)
505 f.format(Tester(include=include, exclude=exclude), include=include, exclude=exclude)
504 f.format(Tester(exclude=exclude), exclude=exclude)
506 f.format(Tester(exclude=exclude), exclude=exclude)
505 f.format(Tester(include=include), include=include)
507 f.format(Tester(include=include), include=include)
506
508
507
509
508 def test_repr_mime_meta():
510 def test_repr_mime_meta():
509 class HasReprMimeMeta(object):
511 class HasReprMimeMeta(object):
510 def _repr_mimebundle_(self, include=None, exclude=None):
512 def _repr_mimebundle_(self, include=None, exclude=None):
511 data = {
513 data = {
512 'image/png': 'base64-image-data',
514 'image/png': 'base64-image-data',
513 }
515 }
514 metadata = {
516 metadata = {
515 'image/png': {
517 'image/png': {
516 'width': 5,
518 'width': 5,
517 'height': 10,
519 'height': 10,
518 }
520 }
519 }
521 }
520 return (data, metadata)
522 return (data, metadata)
521
523
522 f = get_ipython().display_formatter
524 f = get_ipython().display_formatter
523 obj = HasReprMimeMeta()
525 obj = HasReprMimeMeta()
524 d, md = f.format(obj)
526 d, md = f.format(obj)
525 assert sorted(d) == ["image/png", "text/plain"]
527 assert sorted(d) == ["image/png", "text/plain"]
526 assert md == {
528 assert md == {
527 "image/png": {
529 "image/png": {
528 "width": 5,
530 "width": 5,
529 "height": 10,
531 "height": 10,
530 }
532 }
531 }
533 }
532
534
533
535
534 def test_repr_mime_failure():
536 def test_repr_mime_failure():
535 class BadReprMime(object):
537 class BadReprMime(object):
536 def _repr_mimebundle_(self, include=None, exclude=None):
538 def _repr_mimebundle_(self, include=None, exclude=None):
537 raise RuntimeError
539 raise RuntimeError
538
540
539 f = get_ipython().display_formatter
541 f = get_ipython().display_formatter
540 obj = BadReprMime()
542 obj = BadReprMime()
541 d, md = f.format(obj)
543 d, md = f.format(obj)
542 assert "text/plain" in d
544 assert "text/plain" in d
@@ -1,94 +1,91 b''
1 """Tests for input handlers.
1 """Tests for input handlers.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Module imports
4 # Module imports
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6
6
7 # third party
8 import nose.tools as nt
9
10 # our own packages
7 # our own packages
11 from IPython.core import autocall
8 from IPython.core import autocall
12 from IPython.testing import tools as tt
9 from IPython.testing import tools as tt
13
10
14 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
15 # Globals
12 # Globals
16 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
17
14
18 # Get the public instance of IPython
15 # Get the public instance of IPython
19
16
20 failures = []
17 failures = []
21 num_tests = 0
18 num_tests = 0
22
19
23 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
24 # Test functions
21 # Test functions
25 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
26
23
27 class CallableIndexable(object):
24 class CallableIndexable(object):
28 def __getitem__(self, idx): return True
25 def __getitem__(self, idx): return True
29 def __call__(self, *args, **kws): return True
26 def __call__(self, *args, **kws): return True
30
27
31
28
32 class Autocallable(autocall.IPyAutocall):
29 class Autocallable(autocall.IPyAutocall):
33 def __call__(self):
30 def __call__(self):
34 return "called"
31 return "called"
35
32
36
33
37 def run(tests):
34 def run(tests):
38 """Loop through a list of (pre, post) inputs, where pre is the string
35 """Loop through a list of (pre, post) inputs, where pre is the string
39 handed to ipython, and post is how that string looks after it's been
36 handed to ipython, and post is how that string looks after it's been
40 transformed (i.e. ipython's notion of _i)"""
37 transformed (i.e. ipython's notion of _i)"""
41 tt.check_pairs(ip.prefilter_manager.prefilter_lines, tests)
38 tt.check_pairs(ip.prefilter_manager.prefilter_lines, tests)
42
39
43
40
44 def test_handlers():
41 def test_handlers():
45 call_idx = CallableIndexable()
42 call_idx = CallableIndexable()
46 ip.user_ns['call_idx'] = call_idx
43 ip.user_ns['call_idx'] = call_idx
47
44
48 # For many of the below, we're also checking that leading whitespace
45 # For many of the below, we're also checking that leading whitespace
49 # turns off the esc char, which it should unless there is a continuation
46 # turns off the esc char, which it should unless there is a continuation
50 # line.
47 # line.
51 run(
48 run(
52 [('"no change"', '"no change"'), # normal
49 [('"no change"', '"no change"'), # normal
53 (u"lsmagic", "get_ipython().run_line_magic('lsmagic', '')"), # magic
50 (u"lsmagic", "get_ipython().run_line_magic('lsmagic', '')"), # magic
54 #("a = b # PYTHON-MODE", '_i'), # emacs -- avoids _in cache
51 #("a = b # PYTHON-MODE", '_i'), # emacs -- avoids _in cache
55 ])
52 ])
56
53
57 # Objects which are instances of IPyAutocall are *always* autocalled
54 # Objects which are instances of IPyAutocall are *always* autocalled
58 autocallable = Autocallable()
55 autocallable = Autocallable()
59 ip.user_ns['autocallable'] = autocallable
56 ip.user_ns['autocallable'] = autocallable
60
57
61 # auto
58 # auto
62 ip.magic('autocall 0')
59 ip.magic('autocall 0')
63 # Only explicit escapes or instances of IPyAutocallable should get
60 # Only explicit escapes or instances of IPyAutocallable should get
64 # expanded
61 # expanded
65 run([
62 run([
66 ('len "abc"', 'len "abc"'),
63 ('len "abc"', 'len "abc"'),
67 ('autocallable', 'autocallable()'),
64 ('autocallable', 'autocallable()'),
68 # Don't add extra brackets (gh-1117)
65 # Don't add extra brackets (gh-1117)
69 ('autocallable()', 'autocallable()'),
66 ('autocallable()', 'autocallable()'),
70 ])
67 ])
71 ip.magic('autocall 1')
68 ip.magic('autocall 1')
72 run([
69 run([
73 ('len "abc"', 'len("abc")'),
70 ('len "abc"', 'len("abc")'),
74 ('len "abc";', 'len("abc");'), # ; is special -- moves out of parens
71 ('len "abc";', 'len("abc");'), # ; is special -- moves out of parens
75 # Autocall is turned off if first arg is [] and the object
72 # Autocall is turned off if first arg is [] and the object
76 # is both callable and indexable. Like so:
73 # is both callable and indexable. Like so:
77 ('len [1,2]', 'len([1,2])'), # len doesn't support __getitem__...
74 ('len [1,2]', 'len([1,2])'), # len doesn't support __getitem__...
78 ('call_idx [1]', 'call_idx [1]'), # call_idx *does*..
75 ('call_idx [1]', 'call_idx [1]'), # call_idx *does*..
79 ('call_idx 1', 'call_idx(1)'),
76 ('call_idx 1', 'call_idx(1)'),
80 ('len', 'len'), # only at 2 does it auto-call on single args
77 ('len', 'len'), # only at 2 does it auto-call on single args
81 ])
78 ])
82 ip.magic('autocall 2')
79 ip.magic('autocall 2')
83 run([
80 run([
84 ('len "abc"', 'len("abc")'),
81 ('len "abc"', 'len("abc")'),
85 ('len "abc";', 'len("abc");'),
82 ('len "abc";', 'len("abc");'),
86 ('len [1,2]', 'len([1,2])'),
83 ('len [1,2]', 'len([1,2])'),
87 ('call_idx [1]', 'call_idx [1]'),
84 ('call_idx [1]', 'call_idx [1]'),
88 ('call_idx 1', 'call_idx(1)'),
85 ('call_idx 1', 'call_idx(1)'),
89 # This is what's different:
86 # This is what's different:
90 ('len', 'len()'), # only at 2 does it auto-call on single args
87 ('len', 'len()'), # only at 2 does it auto-call on single args
91 ])
88 ])
92 ip.magic('autocall 1')
89 ip.magic('autocall 1')
93
90
94 nt.assert_equal(failures, [])
91 assert failures == []
@@ -1,223 +1,218 b''
1 # coding: utf-8
1 # coding: utf-8
2 """Tests for the IPython tab-completion machinery.
2 """Tests for the IPython tab-completion machinery.
3 """
3 """
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Module imports
5 # Module imports
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7
7
8 # stdlib
8 # stdlib
9 import io
9 import io
10 from pathlib import Path
10 from pathlib import Path
11 import sys
11 import sys
12 import tempfile
12 import tempfile
13 from datetime import datetime
13 from datetime import datetime
14 import sqlite3
14 import sqlite3
15
15
16 # third party
17 import nose.tools as nt
18
19 # our own packages
16 # our own packages
20 from traitlets.config.loader import Config
17 from traitlets.config.loader import Config
21 from IPython.utils.tempdir import TemporaryDirectory
18 from IPython.utils.tempdir import TemporaryDirectory
22 from IPython.core.history import HistoryManager, extract_hist_ranges
19 from IPython.core.history import HistoryManager, extract_hist_ranges
23 from IPython.testing.decorators import skipif
20 from IPython.testing.decorators import skipif
24
21
25 def test_proper_default_encoding():
22 def test_proper_default_encoding():
26 nt.assert_equal(sys.getdefaultencoding(), "utf-8")
23 assert sys.getdefaultencoding() == "utf-8"
27
24
28 @skipif(sqlite3.sqlite_version_info > (3,24,0))
25 @skipif(sqlite3.sqlite_version_info > (3,24,0))
29 def test_history():
26 def test_history():
30 ip = get_ipython()
27 ip = get_ipython()
31 with TemporaryDirectory() as tmpdir:
28 with TemporaryDirectory() as tmpdir:
32 tmp_path = Path(tmpdir)
29 tmp_path = Path(tmpdir)
33 hist_manager_ori = ip.history_manager
30 hist_manager_ori = ip.history_manager
34 hist_file = tmp_path / "history.sqlite"
31 hist_file = tmp_path / "history.sqlite"
35 try:
32 try:
36 ip.history_manager = HistoryManager(shell=ip, hist_file=hist_file)
33 ip.history_manager = HistoryManager(shell=ip, hist_file=hist_file)
37 hist = [u'a=1', u'def f():\n test = 1\n return test', u"b='€Æ¾÷ß'"]
34 hist = ["a=1", "def f():\n test = 1\n return test", "b='€Æ¾÷ß'"]
38 for i, h in enumerate(hist, start=1):
35 for i, h in enumerate(hist, start=1):
39 ip.history_manager.store_inputs(i, h)
36 ip.history_manager.store_inputs(i, h)
40
37
41 ip.history_manager.db_log_output = True
38 ip.history_manager.db_log_output = True
42 # Doesn't match the input, but we'll just check it's stored.
39 # Doesn't match the input, but we'll just check it's stored.
43 ip.history_manager.output_hist_reprs[3] = "spam"
40 ip.history_manager.output_hist_reprs[3] = "spam"
44 ip.history_manager.store_output(3)
41 ip.history_manager.store_output(3)
45
42
46 nt.assert_equal(ip.history_manager.input_hist_raw, [''] + hist)
43 assert ip.history_manager.input_hist_raw == [""] + hist
47
44
48 # Detailed tests for _get_range_session
45 # Detailed tests for _get_range_session
49 grs = ip.history_manager._get_range_session
46 grs = ip.history_manager._get_range_session
50 nt.assert_equal(list(grs(start=2,stop=-1)), list(zip([0], [2], hist[1:-1])))
47 assert list(grs(start=2, stop=-1)) == list(zip([0], [2], hist[1:-1]))
51 nt.assert_equal(list(grs(start=-2)), list(zip([0,0], [2,3], hist[-2:])))
48 assert list(grs(start=-2)) == list(zip([0, 0], [2, 3], hist[-2:]))
52 nt.assert_equal(list(grs(output=True)), list(zip([0,0,0], [1,2,3], zip(hist, [None,None,'spam']))))
49 assert list(grs(output=True)) == list(
50 zip([0, 0, 0], [1, 2, 3], zip(hist, [None, None, "spam"]))
51 )
53
52
54 # Check whether specifying a range beyond the end of the current
53 # Check whether specifying a range beyond the end of the current
55 # session results in an error (gh-804)
54 # session results in an error (gh-804)
56 ip.magic('%hist 2-500')
55 ip.magic('%hist 2-500')
57
56
58 # Check that we can write non-ascii characters to a file
57 # Check that we can write non-ascii characters to a file
59 ip.magic("%%hist -f %s" % (tmp_path / "test1"))
58 ip.magic("%%hist -f %s" % (tmp_path / "test1"))
60 ip.magic("%%hist -pf %s" % (tmp_path / "test2"))
59 ip.magic("%%hist -pf %s" % (tmp_path / "test2"))
61 ip.magic("%%hist -nf %s" % (tmp_path / "test3"))
60 ip.magic("%%hist -nf %s" % (tmp_path / "test3"))
62 ip.magic("%%save %s 1-10" % (tmp_path / "test4"))
61 ip.magic("%%save %s 1-10" % (tmp_path / "test4"))
63
62
64 # New session
63 # New session
65 ip.history_manager.reset()
64 ip.history_manager.reset()
66 newcmds = [u"z=5",
65 newcmds = ["z=5", "class X(object):\n pass", "k='p'", "z=5"]
67 u"class X(object):\n pass",
68 u"k='p'",
69 u"z=5"]
70 for i, cmd in enumerate(newcmds, start=1):
66 for i, cmd in enumerate(newcmds, start=1):
71 ip.history_manager.store_inputs(i, cmd)
67 ip.history_manager.store_inputs(i, cmd)
72 gothist = ip.history_manager.get_range(start=1, stop=4)
68 gothist = ip.history_manager.get_range(start=1, stop=4)
73 nt.assert_equal(list(gothist), list(zip([0,0,0],[1,2,3], newcmds)))
69 assert list(gothist) == list(zip([0, 0, 0], [1, 2, 3], newcmds))
74 # Previous session:
70 # Previous session:
75 gothist = ip.history_manager.get_range(-1, 1, 4)
71 gothist = ip.history_manager.get_range(-1, 1, 4)
76 nt.assert_equal(list(gothist), list(zip([1,1,1],[1,2,3], hist)))
72 assert list(gothist) == list(zip([1, 1, 1], [1, 2, 3], hist))
77
73
78 newhist = [(2, i, c) for (i, c) in enumerate(newcmds, 1)]
74 newhist = [(2, i, c) for (i, c) in enumerate(newcmds, 1)]
79
75
80 # Check get_hist_tail
76 # Check get_hist_tail
81 gothist = ip.history_manager.get_tail(5, output=True,
77 gothist = ip.history_manager.get_tail(5, output=True,
82 include_latest=True)
78 include_latest=True)
83 expected = [(1, 3, (hist[-1], "spam"))] \
79 expected = [(1, 3, (hist[-1], "spam"))] \
84 + [(s, n, (c, None)) for (s, n, c) in newhist]
80 + [(s, n, (c, None)) for (s, n, c) in newhist]
85 nt.assert_equal(list(gothist), expected)
81 assert list(gothist) == expected
86
82
87 gothist = ip.history_manager.get_tail(2)
83 gothist = ip.history_manager.get_tail(2)
88 expected = newhist[-3:-1]
84 expected = newhist[-3:-1]
89 nt.assert_equal(list(gothist), expected)
85 assert list(gothist) == expected
90
86
91 # Check get_hist_search
87 # Check get_hist_search
92
88
93 gothist = ip.history_manager.search("*test*")
89 gothist = ip.history_manager.search("*test*")
94 nt.assert_equal(list(gothist), [(1,2,hist[1])] )
90 assert list(gothist) == [(1, 2, hist[1])]
95
91
96 gothist = ip.history_manager.search("*=*")
92 gothist = ip.history_manager.search("*=*")
97 nt.assert_equal(list(gothist),
93 assert list(gothist) == [
98 [(1, 1, hist[0]),
94 (1, 1, hist[0]),
99 (1, 2, hist[1]),
95 (1, 2, hist[1]),
100 (1, 3, hist[2]),
96 (1, 3, hist[2]),
101 newhist[0],
97 newhist[0],
102 newhist[2],
98 newhist[2],
103 newhist[3]])
99 newhist[3],
100 ]
104
101
105 gothist = ip.history_manager.search("*=*", n=4)
102 gothist = ip.history_manager.search("*=*", n=4)
106 nt.assert_equal(list(gothist),
103 assert list(gothist) == [
107 [(1, 3, hist[2]),
104 (1, 3, hist[2]),
108 newhist[0],
105 newhist[0],
109 newhist[2],
106 newhist[2],
110 newhist[3]])
107 newhist[3],
108 ]
111
109
112 gothist = ip.history_manager.search("*=*", unique=True)
110 gothist = ip.history_manager.search("*=*", unique=True)
113 nt.assert_equal(list(gothist),
111 assert list(gothist) == [
114 [(1, 1, hist[0]),
112 (1, 1, hist[0]),
115 (1, 2, hist[1]),
113 (1, 2, hist[1]),
116 (1, 3, hist[2]),
114 (1, 3, hist[2]),
117 newhist[2],
115 newhist[2],
118 newhist[3]])
116 newhist[3],
117 ]
119
118
120 gothist = ip.history_manager.search("*=*", unique=True, n=3)
119 gothist = ip.history_manager.search("*=*", unique=True, n=3)
121 nt.assert_equal(list(gothist),
120 assert list(gothist) == [(1, 3, hist[2]), newhist[2], newhist[3]]
122 [(1, 3, hist[2]),
123 newhist[2],
124 newhist[3]])
125
121
126 gothist = ip.history_manager.search("b*", output=True)
122 gothist = ip.history_manager.search("b*", output=True)
127 nt.assert_equal(list(gothist), [(1,3,(hist[2],"spam"))] )
123 assert list(gothist) == [(1, 3, (hist[2], "spam"))]
128
124
129 # Cross testing: check that magic %save can get previous session.
125 # Cross testing: check that magic %save can get previous session.
130 testfilename = (tmp_path / "test.py").resolve()
126 testfilename = (tmp_path / "test.py").resolve()
131 ip.magic("save " + str(testfilename) + " ~1/1-3")
127 ip.magic("save " + str(testfilename) + " ~1/1-3")
132 with io.open(testfilename, encoding='utf-8') as testfile:
128 with io.open(testfilename, encoding="utf-8") as testfile:
133 nt.assert_equal(testfile.read(),
129 assert testfile.read() == "# coding: utf-8\n" + "\n".join(hist) + "\n"
134 u"# coding: utf-8\n" + u"\n".join(hist)+u"\n")
135
130
136 # Duplicate line numbers - check that it doesn't crash, and
131 # Duplicate line numbers - check that it doesn't crash, and
137 # gets a new session
132 # gets a new session
138 ip.history_manager.store_inputs(1, "rogue")
133 ip.history_manager.store_inputs(1, "rogue")
139 ip.history_manager.writeout_cache()
134 ip.history_manager.writeout_cache()
140 nt.assert_equal(ip.history_manager.session_number, 3)
135 assert ip.history_manager.session_number == 3
141 finally:
136 finally:
142 # Ensure saving thread is shut down before we try to clean up the files
137 # Ensure saving thread is shut down before we try to clean up the files
143 ip.history_manager.save_thread.stop()
138 ip.history_manager.save_thread.stop()
144 # Forcibly close database rather than relying on garbage collection
139 # Forcibly close database rather than relying on garbage collection
145 ip.history_manager.db.close()
140 ip.history_manager.db.close()
146 # Restore history manager
141 # Restore history manager
147 ip.history_manager = hist_manager_ori
142 ip.history_manager = hist_manager_ori
148
143
149
144
150 def test_extract_hist_ranges():
145 def test_extract_hist_ranges():
151 instr = "1 2/3 ~4/5-6 ~4/7-~4/9 ~9/2-~7/5 ~10/"
146 instr = "1 2/3 ~4/5-6 ~4/7-~4/9 ~9/2-~7/5 ~10/"
152 expected = [(0, 1, 2), # 0 == current session
147 expected = [(0, 1, 2), # 0 == current session
153 (2, 3, 4),
148 (2, 3, 4),
154 (-4, 5, 7),
149 (-4, 5, 7),
155 (-4, 7, 10),
150 (-4, 7, 10),
156 (-9, 2, None), # None == to end
151 (-9, 2, None), # None == to end
157 (-8, 1, None),
152 (-8, 1, None),
158 (-7, 1, 6),
153 (-7, 1, 6),
159 (-10, 1, None)]
154 (-10, 1, None)]
160 actual = list(extract_hist_ranges(instr))
155 actual = list(extract_hist_ranges(instr))
161 nt.assert_equal(actual, expected)
156 assert actual == expected
162
157
163
158
164 def test_extract_hist_ranges_empty_str():
159 def test_extract_hist_ranges_empty_str():
165 instr = ""
160 instr = ""
166 expected = [(0, 1, None)] # 0 == current session, None == to end
161 expected = [(0, 1, None)] # 0 == current session, None == to end
167 actual = list(extract_hist_ranges(instr))
162 actual = list(extract_hist_ranges(instr))
168 nt.assert_equal(actual, expected)
163 assert actual == expected
169
164
170
165
171 def test_magic_rerun():
166 def test_magic_rerun():
172 """Simple test for %rerun (no args -> rerun last line)"""
167 """Simple test for %rerun (no args -> rerun last line)"""
173 ip = get_ipython()
168 ip = get_ipython()
174 ip.run_cell("a = 10", store_history=True)
169 ip.run_cell("a = 10", store_history=True)
175 ip.run_cell("a += 1", store_history=True)
170 ip.run_cell("a += 1", store_history=True)
176 nt.assert_equal(ip.user_ns["a"], 11)
171 assert ip.user_ns["a"] == 11
177 ip.run_cell("%rerun", store_history=True)
172 ip.run_cell("%rerun", store_history=True)
178 nt.assert_equal(ip.user_ns["a"], 12)
173 assert ip.user_ns["a"] == 12
179
174
180 def test_timestamp_type():
175 def test_timestamp_type():
181 ip = get_ipython()
176 ip = get_ipython()
182 info = ip.history_manager.get_session_info()
177 info = ip.history_manager.get_session_info()
183 nt.assert_true(isinstance(info[1], datetime))
178 assert isinstance(info[1], datetime)
184
179
185 def test_hist_file_config():
180 def test_hist_file_config():
186 cfg = Config()
181 cfg = Config()
187 tfile = tempfile.NamedTemporaryFile(delete=False)
182 tfile = tempfile.NamedTemporaryFile(delete=False)
188 cfg.HistoryManager.hist_file = Path(tfile.name)
183 cfg.HistoryManager.hist_file = Path(tfile.name)
189 try:
184 try:
190 hm = HistoryManager(shell=get_ipython(), config=cfg)
185 hm = HistoryManager(shell=get_ipython(), config=cfg)
191 nt.assert_equal(hm.hist_file, cfg.HistoryManager.hist_file)
186 assert hm.hist_file == cfg.HistoryManager.hist_file
192 finally:
187 finally:
193 try:
188 try:
194 Path(tfile.name).unlink()
189 Path(tfile.name).unlink()
195 except OSError:
190 except OSError:
196 # same catch as in testing.tools.TempFileMixin
191 # same catch as in testing.tools.TempFileMixin
197 # On Windows, even though we close the file, we still can't
192 # On Windows, even though we close the file, we still can't
198 # delete it. I have no clue why
193 # delete it. I have no clue why
199 pass
194 pass
200
195
201 def test_histmanager_disabled():
196 def test_histmanager_disabled():
202 """Ensure that disabling the history manager doesn't create a database."""
197 """Ensure that disabling the history manager doesn't create a database."""
203 cfg = Config()
198 cfg = Config()
204 cfg.HistoryAccessor.enabled = False
199 cfg.HistoryAccessor.enabled = False
205
200
206 ip = get_ipython()
201 ip = get_ipython()
207 with TemporaryDirectory() as tmpdir:
202 with TemporaryDirectory() as tmpdir:
208 hist_manager_ori = ip.history_manager
203 hist_manager_ori = ip.history_manager
209 hist_file = Path(tmpdir) / "history.sqlite"
204 hist_file = Path(tmpdir) / "history.sqlite"
210 cfg.HistoryManager.hist_file = hist_file
205 cfg.HistoryManager.hist_file = hist_file
211 try:
206 try:
212 ip.history_manager = HistoryManager(shell=ip, config=cfg)
207 ip.history_manager = HistoryManager(shell=ip, config=cfg)
213 hist = [u'a=1', u'def f():\n test = 1\n return test', u"b='€Æ¾÷ß'"]
208 hist = ["a=1", "def f():\n test = 1\n return test", "b='€Æ¾÷ß'"]
214 for i, h in enumerate(hist, start=1):
209 for i, h in enumerate(hist, start=1):
215 ip.history_manager.store_inputs(i, h)
210 ip.history_manager.store_inputs(i, h)
216 nt.assert_equal(ip.history_manager.input_hist_raw, [''] + hist)
211 assert ip.history_manager.input_hist_raw == [""] + hist
217 ip.history_manager.reset()
212 ip.history_manager.reset()
218 ip.history_manager.end_session()
213 ip.history_manager.end_session()
219 finally:
214 finally:
220 ip.history_manager = hist_manager_ori
215 ip.history_manager = hist_manager_ori
221
216
222 # hist_file should not be created
217 # hist_file should not be created
223 nt.assert_false(hist_file.exists())
218 assert hist_file.exists() is False
@@ -1,80 +1,78 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for CommandChainDispatcher."""
2 """Tests for CommandChainDispatcher."""
3
3
4
4
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Imports
6 # Imports
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8
8
9 import nose.tools as nt
10 from IPython.core.error import TryNext
9 from IPython.core.error import TryNext
11 from IPython.core.hooks import CommandChainDispatcher
10 from IPython.core.hooks import CommandChainDispatcher
12
11
13 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
14 # Local utilities
13 # Local utilities
15 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
16
15
17 # Define two classes, one which succeeds and one which raises TryNext. Each
16 # Define two classes, one which succeeds and one which raises TryNext. Each
18 # sets the attribute `called` to True when it is called.
17 # sets the attribute `called` to True when it is called.
19 class Okay(object):
18 class Okay(object):
20 def __init__(self, message):
19 def __init__(self, message):
21 self.message = message
20 self.message = message
22 self.called = False
21 self.called = False
23 def __call__(self):
22 def __call__(self):
24 self.called = True
23 self.called = True
25 return self.message
24 return self.message
26
25
27 class Fail(object):
26 class Fail(object):
28 def __init__(self, message):
27 def __init__(self, message):
29 self.message = message
28 self.message = message
30 self.called = False
29 self.called = False
31 def __call__(self):
30 def __call__(self):
32 self.called = True
31 self.called = True
33 raise TryNext(self.message)
32 raise TryNext(self.message)
34
33
35 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
36 # Test functions
35 # Test functions
37 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
38
37
39 def test_command_chain_dispatcher_ff():
38 def test_command_chain_dispatcher_ff():
40 """Test two failing hooks"""
39 """Test two failing hooks"""
41 fail1 = Fail(u'fail1')
40 fail1 = Fail("fail1")
42 fail2 = Fail(u'fail2')
41 fail2 = Fail("fail2")
43 dp = CommandChainDispatcher([(0, fail1),
42 dp = CommandChainDispatcher([(0, fail1), (10, fail2)])
44 (10, fail2)])
45
43
46 try:
44 try:
47 dp()
45 dp()
48 except TryNext as e:
46 except TryNext as e:
49 nt.assert_equal(str(e), u'fail2')
47 assert str(e) == "fail2"
50 else:
48 else:
51 assert False, "Expected exception was not raised."
49 assert False, "Expected exception was not raised."
52
50
53 nt.assert_true(fail1.called)
51 assert fail1.called is True
54 nt.assert_true(fail2.called)
52 assert fail2.called is True
55
53
56 def test_command_chain_dispatcher_fofo():
54 def test_command_chain_dispatcher_fofo():
57 """Test a mixture of failing and succeeding hooks."""
55 """Test a mixture of failing and succeeding hooks."""
58 fail1 = Fail(u'fail1')
56 fail1 = Fail("fail1")
59 fail2 = Fail(u'fail2')
57 fail2 = Fail("fail2")
60 okay1 = Okay(u'okay1')
58 okay1 = Okay("okay1")
61 okay2 = Okay(u'okay2')
59 okay2 = Okay("okay2")
62
60
63 dp = CommandChainDispatcher([(0, fail1),
61 dp = CommandChainDispatcher([(0, fail1),
64 # (5, okay1), # add this later
62 # (5, okay1), # add this later
65 (10, fail2),
63 (10, fail2),
66 (15, okay2)])
64 (15, okay2)])
67 dp.add(okay1, 5)
65 dp.add(okay1, 5)
68
66
69 nt.assert_equal(dp(), u'okay1')
67 assert dp() == "okay1"
70
68
71 nt.assert_true(fail1.called)
69 assert fail1.called is True
72 nt.assert_true(okay1.called)
70 assert okay1.called is True
73 nt.assert_false(fail2.called)
71 assert fail2.called is False
74 nt.assert_false(okay2.called)
72 assert okay2.called is False
75
73
76 def test_command_chain_dispatcher_eq_priority():
74 def test_command_chain_dispatcher_eq_priority():
77 okay1 = Okay(u'okay1')
75 okay1 = Okay(u'okay1')
78 okay2 = Okay(u'okay2')
76 okay2 = Okay(u'okay2')
79 dp = CommandChainDispatcher([(1, okay1)])
77 dp = CommandChainDispatcher([(1, okay1)])
80 dp.add(okay2, 1)
78 dp.add(okay2, 1)
@@ -1,639 +1,638 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for the inputsplitter module."""
2 """Tests for the inputsplitter module."""
3
3
4
4
5 # Copyright (c) IPython Development Team.
5 # Copyright (c) IPython Development Team.
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7
7
8 import unittest
8 import unittest
9 import sys
9 import sys
10
10
11 import nose.tools as nt
12
13 from IPython.core import inputsplitter as isp
11 from IPython.core import inputsplitter as isp
14 from IPython.core.inputtransformer import InputTransformer
12 from IPython.core.inputtransformer import InputTransformer
15 from IPython.core.tests.test_inputtransformer import syntax, syntax_ml
13 from IPython.core.tests.test_inputtransformer import syntax, syntax_ml
16 from IPython.testing import tools as tt
14 from IPython.testing import tools as tt
17
15
18 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
19 # Semi-complete examples (also used as tests)
17 # Semi-complete examples (also used as tests)
20 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
21
19
22 # Note: at the bottom, there's a slightly more complete version of this that
20 # Note: at the bottom, there's a slightly more complete version of this that
23 # can be useful during development of code here.
21 # can be useful during development of code here.
24
22
25 def mini_interactive_loop(input_func):
23 def mini_interactive_loop(input_func):
26 """Minimal example of the logic of an interactive interpreter loop.
24 """Minimal example of the logic of an interactive interpreter loop.
27
25
28 This serves as an example, and it is used by the test system with a fake
26 This serves as an example, and it is used by the test system with a fake
29 raw_input that simulates interactive input."""
27 raw_input that simulates interactive input."""
30
28
31 from IPython.core.inputsplitter import InputSplitter
29 from IPython.core.inputsplitter import InputSplitter
32
30
33 isp = InputSplitter()
31 isp = InputSplitter()
34 # In practice, this input loop would be wrapped in an outside loop to read
32 # In practice, this input loop would be wrapped in an outside loop to read
35 # input indefinitely, until some exit/quit command was issued. Here we
33 # input indefinitely, until some exit/quit command was issued. Here we
36 # only illustrate the basic inner loop.
34 # only illustrate the basic inner loop.
37 while isp.push_accepts_more():
35 while isp.push_accepts_more():
38 indent = ' '*isp.get_indent_spaces()
36 indent = ' '*isp.get_indent_spaces()
39 prompt = '>>> ' + indent
37 prompt = '>>> ' + indent
40 line = indent + input_func(prompt)
38 line = indent + input_func(prompt)
41 isp.push(line)
39 isp.push(line)
42
40
43 # Here we just return input so we can use it in a test suite, but a real
41 # Here we just return input so we can use it in a test suite, but a real
44 # interpreter would instead send it for execution somewhere.
42 # interpreter would instead send it for execution somewhere.
45 src = isp.source_reset()
43 src = isp.source_reset()
46 #print 'Input source was:\n', src # dbg
44 #print 'Input source was:\n', src # dbg
47 return src
45 return src
48
46
49 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
50 # Test utilities, just for local use
48 # Test utilities, just for local use
51 #-----------------------------------------------------------------------------
49 #-----------------------------------------------------------------------------
52
50
53 def assemble(block):
51 def assemble(block):
54 """Assemble a block into multi-line sub-blocks."""
52 """Assemble a block into multi-line sub-blocks."""
55 return ['\n'.join(sub_block)+'\n' for sub_block in block]
53 return ['\n'.join(sub_block)+'\n' for sub_block in block]
56
54
57
55
58 def pseudo_input(lines):
56 def pseudo_input(lines):
59 """Return a function that acts like raw_input but feeds the input list."""
57 """Return a function that acts like raw_input but feeds the input list."""
60 ilines = iter(lines)
58 ilines = iter(lines)
61 def raw_in(prompt):
59 def raw_in(prompt):
62 try:
60 try:
63 return next(ilines)
61 return next(ilines)
64 except StopIteration:
62 except StopIteration:
65 return ''
63 return ''
66 return raw_in
64 return raw_in
67
65
68 #-----------------------------------------------------------------------------
66 #-----------------------------------------------------------------------------
69 # Tests
67 # Tests
70 #-----------------------------------------------------------------------------
68 #-----------------------------------------------------------------------------
71 def test_spaces():
69 def test_spaces():
72 tests = [('', 0),
70 tests = [('', 0),
73 (' ', 1),
71 (' ', 1),
74 ('\n', 0),
72 ('\n', 0),
75 (' \n', 1),
73 (' \n', 1),
76 ('x', 0),
74 ('x', 0),
77 (' x', 1),
75 (' x', 1),
78 (' x',2),
76 (' x',2),
79 (' x',4),
77 (' x',4),
80 # Note: tabs are counted as a single whitespace!
78 # Note: tabs are counted as a single whitespace!
81 ('\tx', 1),
79 ('\tx', 1),
82 ('\t x', 2),
80 ('\t x', 2),
83 ]
81 ]
84 tt.check_pairs(isp.num_ini_spaces, tests)
82 tt.check_pairs(isp.num_ini_spaces, tests)
85
83
86
84
87 def test_remove_comments():
85 def test_remove_comments():
88 tests = [('text', 'text'),
86 tests = [('text', 'text'),
89 ('text # comment', 'text '),
87 ('text # comment', 'text '),
90 ('text # comment\n', 'text \n'),
88 ('text # comment\n', 'text \n'),
91 ('text # comment \n', 'text \n'),
89 ('text # comment \n', 'text \n'),
92 ('line # c \nline\n','line \nline\n'),
90 ('line # c \nline\n','line \nline\n'),
93 ('line # c \nline#c2 \nline\nline #c\n\n',
91 ('line # c \nline#c2 \nline\nline #c\n\n',
94 'line \nline\nline\nline \n\n'),
92 'line \nline\nline\nline \n\n'),
95 ]
93 ]
96 tt.check_pairs(isp.remove_comments, tests)
94 tt.check_pairs(isp.remove_comments, tests)
97
95
98
96
99 def test_get_input_encoding():
97 def test_get_input_encoding():
100 encoding = isp.get_input_encoding()
98 encoding = isp.get_input_encoding()
101 nt.assert_true(isinstance(encoding, str))
99 assert isinstance(encoding, str)
102 # simple-minded check that at least encoding a simple string works with the
100 # simple-minded check that at least encoding a simple string works with the
103 # encoding we got.
101 # encoding we got.
104 nt.assert_equal(u'test'.encode(encoding), b'test')
102 assert "test".encode(encoding) == b"test"
105
103
106
104
107 class NoInputEncodingTestCase(unittest.TestCase):
105 class NoInputEncodingTestCase(unittest.TestCase):
108 def setUp(self):
106 def setUp(self):
109 self.old_stdin = sys.stdin
107 self.old_stdin = sys.stdin
110 class X: pass
108 class X: pass
111 fake_stdin = X()
109 fake_stdin = X()
112 sys.stdin = fake_stdin
110 sys.stdin = fake_stdin
113
111
114 def test(self):
112 def test(self):
115 # Verify that if sys.stdin has no 'encoding' attribute we do the right
113 # Verify that if sys.stdin has no 'encoding' attribute we do the right
116 # thing
114 # thing
117 enc = isp.get_input_encoding()
115 enc = isp.get_input_encoding()
118 self.assertEqual(enc, 'ascii')
116 self.assertEqual(enc, 'ascii')
119
117
120 def tearDown(self):
118 def tearDown(self):
121 sys.stdin = self.old_stdin
119 sys.stdin = self.old_stdin
122
120
123
121
124 class InputSplitterTestCase(unittest.TestCase):
122 class InputSplitterTestCase(unittest.TestCase):
125 def setUp(self):
123 def setUp(self):
126 self.isp = isp.InputSplitter()
124 self.isp = isp.InputSplitter()
127
125
128 def test_reset(self):
126 def test_reset(self):
129 isp = self.isp
127 isp = self.isp
130 isp.push('x=1')
128 isp.push('x=1')
131 isp.reset()
129 isp.reset()
132 self.assertEqual(isp._buffer, [])
130 self.assertEqual(isp._buffer, [])
133 self.assertEqual(isp.get_indent_spaces(), 0)
131 self.assertEqual(isp.get_indent_spaces(), 0)
134 self.assertEqual(isp.source, '')
132 self.assertEqual(isp.source, '')
135 self.assertEqual(isp.code, None)
133 self.assertEqual(isp.code, None)
136 self.assertEqual(isp._is_complete, False)
134 self.assertEqual(isp._is_complete, False)
137
135
138 def test_source(self):
136 def test_source(self):
139 self.isp._store('1')
137 self.isp._store('1')
140 self.isp._store('2')
138 self.isp._store('2')
141 self.assertEqual(self.isp.source, '1\n2\n')
139 self.assertEqual(self.isp.source, '1\n2\n')
142 self.assertEqual(len(self.isp._buffer)>0, True)
140 self.assertEqual(len(self.isp._buffer)>0, True)
143 self.assertEqual(self.isp.source_reset(), '1\n2\n')
141 self.assertEqual(self.isp.source_reset(), '1\n2\n')
144 self.assertEqual(self.isp._buffer, [])
142 self.assertEqual(self.isp._buffer, [])
145 self.assertEqual(self.isp.source, '')
143 self.assertEqual(self.isp.source, '')
146
144
147 def test_indent(self):
145 def test_indent(self):
148 isp = self.isp # shorthand
146 isp = self.isp # shorthand
149 isp.push('x=1')
147 isp.push('x=1')
150 self.assertEqual(isp.get_indent_spaces(), 0)
148 self.assertEqual(isp.get_indent_spaces(), 0)
151 isp.push('if 1:\n x=1')
149 isp.push('if 1:\n x=1')
152 self.assertEqual(isp.get_indent_spaces(), 4)
150 self.assertEqual(isp.get_indent_spaces(), 4)
153 isp.push('y=2\n')
151 isp.push('y=2\n')
154 self.assertEqual(isp.get_indent_spaces(), 0)
152 self.assertEqual(isp.get_indent_spaces(), 0)
155
153
156 def test_indent2(self):
154 def test_indent2(self):
157 isp = self.isp
155 isp = self.isp
158 isp.push('if 1:')
156 isp.push('if 1:')
159 self.assertEqual(isp.get_indent_spaces(), 4)
157 self.assertEqual(isp.get_indent_spaces(), 4)
160 isp.push(' x=1')
158 isp.push(' x=1')
161 self.assertEqual(isp.get_indent_spaces(), 4)
159 self.assertEqual(isp.get_indent_spaces(), 4)
162 # Blank lines shouldn't change the indent level
160 # Blank lines shouldn't change the indent level
163 isp.push(' '*2)
161 isp.push(' '*2)
164 self.assertEqual(isp.get_indent_spaces(), 4)
162 self.assertEqual(isp.get_indent_spaces(), 4)
165
163
166 def test_indent3(self):
164 def test_indent3(self):
167 isp = self.isp
165 isp = self.isp
168 # When a multiline statement contains parens or multiline strings, we
166 # When a multiline statement contains parens or multiline strings, we
169 # shouldn't get confused.
167 # shouldn't get confused.
170 isp.push("if 1:")
168 isp.push("if 1:")
171 isp.push(" x = (1+\n 2)")
169 isp.push(" x = (1+\n 2)")
172 self.assertEqual(isp.get_indent_spaces(), 4)
170 self.assertEqual(isp.get_indent_spaces(), 4)
173
171
174 def test_indent4(self):
172 def test_indent4(self):
175 isp = self.isp
173 isp = self.isp
176 # whitespace after ':' should not screw up indent level
174 # whitespace after ':' should not screw up indent level
177 isp.push('if 1: \n x=1')
175 isp.push('if 1: \n x=1')
178 self.assertEqual(isp.get_indent_spaces(), 4)
176 self.assertEqual(isp.get_indent_spaces(), 4)
179 isp.push('y=2\n')
177 isp.push('y=2\n')
180 self.assertEqual(isp.get_indent_spaces(), 0)
178 self.assertEqual(isp.get_indent_spaces(), 0)
181 isp.push('if 1:\t\n x=1')
179 isp.push('if 1:\t\n x=1')
182 self.assertEqual(isp.get_indent_spaces(), 4)
180 self.assertEqual(isp.get_indent_spaces(), 4)
183 isp.push('y=2\n')
181 isp.push('y=2\n')
184 self.assertEqual(isp.get_indent_spaces(), 0)
182 self.assertEqual(isp.get_indent_spaces(), 0)
185
183
186 def test_dedent_pass(self):
184 def test_dedent_pass(self):
187 isp = self.isp # shorthand
185 isp = self.isp # shorthand
188 # should NOT cause dedent
186 # should NOT cause dedent
189 isp.push('if 1:\n passes = 5')
187 isp.push('if 1:\n passes = 5')
190 self.assertEqual(isp.get_indent_spaces(), 4)
188 self.assertEqual(isp.get_indent_spaces(), 4)
191 isp.push('if 1:\n pass')
189 isp.push('if 1:\n pass')
192 self.assertEqual(isp.get_indent_spaces(), 0)
190 self.assertEqual(isp.get_indent_spaces(), 0)
193 isp.push('if 1:\n pass ')
191 isp.push('if 1:\n pass ')
194 self.assertEqual(isp.get_indent_spaces(), 0)
192 self.assertEqual(isp.get_indent_spaces(), 0)
195
193
196 def test_dedent_break(self):
194 def test_dedent_break(self):
197 isp = self.isp # shorthand
195 isp = self.isp # shorthand
198 # should NOT cause dedent
196 # should NOT cause dedent
199 isp.push('while 1:\n breaks = 5')
197 isp.push('while 1:\n breaks = 5')
200 self.assertEqual(isp.get_indent_spaces(), 4)
198 self.assertEqual(isp.get_indent_spaces(), 4)
201 isp.push('while 1:\n break')
199 isp.push('while 1:\n break')
202 self.assertEqual(isp.get_indent_spaces(), 0)
200 self.assertEqual(isp.get_indent_spaces(), 0)
203 isp.push('while 1:\n break ')
201 isp.push('while 1:\n break ')
204 self.assertEqual(isp.get_indent_spaces(), 0)
202 self.assertEqual(isp.get_indent_spaces(), 0)
205
203
206 def test_dedent_continue(self):
204 def test_dedent_continue(self):
207 isp = self.isp # shorthand
205 isp = self.isp # shorthand
208 # should NOT cause dedent
206 # should NOT cause dedent
209 isp.push('while 1:\n continues = 5')
207 isp.push('while 1:\n continues = 5')
210 self.assertEqual(isp.get_indent_spaces(), 4)
208 self.assertEqual(isp.get_indent_spaces(), 4)
211 isp.push('while 1:\n continue')
209 isp.push('while 1:\n continue')
212 self.assertEqual(isp.get_indent_spaces(), 0)
210 self.assertEqual(isp.get_indent_spaces(), 0)
213 isp.push('while 1:\n continue ')
211 isp.push('while 1:\n continue ')
214 self.assertEqual(isp.get_indent_spaces(), 0)
212 self.assertEqual(isp.get_indent_spaces(), 0)
215
213
216 def test_dedent_raise(self):
214 def test_dedent_raise(self):
217 isp = self.isp # shorthand
215 isp = self.isp # shorthand
218 # should NOT cause dedent
216 # should NOT cause dedent
219 isp.push('if 1:\n raised = 4')
217 isp.push('if 1:\n raised = 4')
220 self.assertEqual(isp.get_indent_spaces(), 4)
218 self.assertEqual(isp.get_indent_spaces(), 4)
221 isp.push('if 1:\n raise TypeError()')
219 isp.push('if 1:\n raise TypeError()')
222 self.assertEqual(isp.get_indent_spaces(), 0)
220 self.assertEqual(isp.get_indent_spaces(), 0)
223 isp.push('if 1:\n raise')
221 isp.push('if 1:\n raise')
224 self.assertEqual(isp.get_indent_spaces(), 0)
222 self.assertEqual(isp.get_indent_spaces(), 0)
225 isp.push('if 1:\n raise ')
223 isp.push('if 1:\n raise ')
226 self.assertEqual(isp.get_indent_spaces(), 0)
224 self.assertEqual(isp.get_indent_spaces(), 0)
227
225
228 def test_dedent_return(self):
226 def test_dedent_return(self):
229 isp = self.isp # shorthand
227 isp = self.isp # shorthand
230 # should NOT cause dedent
228 # should NOT cause dedent
231 isp.push('if 1:\n returning = 4')
229 isp.push('if 1:\n returning = 4')
232 self.assertEqual(isp.get_indent_spaces(), 4)
230 self.assertEqual(isp.get_indent_spaces(), 4)
233 isp.push('if 1:\n return 5 + 493')
231 isp.push('if 1:\n return 5 + 493')
234 self.assertEqual(isp.get_indent_spaces(), 0)
232 self.assertEqual(isp.get_indent_spaces(), 0)
235 isp.push('if 1:\n return')
233 isp.push('if 1:\n return')
236 self.assertEqual(isp.get_indent_spaces(), 0)
234 self.assertEqual(isp.get_indent_spaces(), 0)
237 isp.push('if 1:\n return ')
235 isp.push('if 1:\n return ')
238 self.assertEqual(isp.get_indent_spaces(), 0)
236 self.assertEqual(isp.get_indent_spaces(), 0)
239 isp.push('if 1:\n return(0)')
237 isp.push('if 1:\n return(0)')
240 self.assertEqual(isp.get_indent_spaces(), 0)
238 self.assertEqual(isp.get_indent_spaces(), 0)
241
239
242 def test_push(self):
240 def test_push(self):
243 isp = self.isp
241 isp = self.isp
244 self.assertEqual(isp.push('x=1'), True)
242 self.assertEqual(isp.push('x=1'), True)
245
243
246 def test_push2(self):
244 def test_push2(self):
247 isp = self.isp
245 isp = self.isp
248 self.assertEqual(isp.push('if 1:'), False)
246 self.assertEqual(isp.push('if 1:'), False)
249 for line in [' x=1', '# a comment', ' y=2']:
247 for line in [' x=1', '# a comment', ' y=2']:
250 print(line)
248 print(line)
251 self.assertEqual(isp.push(line), True)
249 self.assertEqual(isp.push(line), True)
252
250
253 def test_push3(self):
251 def test_push3(self):
254 isp = self.isp
252 isp = self.isp
255 isp.push('if True:')
253 isp.push('if True:')
256 isp.push(' a = 1')
254 isp.push(' a = 1')
257 self.assertEqual(isp.push('b = [1,'), False)
255 self.assertEqual(isp.push('b = [1,'), False)
258
256
259 def test_push_accepts_more(self):
257 def test_push_accepts_more(self):
260 isp = self.isp
258 isp = self.isp
261 isp.push('x=1')
259 isp.push('x=1')
262 self.assertEqual(isp.push_accepts_more(), False)
260 self.assertEqual(isp.push_accepts_more(), False)
263
261
264 def test_push_accepts_more2(self):
262 def test_push_accepts_more2(self):
265 isp = self.isp
263 isp = self.isp
266 isp.push('if 1:')
264 isp.push('if 1:')
267 self.assertEqual(isp.push_accepts_more(), True)
265 self.assertEqual(isp.push_accepts_more(), True)
268 isp.push(' x=1')
266 isp.push(' x=1')
269 self.assertEqual(isp.push_accepts_more(), True)
267 self.assertEqual(isp.push_accepts_more(), True)
270 isp.push('')
268 isp.push('')
271 self.assertEqual(isp.push_accepts_more(), False)
269 self.assertEqual(isp.push_accepts_more(), False)
272
270
273 def test_push_accepts_more3(self):
271 def test_push_accepts_more3(self):
274 isp = self.isp
272 isp = self.isp
275 isp.push("x = (2+\n3)")
273 isp.push("x = (2+\n3)")
276 self.assertEqual(isp.push_accepts_more(), False)
274 self.assertEqual(isp.push_accepts_more(), False)
277
275
278 def test_push_accepts_more4(self):
276 def test_push_accepts_more4(self):
279 isp = self.isp
277 isp = self.isp
280 # When a multiline statement contains parens or multiline strings, we
278 # When a multiline statement contains parens or multiline strings, we
281 # shouldn't get confused.
279 # shouldn't get confused.
282 # FIXME: we should be able to better handle de-dents in statements like
280 # FIXME: we should be able to better handle de-dents in statements like
283 # multiline strings and multiline expressions (continued with \ or
281 # multiline strings and multiline expressions (continued with \ or
284 # parens). Right now we aren't handling the indentation tracking quite
282 # parens). Right now we aren't handling the indentation tracking quite
285 # correctly with this, though in practice it may not be too much of a
283 # correctly with this, though in practice it may not be too much of a
286 # problem. We'll need to see.
284 # problem. We'll need to see.
287 isp.push("if 1:")
285 isp.push("if 1:")
288 isp.push(" x = (2+")
286 isp.push(" x = (2+")
289 isp.push(" 3)")
287 isp.push(" 3)")
290 self.assertEqual(isp.push_accepts_more(), True)
288 self.assertEqual(isp.push_accepts_more(), True)
291 isp.push(" y = 3")
289 isp.push(" y = 3")
292 self.assertEqual(isp.push_accepts_more(), True)
290 self.assertEqual(isp.push_accepts_more(), True)
293 isp.push('')
291 isp.push('')
294 self.assertEqual(isp.push_accepts_more(), False)
292 self.assertEqual(isp.push_accepts_more(), False)
295
293
296 def test_push_accepts_more5(self):
294 def test_push_accepts_more5(self):
297 isp = self.isp
295 isp = self.isp
298 isp.push('try:')
296 isp.push('try:')
299 isp.push(' a = 5')
297 isp.push(' a = 5')
300 isp.push('except:')
298 isp.push('except:')
301 isp.push(' raise')
299 isp.push(' raise')
302 # We want to be able to add an else: block at this point, so it should
300 # We want to be able to add an else: block at this point, so it should
303 # wait for a blank line.
301 # wait for a blank line.
304 self.assertEqual(isp.push_accepts_more(), True)
302 self.assertEqual(isp.push_accepts_more(), True)
305
303
306 def test_continuation(self):
304 def test_continuation(self):
307 isp = self.isp
305 isp = self.isp
308 isp.push("import os, \\")
306 isp.push("import os, \\")
309 self.assertEqual(isp.push_accepts_more(), True)
307 self.assertEqual(isp.push_accepts_more(), True)
310 isp.push("sys")
308 isp.push("sys")
311 self.assertEqual(isp.push_accepts_more(), False)
309 self.assertEqual(isp.push_accepts_more(), False)
312
310
313 def test_syntax_error(self):
311 def test_syntax_error(self):
314 isp = self.isp
312 isp = self.isp
315 # Syntax errors immediately produce a 'ready' block, so the invalid
313 # Syntax errors immediately produce a 'ready' block, so the invalid
316 # Python can be sent to the kernel for evaluation with possible ipython
314 # Python can be sent to the kernel for evaluation with possible ipython
317 # special-syntax conversion.
315 # special-syntax conversion.
318 isp.push('run foo')
316 isp.push('run foo')
319 self.assertEqual(isp.push_accepts_more(), False)
317 self.assertEqual(isp.push_accepts_more(), False)
320
318
321 def test_unicode(self):
319 def test_unicode(self):
322 self.isp.push(u"Pérez")
320 self.isp.push(u"Pérez")
323 self.isp.push(u'\xc3\xa9')
321 self.isp.push(u'\xc3\xa9')
324 self.isp.push(u"u'\xc3\xa9'")
322 self.isp.push(u"u'\xc3\xa9'")
325
323
326 def test_line_continuation(self):
324 def test_line_continuation(self):
327 """ Test issue #2108."""
325 """ Test issue #2108."""
328 isp = self.isp
326 isp = self.isp
329 # A blank line after a line continuation should not accept more
327 # A blank line after a line continuation should not accept more
330 isp.push("1 \\\n\n")
328 isp.push("1 \\\n\n")
331 self.assertEqual(isp.push_accepts_more(), False)
329 self.assertEqual(isp.push_accepts_more(), False)
332 # Whitespace after a \ is a SyntaxError. The only way to test that
330 # Whitespace after a \ is a SyntaxError. The only way to test that
333 # here is to test that push doesn't accept more (as with
331 # here is to test that push doesn't accept more (as with
334 # test_syntax_error() above).
332 # test_syntax_error() above).
335 isp.push(r"1 \ ")
333 isp.push(r"1 \ ")
336 self.assertEqual(isp.push_accepts_more(), False)
334 self.assertEqual(isp.push_accepts_more(), False)
337 # Even if the line is continuable (c.f. the regular Python
335 # Even if the line is continuable (c.f. the regular Python
338 # interpreter)
336 # interpreter)
339 isp.push(r"(1 \ ")
337 isp.push(r"(1 \ ")
340 self.assertEqual(isp.push_accepts_more(), False)
338 self.assertEqual(isp.push_accepts_more(), False)
341
339
342 def test_check_complete(self):
340 def test_check_complete(self):
343 isp = self.isp
341 isp = self.isp
344 self.assertEqual(isp.check_complete("a = 1"), ('complete', None))
342 self.assertEqual(isp.check_complete("a = 1"), ('complete', None))
345 self.assertEqual(isp.check_complete("for a in range(5):"), ('incomplete', 4))
343 self.assertEqual(isp.check_complete("for a in range(5):"), ('incomplete', 4))
346 self.assertEqual(isp.check_complete("raise = 2"), ('invalid', None))
344 self.assertEqual(isp.check_complete("raise = 2"), ('invalid', None))
347 self.assertEqual(isp.check_complete("a = [1,\n2,"), ('incomplete', 0))
345 self.assertEqual(isp.check_complete("a = [1,\n2,"), ('incomplete', 0))
348 self.assertEqual(isp.check_complete("def a():\n x=1\n global x"), ('invalid', None))
346 self.assertEqual(isp.check_complete("def a():\n x=1\n global x"), ('invalid', None))
349
347
350 class InteractiveLoopTestCase(unittest.TestCase):
348 class InteractiveLoopTestCase(unittest.TestCase):
351 """Tests for an interactive loop like a python shell.
349 """Tests for an interactive loop like a python shell.
352 """
350 """
353 def check_ns(self, lines, ns):
351 def check_ns(self, lines, ns):
354 """Validate that the given input lines produce the resulting namespace.
352 """Validate that the given input lines produce the resulting namespace.
355
353
356 Note: the input lines are given exactly as they would be typed in an
354 Note: the input lines are given exactly as they would be typed in an
357 auto-indenting environment, as mini_interactive_loop above already does
355 auto-indenting environment, as mini_interactive_loop above already does
358 auto-indenting and prepends spaces to the input.
356 auto-indenting and prepends spaces to the input.
359 """
357 """
360 src = mini_interactive_loop(pseudo_input(lines))
358 src = mini_interactive_loop(pseudo_input(lines))
361 test_ns = {}
359 test_ns = {}
362 exec(src, test_ns)
360 exec(src, test_ns)
363 # We can't check that the provided ns is identical to the test_ns,
361 # We can't check that the provided ns is identical to the test_ns,
364 # because Python fills test_ns with extra keys (copyright, etc). But
362 # because Python fills test_ns with extra keys (copyright, etc). But
365 # we can check that the given dict is *contained* in test_ns
363 # we can check that the given dict is *contained* in test_ns
366 for k,v in ns.items():
364 for k,v in ns.items():
367 self.assertEqual(test_ns[k], v)
365 self.assertEqual(test_ns[k], v)
368
366
369 def test_simple(self):
367 def test_simple(self):
370 self.check_ns(['x=1'], dict(x=1))
368 self.check_ns(['x=1'], dict(x=1))
371
369
372 def test_simple2(self):
370 def test_simple2(self):
373 self.check_ns(['if 1:', 'x=2'], dict(x=2))
371 self.check_ns(['if 1:', 'x=2'], dict(x=2))
374
372
375 def test_xy(self):
373 def test_xy(self):
376 self.check_ns(['x=1; y=2'], dict(x=1, y=2))
374 self.check_ns(['x=1; y=2'], dict(x=1, y=2))
377
375
378 def test_abc(self):
376 def test_abc(self):
379 self.check_ns(['if 1:','a=1','b=2','c=3'], dict(a=1, b=2, c=3))
377 self.check_ns(['if 1:','a=1','b=2','c=3'], dict(a=1, b=2, c=3))
380
378
381 def test_multi(self):
379 def test_multi(self):
382 self.check_ns(['x =(1+','1+','2)'], dict(x=4))
380 self.check_ns(['x =(1+','1+','2)'], dict(x=4))
383
381
384
382
385 class IPythonInputTestCase(InputSplitterTestCase):
383 class IPythonInputTestCase(InputSplitterTestCase):
386 """By just creating a new class whose .isp is a different instance, we
384 """By just creating a new class whose .isp is a different instance, we
387 re-run the same test battery on the new input splitter.
385 re-run the same test battery on the new input splitter.
388
386
389 In addition, this runs the tests over the syntax and syntax_ml dicts that
387 In addition, this runs the tests over the syntax and syntax_ml dicts that
390 were tested by individual functions, as part of the OO interface.
388 were tested by individual functions, as part of the OO interface.
391
389
392 It also makes some checks on the raw buffer storage.
390 It also makes some checks on the raw buffer storage.
393 """
391 """
394
392
395 def setUp(self):
393 def setUp(self):
396 self.isp = isp.IPythonInputSplitter()
394 self.isp = isp.IPythonInputSplitter()
397
395
398 def test_syntax(self):
396 def test_syntax(self):
399 """Call all single-line syntax tests from the main object"""
397 """Call all single-line syntax tests from the main object"""
400 isp = self.isp
398 isp = self.isp
401 for example in syntax.values():
399 for example in syntax.values():
402 for raw, out_t in example:
400 for raw, out_t in example:
403 if raw.startswith(' '):
401 if raw.startswith(' '):
404 continue
402 continue
405
403
406 isp.push(raw+'\n')
404 isp.push(raw+'\n')
407 out_raw = isp.source_raw
405 out_raw = isp.source_raw
408 out = isp.source_reset()
406 out = isp.source_reset()
409 self.assertEqual(out.rstrip(), out_t,
407 self.assertEqual(out.rstrip(), out_t,
410 tt.pair_fail_msg.format("inputsplitter",raw, out_t, out))
408 tt.pair_fail_msg.format("inputsplitter",raw, out_t, out))
411 self.assertEqual(out_raw.rstrip(), raw.rstrip())
409 self.assertEqual(out_raw.rstrip(), raw.rstrip())
412
410
413 def test_syntax_multiline(self):
411 def test_syntax_multiline(self):
414 isp = self.isp
412 isp = self.isp
415 for example in syntax_ml.values():
413 for example in syntax_ml.values():
416 for line_pairs in example:
414 for line_pairs in example:
417 out_t_parts = []
415 out_t_parts = []
418 raw_parts = []
416 raw_parts = []
419 for lraw, out_t_part in line_pairs:
417 for lraw, out_t_part in line_pairs:
420 if out_t_part is not None:
418 if out_t_part is not None:
421 out_t_parts.append(out_t_part)
419 out_t_parts.append(out_t_part)
422
420
423 if lraw is not None:
421 if lraw is not None:
424 isp.push(lraw)
422 isp.push(lraw)
425 raw_parts.append(lraw)
423 raw_parts.append(lraw)
426
424
427 out_raw = isp.source_raw
425 out_raw = isp.source_raw
428 out = isp.source_reset()
426 out = isp.source_reset()
429 out_t = '\n'.join(out_t_parts).rstrip()
427 out_t = '\n'.join(out_t_parts).rstrip()
430 raw = '\n'.join(raw_parts).rstrip()
428 raw = '\n'.join(raw_parts).rstrip()
431 self.assertEqual(out.rstrip(), out_t)
429 self.assertEqual(out.rstrip(), out_t)
432 self.assertEqual(out_raw.rstrip(), raw)
430 self.assertEqual(out_raw.rstrip(), raw)
433
431
434 def test_syntax_multiline_cell(self):
432 def test_syntax_multiline_cell(self):
435 isp = self.isp
433 isp = self.isp
436 for example in syntax_ml.values():
434 for example in syntax_ml.values():
437
435
438 out_t_parts = []
436 out_t_parts = []
439 for line_pairs in example:
437 for line_pairs in example:
440 raw = '\n'.join(r for r, _ in line_pairs if r is not None)
438 raw = '\n'.join(r for r, _ in line_pairs if r is not None)
441 out_t = '\n'.join(t for _,t in line_pairs if t is not None)
439 out_t = '\n'.join(t for _,t in line_pairs if t is not None)
442 out = isp.transform_cell(raw)
440 out = isp.transform_cell(raw)
443 # Match ignoring trailing whitespace
441 # Match ignoring trailing whitespace
444 self.assertEqual(out.rstrip(), out_t.rstrip())
442 self.assertEqual(out.rstrip(), out_t.rstrip())
445
443
446 def test_cellmagic_preempt(self):
444 def test_cellmagic_preempt(self):
447 isp = self.isp
445 isp = self.isp
448 for raw, name, line, cell in [
446 for raw, name, line, cell in [
449 ("%%cellm a\nIn[1]:", u'cellm', u'a', u'In[1]:'),
447 ("%%cellm a\nIn[1]:", u'cellm', u'a', u'In[1]:'),
450 ("%%cellm \nline\n>>> hi", u'cellm', u'', u'line\n>>> hi'),
448 ("%%cellm \nline\n>>> hi", u'cellm', u'', u'line\n>>> hi'),
451 (">>> %%cellm \nline\n>>> hi", u'cellm', u'', u'line\nhi'),
449 (">>> %%cellm \nline\n>>> hi", u'cellm', u'', u'line\nhi'),
452 ("%%cellm \n>>> hi", u'cellm', u'', u'>>> hi'),
450 ("%%cellm \n>>> hi", u'cellm', u'', u'>>> hi'),
453 ("%%cellm \nline1\nline2", u'cellm', u'', u'line1\nline2'),
451 ("%%cellm \nline1\nline2", u'cellm', u'', u'line1\nline2'),
454 ("%%cellm \nline1\\\\\nline2", u'cellm', u'', u'line1\\\\\nline2'),
452 ("%%cellm \nline1\\\\\nline2", u'cellm', u'', u'line1\\\\\nline2'),
455 ]:
453 ]:
456 expected = "get_ipython().run_cell_magic(%r, %r, %r)" % (
454 expected = "get_ipython().run_cell_magic(%r, %r, %r)" % (
457 name, line, cell
455 name, line, cell
458 )
456 )
459 out = isp.transform_cell(raw)
457 out = isp.transform_cell(raw)
460 self.assertEqual(out.rstrip(), expected.rstrip())
458 self.assertEqual(out.rstrip(), expected.rstrip())
461
459
462 def test_multiline_passthrough(self):
460 def test_multiline_passthrough(self):
463 isp = self.isp
461 isp = self.isp
464 class CommentTransformer(InputTransformer):
462 class CommentTransformer(InputTransformer):
465 def __init__(self):
463 def __init__(self):
466 self._lines = []
464 self._lines = []
467
465
468 def push(self, line):
466 def push(self, line):
469 self._lines.append(line + '#')
467 self._lines.append(line + '#')
470
468
471 def reset(self):
469 def reset(self):
472 text = '\n'.join(self._lines)
470 text = '\n'.join(self._lines)
473 self._lines = []
471 self._lines = []
474 return text
472 return text
475
473
476 isp.physical_line_transforms.insert(0, CommentTransformer())
474 isp.physical_line_transforms.insert(0, CommentTransformer())
477
475
478 for raw, expected in [
476 for raw, expected in [
479 ("a=5", "a=5#"),
477 ("a=5", "a=5#"),
480 ("%ls foo", "get_ipython().run_line_magic(%r, %r)" % (u'ls', u'foo#')),
478 ("%ls foo", "get_ipython().run_line_magic(%r, %r)" % (u'ls', u'foo#')),
481 ("!ls foo\n%ls bar", "get_ipython().system(%r)\nget_ipython().run_line_magic(%r, %r)" % (
479 ("!ls foo\n%ls bar", "get_ipython().system(%r)\nget_ipython().run_line_magic(%r, %r)" % (
482 u'ls foo#', u'ls', u'bar#'
480 u'ls foo#', u'ls', u'bar#'
483 )),
481 )),
484 ("1\n2\n3\n%ls foo\n4\n5", "1#\n2#\n3#\nget_ipython().run_line_magic(%r, %r)\n4#\n5#" % (u'ls', u'foo#')),
482 ("1\n2\n3\n%ls foo\n4\n5", "1#\n2#\n3#\nget_ipython().run_line_magic(%r, %r)\n4#\n5#" % (u'ls', u'foo#')),
485 ]:
483 ]:
486 out = isp.transform_cell(raw)
484 out = isp.transform_cell(raw)
487 self.assertEqual(out.rstrip(), expected.rstrip())
485 self.assertEqual(out.rstrip(), expected.rstrip())
488
486
489 #-----------------------------------------------------------------------------
487 #-----------------------------------------------------------------------------
490 # Main - use as a script, mostly for developer experiments
488 # Main - use as a script, mostly for developer experiments
491 #-----------------------------------------------------------------------------
489 #-----------------------------------------------------------------------------
492
490
493 if __name__ == '__main__':
491 if __name__ == '__main__':
494 # A simple demo for interactive experimentation. This code will not get
492 # A simple demo for interactive experimentation. This code will not get
495 # picked up by any test suite.
493 # picked up by any test suite.
496 from IPython.core.inputsplitter import IPythonInputSplitter
494 from IPython.core.inputsplitter import IPythonInputSplitter
497
495
498 # configure here the syntax to use, prompt and whether to autoindent
496 # configure here the syntax to use, prompt and whether to autoindent
499 #isp, start_prompt = InputSplitter(), '>>> '
497 #isp, start_prompt = InputSplitter(), '>>> '
500 isp, start_prompt = IPythonInputSplitter(), 'In> '
498 isp, start_prompt = IPythonInputSplitter(), 'In> '
501
499
502 autoindent = True
500 autoindent = True
503 #autoindent = False
501 #autoindent = False
504
502
505 try:
503 try:
506 while True:
504 while True:
507 prompt = start_prompt
505 prompt = start_prompt
508 while isp.push_accepts_more():
506 while isp.push_accepts_more():
509 indent = ' '*isp.get_indent_spaces()
507 indent = ' '*isp.get_indent_spaces()
510 if autoindent:
508 if autoindent:
511 line = indent + input(prompt+indent)
509 line = indent + input(prompt+indent)
512 else:
510 else:
513 line = input(prompt)
511 line = input(prompt)
514 isp.push(line)
512 isp.push(line)
515 prompt = '... '
513 prompt = '... '
516
514
517 # Here we just return input so we can use it in a test suite, but a
515 # Here we just return input so we can use it in a test suite, but a
518 # real interpreter would instead send it for execution somewhere.
516 # real interpreter would instead send it for execution somewhere.
519 #src = isp.source; raise EOFError # dbg
517 #src = isp.source; raise EOFError # dbg
520 raw = isp.source_raw
518 raw = isp.source_raw
521 src = isp.source_reset()
519 src = isp.source_reset()
522 print('Input source was:\n', src)
520 print('Input source was:\n', src)
523 print('Raw source was:\n', raw)
521 print('Raw source was:\n', raw)
524 except EOFError:
522 except EOFError:
525 print('Bye')
523 print('Bye')
526
524
527 # Tests for cell magics support
525 # Tests for cell magics support
528
526
529 def test_last_blank():
527 def test_last_blank():
530 nt.assert_false(isp.last_blank(''))
528 assert isp.last_blank("") is False
531 nt.assert_false(isp.last_blank('abc'))
529 assert isp.last_blank("abc") is False
532 nt.assert_false(isp.last_blank('abc\n'))
530 assert isp.last_blank("abc\n") is False
533 nt.assert_false(isp.last_blank('abc\na'))
531 assert isp.last_blank("abc\na") is False
534
532
535 nt.assert_true(isp.last_blank('\n'))
533 assert isp.last_blank("\n") is True
536 nt.assert_true(isp.last_blank('\n '))
534 assert isp.last_blank("\n ") is True
537 nt.assert_true(isp.last_blank('abc\n '))
535 assert isp.last_blank("abc\n ") is True
538 nt.assert_true(isp.last_blank('abc\n\n'))
536 assert isp.last_blank("abc\n\n") is True
539 nt.assert_true(isp.last_blank('abc\nd\n\n'))
537 assert isp.last_blank("abc\nd\n\n") is True
540 nt.assert_true(isp.last_blank('abc\nd\ne\n\n'))
538 assert isp.last_blank("abc\nd\ne\n\n") is True
541 nt.assert_true(isp.last_blank('abc \n \n \n\n'))
539 assert isp.last_blank("abc \n \n \n\n") is True
542
540
543
541
544 def test_last_two_blanks():
542 def test_last_two_blanks():
545 nt.assert_false(isp.last_two_blanks(''))
543 assert isp.last_two_blanks("") is False
546 nt.assert_false(isp.last_two_blanks('abc'))
544 assert isp.last_two_blanks("abc") is False
547 nt.assert_false(isp.last_two_blanks('abc\n'))
545 assert isp.last_two_blanks("abc\n") is False
548 nt.assert_false(isp.last_two_blanks('abc\n\na'))
546 assert isp.last_two_blanks("abc\n\na") is False
549 nt.assert_false(isp.last_two_blanks('abc\n \n'))
547 assert isp.last_two_blanks("abc\n \n") is False
550 nt.assert_false(isp.last_two_blanks('abc\n\n'))
548 assert isp.last_two_blanks("abc\n\n") is False
551
549
552 nt.assert_true(isp.last_two_blanks('\n\n'))
550 assert isp.last_two_blanks("\n\n") is True
553 nt.assert_true(isp.last_two_blanks('\n\n '))
551 assert isp.last_two_blanks("\n\n ") is True
554 nt.assert_true(isp.last_two_blanks('\n \n'))
552 assert isp.last_two_blanks("\n \n") is True
555 nt.assert_true(isp.last_two_blanks('abc\n\n '))
553 assert isp.last_two_blanks("abc\n\n ") is True
556 nt.assert_true(isp.last_two_blanks('abc\n\n\n'))
554 assert isp.last_two_blanks("abc\n\n\n") is True
557 nt.assert_true(isp.last_two_blanks('abc\n\n \n'))
555 assert isp.last_two_blanks("abc\n\n \n") is True
558 nt.assert_true(isp.last_two_blanks('abc\n\n \n '))
556 assert isp.last_two_blanks("abc\n\n \n ") is True
559 nt.assert_true(isp.last_two_blanks('abc\n\n \n \n'))
557 assert isp.last_two_blanks("abc\n\n \n \n") is True
560 nt.assert_true(isp.last_two_blanks('abc\nd\n\n\n'))
558 assert isp.last_two_blanks("abc\nd\n\n\n") is True
561 nt.assert_true(isp.last_two_blanks('abc\nd\ne\nf\n\n\n'))
559 assert isp.last_two_blanks("abc\nd\ne\nf\n\n\n") is True
562
560
563
561
564 class CellMagicsCommon(object):
562 class CellMagicsCommon(object):
565
563
566 def test_whole_cell(self):
564 def test_whole_cell(self):
567 src = "%%cellm line\nbody\n"
565 src = "%%cellm line\nbody\n"
568 out = self.sp.transform_cell(src)
566 out = self.sp.transform_cell(src)
569 ref = "get_ipython().run_cell_magic('cellm', 'line', 'body')\n"
567 ref = "get_ipython().run_cell_magic('cellm', 'line', 'body')\n"
570 nt.assert_equal(out, ref)
568 assert out == ref
571
569
572 def test_cellmagic_help(self):
570 def test_cellmagic_help(self):
573 self.sp.push('%%cellm?')
571 self.sp.push('%%cellm?')
574 nt.assert_false(self.sp.push_accepts_more())
572 assert self.sp.push_accepts_more() is False
575
573
576 def tearDown(self):
574 def tearDown(self):
577 self.sp.reset()
575 self.sp.reset()
578
576
579
577
580 class CellModeCellMagics(CellMagicsCommon, unittest.TestCase):
578 class CellModeCellMagics(CellMagicsCommon, unittest.TestCase):
581 sp = isp.IPythonInputSplitter(line_input_checker=False)
579 sp = isp.IPythonInputSplitter(line_input_checker=False)
582
580
583 def test_incremental(self):
581 def test_incremental(self):
584 sp = self.sp
582 sp = self.sp
585 sp.push('%%cellm firstline\n')
583 sp.push("%%cellm firstline\n")
586 nt.assert_true(sp.push_accepts_more()) #1
584 assert sp.push_accepts_more() is True # 1
587 sp.push('line2\n')
585 sp.push("line2\n")
588 nt.assert_true(sp.push_accepts_more()) #2
586 assert sp.push_accepts_more() is True # 2
589 sp.push('\n')
587 sp.push("\n")
590 # This should accept a blank line and carry on until the cell is reset
588 # This should accept a blank line and carry on until the cell is reset
591 nt.assert_true(sp.push_accepts_more()) #3
589 assert sp.push_accepts_more() is True # 3
592
590
593 def test_no_strip_coding(self):
591 def test_no_strip_coding(self):
594 src = '\n'.join([
592 src = '\n'.join([
595 '%%writefile foo.py',
593 '%%writefile foo.py',
596 '# coding: utf-8',
594 '# coding: utf-8',
597 'print(u"üñîçø∂é")',
595 'print(u"üñîçø∂é")',
598 ])
596 ])
599 out = self.sp.transform_cell(src)
597 out = self.sp.transform_cell(src)
600 nt.assert_in('# coding: utf-8', out)
598 assert "# coding: utf-8" in out
601
599
602
600
603 class LineModeCellMagics(CellMagicsCommon, unittest.TestCase):
601 class LineModeCellMagics(CellMagicsCommon, unittest.TestCase):
604 sp = isp.IPythonInputSplitter(line_input_checker=True)
602 sp = isp.IPythonInputSplitter(line_input_checker=True)
605
603
606 def test_incremental(self):
604 def test_incremental(self):
607 sp = self.sp
605 sp = self.sp
608 sp.push('%%cellm line2\n')
606 sp.push("%%cellm line2\n")
609 nt.assert_true(sp.push_accepts_more()) #1
607 assert sp.push_accepts_more() is True # 1
610 sp.push('\n')
608 sp.push("\n")
611 # In this case, a blank line should end the cell magic
609 # In this case, a blank line should end the cell magic
612 nt.assert_false(sp.push_accepts_more()) #2
610 assert sp.push_accepts_more() is False # 2
611
613
612
614 indentation_samples = [
613 indentation_samples = [
615 ('a = 1', 0),
614 ('a = 1', 0),
616 ('for a in b:', 4),
615 ('for a in b:', 4),
617 ('def f():', 4),
616 ('def f():', 4),
618 ('def f(): #comment', 4),
617 ('def f(): #comment', 4),
619 ('a = ":#not a comment"', 0),
618 ('a = ":#not a comment"', 0),
620 ('def f():\n a = 1', 4),
619 ('def f():\n a = 1', 4),
621 ('def f():\n return 1', 0),
620 ('def f():\n return 1', 0),
622 ('for a in b:\n'
621 ('for a in b:\n'
623 ' if a < 0:'
622 ' if a < 0:'
624 ' continue', 3),
623 ' continue', 3),
625 ('a = {', 4),
624 ('a = {', 4),
626 ('a = {\n'
625 ('a = {\n'
627 ' 1,', 5),
626 ' 1,', 5),
628 ('b = """123', 0),
627 ('b = """123', 0),
629 ('', 0),
628 ('', 0),
630 ('def f():\n pass', 0),
629 ('def f():\n pass', 0),
631 ('class Bar:\n def f():\n pass', 4),
630 ('class Bar:\n def f():\n pass', 4),
632 ('class Bar:\n def f():\n raise', 4),
631 ('class Bar:\n def f():\n raise', 4),
633 ]
632 ]
634
633
635 def test_find_next_indent():
634 def test_find_next_indent():
636 for code, exp in indentation_samples:
635 for code, exp in indentation_samples:
637 res = isp.find_next_indent(code)
636 res = isp.find_next_indent(code)
638 msg = "{!r} != {!r} (expected)\n Code: {!r}".format(res, exp, code)
637 msg = "{!r} != {!r} (expected)\n Code: {!r}".format(res, exp, code)
639 assert res == exp, msg
638 assert res == exp, msg
@@ -1,485 +1,484 b''
1 import tokenize
1 import tokenize
2 import nose.tools as nt
3
2
4 from IPython.testing import tools as tt
3 from IPython.testing import tools as tt
5
4
6 from IPython.core import inputtransformer as ipt
5 from IPython.core import inputtransformer as ipt
7
6
8 def transform_and_reset(transformer):
7 def transform_and_reset(transformer):
9 transformer = transformer()
8 transformer = transformer()
10 def transform(inp):
9 def transform(inp):
11 try:
10 try:
12 return transformer.push(inp)
11 return transformer.push(inp)
13 finally:
12 finally:
14 transformer.reset()
13 transformer.reset()
15
14
16 return transform
15 return transform
17
16
18 # Transformer tests
17 # Transformer tests
19 def transform_checker(tests, transformer, **kwargs):
18 def transform_checker(tests, transformer, **kwargs):
20 """Utility to loop over test inputs"""
19 """Utility to loop over test inputs"""
21 transformer = transformer(**kwargs)
20 transformer = transformer(**kwargs)
22 try:
21 try:
23 for inp, tr in tests:
22 for inp, tr in tests:
24 if inp is None:
23 if inp is None:
25 out = transformer.reset()
24 out = transformer.reset()
26 else:
25 else:
27 out = transformer.push(inp)
26 out = transformer.push(inp)
28 nt.assert_equal(out, tr)
27 assert out == tr
29 finally:
28 finally:
30 transformer.reset()
29 transformer.reset()
31
30
32 # Data for all the syntax tests in the form of lists of pairs of
31 # Data for all the syntax tests in the form of lists of pairs of
33 # raw/transformed input. We store it here as a global dict so that we can use
32 # raw/transformed input. We store it here as a global dict so that we can use
34 # it both within single-function tests and also to validate the behavior of the
33 # it both within single-function tests and also to validate the behavior of the
35 # larger objects
34 # larger objects
36
35
37 syntax = \
36 syntax = \
38 dict(assign_system =
37 dict(assign_system =
39 [('a =! ls', "a = get_ipython().getoutput('ls')"),
38 [('a =! ls', "a = get_ipython().getoutput('ls')"),
40 ('b = !ls', "b = get_ipython().getoutput('ls')"),
39 ('b = !ls', "b = get_ipython().getoutput('ls')"),
41 ('c= !ls', "c = get_ipython().getoutput('ls')"),
40 ('c= !ls', "c = get_ipython().getoutput('ls')"),
42 ('d == !ls', 'd == !ls'), # Invalid syntax, but we leave == alone.
41 ('d == !ls', 'd == !ls'), # Invalid syntax, but we leave == alone.
43 ('x=1', 'x=1'), # normal input is unmodified
42 ('x=1', 'x=1'), # normal input is unmodified
44 (' ',' '), # blank lines are kept intact
43 (' ',' '), # blank lines are kept intact
45 # Tuple unpacking
44 # Tuple unpacking
46 ("a, b = !echo 'a\\nb'", "a, b = get_ipython().getoutput(\"echo 'a\\\\nb'\")"),
45 ("a, b = !echo 'a\\nb'", "a, b = get_ipython().getoutput(\"echo 'a\\\\nb'\")"),
47 ("a,= !echo 'a'", "a, = get_ipython().getoutput(\"echo 'a'\")"),
46 ("a,= !echo 'a'", "a, = get_ipython().getoutput(\"echo 'a'\")"),
48 ("a, *bc = !echo 'a\\nb\\nc'", "a, *bc = get_ipython().getoutput(\"echo 'a\\\\nb\\\\nc'\")"),
47 ("a, *bc = !echo 'a\\nb\\nc'", "a, *bc = get_ipython().getoutput(\"echo 'a\\\\nb\\\\nc'\")"),
49 # Tuple unpacking with regular Python expressions, not our syntax.
48 # Tuple unpacking with regular Python expressions, not our syntax.
50 ("a, b = range(2)", "a, b = range(2)"),
49 ("a, b = range(2)", "a, b = range(2)"),
51 ("a, = range(1)", "a, = range(1)"),
50 ("a, = range(1)", "a, = range(1)"),
52 ("a, *bc = range(3)", "a, *bc = range(3)"),
51 ("a, *bc = range(3)", "a, *bc = range(3)"),
53 ],
52 ],
54
53
55 assign_magic =
54 assign_magic =
56 [('a =% who', "a = get_ipython().run_line_magic('who', '')"),
55 [('a =% who', "a = get_ipython().run_line_magic('who', '')"),
57 ('b = %who', "b = get_ipython().run_line_magic('who', '')"),
56 ('b = %who', "b = get_ipython().run_line_magic('who', '')"),
58 ('c= %ls', "c = get_ipython().run_line_magic('ls', '')"),
57 ('c= %ls', "c = get_ipython().run_line_magic('ls', '')"),
59 ('d == %ls', 'd == %ls'), # Invalid syntax, but we leave == alone.
58 ('d == %ls', 'd == %ls'), # Invalid syntax, but we leave == alone.
60 ('x=1', 'x=1'), # normal input is unmodified
59 ('x=1', 'x=1'), # normal input is unmodified
61 (' ',' '), # blank lines are kept intact
60 (' ',' '), # blank lines are kept intact
62 ("a, b = %foo", "a, b = get_ipython().run_line_magic('foo', '')"),
61 ("a, b = %foo", "a, b = get_ipython().run_line_magic('foo', '')"),
63 ],
62 ],
64
63
65 classic_prompt =
64 classic_prompt =
66 [('>>> x=1', 'x=1'),
65 [('>>> x=1', 'x=1'),
67 ('x=1', 'x=1'), # normal input is unmodified
66 ('x=1', 'x=1'), # normal input is unmodified
68 (' ', ' '), # blank lines are kept intact
67 (' ', ' '), # blank lines are kept intact
69 ],
68 ],
70
69
71 ipy_prompt =
70 ipy_prompt =
72 [('In [1]: x=1', 'x=1'),
71 [('In [1]: x=1', 'x=1'),
73 ('x=1', 'x=1'), # normal input is unmodified
72 ('x=1', 'x=1'), # normal input is unmodified
74 (' ',' '), # blank lines are kept intact
73 (' ',' '), # blank lines are kept intact
75 ],
74 ],
76
75
77 # Tests for the escape transformer to leave normal code alone
76 # Tests for the escape transformer to leave normal code alone
78 escaped_noesc =
77 escaped_noesc =
79 [ (' ', ' '),
78 [ (' ', ' '),
80 ('x=1', 'x=1'),
79 ('x=1', 'x=1'),
81 ],
80 ],
82
81
83 # System calls
82 # System calls
84 escaped_shell =
83 escaped_shell =
85 [ ('!ls', "get_ipython().system('ls')"),
84 [ ('!ls', "get_ipython().system('ls')"),
86 # Double-escape shell, this means to capture the output of the
85 # Double-escape shell, this means to capture the output of the
87 # subprocess and return it
86 # subprocess and return it
88 ('!!ls', "get_ipython().getoutput('ls')"),
87 ('!!ls', "get_ipython().getoutput('ls')"),
89 ],
88 ],
90
89
91 # Help/object info
90 # Help/object info
92 escaped_help =
91 escaped_help =
93 [ ('?', 'get_ipython().show_usage()'),
92 [ ('?', 'get_ipython().show_usage()'),
94 ('?x1', "get_ipython().run_line_magic('pinfo', 'x1')"),
93 ('?x1', "get_ipython().run_line_magic('pinfo', 'x1')"),
95 ('??x2', "get_ipython().run_line_magic('pinfo2', 'x2')"),
94 ('??x2', "get_ipython().run_line_magic('pinfo2', 'x2')"),
96 ('?a.*s', "get_ipython().run_line_magic('psearch', 'a.*s')"),
95 ('?a.*s', "get_ipython().run_line_magic('psearch', 'a.*s')"),
97 ('?%hist1', "get_ipython().run_line_magic('pinfo', '%hist1')"),
96 ('?%hist1', "get_ipython().run_line_magic('pinfo', '%hist1')"),
98 ('?%%hist2', "get_ipython().run_line_magic('pinfo', '%%hist2')"),
97 ('?%%hist2', "get_ipython().run_line_magic('pinfo', '%%hist2')"),
99 ('?abc = qwe', "get_ipython().run_line_magic('pinfo', 'abc')"),
98 ('?abc = qwe', "get_ipython().run_line_magic('pinfo', 'abc')"),
100 ],
99 ],
101
100
102 end_help =
101 end_help =
103 [ ('x3?', "get_ipython().run_line_magic('pinfo', 'x3')"),
102 [ ('x3?', "get_ipython().run_line_magic('pinfo', 'x3')"),
104 ('x4??', "get_ipython().run_line_magic('pinfo2', 'x4')"),
103 ('x4??', "get_ipython().run_line_magic('pinfo2', 'x4')"),
105 ('%hist1?', "get_ipython().run_line_magic('pinfo', '%hist1')"),
104 ('%hist1?', "get_ipython().run_line_magic('pinfo', '%hist1')"),
106 ('%hist2??', "get_ipython().run_line_magic('pinfo2', '%hist2')"),
105 ('%hist2??', "get_ipython().run_line_magic('pinfo2', '%hist2')"),
107 ('%%hist3?', "get_ipython().run_line_magic('pinfo', '%%hist3')"),
106 ('%%hist3?', "get_ipython().run_line_magic('pinfo', '%%hist3')"),
108 ('%%hist4??', "get_ipython().run_line_magic('pinfo2', '%%hist4')"),
107 ('%%hist4??', "get_ipython().run_line_magic('pinfo2', '%%hist4')"),
109 ('π.foo?', "get_ipython().run_line_magic('pinfo', 'π.foo')"),
108 ('π.foo?', "get_ipython().run_line_magic('pinfo', 'π.foo')"),
110 ('f*?', "get_ipython().run_line_magic('psearch', 'f*')"),
109 ('f*?', "get_ipython().run_line_magic('psearch', 'f*')"),
111 ('ax.*aspe*?', "get_ipython().run_line_magic('psearch', 'ax.*aspe*')"),
110 ('ax.*aspe*?', "get_ipython().run_line_magic('psearch', 'ax.*aspe*')"),
112 ('a = abc?', "get_ipython().set_next_input('a = abc');"
111 ('a = abc?', "get_ipython().set_next_input('a = abc');"
113 "get_ipython().run_line_magic('pinfo', 'abc')"),
112 "get_ipython().run_line_magic('pinfo', 'abc')"),
114 ('a = abc.qe??', "get_ipython().set_next_input('a = abc.qe');"
113 ('a = abc.qe??', "get_ipython().set_next_input('a = abc.qe');"
115 "get_ipython().run_line_magic('pinfo2', 'abc.qe')"),
114 "get_ipython().run_line_magic('pinfo2', 'abc.qe')"),
116 ('a = *.items?', "get_ipython().set_next_input('a = *.items');"
115 ('a = *.items?', "get_ipython().set_next_input('a = *.items');"
117 "get_ipython().run_line_magic('psearch', '*.items')"),
116 "get_ipython().run_line_magic('psearch', '*.items')"),
118 ('plot(a?', "get_ipython().set_next_input('plot(a');"
117 ('plot(a?', "get_ipython().set_next_input('plot(a');"
119 "get_ipython().run_line_magic('pinfo', 'a')"),
118 "get_ipython().run_line_magic('pinfo', 'a')"),
120 ('a*2 #comment?', 'a*2 #comment?'),
119 ('a*2 #comment?', 'a*2 #comment?'),
121 ],
120 ],
122
121
123 # Explicit magic calls
122 # Explicit magic calls
124 escaped_magic =
123 escaped_magic =
125 [ ('%cd', "get_ipython().run_line_magic('cd', '')"),
124 [ ('%cd', "get_ipython().run_line_magic('cd', '')"),
126 ('%cd /home', "get_ipython().run_line_magic('cd', '/home')"),
125 ('%cd /home', "get_ipython().run_line_magic('cd', '/home')"),
127 # Backslashes need to be escaped.
126 # Backslashes need to be escaped.
128 ('%cd C:\\User', "get_ipython().run_line_magic('cd', 'C:\\\\User')"),
127 ('%cd C:\\User', "get_ipython().run_line_magic('cd', 'C:\\\\User')"),
129 (' %magic', " get_ipython().run_line_magic('magic', '')"),
128 (' %magic', " get_ipython().run_line_magic('magic', '')"),
130 ],
129 ],
131
130
132 # Quoting with separate arguments
131 # Quoting with separate arguments
133 escaped_quote =
132 escaped_quote =
134 [ (',f', 'f("")'),
133 [ (',f', 'f("")'),
135 (',f x', 'f("x")'),
134 (',f x', 'f("x")'),
136 (' ,f y', ' f("y")'),
135 (' ,f y', ' f("y")'),
137 (',f a b', 'f("a", "b")'),
136 (',f a b', 'f("a", "b")'),
138 ],
137 ],
139
138
140 # Quoting with single argument
139 # Quoting with single argument
141 escaped_quote2 =
140 escaped_quote2 =
142 [ (';f', 'f("")'),
141 [ (';f', 'f("")'),
143 (';f x', 'f("x")'),
142 (';f x', 'f("x")'),
144 (' ;f y', ' f("y")'),
143 (' ;f y', ' f("y")'),
145 (';f a b', 'f("a b")'),
144 (';f a b', 'f("a b")'),
146 ],
145 ],
147
146
148 # Simply apply parens
147 # Simply apply parens
149 escaped_paren =
148 escaped_paren =
150 [ ('/f', 'f()'),
149 [ ('/f', 'f()'),
151 ('/f x', 'f(x)'),
150 ('/f x', 'f(x)'),
152 (' /f y', ' f(y)'),
151 (' /f y', ' f(y)'),
153 ('/f a b', 'f(a, b)'),
152 ('/f a b', 'f(a, b)'),
154 ],
153 ],
155
154
156 # Check that we transform prompts before other transforms
155 # Check that we transform prompts before other transforms
157 mixed =
156 mixed =
158 [ ('In [1]: %lsmagic', "get_ipython().run_line_magic('lsmagic', '')"),
157 [ ('In [1]: %lsmagic', "get_ipython().run_line_magic('lsmagic', '')"),
159 ('>>> %lsmagic', "get_ipython().run_line_magic('lsmagic', '')"),
158 ('>>> %lsmagic', "get_ipython().run_line_magic('lsmagic', '')"),
160 ('In [2]: !ls', "get_ipython().system('ls')"),
159 ('In [2]: !ls', "get_ipython().system('ls')"),
161 ('In [3]: abs?', "get_ipython().run_line_magic('pinfo', 'abs')"),
160 ('In [3]: abs?', "get_ipython().run_line_magic('pinfo', 'abs')"),
162 ('In [4]: b = %who', "b = get_ipython().run_line_magic('who', '')"),
161 ('In [4]: b = %who', "b = get_ipython().run_line_magic('who', '')"),
163 ],
162 ],
164 )
163 )
165
164
166 # multiline syntax examples. Each of these should be a list of lists, with
165 # multiline syntax examples. Each of these should be a list of lists, with
167 # each entry itself having pairs of raw/transformed input. The union (with
166 # each entry itself having pairs of raw/transformed input. The union (with
168 # '\n'.join() of the transformed inputs is what the splitter should produce
167 # '\n'.join() of the transformed inputs is what the splitter should produce
169 # when fed the raw lines one at a time via push.
168 # when fed the raw lines one at a time via push.
170 syntax_ml = \
169 syntax_ml = \
171 dict(classic_prompt =
170 dict(classic_prompt =
172 [ [('>>> for i in range(10):','for i in range(10):'),
171 [ [('>>> for i in range(10):','for i in range(10):'),
173 ('... print i',' print i'),
172 ('... print i',' print i'),
174 ('... ', ''),
173 ('... ', ''),
175 ],
174 ],
176 [('>>> a="""','a="""'),
175 [('>>> a="""','a="""'),
177 ('... 123"""','123"""'),
176 ('... 123"""','123"""'),
178 ],
177 ],
179 [('a="""','a="""'),
178 [('a="""','a="""'),
180 ('... 123','123'),
179 ('... 123','123'),
181 ('... 456"""','456"""'),
180 ('... 456"""','456"""'),
182 ],
181 ],
183 [('a="""','a="""'),
182 [('a="""','a="""'),
184 ('>>> 123','123'),
183 ('>>> 123','123'),
185 ('... 456"""','456"""'),
184 ('... 456"""','456"""'),
186 ],
185 ],
187 [('a="""','a="""'),
186 [('a="""','a="""'),
188 ('123','123'),
187 ('123','123'),
189 ('... 456"""','... 456"""'),
188 ('... 456"""','... 456"""'),
190 ],
189 ],
191 [('....__class__','....__class__'),
190 [('....__class__','....__class__'),
192 ],
191 ],
193 [('a=5', 'a=5'),
192 [('a=5', 'a=5'),
194 ('...', ''),
193 ('...', ''),
195 ],
194 ],
196 [('>>> def f(x):', 'def f(x):'),
195 [('>>> def f(x):', 'def f(x):'),
197 ('...', ''),
196 ('...', ''),
198 ('... return x', ' return x'),
197 ('... return x', ' return x'),
199 ],
198 ],
200 [('board = """....', 'board = """....'),
199 [('board = """....', 'board = """....'),
201 ('....', '....'),
200 ('....', '....'),
202 ('...."""', '...."""'),
201 ('...."""', '...."""'),
203 ],
202 ],
204 ],
203 ],
205
204
206 ipy_prompt =
205 ipy_prompt =
207 [ [('In [24]: for i in range(10):','for i in range(10):'),
206 [ [('In [24]: for i in range(10):','for i in range(10):'),
208 (' ....: print i',' print i'),
207 (' ....: print i',' print i'),
209 (' ....: ', ''),
208 (' ....: ', ''),
210 ],
209 ],
211 [('In [24]: for i in range(10):','for i in range(10):'),
210 [('In [24]: for i in range(10):','for i in range(10):'),
212 # Qt console prompts expand with spaces, not dots
211 # Qt console prompts expand with spaces, not dots
213 (' ...: print i',' print i'),
212 (' ...: print i',' print i'),
214 (' ...: ', ''),
213 (' ...: ', ''),
215 ],
214 ],
216 [('In [24]: for i in range(10):','for i in range(10):'),
215 [('In [24]: for i in range(10):','for i in range(10):'),
217 # Sometimes whitespace preceding '...' has been removed
216 # Sometimes whitespace preceding '...' has been removed
218 ('...: print i',' print i'),
217 ('...: print i',' print i'),
219 ('...: ', ''),
218 ('...: ', ''),
220 ],
219 ],
221 [('In [24]: for i in range(10):','for i in range(10):'),
220 [('In [24]: for i in range(10):','for i in range(10):'),
222 # Space after last continuation prompt has been removed (issue #6674)
221 # Space after last continuation prompt has been removed (issue #6674)
223 ('...: print i',' print i'),
222 ('...: print i',' print i'),
224 ('...:', ''),
223 ('...:', ''),
225 ],
224 ],
226 [('In [2]: a="""','a="""'),
225 [('In [2]: a="""','a="""'),
227 (' ...: 123"""','123"""'),
226 (' ...: 123"""','123"""'),
228 ],
227 ],
229 [('a="""','a="""'),
228 [('a="""','a="""'),
230 (' ...: 123','123'),
229 (' ...: 123','123'),
231 (' ...: 456"""','456"""'),
230 (' ...: 456"""','456"""'),
232 ],
231 ],
233 [('a="""','a="""'),
232 [('a="""','a="""'),
234 ('In [1]: 123','123'),
233 ('In [1]: 123','123'),
235 (' ...: 456"""','456"""'),
234 (' ...: 456"""','456"""'),
236 ],
235 ],
237 [('a="""','a="""'),
236 [('a="""','a="""'),
238 ('123','123'),
237 ('123','123'),
239 (' ...: 456"""',' ...: 456"""'),
238 (' ...: 456"""',' ...: 456"""'),
240 ],
239 ],
241 ],
240 ],
242
241
243 multiline_datastructure_prompt =
242 multiline_datastructure_prompt =
244 [ [('>>> a = [1,','a = [1,'),
243 [ [('>>> a = [1,','a = [1,'),
245 ('... 2]','2]'),
244 ('... 2]','2]'),
246 ],
245 ],
247 ],
246 ],
248
247
249 multiline_datastructure =
248 multiline_datastructure =
250 [ [('b = ("%s"', None),
249 [ [('b = ("%s"', None),
251 ('# comment', None),
250 ('# comment', None),
252 ('%foo )', 'b = ("%s"\n# comment\n%foo )'),
251 ('%foo )', 'b = ("%s"\n# comment\n%foo )'),
253 ],
252 ],
254 ],
253 ],
255
254
256 multiline_string =
255 multiline_string =
257 [ [("'''foo?", None),
256 [ [("'''foo?", None),
258 ("bar'''", "'''foo?\nbar'''"),
257 ("bar'''", "'''foo?\nbar'''"),
259 ],
258 ],
260 ],
259 ],
261
260
262 leading_indent =
261 leading_indent =
263 [ [(' print "hi"','print "hi"'),
262 [ [(' print "hi"','print "hi"'),
264 ],
263 ],
265 [(' for a in range(5):','for a in range(5):'),
264 [(' for a in range(5):','for a in range(5):'),
266 (' a*2',' a*2'),
265 (' a*2',' a*2'),
267 ],
266 ],
268 [(' a="""','a="""'),
267 [(' a="""','a="""'),
269 (' 123"""','123"""'),
268 (' 123"""','123"""'),
270 ],
269 ],
271 [('a="""','a="""'),
270 [('a="""','a="""'),
272 (' 123"""',' 123"""'),
271 (' 123"""',' 123"""'),
273 ],
272 ],
274 ],
273 ],
275
274
276 cellmagic =
275 cellmagic =
277 [ [('%%foo a', None),
276 [ [('%%foo a', None),
278 (None, "get_ipython().run_cell_magic('foo', 'a', '')"),
277 (None, "get_ipython().run_cell_magic('foo', 'a', '')"),
279 ],
278 ],
280 [('%%bar 123', None),
279 [('%%bar 123', None),
281 ('hello', None),
280 ('hello', None),
282 (None , "get_ipython().run_cell_magic('bar', '123', 'hello')"),
281 (None , "get_ipython().run_cell_magic('bar', '123', 'hello')"),
283 ],
282 ],
284 [('a=5', 'a=5'),
283 [('a=5', 'a=5'),
285 ('%%cellmagic', '%%cellmagic'),
284 ('%%cellmagic', '%%cellmagic'),
286 ],
285 ],
287 ],
286 ],
288
287
289 escaped =
288 escaped =
290 [ [('%abc def \\', None),
289 [ [('%abc def \\', None),
291 ('ghi', "get_ipython().run_line_magic('abc', 'def ghi')"),
290 ('ghi', "get_ipython().run_line_magic('abc', 'def ghi')"),
292 ],
291 ],
293 [('%abc def \\', None),
292 [('%abc def \\', None),
294 ('ghi\\', None),
293 ('ghi\\', None),
295 (None, "get_ipython().run_line_magic('abc', 'def ghi')"),
294 (None, "get_ipython().run_line_magic('abc', 'def ghi')"),
296 ],
295 ],
297 ],
296 ],
298
297
299 assign_magic =
298 assign_magic =
300 [ [('a = %bc de \\', None),
299 [ [('a = %bc de \\', None),
301 ('fg', "a = get_ipython().run_line_magic('bc', 'de fg')"),
300 ('fg', "a = get_ipython().run_line_magic('bc', 'de fg')"),
302 ],
301 ],
303 [('a = %bc de \\', None),
302 [('a = %bc de \\', None),
304 ('fg\\', None),
303 ('fg\\', None),
305 (None, "a = get_ipython().run_line_magic('bc', 'de fg')"),
304 (None, "a = get_ipython().run_line_magic('bc', 'de fg')"),
306 ],
305 ],
307 ],
306 ],
308
307
309 assign_system =
308 assign_system =
310 [ [('a = !bc de \\', None),
309 [ [('a = !bc de \\', None),
311 ('fg', "a = get_ipython().getoutput('bc de fg')"),
310 ('fg', "a = get_ipython().getoutput('bc de fg')"),
312 ],
311 ],
313 [('a = !bc de \\', None),
312 [('a = !bc de \\', None),
314 ('fg\\', None),
313 ('fg\\', None),
315 (None, "a = get_ipython().getoutput('bc de fg')"),
314 (None, "a = get_ipython().getoutput('bc de fg')"),
316 ],
315 ],
317 ],
316 ],
318 )
317 )
319
318
320
319
321 def test_assign_system():
320 def test_assign_system():
322 tt.check_pairs(transform_and_reset(ipt.assign_from_system), syntax['assign_system'])
321 tt.check_pairs(transform_and_reset(ipt.assign_from_system), syntax['assign_system'])
323
322
324 def test_assign_magic():
323 def test_assign_magic():
325 tt.check_pairs(transform_and_reset(ipt.assign_from_magic), syntax['assign_magic'])
324 tt.check_pairs(transform_and_reset(ipt.assign_from_magic), syntax['assign_magic'])
326
325
327 def test_classic_prompt():
326 def test_classic_prompt():
328 tt.check_pairs(transform_and_reset(ipt.classic_prompt), syntax['classic_prompt'])
327 tt.check_pairs(transform_and_reset(ipt.classic_prompt), syntax['classic_prompt'])
329 for example in syntax_ml['classic_prompt']:
328 for example in syntax_ml['classic_prompt']:
330 transform_checker(example, ipt.classic_prompt)
329 transform_checker(example, ipt.classic_prompt)
331 for example in syntax_ml['multiline_datastructure_prompt']:
330 for example in syntax_ml['multiline_datastructure_prompt']:
332 transform_checker(example, ipt.classic_prompt)
331 transform_checker(example, ipt.classic_prompt)
333
332
334 # Check that we don't transform the second line if the first is obviously
333 # Check that we don't transform the second line if the first is obviously
335 # IPython syntax
334 # IPython syntax
336 transform_checker([
335 transform_checker([
337 ('%foo', '%foo'),
336 ('%foo', '%foo'),
338 ('>>> bar', '>>> bar'),
337 ('>>> bar', '>>> bar'),
339 ], ipt.classic_prompt)
338 ], ipt.classic_prompt)
340
339
341
340
342 def test_ipy_prompt():
341 def test_ipy_prompt():
343 tt.check_pairs(transform_and_reset(ipt.ipy_prompt), syntax['ipy_prompt'])
342 tt.check_pairs(transform_and_reset(ipt.ipy_prompt), syntax['ipy_prompt'])
344 for example in syntax_ml['ipy_prompt']:
343 for example in syntax_ml['ipy_prompt']:
345 transform_checker(example, ipt.ipy_prompt)
344 transform_checker(example, ipt.ipy_prompt)
346
345
347 # Check that we don't transform the second line if we're inside a cell magic
346 # Check that we don't transform the second line if we're inside a cell magic
348 transform_checker([
347 transform_checker([
349 ('%%foo', '%%foo'),
348 ('%%foo', '%%foo'),
350 ('In [1]: bar', 'In [1]: bar'),
349 ('In [1]: bar', 'In [1]: bar'),
351 ], ipt.ipy_prompt)
350 ], ipt.ipy_prompt)
352
351
353 def test_assemble_logical_lines():
352 def test_assemble_logical_lines():
354 tests = \
353 tests = \
355 [ [("a = \\", None),
354 [ [("a = \\", None),
356 ("123", "a = 123"),
355 ("123", "a = 123"),
357 ],
356 ],
358 [("a = \\", None), # Test resetting when within a multi-line string
357 [("a = \\", None), # Test resetting when within a multi-line string
359 ("12 *\\", None),
358 ("12 *\\", None),
360 (None, "a = 12 *"),
359 (None, "a = 12 *"),
361 ],
360 ],
362 [("# foo\\", "# foo\\"), # Comments can't be continued like this
361 [("# foo\\", "# foo\\"), # Comments can't be continued like this
363 ],
362 ],
364 ]
363 ]
365 for example in tests:
364 for example in tests:
366 transform_checker(example, ipt.assemble_logical_lines)
365 transform_checker(example, ipt.assemble_logical_lines)
367
366
368 def test_assemble_python_lines():
367 def test_assemble_python_lines():
369 tests = \
368 tests = \
370 [ [("a = '''", None),
369 [ [("a = '''", None),
371 ("abc'''", "a = '''\nabc'''"),
370 ("abc'''", "a = '''\nabc'''"),
372 ],
371 ],
373 [("a = '''", None), # Test resetting when within a multi-line string
372 [("a = '''", None), # Test resetting when within a multi-line string
374 ("def", None),
373 ("def", None),
375 (None, "a = '''\ndef"),
374 (None, "a = '''\ndef"),
376 ],
375 ],
377 [("a = [1,", None),
376 [("a = [1,", None),
378 ("2]", "a = [1,\n2]"),
377 ("2]", "a = [1,\n2]"),
379 ],
378 ],
380 [("a = [1,", None), # Test resetting when within a multi-line string
379 [("a = [1,", None), # Test resetting when within a multi-line string
381 ("2,", None),
380 ("2,", None),
382 (None, "a = [1,\n2,"),
381 (None, "a = [1,\n2,"),
383 ],
382 ],
384 [("a = '''", None), # Test line continuation within a multi-line string
383 [("a = '''", None), # Test line continuation within a multi-line string
385 ("abc\\", None),
384 ("abc\\", None),
386 ("def", None),
385 ("def", None),
387 ("'''", "a = '''\nabc\\\ndef\n'''"),
386 ("'''", "a = '''\nabc\\\ndef\n'''"),
388 ],
387 ],
389 ] + syntax_ml['multiline_datastructure']
388 ] + syntax_ml['multiline_datastructure']
390 for example in tests:
389 for example in tests:
391 transform_checker(example, ipt.assemble_python_lines)
390 transform_checker(example, ipt.assemble_python_lines)
392
391
393
392
394 def test_help_end():
393 def test_help_end():
395 tt.check_pairs(transform_and_reset(ipt.help_end), syntax['end_help'])
394 tt.check_pairs(transform_and_reset(ipt.help_end), syntax['end_help'])
396
395
397 def test_escaped_noesc():
396 def test_escaped_noesc():
398 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_noesc'])
397 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_noesc'])
399
398
400
399
401 def test_escaped_shell():
400 def test_escaped_shell():
402 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_shell'])
401 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_shell'])
403
402
404
403
405 def test_escaped_help():
404 def test_escaped_help():
406 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_help'])
405 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_help'])
407
406
408
407
409 def test_escaped_magic():
408 def test_escaped_magic():
410 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_magic'])
409 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_magic'])
411
410
412
411
413 def test_escaped_quote():
412 def test_escaped_quote():
414 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_quote'])
413 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_quote'])
415
414
416
415
417 def test_escaped_quote2():
416 def test_escaped_quote2():
418 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_quote2'])
417 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_quote2'])
419
418
420
419
421 def test_escaped_paren():
420 def test_escaped_paren():
422 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_paren'])
421 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_paren'])
423
422
424
423
425 def test_cellmagic():
424 def test_cellmagic():
426 for example in syntax_ml['cellmagic']:
425 for example in syntax_ml['cellmagic']:
427 transform_checker(example, ipt.cellmagic)
426 transform_checker(example, ipt.cellmagic)
428
427
429 line_example = [('%%bar 123', None),
428 line_example = [('%%bar 123', None),
430 ('hello', None),
429 ('hello', None),
431 ('' , "get_ipython().run_cell_magic('bar', '123', 'hello')"),
430 ('' , "get_ipython().run_cell_magic('bar', '123', 'hello')"),
432 ]
431 ]
433 transform_checker(line_example, ipt.cellmagic, end_on_blank_line=True)
432 transform_checker(line_example, ipt.cellmagic, end_on_blank_line=True)
434
433
435 def test_has_comment():
434 def test_has_comment():
436 tests = [('text', False),
435 tests = [('text', False),
437 ('text #comment', True),
436 ('text #comment', True),
438 ('text #comment\n', True),
437 ('text #comment\n', True),
439 ('#comment', True),
438 ('#comment', True),
440 ('#comment\n', True),
439 ('#comment\n', True),
441 ('a = "#string"', False),
440 ('a = "#string"', False),
442 ('a = "#string" # comment', True),
441 ('a = "#string" # comment', True),
443 ('a #comment not "string"', True),
442 ('a #comment not "string"', True),
444 ]
443 ]
445 tt.check_pairs(ipt.has_comment, tests)
444 tt.check_pairs(ipt.has_comment, tests)
446
445
447 @ipt.TokenInputTransformer.wrap
446 @ipt.TokenInputTransformer.wrap
448 def decistmt(tokens):
447 def decistmt(tokens):
449 """Substitute Decimals for floats in a string of statements.
448 """Substitute Decimals for floats in a string of statements.
450
449
451 Based on an example from the tokenize module docs.
450 Based on an example from the tokenize module docs.
452 """
451 """
453 result = []
452 result = []
454 for toknum, tokval, _, _, _ in tokens:
453 for toknum, tokval, _, _, _ in tokens:
455 if toknum == tokenize.NUMBER and '.' in tokval: # replace NUMBER tokens
454 if toknum == tokenize.NUMBER and '.' in tokval: # replace NUMBER tokens
456 yield from [
455 yield from [
457 (tokenize.NAME, 'Decimal'),
456 (tokenize.NAME, 'Decimal'),
458 (tokenize.OP, '('),
457 (tokenize.OP, '('),
459 (tokenize.STRING, repr(tokval)),
458 (tokenize.STRING, repr(tokval)),
460 (tokenize.OP, ')')
459 (tokenize.OP, ')')
461 ]
460 ]
462 else:
461 else:
463 yield (toknum, tokval)
462 yield (toknum, tokval)
464
463
465
464
466
465
467 def test_token_input_transformer():
466 def test_token_input_transformer():
468 tests = [('1.2', "Decimal ('1.2')"),
467 tests = [('1.2', "Decimal ('1.2')"),
469 ('"1.2"', '"1.2"'),
468 ('"1.2"', '"1.2"'),
470 ]
469 ]
471 tt.check_pairs(transform_and_reset(decistmt), tests)
470 tt.check_pairs(transform_and_reset(decistmt), tests)
472 ml_tests = \
471 ml_tests = \
473 [ [("a = 1.2; b = '''x", None),
472 [ [("a = 1.2; b = '''x", None),
474 ("y'''", "a =Decimal ('1.2');b ='''x\ny'''"),
473 ("y'''", "a =Decimal ('1.2');b ='''x\ny'''"),
475 ],
474 ],
476 [("a = [1.2,", None),
475 [("a = [1.2,", None),
477 ("3]", "a =[Decimal ('1.2'),\n3 ]"),
476 ("3]", "a =[Decimal ('1.2'),\n3 ]"),
478 ],
477 ],
479 [("a = '''foo", None), # Test resetting when within a multi-line string
478 [("a = '''foo", None), # Test resetting when within a multi-line string
480 ("bar", None),
479 ("bar", None),
481 (None, "a = '''foo\nbar"),
480 (None, "a = '''foo\nbar"),
482 ],
481 ],
483 ]
482 ]
484 for example in ml_tests:
483 for example in ml_tests:
485 transform_checker(example, decistmt)
484 transform_checker(example, decistmt)
@@ -1,355 +1,359 b''
1 """Tests for the token-based transformers in IPython.core.inputtransformer2
1 """Tests for the token-based transformers in IPython.core.inputtransformer2
2
2
3 Line-based transformers are the simpler ones; token-based transformers are
3 Line-based transformers are the simpler ones; token-based transformers are
4 more complex. See test_inputtransformer2_line for tests for line-based
4 more complex. See test_inputtransformer2_line for tests for line-based
5 transformations.
5 transformations.
6 """
6 """
7 import nose.tools as nt
8 import string
7 import string
9
8
10 from IPython.core import inputtransformer2 as ipt2
9 from IPython.core import inputtransformer2 as ipt2
11 from IPython.core.inputtransformer2 import make_tokens_by_line, _find_assign_op
10 from IPython.core.inputtransformer2 import make_tokens_by_line, _find_assign_op
12
11
13 from textwrap import dedent
12 from textwrap import dedent
14
13
15 MULTILINE_MAGIC = ("""\
14 MULTILINE_MAGIC = ("""\
16 a = f()
15 a = f()
17 %foo \\
16 %foo \\
18 bar
17 bar
19 g()
18 g()
20 """.splitlines(keepends=True), (2, 0), """\
19 """.splitlines(keepends=True), (2, 0), """\
21 a = f()
20 a = f()
22 get_ipython().run_line_magic('foo', ' bar')
21 get_ipython().run_line_magic('foo', ' bar')
23 g()
22 g()
24 """.splitlines(keepends=True))
23 """.splitlines(keepends=True))
25
24
26 INDENTED_MAGIC = ("""\
25 INDENTED_MAGIC = ("""\
27 for a in range(5):
26 for a in range(5):
28 %ls
27 %ls
29 """.splitlines(keepends=True), (2, 4), """\
28 """.splitlines(keepends=True), (2, 4), """\
30 for a in range(5):
29 for a in range(5):
31 get_ipython().run_line_magic('ls', '')
30 get_ipython().run_line_magic('ls', '')
32 """.splitlines(keepends=True))
31 """.splitlines(keepends=True))
33
32
34 CRLF_MAGIC = ([
33 CRLF_MAGIC = ([
35 "a = f()\n",
34 "a = f()\n",
36 "%ls\r\n",
35 "%ls\r\n",
37 "g()\n"
36 "g()\n"
38 ], (2, 0), [
37 ], (2, 0), [
39 "a = f()\n",
38 "a = f()\n",
40 "get_ipython().run_line_magic('ls', '')\n",
39 "get_ipython().run_line_magic('ls', '')\n",
41 "g()\n"
40 "g()\n"
42 ])
41 ])
43
42
44 MULTILINE_MAGIC_ASSIGN = ("""\
43 MULTILINE_MAGIC_ASSIGN = ("""\
45 a = f()
44 a = f()
46 b = %foo \\
45 b = %foo \\
47 bar
46 bar
48 g()
47 g()
49 """.splitlines(keepends=True), (2, 4), """\
48 """.splitlines(keepends=True), (2, 4), """\
50 a = f()
49 a = f()
51 b = get_ipython().run_line_magic('foo', ' bar')
50 b = get_ipython().run_line_magic('foo', ' bar')
52 g()
51 g()
53 """.splitlines(keepends=True))
52 """.splitlines(keepends=True))
54
53
55 MULTILINE_SYSTEM_ASSIGN = ("""\
54 MULTILINE_SYSTEM_ASSIGN = ("""\
56 a = f()
55 a = f()
57 b = !foo \\
56 b = !foo \\
58 bar
57 bar
59 g()
58 g()
60 """.splitlines(keepends=True), (2, 4), """\
59 """.splitlines(keepends=True), (2, 4), """\
61 a = f()
60 a = f()
62 b = get_ipython().getoutput('foo bar')
61 b = get_ipython().getoutput('foo bar')
63 g()
62 g()
64 """.splitlines(keepends=True))
63 """.splitlines(keepends=True))
65
64
66 #####
65 #####
67
66
68 MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT = ("""\
67 MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT = ("""\
69 def test():
68 def test():
70 for i in range(1):
69 for i in range(1):
71 print(i)
70 print(i)
72 res =! ls
71 res =! ls
73 """.splitlines(keepends=True), (4, 7), '''\
72 """.splitlines(keepends=True), (4, 7), '''\
74 def test():
73 def test():
75 for i in range(1):
74 for i in range(1):
76 print(i)
75 print(i)
77 res =get_ipython().getoutput(\' ls\')
76 res =get_ipython().getoutput(\' ls\')
78 '''.splitlines(keepends=True))
77 '''.splitlines(keepends=True))
79
78
80 ######
79 ######
81
80
82 AUTOCALL_QUOTE = (
81 AUTOCALL_QUOTE = (
83 [",f 1 2 3\n"], (1, 0),
82 [",f 1 2 3\n"], (1, 0),
84 ['f("1", "2", "3")\n']
83 ['f("1", "2", "3")\n']
85 )
84 )
86
85
87 AUTOCALL_QUOTE2 = (
86 AUTOCALL_QUOTE2 = (
88 [";f 1 2 3\n"], (1, 0),
87 [";f 1 2 3\n"], (1, 0),
89 ['f("1 2 3")\n']
88 ['f("1 2 3")\n']
90 )
89 )
91
90
92 AUTOCALL_PAREN = (
91 AUTOCALL_PAREN = (
93 ["/f 1 2 3\n"], (1, 0),
92 ["/f 1 2 3\n"], (1, 0),
94 ['f(1, 2, 3)\n']
93 ['f(1, 2, 3)\n']
95 )
94 )
96
95
97 SIMPLE_HELP = (
96 SIMPLE_HELP = (
98 ["foo?\n"], (1, 0),
97 ["foo?\n"], (1, 0),
99 ["get_ipython().run_line_magic('pinfo', 'foo')\n"]
98 ["get_ipython().run_line_magic('pinfo', 'foo')\n"]
100 )
99 )
101
100
102 DETAILED_HELP = (
101 DETAILED_HELP = (
103 ["foo??\n"], (1, 0),
102 ["foo??\n"], (1, 0),
104 ["get_ipython().run_line_magic('pinfo2', 'foo')\n"]
103 ["get_ipython().run_line_magic('pinfo2', 'foo')\n"]
105 )
104 )
106
105
107 MAGIC_HELP = (
106 MAGIC_HELP = (
108 ["%foo?\n"], (1, 0),
107 ["%foo?\n"], (1, 0),
109 ["get_ipython().run_line_magic('pinfo', '%foo')\n"]
108 ["get_ipython().run_line_magic('pinfo', '%foo')\n"]
110 )
109 )
111
110
112 HELP_IN_EXPR = (
111 HELP_IN_EXPR = (
113 ["a = b + c?\n"], (1, 0),
112 ["a = b + c?\n"], (1, 0),
114 ["get_ipython().set_next_input('a = b + c');"
113 ["get_ipython().set_next_input('a = b + c');"
115 "get_ipython().run_line_magic('pinfo', 'c')\n"]
114 "get_ipython().run_line_magic('pinfo', 'c')\n"]
116 )
115 )
117
116
118 HELP_CONTINUED_LINE = ("""\
117 HELP_CONTINUED_LINE = ("""\
119 a = \\
118 a = \\
120 zip?
119 zip?
121 """.splitlines(keepends=True), (1, 0),
120 """.splitlines(keepends=True), (1, 0),
122 [r"get_ipython().set_next_input('a = \\\nzip');get_ipython().run_line_magic('pinfo', 'zip')" + "\n"]
121 [r"get_ipython().set_next_input('a = \\\nzip');get_ipython().run_line_magic('pinfo', 'zip')" + "\n"]
123 )
122 )
124
123
125 HELP_MULTILINE = ("""\
124 HELP_MULTILINE = ("""\
126 (a,
125 (a,
127 b) = zip?
126 b) = zip?
128 """.splitlines(keepends=True), (1, 0),
127 """.splitlines(keepends=True), (1, 0),
129 [r"get_ipython().set_next_input('(a,\nb) = zip');get_ipython().run_line_magic('pinfo', 'zip')" + "\n"]
128 [r"get_ipython().set_next_input('(a,\nb) = zip');get_ipython().run_line_magic('pinfo', 'zip')" + "\n"]
130 )
129 )
131
130
132 HELP_UNICODE = (
131 HELP_UNICODE = (
133 ["π.foo?\n"], (1, 0),
132 ["π.foo?\n"], (1, 0),
134 ["get_ipython().run_line_magic('pinfo', 'π.foo')\n"]
133 ["get_ipython().run_line_magic('pinfo', 'π.foo')\n"]
135 )
134 )
136
135
137
136
138 def null_cleanup_transformer(lines):
137 def null_cleanup_transformer(lines):
139 """
138 """
140 A cleanup transform that returns an empty list.
139 A cleanup transform that returns an empty list.
141 """
140 """
142 return []
141 return []
143
142
144 def check_make_token_by_line_never_ends_empty():
143 def check_make_token_by_line_never_ends_empty():
145 """
144 """
146 Check that not sequence of single or double characters ends up leading to en empty list of tokens
145 Check that not sequence of single or double characters ends up leading to en empty list of tokens
147 """
146 """
148 from string import printable
147 from string import printable
149 for c in printable:
148 for c in printable:
150 nt.assert_not_equal(make_tokens_by_line(c)[-1], [])
149 assert make_tokens_by_line(c)[-1] != []
151 for k in printable:
150 for k in printable:
152 nt.assert_not_equal(make_tokens_by_line(c+k)[-1], [])
151 assert make_tokens_by_line(c + k)[-1] != []
152
153
153
154 def check_find(transformer, case, match=True):
154 def check_find(transformer, case, match=True):
155 sample, expected_start, _ = case
155 sample, expected_start, _ = case
156 tbl = make_tokens_by_line(sample)
156 tbl = make_tokens_by_line(sample)
157 res = transformer.find(tbl)
157 res = transformer.find(tbl)
158 if match:
158 if match:
159 # start_line is stored 0-indexed, expected values are 1-indexed
159 # start_line is stored 0-indexed, expected values are 1-indexed
160 nt.assert_equal((res.start_line+1, res.start_col), expected_start)
160 assert (res.start_line + 1, res.start_col) == expected_start
161 return res
161 return res
162 else:
162 else:
163 nt.assert_is(res, None)
163 assert res is None
164
164
165 def check_transform(transformer_cls, case):
165 def check_transform(transformer_cls, case):
166 lines, start, expected = case
166 lines, start, expected = case
167 transformer = transformer_cls(start)
167 transformer = transformer_cls(start)
168 nt.assert_equal(transformer.transform(lines), expected)
168 assert transformer.transform(lines) == expected
169
169
170 def test_continued_line():
170 def test_continued_line():
171 lines = MULTILINE_MAGIC_ASSIGN[0]
171 lines = MULTILINE_MAGIC_ASSIGN[0]
172 nt.assert_equal(ipt2.find_end_of_continued_line(lines, 1), 2)
172 assert ipt2.find_end_of_continued_line(lines, 1) == 2
173
173
174 nt.assert_equal(ipt2.assemble_continued_line(lines, (1, 5), 2), "foo bar")
174 assert ipt2.assemble_continued_line(lines, (1, 5), 2) == "foo bar"
175
175
176 def test_find_assign_magic():
176 def test_find_assign_magic():
177 check_find(ipt2.MagicAssign, MULTILINE_MAGIC_ASSIGN)
177 check_find(ipt2.MagicAssign, MULTILINE_MAGIC_ASSIGN)
178 check_find(ipt2.MagicAssign, MULTILINE_SYSTEM_ASSIGN, match=False)
178 check_find(ipt2.MagicAssign, MULTILINE_SYSTEM_ASSIGN, match=False)
179 check_find(ipt2.MagicAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT, match=False)
179 check_find(ipt2.MagicAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT, match=False)
180
180
181 def test_transform_assign_magic():
181 def test_transform_assign_magic():
182 check_transform(ipt2.MagicAssign, MULTILINE_MAGIC_ASSIGN)
182 check_transform(ipt2.MagicAssign, MULTILINE_MAGIC_ASSIGN)
183
183
184 def test_find_assign_system():
184 def test_find_assign_system():
185 check_find(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN)
185 check_find(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN)
186 check_find(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT)
186 check_find(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT)
187 check_find(ipt2.SystemAssign, (["a = !ls\n"], (1, 5), None))
187 check_find(ipt2.SystemAssign, (["a = !ls\n"], (1, 5), None))
188 check_find(ipt2.SystemAssign, (["a=!ls\n"], (1, 2), None))
188 check_find(ipt2.SystemAssign, (["a=!ls\n"], (1, 2), None))
189 check_find(ipt2.SystemAssign, MULTILINE_MAGIC_ASSIGN, match=False)
189 check_find(ipt2.SystemAssign, MULTILINE_MAGIC_ASSIGN, match=False)
190
190
191 def test_transform_assign_system():
191 def test_transform_assign_system():
192 check_transform(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN)
192 check_transform(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN)
193 check_transform(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT)
193 check_transform(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT)
194
194
195 def test_find_magic_escape():
195 def test_find_magic_escape():
196 check_find(ipt2.EscapedCommand, MULTILINE_MAGIC)
196 check_find(ipt2.EscapedCommand, MULTILINE_MAGIC)
197 check_find(ipt2.EscapedCommand, INDENTED_MAGIC)
197 check_find(ipt2.EscapedCommand, INDENTED_MAGIC)
198 check_find(ipt2.EscapedCommand, MULTILINE_MAGIC_ASSIGN, match=False)
198 check_find(ipt2.EscapedCommand, MULTILINE_MAGIC_ASSIGN, match=False)
199
199
200 def test_transform_magic_escape():
200 def test_transform_magic_escape():
201 check_transform(ipt2.EscapedCommand, MULTILINE_MAGIC)
201 check_transform(ipt2.EscapedCommand, MULTILINE_MAGIC)
202 check_transform(ipt2.EscapedCommand, INDENTED_MAGIC)
202 check_transform(ipt2.EscapedCommand, INDENTED_MAGIC)
203 check_transform(ipt2.EscapedCommand, CRLF_MAGIC)
203 check_transform(ipt2.EscapedCommand, CRLF_MAGIC)
204
204
205 def test_find_autocalls():
205 def test_find_autocalls():
206 for case in [AUTOCALL_QUOTE, AUTOCALL_QUOTE2, AUTOCALL_PAREN]:
206 for case in [AUTOCALL_QUOTE, AUTOCALL_QUOTE2, AUTOCALL_PAREN]:
207 print("Testing %r" % case[0])
207 print("Testing %r" % case[0])
208 check_find(ipt2.EscapedCommand, case)
208 check_find(ipt2.EscapedCommand, case)
209
209
210 def test_transform_autocall():
210 def test_transform_autocall():
211 for case in [AUTOCALL_QUOTE, AUTOCALL_QUOTE2, AUTOCALL_PAREN]:
211 for case in [AUTOCALL_QUOTE, AUTOCALL_QUOTE2, AUTOCALL_PAREN]:
212 print("Testing %r" % case[0])
212 print("Testing %r" % case[0])
213 check_transform(ipt2.EscapedCommand, case)
213 check_transform(ipt2.EscapedCommand, case)
214
214
215 def test_find_help():
215 def test_find_help():
216 for case in [SIMPLE_HELP, DETAILED_HELP, MAGIC_HELP, HELP_IN_EXPR]:
216 for case in [SIMPLE_HELP, DETAILED_HELP, MAGIC_HELP, HELP_IN_EXPR]:
217 check_find(ipt2.HelpEnd, case)
217 check_find(ipt2.HelpEnd, case)
218
218
219 tf = check_find(ipt2.HelpEnd, HELP_CONTINUED_LINE)
219 tf = check_find(ipt2.HelpEnd, HELP_CONTINUED_LINE)
220 nt.assert_equal(tf.q_line, 1)
220 assert tf.q_line == 1
221 nt.assert_equal(tf.q_col, 3)
221 assert tf.q_col == 3
222
222
223 tf = check_find(ipt2.HelpEnd, HELP_MULTILINE)
223 tf = check_find(ipt2.HelpEnd, HELP_MULTILINE)
224 nt.assert_equal(tf.q_line, 1)
224 assert tf.q_line == 1
225 nt.assert_equal(tf.q_col, 8)
225 assert tf.q_col == 8
226
226
227 # ? in a comment does not trigger help
227 # ? in a comment does not trigger help
228 check_find(ipt2.HelpEnd, (["foo # bar?\n"], None, None), match=False)
228 check_find(ipt2.HelpEnd, (["foo # bar?\n"], None, None), match=False)
229 # Nor in a string
229 # Nor in a string
230 check_find(ipt2.HelpEnd, (["foo = '''bar?\n"], None, None), match=False)
230 check_find(ipt2.HelpEnd, (["foo = '''bar?\n"], None, None), match=False)
231
231
232 def test_transform_help():
232 def test_transform_help():
233 tf = ipt2.HelpEnd((1, 0), (1, 9))
233 tf = ipt2.HelpEnd((1, 0), (1, 9))
234 nt.assert_equal(tf.transform(HELP_IN_EXPR[0]), HELP_IN_EXPR[2])
234 assert tf.transform(HELP_IN_EXPR[0]) == HELP_IN_EXPR[2]
235
235
236 tf = ipt2.HelpEnd((1, 0), (2, 3))
236 tf = ipt2.HelpEnd((1, 0), (2, 3))
237 nt.assert_equal(tf.transform(HELP_CONTINUED_LINE[0]), HELP_CONTINUED_LINE[2])
237 assert tf.transform(HELP_CONTINUED_LINE[0]) == HELP_CONTINUED_LINE[2]
238
238
239 tf = ipt2.HelpEnd((1, 0), (2, 8))
239 tf = ipt2.HelpEnd((1, 0), (2, 8))
240 nt.assert_equal(tf.transform(HELP_MULTILINE[0]), HELP_MULTILINE[2])
240 assert tf.transform(HELP_MULTILINE[0]) == HELP_MULTILINE[2]
241
241
242 tf = ipt2.HelpEnd((1, 0), (1, 0))
242 tf = ipt2.HelpEnd((1, 0), (1, 0))
243 nt.assert_equal(tf.transform(HELP_UNICODE[0]), HELP_UNICODE[2])
243 assert tf.transform(HELP_UNICODE[0]) == HELP_UNICODE[2]
244
244
245 def test_find_assign_op_dedent():
245 def test_find_assign_op_dedent():
246 """
246 """
247 be careful that empty token like dedent are not counted as parens
247 be careful that empty token like dedent are not counted as parens
248 """
248 """
249 class Tk:
249 class Tk:
250 def __init__(self, s):
250 def __init__(self, s):
251 self.string = s
251 self.string = s
252
252
253 nt.assert_equal(_find_assign_op([Tk(s) for s in ('','a','=','b')]), 2)
253 assert _find_assign_op([Tk(s) for s in ("", "a", "=", "b")]) == 2
254 nt.assert_equal(_find_assign_op([Tk(s) for s in ('','(', 'a','=','b', ')', '=' ,'5')]), 6)
254 assert (
255 _find_assign_op([Tk(s) for s in ("", "(", "a", "=", "b", ")", "=", "5")]) == 6
256 )
257
255
258
256 def test_check_complete():
259 def test_check_complete():
257 cc = ipt2.TransformerManager().check_complete
260 cc = ipt2.TransformerManager().check_complete
258 nt.assert_equal(cc("a = 1"), ("complete", None))
261 assert cc("a = 1") == ("complete", None)
259 nt.assert_equal(cc("for a in range(5):"), ("incomplete", 4))
262 assert cc("for a in range(5):") == ("incomplete", 4)
260 nt.assert_equal(cc("for a in range(5):\n if a > 0:"), ("incomplete", 8))
263 assert cc("for a in range(5):\n if a > 0:") == ("incomplete", 8)
261 nt.assert_equal(cc("raise = 2"), ("invalid", None))
264 assert cc("raise = 2") == ("invalid", None)
262 nt.assert_equal(cc("a = [1,\n2,"), ("incomplete", 0))
265 assert cc("a = [1,\n2,") == ("incomplete", 0)
263 nt.assert_equal(cc("(\n))"), ("incomplete", 0))
266 assert cc("(\n))") == ("incomplete", 0)
264 nt.assert_equal(cc("\\\r\n"), ("incomplete", 0))
267 assert cc("\\\r\n") == ("incomplete", 0)
265 nt.assert_equal(cc("a = '''\n hi"), ("incomplete", 3))
268 assert cc("a = '''\n hi") == ("incomplete", 3)
266 nt.assert_equal(cc("def a():\n x=1\n global x"), ("invalid", None))
269 assert cc("def a():\n x=1\n global x") == ("invalid", None)
267 nt.assert_equal(cc("a \\ "), ("invalid", None)) # Nothing allowed after backslash
270 assert cc("a \\ ") == ("invalid", None) # Nothing allowed after backslash
268 nt.assert_equal(cc("1\\\n+2"), ("complete", None))
271 assert cc("1\\\n+2") == ("complete", None)
269 nt.assert_equal(cc("exit"), ("complete", None))
272 assert cc("exit") == ("complete", None)
270
273
271 example = dedent("""
274 example = dedent("""
272 if True:
275 if True:
273 a=1""" )
276 a=1""" )
274
277
275 nt.assert_equal(cc(example), ('incomplete', 4))
278 assert cc(example) == ("incomplete", 4)
276 nt.assert_equal(cc(example+'\n'), ('complete', None))
279 assert cc(example + "\n") == ("complete", None)
277 nt.assert_equal(cc(example+'\n '), ('complete', None))
280 assert cc(example + "\n ") == ("complete", None)
278
281
279 # no need to loop on all the letters/numbers.
282 # no need to loop on all the letters/numbers.
280 short = '12abAB'+string.printable[62:]
283 short = '12abAB'+string.printable[62:]
281 for c in short:
284 for c in short:
282 # test does not raise:
285 # test does not raise:
283 cc(c)
286 cc(c)
284 for k in short:
287 for k in short:
285 cc(c+k)
288 cc(c+k)
286
289
287 nt.assert_equal(cc("def f():\n x=0\n \\\n "), ('incomplete', 2))
290 assert cc("def f():\n x=0\n \\\n ") == ("incomplete", 2)
291
288
292
289 def test_check_complete_II():
293 def test_check_complete_II():
290 """
294 """
291 Test that multiple line strings are properly handled.
295 Test that multiple line strings are properly handled.
292
296
293 Separate test function for convenience
297 Separate test function for convenience
294
298
295 """
299 """
296 cc = ipt2.TransformerManager().check_complete
300 cc = ipt2.TransformerManager().check_complete
297 nt.assert_equal(cc('''def foo():\n """'''), ('incomplete', 4))
301 assert cc('''def foo():\n """''') == ("incomplete", 4)
298
302
299
303
300 def test_check_complete_invalidates_sunken_brackets():
304 def test_check_complete_invalidates_sunken_brackets():
301 """
305 """
302 Test that a single line with more closing brackets than the opening ones is
306 Test that a single line with more closing brackets than the opening ones is
303 interpreted as invalid
307 interpreted as invalid
304 """
308 """
305 cc = ipt2.TransformerManager().check_complete
309 cc = ipt2.TransformerManager().check_complete
306 nt.assert_equal(cc(")"), ("invalid", None))
310 assert cc(")") == ("invalid", None)
307 nt.assert_equal(cc("]"), ("invalid", None))
311 assert cc("]") == ("invalid", None)
308 nt.assert_equal(cc("}"), ("invalid", None))
312 assert cc("}") == ("invalid", None)
309 nt.assert_equal(cc(")("), ("invalid", None))
313 assert cc(")(") == ("invalid", None)
310 nt.assert_equal(cc("]["), ("invalid", None))
314 assert cc("][") == ("invalid", None)
311 nt.assert_equal(cc("}{"), ("invalid", None))
315 assert cc("}{") == ("invalid", None)
312 nt.assert_equal(cc("]()("), ("invalid", None))
316 assert cc("]()(") == ("invalid", None)
313 nt.assert_equal(cc("())("), ("invalid", None))
317 assert cc("())(") == ("invalid", None)
314 nt.assert_equal(cc(")[]("), ("invalid", None))
318 assert cc(")[](") == ("invalid", None)
315 nt.assert_equal(cc("()]("), ("invalid", None))
319 assert cc("()](") == ("invalid", None)
316
320
317
321
318 def test_null_cleanup_transformer():
322 def test_null_cleanup_transformer():
319 manager = ipt2.TransformerManager()
323 manager = ipt2.TransformerManager()
320 manager.cleanup_transforms.insert(0, null_cleanup_transformer)
324 manager.cleanup_transforms.insert(0, null_cleanup_transformer)
321 assert manager.transform_cell("") == ""
325 assert manager.transform_cell("") == ""
322
326
323
327
324
328
325
329
326 def test_side_effects_I():
330 def test_side_effects_I():
327 count = 0
331 count = 0
328 def counter(lines):
332 def counter(lines):
329 nonlocal count
333 nonlocal count
330 count += 1
334 count += 1
331 return lines
335 return lines
332
336
333 counter.has_side_effects = True
337 counter.has_side_effects = True
334
338
335 manager = ipt2.TransformerManager()
339 manager = ipt2.TransformerManager()
336 manager.cleanup_transforms.insert(0, counter)
340 manager.cleanup_transforms.insert(0, counter)
337 assert manager.check_complete("a=1\n") == ('complete', None)
341 assert manager.check_complete("a=1\n") == ('complete', None)
338 assert count == 0
342 assert count == 0
339
343
340
344
341
345
342
346
343 def test_side_effects_II():
347 def test_side_effects_II():
344 count = 0
348 count = 0
345 def counter(lines):
349 def counter(lines):
346 nonlocal count
350 nonlocal count
347 count += 1
351 count += 1
348 return lines
352 return lines
349
353
350 counter.has_side_effects = True
354 counter.has_side_effects = True
351
355
352 manager = ipt2.TransformerManager()
356 manager = ipt2.TransformerManager()
353 manager.line_transforms.insert(0, counter)
357 manager.line_transforms.insert(0, counter)
354 assert manager.check_complete("b=1\n") == ('complete', None)
358 assert manager.check_complete("b=1\n") == ('complete', None)
355 assert count == 0
359 assert count == 0
@@ -1,1068 +1,1072 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for the key interactiveshell module.
2 """Tests for the key interactiveshell module.
3
3
4 Historically the main classes in interactiveshell have been under-tested. This
4 Historically the main classes in interactiveshell have been under-tested. This
5 module should grow as many single-method tests as possible to trap many of the
5 module should grow as many single-method tests as possible to trap many of the
6 recurring bugs we seem to encounter with high-level interaction.
6 recurring bugs we seem to encounter with high-level interaction.
7 """
7 """
8
8
9 # Copyright (c) IPython Development Team.
9 # Copyright (c) IPython Development Team.
10 # Distributed under the terms of the Modified BSD License.
10 # Distributed under the terms of the Modified BSD License.
11
11
12 import asyncio
12 import asyncio
13 import ast
13 import ast
14 import os
14 import os
15 import signal
15 import signal
16 import shutil
16 import shutil
17 import sys
17 import sys
18 import tempfile
18 import tempfile
19 import unittest
19 import unittest
20 from unittest import mock
20 from unittest import mock
21
21
22 from os.path import join
22 from os.path import join
23
23
24 import nose.tools as nt
25
26 from IPython.core.error import InputRejected
24 from IPython.core.error import InputRejected
27 from IPython.core.inputtransformer import InputTransformer
25 from IPython.core.inputtransformer import InputTransformer
28 from IPython.core import interactiveshell
26 from IPython.core import interactiveshell
29 from IPython.testing.decorators import (
27 from IPython.testing.decorators import (
30 skipif, skip_win32, onlyif_unicode_paths, onlyif_cmds_exist,
28 skipif, skip_win32, onlyif_unicode_paths, onlyif_cmds_exist,
31 )
29 )
32 from IPython.testing import tools as tt
30 from IPython.testing import tools as tt
33 from IPython.utils.process import find_cmd
31 from IPython.utils.process import find_cmd
34
32
35 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
36 # Globals
34 # Globals
37 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
38 # This is used by every single test, no point repeating it ad nauseam
36 # This is used by every single test, no point repeating it ad nauseam
39
37
40 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
41 # Tests
39 # Tests
42 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
43
41
44 class DerivedInterrupt(KeyboardInterrupt):
42 class DerivedInterrupt(KeyboardInterrupt):
45 pass
43 pass
46
44
47 class InteractiveShellTestCase(unittest.TestCase):
45 class InteractiveShellTestCase(unittest.TestCase):
48 def test_naked_string_cells(self):
46 def test_naked_string_cells(self):
49 """Test that cells with only naked strings are fully executed"""
47 """Test that cells with only naked strings are fully executed"""
50 # First, single-line inputs
48 # First, single-line inputs
51 ip.run_cell('"a"\n')
49 ip.run_cell('"a"\n')
52 self.assertEqual(ip.user_ns['_'], 'a')
50 self.assertEqual(ip.user_ns['_'], 'a')
53 # And also multi-line cells
51 # And also multi-line cells
54 ip.run_cell('"""a\nb"""\n')
52 ip.run_cell('"""a\nb"""\n')
55 self.assertEqual(ip.user_ns['_'], 'a\nb')
53 self.assertEqual(ip.user_ns['_'], 'a\nb')
56
54
57 def test_run_empty_cell(self):
55 def test_run_empty_cell(self):
58 """Just make sure we don't get a horrible error with a blank
56 """Just make sure we don't get a horrible error with a blank
59 cell of input. Yes, I did overlook that."""
57 cell of input. Yes, I did overlook that."""
60 old_xc = ip.execution_count
58 old_xc = ip.execution_count
61 res = ip.run_cell('')
59 res = ip.run_cell('')
62 self.assertEqual(ip.execution_count, old_xc)
60 self.assertEqual(ip.execution_count, old_xc)
63 self.assertEqual(res.execution_count, None)
61 self.assertEqual(res.execution_count, None)
64
62
65 def test_run_cell_multiline(self):
63 def test_run_cell_multiline(self):
66 """Multi-block, multi-line cells must execute correctly.
64 """Multi-block, multi-line cells must execute correctly.
67 """
65 """
68 src = '\n'.join(["x=1",
66 src = '\n'.join(["x=1",
69 "y=2",
67 "y=2",
70 "if 1:",
68 "if 1:",
71 " x += 1",
69 " x += 1",
72 " y += 1",])
70 " y += 1",])
73 res = ip.run_cell(src)
71 res = ip.run_cell(src)
74 self.assertEqual(ip.user_ns['x'], 2)
72 self.assertEqual(ip.user_ns['x'], 2)
75 self.assertEqual(ip.user_ns['y'], 3)
73 self.assertEqual(ip.user_ns['y'], 3)
76 self.assertEqual(res.success, True)
74 self.assertEqual(res.success, True)
77 self.assertEqual(res.result, None)
75 self.assertEqual(res.result, None)
78
76
79 def test_multiline_string_cells(self):
77 def test_multiline_string_cells(self):
80 "Code sprinkled with multiline strings should execute (GH-306)"
78 "Code sprinkled with multiline strings should execute (GH-306)"
81 ip.run_cell('tmp=0')
79 ip.run_cell('tmp=0')
82 self.assertEqual(ip.user_ns['tmp'], 0)
80 self.assertEqual(ip.user_ns['tmp'], 0)
83 res = ip.run_cell('tmp=1;"""a\nb"""\n')
81 res = ip.run_cell('tmp=1;"""a\nb"""\n')
84 self.assertEqual(ip.user_ns['tmp'], 1)
82 self.assertEqual(ip.user_ns['tmp'], 1)
85 self.assertEqual(res.success, True)
83 self.assertEqual(res.success, True)
86 self.assertEqual(res.result, "a\nb")
84 self.assertEqual(res.result, "a\nb")
87
85
88 def test_dont_cache_with_semicolon(self):
86 def test_dont_cache_with_semicolon(self):
89 "Ending a line with semicolon should not cache the returned object (GH-307)"
87 "Ending a line with semicolon should not cache the returned object (GH-307)"
90 oldlen = len(ip.user_ns['Out'])
88 oldlen = len(ip.user_ns['Out'])
91 for cell in ['1;', '1;1;']:
89 for cell in ['1;', '1;1;']:
92 res = ip.run_cell(cell, store_history=True)
90 res = ip.run_cell(cell, store_history=True)
93 newlen = len(ip.user_ns['Out'])
91 newlen = len(ip.user_ns['Out'])
94 self.assertEqual(oldlen, newlen)
92 self.assertEqual(oldlen, newlen)
95 self.assertIsNone(res.result)
93 self.assertIsNone(res.result)
96 i = 0
94 i = 0
97 #also test the default caching behavior
95 #also test the default caching behavior
98 for cell in ['1', '1;1']:
96 for cell in ['1', '1;1']:
99 ip.run_cell(cell, store_history=True)
97 ip.run_cell(cell, store_history=True)
100 newlen = len(ip.user_ns['Out'])
98 newlen = len(ip.user_ns['Out'])
101 i += 1
99 i += 1
102 self.assertEqual(oldlen+i, newlen)
100 self.assertEqual(oldlen+i, newlen)
103
101
104 def test_syntax_error(self):
102 def test_syntax_error(self):
105 res = ip.run_cell("raise = 3")
103 res = ip.run_cell("raise = 3")
106 self.assertIsInstance(res.error_before_exec, SyntaxError)
104 self.assertIsInstance(res.error_before_exec, SyntaxError)
107
105
108 def test_In_variable(self):
106 def test_In_variable(self):
109 "Verify that In variable grows with user input (GH-284)"
107 "Verify that In variable grows with user input (GH-284)"
110 oldlen = len(ip.user_ns['In'])
108 oldlen = len(ip.user_ns['In'])
111 ip.run_cell('1;', store_history=True)
109 ip.run_cell('1;', store_history=True)
112 newlen = len(ip.user_ns['In'])
110 newlen = len(ip.user_ns['In'])
113 self.assertEqual(oldlen+1, newlen)
111 self.assertEqual(oldlen+1, newlen)
114 self.assertEqual(ip.user_ns['In'][-1],'1;')
112 self.assertEqual(ip.user_ns['In'][-1],'1;')
115
113
116 def test_magic_names_in_string(self):
114 def test_magic_names_in_string(self):
117 ip.run_cell('a = """\n%exit\n"""')
115 ip.run_cell('a = """\n%exit\n"""')
118 self.assertEqual(ip.user_ns['a'], '\n%exit\n')
116 self.assertEqual(ip.user_ns['a'], '\n%exit\n')
119
117
120 def test_trailing_newline(self):
118 def test_trailing_newline(self):
121 """test that running !(command) does not raise a SyntaxError"""
119 """test that running !(command) does not raise a SyntaxError"""
122 ip.run_cell('!(true)\n', False)
120 ip.run_cell('!(true)\n', False)
123 ip.run_cell('!(true)\n\n\n', False)
121 ip.run_cell('!(true)\n\n\n', False)
124
122
125 def test_gh_597(self):
123 def test_gh_597(self):
126 """Pretty-printing lists of objects with non-ascii reprs may cause
124 """Pretty-printing lists of objects with non-ascii reprs may cause
127 problems."""
125 problems."""
128 class Spam(object):
126 class Spam(object):
129 def __repr__(self):
127 def __repr__(self):
130 return "\xe9"*50
128 return "\xe9"*50
131 import IPython.core.formatters
129 import IPython.core.formatters
132 f = IPython.core.formatters.PlainTextFormatter()
130 f = IPython.core.formatters.PlainTextFormatter()
133 f([Spam(),Spam()])
131 f([Spam(),Spam()])
134
132
135
133
136 def test_future_flags(self):
134 def test_future_flags(self):
137 """Check that future flags are used for parsing code (gh-777)"""
135 """Check that future flags are used for parsing code (gh-777)"""
138 ip.run_cell('from __future__ import barry_as_FLUFL')
136 ip.run_cell('from __future__ import barry_as_FLUFL')
139 try:
137 try:
140 ip.run_cell('prfunc_return_val = 1 <> 2')
138 ip.run_cell('prfunc_return_val = 1 <> 2')
141 assert 'prfunc_return_val' in ip.user_ns
139 assert 'prfunc_return_val' in ip.user_ns
142 finally:
140 finally:
143 # Reset compiler flags so we don't mess up other tests.
141 # Reset compiler flags so we don't mess up other tests.
144 ip.compile.reset_compiler_flags()
142 ip.compile.reset_compiler_flags()
145
143
146 def test_can_pickle(self):
144 def test_can_pickle(self):
147 "Can we pickle objects defined interactively (GH-29)"
145 "Can we pickle objects defined interactively (GH-29)"
148 ip = get_ipython()
146 ip = get_ipython()
149 ip.reset()
147 ip.reset()
150 ip.run_cell(("class Mylist(list):\n"
148 ip.run_cell(("class Mylist(list):\n"
151 " def __init__(self,x=[]):\n"
149 " def __init__(self,x=[]):\n"
152 " list.__init__(self,x)"))
150 " list.__init__(self,x)"))
153 ip.run_cell("w=Mylist([1,2,3])")
151 ip.run_cell("w=Mylist([1,2,3])")
154
152
155 from pickle import dumps
153 from pickle import dumps
156
154
157 # We need to swap in our main module - this is only necessary
155 # We need to swap in our main module - this is only necessary
158 # inside the test framework, because IPython puts the interactive module
156 # inside the test framework, because IPython puts the interactive module
159 # in place (but the test framework undoes this).
157 # in place (but the test framework undoes this).
160 _main = sys.modules['__main__']
158 _main = sys.modules['__main__']
161 sys.modules['__main__'] = ip.user_module
159 sys.modules['__main__'] = ip.user_module
162 try:
160 try:
163 res = dumps(ip.user_ns["w"])
161 res = dumps(ip.user_ns["w"])
164 finally:
162 finally:
165 sys.modules['__main__'] = _main
163 sys.modules['__main__'] = _main
166 self.assertTrue(isinstance(res, bytes))
164 self.assertTrue(isinstance(res, bytes))
167
165
168 def test_global_ns(self):
166 def test_global_ns(self):
169 "Code in functions must be able to access variables outside them."
167 "Code in functions must be able to access variables outside them."
170 ip = get_ipython()
168 ip = get_ipython()
171 ip.run_cell("a = 10")
169 ip.run_cell("a = 10")
172 ip.run_cell(("def f(x):\n"
170 ip.run_cell(("def f(x):\n"
173 " return x + a"))
171 " return x + a"))
174 ip.run_cell("b = f(12)")
172 ip.run_cell("b = f(12)")
175 self.assertEqual(ip.user_ns["b"], 22)
173 self.assertEqual(ip.user_ns["b"], 22)
176
174
177 def test_bad_custom_tb(self):
175 def test_bad_custom_tb(self):
178 """Check that InteractiveShell is protected from bad custom exception handlers"""
176 """Check that InteractiveShell is protected from bad custom exception handlers"""
179 ip.set_custom_exc((IOError,), lambda etype,value,tb: 1/0)
177 ip.set_custom_exc((IOError,), lambda etype,value,tb: 1/0)
180 self.assertEqual(ip.custom_exceptions, (IOError,))
178 self.assertEqual(ip.custom_exceptions, (IOError,))
181 with tt.AssertPrints("Custom TB Handler failed", channel='stderr'):
179 with tt.AssertPrints("Custom TB Handler failed", channel='stderr'):
182 ip.run_cell(u'raise IOError("foo")')
180 ip.run_cell(u'raise IOError("foo")')
183 self.assertEqual(ip.custom_exceptions, ())
181 self.assertEqual(ip.custom_exceptions, ())
184
182
185 def test_bad_custom_tb_return(self):
183 def test_bad_custom_tb_return(self):
186 """Check that InteractiveShell is protected from bad return types in custom exception handlers"""
184 """Check that InteractiveShell is protected from bad return types in custom exception handlers"""
187 ip.set_custom_exc((NameError,),lambda etype,value,tb, tb_offset=None: 1)
185 ip.set_custom_exc((NameError,),lambda etype,value,tb, tb_offset=None: 1)
188 self.assertEqual(ip.custom_exceptions, (NameError,))
186 self.assertEqual(ip.custom_exceptions, (NameError,))
189 with tt.AssertPrints("Custom TB Handler failed", channel='stderr'):
187 with tt.AssertPrints("Custom TB Handler failed", channel='stderr'):
190 ip.run_cell(u'a=abracadabra')
188 ip.run_cell(u'a=abracadabra')
191 self.assertEqual(ip.custom_exceptions, ())
189 self.assertEqual(ip.custom_exceptions, ())
192
190
193 def test_drop_by_id(self):
191 def test_drop_by_id(self):
194 myvars = {"a":object(), "b":object(), "c": object()}
192 myvars = {"a":object(), "b":object(), "c": object()}
195 ip.push(myvars, interactive=False)
193 ip.push(myvars, interactive=False)
196 for name in myvars:
194 for name in myvars:
197 assert name in ip.user_ns, name
195 assert name in ip.user_ns, name
198 assert name in ip.user_ns_hidden, name
196 assert name in ip.user_ns_hidden, name
199 ip.user_ns['b'] = 12
197 ip.user_ns['b'] = 12
200 ip.drop_by_id(myvars)
198 ip.drop_by_id(myvars)
201 for name in ["a", "c"]:
199 for name in ["a", "c"]:
202 assert name not in ip.user_ns, name
200 assert name not in ip.user_ns, name
203 assert name not in ip.user_ns_hidden, name
201 assert name not in ip.user_ns_hidden, name
204 assert ip.user_ns['b'] == 12
202 assert ip.user_ns['b'] == 12
205 ip.reset()
203 ip.reset()
206
204
207 def test_var_expand(self):
205 def test_var_expand(self):
208 ip.user_ns['f'] = u'Ca\xf1o'
206 ip.user_ns['f'] = u'Ca\xf1o'
209 self.assertEqual(ip.var_expand(u'echo $f'), u'echo Ca\xf1o')
207 self.assertEqual(ip.var_expand(u'echo $f'), u'echo Ca\xf1o')
210 self.assertEqual(ip.var_expand(u'echo {f}'), u'echo Ca\xf1o')
208 self.assertEqual(ip.var_expand(u'echo {f}'), u'echo Ca\xf1o')
211 self.assertEqual(ip.var_expand(u'echo {f[:-1]}'), u'echo Ca\xf1')
209 self.assertEqual(ip.var_expand(u'echo {f[:-1]}'), u'echo Ca\xf1')
212 self.assertEqual(ip.var_expand(u'echo {1*2}'), u'echo 2')
210 self.assertEqual(ip.var_expand(u'echo {1*2}'), u'echo 2')
213
211
214 self.assertEqual(ip.var_expand(u"grep x | awk '{print $1}'"), u"grep x | awk '{print $1}'")
212 self.assertEqual(ip.var_expand(u"grep x | awk '{print $1}'"), u"grep x | awk '{print $1}'")
215
213
216 ip.user_ns['f'] = b'Ca\xc3\xb1o'
214 ip.user_ns['f'] = b'Ca\xc3\xb1o'
217 # This should not raise any exception:
215 # This should not raise any exception:
218 ip.var_expand(u'echo $f')
216 ip.var_expand(u'echo $f')
219
217
220 def test_var_expand_local(self):
218 def test_var_expand_local(self):
221 """Test local variable expansion in !system and %magic calls"""
219 """Test local variable expansion in !system and %magic calls"""
222 # !system
220 # !system
223 ip.run_cell('def test():\n'
221 ip.run_cell(
224 ' lvar = "ttt"\n'
222 "def test():\n"
225 ' ret = !echo {lvar}\n'
223 ' lvar = "ttt"\n'
226 ' return ret[0]\n')
224 " ret = !echo {lvar}\n"
227 res = ip.user_ns['test']()
225 " return ret[0]\n"
228 nt.assert_in('ttt', res)
226 )
229
227 res = ip.user_ns["test"]()
228 self.assertIn("ttt", res)
229
230 # %magic
230 # %magic
231 ip.run_cell('def makemacro():\n'
231 ip.run_cell(
232 ' macroname = "macro_var_expand_locals"\n'
232 "def makemacro():\n"
233 ' %macro {macroname} codestr\n')
233 ' macroname = "macro_var_expand_locals"\n'
234 ip.user_ns['codestr'] = "str(12)"
234 " %macro {macroname} codestr\n"
235 ip.run_cell('makemacro()')
235 )
236 nt.assert_in('macro_var_expand_locals', ip.user_ns)
236 ip.user_ns["codestr"] = "str(12)"
237
237 ip.run_cell("makemacro()")
238 self.assertIn("macro_var_expand_locals", ip.user_ns)
239
238 def test_var_expand_self(self):
240 def test_var_expand_self(self):
239 """Test variable expansion with the name 'self', which was failing.
241 """Test variable expansion with the name 'self', which was failing.
240
242
241 See https://github.com/ipython/ipython/issues/1878#issuecomment-7698218
243 See https://github.com/ipython/ipython/issues/1878#issuecomment-7698218
242 """
244 """
243 ip.run_cell('class cTest:\n'
245 ip.run_cell(
244 ' classvar="see me"\n'
246 "class cTest:\n"
245 ' def test(self):\n'
247 ' classvar="see me"\n'
246 ' res = !echo Variable: {self.classvar}\n'
248 " def test(self):\n"
247 ' return res[0]\n')
249 " res = !echo Variable: {self.classvar}\n"
248 nt.assert_in('see me', ip.user_ns['cTest']().test())
250 " return res[0]\n"
249
251 )
252 self.assertIn("see me", ip.user_ns["cTest"]().test())
253
250 def test_bad_var_expand(self):
254 def test_bad_var_expand(self):
251 """var_expand on invalid formats shouldn't raise"""
255 """var_expand on invalid formats shouldn't raise"""
252 # SyntaxError
256 # SyntaxError
253 self.assertEqual(ip.var_expand(u"{'a':5}"), u"{'a':5}")
257 self.assertEqual(ip.var_expand(u"{'a':5}"), u"{'a':5}")
254 # NameError
258 # NameError
255 self.assertEqual(ip.var_expand(u"{asdf}"), u"{asdf}")
259 self.assertEqual(ip.var_expand(u"{asdf}"), u"{asdf}")
256 # ZeroDivisionError
260 # ZeroDivisionError
257 self.assertEqual(ip.var_expand(u"{1/0}"), u"{1/0}")
261 self.assertEqual(ip.var_expand(u"{1/0}"), u"{1/0}")
258
262
259 def test_silent_postexec(self):
263 def test_silent_postexec(self):
260 """run_cell(silent=True) doesn't invoke pre/post_run_cell callbacks"""
264 """run_cell(silent=True) doesn't invoke pre/post_run_cell callbacks"""
261 pre_explicit = mock.Mock()
265 pre_explicit = mock.Mock()
262 pre_always = mock.Mock()
266 pre_always = mock.Mock()
263 post_explicit = mock.Mock()
267 post_explicit = mock.Mock()
264 post_always = mock.Mock()
268 post_always = mock.Mock()
265 all_mocks = [pre_explicit, pre_always, post_explicit, post_always]
269 all_mocks = [pre_explicit, pre_always, post_explicit, post_always]
266
270
267 ip.events.register('pre_run_cell', pre_explicit)
271 ip.events.register('pre_run_cell', pre_explicit)
268 ip.events.register('pre_execute', pre_always)
272 ip.events.register('pre_execute', pre_always)
269 ip.events.register('post_run_cell', post_explicit)
273 ip.events.register('post_run_cell', post_explicit)
270 ip.events.register('post_execute', post_always)
274 ip.events.register('post_execute', post_always)
271
275
272 try:
276 try:
273 ip.run_cell("1", silent=True)
277 ip.run_cell("1", silent=True)
274 assert pre_always.called
278 assert pre_always.called
275 assert not pre_explicit.called
279 assert not pre_explicit.called
276 assert post_always.called
280 assert post_always.called
277 assert not post_explicit.called
281 assert not post_explicit.called
278 # double-check that non-silent exec did what we expected
282 # double-check that non-silent exec did what we expected
279 # silent to avoid
283 # silent to avoid
280 ip.run_cell("1")
284 ip.run_cell("1")
281 assert pre_explicit.called
285 assert pre_explicit.called
282 assert post_explicit.called
286 assert post_explicit.called
283 info, = pre_explicit.call_args[0]
287 info, = pre_explicit.call_args[0]
284 result, = post_explicit.call_args[0]
288 result, = post_explicit.call_args[0]
285 self.assertEqual(info, result.info)
289 self.assertEqual(info, result.info)
286 # check that post hooks are always called
290 # check that post hooks are always called
287 [m.reset_mock() for m in all_mocks]
291 [m.reset_mock() for m in all_mocks]
288 ip.run_cell("syntax error")
292 ip.run_cell("syntax error")
289 assert pre_always.called
293 assert pre_always.called
290 assert pre_explicit.called
294 assert pre_explicit.called
291 assert post_always.called
295 assert post_always.called
292 assert post_explicit.called
296 assert post_explicit.called
293 info, = pre_explicit.call_args[0]
297 info, = pre_explicit.call_args[0]
294 result, = post_explicit.call_args[0]
298 result, = post_explicit.call_args[0]
295 self.assertEqual(info, result.info)
299 self.assertEqual(info, result.info)
296 finally:
300 finally:
297 # remove post-exec
301 # remove post-exec
298 ip.events.unregister('pre_run_cell', pre_explicit)
302 ip.events.unregister('pre_run_cell', pre_explicit)
299 ip.events.unregister('pre_execute', pre_always)
303 ip.events.unregister('pre_execute', pre_always)
300 ip.events.unregister('post_run_cell', post_explicit)
304 ip.events.unregister('post_run_cell', post_explicit)
301 ip.events.unregister('post_execute', post_always)
305 ip.events.unregister('post_execute', post_always)
302
306
303 def test_silent_noadvance(self):
307 def test_silent_noadvance(self):
304 """run_cell(silent=True) doesn't advance execution_count"""
308 """run_cell(silent=True) doesn't advance execution_count"""
305 ec = ip.execution_count
309 ec = ip.execution_count
306 # silent should force store_history=False
310 # silent should force store_history=False
307 ip.run_cell("1", store_history=True, silent=True)
311 ip.run_cell("1", store_history=True, silent=True)
308
312
309 self.assertEqual(ec, ip.execution_count)
313 self.assertEqual(ec, ip.execution_count)
310 # double-check that non-silent exec did what we expected
314 # double-check that non-silent exec did what we expected
311 # silent to avoid
315 # silent to avoid
312 ip.run_cell("1", store_history=True)
316 ip.run_cell("1", store_history=True)
313 self.assertEqual(ec+1, ip.execution_count)
317 self.assertEqual(ec+1, ip.execution_count)
314
318
315 def test_silent_nodisplayhook(self):
319 def test_silent_nodisplayhook(self):
316 """run_cell(silent=True) doesn't trigger displayhook"""
320 """run_cell(silent=True) doesn't trigger displayhook"""
317 d = dict(called=False)
321 d = dict(called=False)
318
322
319 trap = ip.display_trap
323 trap = ip.display_trap
320 save_hook = trap.hook
324 save_hook = trap.hook
321
325
322 def failing_hook(*args, **kwargs):
326 def failing_hook(*args, **kwargs):
323 d['called'] = True
327 d['called'] = True
324
328
325 try:
329 try:
326 trap.hook = failing_hook
330 trap.hook = failing_hook
327 res = ip.run_cell("1", silent=True)
331 res = ip.run_cell("1", silent=True)
328 self.assertFalse(d['called'])
332 self.assertFalse(d['called'])
329 self.assertIsNone(res.result)
333 self.assertIsNone(res.result)
330 # double-check that non-silent exec did what we expected
334 # double-check that non-silent exec did what we expected
331 # silent to avoid
335 # silent to avoid
332 ip.run_cell("1")
336 ip.run_cell("1")
333 self.assertTrue(d['called'])
337 self.assertTrue(d['called'])
334 finally:
338 finally:
335 trap.hook = save_hook
339 trap.hook = save_hook
336
340
337 def test_ofind_line_magic(self):
341 def test_ofind_line_magic(self):
338 from IPython.core.magic import register_line_magic
342 from IPython.core.magic import register_line_magic
339
343
340 @register_line_magic
344 @register_line_magic
341 def lmagic(line):
345 def lmagic(line):
342 "A line magic"
346 "A line magic"
343
347
344 # Get info on line magic
348 # Get info on line magic
345 lfind = ip._ofind('lmagic')
349 lfind = ip._ofind('lmagic')
346 info = dict(found=True, isalias=False, ismagic=True,
350 info = dict(found=True, isalias=False, ismagic=True,
347 namespace = 'IPython internal', obj= lmagic.__wrapped__,
351 namespace = 'IPython internal', obj= lmagic.__wrapped__,
348 parent = None)
352 parent = None)
349 nt.assert_equal(lfind, info)
353 self.assertEqual(lfind, info)
350
354
351 def test_ofind_cell_magic(self):
355 def test_ofind_cell_magic(self):
352 from IPython.core.magic import register_cell_magic
356 from IPython.core.magic import register_cell_magic
353
357
354 @register_cell_magic
358 @register_cell_magic
355 def cmagic(line, cell):
359 def cmagic(line, cell):
356 "A cell magic"
360 "A cell magic"
357
361
358 # Get info on cell magic
362 # Get info on cell magic
359 find = ip._ofind('cmagic')
363 find = ip._ofind('cmagic')
360 info = dict(found=True, isalias=False, ismagic=True,
364 info = dict(found=True, isalias=False, ismagic=True,
361 namespace = 'IPython internal', obj= cmagic.__wrapped__,
365 namespace = 'IPython internal', obj= cmagic.__wrapped__,
362 parent = None)
366 parent = None)
363 nt.assert_equal(find, info)
367 self.assertEqual(find, info)
364
368
365 def test_ofind_property_with_error(self):
369 def test_ofind_property_with_error(self):
366 class A(object):
370 class A(object):
367 @property
371 @property
368 def foo(self):
372 def foo(self):
369 raise NotImplementedError()
373 raise NotImplementedError()
370 a = A()
374 a = A()
371
375
372 found = ip._ofind('a.foo', [('locals', locals())])
376 found = ip._ofind('a.foo', [('locals', locals())])
373 info = dict(found=True, isalias=False, ismagic=False,
377 info = dict(found=True, isalias=False, ismagic=False,
374 namespace='locals', obj=A.foo, parent=a)
378 namespace='locals', obj=A.foo, parent=a)
375 nt.assert_equal(found, info)
379 self.assertEqual(found, info)
376
380
377 def test_ofind_multiple_attribute_lookups(self):
381 def test_ofind_multiple_attribute_lookups(self):
378 class A(object):
382 class A(object):
379 @property
383 @property
380 def foo(self):
384 def foo(self):
381 raise NotImplementedError()
385 raise NotImplementedError()
382
386
383 a = A()
387 a = A()
384 a.a = A()
388 a.a = A()
385 a.a.a = A()
389 a.a.a = A()
386
390
387 found = ip._ofind('a.a.a.foo', [('locals', locals())])
391 found = ip._ofind('a.a.a.foo', [('locals', locals())])
388 info = dict(found=True, isalias=False, ismagic=False,
392 info = dict(found=True, isalias=False, ismagic=False,
389 namespace='locals', obj=A.foo, parent=a.a.a)
393 namespace='locals', obj=A.foo, parent=a.a.a)
390 nt.assert_equal(found, info)
394 self.assertEqual(found, info)
391
395
392 def test_ofind_slotted_attributes(self):
396 def test_ofind_slotted_attributes(self):
393 class A(object):
397 class A(object):
394 __slots__ = ['foo']
398 __slots__ = ['foo']
395 def __init__(self):
399 def __init__(self):
396 self.foo = 'bar'
400 self.foo = 'bar'
397
401
398 a = A()
402 a = A()
399 found = ip._ofind('a.foo', [('locals', locals())])
403 found = ip._ofind('a.foo', [('locals', locals())])
400 info = dict(found=True, isalias=False, ismagic=False,
404 info = dict(found=True, isalias=False, ismagic=False,
401 namespace='locals', obj=a.foo, parent=a)
405 namespace='locals', obj=a.foo, parent=a)
402 nt.assert_equal(found, info)
406 self.assertEqual(found, info)
403
407
404 found = ip._ofind('a.bar', [('locals', locals())])
408 found = ip._ofind('a.bar', [('locals', locals())])
405 info = dict(found=False, isalias=False, ismagic=False,
409 info = dict(found=False, isalias=False, ismagic=False,
406 namespace=None, obj=None, parent=a)
410 namespace=None, obj=None, parent=a)
407 nt.assert_equal(found, info)
411 self.assertEqual(found, info)
408
412
409 def test_ofind_prefers_property_to_instance_level_attribute(self):
413 def test_ofind_prefers_property_to_instance_level_attribute(self):
410 class A(object):
414 class A(object):
411 @property
415 @property
412 def foo(self):
416 def foo(self):
413 return 'bar'
417 return 'bar'
414 a = A()
418 a = A()
415 a.__dict__['foo'] = 'baz'
419 a.__dict__["foo"] = "baz"
416 nt.assert_equal(a.foo, 'bar')
420 self.assertEqual(a.foo, "bar")
417 found = ip._ofind('a.foo', [('locals', locals())])
421 found = ip._ofind("a.foo", [("locals", locals())])
418 nt.assert_is(found['obj'], A.foo)
422 self.assertIs(found["obj"], A.foo)
419
423
420 def test_custom_syntaxerror_exception(self):
424 def test_custom_syntaxerror_exception(self):
421 called = []
425 called = []
422 def my_handler(shell, etype, value, tb, tb_offset=None):
426 def my_handler(shell, etype, value, tb, tb_offset=None):
423 called.append(etype)
427 called.append(etype)
424 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
428 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
425
429
426 ip.set_custom_exc((SyntaxError,), my_handler)
430 ip.set_custom_exc((SyntaxError,), my_handler)
427 try:
431 try:
428 ip.run_cell("1f")
432 ip.run_cell("1f")
429 # Check that this was called, and only once.
433 # Check that this was called, and only once.
430 self.assertEqual(called, [SyntaxError])
434 self.assertEqual(called, [SyntaxError])
431 finally:
435 finally:
432 # Reset the custom exception hook
436 # Reset the custom exception hook
433 ip.set_custom_exc((), None)
437 ip.set_custom_exc((), None)
434
438
435 def test_custom_exception(self):
439 def test_custom_exception(self):
436 called = []
440 called = []
437 def my_handler(shell, etype, value, tb, tb_offset=None):
441 def my_handler(shell, etype, value, tb, tb_offset=None):
438 called.append(etype)
442 called.append(etype)
439 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
443 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
440
444
441 ip.set_custom_exc((ValueError,), my_handler)
445 ip.set_custom_exc((ValueError,), my_handler)
442 try:
446 try:
443 res = ip.run_cell("raise ValueError('test')")
447 res = ip.run_cell("raise ValueError('test')")
444 # Check that this was called, and only once.
448 # Check that this was called, and only once.
445 self.assertEqual(called, [ValueError])
449 self.assertEqual(called, [ValueError])
446 # Check that the error is on the result object
450 # Check that the error is on the result object
447 self.assertIsInstance(res.error_in_exec, ValueError)
451 self.assertIsInstance(res.error_in_exec, ValueError)
448 finally:
452 finally:
449 # Reset the custom exception hook
453 # Reset the custom exception hook
450 ip.set_custom_exc((), None)
454 ip.set_custom_exc((), None)
451
455
452 @mock.patch("builtins.print")
456 @mock.patch("builtins.print")
453 def test_showtraceback_with_surrogates(self, mocked_print):
457 def test_showtraceback_with_surrogates(self, mocked_print):
454 values = []
458 values = []
455
459
456 def mock_print_func(value, sep=" ", end="\n", file=sys.stdout, flush=False):
460 def mock_print_func(value, sep=" ", end="\n", file=sys.stdout, flush=False):
457 values.append(value)
461 values.append(value)
458 if value == chr(0xD8FF):
462 if value == chr(0xD8FF):
459 raise UnicodeEncodeError("utf-8", chr(0xD8FF), 0, 1, "")
463 raise UnicodeEncodeError("utf-8", chr(0xD8FF), 0, 1, "")
460
464
461 # mock builtins.print
465 # mock builtins.print
462 mocked_print.side_effect = mock_print_func
466 mocked_print.side_effect = mock_print_func
463
467
464 # ip._showtraceback() is replaced in globalipapp.py.
468 # ip._showtraceback() is replaced in globalipapp.py.
465 # Call original method to test.
469 # Call original method to test.
466 interactiveshell.InteractiveShell._showtraceback(ip, None, None, chr(0xD8FF))
470 interactiveshell.InteractiveShell._showtraceback(ip, None, None, chr(0xD8FF))
467
471
468 self.assertEqual(mocked_print.call_count, 2)
472 self.assertEqual(mocked_print.call_count, 2)
469 self.assertEqual(values, [chr(0xD8FF), "\\ud8ff"])
473 self.assertEqual(values, [chr(0xD8FF), "\\ud8ff"])
470
474
471 def test_mktempfile(self):
475 def test_mktempfile(self):
472 filename = ip.mktempfile()
476 filename = ip.mktempfile()
473 # Check that we can open the file again on Windows
477 # Check that we can open the file again on Windows
474 with open(filename, 'w') as f:
478 with open(filename, 'w') as f:
475 f.write('abc')
479 f.write('abc')
476
480
477 filename = ip.mktempfile(data='blah')
481 filename = ip.mktempfile(data='blah')
478 with open(filename, 'r') as f:
482 with open(filename, 'r') as f:
479 self.assertEqual(f.read(), 'blah')
483 self.assertEqual(f.read(), 'blah')
480
484
481 def test_new_main_mod(self):
485 def test_new_main_mod(self):
482 # Smoketest to check that this accepts a unicode module name
486 # Smoketest to check that this accepts a unicode module name
483 name = u'jiefmw'
487 name = u'jiefmw'
484 mod = ip.new_main_mod(u'%s.py' % name, name)
488 mod = ip.new_main_mod(u'%s.py' % name, name)
485 self.assertEqual(mod.__name__, name)
489 self.assertEqual(mod.__name__, name)
486
490
487 def test_get_exception_only(self):
491 def test_get_exception_only(self):
488 try:
492 try:
489 raise KeyboardInterrupt
493 raise KeyboardInterrupt
490 except KeyboardInterrupt:
494 except KeyboardInterrupt:
491 msg = ip.get_exception_only()
495 msg = ip.get_exception_only()
492 self.assertEqual(msg, 'KeyboardInterrupt\n')
496 self.assertEqual(msg, 'KeyboardInterrupt\n')
493
497
494 try:
498 try:
495 raise DerivedInterrupt("foo")
499 raise DerivedInterrupt("foo")
496 except KeyboardInterrupt:
500 except KeyboardInterrupt:
497 msg = ip.get_exception_only()
501 msg = ip.get_exception_only()
498 self.assertEqual(msg, 'IPython.core.tests.test_interactiveshell.DerivedInterrupt: foo\n')
502 self.assertEqual(msg, 'IPython.core.tests.test_interactiveshell.DerivedInterrupt: foo\n')
499
503
500 def test_inspect_text(self):
504 def test_inspect_text(self):
501 ip.run_cell('a = 5')
505 ip.run_cell('a = 5')
502 text = ip.object_inspect_text('a')
506 text = ip.object_inspect_text('a')
503 self.assertIsInstance(text, str)
507 self.assertIsInstance(text, str)
504
508
505 def test_last_execution_result(self):
509 def test_last_execution_result(self):
506 """ Check that last execution result gets set correctly (GH-10702) """
510 """ Check that last execution result gets set correctly (GH-10702) """
507 result = ip.run_cell('a = 5; a')
511 result = ip.run_cell('a = 5; a')
508 self.assertTrue(ip.last_execution_succeeded)
512 self.assertTrue(ip.last_execution_succeeded)
509 self.assertEqual(ip.last_execution_result.result, 5)
513 self.assertEqual(ip.last_execution_result.result, 5)
510
514
511 result = ip.run_cell('a = x_invalid_id_x')
515 result = ip.run_cell('a = x_invalid_id_x')
512 self.assertFalse(ip.last_execution_succeeded)
516 self.assertFalse(ip.last_execution_succeeded)
513 self.assertFalse(ip.last_execution_result.success)
517 self.assertFalse(ip.last_execution_result.success)
514 self.assertIsInstance(ip.last_execution_result.error_in_exec, NameError)
518 self.assertIsInstance(ip.last_execution_result.error_in_exec, NameError)
515
519
516 def test_reset_aliasing(self):
520 def test_reset_aliasing(self):
517 """ Check that standard posix aliases work after %reset. """
521 """ Check that standard posix aliases work after %reset. """
518 if os.name != 'posix':
522 if os.name != 'posix':
519 return
523 return
520
524
521 ip.reset()
525 ip.reset()
522 for cmd in ('clear', 'more', 'less', 'man'):
526 for cmd in ('clear', 'more', 'less', 'man'):
523 res = ip.run_cell('%' + cmd)
527 res = ip.run_cell('%' + cmd)
524 self.assertEqual(res.success, True)
528 self.assertEqual(res.success, True)
525
529
526
530
527 class TestSafeExecfileNonAsciiPath(unittest.TestCase):
531 class TestSafeExecfileNonAsciiPath(unittest.TestCase):
528
532
529 @onlyif_unicode_paths
533 @onlyif_unicode_paths
530 def setUp(self):
534 def setUp(self):
531 self.BASETESTDIR = tempfile.mkdtemp()
535 self.BASETESTDIR = tempfile.mkdtemp()
532 self.TESTDIR = join(self.BASETESTDIR, u"åäö")
536 self.TESTDIR = join(self.BASETESTDIR, u"åäö")
533 os.mkdir(self.TESTDIR)
537 os.mkdir(self.TESTDIR)
534 with open(join(self.TESTDIR, u"åäötestscript.py"), "w") as sfile:
538 with open(join(self.TESTDIR, u"åäötestscript.py"), "w") as sfile:
535 sfile.write("pass\n")
539 sfile.write("pass\n")
536 self.oldpath = os.getcwd()
540 self.oldpath = os.getcwd()
537 os.chdir(self.TESTDIR)
541 os.chdir(self.TESTDIR)
538 self.fname = u"åäötestscript.py"
542 self.fname = u"åäötestscript.py"
539
543
540 def tearDown(self):
544 def tearDown(self):
541 os.chdir(self.oldpath)
545 os.chdir(self.oldpath)
542 shutil.rmtree(self.BASETESTDIR)
546 shutil.rmtree(self.BASETESTDIR)
543
547
544 @onlyif_unicode_paths
548 @onlyif_unicode_paths
545 def test_1(self):
549 def test_1(self):
546 """Test safe_execfile with non-ascii path
550 """Test safe_execfile with non-ascii path
547 """
551 """
548 ip.safe_execfile(self.fname, {}, raise_exceptions=True)
552 ip.safe_execfile(self.fname, {}, raise_exceptions=True)
549
553
550 class ExitCodeChecks(tt.TempFileMixin):
554 class ExitCodeChecks(tt.TempFileMixin):
551
555
552 def setUp(self):
556 def setUp(self):
553 self.system = ip.system_raw
557 self.system = ip.system_raw
554
558
555 def test_exit_code_ok(self):
559 def test_exit_code_ok(self):
556 self.system('exit 0')
560 self.system('exit 0')
557 self.assertEqual(ip.user_ns['_exit_code'], 0)
561 self.assertEqual(ip.user_ns['_exit_code'], 0)
558
562
559 def test_exit_code_error(self):
563 def test_exit_code_error(self):
560 self.system('exit 1')
564 self.system('exit 1')
561 self.assertEqual(ip.user_ns['_exit_code'], 1)
565 self.assertEqual(ip.user_ns['_exit_code'], 1)
562
566
563 @skipif(not hasattr(signal, 'SIGALRM'))
567 @skipif(not hasattr(signal, 'SIGALRM'))
564 def test_exit_code_signal(self):
568 def test_exit_code_signal(self):
565 self.mktmp("import signal, time\n"
569 self.mktmp("import signal, time\n"
566 "signal.setitimer(signal.ITIMER_REAL, 0.1)\n"
570 "signal.setitimer(signal.ITIMER_REAL, 0.1)\n"
567 "time.sleep(1)\n")
571 "time.sleep(1)\n")
568 self.system("%s %s" % (sys.executable, self.fname))
572 self.system("%s %s" % (sys.executable, self.fname))
569 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGALRM)
573 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGALRM)
570
574
571 @onlyif_cmds_exist("csh")
575 @onlyif_cmds_exist("csh")
572 def test_exit_code_signal_csh(self):
576 def test_exit_code_signal_csh(self):
573 SHELL = os.environ.get('SHELL', None)
577 SHELL = os.environ.get('SHELL', None)
574 os.environ['SHELL'] = find_cmd("csh")
578 os.environ['SHELL'] = find_cmd("csh")
575 try:
579 try:
576 self.test_exit_code_signal()
580 self.test_exit_code_signal()
577 finally:
581 finally:
578 if SHELL is not None:
582 if SHELL is not None:
579 os.environ['SHELL'] = SHELL
583 os.environ['SHELL'] = SHELL
580 else:
584 else:
581 del os.environ['SHELL']
585 del os.environ['SHELL']
582
586
583
587
584 class TestSystemRaw(ExitCodeChecks):
588 class TestSystemRaw(ExitCodeChecks):
585
589
586 def setUp(self):
590 def setUp(self):
587 super().setUp()
591 super().setUp()
588 self.system = ip.system_raw
592 self.system = ip.system_raw
589
593
590 @onlyif_unicode_paths
594 @onlyif_unicode_paths
591 def test_1(self):
595 def test_1(self):
592 """Test system_raw with non-ascii cmd
596 """Test system_raw with non-ascii cmd
593 """
597 """
594 cmd = u'''python -c "'åäö'" '''
598 cmd = u'''python -c "'åäö'" '''
595 ip.system_raw(cmd)
599 ip.system_raw(cmd)
596
600
597 @mock.patch('subprocess.call', side_effect=KeyboardInterrupt)
601 @mock.patch('subprocess.call', side_effect=KeyboardInterrupt)
598 @mock.patch('os.system', side_effect=KeyboardInterrupt)
602 @mock.patch('os.system', side_effect=KeyboardInterrupt)
599 def test_control_c(self, *mocks):
603 def test_control_c(self, *mocks):
600 try:
604 try:
601 self.system("sleep 1 # wont happen")
605 self.system("sleep 1 # wont happen")
602 except KeyboardInterrupt:
606 except KeyboardInterrupt:
603 self.fail(
607 self.fail(
604 "system call should intercept "
608 "system call should intercept "
605 "keyboard interrupt from subprocess.call"
609 "keyboard interrupt from subprocess.call"
606 )
610 )
607 self.assertEqual(ip.user_ns["_exit_code"], -signal.SIGINT)
611 self.assertEqual(ip.user_ns["_exit_code"], -signal.SIGINT)
608
612
609 def test_magic_warnings(self):
613 def test_magic_warnings(self):
610 for magic_cmd in ("ls", "pip", "conda", "cd"):
614 for magic_cmd in ("ls", "pip", "conda", "cd"):
611 with self.assertWarnsRegex(Warning, "You executed the system command"):
615 with self.assertWarnsRegex(Warning, "You executed the system command"):
612 ip.system_raw(magic_cmd)
616 ip.system_raw(magic_cmd)
613
617
614 # TODO: Exit codes are currently ignored on Windows.
618 # TODO: Exit codes are currently ignored on Windows.
615 class TestSystemPipedExitCode(ExitCodeChecks):
619 class TestSystemPipedExitCode(ExitCodeChecks):
616
620
617 def setUp(self):
621 def setUp(self):
618 super().setUp()
622 super().setUp()
619 self.system = ip.system_piped
623 self.system = ip.system_piped
620
624
621 @skip_win32
625 @skip_win32
622 def test_exit_code_ok(self):
626 def test_exit_code_ok(self):
623 ExitCodeChecks.test_exit_code_ok(self)
627 ExitCodeChecks.test_exit_code_ok(self)
624
628
625 @skip_win32
629 @skip_win32
626 def test_exit_code_error(self):
630 def test_exit_code_error(self):
627 ExitCodeChecks.test_exit_code_error(self)
631 ExitCodeChecks.test_exit_code_error(self)
628
632
629 @skip_win32
633 @skip_win32
630 def test_exit_code_signal(self):
634 def test_exit_code_signal(self):
631 ExitCodeChecks.test_exit_code_signal(self)
635 ExitCodeChecks.test_exit_code_signal(self)
632
636
633 class TestModules(tt.TempFileMixin):
637 class TestModules(tt.TempFileMixin):
634 def test_extraneous_loads(self):
638 def test_extraneous_loads(self):
635 """Test we're not loading modules on startup that we shouldn't.
639 """Test we're not loading modules on startup that we shouldn't.
636 """
640 """
637 self.mktmp("import sys\n"
641 self.mktmp("import sys\n"
638 "print('numpy' in sys.modules)\n"
642 "print('numpy' in sys.modules)\n"
639 "print('ipyparallel' in sys.modules)\n"
643 "print('ipyparallel' in sys.modules)\n"
640 "print('ipykernel' in sys.modules)\n"
644 "print('ipykernel' in sys.modules)\n"
641 )
645 )
642 out = "False\nFalse\nFalse\n"
646 out = "False\nFalse\nFalse\n"
643 tt.ipexec_validate(self.fname, out)
647 tt.ipexec_validate(self.fname, out)
644
648
645 class Negator(ast.NodeTransformer):
649 class Negator(ast.NodeTransformer):
646 """Negates all number literals in an AST."""
650 """Negates all number literals in an AST."""
647
651
648 # for python 3.7 and earlier
652 # for python 3.7 and earlier
649 def visit_Num(self, node):
653 def visit_Num(self, node):
650 node.n = -node.n
654 node.n = -node.n
651 return node
655 return node
652
656
653 # for python 3.8+
657 # for python 3.8+
654 def visit_Constant(self, node):
658 def visit_Constant(self, node):
655 if isinstance(node.value, int):
659 if isinstance(node.value, int):
656 return self.visit_Num(node)
660 return self.visit_Num(node)
657 return node
661 return node
658
662
659 class TestAstTransform(unittest.TestCase):
663 class TestAstTransform(unittest.TestCase):
660 def setUp(self):
664 def setUp(self):
661 self.negator = Negator()
665 self.negator = Negator()
662 ip.ast_transformers.append(self.negator)
666 ip.ast_transformers.append(self.negator)
663
667
664 def tearDown(self):
668 def tearDown(self):
665 ip.ast_transformers.remove(self.negator)
669 ip.ast_transformers.remove(self.negator)
666
670
667 def test_run_cell(self):
671 def test_run_cell(self):
668 with tt.AssertPrints('-34'):
672 with tt.AssertPrints('-34'):
669 ip.run_cell('print (12 + 22)')
673 ip.run_cell('print (12 + 22)')
670
674
671 # A named reference to a number shouldn't be transformed.
675 # A named reference to a number shouldn't be transformed.
672 ip.user_ns['n'] = 55
676 ip.user_ns['n'] = 55
673 with tt.AssertNotPrints('-55'):
677 with tt.AssertNotPrints('-55'):
674 ip.run_cell('print (n)')
678 ip.run_cell('print (n)')
675
679
676 def test_timeit(self):
680 def test_timeit(self):
677 called = set()
681 called = set()
678 def f(x):
682 def f(x):
679 called.add(x)
683 called.add(x)
680 ip.push({'f':f})
684 ip.push({'f':f})
681
685
682 with tt.AssertPrints("std. dev. of"):
686 with tt.AssertPrints("std. dev. of"):
683 ip.run_line_magic("timeit", "-n1 f(1)")
687 ip.run_line_magic("timeit", "-n1 f(1)")
684 self.assertEqual(called, {-1})
688 self.assertEqual(called, {-1})
685 called.clear()
689 called.clear()
686
690
687 with tt.AssertPrints("std. dev. of"):
691 with tt.AssertPrints("std. dev. of"):
688 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
692 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
689 self.assertEqual(called, {-2, -3})
693 self.assertEqual(called, {-2, -3})
690
694
691 def test_time(self):
695 def test_time(self):
692 called = []
696 called = []
693 def f(x):
697 def f(x):
694 called.append(x)
698 called.append(x)
695 ip.push({'f':f})
699 ip.push({'f':f})
696
700
697 # Test with an expression
701 # Test with an expression
698 with tt.AssertPrints("Wall time: "):
702 with tt.AssertPrints("Wall time: "):
699 ip.run_line_magic("time", "f(5+9)")
703 ip.run_line_magic("time", "f(5+9)")
700 self.assertEqual(called, [-14])
704 self.assertEqual(called, [-14])
701 called[:] = []
705 called[:] = []
702
706
703 # Test with a statement (different code path)
707 # Test with a statement (different code path)
704 with tt.AssertPrints("Wall time: "):
708 with tt.AssertPrints("Wall time: "):
705 ip.run_line_magic("time", "a = f(-3 + -2)")
709 ip.run_line_magic("time", "a = f(-3 + -2)")
706 self.assertEqual(called, [5])
710 self.assertEqual(called, [5])
707
711
708 def test_macro(self):
712 def test_macro(self):
709 ip.push({'a':10})
713 ip.push({'a':10})
710 # The AST transformation makes this do a+=-1
714 # The AST transformation makes this do a+=-1
711 ip.define_macro("amacro", "a+=1\nprint(a)")
715 ip.define_macro("amacro", "a+=1\nprint(a)")
712
716
713 with tt.AssertPrints("9"):
717 with tt.AssertPrints("9"):
714 ip.run_cell("amacro")
718 ip.run_cell("amacro")
715 with tt.AssertPrints("8"):
719 with tt.AssertPrints("8"):
716 ip.run_cell("amacro")
720 ip.run_cell("amacro")
717
721
718 class TestMiscTransform(unittest.TestCase):
722 class TestMiscTransform(unittest.TestCase):
719
723
720
724
721 def test_transform_only_once(self):
725 def test_transform_only_once(self):
722 cleanup = 0
726 cleanup = 0
723 line_t = 0
727 line_t = 0
724 def count_cleanup(lines):
728 def count_cleanup(lines):
725 nonlocal cleanup
729 nonlocal cleanup
726 cleanup += 1
730 cleanup += 1
727 return lines
731 return lines
728
732
729 def count_line_t(lines):
733 def count_line_t(lines):
730 nonlocal line_t
734 nonlocal line_t
731 line_t += 1
735 line_t += 1
732 return lines
736 return lines
733
737
734 ip.input_transformer_manager.cleanup_transforms.append(count_cleanup)
738 ip.input_transformer_manager.cleanup_transforms.append(count_cleanup)
735 ip.input_transformer_manager.line_transforms.append(count_line_t)
739 ip.input_transformer_manager.line_transforms.append(count_line_t)
736
740
737 ip.run_cell('1')
741 ip.run_cell('1')
738
742
739 assert cleanup == 1
743 assert cleanup == 1
740 assert line_t == 1
744 assert line_t == 1
741
745
742 class IntegerWrapper(ast.NodeTransformer):
746 class IntegerWrapper(ast.NodeTransformer):
743 """Wraps all integers in a call to Integer()"""
747 """Wraps all integers in a call to Integer()"""
744
748
745 # for Python 3.7 and earlier
749 # for Python 3.7 and earlier
746
750
747 # for Python 3.7 and earlier
751 # for Python 3.7 and earlier
748 def visit_Num(self, node):
752 def visit_Num(self, node):
749 if isinstance(node.n, int):
753 if isinstance(node.n, int):
750 return ast.Call(func=ast.Name(id='Integer', ctx=ast.Load()),
754 return ast.Call(func=ast.Name(id='Integer', ctx=ast.Load()),
751 args=[node], keywords=[])
755 args=[node], keywords=[])
752 return node
756 return node
753
757
754 # For Python 3.8+
758 # For Python 3.8+
755 def visit_Constant(self, node):
759 def visit_Constant(self, node):
756 if isinstance(node.value, int):
760 if isinstance(node.value, int):
757 return self.visit_Num(node)
761 return self.visit_Num(node)
758 return node
762 return node
759
763
760
764
761 class TestAstTransform2(unittest.TestCase):
765 class TestAstTransform2(unittest.TestCase):
762 def setUp(self):
766 def setUp(self):
763 self.intwrapper = IntegerWrapper()
767 self.intwrapper = IntegerWrapper()
764 ip.ast_transformers.append(self.intwrapper)
768 ip.ast_transformers.append(self.intwrapper)
765
769
766 self.calls = []
770 self.calls = []
767 def Integer(*args):
771 def Integer(*args):
768 self.calls.append(args)
772 self.calls.append(args)
769 return args
773 return args
770 ip.push({"Integer": Integer})
774 ip.push({"Integer": Integer})
771
775
772 def tearDown(self):
776 def tearDown(self):
773 ip.ast_transformers.remove(self.intwrapper)
777 ip.ast_transformers.remove(self.intwrapper)
774 del ip.user_ns['Integer']
778 del ip.user_ns['Integer']
775
779
776 def test_run_cell(self):
780 def test_run_cell(self):
777 ip.run_cell("n = 2")
781 ip.run_cell("n = 2")
778 self.assertEqual(self.calls, [(2,)])
782 self.assertEqual(self.calls, [(2,)])
779
783
780 # This shouldn't throw an error
784 # This shouldn't throw an error
781 ip.run_cell("o = 2.0")
785 ip.run_cell("o = 2.0")
782 self.assertEqual(ip.user_ns['o'], 2.0)
786 self.assertEqual(ip.user_ns['o'], 2.0)
783
787
784 def test_timeit(self):
788 def test_timeit(self):
785 called = set()
789 called = set()
786 def f(x):
790 def f(x):
787 called.add(x)
791 called.add(x)
788 ip.push({'f':f})
792 ip.push({'f':f})
789
793
790 with tt.AssertPrints("std. dev. of"):
794 with tt.AssertPrints("std. dev. of"):
791 ip.run_line_magic("timeit", "-n1 f(1)")
795 ip.run_line_magic("timeit", "-n1 f(1)")
792 self.assertEqual(called, {(1,)})
796 self.assertEqual(called, {(1,)})
793 called.clear()
797 called.clear()
794
798
795 with tt.AssertPrints("std. dev. of"):
799 with tt.AssertPrints("std. dev. of"):
796 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
800 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
797 self.assertEqual(called, {(2,), (3,)})
801 self.assertEqual(called, {(2,), (3,)})
798
802
799 class ErrorTransformer(ast.NodeTransformer):
803 class ErrorTransformer(ast.NodeTransformer):
800 """Throws an error when it sees a number."""
804 """Throws an error when it sees a number."""
801
805
802 # for Python 3.7 and earlier
806 # for Python 3.7 and earlier
803 def visit_Num(self, node):
807 def visit_Num(self, node):
804 raise ValueError("test")
808 raise ValueError("test")
805
809
806 # for Python 3.8+
810 # for Python 3.8+
807 def visit_Constant(self, node):
811 def visit_Constant(self, node):
808 if isinstance(node.value, int):
812 if isinstance(node.value, int):
809 return self.visit_Num(node)
813 return self.visit_Num(node)
810 return node
814 return node
811
815
812
816
813 class TestAstTransformError(unittest.TestCase):
817 class TestAstTransformError(unittest.TestCase):
814 def test_unregistering(self):
818 def test_unregistering(self):
815 err_transformer = ErrorTransformer()
819 err_transformer = ErrorTransformer()
816 ip.ast_transformers.append(err_transformer)
820 ip.ast_transformers.append(err_transformer)
817
821
818 with self.assertWarnsRegex(UserWarning, "It will be unregistered"):
822 with self.assertWarnsRegex(UserWarning, "It will be unregistered"):
819 ip.run_cell("1 + 2")
823 ip.run_cell("1 + 2")
820
824
821 # This should have been removed.
825 # This should have been removed.
822 nt.assert_not_in(err_transformer, ip.ast_transformers)
826 self.assertNotIn(err_transformer, ip.ast_transformers)
823
827
824
828
825 class StringRejector(ast.NodeTransformer):
829 class StringRejector(ast.NodeTransformer):
826 """Throws an InputRejected when it sees a string literal.
830 """Throws an InputRejected when it sees a string literal.
827
831
828 Used to verify that NodeTransformers can signal that a piece of code should
832 Used to verify that NodeTransformers can signal that a piece of code should
829 not be executed by throwing an InputRejected.
833 not be executed by throwing an InputRejected.
830 """
834 """
831
835
832 #for python 3.7 and earlier
836 #for python 3.7 and earlier
833 def visit_Str(self, node):
837 def visit_Str(self, node):
834 raise InputRejected("test")
838 raise InputRejected("test")
835
839
836 # 3.8 only
840 # 3.8 only
837 def visit_Constant(self, node):
841 def visit_Constant(self, node):
838 if isinstance(node.value, str):
842 if isinstance(node.value, str):
839 raise InputRejected("test")
843 raise InputRejected("test")
840 return node
844 return node
841
845
842
846
843 class TestAstTransformInputRejection(unittest.TestCase):
847 class TestAstTransformInputRejection(unittest.TestCase):
844
848
845 def setUp(self):
849 def setUp(self):
846 self.transformer = StringRejector()
850 self.transformer = StringRejector()
847 ip.ast_transformers.append(self.transformer)
851 ip.ast_transformers.append(self.transformer)
848
852
849 def tearDown(self):
853 def tearDown(self):
850 ip.ast_transformers.remove(self.transformer)
854 ip.ast_transformers.remove(self.transformer)
851
855
852 def test_input_rejection(self):
856 def test_input_rejection(self):
853 """Check that NodeTransformers can reject input."""
857 """Check that NodeTransformers can reject input."""
854
858
855 expect_exception_tb = tt.AssertPrints("InputRejected: test")
859 expect_exception_tb = tt.AssertPrints("InputRejected: test")
856 expect_no_cell_output = tt.AssertNotPrints("'unsafe'", suppress=False)
860 expect_no_cell_output = tt.AssertNotPrints("'unsafe'", suppress=False)
857
861
858 # Run the same check twice to verify that the transformer is not
862 # Run the same check twice to verify that the transformer is not
859 # disabled after raising.
863 # disabled after raising.
860 with expect_exception_tb, expect_no_cell_output:
864 with expect_exception_tb, expect_no_cell_output:
861 ip.run_cell("'unsafe'")
865 ip.run_cell("'unsafe'")
862
866
863 with expect_exception_tb, expect_no_cell_output:
867 with expect_exception_tb, expect_no_cell_output:
864 res = ip.run_cell("'unsafe'")
868 res = ip.run_cell("'unsafe'")
865
869
866 self.assertIsInstance(res.error_before_exec, InputRejected)
870 self.assertIsInstance(res.error_before_exec, InputRejected)
867
871
868 def test__IPYTHON__():
872 def test__IPYTHON__():
869 # This shouldn't raise a NameError, that's all
873 # This shouldn't raise a NameError, that's all
870 __IPYTHON__
874 __IPYTHON__
871
875
872
876
873 class DummyRepr(object):
877 class DummyRepr(object):
874 def __repr__(self):
878 def __repr__(self):
875 return "DummyRepr"
879 return "DummyRepr"
876
880
877 def _repr_html_(self):
881 def _repr_html_(self):
878 return "<b>dummy</b>"
882 return "<b>dummy</b>"
879
883
880 def _repr_javascript_(self):
884 def _repr_javascript_(self):
881 return "console.log('hi');", {'key': 'value'}
885 return "console.log('hi');", {'key': 'value'}
882
886
883
887
884 def test_user_variables():
888 def test_user_variables():
885 # enable all formatters
889 # enable all formatters
886 ip.display_formatter.active_types = ip.display_formatter.format_types
890 ip.display_formatter.active_types = ip.display_formatter.format_types
887
891
888 ip.user_ns['dummy'] = d = DummyRepr()
892 ip.user_ns['dummy'] = d = DummyRepr()
889 keys = {'dummy', 'doesnotexist'}
893 keys = {'dummy', 'doesnotexist'}
890 r = ip.user_expressions({ key:key for key in keys})
894 r = ip.user_expressions({ key:key for key in keys})
891
895
892 nt.assert_equal(keys, set(r.keys()))
896 assert keys == set(r.keys())
893 dummy = r['dummy']
897 dummy = r["dummy"]
894 nt.assert_equal({'status', 'data', 'metadata'}, set(dummy.keys()))
898 assert {"status", "data", "metadata"} == set(dummy.keys())
895 nt.assert_equal(dummy['status'], 'ok')
899 assert dummy["status"] == "ok"
896 data = dummy['data']
900 data = dummy["data"]
897 metadata = dummy['metadata']
901 metadata = dummy["metadata"]
898 nt.assert_equal(data.get('text/html'), d._repr_html_())
902 assert data.get("text/html") == d._repr_html_()
899 js, jsmd = d._repr_javascript_()
903 js, jsmd = d._repr_javascript_()
900 nt.assert_equal(data.get('application/javascript'), js)
904 assert data.get("application/javascript") == js
901 nt.assert_equal(metadata.get('application/javascript'), jsmd)
905 assert metadata.get("application/javascript") == jsmd
902
906
903 dne = r['doesnotexist']
907 dne = r["doesnotexist"]
904 nt.assert_equal(dne['status'], 'error')
908 assert dne["status"] == "error"
905 nt.assert_equal(dne['ename'], 'NameError')
909 assert dne["ename"] == "NameError"
906
910
907 # back to text only
911 # back to text only
908 ip.display_formatter.active_types = ['text/plain']
912 ip.display_formatter.active_types = ['text/plain']
909
913
910 def test_user_expression():
914 def test_user_expression():
911 # enable all formatters
915 # enable all formatters
912 ip.display_formatter.active_types = ip.display_formatter.format_types
916 ip.display_formatter.active_types = ip.display_formatter.format_types
913 query = {
917 query = {
914 'a' : '1 + 2',
918 'a' : '1 + 2',
915 'b' : '1/0',
919 'b' : '1/0',
916 }
920 }
917 r = ip.user_expressions(query)
921 r = ip.user_expressions(query)
918 import pprint
922 import pprint
919 pprint.pprint(r)
923 pprint.pprint(r)
920 nt.assert_equal(set(r.keys()), set(query.keys()))
924 assert set(r.keys()) == set(query.keys())
921 a = r['a']
925 a = r["a"]
922 nt.assert_equal({'status', 'data', 'metadata'}, set(a.keys()))
926 assert {"status", "data", "metadata"} == set(a.keys())
923 nt.assert_equal(a['status'], 'ok')
927 assert a["status"] == "ok"
924 data = a['data']
928 data = a["data"]
925 metadata = a['metadata']
929 metadata = a["metadata"]
926 nt.assert_equal(data.get('text/plain'), '3')
930 assert data.get("text/plain") == "3"
927
931
928 b = r['b']
932 b = r["b"]
929 nt.assert_equal(b['status'], 'error')
933 assert b["status"] == "error"
930 nt.assert_equal(b['ename'], 'ZeroDivisionError')
934 assert b["ename"] == "ZeroDivisionError"
931
935
932 # back to text only
936 # back to text only
933 ip.display_formatter.active_types = ['text/plain']
937 ip.display_formatter.active_types = ['text/plain']
934
938
935
939
936 class TestSyntaxErrorTransformer(unittest.TestCase):
940 class TestSyntaxErrorTransformer(unittest.TestCase):
937 """Check that SyntaxError raised by an input transformer is handled by run_cell()"""
941 """Check that SyntaxError raised by an input transformer is handled by run_cell()"""
938
942
939 @staticmethod
943 @staticmethod
940 def transformer(lines):
944 def transformer(lines):
941 for line in lines:
945 for line in lines:
942 pos = line.find('syntaxerror')
946 pos = line.find('syntaxerror')
943 if pos >= 0:
947 if pos >= 0:
944 e = SyntaxError('input contains "syntaxerror"')
948 e = SyntaxError('input contains "syntaxerror"')
945 e.text = line
949 e.text = line
946 e.offset = pos + 1
950 e.offset = pos + 1
947 raise e
951 raise e
948 return lines
952 return lines
949
953
950 def setUp(self):
954 def setUp(self):
951 ip.input_transformers_post.append(self.transformer)
955 ip.input_transformers_post.append(self.transformer)
952
956
953 def tearDown(self):
957 def tearDown(self):
954 ip.input_transformers_post.remove(self.transformer)
958 ip.input_transformers_post.remove(self.transformer)
955
959
956 def test_syntaxerror_input_transformer(self):
960 def test_syntaxerror_input_transformer(self):
957 with tt.AssertPrints('1234'):
961 with tt.AssertPrints('1234'):
958 ip.run_cell('1234')
962 ip.run_cell('1234')
959 with tt.AssertPrints('SyntaxError: invalid syntax'):
963 with tt.AssertPrints('SyntaxError: invalid syntax'):
960 ip.run_cell('1 2 3') # plain python syntax error
964 ip.run_cell('1 2 3') # plain python syntax error
961 with tt.AssertPrints('SyntaxError: input contains "syntaxerror"'):
965 with tt.AssertPrints('SyntaxError: input contains "syntaxerror"'):
962 ip.run_cell('2345 # syntaxerror') # input transformer syntax error
966 ip.run_cell('2345 # syntaxerror') # input transformer syntax error
963 with tt.AssertPrints('3456'):
967 with tt.AssertPrints('3456'):
964 ip.run_cell('3456')
968 ip.run_cell('3456')
965
969
966
970
967 class TestWarningSuppression(unittest.TestCase):
971 class TestWarningSuppression(unittest.TestCase):
968 def test_warning_suppression(self):
972 def test_warning_suppression(self):
969 ip.run_cell("import warnings")
973 ip.run_cell("import warnings")
970 try:
974 try:
971 with self.assertWarnsRegex(UserWarning, "asdf"):
975 with self.assertWarnsRegex(UserWarning, "asdf"):
972 ip.run_cell("warnings.warn('asdf')")
976 ip.run_cell("warnings.warn('asdf')")
973 # Here's the real test -- if we run that again, we should get the
977 # Here's the real test -- if we run that again, we should get the
974 # warning again. Traditionally, each warning was only issued once per
978 # warning again. Traditionally, each warning was only issued once per
975 # IPython session (approximately), even if the user typed in new and
979 # IPython session (approximately), even if the user typed in new and
976 # different code that should have also triggered the warning, leading
980 # different code that should have also triggered the warning, leading
977 # to much confusion.
981 # to much confusion.
978 with self.assertWarnsRegex(UserWarning, "asdf"):
982 with self.assertWarnsRegex(UserWarning, "asdf"):
979 ip.run_cell("warnings.warn('asdf')")
983 ip.run_cell("warnings.warn('asdf')")
980 finally:
984 finally:
981 ip.run_cell("del warnings")
985 ip.run_cell("del warnings")
982
986
983
987
984 def test_deprecation_warning(self):
988 def test_deprecation_warning(self):
985 ip.run_cell("""
989 ip.run_cell("""
986 import warnings
990 import warnings
987 def wrn():
991 def wrn():
988 warnings.warn(
992 warnings.warn(
989 "I AM A WARNING",
993 "I AM A WARNING",
990 DeprecationWarning
994 DeprecationWarning
991 )
995 )
992 """)
996 """)
993 try:
997 try:
994 with self.assertWarnsRegex(DeprecationWarning, "I AM A WARNING"):
998 with self.assertWarnsRegex(DeprecationWarning, "I AM A WARNING"):
995 ip.run_cell("wrn()")
999 ip.run_cell("wrn()")
996 finally:
1000 finally:
997 ip.run_cell("del warnings")
1001 ip.run_cell("del warnings")
998 ip.run_cell("del wrn")
1002 ip.run_cell("del wrn")
999
1003
1000
1004
1001 class TestImportNoDeprecate(tt.TempFileMixin):
1005 class TestImportNoDeprecate(tt.TempFileMixin):
1002
1006
1003 def setUp(self):
1007 def setUp(self):
1004 """Make a valid python temp file."""
1008 """Make a valid python temp file."""
1005 self.mktmp("""
1009 self.mktmp("""
1006 import warnings
1010 import warnings
1007 def wrn():
1011 def wrn():
1008 warnings.warn(
1012 warnings.warn(
1009 "I AM A WARNING",
1013 "I AM A WARNING",
1010 DeprecationWarning
1014 DeprecationWarning
1011 )
1015 )
1012 """)
1016 """)
1013 super().setUp()
1017 super().setUp()
1014
1018
1015 def test_no_dep(self):
1019 def test_no_dep(self):
1016 """
1020 """
1017 No deprecation warning should be raised from imported functions
1021 No deprecation warning should be raised from imported functions
1018 """
1022 """
1019 ip.run_cell("from {} import wrn".format(self.fname))
1023 ip.run_cell("from {} import wrn".format(self.fname))
1020
1024
1021 with tt.AssertNotPrints("I AM A WARNING"):
1025 with tt.AssertNotPrints("I AM A WARNING"):
1022 ip.run_cell("wrn()")
1026 ip.run_cell("wrn()")
1023 ip.run_cell("del wrn")
1027 ip.run_cell("del wrn")
1024
1028
1025
1029
1026 def test_custom_exc_count():
1030 def test_custom_exc_count():
1027 hook = mock.Mock(return_value=None)
1031 hook = mock.Mock(return_value=None)
1028 ip.set_custom_exc((SyntaxError,), hook)
1032 ip.set_custom_exc((SyntaxError,), hook)
1029 before = ip.execution_count
1033 before = ip.execution_count
1030 ip.run_cell("def foo()", store_history=True)
1034 ip.run_cell("def foo()", store_history=True)
1031 # restore default excepthook
1035 # restore default excepthook
1032 ip.set_custom_exc((), None)
1036 ip.set_custom_exc((), None)
1033 nt.assert_equal(hook.call_count, 1)
1037 assert hook.call_count == 1
1034 nt.assert_equal(ip.execution_count, before + 1)
1038 assert ip.execution_count == before + 1
1035
1039
1036
1040
1037 def test_run_cell_async():
1041 def test_run_cell_async():
1038 loop = asyncio.get_event_loop()
1042 loop = asyncio.get_event_loop()
1039 ip.run_cell("import asyncio")
1043 ip.run_cell("import asyncio")
1040 coro = ip.run_cell_async("await asyncio.sleep(0.01)\n5")
1044 coro = ip.run_cell_async("await asyncio.sleep(0.01)\n5")
1041 assert asyncio.iscoroutine(coro)
1045 assert asyncio.iscoroutine(coro)
1042 result = loop.run_until_complete(coro)
1046 result = loop.run_until_complete(coro)
1043 assert isinstance(result, interactiveshell.ExecutionResult)
1047 assert isinstance(result, interactiveshell.ExecutionResult)
1044 assert result.result == 5
1048 assert result.result == 5
1045
1049
1046
1050
1047 def test_should_run_async():
1051 def test_should_run_async():
1048 assert not ip.should_run_async("a = 5")
1052 assert not ip.should_run_async("a = 5")
1049 assert ip.should_run_async("await x")
1053 assert ip.should_run_async("await x")
1050 assert ip.should_run_async("import asyncio; await asyncio.sleep(1)")
1054 assert ip.should_run_async("import asyncio; await asyncio.sleep(1)")
1051
1055
1052
1056
1053 def test_set_custom_completer():
1057 def test_set_custom_completer():
1054 num_completers = len(ip.Completer.matchers)
1058 num_completers = len(ip.Completer.matchers)
1055
1059
1056 def foo(*args, **kwargs):
1060 def foo(*args, **kwargs):
1057 return "I'm a completer!"
1061 return "I'm a completer!"
1058
1062
1059 ip.set_custom_completer(foo, 0)
1063 ip.set_custom_completer(foo, 0)
1060
1064
1061 # check that we've really added a new completer
1065 # check that we've really added a new completer
1062 assert len(ip.Completer.matchers) == num_completers + 1
1066 assert len(ip.Completer.matchers) == num_completers + 1
1063
1067
1064 # check that the first completer is the function we defined
1068 # check that the first completer is the function we defined
1065 assert ip.Completer.matchers[0]() == "I'm a completer!"
1069 assert ip.Completer.matchers[0]() == "I'm a completer!"
1066
1070
1067 # clean up
1071 # clean up
1068 ip.Completer.custom_matchers.pop()
1072 ip.Completer.custom_matchers.pop()
@@ -1,1341 +1,1366 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for various magic functions.
2 """Tests for various magic functions.
3
3
4 Needs to be run by nose (to make ipython session available).
4 Needs to be run by nose (to make ipython session available).
5 """
5 """
6
6
7 import asyncio
7 import asyncio
8 import io
8 import io
9 import os
9 import os
10 import re
10 import re
11 import shlex
11 import shlex
12 import sys
12 import sys
13 import warnings
13 import warnings
14 from importlib import invalidate_caches
14 from importlib import invalidate_caches
15 from io import StringIO
15 from io import StringIO
16 from pathlib import Path
16 from pathlib import Path
17 from textwrap import dedent
17 from textwrap import dedent
18 from unittest import TestCase, mock
18 from unittest import TestCase, mock
19
19
20 import nose.tools as nt
21
22 import pytest
20 import pytest
23
21
24 from IPython import get_ipython
22 from IPython import get_ipython
25 from IPython.core import magic
23 from IPython.core import magic
26 from IPython.core.error import UsageError
24 from IPython.core.error import UsageError
27 from IPython.core.magic import (
25 from IPython.core.magic import (
28 Magics,
26 Magics,
29 cell_magic,
27 cell_magic,
30 line_magic,
28 line_magic,
31 magics_class,
29 magics_class,
32 register_cell_magic,
30 register_cell_magic,
33 register_line_magic,
31 register_line_magic,
34 )
32 )
35 from IPython.core.magics import code, execution, logging, osm, script
33 from IPython.core.magics import code, execution, logging, osm, script
36 from IPython.testing import decorators as dec
34 from IPython.testing import decorators as dec
37 from IPython.testing import tools as tt
35 from IPython.testing import tools as tt
38 from IPython.utils.io import capture_output
36 from IPython.utils.io import capture_output
39 from IPython.utils.process import find_cmd
37 from IPython.utils.process import find_cmd
40 from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory
38 from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory
41
39
42 from .test_debugger import PdbTestInput
40 from .test_debugger import PdbTestInput
43
41
44
42
45 @magic.magics_class
43 @magic.magics_class
46 class DummyMagics(magic.Magics): pass
44 class DummyMagics(magic.Magics): pass
47
45
48 def test_extract_code_ranges():
46 def test_extract_code_ranges():
49 instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
47 instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
50 expected = [(0, 1),
48 expected = [
51 (2, 3),
49 (0, 1),
52 (4, 6),
50 (2, 3),
53 (6, 9),
51 (4, 6),
54 (9, 14),
52 (6, 9),
55 (16, None),
53 (9, 14),
56 (None, 9),
54 (16, None),
57 (9, None),
55 (None, 9),
58 (None, 13),
56 (9, None),
59 (None, None)]
57 (None, 13),
58 (None, None),
59 ]
60 actual = list(code.extract_code_ranges(instr))
60 actual = list(code.extract_code_ranges(instr))
61 nt.assert_equal(actual, expected)
61 assert actual == expected
62
62
63 def test_extract_symbols():
63 def test_extract_symbols():
64 source = """import foo\na = 10\ndef b():\n return 42\n\n\nclass A: pass\n\n\n"""
64 source = """import foo\na = 10\ndef b():\n return 42\n\n\nclass A: pass\n\n\n"""
65 symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
65 symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
66 expected = [([], ['a']),
66 expected = [([], ['a']),
67 (["def b():\n return 42\n"], []),
67 (["def b():\n return 42\n"], []),
68 (["class A: pass\n"], []),
68 (["class A: pass\n"], []),
69 (["class A: pass\n", "def b():\n return 42\n"], []),
69 (["class A: pass\n", "def b():\n return 42\n"], []),
70 (["class A: pass\n"], ['a']),
70 (["class A: pass\n"], ['a']),
71 ([], ['z'])]
71 ([], ['z'])]
72 for symbols, exp in zip(symbols_args, expected):
72 for symbols, exp in zip(symbols_args, expected):
73 nt.assert_equal(code.extract_symbols(source, symbols), exp)
73 assert code.extract_symbols(source, symbols) == exp
74
74
75
75
76 def test_extract_symbols_raises_exception_with_non_python_code():
76 def test_extract_symbols_raises_exception_with_non_python_code():
77 source = ("=begin A Ruby program :)=end\n"
77 source = ("=begin A Ruby program :)=end\n"
78 "def hello\n"
78 "def hello\n"
79 "puts 'Hello world'\n"
79 "puts 'Hello world'\n"
80 "end")
80 "end")
81 with nt.assert_raises(SyntaxError):
81 with pytest.raises(SyntaxError):
82 code.extract_symbols(source, "hello")
82 code.extract_symbols(source, "hello")
83
83
84
84
85 def test_magic_not_found():
85 def test_magic_not_found():
86 # magic not found raises UsageError
86 # magic not found raises UsageError
87 with nt.assert_raises(UsageError):
87 with pytest.raises(UsageError):
88 _ip.magic('doesntexist')
88 _ip.magic('doesntexist')
89
89
90 # ensure result isn't success when a magic isn't found
90 # ensure result isn't success when a magic isn't found
91 result = _ip.run_cell('%doesntexist')
91 result = _ip.run_cell('%doesntexist')
92 assert isinstance(result.error_in_exec, UsageError)
92 assert isinstance(result.error_in_exec, UsageError)
93
93
94
94
95 def test_cell_magic_not_found():
95 def test_cell_magic_not_found():
96 # magic not found raises UsageError
96 # magic not found raises UsageError
97 with nt.assert_raises(UsageError):
97 with pytest.raises(UsageError):
98 _ip.run_cell_magic('doesntexist', 'line', 'cell')
98 _ip.run_cell_magic('doesntexist', 'line', 'cell')
99
99
100 # ensure result isn't success when a magic isn't found
100 # ensure result isn't success when a magic isn't found
101 result = _ip.run_cell('%%doesntexist')
101 result = _ip.run_cell('%%doesntexist')
102 assert isinstance(result.error_in_exec, UsageError)
102 assert isinstance(result.error_in_exec, UsageError)
103
103
104
104
105 def test_magic_error_status():
105 def test_magic_error_status():
106 def fail(shell):
106 def fail(shell):
107 1/0
107 1/0
108 _ip.register_magic_function(fail)
108 _ip.register_magic_function(fail)
109 result = _ip.run_cell('%fail')
109 result = _ip.run_cell('%fail')
110 assert isinstance(result.error_in_exec, ZeroDivisionError)
110 assert isinstance(result.error_in_exec, ZeroDivisionError)
111
111
112
112
113 def test_config():
113 def test_config():
114 """ test that config magic does not raise
114 """ test that config magic does not raise
115 can happen if Configurable init is moved too early into
115 can happen if Configurable init is moved too early into
116 Magics.__init__ as then a Config object will be registered as a
116 Magics.__init__ as then a Config object will be registered as a
117 magic.
117 magic.
118 """
118 """
119 ## should not raise.
119 ## should not raise.
120 _ip.magic('config')
120 _ip.magic('config')
121
121
122 def test_config_available_configs():
122 def test_config_available_configs():
123 """ test that config magic prints available configs in unique and
123 """ test that config magic prints available configs in unique and
124 sorted order. """
124 sorted order. """
125 with capture_output() as captured:
125 with capture_output() as captured:
126 _ip.magic('config')
126 _ip.magic('config')
127
127
128 stdout = captured.stdout
128 stdout = captured.stdout
129 config_classes = stdout.strip().split('\n')[1:]
129 config_classes = stdout.strip().split('\n')[1:]
130 nt.assert_list_equal(config_classes, sorted(set(config_classes)))
130 assert config_classes == sorted(set(config_classes))
131
131
132 def test_config_print_class():
132 def test_config_print_class():
133 """ test that config with a classname prints the class's options. """
133 """ test that config with a classname prints the class's options. """
134 with capture_output() as captured:
134 with capture_output() as captured:
135 _ip.magic('config TerminalInteractiveShell')
135 _ip.magic('config TerminalInteractiveShell')
136
136
137 stdout = captured.stdout
137 stdout = captured.stdout
138 if not re.match("TerminalInteractiveShell.* options", stdout.splitlines()[0]):
138 if not re.match("TerminalInteractiveShell.* options", stdout.splitlines()[0]):
139 print(stdout)
139 print(stdout)
140 raise AssertionError("1st line of stdout not like "
140 raise AssertionError("1st line of stdout not like "
141 "'TerminalInteractiveShell.* options'")
141 "'TerminalInteractiveShell.* options'")
142
142
143 def test_rehashx():
143 def test_rehashx():
144 # clear up everything
144 # clear up everything
145 _ip.alias_manager.clear_aliases()
145 _ip.alias_manager.clear_aliases()
146 del _ip.db['syscmdlist']
146 del _ip.db['syscmdlist']
147
147
148 _ip.magic('rehashx')
148 _ip.magic('rehashx')
149 # Practically ALL ipython development systems will have more than 10 aliases
149 # Practically ALL ipython development systems will have more than 10 aliases
150
150
151 nt.assert_true(len(_ip.alias_manager.aliases) > 10)
151 assert len(_ip.alias_manager.aliases) > 10
152 for name, cmd in _ip.alias_manager.aliases:
152 for name, cmd in _ip.alias_manager.aliases:
153 # we must strip dots from alias names
153 # we must strip dots from alias names
154 nt.assert_not_in('.', name)
154 assert "." not in name
155
155
156 # rehashx must fill up syscmdlist
156 # rehashx must fill up syscmdlist
157 scoms = _ip.db['syscmdlist']
157 scoms = _ip.db['syscmdlist']
158 nt.assert_true(len(scoms) > 10)
158 assert len(scoms) > 10
159
160
159
161
160
162 def test_magic_parse_options():
161 def test_magic_parse_options():
163 """Test that we don't mangle paths when parsing magic options."""
162 """Test that we don't mangle paths when parsing magic options."""
164 ip = get_ipython()
163 ip = get_ipython()
165 path = 'c:\\x'
164 path = 'c:\\x'
166 m = DummyMagics(ip)
165 m = DummyMagics(ip)
167 opts = m.parse_options('-f %s' % path,'f:')[0]
166 opts = m.parse_options('-f %s' % path,'f:')[0]
168 # argv splitting is os-dependent
167 # argv splitting is os-dependent
169 if os.name == 'posix':
168 if os.name == 'posix':
170 expected = 'c:x'
169 expected = 'c:x'
171 else:
170 else:
172 expected = path
171 expected = path
173 nt.assert_equal(opts['f'], expected)
172 assert opts["f"] == expected
173
174
174
175 def test_magic_parse_long_options():
175 def test_magic_parse_long_options():
176 """Magic.parse_options can handle --foo=bar long options"""
176 """Magic.parse_options can handle --foo=bar long options"""
177 ip = get_ipython()
177 ip = get_ipython()
178 m = DummyMagics(ip)
178 m = DummyMagics(ip)
179 opts, _ = m.parse_options('--foo --bar=bubble', 'a', 'foo', 'bar=')
179 opts, _ = m.parse_options("--foo --bar=bubble", "a", "foo", "bar=")
180 nt.assert_in('foo', opts)
180 assert "foo" in opts
181 nt.assert_in('bar', opts)
181 assert "bar" in opts
182 nt.assert_equal(opts['bar'], "bubble")
182 assert opts["bar"] == "bubble"
183
183
184
184
185 def doctest_hist_f():
185 def doctest_hist_f():
186 """Test %hist -f with temporary filename.
186 """Test %hist -f with temporary filename.
187
187
188 In [9]: import tempfile
188 In [9]: import tempfile
189
189
190 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
190 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
191
191
192 In [11]: %hist -nl -f $tfile 3
192 In [11]: %hist -nl -f $tfile 3
193
193
194 In [13]: import os; os.unlink(tfile)
194 In [13]: import os; os.unlink(tfile)
195 """
195 """
196
196
197
197
198 def doctest_hist_op():
198 def doctest_hist_op():
199 """Test %hist -op
199 """Test %hist -op
200
200
201 In [1]: class b(float):
201 In [1]: class b(float):
202 ...: pass
202 ...: pass
203 ...:
203 ...:
204
204
205 In [2]: class s(object):
205 In [2]: class s(object):
206 ...: def __str__(self):
206 ...: def __str__(self):
207 ...: return 's'
207 ...: return 's'
208 ...:
208 ...:
209
209
210 In [3]:
210 In [3]:
211
211
212 In [4]: class r(b):
212 In [4]: class r(b):
213 ...: def __repr__(self):
213 ...: def __repr__(self):
214 ...: return 'r'
214 ...: return 'r'
215 ...:
215 ...:
216
216
217 In [5]: class sr(s,r): pass
217 In [5]: class sr(s,r): pass
218 ...:
218 ...:
219
219
220 In [6]:
220 In [6]:
221
221
222 In [7]: bb=b()
222 In [7]: bb=b()
223
223
224 In [8]: ss=s()
224 In [8]: ss=s()
225
225
226 In [9]: rr=r()
226 In [9]: rr=r()
227
227
228 In [10]: ssrr=sr()
228 In [10]: ssrr=sr()
229
229
230 In [11]: 4.5
230 In [11]: 4.5
231 Out[11]: 4.5
231 Out[11]: 4.5
232
232
233 In [12]: str(ss)
233 In [12]: str(ss)
234 Out[12]: 's'
234 Out[12]: 's'
235
235
236 In [13]:
236 In [13]:
237
237
238 In [14]: %hist -op
238 In [14]: %hist -op
239 >>> class b:
239 >>> class b:
240 ... pass
240 ... pass
241 ...
241 ...
242 >>> class s(b):
242 >>> class s(b):
243 ... def __str__(self):
243 ... def __str__(self):
244 ... return 's'
244 ... return 's'
245 ...
245 ...
246 >>>
246 >>>
247 >>> class r(b):
247 >>> class r(b):
248 ... def __repr__(self):
248 ... def __repr__(self):
249 ... return 'r'
249 ... return 'r'
250 ...
250 ...
251 >>> class sr(s,r): pass
251 >>> class sr(s,r): pass
252 >>>
252 >>>
253 >>> bb=b()
253 >>> bb=b()
254 >>> ss=s()
254 >>> ss=s()
255 >>> rr=r()
255 >>> rr=r()
256 >>> ssrr=sr()
256 >>> ssrr=sr()
257 >>> 4.5
257 >>> 4.5
258 4.5
258 4.5
259 >>> str(ss)
259 >>> str(ss)
260 's'
260 's'
261 >>>
261 >>>
262 """
262 """
263
263
264 def test_hist_pof():
264 def test_hist_pof():
265 ip = get_ipython()
265 ip = get_ipython()
266 ip.run_cell(u"1+2", store_history=True)
266 ip.run_cell("1+2", store_history=True)
267 #raise Exception(ip.history_manager.session_number)
267 #raise Exception(ip.history_manager.session_number)
268 #raise Exception(list(ip.history_manager._get_range_session()))
268 #raise Exception(list(ip.history_manager._get_range_session()))
269 with TemporaryDirectory() as td:
269 with TemporaryDirectory() as td:
270 tf = os.path.join(td, 'hist.py')
270 tf = os.path.join(td, 'hist.py')
271 ip.run_line_magic('history', '-pof %s' % tf)
271 ip.run_line_magic('history', '-pof %s' % tf)
272 assert os.path.isfile(tf)
272 assert os.path.isfile(tf)
273
273
274
274
275 def test_macro():
275 def test_macro():
276 ip = get_ipython()
276 ip = get_ipython()
277 ip.history_manager.reset() # Clear any existing history.
277 ip.history_manager.reset() # Clear any existing history.
278 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
278 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
279 for i, cmd in enumerate(cmds, start=1):
279 for i, cmd in enumerate(cmds, start=1):
280 ip.history_manager.store_inputs(i, cmd)
280 ip.history_manager.store_inputs(i, cmd)
281 ip.magic("macro test 1-3")
281 ip.magic("macro test 1-3")
282 nt.assert_equal(ip.user_ns["test"].value, "\n".join(cmds)+"\n")
282 assert ip.user_ns["test"].value == "\n".join(cmds) + "\n"
283
283
284 # List macros
284 # List macros
285 nt.assert_in("test", ip.magic("macro"))
285 assert "test" in ip.magic("macro")
286
286
287
287
288 def test_macro_run():
288 def test_macro_run():
289 """Test that we can run a multi-line macro successfully."""
289 """Test that we can run a multi-line macro successfully."""
290 ip = get_ipython()
290 ip = get_ipython()
291 ip.history_manager.reset()
291 ip.history_manager.reset()
292 cmds = ["a=10", "a+=1", "print(a)", "%macro test 2-3"]
292 cmds = ["a=10", "a+=1", "print(a)", "%macro test 2-3"]
293 for cmd in cmds:
293 for cmd in cmds:
294 ip.run_cell(cmd, store_history=True)
294 ip.run_cell(cmd, store_history=True)
295 nt.assert_equal(ip.user_ns["test"].value, "a+=1\nprint(a)\n")
295 assert ip.user_ns["test"].value == "a+=1\nprint(a)\n"
296 with tt.AssertPrints("12"):
296 with tt.AssertPrints("12"):
297 ip.run_cell("test")
297 ip.run_cell("test")
298 with tt.AssertPrints("13"):
298 with tt.AssertPrints("13"):
299 ip.run_cell("test")
299 ip.run_cell("test")
300
300
301
301
302 def test_magic_magic():
302 def test_magic_magic():
303 """Test %magic"""
303 """Test %magic"""
304 ip = get_ipython()
304 ip = get_ipython()
305 with capture_output() as captured:
305 with capture_output() as captured:
306 ip.magic("magic")
306 ip.magic("magic")
307
307
308 stdout = captured.stdout
308 stdout = captured.stdout
309 nt.assert_in('%magic', stdout)
309 assert "%magic" in stdout
310 nt.assert_in('IPython', stdout)
310 assert "IPython" in stdout
311 nt.assert_in('Available', stdout)
311 assert "Available" in stdout
312
312
313
313
314 @dec.skipif_not_numpy
314 @dec.skipif_not_numpy
315 def test_numpy_reset_array_undec():
315 def test_numpy_reset_array_undec():
316 "Test '%reset array' functionality"
316 "Test '%reset array' functionality"
317 _ip.ex('import numpy as np')
317 _ip.ex("import numpy as np")
318 _ip.ex('a = np.empty(2)')
318 _ip.ex("a = np.empty(2)")
319 nt.assert_in('a', _ip.user_ns)
319 assert "a" in _ip.user_ns
320 _ip.magic('reset -f array')
320 _ip.magic("reset -f array")
321 nt.assert_not_in('a', _ip.user_ns)
321 assert "a" not in _ip.user_ns
322
322
323
323 def test_reset_out():
324 def test_reset_out():
324 "Test '%reset out' magic"
325 "Test '%reset out' magic"
325 _ip.run_cell("parrot = 'dead'", store_history=True)
326 _ip.run_cell("parrot = 'dead'", store_history=True)
326 # test '%reset -f out', make an Out prompt
327 # test '%reset -f out', make an Out prompt
327 _ip.run_cell("parrot", store_history=True)
328 _ip.run_cell("parrot", store_history=True)
328 nt.assert_true('dead' in [_ip.user_ns[x] for x in ('_','__','___')])
329 assert "dead" in [_ip.user_ns[x] for x in ("_", "__", "___")]
329 _ip.magic('reset -f out')
330 _ip.magic("reset -f out")
330 nt.assert_false('dead' in [_ip.user_ns[x] for x in ('_','__','___')])
331 assert "dead" not in [_ip.user_ns[x] for x in ("_", "__", "___")]
331 nt.assert_equal(len(_ip.user_ns['Out']), 0)
332 assert len(_ip.user_ns["Out"]) == 0
333
332
334
333 def test_reset_in():
335 def test_reset_in():
334 "Test '%reset in' magic"
336 "Test '%reset in' magic"
335 # test '%reset -f in'
337 # test '%reset -f in'
336 _ip.run_cell("parrot", store_history=True)
338 _ip.run_cell("parrot", store_history=True)
337 nt.assert_true('parrot' in [_ip.user_ns[x] for x in ('_i','_ii','_iii')])
339 assert "parrot" in [_ip.user_ns[x] for x in ("_i", "_ii", "_iii")]
338 _ip.magic('%reset -f in')
340 _ip.magic("%reset -f in")
339 nt.assert_false('parrot' in [_ip.user_ns[x] for x in ('_i','_ii','_iii')])
341 assert "parrot" not in [_ip.user_ns[x] for x in ("_i", "_ii", "_iii")]
340 nt.assert_equal(len(set(_ip.user_ns['In'])), 1)
342 assert len(set(_ip.user_ns["In"])) == 1
343
341
344
342 def test_reset_dhist():
345 def test_reset_dhist():
343 "Test '%reset dhist' magic"
346 "Test '%reset dhist' magic"
344 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
347 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
345 _ip.magic('cd ' + os.path.dirname(nt.__file__))
348 _ip.magic("cd " + os.path.dirname(pytest.__file__))
346 _ip.magic('cd -')
349 _ip.magic("cd -")
347 nt.assert_true(len(_ip.user_ns['_dh']) > 0)
350 assert len(_ip.user_ns["_dh"]) > 0
348 _ip.magic('reset -f dhist')
351 _ip.magic("reset -f dhist")
349 nt.assert_equal(len(_ip.user_ns['_dh']), 0)
352 assert len(_ip.user_ns["_dh"]) == 0
350 _ip.run_cell("_dh = [d for d in tmp]") #restore
353 _ip.run_cell("_dh = [d for d in tmp]") # restore
354
351
355
352 def test_reset_in_length():
356 def test_reset_in_length():
353 "Test that '%reset in' preserves In[] length"
357 "Test that '%reset in' preserves In[] length"
354 _ip.run_cell("print 'foo'")
358 _ip.run_cell("print 'foo'")
355 _ip.run_cell("reset -f in")
359 _ip.run_cell("reset -f in")
356 nt.assert_equal(len(_ip.user_ns['In']), _ip.displayhook.prompt_count+1)
360 assert len(_ip.user_ns["In"]) == _ip.displayhook.prompt_count + 1
361
357
362
358 class TestResetErrors(TestCase):
363 class TestResetErrors(TestCase):
359
364
360 def test_reset_redefine(self):
365 def test_reset_redefine(self):
361
366
362 @magics_class
367 @magics_class
363 class KernelMagics(Magics):
368 class KernelMagics(Magics):
364 @line_magic
369 @line_magic
365 def less(self, shell): pass
370 def less(self, shell): pass
366
371
367 _ip.register_magics(KernelMagics)
372 _ip.register_magics(KernelMagics)
368
373
369 with self.assertLogs() as cm:
374 with self.assertLogs() as cm:
370 # hack, we want to just capture logs, but assertLogs fails if not
375 # hack, we want to just capture logs, but assertLogs fails if not
371 # logs get produce.
376 # logs get produce.
372 # so log one things we ignore.
377 # so log one things we ignore.
373 import logging as log_mod
378 import logging as log_mod
374 log = log_mod.getLogger()
379 log = log_mod.getLogger()
375 log.info('Nothing')
380 log.info('Nothing')
376 # end hack.
381 # end hack.
377 _ip.run_cell("reset -f")
382 _ip.run_cell("reset -f")
378
383
379 assert len(cm.output) == 1
384 assert len(cm.output) == 1
380 for out in cm.output:
385 for out in cm.output:
381 assert "Invalid alias" not in out
386 assert "Invalid alias" not in out
382
387
383 def test_tb_syntaxerror():
388 def test_tb_syntaxerror():
384 """test %tb after a SyntaxError"""
389 """test %tb after a SyntaxError"""
385 ip = get_ipython()
390 ip = get_ipython()
386 ip.run_cell("for")
391 ip.run_cell("for")
387
392
388 # trap and validate stdout
393 # trap and validate stdout
389 save_stdout = sys.stdout
394 save_stdout = sys.stdout
390 try:
395 try:
391 sys.stdout = StringIO()
396 sys.stdout = StringIO()
392 ip.run_cell("%tb")
397 ip.run_cell("%tb")
393 out = sys.stdout.getvalue()
398 out = sys.stdout.getvalue()
394 finally:
399 finally:
395 sys.stdout = save_stdout
400 sys.stdout = save_stdout
396 # trim output, and only check the last line
401 # trim output, and only check the last line
397 last_line = out.rstrip().splitlines()[-1].strip()
402 last_line = out.rstrip().splitlines()[-1].strip()
398 nt.assert_equal(last_line, "SyntaxError: invalid syntax")
403 assert last_line == "SyntaxError: invalid syntax"
399
404
400
405
401 def test_time():
406 def test_time():
402 ip = get_ipython()
407 ip = get_ipython()
403
408
404 with tt.AssertPrints("Wall time: "):
409 with tt.AssertPrints("Wall time: "):
405 ip.run_cell("%time None")
410 ip.run_cell("%time None")
406
411
407 ip.run_cell("def f(kmjy):\n"
412 ip.run_cell("def f(kmjy):\n"
408 " %time print (2*kmjy)")
413 " %time print (2*kmjy)")
409
414
410 with tt.AssertPrints("Wall time: "):
415 with tt.AssertPrints("Wall time: "):
411 with tt.AssertPrints("hihi", suppress=False):
416 with tt.AssertPrints("hihi", suppress=False):
412 ip.run_cell("f('hi')")
417 ip.run_cell("f('hi')")
413
418
414 def test_time_last_not_expression():
419 def test_time_last_not_expression():
415 ip.run_cell("%%time\n"
420 ip.run_cell("%%time\n"
416 "var_1 = 1\n"
421 "var_1 = 1\n"
417 "var_2 = 2\n")
422 "var_2 = 2\n")
418 assert ip.user_ns['var_1'] == 1
423 assert ip.user_ns['var_1'] == 1
419 del ip.user_ns['var_1']
424 del ip.user_ns['var_1']
420 assert ip.user_ns['var_2'] == 2
425 assert ip.user_ns['var_2'] == 2
421 del ip.user_ns['var_2']
426 del ip.user_ns['var_2']
422
427
423
428
424 @dec.skip_win32
429 @dec.skip_win32
425 def test_time2():
430 def test_time2():
426 ip = get_ipython()
431 ip = get_ipython()
427
432
428 with tt.AssertPrints("CPU times: user "):
433 with tt.AssertPrints("CPU times: user "):
429 ip.run_cell("%time None")
434 ip.run_cell("%time None")
430
435
431 def test_time3():
436 def test_time3():
432 """Erroneous magic function calls, issue gh-3334"""
437 """Erroneous magic function calls, issue gh-3334"""
433 ip = get_ipython()
438 ip = get_ipython()
434 ip.user_ns.pop('run', None)
439 ip.user_ns.pop('run', None)
435
440
436 with tt.AssertNotPrints("not found", channel='stderr'):
441 with tt.AssertNotPrints("not found", channel='stderr'):
437 ip.run_cell("%%time\n"
442 ip.run_cell("%%time\n"
438 "run = 0\n"
443 "run = 0\n"
439 "run += 1")
444 "run += 1")
440
445
441 def test_multiline_time():
446 def test_multiline_time():
442 """Make sure last statement from time return a value."""
447 """Make sure last statement from time return a value."""
443 ip = get_ipython()
448 ip = get_ipython()
444 ip.user_ns.pop('run', None)
449 ip.user_ns.pop('run', None)
445
450
446 ip.run_cell(dedent("""\
451 ip.run_cell(dedent("""\
447 %%time
452 %%time
448 a = "ho"
453 a = "ho"
449 b = "hey"
454 b = "hey"
450 a+b
455 a+b
451 """))
456 """
452 nt.assert_equal(ip.user_ns_hidden['_'], 'hohey')
457 )
458 )
459 assert ip.user_ns_hidden["_"] == "hohey"
460
453
461
454 def test_time_local_ns():
462 def test_time_local_ns():
455 """
463 """
456 Test that local_ns is actually global_ns when running a cell magic
464 Test that local_ns is actually global_ns when running a cell magic
457 """
465 """
458 ip = get_ipython()
466 ip = get_ipython()
459 ip.run_cell("%%time\n"
467 ip.run_cell("%%time\n" "myvar = 1")
460 "myvar = 1")
468 assert ip.user_ns["myvar"] == 1
461 nt.assert_equal(ip.user_ns['myvar'], 1)
469 del ip.user_ns["myvar"]
462 del ip.user_ns['myvar']
470
463
471
464 def test_doctest_mode():
472 def test_doctest_mode():
465 "Toggle doctest_mode twice, it should be a no-op and run without error"
473 "Toggle doctest_mode twice, it should be a no-op and run without error"
466 _ip.magic('doctest_mode')
474 _ip.magic('doctest_mode')
467 _ip.magic('doctest_mode')
475 _ip.magic('doctest_mode')
468
476
469
477
470 def test_parse_options():
478 def test_parse_options():
471 """Tests for basic options parsing in magics."""
479 """Tests for basic options parsing in magics."""
472 # These are only the most minimal of tests, more should be added later. At
480 # These are only the most minimal of tests, more should be added later. At
473 # the very least we check that basic text/unicode calls work OK.
481 # the very least we check that basic text/unicode calls work OK.
474 m = DummyMagics(_ip)
482 m = DummyMagics(_ip)
475 nt.assert_equal(m.parse_options('foo', '')[1], 'foo')
483 assert m.parse_options("foo", "")[1] == "foo"
476 nt.assert_equal(m.parse_options(u'foo', '')[1], u'foo')
484 assert m.parse_options("foo", "")[1] == "foo"
477
485
478
486
479 def test_parse_options_preserve_non_option_string():
487 def test_parse_options_preserve_non_option_string():
480 """Test to assert preservation of non-option part of magic-block, while parsing magic options."""
488 """Test to assert preservation of non-option part of magic-block, while parsing magic options."""
481 m = DummyMagics(_ip)
489 m = DummyMagics(_ip)
482 opts, stmt = m.parse_options(
490 opts, stmt = m.parse_options(
483 " -n1 -r 13 _ = 314 + foo", "n:r:", preserve_non_opts=True
491 " -n1 -r 13 _ = 314 + foo", "n:r:", preserve_non_opts=True
484 )
492 )
485 nt.assert_equal(opts, {"n": "1", "r": "13"})
493 assert opts == {"n": "1", "r": "13"}
486 nt.assert_equal(stmt, "_ = 314 + foo")
494 assert stmt == "_ = 314 + foo"
487
495
488
496
489 def test_run_magic_preserve_code_block():
497 def test_run_magic_preserve_code_block():
490 """Test to assert preservation of non-option part of magic-block, while running magic."""
498 """Test to assert preservation of non-option part of magic-block, while running magic."""
491 _ip.user_ns["spaces"] = []
499 _ip.user_ns["spaces"] = []
492 _ip.magic("timeit -n1 -r1 spaces.append([s.count(' ') for s in ['document']])")
500 _ip.magic("timeit -n1 -r1 spaces.append([s.count(' ') for s in ['document']])")
493 assert _ip.user_ns["spaces"] == [[0]]
501 assert _ip.user_ns["spaces"] == [[0]]
494
502
495
503
496 def test_dirops():
504 def test_dirops():
497 """Test various directory handling operations."""
505 """Test various directory handling operations."""
498 # curpath = lambda :os.path.splitdrive(os.getcwd())[1].replace('\\','/')
506 # curpath = lambda :os.path.splitdrive(os.getcwd())[1].replace('\\','/')
499 curpath = os.getcwd
507 curpath = os.getcwd
500 startdir = os.getcwd()
508 startdir = os.getcwd()
501 ipdir = os.path.realpath(_ip.ipython_dir)
509 ipdir = os.path.realpath(_ip.ipython_dir)
502 try:
510 try:
503 _ip.magic('cd "%s"' % ipdir)
511 _ip.magic('cd "%s"' % ipdir)
504 nt.assert_equal(curpath(), ipdir)
512 assert curpath() == ipdir
505 _ip.magic('cd -')
513 _ip.magic('cd -')
506 nt.assert_equal(curpath(), startdir)
514 assert curpath() == startdir
507 _ip.magic('pushd "%s"' % ipdir)
515 _ip.magic('pushd "%s"' % ipdir)
508 nt.assert_equal(curpath(), ipdir)
516 assert curpath() == ipdir
509 _ip.magic('popd')
517 _ip.magic('popd')
510 nt.assert_equal(curpath(), startdir)
518 assert curpath() == startdir
511 finally:
519 finally:
512 os.chdir(startdir)
520 os.chdir(startdir)
513
521
514
522
515 def test_cd_force_quiet():
523 def test_cd_force_quiet():
516 """Test OSMagics.cd_force_quiet option"""
524 """Test OSMagics.cd_force_quiet option"""
517 _ip.config.OSMagics.cd_force_quiet = True
525 _ip.config.OSMagics.cd_force_quiet = True
518 osmagics = osm.OSMagics(shell=_ip)
526 osmagics = osm.OSMagics(shell=_ip)
519
527
520 startdir = os.getcwd()
528 startdir = os.getcwd()
521 ipdir = os.path.realpath(_ip.ipython_dir)
529 ipdir = os.path.realpath(_ip.ipython_dir)
522
530
523 try:
531 try:
524 with tt.AssertNotPrints(ipdir):
532 with tt.AssertNotPrints(ipdir):
525 osmagics.cd('"%s"' % ipdir)
533 osmagics.cd('"%s"' % ipdir)
526 with tt.AssertNotPrints(startdir):
534 with tt.AssertNotPrints(startdir):
527 osmagics.cd('-')
535 osmagics.cd('-')
528 finally:
536 finally:
529 os.chdir(startdir)
537 os.chdir(startdir)
530
538
531
539
532 def test_xmode():
540 def test_xmode():
533 # Calling xmode three times should be a no-op
541 # Calling xmode three times should be a no-op
534 xmode = _ip.InteractiveTB.mode
542 xmode = _ip.InteractiveTB.mode
535 for i in range(4):
543 for i in range(4):
536 _ip.magic("xmode")
544 _ip.magic("xmode")
537 nt.assert_equal(_ip.InteractiveTB.mode, xmode)
545 assert _ip.InteractiveTB.mode == xmode
538
546
539 def test_reset_hard():
547 def test_reset_hard():
540 monitor = []
548 monitor = []
541 class A(object):
549 class A(object):
542 def __del__(self):
550 def __del__(self):
543 monitor.append(1)
551 monitor.append(1)
544 def __repr__(self):
552 def __repr__(self):
545 return "<A instance>"
553 return "<A instance>"
546
554
547 _ip.user_ns["a"] = A()
555 _ip.user_ns["a"] = A()
548 _ip.run_cell("a")
556 _ip.run_cell("a")
549
557
550 nt.assert_equal(monitor, [])
558 assert monitor == []
551 _ip.magic("reset -f")
559 _ip.magic("reset -f")
552 nt.assert_equal(monitor, [1])
560 assert monitor == [1]
553
561
554 class TestXdel(tt.TempFileMixin):
562 class TestXdel(tt.TempFileMixin):
555 def test_xdel(self):
563 def test_xdel(self):
556 """Test that references from %run are cleared by xdel."""
564 """Test that references from %run are cleared by xdel."""
557 src = ("class A(object):\n"
565 src = ("class A(object):\n"
558 " monitor = []\n"
566 " monitor = []\n"
559 " def __del__(self):\n"
567 " def __del__(self):\n"
560 " self.monitor.append(1)\n"
568 " self.monitor.append(1)\n"
561 "a = A()\n")
569 "a = A()\n")
562 self.mktmp(src)
570 self.mktmp(src)
563 # %run creates some hidden references...
571 # %run creates some hidden references...
564 _ip.magic("run %s" % self.fname)
572 _ip.magic("run %s" % self.fname)
565 # ... as does the displayhook.
573 # ... as does the displayhook.
566 _ip.run_cell("a")
574 _ip.run_cell("a")
567
575
568 monitor = _ip.user_ns["A"].monitor
576 monitor = _ip.user_ns["A"].monitor
569 nt.assert_equal(monitor, [])
577 assert monitor == []
570
578
571 _ip.magic("xdel a")
579 _ip.magic("xdel a")
572
580
573 # Check that a's __del__ method has been called.
581 # Check that a's __del__ method has been called.
574 nt.assert_equal(monitor, [1])
582 assert monitor == [1]
575
583
576 def doctest_who():
584 def doctest_who():
577 """doctest for %who
585 """doctest for %who
578
586
579 In [1]: %reset -f
587 In [1]: %reset -f
580
588
581 In [2]: alpha = 123
589 In [2]: alpha = 123
582
590
583 In [3]: beta = 'beta'
591 In [3]: beta = 'beta'
584
592
585 In [4]: %who int
593 In [4]: %who int
586 alpha
594 alpha
587
595
588 In [5]: %who str
596 In [5]: %who str
589 beta
597 beta
590
598
591 In [6]: %whos
599 In [6]: %whos
592 Variable Type Data/Info
600 Variable Type Data/Info
593 ----------------------------
601 ----------------------------
594 alpha int 123
602 alpha int 123
595 beta str beta
603 beta str beta
596
604
597 In [7]: %who_ls
605 In [7]: %who_ls
598 Out[7]: ['alpha', 'beta']
606 Out[7]: ['alpha', 'beta']
599 """
607 """
600
608
601 def test_whos():
609 def test_whos():
602 """Check that whos is protected against objects where repr() fails."""
610 """Check that whos is protected against objects where repr() fails."""
603 class A(object):
611 class A(object):
604 def __repr__(self):
612 def __repr__(self):
605 raise Exception()
613 raise Exception()
606 _ip.user_ns['a'] = A()
614 _ip.user_ns['a'] = A()
607 _ip.magic("whos")
615 _ip.magic("whos")
608
616
609 def doctest_precision():
617 def doctest_precision():
610 """doctest for %precision
618 """doctest for %precision
611
619
612 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
620 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
613
621
614 In [2]: %precision 5
622 In [2]: %precision 5
615 Out[2]: '%.5f'
623 Out[2]: '%.5f'
616
624
617 In [3]: f.float_format
625 In [3]: f.float_format
618 Out[3]: '%.5f'
626 Out[3]: '%.5f'
619
627
620 In [4]: %precision %e
628 In [4]: %precision %e
621 Out[4]: '%e'
629 Out[4]: '%e'
622
630
623 In [5]: f(3.1415927)
631 In [5]: f(3.1415927)
624 Out[5]: '3.141593e+00'
632 Out[5]: '3.141593e+00'
625 """
633 """
626
634
627 def test_debug_magic():
635 def test_debug_magic():
628 """Test debugging a small code with %debug
636 """Test debugging a small code with %debug
629
637
630 In [1]: with PdbTestInput(['c']):
638 In [1]: with PdbTestInput(['c']):
631 ...: %debug print("a b") #doctest: +ELLIPSIS
639 ...: %debug print("a b") #doctest: +ELLIPSIS
632 ...:
640 ...:
633 ...
641 ...
634 ipdb> c
642 ipdb> c
635 a b
643 a b
636 In [2]:
644 In [2]:
637 """
645 """
638
646
639 def test_psearch():
647 def test_psearch():
640 with tt.AssertPrints("dict.fromkeys"):
648 with tt.AssertPrints("dict.fromkeys"):
641 _ip.run_cell("dict.fr*?")
649 _ip.run_cell("dict.fr*?")
642 with tt.AssertPrints("π.is_integer"):
650 with tt.AssertPrints("π.is_integer"):
643 _ip.run_cell("π = 3.14;\nπ.is_integ*?")
651 _ip.run_cell("π = 3.14;\nπ.is_integ*?")
644
652
645 def test_timeit_shlex():
653 def test_timeit_shlex():
646 """test shlex issues with timeit (#1109)"""
654 """test shlex issues with timeit (#1109)"""
647 _ip.ex("def f(*a,**kw): pass")
655 _ip.ex("def f(*a,**kw): pass")
648 _ip.magic('timeit -n1 "this is a bug".count(" ")')
656 _ip.magic('timeit -n1 "this is a bug".count(" ")')
649 _ip.magic('timeit -r1 -n1 f(" ", 1)')
657 _ip.magic('timeit -r1 -n1 f(" ", 1)')
650 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
658 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
651 _ip.magic('timeit -r1 -n1 ("a " + "b")')
659 _ip.magic('timeit -r1 -n1 ("a " + "b")')
652 _ip.magic('timeit -r1 -n1 f("a " + "b")')
660 _ip.magic('timeit -r1 -n1 f("a " + "b")')
653 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
661 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
654
662
655
663
656 def test_timeit_special_syntax():
664 def test_timeit_special_syntax():
657 "Test %%timeit with IPython special syntax"
665 "Test %%timeit with IPython special syntax"
658 @register_line_magic
666 @register_line_magic
659 def lmagic(line):
667 def lmagic(line):
660 ip = get_ipython()
668 ip = get_ipython()
661 ip.user_ns['lmagic_out'] = line
669 ip.user_ns['lmagic_out'] = line
662
670
663 # line mode test
671 # line mode test
664 _ip.run_line_magic('timeit', '-n1 -r1 %lmagic my line')
672 _ip.run_line_magic("timeit", "-n1 -r1 %lmagic my line")
665 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
673 assert _ip.user_ns["lmagic_out"] == "my line"
666 # cell mode test
674 # cell mode test
667 _ip.run_cell_magic('timeit', '-n1 -r1', '%lmagic my line2')
675 _ip.run_cell_magic("timeit", "-n1 -r1", "%lmagic my line2")
668 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
676 assert _ip.user_ns["lmagic_out"] == "my line2"
677
669
678
670 def test_timeit_return():
679 def test_timeit_return():
671 """
680 """
672 test whether timeit -o return object
681 test whether timeit -o return object
673 """
682 """
674
683
675 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
684 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
676 assert(res is not None)
685 assert(res is not None)
677
686
678 def test_timeit_quiet():
687 def test_timeit_quiet():
679 """
688 """
680 test quiet option of timeit magic
689 test quiet option of timeit magic
681 """
690 """
682 with tt.AssertNotPrints("loops"):
691 with tt.AssertNotPrints("loops"):
683 _ip.run_cell("%timeit -n1 -r1 -q 1")
692 _ip.run_cell("%timeit -n1 -r1 -q 1")
684
693
685 def test_timeit_return_quiet():
694 def test_timeit_return_quiet():
686 with tt.AssertNotPrints("loops"):
695 with tt.AssertNotPrints("loops"):
687 res = _ip.run_line_magic('timeit', '-n1 -r1 -q -o 1')
696 res = _ip.run_line_magic('timeit', '-n1 -r1 -q -o 1')
688 assert (res is not None)
697 assert (res is not None)
689
698
690 def test_timeit_invalid_return():
699 def test_timeit_invalid_return():
691 with nt.assert_raises_regex(SyntaxError, "outside function"):
700 with pytest.raises(SyntaxError):
692 _ip.run_line_magic('timeit', 'return')
701 _ip.run_line_magic('timeit', 'return')
693
702
694 @dec.skipif(execution.profile is None)
703 @dec.skipif(execution.profile is None)
695 def test_prun_special_syntax():
704 def test_prun_special_syntax():
696 "Test %%prun with IPython special syntax"
705 "Test %%prun with IPython special syntax"
697 @register_line_magic
706 @register_line_magic
698 def lmagic(line):
707 def lmagic(line):
699 ip = get_ipython()
708 ip = get_ipython()
700 ip.user_ns['lmagic_out'] = line
709 ip.user_ns['lmagic_out'] = line
701
710
702 # line mode test
711 # line mode test
703 _ip.run_line_magic('prun', '-q %lmagic my line')
712 _ip.run_line_magic("prun", "-q %lmagic my line")
704 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
713 assert _ip.user_ns["lmagic_out"] == "my line"
705 # cell mode test
714 # cell mode test
706 _ip.run_cell_magic('prun', '-q', '%lmagic my line2')
715 _ip.run_cell_magic("prun", "-q", "%lmagic my line2")
707 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
716 assert _ip.user_ns["lmagic_out"] == "my line2"
717
708
718
709 @dec.skipif(execution.profile is None)
719 @dec.skipif(execution.profile is None)
710 def test_prun_quotes():
720 def test_prun_quotes():
711 "Test that prun does not clobber string escapes (GH #1302)"
721 "Test that prun does not clobber string escapes (GH #1302)"
712 _ip.magic(r"prun -q x = '\t'")
722 _ip.magic(r"prun -q x = '\t'")
713 nt.assert_equal(_ip.user_ns['x'], '\t')
723 assert _ip.user_ns["x"] == "\t"
724
714
725
715 def test_extension():
726 def test_extension():
716 # Debugging information for failures of this test
727 # Debugging information for failures of this test
717 print('sys.path:')
728 print('sys.path:')
718 for p in sys.path:
729 for p in sys.path:
719 print(' ', p)
730 print(' ', p)
720 print('CWD', os.getcwd())
731 print('CWD', os.getcwd())
721
732
722 nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension")
733 pytest.raises(ImportError, _ip.magic, "load_ext daft_extension")
723 daft_path = os.path.join(os.path.dirname(__file__), "daft_extension")
734 daft_path = os.path.join(os.path.dirname(__file__), "daft_extension")
724 sys.path.insert(0, daft_path)
735 sys.path.insert(0, daft_path)
725 try:
736 try:
726 _ip.user_ns.pop('arq', None)
737 _ip.user_ns.pop('arq', None)
727 invalidate_caches() # Clear import caches
738 invalidate_caches() # Clear import caches
728 _ip.magic("load_ext daft_extension")
739 _ip.magic("load_ext daft_extension")
729 nt.assert_equal(_ip.user_ns['arq'], 185)
740 assert _ip.user_ns["arq"] == 185
730 _ip.magic("unload_ext daft_extension")
741 _ip.magic("unload_ext daft_extension")
731 assert 'arq' not in _ip.user_ns
742 assert 'arq' not in _ip.user_ns
732 finally:
743 finally:
733 sys.path.remove(daft_path)
744 sys.path.remove(daft_path)
734
745
735
746
736 def test_notebook_export_json():
747 def test_notebook_export_json():
737 _ip = get_ipython()
748 _ip = get_ipython()
738 _ip.history_manager.reset() # Clear any existing history.
749 _ip.history_manager.reset() # Clear any existing history.
739 cmds = [u"a=1", u"def b():\n return a**2", u"print('noël, été', b())"]
750 cmds = ["a=1", "def b():\n return a**2", "print('noël, été', b())"]
740 for i, cmd in enumerate(cmds, start=1):
751 for i, cmd in enumerate(cmds, start=1):
741 _ip.history_manager.store_inputs(i, cmd)
752 _ip.history_manager.store_inputs(i, cmd)
742 with TemporaryDirectory() as td:
753 with TemporaryDirectory() as td:
743 outfile = os.path.join(td, "nb.ipynb")
754 outfile = os.path.join(td, "nb.ipynb")
744 _ip.magic("notebook -e %s" % outfile)
755 _ip.magic("notebook -e %s" % outfile)
745
756
746
757
747 class TestEnv(TestCase):
758 class TestEnv(TestCase):
748
759
749 def test_env(self):
760 def test_env(self):
750 env = _ip.magic("env")
761 env = _ip.magic("env")
751 self.assertTrue(isinstance(env, dict))
762 self.assertTrue(isinstance(env, dict))
752
763
753 def test_env_secret(self):
764 def test_env_secret(self):
754 env = _ip.magic("env")
765 env = _ip.magic("env")
755 hidden = "<hidden>"
766 hidden = "<hidden>"
756 with mock.patch.dict(
767 with mock.patch.dict(
757 os.environ,
768 os.environ,
758 {
769 {
759 "API_KEY": "abc123",
770 "API_KEY": "abc123",
760 "SECRET_THING": "ssshhh",
771 "SECRET_THING": "ssshhh",
761 "JUPYTER_TOKEN": "",
772 "JUPYTER_TOKEN": "",
762 "VAR": "abc"
773 "VAR": "abc"
763 }
774 }
764 ):
775 ):
765 env = _ip.magic("env")
776 env = _ip.magic("env")
766 assert env["API_KEY"] == hidden
777 assert env["API_KEY"] == hidden
767 assert env["SECRET_THING"] == hidden
778 assert env["SECRET_THING"] == hidden
768 assert env["JUPYTER_TOKEN"] == hidden
779 assert env["JUPYTER_TOKEN"] == hidden
769 assert env["VAR"] == "abc"
780 assert env["VAR"] == "abc"
770
781
771 def test_env_get_set_simple(self):
782 def test_env_get_set_simple(self):
772 env = _ip.magic("env var val1")
783 env = _ip.magic("env var val1")
773 self.assertEqual(env, None)
784 self.assertEqual(env, None)
774 self.assertEqual(os.environ['var'], 'val1')
785 self.assertEqual(os.environ['var'], 'val1')
775 self.assertEqual(_ip.magic("env var"), 'val1')
786 self.assertEqual(_ip.magic("env var"), 'val1')
776 env = _ip.magic("env var=val2")
787 env = _ip.magic("env var=val2")
777 self.assertEqual(env, None)
788 self.assertEqual(env, None)
778 self.assertEqual(os.environ['var'], 'val2')
789 self.assertEqual(os.environ['var'], 'val2')
779
790
780 def test_env_get_set_complex(self):
791 def test_env_get_set_complex(self):
781 env = _ip.magic("env var 'val1 '' 'val2")
792 env = _ip.magic("env var 'val1 '' 'val2")
782 self.assertEqual(env, None)
793 self.assertEqual(env, None)
783 self.assertEqual(os.environ['var'], "'val1 '' 'val2")
794 self.assertEqual(os.environ['var'], "'val1 '' 'val2")
784 self.assertEqual(_ip.magic("env var"), "'val1 '' 'val2")
795 self.assertEqual(_ip.magic("env var"), "'val1 '' 'val2")
785 env = _ip.magic('env var=val2 val3="val4')
796 env = _ip.magic('env var=val2 val3="val4')
786 self.assertEqual(env, None)
797 self.assertEqual(env, None)
787 self.assertEqual(os.environ['var'], 'val2 val3="val4')
798 self.assertEqual(os.environ['var'], 'val2 val3="val4')
788
799
789 def test_env_set_bad_input(self):
800 def test_env_set_bad_input(self):
790 self.assertRaises(UsageError, lambda: _ip.magic("set_env var"))
801 self.assertRaises(UsageError, lambda: _ip.magic("set_env var"))
791
802
792 def test_env_set_whitespace(self):
803 def test_env_set_whitespace(self):
793 self.assertRaises(UsageError, lambda: _ip.magic("env var A=B"))
804 self.assertRaises(UsageError, lambda: _ip.magic("env var A=B"))
794
805
795
806
796 class CellMagicTestCase(TestCase):
807 class CellMagicTestCase(TestCase):
797
808
798 def check_ident(self, magic):
809 def check_ident(self, magic):
799 # Manually called, we get the result
810 # Manually called, we get the result
800 out = _ip.run_cell_magic(magic, 'a', 'b')
811 out = _ip.run_cell_magic(magic, "a", "b")
801 nt.assert_equal(out, ('a','b'))
812 assert out == ("a", "b")
802 # Via run_cell, it goes into the user's namespace via displayhook
813 # Via run_cell, it goes into the user's namespace via displayhook
803 _ip.run_cell('%%' + magic +' c\nd\n')
814 _ip.run_cell("%%" + magic + " c\nd\n")
804 nt.assert_equal(_ip.user_ns['_'], ('c','d\n'))
815 assert _ip.user_ns["_"] == ("c", "d\n")
805
816
806 def test_cell_magic_func_deco(self):
817 def test_cell_magic_func_deco(self):
807 "Cell magic using simple decorator"
818 "Cell magic using simple decorator"
808 @register_cell_magic
819 @register_cell_magic
809 def cellm(line, cell):
820 def cellm(line, cell):
810 return line, cell
821 return line, cell
811
822
812 self.check_ident('cellm')
823 self.check_ident('cellm')
813
824
814 def test_cell_magic_reg(self):
825 def test_cell_magic_reg(self):
815 "Cell magic manually registered"
826 "Cell magic manually registered"
816 def cellm(line, cell):
827 def cellm(line, cell):
817 return line, cell
828 return line, cell
818
829
819 _ip.register_magic_function(cellm, 'cell', 'cellm2')
830 _ip.register_magic_function(cellm, 'cell', 'cellm2')
820 self.check_ident('cellm2')
831 self.check_ident('cellm2')
821
832
822 def test_cell_magic_class(self):
833 def test_cell_magic_class(self):
823 "Cell magics declared via a class"
834 "Cell magics declared via a class"
824 @magics_class
835 @magics_class
825 class MyMagics(Magics):
836 class MyMagics(Magics):
826
837
827 @cell_magic
838 @cell_magic
828 def cellm3(self, line, cell):
839 def cellm3(self, line, cell):
829 return line, cell
840 return line, cell
830
841
831 _ip.register_magics(MyMagics)
842 _ip.register_magics(MyMagics)
832 self.check_ident('cellm3')
843 self.check_ident('cellm3')
833
844
834 def test_cell_magic_class2(self):
845 def test_cell_magic_class2(self):
835 "Cell magics declared via a class, #2"
846 "Cell magics declared via a class, #2"
836 @magics_class
847 @magics_class
837 class MyMagics2(Magics):
848 class MyMagics2(Magics):
838
849
839 @cell_magic('cellm4')
850 @cell_magic('cellm4')
840 def cellm33(self, line, cell):
851 def cellm33(self, line, cell):
841 return line, cell
852 return line, cell
842
853
843 _ip.register_magics(MyMagics2)
854 _ip.register_magics(MyMagics2)
844 self.check_ident('cellm4')
855 self.check_ident('cellm4')
845 # Check that nothing is registered as 'cellm33'
856 # Check that nothing is registered as 'cellm33'
846 c33 = _ip.find_cell_magic('cellm33')
857 c33 = _ip.find_cell_magic('cellm33')
847 nt.assert_equal(c33, None)
858 assert c33 == None
848
859
849 def test_file():
860 def test_file():
850 """Basic %%writefile"""
861 """Basic %%writefile"""
851 ip = get_ipython()
862 ip = get_ipython()
852 with TemporaryDirectory() as td:
863 with TemporaryDirectory() as td:
853 fname = os.path.join(td, 'file1')
864 fname = os.path.join(td, 'file1')
854 ip.run_cell_magic("writefile", fname, u'\n'.join([
865 ip.run_cell_magic("writefile", fname, u'\n'.join([
855 'line1',
866 'line1',
856 'line2',
867 'line2',
857 ]))
868 ]))
858 s = Path(fname).read_text()
869 s = Path(fname).read_text()
859 nt.assert_in('line1\n', s)
870 assert "line1\n" in s
860 nt.assert_in('line2', s)
871 assert "line2" in s
872
861
873
862 @dec.skip_win32
874 @dec.skip_win32
863 def test_file_single_quote():
875 def test_file_single_quote():
864 """Basic %%writefile with embedded single quotes"""
876 """Basic %%writefile with embedded single quotes"""
865 ip = get_ipython()
877 ip = get_ipython()
866 with TemporaryDirectory() as td:
878 with TemporaryDirectory() as td:
867 fname = os.path.join(td, '\'file1\'')
879 fname = os.path.join(td, '\'file1\'')
868 ip.run_cell_magic("writefile", fname, u'\n'.join([
880 ip.run_cell_magic("writefile", fname, u'\n'.join([
869 'line1',
881 'line1',
870 'line2',
882 'line2',
871 ]))
883 ]))
872 s = Path(fname).read_text()
884 s = Path(fname).read_text()
873 nt.assert_in('line1\n', s)
885 assert "line1\n" in s
874 nt.assert_in('line2', s)
886 assert "line2" in s
887
875
888
876 @dec.skip_win32
889 @dec.skip_win32
877 def test_file_double_quote():
890 def test_file_double_quote():
878 """Basic %%writefile with embedded double quotes"""
891 """Basic %%writefile with embedded double quotes"""
879 ip = get_ipython()
892 ip = get_ipython()
880 with TemporaryDirectory() as td:
893 with TemporaryDirectory() as td:
881 fname = os.path.join(td, '"file1"')
894 fname = os.path.join(td, '"file1"')
882 ip.run_cell_magic("writefile", fname, u'\n'.join([
895 ip.run_cell_magic("writefile", fname, u'\n'.join([
883 'line1',
896 'line1',
884 'line2',
897 'line2',
885 ]))
898 ]))
886 s = Path(fname).read_text()
899 s = Path(fname).read_text()
887 nt.assert_in('line1\n', s)
900 assert "line1\n" in s
888 nt.assert_in('line2', s)
901 assert "line2" in s
902
889
903
890 def test_file_var_expand():
904 def test_file_var_expand():
891 """%%writefile $filename"""
905 """%%writefile $filename"""
892 ip = get_ipython()
906 ip = get_ipython()
893 with TemporaryDirectory() as td:
907 with TemporaryDirectory() as td:
894 fname = os.path.join(td, 'file1')
908 fname = os.path.join(td, 'file1')
895 ip.user_ns['filename'] = fname
909 ip.user_ns['filename'] = fname
896 ip.run_cell_magic("writefile", '$filename', u'\n'.join([
910 ip.run_cell_magic("writefile", '$filename', u'\n'.join([
897 'line1',
911 'line1',
898 'line2',
912 'line2',
899 ]))
913 ]))
900 s = Path(fname).read_text()
914 s = Path(fname).read_text()
901 nt.assert_in('line1\n', s)
915 assert "line1\n" in s
902 nt.assert_in('line2', s)
916 assert "line2" in s
917
903
918
904 def test_file_unicode():
919 def test_file_unicode():
905 """%%writefile with unicode cell"""
920 """%%writefile with unicode cell"""
906 ip = get_ipython()
921 ip = get_ipython()
907 with TemporaryDirectory() as td:
922 with TemporaryDirectory() as td:
908 fname = os.path.join(td, 'file1')
923 fname = os.path.join(td, 'file1')
909 ip.run_cell_magic("writefile", fname, u'\n'.join([
924 ip.run_cell_magic("writefile", fname, u'\n'.join([
910 u'liné1',
925 u'liné1',
911 u'liné2',
926 u'liné2',
912 ]))
927 ]))
913 with io.open(fname, encoding='utf-8') as f:
928 with io.open(fname, encoding='utf-8') as f:
914 s = f.read()
929 s = f.read()
915 nt.assert_in(u'liné1\n', s)
930 assert "liné1\n" in s
916 nt.assert_in(u'liné2', s)
931 assert "liné2" in s
932
917
933
918 def test_file_amend():
934 def test_file_amend():
919 """%%writefile -a amends files"""
935 """%%writefile -a amends files"""
920 ip = get_ipython()
936 ip = get_ipython()
921 with TemporaryDirectory() as td:
937 with TemporaryDirectory() as td:
922 fname = os.path.join(td, 'file2')
938 fname = os.path.join(td, 'file2')
923 ip.run_cell_magic("writefile", fname, u'\n'.join([
939 ip.run_cell_magic("writefile", fname, u'\n'.join([
924 'line1',
940 'line1',
925 'line2',
941 'line2',
926 ]))
942 ]))
927 ip.run_cell_magic("writefile", "-a %s" % fname, u'\n'.join([
943 ip.run_cell_magic("writefile", "-a %s" % fname, u'\n'.join([
928 'line3',
944 'line3',
929 'line4',
945 'line4',
930 ]))
946 ]))
931 s = Path(fname).read_text()
947 s = Path(fname).read_text()
932 nt.assert_in('line1\n', s)
948 assert "line1\n" in s
933 nt.assert_in('line3\n', s)
949 assert "line3\n" in s
950
934
951
935 def test_file_spaces():
952 def test_file_spaces():
936 """%%file with spaces in filename"""
953 """%%file with spaces in filename"""
937 ip = get_ipython()
954 ip = get_ipython()
938 with TemporaryWorkingDirectory() as td:
955 with TemporaryWorkingDirectory() as td:
939 fname = "file name"
956 fname = "file name"
940 ip.run_cell_magic("file", '"%s"'%fname, u'\n'.join([
957 ip.run_cell_magic("file", '"%s"'%fname, u'\n'.join([
941 'line1',
958 'line1',
942 'line2',
959 'line2',
943 ]))
960 ]))
944 s = Path(fname).read_text()
961 s = Path(fname).read_text()
945 nt.assert_in('line1\n', s)
962 assert "line1\n" in s
946 nt.assert_in('line2', s)
963 assert "line2" in s
947
964
965
948 def test_script_config():
966 def test_script_config():
949 ip = get_ipython()
967 ip = get_ipython()
950 ip.config.ScriptMagics.script_magics = ['whoda']
968 ip.config.ScriptMagics.script_magics = ['whoda']
951 sm = script.ScriptMagics(shell=ip)
969 sm = script.ScriptMagics(shell=ip)
952 nt.assert_in('whoda', sm.magics['cell'])
970 assert "whoda" in sm.magics["cell"]
971
953
972
954 @dec.skip_iptest_but_not_pytest
973 @dec.skip_iptest_but_not_pytest
955 @dec.skip_win32
974 @dec.skip_win32
956 @pytest.mark.skipif(
975 @pytest.mark.skipif(
957 sys.platform == "win32", reason="This test does not run under Windows"
976 sys.platform == "win32", reason="This test does not run under Windows"
958 )
977 )
959 def test_script_out():
978 def test_script_out():
960 assert asyncio.get_event_loop().is_running() is False
979 assert asyncio.get_event_loop().is_running() is False
961
980
962 ip = get_ipython()
981 ip = get_ipython()
963 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
982 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
964 assert asyncio.get_event_loop().is_running() is False
983 assert asyncio.get_event_loop().is_running() is False
965 nt.assert_equal(ip.user_ns['output'], 'hi\n')
984 assert ip.user_ns["output"] == "hi\n"
985
966
986
967 @dec.skip_iptest_but_not_pytest
987 @dec.skip_iptest_but_not_pytest
968 @dec.skip_win32
988 @dec.skip_win32
969 @pytest.mark.skipif(
989 @pytest.mark.skipif(
970 sys.platform == "win32", reason="This test does not run under Windows"
990 sys.platform == "win32", reason="This test does not run under Windows"
971 )
991 )
972 def test_script_err():
992 def test_script_err():
973 ip = get_ipython()
993 ip = get_ipython()
974 assert asyncio.get_event_loop().is_running() is False
994 assert asyncio.get_event_loop().is_running() is False
975 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
995 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
976 assert asyncio.get_event_loop().is_running() is False
996 assert asyncio.get_event_loop().is_running() is False
977 nt.assert_equal(ip.user_ns['error'], 'hello\n')
997 assert ip.user_ns["error"] == "hello\n"
978
998
979
999
980 @dec.skip_iptest_but_not_pytest
1000 @dec.skip_iptest_but_not_pytest
981 @dec.skip_win32
1001 @dec.skip_win32
982 @pytest.mark.skipif(
1002 @pytest.mark.skipif(
983 sys.platform == "win32", reason="This test does not run under Windows"
1003 sys.platform == "win32", reason="This test does not run under Windows"
984 )
1004 )
985 def test_script_out_err():
1005 def test_script_out_err():
986
1006
987 ip = get_ipython()
1007 ip = get_ipython()
988 ip.run_cell_magic(
1008 ip.run_cell_magic(
989 "script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2"
1009 "script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2"
990 )
1010 )
991 nt.assert_equal(ip.user_ns["output"], "hi\n")
1011 assert ip.user_ns["output"] == "hi\n"
992 nt.assert_equal(ip.user_ns["error"], "hello\n")
1012 assert ip.user_ns["error"] == "hello\n"
993
1013
994
1014
995 @dec.skip_iptest_but_not_pytest
1015 @dec.skip_iptest_but_not_pytest
996 @dec.skip_win32
1016 @dec.skip_win32
997 @pytest.mark.skipif(
1017 @pytest.mark.skipif(
998 sys.platform == "win32", reason="This test does not run under Windows"
1018 sys.platform == "win32", reason="This test does not run under Windows"
999 )
1019 )
1000 async def test_script_bg_out():
1020 async def test_script_bg_out():
1001 ip = get_ipython()
1021 ip = get_ipython()
1002 ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
1022 ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
1003 nt.assert_equal((await ip.user_ns["output"].read()), b"hi\n")
1023 assert (await ip.user_ns["output"].read()) == b"hi\n"
1004 ip.user_ns["output"].close()
1024 ip.user_ns["output"].close()
1005 asyncio.get_event_loop().stop()
1025 asyncio.get_event_loop().stop()
1006
1026
1027
1007 @dec.skip_iptest_but_not_pytest
1028 @dec.skip_iptest_but_not_pytest
1008 @dec.skip_win32
1029 @dec.skip_win32
1009 @pytest.mark.skipif(
1030 @pytest.mark.skipif(
1010 sys.platform == "win32", reason="This test does not run under Windows"
1031 sys.platform == "win32", reason="This test does not run under Windows"
1011 )
1032 )
1012 async def test_script_bg_err():
1033 async def test_script_bg_err():
1013 ip = get_ipython()
1034 ip = get_ipython()
1014 ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2")
1035 ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2")
1015 nt.assert_equal((await ip.user_ns["error"].read()), b"hello\n")
1036 assert (await ip.user_ns["error"].read()) == b"hello\n"
1016 ip.user_ns["error"].close()
1037 ip.user_ns["error"].close()
1017
1038
1018
1039
1019 @dec.skip_iptest_but_not_pytest
1040 @dec.skip_iptest_but_not_pytest
1020 @dec.skip_win32
1041 @dec.skip_win32
1021 @pytest.mark.skipif(
1042 @pytest.mark.skipif(
1022 sys.platform == "win32", reason="This test does not run under Windows"
1043 sys.platform == "win32", reason="This test does not run under Windows"
1023 )
1044 )
1024 async def test_script_bg_out_err():
1045 async def test_script_bg_out_err():
1025 ip = get_ipython()
1046 ip = get_ipython()
1026 ip.run_cell_magic(
1047 ip.run_cell_magic(
1027 "script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2"
1048 "script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2"
1028 )
1049 )
1029 nt.assert_equal((await ip.user_ns["output"].read()), b"hi\n")
1050 assert (await ip.user_ns["output"].read()) == b"hi\n"
1030 nt.assert_equal((await ip.user_ns["error"].read()), b"hello\n")
1051 assert (await ip.user_ns["error"].read()) == b"hello\n"
1031 ip.user_ns["output"].close()
1052 ip.user_ns["output"].close()
1032 ip.user_ns["error"].close()
1053 ip.user_ns["error"].close()
1033
1054
1034
1055
1035 def test_script_defaults():
1056 def test_script_defaults():
1036 ip = get_ipython()
1057 ip = get_ipython()
1037 for cmd in ['sh', 'bash', 'perl', 'ruby']:
1058 for cmd in ['sh', 'bash', 'perl', 'ruby']:
1038 try:
1059 try:
1039 find_cmd(cmd)
1060 find_cmd(cmd)
1040 except Exception:
1061 except Exception:
1041 pass
1062 pass
1042 else:
1063 else:
1043 nt.assert_in(cmd, ip.magics_manager.magics['cell'])
1064 assert cmd in ip.magics_manager.magics["cell"]
1044
1065
1045
1066
1046 @magics_class
1067 @magics_class
1047 class FooFoo(Magics):
1068 class FooFoo(Magics):
1048 """class with both %foo and %%foo magics"""
1069 """class with both %foo and %%foo magics"""
1049 @line_magic('foo')
1070 @line_magic('foo')
1050 def line_foo(self, line):
1071 def line_foo(self, line):
1051 "I am line foo"
1072 "I am line foo"
1052 pass
1073 pass
1053
1074
1054 @cell_magic("foo")
1075 @cell_magic("foo")
1055 def cell_foo(self, line, cell):
1076 def cell_foo(self, line, cell):
1056 "I am cell foo, not line foo"
1077 "I am cell foo, not line foo"
1057 pass
1078 pass
1058
1079
1059 def test_line_cell_info():
1080 def test_line_cell_info():
1060 """%%foo and %foo magics are distinguishable to inspect"""
1081 """%%foo and %foo magics are distinguishable to inspect"""
1061 ip = get_ipython()
1082 ip = get_ipython()
1062 ip.magics_manager.register(FooFoo)
1083 ip.magics_manager.register(FooFoo)
1063 oinfo = ip.object_inspect('foo')
1084 oinfo = ip.object_inspect("foo")
1064 nt.assert_true(oinfo['found'])
1085 assert oinfo["found"] is True
1065 nt.assert_true(oinfo['ismagic'])
1086 assert oinfo["ismagic"] is True
1066
1087
1067 oinfo = ip.object_inspect('%%foo')
1088 oinfo = ip.object_inspect("%%foo")
1068 nt.assert_true(oinfo['found'])
1089 assert oinfo["found"] is True
1069 nt.assert_true(oinfo['ismagic'])
1090 assert oinfo["ismagic"] is True
1070 nt.assert_equal(oinfo['docstring'], FooFoo.cell_foo.__doc__)
1091 assert oinfo["docstring"] == FooFoo.cell_foo.__doc__
1071
1092
1072 oinfo = ip.object_inspect('%foo')
1093 oinfo = ip.object_inspect("%foo")
1073 nt.assert_true(oinfo['found'])
1094 assert oinfo["found"] is True
1074 nt.assert_true(oinfo['ismagic'])
1095 assert oinfo["ismagic"] is True
1075 nt.assert_equal(oinfo['docstring'], FooFoo.line_foo.__doc__)
1096 assert oinfo["docstring"] == FooFoo.line_foo.__doc__
1097
1076
1098
1077 def test_multiple_magics():
1099 def test_multiple_magics():
1078 ip = get_ipython()
1100 ip = get_ipython()
1079 foo1 = FooFoo(ip)
1101 foo1 = FooFoo(ip)
1080 foo2 = FooFoo(ip)
1102 foo2 = FooFoo(ip)
1081 mm = ip.magics_manager
1103 mm = ip.magics_manager
1082 mm.register(foo1)
1104 mm.register(foo1)
1083 nt.assert_true(mm.magics['line']['foo'].__self__ is foo1)
1105 assert mm.magics["line"]["foo"].__self__ is foo1
1084 mm.register(foo2)
1106 mm.register(foo2)
1085 nt.assert_true(mm.magics['line']['foo'].__self__ is foo2)
1107 assert mm.magics["line"]["foo"].__self__ is foo2
1108
1086
1109
1087 def test_alias_magic():
1110 def test_alias_magic():
1088 """Test %alias_magic."""
1111 """Test %alias_magic."""
1089 ip = get_ipython()
1112 ip = get_ipython()
1090 mm = ip.magics_manager
1113 mm = ip.magics_manager
1091
1114
1092 # Basic operation: both cell and line magics are created, if possible.
1115 # Basic operation: both cell and line magics are created, if possible.
1093 ip.run_line_magic('alias_magic', 'timeit_alias timeit')
1116 ip.run_line_magic("alias_magic", "timeit_alias timeit")
1094 nt.assert_in('timeit_alias', mm.magics['line'])
1117 assert "timeit_alias" in mm.magics["line"]
1095 nt.assert_in('timeit_alias', mm.magics['cell'])
1118 assert "timeit_alias" in mm.magics["cell"]
1096
1119
1097 # --cell is specified, line magic not created.
1120 # --cell is specified, line magic not created.
1098 ip.run_line_magic('alias_magic', '--cell timeit_cell_alias timeit')
1121 ip.run_line_magic("alias_magic", "--cell timeit_cell_alias timeit")
1099 nt.assert_not_in('timeit_cell_alias', mm.magics['line'])
1122 assert "timeit_cell_alias" not in mm.magics["line"]
1100 nt.assert_in('timeit_cell_alias', mm.magics['cell'])
1123 assert "timeit_cell_alias" in mm.magics["cell"]
1101
1124
1102 # Test that line alias is created successfully.
1125 # Test that line alias is created successfully.
1103 ip.run_line_magic('alias_magic', '--line env_alias env')
1126 ip.run_line_magic("alias_magic", "--line env_alias env")
1104 nt.assert_equal(ip.run_line_magic('env', ''),
1127 assert ip.run_line_magic("env", "") == ip.run_line_magic("env_alias", "")
1105 ip.run_line_magic('env_alias', ''))
1106
1128
1107 # Test that line alias with parameters passed in is created successfully.
1129 # Test that line alias with parameters passed in is created successfully.
1108 ip.run_line_magic('alias_magic', '--line history_alias history --params ' + shlex.quote('3'))
1130 ip.run_line_magic(
1109 nt.assert_in('history_alias', mm.magics['line'])
1131 "alias_magic", "--line history_alias history --params " + shlex.quote("3")
1132 )
1133 assert "history_alias" in mm.magics["line"]
1110
1134
1111
1135
1112 def test_save():
1136 def test_save():
1113 """Test %save."""
1137 """Test %save."""
1114 ip = get_ipython()
1138 ip = get_ipython()
1115 ip.history_manager.reset() # Clear any existing history.
1139 ip.history_manager.reset() # Clear any existing history.
1116 cmds = [u"a=1", u"def b():\n return a**2", u"print(a, b())"]
1140 cmds = ["a=1", "def b():\n return a**2", "print(a, b())"]
1117 for i, cmd in enumerate(cmds, start=1):
1141 for i, cmd in enumerate(cmds, start=1):
1118 ip.history_manager.store_inputs(i, cmd)
1142 ip.history_manager.store_inputs(i, cmd)
1119 with TemporaryDirectory() as tmpdir:
1143 with TemporaryDirectory() as tmpdir:
1120 file = os.path.join(tmpdir, "testsave.py")
1144 file = os.path.join(tmpdir, "testsave.py")
1121 ip.run_line_magic("save", "%s 1-10" % file)
1145 ip.run_line_magic("save", "%s 1-10" % file)
1122 content = Path(file).read_text()
1146 content = Path(file).read_text()
1123 nt.assert_equal(content.count(cmds[0]), 1)
1147 assert content.count(cmds[0]) == 1
1124 nt.assert_in("coding: utf-8", content)
1148 assert "coding: utf-8" in content
1125 ip.run_line_magic("save", "-a %s 1-10" % file)
1149 ip.run_line_magic("save", "-a %s 1-10" % file)
1126 content = Path(file).read_text()
1150 content = Path(file).read_text()
1127 nt.assert_equal(content.count(cmds[0]), 2)
1151 assert content.count(cmds[0]) == 2
1128 nt.assert_in("coding: utf-8", content)
1152 assert "coding: utf-8" in content
1129
1153
1130
1154
1131 def test_save_with_no_args():
1155 def test_save_with_no_args():
1132 ip = get_ipython()
1156 ip = get_ipython()
1133 ip.history_manager.reset() # Clear any existing history.
1157 ip.history_manager.reset() # Clear any existing history.
1134 cmds = [u"a=1", u"def b():\n return a**2", u"print(a, b())", "%save"]
1158 cmds = ["a=1", "def b():\n return a**2", "print(a, b())", "%save"]
1135 for i, cmd in enumerate(cmds, start=1):
1159 for i, cmd in enumerate(cmds, start=1):
1136 ip.history_manager.store_inputs(i, cmd)
1160 ip.history_manager.store_inputs(i, cmd)
1137
1161
1138 with TemporaryDirectory() as tmpdir:
1162 with TemporaryDirectory() as tmpdir:
1139 path = os.path.join(tmpdir, "testsave.py")
1163 path = os.path.join(tmpdir, "testsave.py")
1140 ip.run_line_magic("save", path)
1164 ip.run_line_magic("save", path)
1141 content = Path(path).read_text()
1165 content = Path(path).read_text()
1142 expected_content = dedent(
1166 expected_content = dedent(
1143 """\
1167 """\
1144 # coding: utf-8
1168 # coding: utf-8
1145 a=1
1169 a=1
1146 def b():
1170 def b():
1147 return a**2
1171 return a**2
1148 print(a, b())
1172 print(a, b())
1149 """
1173 """
1150 )
1174 )
1151 nt.assert_equal(content, expected_content)
1175 assert content == expected_content
1152
1176
1153
1177
1154 def test_store():
1178 def test_store():
1155 """Test %store."""
1179 """Test %store."""
1156 ip = get_ipython()
1180 ip = get_ipython()
1157 ip.run_line_magic('load_ext', 'storemagic')
1181 ip.run_line_magic('load_ext', 'storemagic')
1158
1182
1159 # make sure the storage is empty
1183 # make sure the storage is empty
1160 ip.run_line_magic('store', '-z')
1184 ip.run_line_magic("store", "-z")
1161 ip.user_ns['var'] = 42
1185 ip.user_ns["var"] = 42
1162 ip.run_line_magic('store', 'var')
1186 ip.run_line_magic("store", "var")
1163 ip.user_ns['var'] = 39
1187 ip.user_ns["var"] = 39
1164 ip.run_line_magic('store', '-r')
1188 ip.run_line_magic("store", "-r")
1165 nt.assert_equal(ip.user_ns['var'], 42)
1189 assert ip.user_ns["var"] == 42
1166
1190
1167 ip.run_line_magic('store', '-d var')
1191 ip.run_line_magic("store", "-d var")
1168 ip.user_ns['var'] = 39
1192 ip.user_ns["var"] = 39
1169 ip.run_line_magic('store' , '-r')
1193 ip.run_line_magic("store", "-r")
1170 nt.assert_equal(ip.user_ns['var'], 39)
1194 assert ip.user_ns["var"] == 39
1171
1195
1172
1196
1173 def _run_edit_test(arg_s, exp_filename=None,
1197 def _run_edit_test(arg_s, exp_filename=None,
1174 exp_lineno=-1,
1198 exp_lineno=-1,
1175 exp_contents=None,
1199 exp_contents=None,
1176 exp_is_temp=None):
1200 exp_is_temp=None):
1177 ip = get_ipython()
1201 ip = get_ipython()
1178 M = code.CodeMagics(ip)
1202 M = code.CodeMagics(ip)
1179 last_call = ['','']
1203 last_call = ['','']
1180 opts,args = M.parse_options(arg_s,'prxn:')
1204 opts,args = M.parse_options(arg_s,'prxn:')
1181 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
1205 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
1182
1206
1183 if exp_filename is not None:
1207 if exp_filename is not None:
1184 nt.assert_equal(exp_filename, filename)
1208 assert exp_filename == filename
1185 if exp_contents is not None:
1209 if exp_contents is not None:
1186 with io.open(filename, 'r', encoding='utf-8') as f:
1210 with io.open(filename, 'r', encoding='utf-8') as f:
1187 contents = f.read()
1211 contents = f.read()
1188 nt.assert_equal(exp_contents, contents)
1212 assert exp_contents == contents
1189 if exp_lineno != -1:
1213 if exp_lineno != -1:
1190 nt.assert_equal(exp_lineno, lineno)
1214 assert exp_lineno == lineno
1191 if exp_is_temp is not None:
1215 if exp_is_temp is not None:
1192 nt.assert_equal(exp_is_temp, is_temp)
1216 assert exp_is_temp == is_temp
1193
1217
1194
1218
1195 def test_edit_interactive():
1219 def test_edit_interactive():
1196 """%edit on interactively defined objects"""
1220 """%edit on interactively defined objects"""
1197 ip = get_ipython()
1221 ip = get_ipython()
1198 n = ip.execution_count
1222 n = ip.execution_count
1199 ip.run_cell(u"def foo(): return 1", store_history=True)
1223 ip.run_cell("def foo(): return 1", store_history=True)
1200
1224
1201 try:
1225 try:
1202 _run_edit_test("foo")
1226 _run_edit_test("foo")
1203 except code.InteractivelyDefined as e:
1227 except code.InteractivelyDefined as e:
1204 nt.assert_equal(e.index, n)
1228 assert e.index == n
1205 else:
1229 else:
1206 raise AssertionError("Should have raised InteractivelyDefined")
1230 raise AssertionError("Should have raised InteractivelyDefined")
1207
1231
1208
1232
1209 def test_edit_cell():
1233 def test_edit_cell():
1210 """%edit [cell id]"""
1234 """%edit [cell id]"""
1211 ip = get_ipython()
1235 ip = get_ipython()
1212
1236
1213 ip.run_cell(u"def foo(): return 1", store_history=True)
1237 ip.run_cell("def foo(): return 1", store_history=True)
1214
1238
1215 # test
1239 # test
1216 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
1240 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
1217
1241
1218 def test_edit_fname():
1242 def test_edit_fname():
1219 """%edit file"""
1243 """%edit file"""
1220 # test
1244 # test
1221 _run_edit_test("test file.py", exp_filename="test file.py")
1245 _run_edit_test("test file.py", exp_filename="test file.py")
1222
1246
1223 def test_bookmark():
1247 def test_bookmark():
1224 ip = get_ipython()
1248 ip = get_ipython()
1225 ip.run_line_magic('bookmark', 'bmname')
1249 ip.run_line_magic('bookmark', 'bmname')
1226 with tt.AssertPrints('bmname'):
1250 with tt.AssertPrints('bmname'):
1227 ip.run_line_magic('bookmark', '-l')
1251 ip.run_line_magic('bookmark', '-l')
1228 ip.run_line_magic('bookmark', '-d bmname')
1252 ip.run_line_magic('bookmark', '-d bmname')
1229
1253
1230 def test_ls_magic():
1254 def test_ls_magic():
1231 ip = get_ipython()
1255 ip = get_ipython()
1232 json_formatter = ip.display_formatter.formatters['application/json']
1256 json_formatter = ip.display_formatter.formatters['application/json']
1233 json_formatter.enabled = True
1257 json_formatter.enabled = True
1234 lsmagic = ip.magic('lsmagic')
1258 lsmagic = ip.magic('lsmagic')
1235 with warnings.catch_warnings(record=True) as w:
1259 with warnings.catch_warnings(record=True) as w:
1236 j = json_formatter(lsmagic)
1260 j = json_formatter(lsmagic)
1237 nt.assert_equal(sorted(j), ['cell', 'line'])
1261 assert sorted(j) == ["cell", "line"]
1238 nt.assert_equal(w, []) # no warnings
1262 assert w == [] # no warnings
1263
1239
1264
1240 def test_strip_initial_indent():
1265 def test_strip_initial_indent():
1241 def sii(s):
1266 def sii(s):
1242 lines = s.splitlines()
1267 lines = s.splitlines()
1243 return '\n'.join(code.strip_initial_indent(lines))
1268 return '\n'.join(code.strip_initial_indent(lines))
1244
1269
1245 nt.assert_equal(sii(" a = 1\nb = 2"), "a = 1\nb = 2")
1270 assert sii(" a = 1\nb = 2") == "a = 1\nb = 2"
1246 nt.assert_equal(sii(" a\n b\nc"), "a\n b\nc")
1271 assert sii(" a\n b\nc") == "a\n b\nc"
1247 nt.assert_equal(sii("a\n b"), "a\n b")
1272 assert sii("a\n b") == "a\n b"
1248
1273
1249 def test_logging_magic_quiet_from_arg():
1274 def test_logging_magic_quiet_from_arg():
1250 _ip.config.LoggingMagics.quiet = False
1275 _ip.config.LoggingMagics.quiet = False
1251 lm = logging.LoggingMagics(shell=_ip)
1276 lm = logging.LoggingMagics(shell=_ip)
1252 with TemporaryDirectory() as td:
1277 with TemporaryDirectory() as td:
1253 try:
1278 try:
1254 with tt.AssertNotPrints(re.compile("Activating.*")):
1279 with tt.AssertNotPrints(re.compile("Activating.*")):
1255 lm.logstart('-q {}'.format(
1280 lm.logstart('-q {}'.format(
1256 os.path.join(td, "quiet_from_arg.log")))
1281 os.path.join(td, "quiet_from_arg.log")))
1257 finally:
1282 finally:
1258 _ip.logger.logstop()
1283 _ip.logger.logstop()
1259
1284
1260 def test_logging_magic_quiet_from_config():
1285 def test_logging_magic_quiet_from_config():
1261 _ip.config.LoggingMagics.quiet = True
1286 _ip.config.LoggingMagics.quiet = True
1262 lm = logging.LoggingMagics(shell=_ip)
1287 lm = logging.LoggingMagics(shell=_ip)
1263 with TemporaryDirectory() as td:
1288 with TemporaryDirectory() as td:
1264 try:
1289 try:
1265 with tt.AssertNotPrints(re.compile("Activating.*")):
1290 with tt.AssertNotPrints(re.compile("Activating.*")):
1266 lm.logstart(os.path.join(td, "quiet_from_config.log"))
1291 lm.logstart(os.path.join(td, "quiet_from_config.log"))
1267 finally:
1292 finally:
1268 _ip.logger.logstop()
1293 _ip.logger.logstop()
1269
1294
1270
1295
1271 def test_logging_magic_not_quiet():
1296 def test_logging_magic_not_quiet():
1272 _ip.config.LoggingMagics.quiet = False
1297 _ip.config.LoggingMagics.quiet = False
1273 lm = logging.LoggingMagics(shell=_ip)
1298 lm = logging.LoggingMagics(shell=_ip)
1274 with TemporaryDirectory() as td:
1299 with TemporaryDirectory() as td:
1275 try:
1300 try:
1276 with tt.AssertPrints(re.compile("Activating.*")):
1301 with tt.AssertPrints(re.compile("Activating.*")):
1277 lm.logstart(os.path.join(td, "not_quiet.log"))
1302 lm.logstart(os.path.join(td, "not_quiet.log"))
1278 finally:
1303 finally:
1279 _ip.logger.logstop()
1304 _ip.logger.logstop()
1280
1305
1281
1306
1282 def test_time_no_var_expand():
1307 def test_time_no_var_expand():
1283 _ip.user_ns['a'] = 5
1308 _ip.user_ns['a'] = 5
1284 _ip.user_ns['b'] = []
1309 _ip.user_ns['b'] = []
1285 _ip.magic('time b.append("{a}")')
1310 _ip.magic('time b.append("{a}")')
1286 assert _ip.user_ns['b'] == ['{a}']
1311 assert _ip.user_ns['b'] == ['{a}']
1287
1312
1288
1313
1289 # this is slow, put at the end for local testing.
1314 # this is slow, put at the end for local testing.
1290 def test_timeit_arguments():
1315 def test_timeit_arguments():
1291 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
1316 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
1292 if sys.version_info < (3,7):
1317 if sys.version_info < (3,7):
1293 _ip.magic("timeit -n1 -r1 ('#')")
1318 _ip.magic("timeit -n1 -r1 ('#')")
1294 else:
1319 else:
1295 # 3.7 optimize no-op statement like above out, and complain there is
1320 # 3.7 optimize no-op statement like above out, and complain there is
1296 # nothing in the for loop.
1321 # nothing in the for loop.
1297 _ip.magic("timeit -n1 -r1 a=('#')")
1322 _ip.magic("timeit -n1 -r1 a=('#')")
1298
1323
1299
1324
1300 TEST_MODULE = """
1325 TEST_MODULE = """
1301 print('Loaded my_tmp')
1326 print('Loaded my_tmp')
1302 if __name__ == "__main__":
1327 if __name__ == "__main__":
1303 print('I just ran a script')
1328 print('I just ran a script')
1304 """
1329 """
1305
1330
1306
1331
1307 def test_run_module_from_import_hook():
1332 def test_run_module_from_import_hook():
1308 "Test that a module can be loaded via an import hook"
1333 "Test that a module can be loaded via an import hook"
1309 with TemporaryDirectory() as tmpdir:
1334 with TemporaryDirectory() as tmpdir:
1310 fullpath = os.path.join(tmpdir, 'my_tmp.py')
1335 fullpath = os.path.join(tmpdir, 'my_tmp.py')
1311 Path(fullpath).write_text(TEST_MODULE)
1336 Path(fullpath).write_text(TEST_MODULE)
1312
1337
1313 class MyTempImporter(object):
1338 class MyTempImporter(object):
1314 def __init__(self):
1339 def __init__(self):
1315 pass
1340 pass
1316
1341
1317 def find_module(self, fullname, path=None):
1342 def find_module(self, fullname, path=None):
1318 if 'my_tmp' in fullname:
1343 if 'my_tmp' in fullname:
1319 return self
1344 return self
1320 return None
1345 return None
1321
1346
1322 def load_module(self, name):
1347 def load_module(self, name):
1323 import imp
1348 import imp
1324 return imp.load_source('my_tmp', fullpath)
1349 return imp.load_source('my_tmp', fullpath)
1325
1350
1326 def get_code(self, fullname):
1351 def get_code(self, fullname):
1327 return compile(Path(fullpath).read_text(), "foo", "exec")
1352 return compile(Path(fullpath).read_text(), "foo", "exec")
1328
1353
1329 def is_package(self, __):
1354 def is_package(self, __):
1330 return False
1355 return False
1331
1356
1332 sys.meta_path.insert(0, MyTempImporter())
1357 sys.meta_path.insert(0, MyTempImporter())
1333
1358
1334 with capture_output() as captured:
1359 with capture_output() as captured:
1335 _ip.magic("run -m my_tmp")
1360 _ip.magic("run -m my_tmp")
1336 _ip.run_cell("import my_tmp")
1361 _ip.run_cell("import my_tmp")
1337
1362
1338 output = "Loaded my_tmp\nI just ran a script\nLoaded my_tmp\n"
1363 output = "Loaded my_tmp\nI just ran a script\nLoaded my_tmp\n"
1339 nt.assert_equal(output, captured.stdout)
1364 assert output == captured.stdout
1340
1365
1341 sys.meta_path.pop(0)
1366 sys.meta_path.pop(0)
@@ -1,192 +1,193 b''
1 """Tests for various magic functions specific to the terminal frontend.
1 """Tests for various magic functions specific to the terminal frontend.
2
2
3 Needs to be run by nose (to make ipython session available).
3 Needs to be run by nose (to make ipython session available).
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Imports
7 # Imports
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9
9
10 import sys
10 import sys
11 from io import StringIO
11 from io import StringIO
12 from unittest import TestCase
12 from unittest import TestCase
13
13
14 import nose.tools as nt
15
16 from IPython.testing import tools as tt
14 from IPython.testing import tools as tt
17
15
18 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
19 # Test functions begin
17 # Test functions begin
20 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
21
19
22 def check_cpaste(code, should_fail=False):
20 def check_cpaste(code, should_fail=False):
23 """Execute code via 'cpaste' and ensure it was executed, unless
21 """Execute code via 'cpaste' and ensure it was executed, unless
24 should_fail is set.
22 should_fail is set.
25 """
23 """
26 ip.user_ns['code_ran'] = False
24 ip.user_ns['code_ran'] = False
27
25
28 src = StringIO()
26 src = StringIO()
29 if not hasattr(src, 'encoding'):
27 if not hasattr(src, 'encoding'):
30 # IPython expects stdin to have an encoding attribute
28 # IPython expects stdin to have an encoding attribute
31 src.encoding = None
29 src.encoding = None
32 src.write(code)
30 src.write(code)
33 src.write('\n--\n')
31 src.write('\n--\n')
34 src.seek(0)
32 src.seek(0)
35
33
36 stdin_save = sys.stdin
34 stdin_save = sys.stdin
37 sys.stdin = src
35 sys.stdin = src
38
36
39 try:
37 try:
40 context = tt.AssertPrints if should_fail else tt.AssertNotPrints
38 context = tt.AssertPrints if should_fail else tt.AssertNotPrints
41 with context("Traceback (most recent call last)"):
39 with context("Traceback (most recent call last)"):
42 ip.magic('cpaste')
40 ip.magic('cpaste')
43
41
44 if not should_fail:
42 if not should_fail:
45 assert ip.user_ns['code_ran'], "%r failed" % code
43 assert ip.user_ns['code_ran'], "%r failed" % code
46 finally:
44 finally:
47 sys.stdin = stdin_save
45 sys.stdin = stdin_save
48
46
49 def test_cpaste():
47 def test_cpaste():
50 """Test cpaste magic"""
48 """Test cpaste magic"""
51
49
52 def runf():
50 def runf():
53 """Marker function: sets a flag when executed.
51 """Marker function: sets a flag when executed.
54 """
52 """
55 ip.user_ns['code_ran'] = True
53 ip.user_ns['code_ran'] = True
56 return 'runf' # return string so '+ runf()' doesn't result in success
54 return 'runf' # return string so '+ runf()' doesn't result in success
57
55
58 tests = {'pass': ["runf()",
56 tests = {'pass': ["runf()",
59 "In [1]: runf()",
57 "In [1]: runf()",
60 "In [1]: if 1:\n ...: runf()",
58 "In [1]: if 1:\n ...: runf()",
61 "> > > runf()",
59 "> > > runf()",
62 ">>> runf()",
60 ">>> runf()",
63 " >>> runf()",
61 " >>> runf()",
64 ],
62 ],
65
63
66 'fail': ["1 + runf()",
64 'fail': ["1 + runf()",
67 "++ runf()",
65 "++ runf()",
68 ]}
66 ]}
69
67
70 ip.user_ns['runf'] = runf
68 ip.user_ns['runf'] = runf
71
69
72 for code in tests['pass']:
70 for code in tests['pass']:
73 check_cpaste(code)
71 check_cpaste(code)
74
72
75 for code in tests['fail']:
73 for code in tests['fail']:
76 check_cpaste(code, should_fail=True)
74 check_cpaste(code, should_fail=True)
77
75
78
76
79 class PasteTestCase(TestCase):
77 class PasteTestCase(TestCase):
80 """Multiple tests for clipboard pasting"""
78 """Multiple tests for clipboard pasting"""
81
79
82 def paste(self, txt, flags='-q'):
80 def paste(self, txt, flags='-q'):
83 """Paste input text, by default in quiet mode"""
81 """Paste input text, by default in quiet mode"""
84 ip.hooks.clipboard_get = lambda : txt
82 ip.hooks.clipboard_get = lambda : txt
85 ip.magic('paste '+flags)
83 ip.magic('paste '+flags)
86
84
87 def setUp(self):
85 def setUp(self):
88 # Inject fake clipboard hook but save original so we can restore it later
86 # Inject fake clipboard hook but save original so we can restore it later
89 self.original_clip = ip.hooks.clipboard_get
87 self.original_clip = ip.hooks.clipboard_get
90
88
91 def tearDown(self):
89 def tearDown(self):
92 # Restore original hook
90 # Restore original hook
93 ip.hooks.clipboard_get = self.original_clip
91 ip.hooks.clipboard_get = self.original_clip
94
92
95 def test_paste(self):
93 def test_paste(self):
96 ip.user_ns.pop('x', None)
94 ip.user_ns.pop("x", None)
97 self.paste('x = 1')
95 self.paste("x = 1")
98 nt.assert_equal(ip.user_ns['x'], 1)
96 self.assertEqual(ip.user_ns["x"], 1)
99 ip.user_ns.pop('x')
97 ip.user_ns.pop("x")
100
98
101 def test_paste_pyprompt(self):
99 def test_paste_pyprompt(self):
102 ip.user_ns.pop('x', None)
100 ip.user_ns.pop("x", None)
103 self.paste('>>> x=2')
101 self.paste(">>> x=2")
104 nt.assert_equal(ip.user_ns['x'], 2)
102 self.assertEqual(ip.user_ns["x"], 2)
105 ip.user_ns.pop('x')
103 ip.user_ns.pop("x")
106
104
107 def test_paste_py_multi(self):
105 def test_paste_py_multi(self):
108 self.paste("""
106 self.paste("""
109 >>> x = [1,2,3]
107 >>> x = [1,2,3]
110 >>> y = []
108 >>> y = []
111 >>> for i in x:
109 >>> for i in x:
112 ... y.append(i**2)
110 ... y.append(i**2)
113 ...
111 ...
114 """)
112 """
115 nt.assert_equal(ip.user_ns['x'], [1,2,3])
113 )
116 nt.assert_equal(ip.user_ns['y'], [1,4,9])
114 self.assertEqual(ip.user_ns["x"], [1, 2, 3])
115 self.assertEqual(ip.user_ns["y"], [1, 4, 9])
117
116
118 def test_paste_py_multi_r(self):
117 def test_paste_py_multi_r(self):
119 "Now, test that self.paste -r works"
118 "Now, test that self.paste -r works"
120 self.test_paste_py_multi()
119 self.test_paste_py_multi()
121 nt.assert_equal(ip.user_ns.pop('x'), [1,2,3])
120 self.assertEqual(ip.user_ns.pop("x"), [1, 2, 3])
122 nt.assert_equal(ip.user_ns.pop('y'), [1,4,9])
121 self.assertEqual(ip.user_ns.pop("y"), [1, 4, 9])
123 nt.assert_false('x' in ip.user_ns)
122 self.assertFalse("x" in ip.user_ns)
124 ip.magic('paste -r')
123 ip.magic("paste -r")
125 nt.assert_equal(ip.user_ns['x'], [1,2,3])
124 self.assertEqual(ip.user_ns["x"], [1, 2, 3])
126 nt.assert_equal(ip.user_ns['y'], [1,4,9])
125 self.assertEqual(ip.user_ns["y"], [1, 4, 9])
127
126
128 def test_paste_email(self):
127 def test_paste_email(self):
129 "Test pasting of email-quoted contents"
128 "Test pasting of email-quoted contents"
130 self.paste("""\
129 self.paste("""\
131 >> def foo(x):
130 >> def foo(x):
132 >> return x + 1
131 >> return x + 1
133 >> xx = foo(1.1)""")
132 >> xx = foo(1.1)"""
134 nt.assert_equal(ip.user_ns['xx'], 2.1)
133 )
134 self.assertEqual(ip.user_ns["xx"], 2.1)
135
135
136 def test_paste_email2(self):
136 def test_paste_email2(self):
137 "Email again; some programs add a space also at each quoting level"
137 "Email again; some programs add a space also at each quoting level"
138 self.paste("""\
138 self.paste("""\
139 > > def foo(x):
139 > > def foo(x):
140 > > return x + 1
140 > > return x + 1
141 > > yy = foo(2.1) """)
141 > > yy = foo(2.1) """
142 nt.assert_equal(ip.user_ns['yy'], 3.1)
142 )
143 self.assertEqual(ip.user_ns["yy"], 3.1)
143
144
144 def test_paste_email_py(self):
145 def test_paste_email_py(self):
145 "Email quoting of interactive input"
146 "Email quoting of interactive input"
146 self.paste("""\
147 self.paste("""\
147 >> >>> def f(x):
148 >> >>> def f(x):
148 >> ... return x+1
149 >> ... return x+1
149 >> ...
150 >> ...
150 >> >>> zz = f(2.5) """)
151 >> >>> zz = f(2.5) """
151 nt.assert_equal(ip.user_ns['zz'], 3.5)
152 )
153 self.assertEqual(ip.user_ns["zz"], 3.5)
152
154
153 def test_paste_echo(self):
155 def test_paste_echo(self):
154 "Also test self.paste echoing, by temporarily faking the writer"
156 "Also test self.paste echoing, by temporarily faking the writer"
155 w = StringIO()
157 w = StringIO()
156 writer = ip.write
158 writer = ip.write
157 ip.write = w.write
159 ip.write = w.write
158 code = """
160 code = """
159 a = 100
161 a = 100
160 b = 200"""
162 b = 200"""
161 try:
163 try:
162 self.paste(code,'')
164 self.paste(code,'')
163 out = w.getvalue()
165 out = w.getvalue()
164 finally:
166 finally:
165 ip.write = writer
167 ip.write = writer
166 nt.assert_equal(ip.user_ns['a'], 100)
168 self.assertEqual(ip.user_ns["a"], 100)
167 nt.assert_equal(ip.user_ns['b'], 200)
169 self.assertEqual(ip.user_ns["b"], 200)
168 assert out == code+"\n## -- End pasted text --\n"
170 assert out == code + "\n## -- End pasted text --\n"
169
171
170 def test_paste_leading_commas(self):
172 def test_paste_leading_commas(self):
171 "Test multiline strings with leading commas"
173 "Test multiline strings with leading commas"
172 tm = ip.magics_manager.registry['TerminalMagics']
174 tm = ip.magics_manager.registry['TerminalMagics']
173 s = '''\
175 s = '''\
174 a = """
176 a = """
175 ,1,2,3
177 ,1,2,3
176 """'''
178 """'''
177 ip.user_ns.pop('foo', None)
179 ip.user_ns.pop("foo", None)
178 tm.store_or_execute(s, 'foo')
180 tm.store_or_execute(s, "foo")
179 nt.assert_in('foo', ip.user_ns)
181 self.assertIn("foo", ip.user_ns)
180
181
182
182 def test_paste_trailing_question(self):
183 def test_paste_trailing_question(self):
183 "Test pasting sources with trailing question marks"
184 "Test pasting sources with trailing question marks"
184 tm = ip.magics_manager.registry['TerminalMagics']
185 tm = ip.magics_manager.registry['TerminalMagics']
185 s = '''\
186 s = '''\
186 def funcfoo():
187 def funcfoo():
187 if True: #am i true?
188 if True: #am i true?
188 return 'fooresult'
189 return 'fooresult'
189 '''
190 '''
190 ip.user_ns.pop('funcfoo', None)
191 ip.user_ns.pop('funcfoo', None)
191 self.paste(s)
192 self.paste(s)
192 nt.assert_equal(ip.user_ns['funcfoo'](), 'fooresult')
193 self.assertEqual(ip.user_ns["funcfoo"](), "fooresult")
@@ -1,455 +1,454 b''
1 """Tests for the object inspection functionality.
1 """Tests for the object inspection functionality.
2 """
2 """
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7
7
8 from inspect import signature, Signature, Parameter
8 from inspect import signature, Signature, Parameter
9 import os
9 import os
10 import re
10 import re
11
11
12 import nose.tools as nt
13
14 from .. import oinspect
12 from .. import oinspect
15
13
16 from decorator import decorator
14 from decorator import decorator
17
15
18 from IPython.testing.tools import AssertPrints, AssertNotPrints
16 from IPython.testing.tools import AssertPrints, AssertNotPrints
19 from IPython.utils.path import compress_user
17 from IPython.utils.path import compress_user
20
18
21
19
22 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
23 # Globals and constants
21 # Globals and constants
24 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
25
23
26 inspector = None
24 inspector = None
27
25
28 def setup_module():
26 def setup_module():
29 global inspector
27 global inspector
30 inspector = oinspect.Inspector()
28 inspector = oinspect.Inspector()
31
29
32
30
33 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
34 # Local utilities
32 # Local utilities
35 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
36
34
37 # WARNING: since this test checks the line number where a function is
35 # WARNING: since this test checks the line number where a function is
38 # defined, if any code is inserted above, the following line will need to be
36 # defined, if any code is inserted above, the following line will need to be
39 # updated. Do NOT insert any whitespace between the next line and the function
37 # updated. Do NOT insert any whitespace between the next line and the function
40 # definition below.
38 # definition below.
41 THIS_LINE_NUMBER = 41 # Put here the actual number of this line
39 THIS_LINE_NUMBER = 39 # Put here the actual number of this line
42
40
43 from unittest import TestCase
41 from unittest import TestCase
44
42
45 class Test(TestCase):
43 class Test(TestCase):
46
44
47 def test_find_source_lines(self):
45 def test_find_source_lines(self):
48 self.assertEqual(oinspect.find_source_lines(Test.test_find_source_lines),
46 self.assertEqual(oinspect.find_source_lines(Test.test_find_source_lines),
49 THIS_LINE_NUMBER+6)
47 THIS_LINE_NUMBER+6)
50
48
51
49
52 # A couple of utilities to ensure these tests work the same from a source or a
50 # A couple of utilities to ensure these tests work the same from a source or a
53 # binary install
51 # binary install
54 def pyfile(fname):
52 def pyfile(fname):
55 return os.path.normcase(re.sub('.py[co]$', '.py', fname))
53 return os.path.normcase(re.sub('.py[co]$', '.py', fname))
56
54
57
55
58 def match_pyfiles(f1, f2):
56 def match_pyfiles(f1, f2):
59 assert pyfile(f1) == pyfile(f2)
57 assert pyfile(f1) == pyfile(f2)
60
58
61
59
62 def test_find_file():
60 def test_find_file():
63 match_pyfiles(oinspect.find_file(test_find_file), os.path.abspath(__file__))
61 match_pyfiles(oinspect.find_file(test_find_file), os.path.abspath(__file__))
64
62
65
63
66 def test_find_file_decorated1():
64 def test_find_file_decorated1():
67
65
68 @decorator
66 @decorator
69 def noop1(f):
67 def noop1(f):
70 def wrapper(*a, **kw):
68 def wrapper(*a, **kw):
71 return f(*a, **kw)
69 return f(*a, **kw)
72 return wrapper
70 return wrapper
73
71
74 @noop1
72 @noop1
75 def f(x):
73 def f(x):
76 "My docstring"
74 "My docstring"
77
75
78 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
76 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
79 assert f.__doc__ == "My docstring"
77 assert f.__doc__ == "My docstring"
80
78
81
79
82 def test_find_file_decorated2():
80 def test_find_file_decorated2():
83
81
84 @decorator
82 @decorator
85 def noop2(f, *a, **kw):
83 def noop2(f, *a, **kw):
86 return f(*a, **kw)
84 return f(*a, **kw)
87
85
88 @noop2
86 @noop2
89 @noop2
87 @noop2
90 @noop2
88 @noop2
91 def f(x):
89 def f(x):
92 "My docstring 2"
90 "My docstring 2"
93
91
94 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
92 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
95 assert f.__doc__ == "My docstring 2"
93 assert f.__doc__ == "My docstring 2"
96
94
97
95
98 def test_find_file_magic():
96 def test_find_file_magic():
99 run = ip.find_line_magic('run')
97 run = ip.find_line_magic('run')
100 nt.assert_not_equal(oinspect.find_file(run), None)
98 assert oinspect.find_file(run) is not None
101
99
102
100
103 # A few generic objects we can then inspect in the tests below
101 # A few generic objects we can then inspect in the tests below
104
102
105 class Call(object):
103 class Call(object):
106 """This is the class docstring."""
104 """This is the class docstring."""
107
105
108 def __init__(self, x, y=1):
106 def __init__(self, x, y=1):
109 """This is the constructor docstring."""
107 """This is the constructor docstring."""
110
108
111 def __call__(self, *a, **kw):
109 def __call__(self, *a, **kw):
112 """This is the call docstring."""
110 """This is the call docstring."""
113
111
114 def method(self, x, z=2):
112 def method(self, x, z=2):
115 """Some method's docstring"""
113 """Some method's docstring"""
116
114
117 class HasSignature(object):
115 class HasSignature(object):
118 """This is the class docstring."""
116 """This is the class docstring."""
119 __signature__ = Signature([Parameter('test', Parameter.POSITIONAL_OR_KEYWORD)])
117 __signature__ = Signature([Parameter('test', Parameter.POSITIONAL_OR_KEYWORD)])
120
118
121 def __init__(self, *args):
119 def __init__(self, *args):
122 """This is the init docstring"""
120 """This is the init docstring"""
123
121
124
122
125 class SimpleClass(object):
123 class SimpleClass(object):
126 def method(self, x, z=2):
124 def method(self, x, z=2):
127 """Some method's docstring"""
125 """Some method's docstring"""
128
126
129
127
130 class Awkward(object):
128 class Awkward(object):
131 def __getattr__(self, name):
129 def __getattr__(self, name):
132 raise Exception(name)
130 raise Exception(name)
133
131
134 class NoBoolCall:
132 class NoBoolCall:
135 """
133 """
136 callable with `__bool__` raising should still be inspect-able.
134 callable with `__bool__` raising should still be inspect-able.
137 """
135 """
138
136
139 def __call__(self):
137 def __call__(self):
140 """does nothing"""
138 """does nothing"""
141 pass
139 pass
142
140
143 def __bool__(self):
141 def __bool__(self):
144 """just raise NotImplemented"""
142 """just raise NotImplemented"""
145 raise NotImplementedError('Must be implemented')
143 raise NotImplementedError('Must be implemented')
146
144
147
145
148 class SerialLiar(object):
146 class SerialLiar(object):
149 """Attribute accesses always get another copy of the same class.
147 """Attribute accesses always get another copy of the same class.
150
148
151 unittest.mock.call does something similar, but it's not ideal for testing
149 unittest.mock.call does something similar, but it's not ideal for testing
152 as the failure mode is to eat all your RAM. This gives up after 10k levels.
150 as the failure mode is to eat all your RAM. This gives up after 10k levels.
153 """
151 """
154 def __init__(self, max_fibbing_twig, lies_told=0):
152 def __init__(self, max_fibbing_twig, lies_told=0):
155 if lies_told > 10000:
153 if lies_told > 10000:
156 raise RuntimeError('Nose too long, honesty is the best policy')
154 raise RuntimeError('Nose too long, honesty is the best policy')
157 self.max_fibbing_twig = max_fibbing_twig
155 self.max_fibbing_twig = max_fibbing_twig
158 self.lies_told = lies_told
156 self.lies_told = lies_told
159 max_fibbing_twig[0] = max(max_fibbing_twig[0], lies_told)
157 max_fibbing_twig[0] = max(max_fibbing_twig[0], lies_told)
160
158
161 def __getattr__(self, item):
159 def __getattr__(self, item):
162 return SerialLiar(self.max_fibbing_twig, self.lies_told + 1)
160 return SerialLiar(self.max_fibbing_twig, self.lies_told + 1)
163
161
164 #-----------------------------------------------------------------------------
162 #-----------------------------------------------------------------------------
165 # Tests
163 # Tests
166 #-----------------------------------------------------------------------------
164 #-----------------------------------------------------------------------------
167
165
168 def test_info():
166 def test_info():
169 "Check that Inspector.info fills out various fields as expected."
167 "Check that Inspector.info fills out various fields as expected."
170 i = inspector.info(Call, oname="Call")
168 i = inspector.info(Call, oname="Call")
171 assert i["type_name"] == "type"
169 assert i["type_name"] == "type"
172 expted_class = str(type(type)) # <class 'type'> (Python 3) or <type 'type'>
170 expected_class = str(type(type)) # <class 'type'> (Python 3) or <type 'type'>
173 assert i["base_class"] == expted_class
171 assert i["base_class"] == expected_class
174 nt.assert_regex(
172 assert re.search(
175 i["string_form"],
176 "<class 'IPython.core.tests.test_oinspect.Call'( at 0x[0-9a-f]{1,9})?>",
173 "<class 'IPython.core.tests.test_oinspect.Call'( at 0x[0-9a-f]{1,9})?>",
174 i["string_form"],
177 )
175 )
178 fname = __file__
176 fname = __file__
179 if fname.endswith(".pyc"):
177 if fname.endswith(".pyc"):
180 fname = fname[:-1]
178 fname = fname[:-1]
181 # case-insensitive comparison needed on some filesystems
179 # case-insensitive comparison needed on some filesystems
182 # e.g. Windows:
180 # e.g. Windows:
183 assert i["file"].lower() == compress_user(fname).lower()
181 assert i["file"].lower() == compress_user(fname).lower()
184 assert i["definition"] == None
182 assert i["definition"] == None
185 assert i["docstring"] == Call.__doc__
183 assert i["docstring"] == Call.__doc__
186 assert i["source"] == None
184 assert i["source"] == None
187 nt.assert_true(i["isclass"])
185 assert i["isclass"] is True
188 assert i["init_definition"] == "Call(x, y=1)"
186 assert i["init_definition"] == "Call(x, y=1)"
189 assert i["init_docstring"] == Call.__init__.__doc__
187 assert i["init_docstring"] == Call.__init__.__doc__
190
188
191 i = inspector.info(Call, detail_level=1)
189 i = inspector.info(Call, detail_level=1)
192 nt.assert_not_equal(i["source"], None)
190 assert i["source"] is not None
193 assert i["docstring"] == None
191 assert i["docstring"] == None
194
192
195 c = Call(1)
193 c = Call(1)
196 c.__doc__ = "Modified instance docstring"
194 c.__doc__ = "Modified instance docstring"
197 i = inspector.info(c)
195 i = inspector.info(c)
198 assert i["type_name"] == "Call"
196 assert i["type_name"] == "Call"
199 assert i["docstring"] == "Modified instance docstring"
197 assert i["docstring"] == "Modified instance docstring"
200 assert i["class_docstring"] == Call.__doc__
198 assert i["class_docstring"] == Call.__doc__
201 assert i["init_docstring"] == Call.__init__.__doc__
199 assert i["init_docstring"] == Call.__init__.__doc__
202 assert i["call_docstring"] == Call.__call__.__doc__
200 assert i["call_docstring"] == Call.__call__.__doc__
203
201
204
202
205 def test_class_signature():
203 def test_class_signature():
206 info = inspector.info(HasSignature, "HasSignature")
204 info = inspector.info(HasSignature, "HasSignature")
207 assert info["init_definition"] == "HasSignature(test)"
205 assert info["init_definition"] == "HasSignature(test)"
208 assert info["init_docstring"] == HasSignature.__init__.__doc__
206 assert info["init_docstring"] == HasSignature.__init__.__doc__
209
207
210
208
211 def test_info_awkward():
209 def test_info_awkward():
212 # Just test that this doesn't throw an error.
210 # Just test that this doesn't throw an error.
213 inspector.info(Awkward())
211 inspector.info(Awkward())
214
212
215 def test_bool_raise():
213 def test_bool_raise():
216 inspector.info(NoBoolCall())
214 inspector.info(NoBoolCall())
217
215
218 def test_info_serialliar():
216 def test_info_serialliar():
219 fib_tracker = [0]
217 fib_tracker = [0]
220 inspector.info(SerialLiar(fib_tracker))
218 inspector.info(SerialLiar(fib_tracker))
221
219
222 # Nested attribute access should be cut off at 100 levels deep to avoid
220 # Nested attribute access should be cut off at 100 levels deep to avoid
223 # infinite loops: https://github.com/ipython/ipython/issues/9122
221 # infinite loops: https://github.com/ipython/ipython/issues/9122
224 nt.assert_less(fib_tracker[0], 9000)
222 assert fib_tracker[0] < 9000
225
223
226 def support_function_one(x, y=2, *a, **kw):
224 def support_function_one(x, y=2, *a, **kw):
227 """A simple function."""
225 """A simple function."""
228
226
229 def test_calldef_none():
227 def test_calldef_none():
230 # We should ignore __call__ for all of these.
228 # We should ignore __call__ for all of these.
231 for obj in [support_function_one, SimpleClass().method, any, str.upper]:
229 for obj in [support_function_one, SimpleClass().method, any, str.upper]:
232 i = inspector.info(obj)
230 i = inspector.info(obj)
233 nt.assert_is(i['call_def'], None)
231 assert i["call_def"] is None
232
234
233
235 def f_kwarg(pos, *, kwonly):
234 def f_kwarg(pos, *, kwonly):
236 pass
235 pass
237
236
238 def test_definition_kwonlyargs():
237 def test_definition_kwonlyargs():
239 i = inspector.info(f_kwarg, oname="f_kwarg") # analysis:ignore
238 i = inspector.info(f_kwarg, oname="f_kwarg") # analysis:ignore
240 assert i["definition"] == "f_kwarg(pos, *, kwonly)"
239 assert i["definition"] == "f_kwarg(pos, *, kwonly)"
241
240
242
241
243 def test_getdoc():
242 def test_getdoc():
244 class A(object):
243 class A(object):
245 """standard docstring"""
244 """standard docstring"""
246 pass
245 pass
247
246
248 class B(object):
247 class B(object):
249 """standard docstring"""
248 """standard docstring"""
250 def getdoc(self):
249 def getdoc(self):
251 return "custom docstring"
250 return "custom docstring"
252
251
253 class C(object):
252 class C(object):
254 """standard docstring"""
253 """standard docstring"""
255 def getdoc(self):
254 def getdoc(self):
256 return None
255 return None
257
256
258 a = A()
257 a = A()
259 b = B()
258 b = B()
260 c = C()
259 c = C()
261
260
262 assert oinspect.getdoc(a) == "standard docstring"
261 assert oinspect.getdoc(a) == "standard docstring"
263 assert oinspect.getdoc(b) == "custom docstring"
262 assert oinspect.getdoc(b) == "custom docstring"
264 assert oinspect.getdoc(c) == "standard docstring"
263 assert oinspect.getdoc(c) == "standard docstring"
265
264
266
265
267 def test_empty_property_has_no_source():
266 def test_empty_property_has_no_source():
268 i = inspector.info(property(), detail_level=1)
267 i = inspector.info(property(), detail_level=1)
269 nt.assert_is(i['source'], None)
268 assert i["source"] is None
270
269
271
270
272 def test_property_sources():
271 def test_property_sources():
273 import posixpath
272 import posixpath
274 # A simple adder whose source and signature stays
273 # A simple adder whose source and signature stays
275 # the same across Python distributions
274 # the same across Python distributions
276 def simple_add(a, b):
275 def simple_add(a, b):
277 "Adds two numbers"
276 "Adds two numbers"
278 return a + b
277 return a + b
279
278
280 class A(object):
279 class A(object):
281 @property
280 @property
282 def foo(self):
281 def foo(self):
283 return 'bar'
282 return 'bar'
284
283
285 foo = foo.setter(lambda self, v: setattr(self, 'bar', v))
284 foo = foo.setter(lambda self, v: setattr(self, 'bar', v))
286
285
287 dname = property(posixpath.dirname)
286 dname = property(posixpath.dirname)
288 adder = property(simple_add)
287 adder = property(simple_add)
289
288
290 i = inspector.info(A.foo, detail_level=1)
289 i = inspector.info(A.foo, detail_level=1)
291 nt.assert_in('def foo(self):', i['source'])
290 assert "def foo(self):" in i["source"]
292 nt.assert_in('lambda self, v:', i['source'])
291 assert "lambda self, v:" in i["source"]
293
292
294 i = inspector.info(A.dname, detail_level=1)
293 i = inspector.info(A.dname, detail_level=1)
295 nt.assert_in('def dirname(p)', i['source'])
294 assert "def dirname(p)" in i["source"]
296
295
297 i = inspector.info(A.adder, detail_level=1)
296 i = inspector.info(A.adder, detail_level=1)
298 nt.assert_in('def simple_add(a, b)', i['source'])
297 assert "def simple_add(a, b)" in i["source"]
299
298
300
299
301 def test_property_docstring_is_in_info_for_detail_level_0():
300 def test_property_docstring_is_in_info_for_detail_level_0():
302 class A(object):
301 class A(object):
303 @property
302 @property
304 def foobar(self):
303 def foobar(self):
305 """This is `foobar` property."""
304 """This is `foobar` property."""
306 pass
305 pass
307
306
308 ip.user_ns["a_obj"] = A()
307 ip.user_ns["a_obj"] = A()
309 assert (
308 assert (
310 "This is `foobar` property."
309 "This is `foobar` property."
311 == ip.object_inspect("a_obj.foobar", detail_level=0)["docstring"]
310 == ip.object_inspect("a_obj.foobar", detail_level=0)["docstring"]
312 )
311 )
313
312
314 ip.user_ns["a_cls"] = A
313 ip.user_ns["a_cls"] = A
315 assert (
314 assert (
316 "This is `foobar` property."
315 "This is `foobar` property."
317 == ip.object_inspect("a_cls.foobar", detail_level=0)["docstring"]
316 == ip.object_inspect("a_cls.foobar", detail_level=0)["docstring"]
318 )
317 )
319
318
320
319
321 def test_pdef():
320 def test_pdef():
322 # See gh-1914
321 # See gh-1914
323 def foo(): pass
322 def foo(): pass
324 inspector.pdef(foo, 'foo')
323 inspector.pdef(foo, 'foo')
325
324
326
325
327 def test_pinfo_nonascii():
326 def test_pinfo_nonascii():
328 # See gh-1177
327 # See gh-1177
329 from . import nonascii2
328 from . import nonascii2
330 ip.user_ns['nonascii2'] = nonascii2
329 ip.user_ns['nonascii2'] = nonascii2
331 ip._inspect('pinfo', 'nonascii2', detail_level=1)
330 ip._inspect('pinfo', 'nonascii2', detail_level=1)
332
331
333 def test_pinfo_type():
332 def test_pinfo_type():
334 """
333 """
335 type can fail in various edge case, for example `type.__subclass__()`
334 type can fail in various edge case, for example `type.__subclass__()`
336 """
335 """
337 ip._inspect('pinfo', 'type')
336 ip._inspect('pinfo', 'type')
338
337
339
338
340 def test_pinfo_docstring_no_source():
339 def test_pinfo_docstring_no_source():
341 """Docstring should be included with detail_level=1 if there is no source"""
340 """Docstring should be included with detail_level=1 if there is no source"""
342 with AssertPrints('Docstring:'):
341 with AssertPrints('Docstring:'):
343 ip._inspect('pinfo', 'str.format', detail_level=0)
342 ip._inspect('pinfo', 'str.format', detail_level=0)
344 with AssertPrints('Docstring:'):
343 with AssertPrints('Docstring:'):
345 ip._inspect('pinfo', 'str.format', detail_level=1)
344 ip._inspect('pinfo', 'str.format', detail_level=1)
346
345
347
346
348 def test_pinfo_no_docstring_if_source():
347 def test_pinfo_no_docstring_if_source():
349 """Docstring should not be included with detail_level=1 if source is found"""
348 """Docstring should not be included with detail_level=1 if source is found"""
350 def foo():
349 def foo():
351 """foo has a docstring"""
350 """foo has a docstring"""
352
351
353 ip.user_ns['foo'] = foo
352 ip.user_ns['foo'] = foo
354
353
355 with AssertPrints('Docstring:'):
354 with AssertPrints('Docstring:'):
356 ip._inspect('pinfo', 'foo', detail_level=0)
355 ip._inspect('pinfo', 'foo', detail_level=0)
357 with AssertPrints('Source:'):
356 with AssertPrints('Source:'):
358 ip._inspect('pinfo', 'foo', detail_level=1)
357 ip._inspect('pinfo', 'foo', detail_level=1)
359 with AssertNotPrints('Docstring:'):
358 with AssertNotPrints('Docstring:'):
360 ip._inspect('pinfo', 'foo', detail_level=1)
359 ip._inspect('pinfo', 'foo', detail_level=1)
361
360
362
361
363 def test_pinfo_docstring_if_detail_and_no_source():
362 def test_pinfo_docstring_if_detail_and_no_source():
364 """ Docstring should be displayed if source info not available """
363 """ Docstring should be displayed if source info not available """
365 obj_def = '''class Foo(object):
364 obj_def = '''class Foo(object):
366 """ This is a docstring for Foo """
365 """ This is a docstring for Foo """
367 def bar(self):
366 def bar(self):
368 """ This is a docstring for Foo.bar """
367 """ This is a docstring for Foo.bar """
369 pass
368 pass
370 '''
369 '''
371
370
372 ip.run_cell(obj_def)
371 ip.run_cell(obj_def)
373 ip.run_cell('foo = Foo()')
372 ip.run_cell('foo = Foo()')
374
373
375 with AssertNotPrints("Source:"):
374 with AssertNotPrints("Source:"):
376 with AssertPrints('Docstring:'):
375 with AssertPrints('Docstring:'):
377 ip._inspect('pinfo', 'foo', detail_level=0)
376 ip._inspect('pinfo', 'foo', detail_level=0)
378 with AssertPrints('Docstring:'):
377 with AssertPrints('Docstring:'):
379 ip._inspect('pinfo', 'foo', detail_level=1)
378 ip._inspect('pinfo', 'foo', detail_level=1)
380 with AssertPrints('Docstring:'):
379 with AssertPrints('Docstring:'):
381 ip._inspect('pinfo', 'foo.bar', detail_level=0)
380 ip._inspect('pinfo', 'foo.bar', detail_level=0)
382
381
383 with AssertNotPrints('Docstring:'):
382 with AssertNotPrints('Docstring:'):
384 with AssertPrints('Source:'):
383 with AssertPrints('Source:'):
385 ip._inspect('pinfo', 'foo.bar', detail_level=1)
384 ip._inspect('pinfo', 'foo.bar', detail_level=1)
386
385
387
386
388 def test_pinfo_magic():
387 def test_pinfo_magic():
389 with AssertPrints('Docstring:'):
388 with AssertPrints('Docstring:'):
390 ip._inspect('pinfo', 'lsmagic', detail_level=0)
389 ip._inspect('pinfo', 'lsmagic', detail_level=0)
391
390
392 with AssertPrints('Source:'):
391 with AssertPrints('Source:'):
393 ip._inspect('pinfo', 'lsmagic', detail_level=1)
392 ip._inspect('pinfo', 'lsmagic', detail_level=1)
394
393
395
394
396 def test_init_colors():
395 def test_init_colors():
397 # ensure colors are not present in signature info
396 # ensure colors are not present in signature info
398 info = inspector.info(HasSignature)
397 info = inspector.info(HasSignature)
399 init_def = info['init_definition']
398 init_def = info["init_definition"]
400 nt.assert_not_in('[0m', init_def)
399 assert "[0m" not in init_def
401
400
402
401
403 def test_builtin_init():
402 def test_builtin_init():
404 info = inspector.info(list)
403 info = inspector.info(list)
405 init_def = info['init_definition']
404 init_def = info['init_definition']
406 nt.assert_is_not_none(init_def)
405 assert init_def is not None
407
406
408
407
409 def test_render_signature_short():
408 def test_render_signature_short():
410 def short_fun(a=1): pass
409 def short_fun(a=1): pass
411 sig = oinspect._render_signature(
410 sig = oinspect._render_signature(
412 signature(short_fun),
411 signature(short_fun),
413 short_fun.__name__,
412 short_fun.__name__,
414 )
413 )
415 assert sig == "short_fun(a=1)"
414 assert sig == "short_fun(a=1)"
416
415
417
416
418 def test_render_signature_long():
417 def test_render_signature_long():
419 from typing import Optional
418 from typing import Optional
420
419
421 def long_function(
420 def long_function(
422 a_really_long_parameter: int,
421 a_really_long_parameter: int,
423 and_another_long_one: bool = False,
422 and_another_long_one: bool = False,
424 let_us_make_sure_this_is_looong: Optional[str] = None,
423 let_us_make_sure_this_is_looong: Optional[str] = None,
425 ) -> bool: pass
424 ) -> bool: pass
426
425
427 sig = oinspect._render_signature(
426 sig = oinspect._render_signature(
428 signature(long_function),
427 signature(long_function),
429 long_function.__name__,
428 long_function.__name__,
430 )
429 )
431 nt.assert_in(sig, [
430 assert sig in [
432 # Python >=3.9
431 # Python >=3.9
433 '''\
432 '''\
434 long_function(
433 long_function(
435 a_really_long_parameter: int,
434 a_really_long_parameter: int,
436 and_another_long_one: bool = False,
435 and_another_long_one: bool = False,
437 let_us_make_sure_this_is_looong: Optional[str] = None,
436 let_us_make_sure_this_is_looong: Optional[str] = None,
438 ) -> bool\
437 ) -> bool\
439 ''',
438 ''',
440 # Python >=3.7
439 # Python >=3.7
441 '''\
440 '''\
442 long_function(
441 long_function(
443 a_really_long_parameter: int,
442 a_really_long_parameter: int,
444 and_another_long_one: bool = False,
443 and_another_long_one: bool = False,
445 let_us_make_sure_this_is_looong: Union[str, NoneType] = None,
444 let_us_make_sure_this_is_looong: Union[str, NoneType] = None,
446 ) -> bool\
445 ) -> bool\
447 ''', # Python <=3.6
446 ''', # Python <=3.6
448 '''\
447 '''\
449 long_function(
448 long_function(
450 a_really_long_parameter:int,
449 a_really_long_parameter:int,
451 and_another_long_one:bool=False,
450 and_another_long_one:bool=False,
452 let_us_make_sure_this_is_looong:Union[str, NoneType]=None,
451 let_us_make_sure_this_is_looong:Union[str, NoneType]=None,
453 ) -> bool\
452 ) -> bool\
454 ''',
453 ''',
455 ])
454 ]
@@ -1,204 +1,205 b''
1 import errno
1 import errno
2 import os
2 import os
3 import shutil
3 import shutil
4 import sys
4 import sys
5 import tempfile
5 import tempfile
6 import warnings
6 import warnings
7 from unittest.mock import patch
7 from unittest.mock import patch
8
8
9 import nose.tools as nt
10 from testpath import modified_env, assert_isdir, assert_isfile
9 from testpath import modified_env, assert_isdir, assert_isfile
11
10
12 from IPython import paths
11 from IPython import paths
13 from IPython.testing.decorators import skip_win32
12 from IPython.testing.decorators import skip_win32
14 from IPython.utils.tempdir import TemporaryDirectory
13 from IPython.utils.tempdir import TemporaryDirectory
15
14
16 TMP_TEST_DIR = os.path.realpath(tempfile.mkdtemp())
15 TMP_TEST_DIR = os.path.realpath(tempfile.mkdtemp())
17 HOME_TEST_DIR = os.path.join(TMP_TEST_DIR, "home_test_dir")
16 HOME_TEST_DIR = os.path.join(TMP_TEST_DIR, "home_test_dir")
18 XDG_TEST_DIR = os.path.join(HOME_TEST_DIR, "xdg_test_dir")
17 XDG_TEST_DIR = os.path.join(HOME_TEST_DIR, "xdg_test_dir")
19 XDG_CACHE_DIR = os.path.join(HOME_TEST_DIR, "xdg_cache_dir")
18 XDG_CACHE_DIR = os.path.join(HOME_TEST_DIR, "xdg_cache_dir")
20 IP_TEST_DIR = os.path.join(HOME_TEST_DIR,'.ipython')
19 IP_TEST_DIR = os.path.join(HOME_TEST_DIR,'.ipython')
21
20
22 def setup_module():
21 def setup_module():
23 """Setup testenvironment for the module:
22 """Setup testenvironment for the module:
24
23
25 - Adds dummy home dir tree
24 - Adds dummy home dir tree
26 """
25 """
27 # Do not mask exceptions here. In particular, catching WindowsError is a
26 # Do not mask exceptions here. In particular, catching WindowsError is a
28 # problem because that exception is only defined on Windows...
27 # problem because that exception is only defined on Windows...
29 os.makedirs(IP_TEST_DIR)
28 os.makedirs(IP_TEST_DIR)
30 os.makedirs(os.path.join(XDG_TEST_DIR, 'ipython'))
29 os.makedirs(os.path.join(XDG_TEST_DIR, 'ipython'))
31 os.makedirs(os.path.join(XDG_CACHE_DIR, 'ipython'))
30 os.makedirs(os.path.join(XDG_CACHE_DIR, 'ipython'))
32
31
33
32
34 def teardown_module():
33 def teardown_module():
35 """Teardown testenvironment for the module:
34 """Teardown testenvironment for the module:
36
35
37 - Remove dummy home dir tree
36 - Remove dummy home dir tree
38 """
37 """
39 # Note: we remove the parent test dir, which is the root of all test
38 # Note: we remove the parent test dir, which is the root of all test
40 # subdirs we may have created. Use shutil instead of os.removedirs, so
39 # subdirs we may have created. Use shutil instead of os.removedirs, so
41 # that non-empty directories are all recursively removed.
40 # that non-empty directories are all recursively removed.
42 shutil.rmtree(TMP_TEST_DIR)
41 shutil.rmtree(TMP_TEST_DIR)
43
42
44 def patch_get_home_dir(dirpath):
43 def patch_get_home_dir(dirpath):
45 return patch.object(paths, 'get_home_dir', return_value=dirpath)
44 return patch.object(paths, 'get_home_dir', return_value=dirpath)
46
45
47
46
48 def test_get_ipython_dir_1():
47 def test_get_ipython_dir_1():
49 """test_get_ipython_dir_1, Testcase to see if we can call get_ipython_dir without Exceptions."""
48 """test_get_ipython_dir_1, Testcase to see if we can call get_ipython_dir without Exceptions."""
50 env_ipdir = os.path.join("someplace", ".ipython")
49 env_ipdir = os.path.join("someplace", ".ipython")
51 with patch.object(paths, '_writable_dir', return_value=True), \
50 with patch.object(paths, '_writable_dir', return_value=True), \
52 modified_env({'IPYTHONDIR': env_ipdir}):
51 modified_env({'IPYTHONDIR': env_ipdir}):
53 ipdir = paths.get_ipython_dir()
52 ipdir = paths.get_ipython_dir()
54
53
55 nt.assert_equal(ipdir, env_ipdir)
54 assert ipdir == env_ipdir
56
55
57 def test_get_ipython_dir_2():
56 def test_get_ipython_dir_2():
58 """test_get_ipython_dir_2, Testcase to see if we can call get_ipython_dir without Exceptions."""
57 """test_get_ipython_dir_2, Testcase to see if we can call get_ipython_dir without Exceptions."""
59 with patch_get_home_dir('someplace'), \
58 with patch_get_home_dir('someplace'), \
60 patch.object(paths, 'get_xdg_dir', return_value=None), \
59 patch.object(paths, 'get_xdg_dir', return_value=None), \
61 patch.object(paths, '_writable_dir', return_value=True), \
60 patch.object(paths, '_writable_dir', return_value=True), \
62 patch('os.name', "posix"), \
61 patch('os.name', "posix"), \
63 modified_env({'IPYTHON_DIR': None,
62 modified_env({'IPYTHON_DIR': None,
64 'IPYTHONDIR': None,
63 'IPYTHONDIR': None,
65 'XDG_CONFIG_HOME': None
64 'XDG_CONFIG_HOME': None
66 }):
65 }):
67 ipdir = paths.get_ipython_dir()
66 ipdir = paths.get_ipython_dir()
68
67
69 nt.assert_equal(ipdir, os.path.join("someplace", ".ipython"))
68 assert ipdir == os.path.join("someplace", ".ipython")
70
69
71 def test_get_ipython_dir_3():
70 def test_get_ipython_dir_3():
72 """test_get_ipython_dir_3, move XDG if defined, and .ipython doesn't exist."""
71 """test_get_ipython_dir_3, move XDG if defined, and .ipython doesn't exist."""
73 tmphome = TemporaryDirectory()
72 tmphome = TemporaryDirectory()
74 try:
73 try:
75 with patch_get_home_dir(tmphome.name), \
74 with patch_get_home_dir(tmphome.name), \
76 patch('os.name', 'posix'), \
75 patch('os.name', 'posix'), \
77 modified_env({
76 modified_env({
78 'IPYTHON_DIR': None,
77 'IPYTHON_DIR': None,
79 'IPYTHONDIR': None,
78 'IPYTHONDIR': None,
80 'XDG_CONFIG_HOME': XDG_TEST_DIR,
79 'XDG_CONFIG_HOME': XDG_TEST_DIR,
81 }), warnings.catch_warnings(record=True) as w:
80 }), warnings.catch_warnings(record=True) as w:
82 ipdir = paths.get_ipython_dir()
81 ipdir = paths.get_ipython_dir()
83
82
84 nt.assert_equal(ipdir, os.path.join(tmphome.name, ".ipython"))
83 assert ipdir == os.path.join(tmphome.name, ".ipython")
85 if sys.platform != 'darwin':
84 if sys.platform != 'darwin':
86 nt.assert_equal(len(w), 1)
85 assert len(w) == 1
87 nt.assert_in('Moving', str(w[0]))
86 assert "Moving" in str(w[0])
88 finally:
87 finally:
89 tmphome.cleanup()
88 tmphome.cleanup()
90
89
91 def test_get_ipython_dir_4():
90 def test_get_ipython_dir_4():
92 """test_get_ipython_dir_4, warn if XDG and home both exist."""
91 """test_get_ipython_dir_4, warn if XDG and home both exist."""
93 with patch_get_home_dir(HOME_TEST_DIR), \
92 with patch_get_home_dir(HOME_TEST_DIR), \
94 patch('os.name', 'posix'):
93 patch('os.name', 'posix'):
95 try:
94 try:
96 os.mkdir(os.path.join(XDG_TEST_DIR, 'ipython'))
95 os.mkdir(os.path.join(XDG_TEST_DIR, 'ipython'))
97 except OSError as e:
96 except OSError as e:
98 if e.errno != errno.EEXIST:
97 if e.errno != errno.EEXIST:
99 raise
98 raise
100
99
101
100
102 with modified_env({
101 with modified_env({
103 'IPYTHON_DIR': None,
102 'IPYTHON_DIR': None,
104 'IPYTHONDIR': None,
103 'IPYTHONDIR': None,
105 'XDG_CONFIG_HOME': XDG_TEST_DIR,
104 'XDG_CONFIG_HOME': XDG_TEST_DIR,
106 }), warnings.catch_warnings(record=True) as w:
105 }), warnings.catch_warnings(record=True) as w:
107 ipdir = paths.get_ipython_dir()
106 ipdir = paths.get_ipython_dir()
108
107
109 nt.assert_equal(ipdir, os.path.join(HOME_TEST_DIR, ".ipython"))
108 assert ipdir == os.path.join(HOME_TEST_DIR, ".ipython")
110 if sys.platform != 'darwin':
109 if sys.platform != 'darwin':
111 nt.assert_equal(len(w), 1)
110 assert len(w) == 1
112 nt.assert_in('Ignoring', str(w[0]))
111 assert "Ignoring" in str(w[0])
112
113
113
114 def test_get_ipython_dir_5():
114 def test_get_ipython_dir_5():
115 """test_get_ipython_dir_5, use .ipython if exists and XDG defined, but doesn't exist."""
115 """test_get_ipython_dir_5, use .ipython if exists and XDG defined, but doesn't exist."""
116 with patch_get_home_dir(HOME_TEST_DIR), \
116 with patch_get_home_dir(HOME_TEST_DIR), \
117 patch('os.name', 'posix'):
117 patch('os.name', 'posix'):
118 try:
118 try:
119 os.rmdir(os.path.join(XDG_TEST_DIR, 'ipython'))
119 os.rmdir(os.path.join(XDG_TEST_DIR, 'ipython'))
120 except OSError as e:
120 except OSError as e:
121 if e.errno != errno.ENOENT:
121 if e.errno != errno.ENOENT:
122 raise
122 raise
123
123
124 with modified_env({
124 with modified_env({
125 'IPYTHON_DIR': None,
125 'IPYTHON_DIR': None,
126 'IPYTHONDIR': None,
126 'IPYTHONDIR': None,
127 'XDG_CONFIG_HOME': XDG_TEST_DIR,
127 'XDG_CONFIG_HOME': XDG_TEST_DIR,
128 }):
128 }):
129 ipdir = paths.get_ipython_dir()
129 ipdir = paths.get_ipython_dir()
130
130
131 nt.assert_equal(ipdir, IP_TEST_DIR)
131 assert ipdir == IP_TEST_DIR
132
132
133 def test_get_ipython_dir_6():
133 def test_get_ipython_dir_6():
134 """test_get_ipython_dir_6, use home over XDG if defined and neither exist."""
134 """test_get_ipython_dir_6, use home over XDG if defined and neither exist."""
135 xdg = os.path.join(HOME_TEST_DIR, 'somexdg')
135 xdg = os.path.join(HOME_TEST_DIR, 'somexdg')
136 os.mkdir(xdg)
136 os.mkdir(xdg)
137 shutil.rmtree(os.path.join(HOME_TEST_DIR, '.ipython'))
137 shutil.rmtree(os.path.join(HOME_TEST_DIR, '.ipython'))
138 print(paths._writable_dir)
138 print(paths._writable_dir)
139 with patch_get_home_dir(HOME_TEST_DIR), \
139 with patch_get_home_dir(HOME_TEST_DIR), \
140 patch.object(paths, 'get_xdg_dir', return_value=xdg), \
140 patch.object(paths, 'get_xdg_dir', return_value=xdg), \
141 patch('os.name', 'posix'), \
141 patch('os.name', 'posix'), \
142 modified_env({
142 modified_env({
143 'IPYTHON_DIR': None,
143 'IPYTHON_DIR': None,
144 'IPYTHONDIR': None,
144 'IPYTHONDIR': None,
145 'XDG_CONFIG_HOME': None,
145 'XDG_CONFIG_HOME': None,
146 }), warnings.catch_warnings(record=True) as w:
146 }), warnings.catch_warnings(record=True) as w:
147 ipdir = paths.get_ipython_dir()
147 ipdir = paths.get_ipython_dir()
148
148
149 nt.assert_equal(ipdir, os.path.join(HOME_TEST_DIR, '.ipython'))
149 assert ipdir == os.path.join(HOME_TEST_DIR, ".ipython")
150 nt.assert_equal(len(w), 0)
150 assert len(w) == 0
151
151
152 def test_get_ipython_dir_7():
152 def test_get_ipython_dir_7():
153 """test_get_ipython_dir_7, test home directory expansion on IPYTHONDIR"""
153 """test_get_ipython_dir_7, test home directory expansion on IPYTHONDIR"""
154 home_dir = os.path.normpath(os.path.expanduser('~'))
154 home_dir = os.path.normpath(os.path.expanduser('~'))
155 with modified_env({'IPYTHONDIR': os.path.join('~', 'somewhere')}), \
155 with modified_env({'IPYTHONDIR': os.path.join('~', 'somewhere')}), \
156 patch.object(paths, '_writable_dir', return_value=True):
156 patch.object(paths, '_writable_dir', return_value=True):
157 ipdir = paths.get_ipython_dir()
157 ipdir = paths.get_ipython_dir()
158 nt.assert_equal(ipdir, os.path.join(home_dir, 'somewhere'))
158 assert ipdir == os.path.join(home_dir, "somewhere")
159
159
160
160 @skip_win32
161 @skip_win32
161 def test_get_ipython_dir_8():
162 def test_get_ipython_dir_8():
162 """test_get_ipython_dir_8, test / home directory"""
163 """test_get_ipython_dir_8, test / home directory"""
163 if not os.access("/", os.W_OK):
164 if not os.access("/", os.W_OK):
164 # test only when HOME directory actually writable
165 # test only when HOME directory actually writable
165 return
166 return
166
167
167 with patch.object(paths, '_writable_dir', lambda path: bool(path)), \
168 with patch.object(paths, "_writable_dir", lambda path: bool(path)), patch.object(
168 patch.object(paths, 'get_xdg_dir', return_value=None), \
169 paths, "get_xdg_dir", return_value=None
169 modified_env({
170 ), modified_env(
170 'IPYTHON_DIR': None,
171 {
171 'IPYTHONDIR': None,
172 "IPYTHON_DIR": None,
172 'HOME': '/',
173 "IPYTHONDIR": None,
173 }):
174 "HOME": "/",
174 nt.assert_equal(paths.get_ipython_dir(), '/.ipython')
175 }
176 ):
177 assert paths.get_ipython_dir() == "/.ipython"
175
178
176
179
177 def test_get_ipython_cache_dir():
180 def test_get_ipython_cache_dir():
178 with modified_env({'HOME': HOME_TEST_DIR}):
181 with modified_env({'HOME': HOME_TEST_DIR}):
179 if os.name == 'posix' and sys.platform != 'darwin':
182 if os.name == 'posix' and sys.platform != 'darwin':
180 # test default
183 # test default
181 os.makedirs(os.path.join(HOME_TEST_DIR, ".cache"))
184 os.makedirs(os.path.join(HOME_TEST_DIR, ".cache"))
182 with modified_env({'XDG_CACHE_HOME': None}):
185 with modified_env({'XDG_CACHE_HOME': None}):
183 ipdir = paths.get_ipython_cache_dir()
186 ipdir = paths.get_ipython_cache_dir()
184 nt.assert_equal(os.path.join(HOME_TEST_DIR, ".cache", "ipython"),
187 assert os.path.join(HOME_TEST_DIR, ".cache", "ipython") == ipdir
185 ipdir)
186 assert_isdir(ipdir)
188 assert_isdir(ipdir)
187
189
188 # test env override
190 # test env override
189 with modified_env({"XDG_CACHE_HOME": XDG_CACHE_DIR}):
191 with modified_env({"XDG_CACHE_HOME": XDG_CACHE_DIR}):
190 ipdir = paths.get_ipython_cache_dir()
192 ipdir = paths.get_ipython_cache_dir()
191 assert_isdir(ipdir)
193 assert_isdir(ipdir)
192 nt.assert_equal(ipdir, os.path.join(XDG_CACHE_DIR, "ipython"))
194 assert ipdir == os.path.join(XDG_CACHE_DIR, "ipython")
193 else:
195 else:
194 nt.assert_equal(paths.get_ipython_cache_dir(),
196 assert paths.get_ipython_cache_dir() == paths.get_ipython_dir()
195 paths.get_ipython_dir())
196
197
197 def test_get_ipython_package_dir():
198 def test_get_ipython_package_dir():
198 ipdir = paths.get_ipython_package_dir()
199 ipdir = paths.get_ipython_package_dir()
199 assert_isdir(ipdir)
200 assert_isdir(ipdir)
200
201
201
202
202 def test_get_ipython_module_path():
203 def test_get_ipython_module_path():
203 ipapp_path = paths.get_ipython_module_path('IPython.terminal.ipapp')
204 ipapp_path = paths.get_ipython_module_path('IPython.terminal.ipapp')
204 assert_isfile(ipapp_path)
205 assert_isfile(ipapp_path)
@@ -1,170 +1,167 b''
1 # coding: utf-8
1 # coding: utf-8
2 """Tests for profile-related functions.
2 """Tests for profile-related functions.
3
3
4 Currently only the startup-dir functionality is tested, but more tests should
4 Currently only the startup-dir functionality is tested, but more tests should
5 be added for:
5 be added for:
6
6
7 * ipython profile create
7 * ipython profile create
8 * ipython profile list
8 * ipython profile list
9 * ipython profile create --parallel
9 * ipython profile create --parallel
10 * security dir permissions
10 * security dir permissions
11
11
12 Authors
12 Authors
13 -------
13 -------
14
14
15 * MinRK
15 * MinRK
16
16
17 """
17 """
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Imports
20 # Imports
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22
22
23 import shutil
23 import shutil
24 import sys
24 import sys
25 import tempfile
25 import tempfile
26
26
27 from pathlib import Path
27 from pathlib import Path
28 from unittest import TestCase
28 from unittest import TestCase
29
29
30 import nose.tools as nt
31
32 from IPython.core.profileapp import list_profiles_in, list_bundled_profiles
30 from IPython.core.profileapp import list_profiles_in, list_bundled_profiles
33 from IPython.core.profiledir import ProfileDir
31 from IPython.core.profiledir import ProfileDir
34
32
35 from IPython.testing import decorators as dec
33 from IPython.testing import decorators as dec
36 from IPython.testing import tools as tt
34 from IPython.testing import tools as tt
37 from IPython.utils.process import getoutput
35 from IPython.utils.process import getoutput
38 from IPython.utils.tempdir import TemporaryDirectory
36 from IPython.utils.tempdir import TemporaryDirectory
39
37
40 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
41 # Globals
39 # Globals
42 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
43 TMP_TEST_DIR = Path(tempfile.mkdtemp())
41 TMP_TEST_DIR = Path(tempfile.mkdtemp())
44 HOME_TEST_DIR = TMP_TEST_DIR / "home_test_dir"
42 HOME_TEST_DIR = TMP_TEST_DIR / "home_test_dir"
45 IP_TEST_DIR = HOME_TEST_DIR / ".ipython"
43 IP_TEST_DIR = HOME_TEST_DIR / ".ipython"
46
44
47 #
45 #
48 # Setup/teardown functions/decorators
46 # Setup/teardown functions/decorators
49 #
47 #
50
48
51 def setup_module():
49 def setup_module():
52 """Setup test environment for the module:
50 """Setup test environment for the module:
53
51
54 - Adds dummy home dir tree
52 - Adds dummy home dir tree
55 """
53 """
56 # Do not mask exceptions here. In particular, catching WindowsError is a
54 # Do not mask exceptions here. In particular, catching WindowsError is a
57 # problem because that exception is only defined on Windows...
55 # problem because that exception is only defined on Windows...
58 (Path.cwd() / IP_TEST_DIR).mkdir(parents=True)
56 (Path.cwd() / IP_TEST_DIR).mkdir(parents=True)
59
57
60
58
61 def teardown_module():
59 def teardown_module():
62 """Teardown test environment for the module:
60 """Teardown test environment for the module:
63
61
64 - Remove dummy home dir tree
62 - Remove dummy home dir tree
65 """
63 """
66 # Note: we remove the parent test dir, which is the root of all test
64 # Note: we remove the parent test dir, which is the root of all test
67 # subdirs we may have created. Use shutil instead of os.removedirs, so
65 # subdirs we may have created. Use shutil instead of os.removedirs, so
68 # that non-empty directories are all recursively removed.
66 # that non-empty directories are all recursively removed.
69 shutil.rmtree(TMP_TEST_DIR)
67 shutil.rmtree(TMP_TEST_DIR)
70
68
71
69
72 #-----------------------------------------------------------------------------
70 #-----------------------------------------------------------------------------
73 # Test functions
71 # Test functions
74 #-----------------------------------------------------------------------------
72 #-----------------------------------------------------------------------------
75 def win32_without_pywin32():
73 def win32_without_pywin32():
76 if sys.platform == 'win32':
74 if sys.platform == 'win32':
77 try:
75 try:
78 import pywin32
76 import pywin32
79 except ImportError:
77 except ImportError:
80 return True
78 return True
81 return False
79 return False
82
80
83
81
84 class ProfileStartupTest(TestCase):
82 class ProfileStartupTest(TestCase):
85 def setUp(self):
83 def setUp(self):
86 # create profile dir
84 # create profile dir
87 self.pd = ProfileDir.create_profile_dir_by_name(IP_TEST_DIR, "test")
85 self.pd = ProfileDir.create_profile_dir_by_name(IP_TEST_DIR, "test")
88 self.options = ["--ipython-dir", IP_TEST_DIR, "--profile", "test"]
86 self.options = ["--ipython-dir", IP_TEST_DIR, "--profile", "test"]
89 self.fname = TMP_TEST_DIR / "test.py"
87 self.fname = TMP_TEST_DIR / "test.py"
90
88
91 def tearDown(self):
89 def tearDown(self):
92 # We must remove this profile right away so its presence doesn't
90 # We must remove this profile right away so its presence doesn't
93 # confuse other tests.
91 # confuse other tests.
94 shutil.rmtree(self.pd.location)
92 shutil.rmtree(self.pd.location)
95
93
96 def init(self, startup_file, startup, test):
94 def init(self, startup_file, startup, test):
97 # write startup python file
95 # write startup python file
98 with open(Path(self.pd.startup_dir) / startup_file, "w") as f:
96 with open(Path(self.pd.startup_dir) / startup_file, "w") as f:
99 f.write(startup)
97 f.write(startup)
100 # write simple test file, to check that the startup file was run
98 # write simple test file, to check that the startup file was run
101 with open(self.fname, 'w') as f:
99 with open(self.fname, 'w') as f:
102 f.write(test)
100 f.write(test)
103
101
104 def validate(self, output):
102 def validate(self, output):
105 tt.ipexec_validate(self.fname, output, '', options=self.options)
103 tt.ipexec_validate(self.fname, output, '', options=self.options)
106
104
107 @dec.skipif(win32_without_pywin32(), "Test requires pywin32 on Windows")
105 @dec.skipif(win32_without_pywin32(), "Test requires pywin32 on Windows")
108 def test_startup_py(self):
106 def test_startup_py(self):
109 self.init('00-start.py', 'zzz=123\n', 'print(zzz)\n')
107 self.init('00-start.py', 'zzz=123\n', 'print(zzz)\n')
110 self.validate('123')
108 self.validate('123')
111
109
112 @dec.skipif(win32_without_pywin32(), "Test requires pywin32 on Windows")
110 @dec.skipif(win32_without_pywin32(), "Test requires pywin32 on Windows")
113 def test_startup_ipy(self):
111 def test_startup_ipy(self):
114 self.init('00-start.ipy', '%xmode plain\n', '')
112 self.init('00-start.ipy', '%xmode plain\n', '')
115 self.validate('Exception reporting mode: Plain')
113 self.validate('Exception reporting mode: Plain')
116
114
117
115
118 def test_list_profiles_in():
116 def test_list_profiles_in():
119 # No need to remove these directories and files, as they will get nuked in
117 # No need to remove these directories and files, as they will get nuked in
120 # the module-level teardown.
118 # the module-level teardown.
121 td = Path(tempfile.mkdtemp(dir=TMP_TEST_DIR))
119 td = Path(tempfile.mkdtemp(dir=TMP_TEST_DIR))
122 for name in ("profile_foo", "profile_hello", "not_a_profile"):
120 for name in ("profile_foo", "profile_hello", "not_a_profile"):
123 Path(td / name).mkdir(parents=True)
121 Path(td / name).mkdir(parents=True)
124 if dec.unicode_paths:
122 if dec.unicode_paths:
125 Path(td / u"profile_ünicode").mkdir(parents=True)
123 Path(td / u"profile_ünicode").mkdir(parents=True)
126
124
127 with open(td / "profile_file", "w") as f:
125 with open(td / "profile_file", "w") as f:
128 f.write("I am not a profile directory")
126 f.write("I am not a profile directory")
129 profiles = list_profiles_in(td)
127 profiles = list_profiles_in(td)
130
128
131 # unicode normalization can turn u'ünicode' into u'u\0308nicode',
129 # unicode normalization can turn u'ünicode' into u'u\0308nicode',
132 # so only check for *nicode, and that creating a ProfileDir from the
130 # so only check for *nicode, and that creating a ProfileDir from the
133 # name remains valid
131 # name remains valid
134 found_unicode = False
132 found_unicode = False
135 for p in list(profiles):
133 for p in list(profiles):
136 if p.endswith('nicode'):
134 if p.endswith('nicode'):
137 pd = ProfileDir.find_profile_dir_by_name(td, p)
135 pd = ProfileDir.find_profile_dir_by_name(td, p)
138 profiles.remove(p)
136 profiles.remove(p)
139 found_unicode = True
137 found_unicode = True
140 break
138 break
141 if dec.unicode_paths:
139 if dec.unicode_paths:
142 nt.assert_true(found_unicode)
140 assert found_unicode is True
143 nt.assert_equal(set(profiles), {'foo', 'hello'})
141 assert set(profiles) == {"foo", "hello"}
144
142
145
143
146 def test_list_bundled_profiles():
144 def test_list_bundled_profiles():
147 # This variable will need to be updated when a new profile gets bundled
145 # This variable will need to be updated when a new profile gets bundled
148 bundled = sorted(list_bundled_profiles())
146 bundled = sorted(list_bundled_profiles())
149 nt.assert_equal(bundled, [])
147 assert bundled == []
150
148
151
149
152 def test_profile_create_ipython_dir():
150 def test_profile_create_ipython_dir():
153 """ipython profile create respects --ipython-dir"""
151 """ipython profile create respects --ipython-dir"""
154 with TemporaryDirectory() as td:
152 with TemporaryDirectory() as td:
155 getoutput(
153 getoutput(
156 [
154 [
157 sys.executable,
155 sys.executable,
158 "-m",
156 "-m",
159 "IPython",
157 "IPython",
160 "profile",
158 "profile",
161 "create",
159 "create",
162 "foo",
160 "foo",
163 "--ipython-dir=%s" % td,
161 "--ipython-dir=%s" % td,
164 ]
162 ]
165 )
163 )
166 profile_dir = Path(td) / "profile_foo"
164 profile_dir = Path(td) / "profile_foo"
167 assert Path(profile_dir).exists()
165 assert Path(profile_dir).exists()
168 ipython_config = profile_dir / "ipython_config.py"
166 ipython_config = profile_dir / "ipython_config.py"
169 assert Path(ipython_config).exists()
167 assert Path(ipython_config).exists()
170
@@ -1,274 +1,273 b''
1 """Tests for pylab tools module.
1 """Tests for pylab tools module.
2 """
2 """
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7
7
8 from binascii import a2b_base64
8 from binascii import a2b_base64
9 from io import BytesIO
9 from io import BytesIO
10
10
11 import matplotlib
11 import matplotlib
12 matplotlib.use('Agg')
12 matplotlib.use('Agg')
13 from matplotlib.figure import Figure
13 from matplotlib.figure import Figure
14
14
15 from nose import SkipTest
16 import nose.tools as nt
17
18 from matplotlib import pyplot as plt
15 from matplotlib import pyplot as plt
19 import matplotlib_inline
16 from matplotlib_inline import backend_inline
20 import numpy as np
17 import numpy as np
18 import pytest
21
19
22 from IPython.core.getipython import get_ipython
20 from IPython.core.getipython import get_ipython
23 from IPython.core.interactiveshell import InteractiveShell
21 from IPython.core.interactiveshell import InteractiveShell
24 from IPython.core.display import _PNG, _JPEG
22 from IPython.core.display import _PNG, _JPEG
25 from .. import pylabtools as pt
23 from .. import pylabtools as pt
26
24
27 from IPython.testing import decorators as dec
25 from IPython.testing import decorators as dec
28
26
29
27
30 def test_figure_to_svg():
28 def test_figure_to_svg():
31 # simple empty-figure test
29 # simple empty-figure test
32 fig = plt.figure()
30 fig = plt.figure()
33 nt.assert_equal(pt.print_figure(fig, 'svg'), None)
31 assert pt.print_figure(fig, "svg") is None
34
32
35 plt.close('all')
33 plt.close('all')
36
34
37 # simple check for at least svg-looking output
35 # simple check for at least svg-looking output
38 fig = plt.figure()
36 fig = plt.figure()
39 ax = fig.add_subplot(1,1,1)
37 ax = fig.add_subplot(1,1,1)
40 ax.plot([1,2,3])
38 ax.plot([1,2,3])
41 plt.draw()
39 plt.draw()
42 svg = pt.print_figure(fig, 'svg')[:100].lower()
40 svg = pt.print_figure(fig, "svg")[:100].lower()
43 nt.assert_in(u'doctype svg', svg)
41 assert "doctype svg" in svg
42
44
43
45 def _check_pil_jpeg_bytes():
44 def _check_pil_jpeg_bytes():
46 """Skip if PIL can't write JPEGs to BytesIO objects"""
45 """Skip if PIL can't write JPEGs to BytesIO objects"""
47 # PIL's JPEG plugin can't write to BytesIO objects
46 # PIL's JPEG plugin can't write to BytesIO objects
48 # Pillow fixes this
47 # Pillow fixes this
49 from PIL import Image
48 from PIL import Image
50 buf = BytesIO()
49 buf = BytesIO()
51 img = Image.new("RGB", (4,4))
50 img = Image.new("RGB", (4,4))
52 try:
51 try:
53 img.save(buf, 'jpeg')
52 img.save(buf, 'jpeg')
54 except Exception as e:
53 except Exception as e:
55 ename = e.__class__.__name__
54 ename = e.__class__.__name__
56 raise SkipTest("PIL can't write JPEG to BytesIO: %s: %s" % (ename, e)) from e
55 raise pytest.skip("PIL can't write JPEG to BytesIO: %s: %s" % (ename, e)) from e
57
56
58 @dec.skip_without("PIL.Image")
57 @dec.skip_without("PIL.Image")
59 def test_figure_to_jpeg():
58 def test_figure_to_jpeg():
60 _check_pil_jpeg_bytes()
59 _check_pil_jpeg_bytes()
61 # simple check for at least jpeg-looking output
60 # simple check for at least jpeg-looking output
62 fig = plt.figure()
61 fig = plt.figure()
63 ax = fig.add_subplot(1,1,1)
62 ax = fig.add_subplot(1,1,1)
64 ax.plot([1,2,3])
63 ax.plot([1,2,3])
65 plt.draw()
64 plt.draw()
66 jpeg = pt.print_figure(fig, 'jpeg', pil_kwargs={'optimize': 50})[:100].lower()
65 jpeg = pt.print_figure(fig, 'jpeg', pil_kwargs={'optimize': 50})[:100].lower()
67 assert jpeg.startswith(_JPEG)
66 assert jpeg.startswith(_JPEG)
68
67
69 def test_retina_figure():
68 def test_retina_figure():
70 # simple empty-figure test
69 # simple empty-figure test
71 fig = plt.figure()
70 fig = plt.figure()
72 nt.assert_equal(pt.retina_figure(fig), None)
71 assert pt.retina_figure(fig) == None
73 plt.close('all')
72 plt.close('all')
74
73
75 fig = plt.figure()
74 fig = plt.figure()
76 ax = fig.add_subplot(1,1,1)
75 ax = fig.add_subplot(1,1,1)
77 ax.plot([1,2,3])
76 ax.plot([1,2,3])
78 plt.draw()
77 plt.draw()
79 png, md = pt.retina_figure(fig)
78 png, md = pt.retina_figure(fig)
80 assert png.startswith(_PNG)
79 assert png.startswith(_PNG)
81 nt.assert_in('width', md)
80 assert "width" in md
82 nt.assert_in('height', md)
81 assert "height" in md
82
83
83
84 _fmt_mime_map = {
84 _fmt_mime_map = {
85 'png': 'image/png',
85 'png': 'image/png',
86 'jpeg': 'image/jpeg',
86 'jpeg': 'image/jpeg',
87 'pdf': 'application/pdf',
87 'pdf': 'application/pdf',
88 'retina': 'image/png',
88 'retina': 'image/png',
89 'svg': 'image/svg+xml',
89 'svg': 'image/svg+xml',
90 }
90 }
91
91
92 def test_select_figure_formats_str():
92 def test_select_figure_formats_str():
93 ip = get_ipython()
93 ip = get_ipython()
94 for fmt, active_mime in _fmt_mime_map.items():
94 for fmt, active_mime in _fmt_mime_map.items():
95 pt.select_figure_formats(ip, fmt)
95 pt.select_figure_formats(ip, fmt)
96 for mime, f in ip.display_formatter.formatters.items():
96 for mime, f in ip.display_formatter.formatters.items():
97 if mime == active_mime:
97 if mime == active_mime:
98 nt.assert_in(Figure, f)
98 assert Figure in f
99 else:
99 else:
100 nt.assert_not_in(Figure, f)
100 assert Figure not in f
101
101
102 def test_select_figure_formats_kwargs():
102 def test_select_figure_formats_kwargs():
103 ip = get_ipython()
103 ip = get_ipython()
104 kwargs = dict(quality=10, bbox_inches='tight')
104 kwargs = dict(quality=10, bbox_inches='tight')
105 pt.select_figure_formats(ip, 'png', **kwargs)
105 pt.select_figure_formats(ip, 'png', **kwargs)
106 formatter = ip.display_formatter.formatters['image/png']
106 formatter = ip.display_formatter.formatters['image/png']
107 f = formatter.lookup_by_type(Figure)
107 f = formatter.lookup_by_type(Figure)
108 cell = f.keywords
108 cell = f.keywords
109 expected = kwargs
109 expected = kwargs
110 expected["base64"] = True
110 expected["base64"] = True
111 expected["fmt"] = "png"
111 expected["fmt"] = "png"
112 assert cell == expected
112 assert cell == expected
113
113
114 # check that the formatter doesn't raise
114 # check that the formatter doesn't raise
115 fig = plt.figure()
115 fig = plt.figure()
116 ax = fig.add_subplot(1,1,1)
116 ax = fig.add_subplot(1,1,1)
117 ax.plot([1,2,3])
117 ax.plot([1,2,3])
118 plt.draw()
118 plt.draw()
119 formatter.enabled = True
119 formatter.enabled = True
120 png = formatter(fig)
120 png = formatter(fig)
121 assert isinstance(png, str)
121 assert isinstance(png, str)
122 png_bytes = a2b_base64(png)
122 png_bytes = a2b_base64(png)
123 assert png_bytes.startswith(_PNG)
123 assert png_bytes.startswith(_PNG)
124
124
125 def test_select_figure_formats_set():
125 def test_select_figure_formats_set():
126 ip = get_ipython()
126 ip = get_ipython()
127 for fmts in [
127 for fmts in [
128 {'png', 'svg'},
128 {'png', 'svg'},
129 ['png'],
129 ['png'],
130 ('jpeg', 'pdf', 'retina'),
130 ('jpeg', 'pdf', 'retina'),
131 {'svg'},
131 {'svg'},
132 ]:
132 ]:
133 active_mimes = {_fmt_mime_map[fmt] for fmt in fmts}
133 active_mimes = {_fmt_mime_map[fmt] for fmt in fmts}
134 pt.select_figure_formats(ip, fmts)
134 pt.select_figure_formats(ip, fmts)
135 for mime, f in ip.display_formatter.formatters.items():
135 for mime, f in ip.display_formatter.formatters.items():
136 if mime in active_mimes:
136 if mime in active_mimes:
137 nt.assert_in(Figure, f)
137 assert Figure in f
138 else:
138 else:
139 nt.assert_not_in(Figure, f)
139 assert Figure not in f
140
140
141 def test_select_figure_formats_bad():
141 def test_select_figure_formats_bad():
142 ip = get_ipython()
142 ip = get_ipython()
143 with nt.assert_raises(ValueError):
143 with pytest.raises(ValueError):
144 pt.select_figure_formats(ip, 'foo')
144 pt.select_figure_formats(ip, 'foo')
145 with nt.assert_raises(ValueError):
145 with pytest.raises(ValueError):
146 pt.select_figure_formats(ip, {'png', 'foo'})
146 pt.select_figure_formats(ip, {'png', 'foo'})
147 with nt.assert_raises(ValueError):
147 with pytest.raises(ValueError):
148 pt.select_figure_formats(ip, ['retina', 'pdf', 'bar', 'bad'])
148 pt.select_figure_formats(ip, ['retina', 'pdf', 'bar', 'bad'])
149
149
150 def test_import_pylab():
150 def test_import_pylab():
151 ns = {}
151 ns = {}
152 pt.import_pylab(ns, import_all=False)
152 pt.import_pylab(ns, import_all=False)
153 nt.assert_true('plt' in ns)
153 assert "plt" in ns
154 nt.assert_equal(ns['np'], np)
154 assert ns["np"] == np
155
155
156
156 from traitlets.config import Config
157 from traitlets.config import Config
157
158
158
159
159 class TestPylabSwitch(object):
160 class TestPylabSwitch(object):
160 class Shell(InteractiveShell):
161 class Shell(InteractiveShell):
161 def init_history(self):
162 def init_history(self):
162 """Sets up the command history, and starts regular autosaves."""
163 """Sets up the command history, and starts regular autosaves."""
163 self.config.HistoryManager.hist_file = ":memory:"
164 self.config.HistoryManager.hist_file = ":memory:"
164 super().init_history()
165 super().init_history()
165
166
166 def enable_gui(self, gui):
167 def enable_gui(self, gui):
167 pass
168 pass
168
169
169 def setup(self):
170 def setup(self):
170 import matplotlib
171 import matplotlib
171 def act_mpl(backend):
172 def act_mpl(backend):
172 matplotlib.rcParams['backend'] = backend
173 matplotlib.rcParams['backend'] = backend
173
174
174 # Save rcParams since they get modified
175 # Save rcParams since they get modified
175 self._saved_rcParams = matplotlib.rcParams
176 self._saved_rcParams = matplotlib.rcParams
176 self._saved_rcParamsOrig = matplotlib.rcParamsOrig
177 self._saved_rcParamsOrig = matplotlib.rcParamsOrig
177 matplotlib.rcParams = dict(backend='Qt4Agg')
178 matplotlib.rcParams = dict(backend='Qt4Agg')
178 matplotlib.rcParamsOrig = dict(backend='Qt4Agg')
179 matplotlib.rcParamsOrig = dict(backend='Qt4Agg')
179
180
180 # Mock out functions
181 # Mock out functions
181 self._save_am = pt.activate_matplotlib
182 self._save_am = pt.activate_matplotlib
182 pt.activate_matplotlib = act_mpl
183 pt.activate_matplotlib = act_mpl
183 self._save_ip = pt.import_pylab
184 self._save_ip = pt.import_pylab
184 pt.import_pylab = lambda *a,**kw:None
185 pt.import_pylab = lambda *a,**kw:None
185 self._save_cis = matplotlib_inline.backend_inline.configure_inline_support
186 self._save_cis = backend_inline.configure_inline_support
186 matplotlib_inline.backend_inline.configure_inline_support = (
187 backend_inline.configure_inline_support = lambda *a, **kw: None
187 lambda *a, **kw: None
188 )
189
188
190 def teardown(self):
189 def teardown(self):
191 pt.activate_matplotlib = self._save_am
190 pt.activate_matplotlib = self._save_am
192 pt.import_pylab = self._save_ip
191 pt.import_pylab = self._save_ip
193 matplotlib_inline.backend_inline.configure_inline_support = self._save_cis
192 backend_inline.configure_inline_support = self._save_cis
194 import matplotlib
193 import matplotlib
195 matplotlib.rcParams = self._saved_rcParams
194 matplotlib.rcParams = self._saved_rcParams
196 matplotlib.rcParamsOrig = self._saved_rcParamsOrig
195 matplotlib.rcParamsOrig = self._saved_rcParamsOrig
197
196
198 def test_qt(self):
197 def test_qt(self):
199
198
200 s = self.Shell()
199 s = self.Shell()
201 gui, backend = s.enable_matplotlib(None)
200 gui, backend = s.enable_matplotlib(None)
202 nt.assert_equal(gui, 'qt')
201 assert gui == "qt"
203 nt.assert_equal(s.pylab_gui_select, 'qt')
202 assert s.pylab_gui_select == "qt"
204
203
205 gui, backend = s.enable_matplotlib('inline')
204 gui, backend = s.enable_matplotlib("inline")
206 nt.assert_equal(gui, 'inline')
205 assert gui == "inline"
207 nt.assert_equal(s.pylab_gui_select, 'qt')
206 assert s.pylab_gui_select == "qt"
208
207
209 gui, backend = s.enable_matplotlib('qt')
208 gui, backend = s.enable_matplotlib("qt")
210 nt.assert_equal(gui, 'qt')
209 assert gui == "qt"
211 nt.assert_equal(s.pylab_gui_select, 'qt')
210 assert s.pylab_gui_select == "qt"
212
211
213 gui, backend = s.enable_matplotlib('inline')
212 gui, backend = s.enable_matplotlib("inline")
214 nt.assert_equal(gui, 'inline')
213 assert gui == "inline"
215 nt.assert_equal(s.pylab_gui_select, 'qt')
214 assert s.pylab_gui_select == "qt"
216
215
217 gui, backend = s.enable_matplotlib()
216 gui, backend = s.enable_matplotlib()
218 nt.assert_equal(gui, 'qt')
217 assert gui == "qt"
219 nt.assert_equal(s.pylab_gui_select, 'qt')
218 assert s.pylab_gui_select == "qt"
220
219
221 def test_inline(self):
220 def test_inline(self):
222 s = self.Shell()
221 s = self.Shell()
223 gui, backend = s.enable_matplotlib('inline')
222 gui, backend = s.enable_matplotlib("inline")
224 nt.assert_equal(gui, 'inline')
223 assert gui == "inline"
225 nt.assert_equal(s.pylab_gui_select, None)
224 assert s.pylab_gui_select == None
226
225
227 gui, backend = s.enable_matplotlib('inline')
226 gui, backend = s.enable_matplotlib("inline")
228 nt.assert_equal(gui, 'inline')
227 assert gui == "inline"
229 nt.assert_equal(s.pylab_gui_select, None)
228 assert s.pylab_gui_select == None
230
229
231 gui, backend = s.enable_matplotlib('qt')
230 gui, backend = s.enable_matplotlib("qt")
232 nt.assert_equal(gui, 'qt')
231 assert gui == "qt"
233 nt.assert_equal(s.pylab_gui_select, 'qt')
232 assert s.pylab_gui_select == "qt"
234
233
235 def test_inline_twice(self):
234 def test_inline_twice(self):
236 "Using '%matplotlib inline' twice should not reset formatters"
235 "Using '%matplotlib inline' twice should not reset formatters"
237
236
238 ip = self.Shell()
237 ip = self.Shell()
239 gui, backend = ip.enable_matplotlib('inline')
238 gui, backend = ip.enable_matplotlib("inline")
240 nt.assert_equal(gui, 'inline')
239 assert gui == "inline"
241
240
242 fmts = {'png'}
241 fmts = {'png'}
243 active_mimes = {_fmt_mime_map[fmt] for fmt in fmts}
242 active_mimes = {_fmt_mime_map[fmt] for fmt in fmts}
244 pt.select_figure_formats(ip, fmts)
243 pt.select_figure_formats(ip, fmts)
245
244
246 gui, backend = ip.enable_matplotlib('inline')
245 gui, backend = ip.enable_matplotlib("inline")
247 nt.assert_equal(gui, 'inline')
246 assert gui == "inline"
248
247
249 for mime, f in ip.display_formatter.formatters.items():
248 for mime, f in ip.display_formatter.formatters.items():
250 if mime in active_mimes:
249 if mime in active_mimes:
251 nt.assert_in(Figure, f)
250 assert Figure in f
252 else:
251 else:
253 nt.assert_not_in(Figure, f)
252 assert Figure not in f
254
253
255 def test_qt_gtk(self):
254 def test_qt_gtk(self):
256 s = self.Shell()
255 s = self.Shell()
257 gui, backend = s.enable_matplotlib('qt')
256 gui, backend = s.enable_matplotlib("qt")
258 nt.assert_equal(gui, 'qt')
257 assert gui == "qt"
259 nt.assert_equal(s.pylab_gui_select, 'qt')
258 assert s.pylab_gui_select == "qt"
260
259
261 gui, backend = s.enable_matplotlib('gtk')
260 gui, backend = s.enable_matplotlib("gtk")
262 nt.assert_equal(gui, 'qt')
261 assert gui == "qt"
263 nt.assert_equal(s.pylab_gui_select, 'qt')
262 assert s.pylab_gui_select == "qt"
264
263
265
264
266 def test_no_gui_backends():
265 def test_no_gui_backends():
267 for k in ['agg', 'svg', 'pdf', 'ps']:
266 for k in ['agg', 'svg', 'pdf', 'ps']:
268 assert k not in pt.backend2gui
267 assert k not in pt.backend2gui
269
268
270
269
271 def test_figure_no_canvas():
270 def test_figure_no_canvas():
272 fig = Figure()
271 fig = Figure()
273 fig.canvas = None
272 fig.canvas = None
274 pt.print_figure(fig)
273 pt.print_figure(fig)
@@ -1,601 +1,599 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """Tests for code execution (%run and related), which is particularly tricky.
2 """Tests for code execution (%run and related), which is particularly tricky.
3
3
4 Because of how %run manages namespaces, and the fact that we are trying here to
4 Because of how %run manages namespaces, and the fact that we are trying here to
5 verify subtle object deletion and reference counting issues, the %run tests
5 verify subtle object deletion and reference counting issues, the %run tests
6 will be kept in this separate file. This makes it easier to aggregate in one
6 will be kept in this separate file. This makes it easier to aggregate in one
7 place the tricks needed to handle it; most other magics are much easier to test
7 place the tricks needed to handle it; most other magics are much easier to test
8 and we do so in a common test_magic file.
8 and we do so in a common test_magic file.
9
9
10 Note that any test using `run -i` should make sure to do a `reset` afterwards,
10 Note that any test using `run -i` should make sure to do a `reset` afterwards,
11 as otherwise it may influence later tests.
11 as otherwise it may influence later tests.
12 """
12 """
13
13
14 # Copyright (c) IPython Development Team.
14 # Copyright (c) IPython Development Team.
15 # Distributed under the terms of the Modified BSD License.
15 # Distributed under the terms of the Modified BSD License.
16
16
17
17
18
18
19 import functools
19 import functools
20 import os
20 import os
21 from os.path import join as pjoin
21 from os.path import join as pjoin
22 import random
22 import random
23 import string
23 import string
24 import sys
24 import sys
25 import textwrap
25 import textwrap
26 import unittest
26 import unittest
27 from unittest.mock import patch
27 from unittest.mock import patch
28
28
29 import nose.tools as nt
29 import pytest
30 from nose import SkipTest
31
30
32 from IPython.testing import decorators as dec
31 from IPython.testing import decorators as dec
33 from IPython.testing import tools as tt
32 from IPython.testing import tools as tt
34 from IPython.utils.io import capture_output
33 from IPython.utils.io import capture_output
35 from IPython.utils.tempdir import TemporaryDirectory
34 from IPython.utils.tempdir import TemporaryDirectory
36 from IPython.core import debugger
35 from IPython.core import debugger
37
36
38 def doctest_refbug():
37 def doctest_refbug():
39 """Very nasty problem with references held by multiple runs of a script.
38 """Very nasty problem with references held by multiple runs of a script.
40 See: https://github.com/ipython/ipython/issues/141
39 See: https://github.com/ipython/ipython/issues/141
41
40
42 In [1]: _ip.clear_main_mod_cache()
41 In [1]: _ip.clear_main_mod_cache()
43 # random
42 # random
44
43
45 In [2]: %run refbug
44 In [2]: %run refbug
46
45
47 In [3]: call_f()
46 In [3]: call_f()
48 lowercased: hello
47 lowercased: hello
49
48
50 In [4]: %run refbug
49 In [4]: %run refbug
51
50
52 In [5]: call_f()
51 In [5]: call_f()
53 lowercased: hello
52 lowercased: hello
54 lowercased: hello
53 lowercased: hello
55 """
54 """
56
55
57
56
58 def doctest_run_builtins():
57 def doctest_run_builtins():
59 r"""Check that %run doesn't damage __builtins__.
58 r"""Check that %run doesn't damage __builtins__.
60
59
61 In [1]: import tempfile
60 In [1]: import tempfile
62
61
63 In [2]: bid1 = id(__builtins__)
62 In [2]: bid1 = id(__builtins__)
64
63
65 In [3]: fname = tempfile.mkstemp('.py')[1]
64 In [3]: fname = tempfile.mkstemp('.py')[1]
66
65
67 In [3]: f = open(fname,'w')
66 In [3]: f = open(fname,'w')
68
67
69 In [4]: dummy= f.write('pass\n')
68 In [4]: dummy= f.write('pass\n')
70
69
71 In [5]: f.flush()
70 In [5]: f.flush()
72
71
73 In [6]: t1 = type(__builtins__)
72 In [6]: t1 = type(__builtins__)
74
73
75 In [7]: %run $fname
74 In [7]: %run $fname
76
75
77 In [7]: f.close()
76 In [7]: f.close()
78
77
79 In [8]: bid2 = id(__builtins__)
78 In [8]: bid2 = id(__builtins__)
80
79
81 In [9]: t2 = type(__builtins__)
80 In [9]: t2 = type(__builtins__)
82
81
83 In [10]: t1 == t2
82 In [10]: t1 == t2
84 Out[10]: True
83 Out[10]: True
85
84
86 In [10]: bid1 == bid2
85 In [10]: bid1 == bid2
87 Out[10]: True
86 Out[10]: True
88
87
89 In [12]: try:
88 In [12]: try:
90 ....: os.unlink(fname)
89 ....: os.unlink(fname)
91 ....: except:
90 ....: except:
92 ....: pass
91 ....: pass
93 ....:
92 ....:
94 """
93 """
95
94
96
95
97 def doctest_run_option_parser():
96 def doctest_run_option_parser():
98 r"""Test option parser in %run.
97 r"""Test option parser in %run.
99
98
100 In [1]: %run print_argv.py
99 In [1]: %run print_argv.py
101 []
100 []
102
101
103 In [2]: %run print_argv.py print*.py
102 In [2]: %run print_argv.py print*.py
104 ['print_argv.py']
103 ['print_argv.py']
105
104
106 In [3]: %run -G print_argv.py print*.py
105 In [3]: %run -G print_argv.py print*.py
107 ['print*.py']
106 ['print*.py']
108
107
109 """
108 """
110
109
111
110
112 @dec.skip_win32
111 @dec.skip_win32
113 def doctest_run_option_parser_for_posix():
112 def doctest_run_option_parser_for_posix():
114 r"""Test option parser in %run (Linux/OSX specific).
113 r"""Test option parser in %run (Linux/OSX specific).
115
114
116 You need double quote to escape glob in POSIX systems:
115 You need double quote to escape glob in POSIX systems:
117
116
118 In [1]: %run print_argv.py print\\*.py
117 In [1]: %run print_argv.py print\\*.py
119 ['print*.py']
118 ['print*.py']
120
119
121 You can't use quote to escape glob in POSIX systems:
120 You can't use quote to escape glob in POSIX systems:
122
121
123 In [2]: %run print_argv.py 'print*.py'
122 In [2]: %run print_argv.py 'print*.py'
124 ['print_argv.py']
123 ['print_argv.py']
125
124
126 """
125 """
127
126
128
127
129 @dec.skip_if_not_win32
128 @dec.skip_if_not_win32
130 def doctest_run_option_parser_for_windows():
129 def doctest_run_option_parser_for_windows():
131 r"""Test option parser in %run (Windows specific).
130 r"""Test option parser in %run (Windows specific).
132
131
133 In Windows, you can't escape ``*` `by backslash:
132 In Windows, you can't escape ``*` `by backslash:
134
133
135 In [1]: %run print_argv.py print\\*.py
134 In [1]: %run print_argv.py print\\*.py
136 ['print\\*.py']
135 ['print\\*.py']
137
136
138 You can use quote to escape glob:
137 You can use quote to escape glob:
139
138
140 In [2]: %run print_argv.py 'print*.py'
139 In [2]: %run print_argv.py 'print*.py'
141 ['print*.py']
140 ['print*.py']
142
141
143 """
142 """
144
143
145
144
146 def doctest_reset_del():
145 def doctest_reset_del():
147 """Test that resetting doesn't cause errors in __del__ methods.
146 """Test that resetting doesn't cause errors in __del__ methods.
148
147
149 In [2]: class A(object):
148 In [2]: class A(object):
150 ...: def __del__(self):
149 ...: def __del__(self):
151 ...: print(str("Hi"))
150 ...: print(str("Hi"))
152 ...:
151 ...:
153
152
154 In [3]: a = A()
153 In [3]: a = A()
155
154
156 In [4]: get_ipython().reset()
155 In [4]: get_ipython().reset()
157 Hi
156 Hi
158
157
159 In [5]: 1+1
158 In [5]: 1+1
160 Out[5]: 2
159 Out[5]: 2
161 """
160 """
162
161
163 # For some tests, it will be handy to organize them in a class with a common
162 # For some tests, it will be handy to organize them in a class with a common
164 # setup that makes a temp file
163 # setup that makes a temp file
165
164
166 class TestMagicRunPass(tt.TempFileMixin):
165 class TestMagicRunPass(tt.TempFileMixin):
167
166
168 def setUp(self):
167 def setUp(self):
169 content = "a = [1,2,3]\nb = 1"
168 content = "a = [1,2,3]\nb = 1"
170 self.mktmp(content)
169 self.mktmp(content)
171
170
172 def run_tmpfile(self):
171 def run_tmpfile(self):
173 _ip = get_ipython()
172 _ip = get_ipython()
174 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
173 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
175 # See below and ticket https://bugs.launchpad.net/bugs/366353
174 # See below and ticket https://bugs.launchpad.net/bugs/366353
176 _ip.magic('run %s' % self.fname)
175 _ip.magic('run %s' % self.fname)
177
176
178 def run_tmpfile_p(self):
177 def run_tmpfile_p(self):
179 _ip = get_ipython()
178 _ip = get_ipython()
180 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
179 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
181 # See below and ticket https://bugs.launchpad.net/bugs/366353
180 # See below and ticket https://bugs.launchpad.net/bugs/366353
182 _ip.magic('run -p %s' % self.fname)
181 _ip.magic('run -p %s' % self.fname)
183
182
184 def test_builtins_id(self):
183 def test_builtins_id(self):
185 """Check that %run doesn't damage __builtins__ """
184 """Check that %run doesn't damage __builtins__ """
186 _ip = get_ipython()
185 _ip = get_ipython()
187 # Test that the id of __builtins__ is not modified by %run
186 # Test that the id of __builtins__ is not modified by %run
188 bid1 = id(_ip.user_ns['__builtins__'])
187 bid1 = id(_ip.user_ns['__builtins__'])
189 self.run_tmpfile()
188 self.run_tmpfile()
190 bid2 = id(_ip.user_ns['__builtins__'])
189 bid2 = id(_ip.user_ns['__builtins__'])
191 nt.assert_equal(bid1, bid2)
190 assert bid1 == bid2
192
191
193 def test_builtins_type(self):
192 def test_builtins_type(self):
194 """Check that the type of __builtins__ doesn't change with %run.
193 """Check that the type of __builtins__ doesn't change with %run.
195
194
196 However, the above could pass if __builtins__ was already modified to
195 However, the above could pass if __builtins__ was already modified to
197 be a dict (it should be a module) by a previous use of %run. So we
196 be a dict (it should be a module) by a previous use of %run. So we
198 also check explicitly that it really is a module:
197 also check explicitly that it really is a module:
199 """
198 """
200 _ip = get_ipython()
199 _ip = get_ipython()
201 self.run_tmpfile()
200 self.run_tmpfile()
202 nt.assert_equal(type(_ip.user_ns['__builtins__']),type(sys))
201 assert type(_ip.user_ns["__builtins__"]) == type(sys)
203
202
204 def test_run_profile( self ):
203 def test_run_profile(self):
205 """Test that the option -p, which invokes the profiler, do not
204 """Test that the option -p, which invokes the profiler, do not
206 crash by invoking execfile"""
205 crash by invoking execfile"""
207 self.run_tmpfile_p()
206 self.run_tmpfile_p()
208
207
209 def test_run_debug_twice(self):
208 def test_run_debug_twice(self):
210 # https://github.com/ipython/ipython/issues/10028
209 # https://github.com/ipython/ipython/issues/10028
211 _ip = get_ipython()
210 _ip = get_ipython()
212 with tt.fake_input(['c']):
211 with tt.fake_input(['c']):
213 _ip.magic('run -d %s' % self.fname)
212 _ip.magic('run -d %s' % self.fname)
214 with tt.fake_input(['c']):
213 with tt.fake_input(['c']):
215 _ip.magic('run -d %s' % self.fname)
214 _ip.magic('run -d %s' % self.fname)
216
215
217 def test_run_debug_twice_with_breakpoint(self):
216 def test_run_debug_twice_with_breakpoint(self):
218 """Make a valid python temp file."""
217 """Make a valid python temp file."""
219 _ip = get_ipython()
218 _ip = get_ipython()
220 with tt.fake_input(['b 2', 'c', 'c']):
219 with tt.fake_input(['b 2', 'c', 'c']):
221 _ip.magic('run -d %s' % self.fname)
220 _ip.magic('run -d %s' % self.fname)
222
221
223 with tt.fake_input(['c']):
222 with tt.fake_input(['c']):
224 with tt.AssertNotPrints('KeyError'):
223 with tt.AssertNotPrints('KeyError'):
225 _ip.magic('run -d %s' % self.fname)
224 _ip.magic('run -d %s' % self.fname)
226
225
227
226
228 class TestMagicRunSimple(tt.TempFileMixin):
227 class TestMagicRunSimple(tt.TempFileMixin):
229
228
230 def test_simpledef(self):
229 def test_simpledef(self):
231 """Test that simple class definitions work."""
230 """Test that simple class definitions work."""
232 src = ("class foo: pass\n"
231 src = ("class foo: pass\n"
233 "def f(): return foo()")
232 "def f(): return foo()")
234 self.mktmp(src)
233 self.mktmp(src)
235 _ip.magic('run %s' % self.fname)
234 _ip.magic("run %s" % self.fname)
236 _ip.run_cell('t = isinstance(f(), foo)')
235 _ip.run_cell("t = isinstance(f(), foo)")
237 nt.assert_true(_ip.user_ns['t'])
236 assert _ip.user_ns["t"] is True
238
237
239 def test_obj_del(self):
238 def test_obj_del(self):
240 """Test that object's __del__ methods are called on exit."""
239 """Test that object's __del__ methods are called on exit."""
241 if sys.platform == 'win32':
240 if sys.platform == 'win32':
242 try:
241 try:
243 import win32api
242 import win32api
244 except ImportError as e:
243 except ImportError as e:
245 raise SkipTest("Test requires pywin32") from e
244 raise unittest.SkipTest("Test requires pywin32") from e
246 src = ("class A(object):\n"
245 src = ("class A(object):\n"
247 " def __del__(self):\n"
246 " def __del__(self):\n"
248 " print('object A deleted')\n"
247 " print('object A deleted')\n"
249 "a = A()\n")
248 "a = A()\n")
250 self.mktmp(src)
249 self.mktmp(src)
251 err = None
250 err = None
252 tt.ipexec_validate(self.fname, 'object A deleted', err)
251 tt.ipexec_validate(self.fname, 'object A deleted', err)
253
252
254 def test_aggressive_namespace_cleanup(self):
253 def test_aggressive_namespace_cleanup(self):
255 """Test that namespace cleanup is not too aggressive GH-238
254 """Test that namespace cleanup is not too aggressive GH-238
256
255
257 Returning from another run magic deletes the namespace"""
256 Returning from another run magic deletes the namespace"""
258 # see ticket https://github.com/ipython/ipython/issues/238
257 # see ticket https://github.com/ipython/ipython/issues/238
259
258
260 with tt.TempFileMixin() as empty:
259 with tt.TempFileMixin() as empty:
261 empty.mktmp('')
260 empty.mktmp("")
262 # On Windows, the filename will have \users in it, so we need to use the
261 # On Windows, the filename will have \users in it, so we need to use the
263 # repr so that the \u becomes \\u.
262 # repr so that the \u becomes \\u.
264 src = ("ip = get_ipython()\n"
263 src = (
265 "for i in range(5):\n"
264 "ip = get_ipython()\n"
266 " try:\n"
265 "for i in range(5):\n"
267 " ip.magic(%r)\n"
266 " try:\n"
268 " except NameError as e:\n"
267 " ip.magic(%r)\n"
269 " print(i)\n"
268 " except NameError as e:\n"
270 " break\n" % ('run ' + empty.fname))
269 " print(i)\n"
270 " break\n" % ("run " + empty.fname)
271 )
271 self.mktmp(src)
272 self.mktmp(src)
272 _ip.magic('run %s' % self.fname)
273 _ip.magic("run %s" % self.fname)
273 _ip.run_cell('ip == get_ipython()')
274 _ip.run_cell("ip == get_ipython()")
274 nt.assert_equal(_ip.user_ns['i'], 4)
275 assert _ip.user_ns["i"] == 4
275
276
276 def test_run_second(self):
277 def test_run_second(self):
277 """Test that running a second file doesn't clobber the first, gh-3547
278 """Test that running a second file doesn't clobber the first, gh-3547"""
278 """
279 self.mktmp("avar = 1\n" "def afunc():\n" " return avar\n")
279 self.mktmp("avar = 1\n"
280 "def afunc():\n"
281 " return avar\n")
282
280
283 with tt.TempFileMixin() as empty:
281 with tt.TempFileMixin() as empty:
284 empty.mktmp("")
282 empty.mktmp("")
285
283
286 _ip.magic('run %s' % self.fname)
284 _ip.magic("run %s" % self.fname)
287 _ip.magic('run %s' % empty.fname)
285 _ip.magic("run %s" % empty.fname)
288 nt.assert_equal(_ip.user_ns['afunc'](), 1)
286 assert _ip.user_ns["afunc"]() == 1
289
287
290 @dec.skip_win32
288 @dec.skip_win32
291 def test_tclass(self):
289 def test_tclass(self):
292 mydir = os.path.dirname(__file__)
290 mydir = os.path.dirname(__file__)
293 tc = os.path.join(mydir, 'tclass')
291 tc = os.path.join(mydir, 'tclass')
294 src = ("%%run '%s' C-first\n"
292 src = ("%%run '%s' C-first\n"
295 "%%run '%s' C-second\n"
293 "%%run '%s' C-second\n"
296 "%%run '%s' C-third\n") % (tc, tc, tc)
294 "%%run '%s' C-third\n") % (tc, tc, tc)
297 self.mktmp(src, '.ipy')
295 self.mktmp(src, '.ipy')
298 out = """\
296 out = """\
299 ARGV 1-: ['C-first']
297 ARGV 1-: ['C-first']
300 ARGV 1-: ['C-second']
298 ARGV 1-: ['C-second']
301 tclass.py: deleting object: C-first
299 tclass.py: deleting object: C-first
302 ARGV 1-: ['C-third']
300 ARGV 1-: ['C-third']
303 tclass.py: deleting object: C-second
301 tclass.py: deleting object: C-second
304 tclass.py: deleting object: C-third
302 tclass.py: deleting object: C-third
305 """
303 """
306 err = None
304 err = None
307 tt.ipexec_validate(self.fname, out, err)
305 tt.ipexec_validate(self.fname, out, err)
308
306
309 def test_run_i_after_reset(self):
307 def test_run_i_after_reset(self):
310 """Check that %run -i still works after %reset (gh-693)"""
308 """Check that %run -i still works after %reset (gh-693)"""
311 src = "yy = zz\n"
309 src = "yy = zz\n"
312 self.mktmp(src)
310 self.mktmp(src)
313 _ip.run_cell("zz = 23")
311 _ip.run_cell("zz = 23")
314 try:
312 try:
315 _ip.magic('run -i %s' % self.fname)
313 _ip.magic("run -i %s" % self.fname)
316 nt.assert_equal(_ip.user_ns['yy'], 23)
314 assert _ip.user_ns["yy"] == 23
317 finally:
315 finally:
318 _ip.magic('reset -f')
316 _ip.magic('reset -f')
319
317
320 _ip.run_cell("zz = 23")
318 _ip.run_cell("zz = 23")
321 try:
319 try:
322 _ip.magic('run -i %s' % self.fname)
320 _ip.magic("run -i %s" % self.fname)
323 nt.assert_equal(_ip.user_ns['yy'], 23)
321 assert _ip.user_ns["yy"] == 23
324 finally:
322 finally:
325 _ip.magic('reset -f')
323 _ip.magic('reset -f')
326
324
327 def test_unicode(self):
325 def test_unicode(self):
328 """Check that files in odd encodings are accepted."""
326 """Check that files in odd encodings are accepted."""
329 mydir = os.path.dirname(__file__)
327 mydir = os.path.dirname(__file__)
330 na = os.path.join(mydir, 'nonascii.py')
328 na = os.path.join(mydir, 'nonascii.py')
331 _ip.magic('run "%s"' % na)
329 _ip.magic('run "%s"' % na)
332 nt.assert_equal(_ip.user_ns['u'], u'Ўт№Ф')
330 assert _ip.user_ns["u"] == "Ўт№Ф"
333
331
334 def test_run_py_file_attribute(self):
332 def test_run_py_file_attribute(self):
335 """Test handling of `__file__` attribute in `%run <file>.py`."""
333 """Test handling of `__file__` attribute in `%run <file>.py`."""
336 src = "t = __file__\n"
334 src = "t = __file__\n"
337 self.mktmp(src)
335 self.mktmp(src)
338 _missing = object()
336 _missing = object()
339 file1 = _ip.user_ns.get('__file__', _missing)
337 file1 = _ip.user_ns.get('__file__', _missing)
340 _ip.magic('run %s' % self.fname)
338 _ip.magic('run %s' % self.fname)
341 file2 = _ip.user_ns.get('__file__', _missing)
339 file2 = _ip.user_ns.get('__file__', _missing)
342
340
343 # Check that __file__ was equal to the filename in the script's
341 # Check that __file__ was equal to the filename in the script's
344 # namespace.
342 # namespace.
345 nt.assert_equal(_ip.user_ns['t'], self.fname)
343 assert _ip.user_ns["t"] == self.fname
346
344
347 # Check that __file__ was not leaked back into user_ns.
345 # Check that __file__ was not leaked back into user_ns.
348 nt.assert_equal(file1, file2)
346 assert file1 == file2
349
347
350 def test_run_ipy_file_attribute(self):
348 def test_run_ipy_file_attribute(self):
351 """Test handling of `__file__` attribute in `%run <file.ipy>`."""
349 """Test handling of `__file__` attribute in `%run <file.ipy>`."""
352 src = "t = __file__\n"
350 src = "t = __file__\n"
353 self.mktmp(src, ext='.ipy')
351 self.mktmp(src, ext='.ipy')
354 _missing = object()
352 _missing = object()
355 file1 = _ip.user_ns.get('__file__', _missing)
353 file1 = _ip.user_ns.get('__file__', _missing)
356 _ip.magic('run %s' % self.fname)
354 _ip.magic('run %s' % self.fname)
357 file2 = _ip.user_ns.get('__file__', _missing)
355 file2 = _ip.user_ns.get('__file__', _missing)
358
356
359 # Check that __file__ was equal to the filename in the script's
357 # Check that __file__ was equal to the filename in the script's
360 # namespace.
358 # namespace.
361 nt.assert_equal(_ip.user_ns['t'], self.fname)
359 assert _ip.user_ns["t"] == self.fname
362
360
363 # Check that __file__ was not leaked back into user_ns.
361 # Check that __file__ was not leaked back into user_ns.
364 nt.assert_equal(file1, file2)
362 assert file1 == file2
365
363
366 def test_run_formatting(self):
364 def test_run_formatting(self):
367 """ Test that %run -t -N<N> does not raise a TypeError for N > 1."""
365 """ Test that %run -t -N<N> does not raise a TypeError for N > 1."""
368 src = "pass"
366 src = "pass"
369 self.mktmp(src)
367 self.mktmp(src)
370 _ip.magic('run -t -N 1 %s' % self.fname)
368 _ip.magic('run -t -N 1 %s' % self.fname)
371 _ip.magic('run -t -N 10 %s' % self.fname)
369 _ip.magic('run -t -N 10 %s' % self.fname)
372
370
373 def test_ignore_sys_exit(self):
371 def test_ignore_sys_exit(self):
374 """Test the -e option to ignore sys.exit()"""
372 """Test the -e option to ignore sys.exit()"""
375 src = "import sys; sys.exit(1)"
373 src = "import sys; sys.exit(1)"
376 self.mktmp(src)
374 self.mktmp(src)
377 with tt.AssertPrints('SystemExit'):
375 with tt.AssertPrints('SystemExit'):
378 _ip.magic('run %s' % self.fname)
376 _ip.magic('run %s' % self.fname)
379
377
380 with tt.AssertNotPrints('SystemExit'):
378 with tt.AssertNotPrints('SystemExit'):
381 _ip.magic('run -e %s' % self.fname)
379 _ip.magic('run -e %s' % self.fname)
382
380
383 def test_run_nb(self):
381 def test_run_nb(self):
384 """Test %run notebook.ipynb"""
382 """Test %run notebook.ipynb"""
385 from nbformat import v4, writes
383 from nbformat import v4, writes
386 nb = v4.new_notebook(
384 nb = v4.new_notebook(
387 cells=[
385 cells=[
388 v4.new_markdown_cell("The Ultimate Question of Everything"),
386 v4.new_markdown_cell("The Ultimate Question of Everything"),
389 v4.new_code_cell("answer=42")
387 v4.new_code_cell("answer=42")
390 ]
388 ]
391 )
389 )
392 src = writes(nb, version=4)
390 src = writes(nb, version=4)
393 self.mktmp(src, ext='.ipynb')
391 self.mktmp(src, ext='.ipynb')
394
392
395 _ip.magic("run %s" % self.fname)
393 _ip.magic("run %s" % self.fname)
396
394
397 nt.assert_equal(_ip.user_ns['answer'], 42)
395 assert _ip.user_ns["answer"] == 42
398
396
399 def test_run_nb_error(self):
397 def test_run_nb_error(self):
400 """Test %run notebook.ipynb error"""
398 """Test %run notebook.ipynb error"""
401 from nbformat import v4, writes
399 from nbformat import v4, writes
402 # %run when a file name isn't provided
400 # %run when a file name isn't provided
403 nt.assert_raises(Exception, _ip.magic, "run")
401 pytest.raises(Exception, _ip.magic, "run")
404
402
405 # %run when a file doesn't exist
403 # %run when a file doesn't exist
406 nt.assert_raises(Exception, _ip.magic, "run foobar.ipynb")
404 pytest.raises(Exception, _ip.magic, "run foobar.ipynb")
407
405
408 # %run on a notebook with an error
406 # %run on a notebook with an error
409 nb = v4.new_notebook(
407 nb = v4.new_notebook(
410 cells=[
408 cells=[
411 v4.new_code_cell("0/0")
409 v4.new_code_cell("0/0")
412 ]
410 ]
413 )
411 )
414 src = writes(nb, version=4)
412 src = writes(nb, version=4)
415 self.mktmp(src, ext='.ipynb')
413 self.mktmp(src, ext='.ipynb')
416 nt.assert_raises(Exception, _ip.magic, "run %s" % self.fname)
414 pytest.raises(Exception, _ip.magic, "run %s" % self.fname)
417
415
418 def test_file_options(self):
416 def test_file_options(self):
419 src = ('import sys\n'
417 src = ('import sys\n'
420 'a = " ".join(sys.argv[1:])\n')
418 'a = " ".join(sys.argv[1:])\n')
421 self.mktmp(src)
419 self.mktmp(src)
422 test_opts = '-x 3 --verbose'
420 test_opts = "-x 3 --verbose"
423 _ip.run_line_magic("run", '{0} {1}'.format(self.fname, test_opts))
421 _ip.run_line_magic("run", "{0} {1}".format(self.fname, test_opts))
424 nt.assert_equal(_ip.user_ns['a'], test_opts)
422 assert _ip.user_ns["a"] == test_opts
425
423
426
424
427 class TestMagicRunWithPackage(unittest.TestCase):
425 class TestMagicRunWithPackage(unittest.TestCase):
428
426
429 def writefile(self, name, content):
427 def writefile(self, name, content):
430 path = os.path.join(self.tempdir.name, name)
428 path = os.path.join(self.tempdir.name, name)
431 d = os.path.dirname(path)
429 d = os.path.dirname(path)
432 if not os.path.isdir(d):
430 if not os.path.isdir(d):
433 os.makedirs(d)
431 os.makedirs(d)
434 with open(path, 'w') as f:
432 with open(path, 'w') as f:
435 f.write(textwrap.dedent(content))
433 f.write(textwrap.dedent(content))
436
434
437 def setUp(self):
435 def setUp(self):
438 self.package = package = 'tmp{0}'.format(''.join([random.choice(string.ascii_letters) for i in range(10)]))
436 self.package = package = 'tmp{0}'.format(''.join([random.choice(string.ascii_letters) for i in range(10)]))
439 """Temporary (probably) valid python package name."""
437 """Temporary (probably) valid python package name."""
440
438
441 self.value = int(random.random() * 10000)
439 self.value = int(random.random() * 10000)
442
440
443 self.tempdir = TemporaryDirectory()
441 self.tempdir = TemporaryDirectory()
444 self.__orig_cwd = os.getcwd()
442 self.__orig_cwd = os.getcwd()
445 sys.path.insert(0, self.tempdir.name)
443 sys.path.insert(0, self.tempdir.name)
446
444
447 self.writefile(os.path.join(package, '__init__.py'), '')
445 self.writefile(os.path.join(package, '__init__.py'), '')
448 self.writefile(os.path.join(package, 'sub.py'), """
446 self.writefile(os.path.join(package, 'sub.py'), """
449 x = {0!r}
447 x = {0!r}
450 """.format(self.value))
448 """.format(self.value))
451 self.writefile(os.path.join(package, 'relative.py'), """
449 self.writefile(os.path.join(package, 'relative.py'), """
452 from .sub import x
450 from .sub import x
453 """)
451 """)
454 self.writefile(os.path.join(package, 'absolute.py'), """
452 self.writefile(os.path.join(package, 'absolute.py'), """
455 from {0}.sub import x
453 from {0}.sub import x
456 """.format(package))
454 """.format(package))
457 self.writefile(os.path.join(package, 'args.py'), """
455 self.writefile(os.path.join(package, 'args.py'), """
458 import sys
456 import sys
459 a = " ".join(sys.argv[1:])
457 a = " ".join(sys.argv[1:])
460 """.format(package))
458 """.format(package))
461
459
462 def tearDown(self):
460 def tearDown(self):
463 os.chdir(self.__orig_cwd)
461 os.chdir(self.__orig_cwd)
464 sys.path[:] = [p for p in sys.path if p != self.tempdir.name]
462 sys.path[:] = [p for p in sys.path if p != self.tempdir.name]
465 self.tempdir.cleanup()
463 self.tempdir.cleanup()
466
464
467 def check_run_submodule(self, submodule, opts=''):
465 def check_run_submodule(self, submodule, opts=''):
468 _ip.user_ns.pop('x', None)
466 _ip.user_ns.pop('x', None)
469 _ip.magic('run {2} -m {0}.{1}'.format(self.package, submodule, opts))
467 _ip.magic('run {2} -m {0}.{1}'.format(self.package, submodule, opts))
470 self.assertEqual(_ip.user_ns['x'], self.value,
468 self.assertEqual(_ip.user_ns['x'], self.value,
471 'Variable `x` is not loaded from module `{0}`.'
469 'Variable `x` is not loaded from module `{0}`.'
472 .format(submodule))
470 .format(submodule))
473
471
474 def test_run_submodule_with_absolute_import(self):
472 def test_run_submodule_with_absolute_import(self):
475 self.check_run_submodule('absolute')
473 self.check_run_submodule('absolute')
476
474
477 def test_run_submodule_with_relative_import(self):
475 def test_run_submodule_with_relative_import(self):
478 """Run submodule that has a relative import statement (#2727)."""
476 """Run submodule that has a relative import statement (#2727)."""
479 self.check_run_submodule('relative')
477 self.check_run_submodule('relative')
480
478
481 def test_prun_submodule_with_absolute_import(self):
479 def test_prun_submodule_with_absolute_import(self):
482 self.check_run_submodule('absolute', '-p')
480 self.check_run_submodule('absolute', '-p')
483
481
484 def test_prun_submodule_with_relative_import(self):
482 def test_prun_submodule_with_relative_import(self):
485 self.check_run_submodule('relative', '-p')
483 self.check_run_submodule('relative', '-p')
486
484
487 def with_fake_debugger(func):
485 def with_fake_debugger(func):
488 @functools.wraps(func)
486 @functools.wraps(func)
489 def wrapper(*args, **kwds):
487 def wrapper(*args, **kwds):
490 with patch.object(debugger.Pdb, 'run', staticmethod(eval)):
488 with patch.object(debugger.Pdb, 'run', staticmethod(eval)):
491 return func(*args, **kwds)
489 return func(*args, **kwds)
492 return wrapper
490 return wrapper
493
491
494 @with_fake_debugger
492 @with_fake_debugger
495 def test_debug_run_submodule_with_absolute_import(self):
493 def test_debug_run_submodule_with_absolute_import(self):
496 self.check_run_submodule('absolute', '-d')
494 self.check_run_submodule('absolute', '-d')
497
495
498 @with_fake_debugger
496 @with_fake_debugger
499 def test_debug_run_submodule_with_relative_import(self):
497 def test_debug_run_submodule_with_relative_import(self):
500 self.check_run_submodule('relative', '-d')
498 self.check_run_submodule('relative', '-d')
501
499
502 def test_module_options(self):
500 def test_module_options(self):
503 _ip.user_ns.pop('a', None)
501 _ip.user_ns.pop("a", None)
504 test_opts = '-x abc -m test'
502 test_opts = "-x abc -m test"
505 _ip.run_line_magic('run', '-m {0}.args {1}'.format(self.package, test_opts))
503 _ip.run_line_magic("run", "-m {0}.args {1}".format(self.package, test_opts))
506 nt.assert_equal(_ip.user_ns['a'], test_opts)
504 assert _ip.user_ns["a"] == test_opts
507
505
508 def test_module_options_with_separator(self):
506 def test_module_options_with_separator(self):
509 _ip.user_ns.pop('a', None)
507 _ip.user_ns.pop("a", None)
510 test_opts = '-x abc -m test'
508 test_opts = "-x abc -m test"
511 _ip.run_line_magic('run', '-m {0}.args -- {1}'.format(self.package, test_opts))
509 _ip.run_line_magic("run", "-m {0}.args -- {1}".format(self.package, test_opts))
512 nt.assert_equal(_ip.user_ns['a'], test_opts)
510 assert _ip.user_ns["a"] == test_opts
511
513
512
514 def test_run__name__():
513 def test_run__name__():
515 with TemporaryDirectory() as td:
514 with TemporaryDirectory() as td:
516 path = pjoin(td, 'foo.py')
515 path = pjoin(td, 'foo.py')
517 with open(path, 'w') as f:
516 with open(path, 'w') as f:
518 f.write("q = __name__")
517 f.write("q = __name__")
519
518
520 _ip.user_ns.pop('q', None)
519 _ip.user_ns.pop("q", None)
521 _ip.magic('run {}'.format(path))
520 _ip.magic("run {}".format(path))
522 nt.assert_equal(_ip.user_ns.pop('q'), '__main__')
521 assert _ip.user_ns.pop("q") == "__main__"
523
522
524 _ip.magic('run -n {}'.format(path))
523 _ip.magic("run -n {}".format(path))
525 nt.assert_equal(_ip.user_ns.pop('q'), 'foo')
524 assert _ip.user_ns.pop("q") == "foo"
526
525
527 try:
526 try:
528 _ip.magic('run -i -n {}'.format(path))
527 _ip.magic("run -i -n {}".format(path))
529 nt.assert_equal(_ip.user_ns.pop('q'), 'foo')
528 assert _ip.user_ns.pop("q") == "foo"
530 finally:
529 finally:
531 _ip.magic('reset -f')
530 _ip.magic('reset -f')
532
531
533
532
534 def test_run_tb():
533 def test_run_tb():
535 """Test traceback offset in %run"""
534 """Test traceback offset in %run"""
536 with TemporaryDirectory() as td:
535 with TemporaryDirectory() as td:
537 path = pjoin(td, 'foo.py')
536 path = pjoin(td, 'foo.py')
538 with open(path, 'w') as f:
537 with open(path, 'w') as f:
539 f.write('\n'.join([
538 f.write('\n'.join([
540 "def foo():",
539 "def foo():",
541 " return bar()",
540 " return bar()",
542 "def bar():",
541 "def bar():",
543 " raise RuntimeError('hello!')",
542 " raise RuntimeError('hello!')",
544 "foo()",
543 "foo()",
545 ]))
544 ]))
546 with capture_output() as io:
545 with capture_output() as io:
547 _ip.magic('run {}'.format(path))
546 _ip.magic('run {}'.format(path))
548 out = io.stdout
547 out = io.stdout
549 nt.assert_not_in("execfile", out)
548 assert "execfile" not in out
550 nt.assert_in("RuntimeError", out)
549 assert "RuntimeError" in out
551 nt.assert_equal(out.count("---->"), 3)
550 assert out.count("---->") == 3
552 del ip.user_ns['bar']
551 del ip.user_ns['bar']
553 del ip.user_ns['foo']
552 del ip.user_ns['foo']
554
553
555
554
556 def test_multiprocessing_run():
555 def test_multiprocessing_run():
557 """Set we can run mutiprocesgin without messing up up main namespace
556 """Set we can run mutiprocesgin without messing up up main namespace
558
557
559 Note that import `nose.tools as nt` mdify the value s
558 Note that import `nose.tools as nt` mdify the value s
560 sys.module['__mp_main__'] so we need to temporarily set it to None to test
559 sys.module['__mp_main__'] so we need to temporarily set it to None to test
561 the issue.
560 the issue.
562 """
561 """
563 with TemporaryDirectory() as td:
562 with TemporaryDirectory() as td:
564 mpm = sys.modules.get('__mp_main__')
563 mpm = sys.modules.get('__mp_main__')
565 assert mpm is not None
564 assert mpm is not None
566 sys.modules['__mp_main__'] = None
565 sys.modules['__mp_main__'] = None
567 try:
566 try:
568 path = pjoin(td, 'test.py')
567 path = pjoin(td, 'test.py')
569 with open(path, 'w') as f:
568 with open(path, 'w') as f:
570 f.write("import multiprocessing\nprint('hoy')")
569 f.write("import multiprocessing\nprint('hoy')")
571 with capture_output() as io:
570 with capture_output() as io:
572 _ip.run_line_magic('run', path)
571 _ip.run_line_magic('run', path)
573 _ip.run_cell("i_m_undefined")
572 _ip.run_cell("i_m_undefined")
574 out = io.stdout
573 out = io.stdout
575 nt.assert_in("hoy", out)
574 assert "hoy" in out
576 nt.assert_not_in("AttributeError", out)
575 assert "AttributeError" not in out
577 nt.assert_in("NameError", out)
576 assert "NameError" in out
578 nt.assert_equal(out.count("---->"), 1)
577 assert out.count("---->") == 1
579 except:
578 except:
580 raise
579 raise
581 finally:
580 finally:
582 sys.modules['__mp_main__'] = mpm
581 sys.modules['__mp_main__'] = mpm
583
582
584 @dec.knownfailureif(sys.platform == 'win32', "writes to io.stdout aren't captured on Windows")
583 @dec.knownfailureif(sys.platform == 'win32', "writes to io.stdout aren't captured on Windows")
585 def test_script_tb():
584 def test_script_tb():
586 """Test traceback offset in `ipython script.py`"""
585 """Test traceback offset in `ipython script.py`"""
587 with TemporaryDirectory() as td:
586 with TemporaryDirectory() as td:
588 path = pjoin(td, 'foo.py')
587 path = pjoin(td, 'foo.py')
589 with open(path, 'w') as f:
588 with open(path, 'w') as f:
590 f.write('\n'.join([
589 f.write('\n'.join([
591 "def foo():",
590 "def foo():",
592 " return bar()",
591 " return bar()",
593 "def bar():",
592 "def bar():",
594 " raise RuntimeError('hello!')",
593 " raise RuntimeError('hello!')",
595 "foo()",
594 "foo()",
596 ]))
595 ]))
597 out, err = tt.ipexec(path)
596 out, err = tt.ipexec(path)
598 nt.assert_not_in("execfile", out)
597 assert "execfile" not in out
599 nt.assert_in("RuntimeError", out)
598 assert "RuntimeError" in out
600 nt.assert_equal(out.count("---->"), 3)
599 assert out.count("---->") == 3
601
@@ -1,38 +1,38 b''
1 # coding: utf-8
1 # coding: utf-8
2 import nose.tools as nt
3
2
4 from IPython.core.splitinput import split_user_input, LineInfo
3 from IPython.core.splitinput import split_user_input, LineInfo
5 from IPython.testing import tools as tt
4 from IPython.testing import tools as tt
6
5
7 tests = [
6 tests = [
8 ('x=1', ('', '', 'x', '=1')),
7 ("x=1", ("", "", "x", "=1")),
9 ('?', ('', '?', '', '')),
8 ("?", ("", "?", "", "")),
10 ('??', ('', '??', '', '')),
9 ("??", ("", "??", "", "")),
11 (' ?', (' ', '?', '', '')),
10 (" ?", (" ", "?", "", "")),
12 (' ??', (' ', '??', '', '')),
11 (" ??", (" ", "??", "", "")),
13 ('??x', ('', '??', 'x', '')),
12 ("??x", ("", "??", "x", "")),
14 ('?x=1', ('', '?', 'x', '=1')),
13 ("?x=1", ("", "?", "x", "=1")),
15 ('!ls', ('', '!', 'ls', '')),
14 ("!ls", ("", "!", "ls", "")),
16 (' !ls', (' ', '!', 'ls', '')),
15 (" !ls", (" ", "!", "ls", "")),
17 ('!!ls', ('', '!!', 'ls', '')),
16 ("!!ls", ("", "!!", "ls", "")),
18 (' !!ls', (' ', '!!', 'ls', '')),
17 (" !!ls", (" ", "!!", "ls", "")),
19 (',ls', ('', ',', 'ls', '')),
18 (",ls", ("", ",", "ls", "")),
20 (';ls', ('', ';', 'ls', '')),
19 (";ls", ("", ";", "ls", "")),
21 (' ;ls', (' ', ';', 'ls', '')),
20 (" ;ls", (" ", ";", "ls", "")),
22 ('f.g(x)', ('', '', 'f.g', '(x)')),
21 ("f.g(x)", ("", "", "f.g", "(x)")),
23 ('f.g (x)', ('', '', 'f.g', '(x)')),
22 ("f.g (x)", ("", "", "f.g", "(x)")),
24 ('?%hist1', ('', '?', '%hist1', '')),
23 ("?%hist1", ("", "?", "%hist1", "")),
25 ('?%%hist2', ('', '?', '%%hist2', '')),
24 ("?%%hist2", ("", "?", "%%hist2", "")),
26 ('??%hist3', ('', '??', '%hist3', '')),
25 ("??%hist3", ("", "??", "%hist3", "")),
27 ('??%%hist4', ('', '??', '%%hist4', '')),
26 ("??%%hist4", ("", "??", "%%hist4", "")),
28 ('?x*', ('', '?', 'x*', '')),
27 ("?x*", ("", "?", "x*", "")),
29 ]
28 ]
30 tests.append((u"Pérez Fernando", (u'', u'', u'Pérez', u'Fernando')))
29 tests.append(("Pérez Fernando", ("", "", "Pérez", "Fernando")))
30
31
31
32 def test_split_user_input():
32 def test_split_user_input():
33 return tt.check_pairs(split_user_input, tests)
33 return tt.check_pairs(split_user_input, tests)
34
34
35 def test_LineInfo():
35 def test_LineInfo():
36 """Simple test for LineInfo construction and str()"""
36 """Simple test for LineInfo construction and str()"""
37 linfo = LineInfo(' %cd /home')
37 linfo = LineInfo(" %cd /home")
38 nt.assert_equal(str(linfo), 'LineInfo [ |%|cd|/home]')
38 assert str(linfo) == "LineInfo [ |%|cd|/home]"
@@ -1,555 +1,554 b''
1 """Tests for autoreload extension.
1 """Tests for autoreload extension.
2 """
2 """
3 # -----------------------------------------------------------------------------
3 # -----------------------------------------------------------------------------
4 # Copyright (c) 2012 IPython Development Team.
4 # Copyright (c) 2012 IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 # -----------------------------------------------------------------------------
9 # -----------------------------------------------------------------------------
10
10
11 # -----------------------------------------------------------------------------
11 # -----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 # -----------------------------------------------------------------------------
13 # -----------------------------------------------------------------------------
14
14
15 import os
15 import os
16 import sys
16 import sys
17 import tempfile
17 import tempfile
18 import textwrap
18 import textwrap
19 import shutil
19 import shutil
20 import random
20 import random
21 import time
21 import time
22 from io import StringIO
22 from io import StringIO
23
23
24 import nose.tools as nt
25 import IPython.testing.tools as tt
24 import IPython.testing.tools as tt
26
25
27 from unittest import TestCase
26 from unittest import TestCase
28
27
29 from IPython.extensions.autoreload import AutoreloadMagics
28 from IPython.extensions.autoreload import AutoreloadMagics
30 from IPython.core.events import EventManager, pre_run_cell
29 from IPython.core.events import EventManager, pre_run_cell
31
30
32 # -----------------------------------------------------------------------------
31 # -----------------------------------------------------------------------------
33 # Test fixture
32 # Test fixture
34 # -----------------------------------------------------------------------------
33 # -----------------------------------------------------------------------------
35
34
36 noop = lambda *a, **kw: None
35 noop = lambda *a, **kw: None
37
36
38
37
39 class FakeShell:
38 class FakeShell:
40 def __init__(self):
39 def __init__(self):
41 self.ns = {}
40 self.ns = {}
42 self.user_ns = self.ns
41 self.user_ns = self.ns
43 self.user_ns_hidden = {}
42 self.user_ns_hidden = {}
44 self.events = EventManager(self, {"pre_run_cell", pre_run_cell})
43 self.events = EventManager(self, {"pre_run_cell", pre_run_cell})
45 self.auto_magics = AutoreloadMagics(shell=self)
44 self.auto_magics = AutoreloadMagics(shell=self)
46 self.events.register("pre_run_cell", self.auto_magics.pre_run_cell)
45 self.events.register("pre_run_cell", self.auto_magics.pre_run_cell)
47
46
48 register_magics = set_hook = noop
47 register_magics = set_hook = noop
49
48
50 def run_code(self, code):
49 def run_code(self, code):
51 self.events.trigger("pre_run_cell")
50 self.events.trigger("pre_run_cell")
52 exec(code, self.user_ns)
51 exec(code, self.user_ns)
53 self.auto_magics.post_execute_hook()
52 self.auto_magics.post_execute_hook()
54
53
55 def push(self, items):
54 def push(self, items):
56 self.ns.update(items)
55 self.ns.update(items)
57
56
58 def magic_autoreload(self, parameter):
57 def magic_autoreload(self, parameter):
59 self.auto_magics.autoreload(parameter)
58 self.auto_magics.autoreload(parameter)
60
59
61 def magic_aimport(self, parameter, stream=None):
60 def magic_aimport(self, parameter, stream=None):
62 self.auto_magics.aimport(parameter, stream=stream)
61 self.auto_magics.aimport(parameter, stream=stream)
63 self.auto_magics.post_execute_hook()
62 self.auto_magics.post_execute_hook()
64
63
65
64
66 class Fixture(TestCase):
65 class Fixture(TestCase):
67 """Fixture for creating test module files"""
66 """Fixture for creating test module files"""
68
67
69 test_dir = None
68 test_dir = None
70 old_sys_path = None
69 old_sys_path = None
71 filename_chars = "abcdefghijklmopqrstuvwxyz0123456789"
70 filename_chars = "abcdefghijklmopqrstuvwxyz0123456789"
72
71
73 def setUp(self):
72 def setUp(self):
74 self.test_dir = tempfile.mkdtemp()
73 self.test_dir = tempfile.mkdtemp()
75 self.old_sys_path = list(sys.path)
74 self.old_sys_path = list(sys.path)
76 sys.path.insert(0, self.test_dir)
75 sys.path.insert(0, self.test_dir)
77 self.shell = FakeShell()
76 self.shell = FakeShell()
78
77
79 def tearDown(self):
78 def tearDown(self):
80 shutil.rmtree(self.test_dir)
79 shutil.rmtree(self.test_dir)
81 sys.path = self.old_sys_path
80 sys.path = self.old_sys_path
82
81
83 self.test_dir = None
82 self.test_dir = None
84 self.old_sys_path = None
83 self.old_sys_path = None
85 self.shell = None
84 self.shell = None
86
85
87 def get_module(self):
86 def get_module(self):
88 module_name = "tmpmod_" + "".join(random.sample(self.filename_chars, 20))
87 module_name = "tmpmod_" + "".join(random.sample(self.filename_chars, 20))
89 if module_name in sys.modules:
88 if module_name in sys.modules:
90 del sys.modules[module_name]
89 del sys.modules[module_name]
91 file_name = os.path.join(self.test_dir, module_name + ".py")
90 file_name = os.path.join(self.test_dir, module_name + ".py")
92 return module_name, file_name
91 return module_name, file_name
93
92
94 def write_file(self, filename, content):
93 def write_file(self, filename, content):
95 """
94 """
96 Write a file, and force a timestamp difference of at least one second
95 Write a file, and force a timestamp difference of at least one second
97
96
98 Notes
97 Notes
99 -----
98 -----
100 Python's .pyc files record the timestamp of their compilation
99 Python's .pyc files record the timestamp of their compilation
101 with a time resolution of one second.
100 with a time resolution of one second.
102
101
103 Therefore, we need to force a timestamp difference between .py
102 Therefore, we need to force a timestamp difference between .py
104 and .pyc, without having the .py file be timestamped in the
103 and .pyc, without having the .py file be timestamped in the
105 future, and without changing the timestamp of the .pyc file
104 future, and without changing the timestamp of the .pyc file
106 (because that is stored in the file). The only reliable way
105 (because that is stored in the file). The only reliable way
107 to achieve this seems to be to sleep.
106 to achieve this seems to be to sleep.
108 """
107 """
109 content = textwrap.dedent(content)
108 content = textwrap.dedent(content)
110 # Sleep one second + eps
109 # Sleep one second + eps
111 time.sleep(1.05)
110 time.sleep(1.05)
112
111
113 # Write
112 # Write
114 with open(filename, "w") as f:
113 with open(filename, "w") as f:
115 f.write(content)
114 f.write(content)
116
115
117 def new_module(self, code):
116 def new_module(self, code):
118 code = textwrap.dedent(code)
117 code = textwrap.dedent(code)
119 mod_name, mod_fn = self.get_module()
118 mod_name, mod_fn = self.get_module()
120 with open(mod_fn, "w") as f:
119 with open(mod_fn, "w") as f:
121 f.write(code)
120 f.write(code)
122 return mod_name, mod_fn
121 return mod_name, mod_fn
123
122
124
123
125 # -----------------------------------------------------------------------------
124 # -----------------------------------------------------------------------------
126 # Test automatic reloading
125 # Test automatic reloading
127 # -----------------------------------------------------------------------------
126 # -----------------------------------------------------------------------------
128
127
129
128
130 def pickle_get_current_class(obj):
129 def pickle_get_current_class(obj):
131 """
130 """
132 Original issue comes from pickle; hence the name.
131 Original issue comes from pickle; hence the name.
133 """
132 """
134 name = obj.__class__.__name__
133 name = obj.__class__.__name__
135 module_name = getattr(obj, "__module__", None)
134 module_name = getattr(obj, "__module__", None)
136 obj2 = sys.modules[module_name]
135 obj2 = sys.modules[module_name]
137 for subpath in name.split("."):
136 for subpath in name.split("."):
138 obj2 = getattr(obj2, subpath)
137 obj2 = getattr(obj2, subpath)
139 return obj2
138 return obj2
140
139
141
140
142 class TestAutoreload(Fixture):
141 class TestAutoreload(Fixture):
143 def test_reload_enums(self):
142 def test_reload_enums(self):
144 mod_name, mod_fn = self.new_module(
143 mod_name, mod_fn = self.new_module(
145 textwrap.dedent(
144 textwrap.dedent(
146 """
145 """
147 from enum import Enum
146 from enum import Enum
148 class MyEnum(Enum):
147 class MyEnum(Enum):
149 A = 'A'
148 A = 'A'
150 B = 'B'
149 B = 'B'
151 """
150 """
152 )
151 )
153 )
152 )
154 self.shell.magic_autoreload("2")
153 self.shell.magic_autoreload("2")
155 self.shell.magic_aimport(mod_name)
154 self.shell.magic_aimport(mod_name)
156 self.write_file(
155 self.write_file(
157 mod_fn,
156 mod_fn,
158 textwrap.dedent(
157 textwrap.dedent(
159 """
158 """
160 from enum import Enum
159 from enum import Enum
161 class MyEnum(Enum):
160 class MyEnum(Enum):
162 A = 'A'
161 A = 'A'
163 B = 'B'
162 B = 'B'
164 C = 'C'
163 C = 'C'
165 """
164 """
166 ),
165 ),
167 )
166 )
168 with tt.AssertNotPrints(
167 with tt.AssertNotPrints(
169 ("[autoreload of %s failed:" % mod_name), channel="stderr"
168 ("[autoreload of %s failed:" % mod_name), channel="stderr"
170 ):
169 ):
171 self.shell.run_code("pass") # trigger another reload
170 self.shell.run_code("pass") # trigger another reload
172
171
173 def test_reload_class_type(self):
172 def test_reload_class_type(self):
174 self.shell.magic_autoreload("2")
173 self.shell.magic_autoreload("2")
175 mod_name, mod_fn = self.new_module(
174 mod_name, mod_fn = self.new_module(
176 """
175 """
177 class Test():
176 class Test():
178 def meth(self):
177 def meth(self):
179 return "old"
178 return "old"
180 """
179 """
181 )
180 )
182 assert "test" not in self.shell.ns
181 assert "test" not in self.shell.ns
183 assert "result" not in self.shell.ns
182 assert "result" not in self.shell.ns
184
183
185 self.shell.run_code("from %s import Test" % mod_name)
184 self.shell.run_code("from %s import Test" % mod_name)
186 self.shell.run_code("test = Test()")
185 self.shell.run_code("test = Test()")
187
186
188 self.write_file(
187 self.write_file(
189 mod_fn,
188 mod_fn,
190 """
189 """
191 class Test():
190 class Test():
192 def meth(self):
191 def meth(self):
193 return "new"
192 return "new"
194 """,
193 """,
195 )
194 )
196
195
197 test_object = self.shell.ns["test"]
196 test_object = self.shell.ns["test"]
198
197
199 # important to trigger autoreload logic !
198 # important to trigger autoreload logic !
200 self.shell.run_code("pass")
199 self.shell.run_code("pass")
201
200
202 test_class = pickle_get_current_class(test_object)
201 test_class = pickle_get_current_class(test_object)
203 assert isinstance(test_object, test_class)
202 assert isinstance(test_object, test_class)
204
203
205 # extra check.
204 # extra check.
206 self.shell.run_code("import pickle")
205 self.shell.run_code("import pickle")
207 self.shell.run_code("p = pickle.dumps(test)")
206 self.shell.run_code("p = pickle.dumps(test)")
208
207
209 def test_reload_class_attributes(self):
208 def test_reload_class_attributes(self):
210 self.shell.magic_autoreload("2")
209 self.shell.magic_autoreload("2")
211 mod_name, mod_fn = self.new_module(
210 mod_name, mod_fn = self.new_module(
212 textwrap.dedent(
211 textwrap.dedent(
213 """
212 """
214 class MyClass:
213 class MyClass:
215
214
216 def __init__(self, a=10):
215 def __init__(self, a=10):
217 self.a = a
216 self.a = a
218 self.b = 22
217 self.b = 22
219 # self.toto = 33
218 # self.toto = 33
220
219
221 def square(self):
220 def square(self):
222 print('compute square')
221 print('compute square')
223 return self.a*self.a
222 return self.a*self.a
224 """
223 """
225 )
224 )
226 )
225 )
227 self.shell.run_code("from %s import MyClass" % mod_name)
226 self.shell.run_code("from %s import MyClass" % mod_name)
228 self.shell.run_code("first = MyClass(5)")
227 self.shell.run_code("first = MyClass(5)")
229 self.shell.run_code("first.square()")
228 self.shell.run_code("first.square()")
230 with nt.assert_raises(AttributeError):
229 with self.assertRaises(AttributeError):
231 self.shell.run_code("first.cube()")
230 self.shell.run_code("first.cube()")
232 with nt.assert_raises(AttributeError):
231 with self.assertRaises(AttributeError):
233 self.shell.run_code("first.power(5)")
232 self.shell.run_code("first.power(5)")
234 self.shell.run_code("first.b")
233 self.shell.run_code("first.b")
235 with nt.assert_raises(AttributeError):
234 with self.assertRaises(AttributeError):
236 self.shell.run_code("first.toto")
235 self.shell.run_code("first.toto")
237
236
238 # remove square, add power
237 # remove square, add power
239
238
240 self.write_file(
239 self.write_file(
241 mod_fn,
240 mod_fn,
242 textwrap.dedent(
241 textwrap.dedent(
243 """
242 """
244 class MyClass:
243 class MyClass:
245
244
246 def __init__(self, a=10):
245 def __init__(self, a=10):
247 self.a = a
246 self.a = a
248 self.b = 11
247 self.b = 11
249
248
250 def power(self, p):
249 def power(self, p):
251 print('compute power '+str(p))
250 print('compute power '+str(p))
252 return self.a**p
251 return self.a**p
253 """
252 """
254 ),
253 ),
255 )
254 )
256
255
257 self.shell.run_code("second = MyClass(5)")
256 self.shell.run_code("second = MyClass(5)")
258
257
259 for object_name in {"first", "second"}:
258 for object_name in {"first", "second"}:
260 self.shell.run_code(f"{object_name}.power(5)")
259 self.shell.run_code(f"{object_name}.power(5)")
261 with nt.assert_raises(AttributeError):
260 with self.assertRaises(AttributeError):
262 self.shell.run_code(f"{object_name}.cube()")
261 self.shell.run_code(f"{object_name}.cube()")
263 with nt.assert_raises(AttributeError):
262 with self.assertRaises(AttributeError):
264 self.shell.run_code(f"{object_name}.square()")
263 self.shell.run_code(f"{object_name}.square()")
265 self.shell.run_code(f"{object_name}.b")
264 self.shell.run_code(f"{object_name}.b")
266 self.shell.run_code(f"{object_name}.a")
265 self.shell.run_code(f"{object_name}.a")
267 with nt.assert_raises(AttributeError):
266 with self.assertRaises(AttributeError):
268 self.shell.run_code(f"{object_name}.toto")
267 self.shell.run_code(f"{object_name}.toto")
269
268
270 def test_autoload_newly_added_objects(self):
269 def test_autoload_newly_added_objects(self):
271 self.shell.magic_autoreload("3")
270 self.shell.magic_autoreload("3")
272 mod_code = """
271 mod_code = """
273 def func1(): pass
272 def func1(): pass
274 """
273 """
275 mod_name, mod_fn = self.new_module(textwrap.dedent(mod_code))
274 mod_name, mod_fn = self.new_module(textwrap.dedent(mod_code))
276 self.shell.run_code(f"from {mod_name} import *")
275 self.shell.run_code(f"from {mod_name} import *")
277 self.shell.run_code("func1()")
276 self.shell.run_code("func1()")
278 with nt.assert_raises(NameError):
277 with self.assertRaises(NameError):
279 self.shell.run_code("func2()")
278 self.shell.run_code("func2()")
280 with nt.assert_raises(NameError):
279 with self.assertRaises(NameError):
281 self.shell.run_code("t = Test()")
280 self.shell.run_code("t = Test()")
282 with nt.assert_raises(NameError):
281 with self.assertRaises(NameError):
283 self.shell.run_code("number")
282 self.shell.run_code("number")
284
283
285 # ----------- TEST NEW OBJ LOADED --------------------------
284 # ----------- TEST NEW OBJ LOADED --------------------------
286
285
287 new_code = """
286 new_code = """
288 def func1(): pass
287 def func1(): pass
289 def func2(): pass
288 def func2(): pass
290 class Test: pass
289 class Test: pass
291 number = 0
290 number = 0
292 from enum import Enum
291 from enum import Enum
293 class TestEnum(Enum):
292 class TestEnum(Enum):
294 A = 'a'
293 A = 'a'
295 """
294 """
296 self.write_file(mod_fn, textwrap.dedent(new_code))
295 self.write_file(mod_fn, textwrap.dedent(new_code))
297
296
298 # test function now exists in shell's namespace namespace
297 # test function now exists in shell's namespace namespace
299 self.shell.run_code("func2()")
298 self.shell.run_code("func2()")
300 # test function now exists in module's dict
299 # test function now exists in module's dict
301 self.shell.run_code(f"import sys; sys.modules['{mod_name}'].func2()")
300 self.shell.run_code(f"import sys; sys.modules['{mod_name}'].func2()")
302 # test class now exists
301 # test class now exists
303 self.shell.run_code("t = Test()")
302 self.shell.run_code("t = Test()")
304 # test global built-in var now exists
303 # test global built-in var now exists
305 self.shell.run_code("number")
304 self.shell.run_code("number")
306 # test the enumerations gets loaded successfully
305 # test the enumerations gets loaded successfully
307 self.shell.run_code("TestEnum.A")
306 self.shell.run_code("TestEnum.A")
308
307
309 # ----------- TEST NEW OBJ CAN BE CHANGED --------------------
308 # ----------- TEST NEW OBJ CAN BE CHANGED --------------------
310
309
311 new_code = """
310 new_code = """
312 def func1(): return 'changed'
311 def func1(): return 'changed'
313 def func2(): return 'changed'
312 def func2(): return 'changed'
314 class Test:
313 class Test:
315 def new_func(self):
314 def new_func(self):
316 return 'changed'
315 return 'changed'
317 number = 1
316 number = 1
318 from enum import Enum
317 from enum import Enum
319 class TestEnum(Enum):
318 class TestEnum(Enum):
320 A = 'a'
319 A = 'a'
321 B = 'added'
320 B = 'added'
322 """
321 """
323 self.write_file(mod_fn, textwrap.dedent(new_code))
322 self.write_file(mod_fn, textwrap.dedent(new_code))
324 self.shell.run_code("assert func1() == 'changed'")
323 self.shell.run_code("assert func1() == 'changed'")
325 self.shell.run_code("assert func2() == 'changed'")
324 self.shell.run_code("assert func2() == 'changed'")
326 self.shell.run_code("t = Test(); assert t.new_func() == 'changed'")
325 self.shell.run_code("t = Test(); assert t.new_func() == 'changed'")
327 self.shell.run_code("assert number == 1")
326 self.shell.run_code("assert number == 1")
328 self.shell.run_code("assert TestEnum.B.value == 'added'")
327 self.shell.run_code("assert TestEnum.B.value == 'added'")
329
328
330 # ----------- TEST IMPORT FROM MODULE --------------------------
329 # ----------- TEST IMPORT FROM MODULE --------------------------
331
330
332 new_mod_code = """
331 new_mod_code = """
333 from enum import Enum
332 from enum import Enum
334 class Ext(Enum):
333 class Ext(Enum):
335 A = 'ext'
334 A = 'ext'
336 def ext_func():
335 def ext_func():
337 return 'ext'
336 return 'ext'
338 class ExtTest:
337 class ExtTest:
339 def meth(self):
338 def meth(self):
340 return 'ext'
339 return 'ext'
341 ext_int = 2
340 ext_int = 2
342 """
341 """
343 new_mod_name, new_mod_fn = self.new_module(textwrap.dedent(new_mod_code))
342 new_mod_name, new_mod_fn = self.new_module(textwrap.dedent(new_mod_code))
344 current_mod_code = f"""
343 current_mod_code = f"""
345 from {new_mod_name} import *
344 from {new_mod_name} import *
346 """
345 """
347 self.write_file(mod_fn, textwrap.dedent(current_mod_code))
346 self.write_file(mod_fn, textwrap.dedent(current_mod_code))
348 self.shell.run_code("assert Ext.A.value == 'ext'")
347 self.shell.run_code("assert Ext.A.value == 'ext'")
349 self.shell.run_code("assert ext_func() == 'ext'")
348 self.shell.run_code("assert ext_func() == 'ext'")
350 self.shell.run_code("t = ExtTest(); assert t.meth() == 'ext'")
349 self.shell.run_code("t = ExtTest(); assert t.meth() == 'ext'")
351 self.shell.run_code("assert ext_int == 2")
350 self.shell.run_code("assert ext_int == 2")
352
351
353 def _check_smoketest(self, use_aimport=True):
352 def _check_smoketest(self, use_aimport=True):
354 """
353 """
355 Functional test for the automatic reloader using either
354 Functional test for the automatic reloader using either
356 '%autoreload 1' or '%autoreload 2'
355 '%autoreload 1' or '%autoreload 2'
357 """
356 """
358
357
359 mod_name, mod_fn = self.new_module(
358 mod_name, mod_fn = self.new_module(
360 """
359 """
361 x = 9
360 x = 9
362
361
363 z = 123 # this item will be deleted
362 z = 123 # this item will be deleted
364
363
365 def foo(y):
364 def foo(y):
366 return y + 3
365 return y + 3
367
366
368 class Baz(object):
367 class Baz(object):
369 def __init__(self, x):
368 def __init__(self, x):
370 self.x = x
369 self.x = x
371 def bar(self, y):
370 def bar(self, y):
372 return self.x + y
371 return self.x + y
373 @property
372 @property
374 def quux(self):
373 def quux(self):
375 return 42
374 return 42
376 def zzz(self):
375 def zzz(self):
377 '''This method will be deleted below'''
376 '''This method will be deleted below'''
378 return 99
377 return 99
379
378
380 class Bar: # old-style class: weakref doesn't work for it on Python < 2.7
379 class Bar: # old-style class: weakref doesn't work for it on Python < 2.7
381 def foo(self):
380 def foo(self):
382 return 1
381 return 1
383 """
382 """
384 )
383 )
385
384
386 #
385 #
387 # Import module, and mark for reloading
386 # Import module, and mark for reloading
388 #
387 #
389 if use_aimport:
388 if use_aimport:
390 self.shell.magic_autoreload("1")
389 self.shell.magic_autoreload("1")
391 self.shell.magic_aimport(mod_name)
390 self.shell.magic_aimport(mod_name)
392 stream = StringIO()
391 stream = StringIO()
393 self.shell.magic_aimport("", stream=stream)
392 self.shell.magic_aimport("", stream=stream)
394 nt.assert_in(("Modules to reload:\n%s" % mod_name), stream.getvalue())
393 self.assertIn(("Modules to reload:\n%s" % mod_name), stream.getvalue())
395
394
396 with nt.assert_raises(ImportError):
395 with self.assertRaises(ImportError):
397 self.shell.magic_aimport("tmpmod_as318989e89ds")
396 self.shell.magic_aimport("tmpmod_as318989e89ds")
398 else:
397 else:
399 self.shell.magic_autoreload("2")
398 self.shell.magic_autoreload("2")
400 self.shell.run_code("import %s" % mod_name)
399 self.shell.run_code("import %s" % mod_name)
401 stream = StringIO()
400 stream = StringIO()
402 self.shell.magic_aimport("", stream=stream)
401 self.shell.magic_aimport("", stream=stream)
403 nt.assert_true(
402 self.assertTrue(
404 "Modules to reload:\nall-except-skipped" in stream.getvalue()
403 "Modules to reload:\nall-except-skipped" in stream.getvalue()
405 )
404 )
406 nt.assert_in(mod_name, self.shell.ns)
405 self.assertIn(mod_name, self.shell.ns)
407
406
408 mod = sys.modules[mod_name]
407 mod = sys.modules[mod_name]
409
408
410 #
409 #
411 # Test module contents
410 # Test module contents
412 #
411 #
413 old_foo = mod.foo
412 old_foo = mod.foo
414 old_obj = mod.Baz(9)
413 old_obj = mod.Baz(9)
415 old_obj2 = mod.Bar()
414 old_obj2 = mod.Bar()
416
415
417 def check_module_contents():
416 def check_module_contents():
418 nt.assert_equal(mod.x, 9)
417 self.assertEqual(mod.x, 9)
419 nt.assert_equal(mod.z, 123)
418 self.assertEqual(mod.z, 123)
420
419
421 nt.assert_equal(old_foo(0), 3)
420 self.assertEqual(old_foo(0), 3)
422 nt.assert_equal(mod.foo(0), 3)
421 self.assertEqual(mod.foo(0), 3)
423
422
424 obj = mod.Baz(9)
423 obj = mod.Baz(9)
425 nt.assert_equal(old_obj.bar(1), 10)
424 self.assertEqual(old_obj.bar(1), 10)
426 nt.assert_equal(obj.bar(1), 10)
425 self.assertEqual(obj.bar(1), 10)
427 nt.assert_equal(obj.quux, 42)
426 self.assertEqual(obj.quux, 42)
428 nt.assert_equal(obj.zzz(), 99)
427 self.assertEqual(obj.zzz(), 99)
429
428
430 obj2 = mod.Bar()
429 obj2 = mod.Bar()
431 nt.assert_equal(old_obj2.foo(), 1)
430 self.assertEqual(old_obj2.foo(), 1)
432 nt.assert_equal(obj2.foo(), 1)
431 self.assertEqual(obj2.foo(), 1)
433
432
434 check_module_contents()
433 check_module_contents()
435
434
436 #
435 #
437 # Simulate a failed reload: no reload should occur and exactly
436 # Simulate a failed reload: no reload should occur and exactly
438 # one error message should be printed
437 # one error message should be printed
439 #
438 #
440 self.write_file(
439 self.write_file(
441 mod_fn,
440 mod_fn,
442 """
441 """
443 a syntax error
442 a syntax error
444 """,
443 """,
445 )
444 )
446
445
447 with tt.AssertPrints(
446 with tt.AssertPrints(
448 ("[autoreload of %s failed:" % mod_name), channel="stderr"
447 ("[autoreload of %s failed:" % mod_name), channel="stderr"
449 ):
448 ):
450 self.shell.run_code("pass") # trigger reload
449 self.shell.run_code("pass") # trigger reload
451 with tt.AssertNotPrints(
450 with tt.AssertNotPrints(
452 ("[autoreload of %s failed:" % mod_name), channel="stderr"
451 ("[autoreload of %s failed:" % mod_name), channel="stderr"
453 ):
452 ):
454 self.shell.run_code("pass") # trigger another reload
453 self.shell.run_code("pass") # trigger another reload
455 check_module_contents()
454 check_module_contents()
456
455
457 #
456 #
458 # Rewrite module (this time reload should succeed)
457 # Rewrite module (this time reload should succeed)
459 #
458 #
460 self.write_file(
459 self.write_file(
461 mod_fn,
460 mod_fn,
462 """
461 """
463 x = 10
462 x = 10
464
463
465 def foo(y):
464 def foo(y):
466 return y + 4
465 return y + 4
467
466
468 class Baz(object):
467 class Baz(object):
469 def __init__(self, x):
468 def __init__(self, x):
470 self.x = x
469 self.x = x
471 def bar(self, y):
470 def bar(self, y):
472 return self.x + y + 1
471 return self.x + y + 1
473 @property
472 @property
474 def quux(self):
473 def quux(self):
475 return 43
474 return 43
476
475
477 class Bar: # old-style class
476 class Bar: # old-style class
478 def foo(self):
477 def foo(self):
479 return 2
478 return 2
480 """,
479 """,
481 )
480 )
482
481
483 def check_module_contents():
482 def check_module_contents():
484 nt.assert_equal(mod.x, 10)
483 self.assertEqual(mod.x, 10)
485 nt.assert_false(hasattr(mod, "z"))
484 self.assertFalse(hasattr(mod, "z"))
486
485
487 nt.assert_equal(old_foo(0), 4) # superreload magic!
486 self.assertEqual(old_foo(0), 4) # superreload magic!
488 nt.assert_equal(mod.foo(0), 4)
487 self.assertEqual(mod.foo(0), 4)
489
488
490 obj = mod.Baz(9)
489 obj = mod.Baz(9)
491 nt.assert_equal(old_obj.bar(1), 11) # superreload magic!
490 self.assertEqual(old_obj.bar(1), 11) # superreload magic!
492 nt.assert_equal(obj.bar(1), 11)
491 self.assertEqual(obj.bar(1), 11)
493
492
494 nt.assert_equal(old_obj.quux, 43)
493 self.assertEqual(old_obj.quux, 43)
495 nt.assert_equal(obj.quux, 43)
494 self.assertEqual(obj.quux, 43)
496
495
497 nt.assert_false(hasattr(old_obj, "zzz"))
496 self.assertFalse(hasattr(old_obj, "zzz"))
498 nt.assert_false(hasattr(obj, "zzz"))
497 self.assertFalse(hasattr(obj, "zzz"))
499
498
500 obj2 = mod.Bar()
499 obj2 = mod.Bar()
501 nt.assert_equal(old_obj2.foo(), 2)
500 self.assertEqual(old_obj2.foo(), 2)
502 nt.assert_equal(obj2.foo(), 2)
501 self.assertEqual(obj2.foo(), 2)
503
502
504 self.shell.run_code("pass") # trigger reload
503 self.shell.run_code("pass") # trigger reload
505 check_module_contents()
504 check_module_contents()
506
505
507 #
506 #
508 # Another failure case: deleted file (shouldn't reload)
507 # Another failure case: deleted file (shouldn't reload)
509 #
508 #
510 os.unlink(mod_fn)
509 os.unlink(mod_fn)
511
510
512 self.shell.run_code("pass") # trigger reload
511 self.shell.run_code("pass") # trigger reload
513 check_module_contents()
512 check_module_contents()
514
513
515 #
514 #
516 # Disable autoreload and rewrite module: no reload should occur
515 # Disable autoreload and rewrite module: no reload should occur
517 #
516 #
518 if use_aimport:
517 if use_aimport:
519 self.shell.magic_aimport("-" + mod_name)
518 self.shell.magic_aimport("-" + mod_name)
520 stream = StringIO()
519 stream = StringIO()
521 self.shell.magic_aimport("", stream=stream)
520 self.shell.magic_aimport("", stream=stream)
522 nt.assert_true(("Modules to skip:\n%s" % mod_name) in stream.getvalue())
521 self.assertTrue(("Modules to skip:\n%s" % mod_name) in stream.getvalue())
523
522
524 # This should succeed, although no such module exists
523 # This should succeed, although no such module exists
525 self.shell.magic_aimport("-tmpmod_as318989e89ds")
524 self.shell.magic_aimport("-tmpmod_as318989e89ds")
526 else:
525 else:
527 self.shell.magic_autoreload("0")
526 self.shell.magic_autoreload("0")
528
527
529 self.write_file(
528 self.write_file(
530 mod_fn,
529 mod_fn,
531 """
530 """
532 x = -99
531 x = -99
533 """,
532 """,
534 )
533 )
535
534
536 self.shell.run_code("pass") # trigger reload
535 self.shell.run_code("pass") # trigger reload
537 self.shell.run_code("pass")
536 self.shell.run_code("pass")
538 check_module_contents()
537 check_module_contents()
539
538
540 #
539 #
541 # Re-enable autoreload: reload should now occur
540 # Re-enable autoreload: reload should now occur
542 #
541 #
543 if use_aimport:
542 if use_aimport:
544 self.shell.magic_aimport(mod_name)
543 self.shell.magic_aimport(mod_name)
545 else:
544 else:
546 self.shell.magic_autoreload("")
545 self.shell.magic_autoreload("")
547
546
548 self.shell.run_code("pass") # trigger reload
547 self.shell.run_code("pass") # trigger reload
549 nt.assert_equal(mod.x, -99)
548 self.assertEqual(mod.x, -99)
550
549
551 def test_smoketest_aimport(self):
550 def test_smoketest_aimport(self):
552 self._check_smoketest(use_aimport=True)
551 self._check_smoketest(use_aimport=True)
553
552
554 def test_smoketest_autoreload(self):
553 def test_smoketest_autoreload(self):
555 self._check_smoketest(use_aimport=False)
554 self._check_smoketest(use_aimport=False)
@@ -1,66 +1,65 b''
1 import tempfile, os
1 import tempfile, os
2
2
3 from traitlets.config.loader import Config
3 from traitlets.config.loader import Config
4 import nose.tools as nt
5
4
6
5
7 def setup_module():
6 def setup_module():
8 ip.magic('load_ext storemagic')
7 ip.magic('load_ext storemagic')
9
8
10 def test_store_restore():
9 def test_store_restore():
11 assert 'bar' not in ip.user_ns, "Error: some other test leaked `bar` in user_ns"
10 assert 'bar' not in ip.user_ns, "Error: some other test leaked `bar` in user_ns"
12 assert 'foo' not in ip.user_ns, "Error: some other test leaked `foo` in user_ns"
11 assert 'foo' not in ip.user_ns, "Error: some other test leaked `foo` in user_ns"
13 assert 'foobar' not in ip.user_ns, "Error: some other test leaked `foobar` in user_ns"
12 assert 'foobar' not in ip.user_ns, "Error: some other test leaked `foobar` in user_ns"
14 assert 'foobaz' not in ip.user_ns, "Error: some other test leaked `foobaz` in user_ns"
13 assert 'foobaz' not in ip.user_ns, "Error: some other test leaked `foobaz` in user_ns"
15 ip.user_ns['foo'] = 78
14 ip.user_ns['foo'] = 78
16 ip.magic('alias bar echo "hello"')
15 ip.magic('alias bar echo "hello"')
17 ip.user_ns['foobar'] = 79
16 ip.user_ns['foobar'] = 79
18 ip.user_ns['foobaz'] = '80'
17 ip.user_ns['foobaz'] = '80'
19 tmpd = tempfile.mkdtemp()
18 tmpd = tempfile.mkdtemp()
20 ip.magic('cd ' + tmpd)
19 ip.magic('cd ' + tmpd)
21 ip.magic('store foo')
20 ip.magic('store foo')
22 ip.magic('store bar')
21 ip.magic('store bar')
23 ip.magic('store foobar foobaz')
22 ip.magic('store foobar foobaz')
24
23
25 # Check storing
24 # Check storing
26 nt.assert_equal(ip.db['autorestore/foo'], 78)
25 assert ip.db["autorestore/foo"] == 78
27 nt.assert_in('bar', ip.db['stored_aliases'])
26 assert "bar" in ip.db["stored_aliases"]
28 nt.assert_equal(ip.db['autorestore/foobar'], 79)
27 assert ip.db["autorestore/foobar"] == 79
29 nt.assert_equal(ip.db['autorestore/foobaz'], '80')
28 assert ip.db["autorestore/foobaz"] == "80"
30
29
31 # Remove those items
30 # Remove those items
32 ip.user_ns.pop('foo', None)
31 ip.user_ns.pop('foo', None)
33 ip.user_ns.pop('foobar', None)
32 ip.user_ns.pop('foobar', None)
34 ip.user_ns.pop('foobaz', None)
33 ip.user_ns.pop('foobaz', None)
35 ip.alias_manager.undefine_alias('bar')
34 ip.alias_manager.undefine_alias('bar')
36 ip.magic('cd -')
35 ip.magic('cd -')
37 ip.user_ns['_dh'][:] = []
36 ip.user_ns['_dh'][:] = []
38
37
39 # Check restoring
38 # Check restoring
40 ip.magic('store -r foo bar foobar foobaz')
39 ip.magic("store -r foo bar foobar foobaz")
41 nt.assert_equal(ip.user_ns['foo'], 78)
40 assert ip.user_ns["foo"] == 78
42 assert ip.alias_manager.is_alias('bar')
41 assert ip.alias_manager.is_alias("bar")
43 nt.assert_equal(ip.user_ns['foobar'], 79)
42 assert ip.user_ns["foobar"] == 79
44 nt.assert_equal(ip.user_ns['foobaz'], '80')
43 assert ip.user_ns["foobaz"] == "80"
45
44
46 ip.magic('store -r') # restores _dh too
45 ip.magic("store -r") # restores _dh too
47 nt.assert_in(os.path.realpath(tmpd), ip.user_ns['_dh'])
46 assert os.path.realpath(tmpd) in ip.user_ns["_dh"]
48
47
49 os.rmdir(tmpd)
48 os.rmdir(tmpd)
50
49
51 def test_autorestore():
50 def test_autorestore():
52 ip.user_ns['foo'] = 95
51 ip.user_ns['foo'] = 95
53 ip.magic('store foo')
52 ip.magic('store foo')
54 del ip.user_ns['foo']
53 del ip.user_ns['foo']
55 c = Config()
54 c = Config()
56 c.StoreMagics.autorestore = False
55 c.StoreMagics.autorestore = False
57 orig_config = ip.config
56 orig_config = ip.config
58 try:
57 try:
59 ip.config = c
58 ip.config = c
60 ip.extension_manager.reload_extension('storemagic')
59 ip.extension_manager.reload_extension("storemagic")
61 nt.assert_not_in('foo', ip.user_ns)
60 assert "foo" not in ip.user_ns
62 c.StoreMagics.autorestore = True
61 c.StoreMagics.autorestore = True
63 ip.extension_manager.reload_extension('storemagic')
62 ip.extension_manager.reload_extension("storemagic")
64 nt.assert_equal(ip.user_ns['foo'], 95)
63 assert ip.user_ns["foo"] == 95
65 finally:
64 finally:
66 ip.config = orig_config
65 ip.config = orig_config
@@ -1,21 +1,19 b''
1 import nose.tools as nt
2
3 from IPython.core.error import TryNext
1 from IPython.core.error import TryNext
4 from IPython.lib.clipboard import ClipboardEmpty
2 from IPython.lib.clipboard import ClipboardEmpty
5 from IPython.testing.decorators import skip_if_no_x11
3 from IPython.testing.decorators import skip_if_no_x11
6
4
7 @skip_if_no_x11
5 @skip_if_no_x11
8 def test_clipboard_get():
6 def test_clipboard_get():
9 # Smoketest for clipboard access - we can't easily guarantee that the
7 # Smoketest for clipboard access - we can't easily guarantee that the
10 # clipboard is accessible and has something on it, but this tries to
8 # clipboard is accessible and has something on it, but this tries to
11 # exercise the relevant code anyway.
9 # exercise the relevant code anyway.
12 try:
10 try:
13 a = get_ipython().hooks.clipboard_get()
11 a = get_ipython().hooks.clipboard_get()
14 except ClipboardEmpty:
12 except ClipboardEmpty:
15 # Nothing in clipboard to get
13 # Nothing in clipboard to get
16 pass
14 pass
17 except TryNext:
15 except TryNext:
18 # No clipboard access API available
16 # No clipboard access API available
19 pass
17 pass
20 else:
18 else:
21 nt.assert_is_instance(a, str)
19 assert isinstance(a, str)
@@ -1,36 +1,34 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Test suite for the deepreload module."""
2 """Test suite for the deepreload module."""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7 from pathlib import Path
7 from pathlib import Path
8
8
9 import nose.tools as nt
10
11 from IPython.utils.syspathcontext import prepended_to_syspath
9 from IPython.utils.syspathcontext import prepended_to_syspath
12 from IPython.utils.tempdir import TemporaryDirectory
10 from IPython.utils.tempdir import TemporaryDirectory
13 from IPython.lib.deepreload import reload as dreload
11 from IPython.lib.deepreload import reload as dreload
14
12
15
13
16 def test_deepreload():
14 def test_deepreload():
17 "Test that dreload does deep reloads and skips excluded modules."
15 "Test that dreload does deep reloads and skips excluded modules."
18 with TemporaryDirectory() as tmpdir:
16 with TemporaryDirectory() as tmpdir:
19 with prepended_to_syspath(tmpdir):
17 with prepended_to_syspath(tmpdir):
20 tmpdirpath = Path(tmpdir)
18 tmpdirpath = Path(tmpdir)
21 with open(tmpdirpath / "A.py", "w") as f:
19 with open(tmpdirpath / "A.py", "w") as f:
22 f.write("class Object(object):\n pass\n")
20 f.write("class Object(object):\n pass\n")
23 with open(tmpdirpath / "B.py", "w") as f:
21 with open(tmpdirpath / "B.py", "w") as f:
24 f.write("import A\n")
22 f.write("import A\n")
25 import A
23 import A
26 import B
24 import B
27
25
28 # Test that A is not reloaded.
26 # Test that A is not reloaded.
29 obj = A.Object()
27 obj = A.Object()
30 dreload(B, exclude=["A"])
28 dreload(B, exclude=["A"])
31 nt.assert_true(isinstance(obj, A.Object))
29 assert isinstance(obj, A.Object) is True
32
30
33 # Test that A is reloaded.
31 # Test that A is reloaded.
34 obj = A.Object()
32 obj = A.Object()
35 dreload(B)
33 dreload(B)
36 nt.assert_false(isinstance(obj, A.Object))
34 assert isinstance(obj, A.Object) is False
@@ -1,272 +1,272 b''
1 """Tests for IPython.lib.display.
1 """Tests for IPython.lib.display.
2
2
3 """
3 """
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (c) 2012, the IPython Development Team.
5 # Copyright (c) 2012, the IPython Development Team.
6 #
6 #
7 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
8 #
8 #
9 # The full license is in the file COPYING.txt, distributed with this software.
9 # The full license is in the file COPYING.txt, distributed with this software.
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Imports
13 # Imports
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 from tempfile import NamedTemporaryFile, mkdtemp
15 from tempfile import NamedTemporaryFile, mkdtemp
16 from os.path import split, join as pjoin, dirname
16 from os.path import split, join as pjoin, dirname
17 import pathlib
17 import pathlib
18 from unittest import TestCase, mock
18 from unittest import TestCase, mock
19 import struct
19 import struct
20 import wave
20 import wave
21 from io import BytesIO
21 from io import BytesIO
22
22
23 # Third-party imports
23 # Third-party imports
24 import nose.tools as nt
24 import pytest
25
25
26 try:
26 try:
27 import numpy
27 import numpy
28 except ImportError:
28 except ImportError:
29 pass
29 pass
30
30
31 # Our own imports
31 # Our own imports
32 from IPython.lib import display
32 from IPython.lib import display
33
33
34 from IPython.testing.decorators import skipif_not_numpy
34 from IPython.testing.decorators import skipif_not_numpy
35
35
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37 # Classes and functions
37 # Classes and functions
38 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
39
39
40 #--------------------------
40 #--------------------------
41 # FileLink tests
41 # FileLink tests
42 #--------------------------
42 #--------------------------
43
43
44 def test_instantiation_FileLink():
44 def test_instantiation_FileLink():
45 """FileLink: Test class can be instantiated"""
45 """FileLink: Test class can be instantiated"""
46 fl = display.FileLink('example.txt')
46 fl = display.FileLink('example.txt')
47 # TODO: remove if when only Python >= 3.6 is supported
47 # TODO: remove if when only Python >= 3.6 is supported
48 fl = display.FileLink(pathlib.PurePath('example.txt'))
48 fl = display.FileLink(pathlib.PurePath('example.txt'))
49
49
50 def test_warning_on_non_existent_path_FileLink():
50 def test_warning_on_non_existent_path_FileLink():
51 """FileLink: Calling _repr_html_ on non-existent files returns a warning
51 """FileLink: Calling _repr_html_ on non-existent files returns a warning"""
52 """
52 fl = display.FileLink("example.txt")
53 fl = display.FileLink('example.txt')
53 assert fl._repr_html_().startswith("Path (<tt>example.txt</tt>)")
54 nt.assert_true(fl._repr_html_().startswith('Path (<tt>example.txt</tt>)'))
54
55
55
56 def test_existing_path_FileLink():
56 def test_existing_path_FileLink():
57 """FileLink: Calling _repr_html_ functions as expected on existing filepath
57 """FileLink: Calling _repr_html_ functions as expected on existing filepath
58 """
58 """
59 tf = NamedTemporaryFile()
59 tf = NamedTemporaryFile()
60 fl = display.FileLink(tf.name)
60 fl = display.FileLink(tf.name)
61 actual = fl._repr_html_()
61 actual = fl._repr_html_()
62 expected = "<a href='%s' target='_blank'>%s</a><br>" % (tf.name, tf.name)
62 expected = "<a href='%s' target='_blank'>%s</a><br>" % (tf.name, tf.name)
63 assert actual == expected
63 assert actual == expected
64
64
65
65
66 def test_existing_path_FileLink_repr():
66 def test_existing_path_FileLink_repr():
67 """FileLink: Calling repr() functions as expected on existing filepath
67 """FileLink: Calling repr() functions as expected on existing filepath
68 """
68 """
69 tf = NamedTemporaryFile()
69 tf = NamedTemporaryFile()
70 fl = display.FileLink(tf.name)
70 fl = display.FileLink(tf.name)
71 actual = repr(fl)
71 actual = repr(fl)
72 expected = tf.name
72 expected = tf.name
73 assert actual == expected
73 assert actual == expected
74
74
75
75
76 def test_error_on_directory_to_FileLink():
76 def test_error_on_directory_to_FileLink():
77 """FileLink: Raises error when passed directory
77 """FileLink: Raises error when passed directory
78 """
78 """
79 td = mkdtemp()
79 td = mkdtemp()
80 nt.assert_raises(ValueError,display.FileLink,td)
80 pytest.raises(ValueError, display.FileLink, td)
81
81
82 #--------------------------
82 #--------------------------
83 # FileLinks tests
83 # FileLinks tests
84 #--------------------------
84 #--------------------------
85
85
86 def test_instantiation_FileLinks():
86 def test_instantiation_FileLinks():
87 """FileLinks: Test class can be instantiated
87 """FileLinks: Test class can be instantiated
88 """
88 """
89 fls = display.FileLinks('example')
89 fls = display.FileLinks('example')
90
90
91 def test_warning_on_non_existent_path_FileLinks():
91 def test_warning_on_non_existent_path_FileLinks():
92 """FileLinks: Calling _repr_html_ on non-existent files returns a warning
92 """FileLinks: Calling _repr_html_ on non-existent files returns a warning"""
93 """
93 fls = display.FileLinks("example")
94 fls = display.FileLinks('example')
94 assert fls._repr_html_().startswith("Path (<tt>example</tt>)")
95 nt.assert_true(fls._repr_html_().startswith('Path (<tt>example</tt>)'))
95
96
96
97 def test_existing_path_FileLinks():
97 def test_existing_path_FileLinks():
98 """FileLinks: Calling _repr_html_ functions as expected on existing dir
98 """FileLinks: Calling _repr_html_ functions as expected on existing dir
99 """
99 """
100 td = mkdtemp()
100 td = mkdtemp()
101 tf1 = NamedTemporaryFile(dir=td)
101 tf1 = NamedTemporaryFile(dir=td)
102 tf2 = NamedTemporaryFile(dir=td)
102 tf2 = NamedTemporaryFile(dir=td)
103 fl = display.FileLinks(td)
103 fl = display.FileLinks(td)
104 actual = fl._repr_html_()
104 actual = fl._repr_html_()
105 actual = actual.split('\n')
105 actual = actual.split('\n')
106 actual.sort()
106 actual.sort()
107 # the links should always have forward slashes, even on windows, so replace
107 # the links should always have forward slashes, even on windows, so replace
108 # backslashes with forward slashes here
108 # backslashes with forward slashes here
109 expected = ["%s/<br>" % td,
109 expected = ["%s/<br>" % td,
110 "&nbsp;&nbsp;<a href='%s' target='_blank'>%s</a><br>" %\
110 "&nbsp;&nbsp;<a href='%s' target='_blank'>%s</a><br>" %\
111 (tf2.name.replace("\\","/"),split(tf2.name)[1]),
111 (tf2.name.replace("\\","/"),split(tf2.name)[1]),
112 "&nbsp;&nbsp;<a href='%s' target='_blank'>%s</a><br>" %\
112 "&nbsp;&nbsp;<a href='%s' target='_blank'>%s</a><br>" %\
113 (tf1.name.replace("\\","/"),split(tf1.name)[1])]
113 (tf1.name.replace("\\","/"),split(tf1.name)[1])]
114 expected.sort()
114 expected.sort()
115 # We compare the sorted list of links here as that's more reliable
115 # We compare the sorted list of links here as that's more reliable
116 assert actual == expected
116 assert actual == expected
117
117
118
118
119 def test_existing_path_FileLinks_alt_formatter():
119 def test_existing_path_FileLinks_alt_formatter():
120 """FileLinks: Calling _repr_html_ functions as expected w/ an alt formatter
120 """FileLinks: Calling _repr_html_ functions as expected w/ an alt formatter
121 """
121 """
122 td = mkdtemp()
122 td = mkdtemp()
123 tf1 = NamedTemporaryFile(dir=td)
123 tf1 = NamedTemporaryFile(dir=td)
124 tf2 = NamedTemporaryFile(dir=td)
124 tf2 = NamedTemporaryFile(dir=td)
125 def fake_formatter(dirname,fnames,included_suffixes):
125 def fake_formatter(dirname,fnames,included_suffixes):
126 return ["hello","world"]
126 return ["hello","world"]
127 fl = display.FileLinks(td,notebook_display_formatter=fake_formatter)
127 fl = display.FileLinks(td,notebook_display_formatter=fake_formatter)
128 actual = fl._repr_html_()
128 actual = fl._repr_html_()
129 actual = actual.split('\n')
129 actual = actual.split('\n')
130 actual.sort()
130 actual.sort()
131 expected = ["hello","world"]
131 expected = ["hello","world"]
132 expected.sort()
132 expected.sort()
133 # We compare the sorted list of links here as that's more reliable
133 # We compare the sorted list of links here as that's more reliable
134 assert actual == expected
134 assert actual == expected
135
135
136
136
137 def test_existing_path_FileLinks_repr():
137 def test_existing_path_FileLinks_repr():
138 """FileLinks: Calling repr() functions as expected on existing directory """
138 """FileLinks: Calling repr() functions as expected on existing directory """
139 td = mkdtemp()
139 td = mkdtemp()
140 tf1 = NamedTemporaryFile(dir=td)
140 tf1 = NamedTemporaryFile(dir=td)
141 tf2 = NamedTemporaryFile(dir=td)
141 tf2 = NamedTemporaryFile(dir=td)
142 fl = display.FileLinks(td)
142 fl = display.FileLinks(td)
143 actual = repr(fl)
143 actual = repr(fl)
144 actual = actual.split('\n')
144 actual = actual.split('\n')
145 actual.sort()
145 actual.sort()
146 expected = ['%s/' % td, ' %s' % split(tf1.name)[1],' %s' % split(tf2.name)[1]]
146 expected = ['%s/' % td, ' %s' % split(tf1.name)[1],' %s' % split(tf2.name)[1]]
147 expected.sort()
147 expected.sort()
148 # We compare the sorted list of links here as that's more reliable
148 # We compare the sorted list of links here as that's more reliable
149 assert actual == expected
149 assert actual == expected
150
150
151
151
152 def test_existing_path_FileLinks_repr_alt_formatter():
152 def test_existing_path_FileLinks_repr_alt_formatter():
153 """FileLinks: Calling repr() functions as expected w/ alt formatter
153 """FileLinks: Calling repr() functions as expected w/ alt formatter
154 """
154 """
155 td = mkdtemp()
155 td = mkdtemp()
156 tf1 = NamedTemporaryFile(dir=td)
156 tf1 = NamedTemporaryFile(dir=td)
157 tf2 = NamedTemporaryFile(dir=td)
157 tf2 = NamedTemporaryFile(dir=td)
158 def fake_formatter(dirname,fnames,included_suffixes):
158 def fake_formatter(dirname,fnames,included_suffixes):
159 return ["hello","world"]
159 return ["hello","world"]
160 fl = display.FileLinks(td,terminal_display_formatter=fake_formatter)
160 fl = display.FileLinks(td,terminal_display_formatter=fake_formatter)
161 actual = repr(fl)
161 actual = repr(fl)
162 actual = actual.split('\n')
162 actual = actual.split('\n')
163 actual.sort()
163 actual.sort()
164 expected = ["hello","world"]
164 expected = ["hello","world"]
165 expected.sort()
165 expected.sort()
166 # We compare the sorted list of links here as that's more reliable
166 # We compare the sorted list of links here as that's more reliable
167 assert actual == expected
167 assert actual == expected
168
168
169
169
170 def test_error_on_file_to_FileLinks():
170 def test_error_on_file_to_FileLinks():
171 """FileLinks: Raises error when passed file
171 """FileLinks: Raises error when passed file
172 """
172 """
173 td = mkdtemp()
173 td = mkdtemp()
174 tf1 = NamedTemporaryFile(dir=td)
174 tf1 = NamedTemporaryFile(dir=td)
175 nt.assert_raises(ValueError,display.FileLinks,tf1.name)
175 pytest.raises(ValueError, display.FileLinks, tf1.name)
176
176
177
177 def test_recursive_FileLinks():
178 def test_recursive_FileLinks():
178 """FileLinks: Does not recurse when recursive=False
179 """FileLinks: Does not recurse when recursive=False
179 """
180 """
180 td = mkdtemp()
181 td = mkdtemp()
181 tf = NamedTemporaryFile(dir=td)
182 tf = NamedTemporaryFile(dir=td)
182 subtd = mkdtemp(dir=td)
183 subtd = mkdtemp(dir=td)
183 subtf = NamedTemporaryFile(dir=subtd)
184 subtf = NamedTemporaryFile(dir=subtd)
184 fl = display.FileLinks(td)
185 fl = display.FileLinks(td)
185 actual = str(fl)
186 actual = str(fl)
186 actual = actual.split('\n')
187 actual = actual.split('\n')
187 assert len(actual) == 4, actual
188 assert len(actual) == 4, actual
188 fl = display.FileLinks(td, recursive=False)
189 fl = display.FileLinks(td, recursive=False)
189 actual = str(fl)
190 actual = str(fl)
190 actual = actual.split('\n')
191 actual = actual.split('\n')
191 assert len(actual) == 2, actual
192 assert len(actual) == 2, actual
192
193
193 def test_audio_from_file():
194 def test_audio_from_file():
194 path = pjoin(dirname(__file__), 'test.wav')
195 path = pjoin(dirname(__file__), 'test.wav')
195 display.Audio(filename=path)
196 display.Audio(filename=path)
196
197
197 class TestAudioDataWithNumpy(TestCase):
198 class TestAudioDataWithNumpy(TestCase):
198
199
199 @skipif_not_numpy
200 @skipif_not_numpy
200 def test_audio_from_numpy_array(self):
201 def test_audio_from_numpy_array(self):
201 test_tone = get_test_tone()
202 test_tone = get_test_tone()
202 audio = display.Audio(test_tone, rate=44100)
203 audio = display.Audio(test_tone, rate=44100)
203 assert len(read_wav(audio.data)) == len(test_tone)
204 assert len(read_wav(audio.data)) == len(test_tone)
204
205
205 @skipif_not_numpy
206 @skipif_not_numpy
206 def test_audio_from_list(self):
207 def test_audio_from_list(self):
207 test_tone = get_test_tone()
208 test_tone = get_test_tone()
208 audio = display.Audio(list(test_tone), rate=44100)
209 audio = display.Audio(list(test_tone), rate=44100)
209 assert len(read_wav(audio.data)) == len(test_tone)
210 assert len(read_wav(audio.data)) == len(test_tone)
210
211
211 @skipif_not_numpy
212 @skipif_not_numpy
212 def test_audio_from_numpy_array_without_rate_raises(self):
213 def test_audio_from_numpy_array_without_rate_raises(self):
213 nt.assert_raises(ValueError, display.Audio, get_test_tone())
214 self.assertRaises(ValueError, display.Audio, get_test_tone())
214
215
215 @skipif_not_numpy
216 @skipif_not_numpy
216 def test_audio_data_normalization(self):
217 def test_audio_data_normalization(self):
217 expected_max_value = numpy.iinfo(numpy.int16).max
218 expected_max_value = numpy.iinfo(numpy.int16).max
218 for scale in [1, 0.5, 2]:
219 for scale in [1, 0.5, 2]:
219 audio = display.Audio(get_test_tone(scale), rate=44100)
220 audio = display.Audio(get_test_tone(scale), rate=44100)
220 actual_max_value = numpy.max(numpy.abs(read_wav(audio.data)))
221 actual_max_value = numpy.max(numpy.abs(read_wav(audio.data)))
221 assert actual_max_value == expected_max_value
222 assert actual_max_value == expected_max_value
222
223
223 @skipif_not_numpy
224 @skipif_not_numpy
224 def test_audio_data_without_normalization(self):
225 def test_audio_data_without_normalization(self):
225 max_int16 = numpy.iinfo(numpy.int16).max
226 max_int16 = numpy.iinfo(numpy.int16).max
226 for scale in [1, 0.5, 0.2]:
227 for scale in [1, 0.5, 0.2]:
227 test_tone = get_test_tone(scale)
228 test_tone = get_test_tone(scale)
228 test_tone_max_abs = numpy.max(numpy.abs(test_tone))
229 test_tone_max_abs = numpy.max(numpy.abs(test_tone))
229 expected_max_value = int(max_int16 * test_tone_max_abs)
230 expected_max_value = int(max_int16 * test_tone_max_abs)
230 audio = display.Audio(test_tone, rate=44100, normalize=False)
231 audio = display.Audio(test_tone, rate=44100, normalize=False)
231 actual_max_value = numpy.max(numpy.abs(read_wav(audio.data)))
232 actual_max_value = numpy.max(numpy.abs(read_wav(audio.data)))
232 assert actual_max_value == expected_max_value
233 assert actual_max_value == expected_max_value
233
234
234 def test_audio_data_without_normalization_raises_for_invalid_data(self):
235 def test_audio_data_without_normalization_raises_for_invalid_data(self):
235 nt.assert_raises(
236 self.assertRaises(
236 ValueError,
237 ValueError,
237 lambda: display.Audio([1.001], rate=44100, normalize=False))
238 lambda: display.Audio([1.001], rate=44100, normalize=False))
238 nt.assert_raises(
239 self.assertRaises(
239 ValueError,
240 ValueError,
240 lambda: display.Audio([-1.001], rate=44100, normalize=False))
241 lambda: display.Audio([-1.001], rate=44100, normalize=False))
241
242
242 def simulate_numpy_not_installed():
243 def simulate_numpy_not_installed():
243 try:
244 try:
244 import numpy
245 import numpy
245 return mock.patch('numpy.array', mock.MagicMock(side_effect=ImportError))
246 return mock.patch('numpy.array', mock.MagicMock(side_effect=ImportError))
246 except ModuleNotFoundError:
247 except ModuleNotFoundError:
247 return lambda x:x
248 return lambda x:x
248
249
249 @simulate_numpy_not_installed()
250 @simulate_numpy_not_installed()
250 class TestAudioDataWithoutNumpy(TestAudioDataWithNumpy):
251 class TestAudioDataWithoutNumpy(TestAudioDataWithNumpy):
251 # All tests from `TestAudioDataWithNumpy` are inherited.
252 # All tests from `TestAudioDataWithNumpy` are inherited.
252
253
253 @skipif_not_numpy
254 @skipif_not_numpy
254 def test_audio_raises_for_nested_list(self):
255 def test_audio_raises_for_nested_list(self):
255 stereo_signal = [list(get_test_tone())] * 2
256 stereo_signal = [list(get_test_tone())] * 2
256 nt.assert_raises(
257 self.assertRaises(TypeError, lambda: display.Audio(stereo_signal, rate=44100))
257 TypeError,
258
258 lambda: display.Audio(stereo_signal, rate=44100))
259
259
260 @skipif_not_numpy
260 @skipif_not_numpy
261 def get_test_tone(scale=1):
261 def get_test_tone(scale=1):
262 return numpy.sin(2 * numpy.pi * 440 * numpy.linspace(0, 1, 44100)) * scale
262 return numpy.sin(2 * numpy.pi * 440 * numpy.linspace(0, 1, 44100)) * scale
263
263
264 def read_wav(data):
264 def read_wav(data):
265 with wave.open(BytesIO(data)) as wave_file:
265 with wave.open(BytesIO(data)) as wave_file:
266 wave_data = wave_file.readframes(wave_file.getnframes())
266 wave_data = wave_file.readframes(wave_file.getnframes())
267 num_samples = wave_file.getnframes() * wave_file.getnchannels()
267 num_samples = wave_file.getnframes() * wave_file.getnchannels()
268 return struct.unpack('<%sh' % num_samples, wave_data)
268 return struct.unpack('<%sh' % num_samples, wave_data)
269
269
270 def test_code_from_file():
270 def test_code_from_file():
271 c = display.Code(filename=__file__)
271 c = display.Code(filename=__file__)
272 assert c._repr_html_().startswith('<style>')
272 assert c._repr_html_().startswith('<style>')
@@ -1,191 +1,196 b''
1 """Tests for IPython.utils.path.py"""
1 """Tests for IPython.utils.path.py"""
2 # Copyright (c) IPython Development Team.
2 # Copyright (c) IPython Development Team.
3 # Distributed under the terms of the Modified BSD License.
3 # Distributed under the terms of the Modified BSD License.
4
4
5 from contextlib import contextmanager
5 from contextlib import contextmanager
6 from unittest.mock import patch
6 from unittest.mock import patch
7
7
8 import nose.tools as nt
9 import pytest
8 import pytest
10
9
11 from IPython.lib import latextools
10 from IPython.lib import latextools
12 from IPython.testing.decorators import (
11 from IPython.testing.decorators import (
13 onlyif_cmds_exist,
12 onlyif_cmds_exist,
14 skipif_not_matplotlib,
13 skipif_not_matplotlib,
15 skip_iptest_but_not_pytest,
14 skip_iptest_but_not_pytest,
16 )
15 )
17 from IPython.utils.process import FindCmdError
16 from IPython.utils.process import FindCmdError
18
17
19
18
20 @pytest.mark.parametrize('command', ['latex', 'dvipng'])
19 @pytest.mark.parametrize('command', ['latex', 'dvipng'])
21 @skip_iptest_but_not_pytest
20 @skip_iptest_but_not_pytest
22 def test_check_latex_to_png_dvipng_fails_when_no_cmd(command):
21 def test_check_latex_to_png_dvipng_fails_when_no_cmd(command):
23 def mock_find_cmd(arg):
22 def mock_find_cmd(arg):
24 if arg == command:
23 if arg == command:
25 raise FindCmdError
24 raise FindCmdError
26
25
27 with patch.object(latextools, "find_cmd", mock_find_cmd):
26 with patch.object(latextools, "find_cmd", mock_find_cmd):
28 assert latextools.latex_to_png_dvipng("whatever", True) is None
27 assert latextools.latex_to_png_dvipng("whatever", True) is None
29
28
30
29
31 @contextmanager
30 @contextmanager
32 def no_op(*args, **kwargs):
31 def no_op(*args, **kwargs):
33 yield
32 yield
34
33
35
34
36 @skip_iptest_but_not_pytest
35 @skip_iptest_but_not_pytest
37 @onlyif_cmds_exist("latex", "dvipng")
36 @onlyif_cmds_exist("latex", "dvipng")
38 @pytest.mark.parametrize("s, wrap", [(u"$$x^2$$", False), (u"x^2", True)])
37 @pytest.mark.parametrize("s, wrap", [(u"$$x^2$$", False), (u"x^2", True)])
39 def test_latex_to_png_dvipng_runs(s, wrap):
38 def test_latex_to_png_dvipng_runs(s, wrap):
40 """
39 """
41 Test that latex_to_png_dvipng just runs without error.
40 Test that latex_to_png_dvipng just runs without error.
42 """
41 """
43 def mock_kpsewhich(filename):
42 def mock_kpsewhich(filename):
44 assert filename == "breqn.sty"
43 assert filename == "breqn.sty"
45 return None
44 return None
46
45
47 latextools.latex_to_png_dvipng(s, wrap)
46 latextools.latex_to_png_dvipng(s, wrap)
48
47
49 with patch_latextool(mock_kpsewhich):
48 with patch_latextool(mock_kpsewhich):
50 latextools.latex_to_png_dvipng(s, wrap)
49 latextools.latex_to_png_dvipng(s, wrap)
51
50
52
51
53 def mock_kpsewhich(filename):
52 def mock_kpsewhich(filename):
54 assert filename == "breqn.sty"
53 assert filename == "breqn.sty"
55 return None
54 return None
56
55
57 @contextmanager
56 @contextmanager
58 def patch_latextool(mock=mock_kpsewhich):
57 def patch_latextool(mock=mock_kpsewhich):
59 with patch.object(latextools, "kpsewhich", mock):
58 with patch.object(latextools, "kpsewhich", mock):
60 yield
59 yield
61
60
62 @pytest.mark.parametrize('context', [no_op, patch_latextool])
61 @pytest.mark.parametrize('context', [no_op, patch_latextool])
63 @pytest.mark.parametrize('s_wrap', [("$x^2$", False), ("x^2", True)])
62 @pytest.mark.parametrize('s_wrap', [("$x^2$", False), ("x^2", True)])
64 @skip_iptest_but_not_pytest
63 @skip_iptest_but_not_pytest
65 def test_latex_to_png_mpl_runs(s_wrap, context):
64 def test_latex_to_png_mpl_runs(s_wrap, context):
66 """
65 """
67 Test that latex_to_png_mpl just runs without error.
66 Test that latex_to_png_mpl just runs without error.
68 """
67 """
69 try:
68 try:
70 import matplotlib
69 import matplotlib
71 except ImportError:
70 except ImportError:
72 pytest.skip("This needs matplotlib to be available")
71 pytest.skip("This needs matplotlib to be available")
73 return
72 return
74 s, wrap = s_wrap
73 s, wrap = s_wrap
75 with context():
74 with context():
76 latextools.latex_to_png_mpl(s, wrap)
75 latextools.latex_to_png_mpl(s, wrap)
77
76
78 @skipif_not_matplotlib
77 @skipif_not_matplotlib
79 def test_latex_to_html():
78 def test_latex_to_html():
80 img = latextools.latex_to_html("$x^2$")
79 img = latextools.latex_to_html("$x^2$")
81 assert "data:image/png;base64,iVBOR" in img
80 assert "data:image/png;base64,iVBOR" in img
82
81
83
82
84 def test_genelatex_no_wrap():
83 def test_genelatex_no_wrap():
85 """
84 """
86 Test genelatex with wrap=False.
85 Test genelatex with wrap=False.
87 """
86 """
88 def mock_kpsewhich(filename):
87 def mock_kpsewhich(filename):
89 assert False, ("kpsewhich should not be called "
88 assert False, ("kpsewhich should not be called "
90 "(called with {0})".format(filename))
89 "(called with {0})".format(filename))
91
90
92 with patch_latextool(mock_kpsewhich):
91 with patch_latextool(mock_kpsewhich):
93 assert '\n'.join(latextools.genelatex("body text", False)) == r'''\documentclass{article}
92 assert '\n'.join(latextools.genelatex("body text", False)) == r'''\documentclass{article}
94 \usepackage{amsmath}
93 \usepackage{amsmath}
95 \usepackage{amsthm}
94 \usepackage{amsthm}
96 \usepackage{amssymb}
95 \usepackage{amssymb}
97 \usepackage{bm}
96 \usepackage{bm}
98 \pagestyle{empty}
97 \pagestyle{empty}
99 \begin{document}
98 \begin{document}
100 body text
99 body text
101 \end{document}'''
100 \end{document}'''
102
101
103
102
104 def test_genelatex_wrap_with_breqn():
103 def test_genelatex_wrap_with_breqn():
105 """
104 """
106 Test genelatex with wrap=True for the case breqn.sty is installed.
105 Test genelatex with wrap=True for the case breqn.sty is installed.
107 """
106 """
108 def mock_kpsewhich(filename):
107 def mock_kpsewhich(filename):
109 assert filename == "breqn.sty"
108 assert filename == "breqn.sty"
110 return "path/to/breqn.sty"
109 return "path/to/breqn.sty"
111
110
112 with patch_latextool(mock_kpsewhich):
111 with patch_latextool(mock_kpsewhich):
113 assert '\n'.join(latextools.genelatex("x^2", True)) == r'''\documentclass{article}
112 assert '\n'.join(latextools.genelatex("x^2", True)) == r'''\documentclass{article}
114 \usepackage{amsmath}
113 \usepackage{amsmath}
115 \usepackage{amsthm}
114 \usepackage{amsthm}
116 \usepackage{amssymb}
115 \usepackage{amssymb}
117 \usepackage{bm}
116 \usepackage{bm}
118 \usepackage{breqn}
117 \usepackage{breqn}
119 \pagestyle{empty}
118 \pagestyle{empty}
120 \begin{document}
119 \begin{document}
121 \begin{dmath*}
120 \begin{dmath*}
122 x^2
121 x^2
123 \end{dmath*}
122 \end{dmath*}
124 \end{document}'''
123 \end{document}'''
125
124
126
125
127 def test_genelatex_wrap_without_breqn():
126 def test_genelatex_wrap_without_breqn():
128 """
127 """
129 Test genelatex with wrap=True for the case breqn.sty is not installed.
128 Test genelatex with wrap=True for the case breqn.sty is not installed.
130 """
129 """
131 def mock_kpsewhich(filename):
130 def mock_kpsewhich(filename):
132 assert filename == "breqn.sty"
131 assert filename == "breqn.sty"
133 return None
132 return None
134
133
135 with patch_latextool(mock_kpsewhich):
134 with patch_latextool(mock_kpsewhich):
136 assert '\n'.join(latextools.genelatex("x^2", True)) == r'''\documentclass{article}
135 assert '\n'.join(latextools.genelatex("x^2", True)) == r'''\documentclass{article}
137 \usepackage{amsmath}
136 \usepackage{amsmath}
138 \usepackage{amsthm}
137 \usepackage{amsthm}
139 \usepackage{amssymb}
138 \usepackage{amssymb}
140 \usepackage{bm}
139 \usepackage{bm}
141 \pagestyle{empty}
140 \pagestyle{empty}
142 \begin{document}
141 \begin{document}
143 $$x^2$$
142 $$x^2$$
144 \end{document}'''
143 \end{document}'''
145
144
146
145
147 @skipif_not_matplotlib
146 @skipif_not_matplotlib
148 @onlyif_cmds_exist('latex', 'dvipng')
147 @onlyif_cmds_exist('latex', 'dvipng')
149 def test_latex_to_png_color():
148 def test_latex_to_png_color():
150 """
149 """
151 Test color settings for latex_to_png.
150 Test color settings for latex_to_png.
152 """
151 """
153 latex_string = "$x^2$"
152 latex_string = "$x^2$"
154 default_value = latextools.latex_to_png(latex_string, wrap=False)
153 default_value = latextools.latex_to_png(latex_string, wrap=False)
155 default_hexblack = latextools.latex_to_png(latex_string, wrap=False,
154 default_hexblack = latextools.latex_to_png(latex_string, wrap=False,
156 color='#000000')
155 color='#000000')
157 dvipng_default = latextools.latex_to_png_dvipng(latex_string, False)
156 dvipng_default = latextools.latex_to_png_dvipng(latex_string, False)
158 dvipng_black = latextools.latex_to_png_dvipng(latex_string, False, 'Black')
157 dvipng_black = latextools.latex_to_png_dvipng(latex_string, False, 'Black')
159 assert dvipng_default == dvipng_black
158 assert dvipng_default == dvipng_black
160 mpl_default = latextools.latex_to_png_mpl(latex_string, False)
159 mpl_default = latextools.latex_to_png_mpl(latex_string, False)
161 mpl_black = latextools.latex_to_png_mpl(latex_string, False, 'Black')
160 mpl_black = latextools.latex_to_png_mpl(latex_string, False, 'Black')
162 assert mpl_default == mpl_black
161 assert mpl_default == mpl_black
163 assert default_value in [dvipng_black, mpl_black]
162 assert default_value in [dvipng_black, mpl_black]
164 assert default_hexblack in [dvipng_black, mpl_black]
163 assert default_hexblack in [dvipng_black, mpl_black]
165
164
166 # Test that dvips name colors can be used without error
165 # Test that dvips name colors can be used without error
167 dvipng_maroon = latextools.latex_to_png_dvipng(latex_string, False,
166 dvipng_maroon = latextools.latex_to_png_dvipng(latex_string, False,
168 'Maroon')
167 'Maroon')
169 # And that it doesn't return the black one
168 # And that it doesn't return the black one
170 assert dvipng_black != dvipng_maroon
169 assert dvipng_black != dvipng_maroon
171
170
172 mpl_maroon = latextools.latex_to_png_mpl(latex_string, False, 'Maroon')
171 mpl_maroon = latextools.latex_to_png_mpl(latex_string, False, 'Maroon')
173 assert mpl_black != mpl_maroon
172 assert mpl_black != mpl_maroon
174 mpl_white = latextools.latex_to_png_mpl(latex_string, False, 'White')
173 mpl_white = latextools.latex_to_png_mpl(latex_string, False, 'White')
175 mpl_hexwhite = latextools.latex_to_png_mpl(latex_string, False, '#FFFFFF')
174 mpl_hexwhite = latextools.latex_to_png_mpl(latex_string, False, '#FFFFFF')
176 assert mpl_white == mpl_hexwhite
175 assert mpl_white == mpl_hexwhite
177
176
178 mpl_white_scale = latextools.latex_to_png_mpl(latex_string, False,
177 mpl_white_scale = latextools.latex_to_png_mpl(latex_string, False,
179 'White', 1.2)
178 'White', 1.2)
180 assert mpl_white != mpl_white_scale
179 assert mpl_white != mpl_white_scale
181
180
182
181
183 def test_latex_to_png_invalid_hex_colors():
182 def test_latex_to_png_invalid_hex_colors():
184 """
183 """
185 Test that invalid hex colors provided to dvipng gives an exception.
184 Test that invalid hex colors provided to dvipng gives an exception.
186 """
185 """
187 latex_string = "$x^2$"
186 latex_string = "$x^2$"
188 nt.assert_raises(ValueError, lambda: latextools.latex_to_png(latex_string,
187 pytest.raises(
189 backend='dvipng', color="#f00bar"))
188 ValueError,
190 nt.assert_raises(ValueError, lambda: latextools.latex_to_png(latex_string,
189 lambda: latextools.latex_to_png(
191 backend='dvipng', color="#f00"))
190 latex_string, backend="dvipng", color="#f00bar"
191 ),
192 )
193 pytest.raises(
194 ValueError,
195 lambda: latextools.latex_to_png(latex_string, backend="dvipng", color="#f00"),
196 )
@@ -1,502 +1,500 b''
1 # coding: utf-8
1 # coding: utf-8
2 """Tests for IPython.lib.pretty."""
2 """Tests for IPython.lib.pretty."""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7
7
8 from collections import Counter, defaultdict, deque, OrderedDict
8 from collections import Counter, defaultdict, deque, OrderedDict
9 import os
9 import os
10 import types
10 import types
11 import string
11 import string
12 import unittest
12 import unittest
13
13
14 import nose.tools as nt
15 import pytest
14 import pytest
16
15
17 from IPython.lib import pretty
16 from IPython.lib import pretty
18 from IPython.testing.decorators import skip_without, skip_iptest_but_not_pytest
17 from IPython.testing.decorators import skip_without, skip_iptest_but_not_pytest
19
18
20 from io import StringIO
19 from io import StringIO
21
20
22
21
23 class MyList(object):
22 class MyList(object):
24 def __init__(self, content):
23 def __init__(self, content):
25 self.content = content
24 self.content = content
26 def _repr_pretty_(self, p, cycle):
25 def _repr_pretty_(self, p, cycle):
27 if cycle:
26 if cycle:
28 p.text("MyList(...)")
27 p.text("MyList(...)")
29 else:
28 else:
30 with p.group(3, "MyList(", ")"):
29 with p.group(3, "MyList(", ")"):
31 for (i, child) in enumerate(self.content):
30 for (i, child) in enumerate(self.content):
32 if i:
31 if i:
33 p.text(",")
32 p.text(",")
34 p.breakable()
33 p.breakable()
35 else:
34 else:
36 p.breakable("")
35 p.breakable("")
37 p.pretty(child)
36 p.pretty(child)
38
37
39
38
40 class MyDict(dict):
39 class MyDict(dict):
41 def _repr_pretty_(self, p, cycle):
40 def _repr_pretty_(self, p, cycle):
42 p.text("MyDict(...)")
41 p.text("MyDict(...)")
43
42
44 class MyObj(object):
43 class MyObj(object):
45 def somemethod(self):
44 def somemethod(self):
46 pass
45 pass
47
46
48
47
49 class Dummy1(object):
48 class Dummy1(object):
50 def _repr_pretty_(self, p, cycle):
49 def _repr_pretty_(self, p, cycle):
51 p.text("Dummy1(...)")
50 p.text("Dummy1(...)")
52
51
53 class Dummy2(Dummy1):
52 class Dummy2(Dummy1):
54 _repr_pretty_ = None
53 _repr_pretty_ = None
55
54
56 class NoModule(object):
55 class NoModule(object):
57 pass
56 pass
58
57
59 NoModule.__module__ = None
58 NoModule.__module__ = None
60
59
61 class Breaking(object):
60 class Breaking(object):
62 def _repr_pretty_(self, p, cycle):
61 def _repr_pretty_(self, p, cycle):
63 with p.group(4,"TG: ",":"):
62 with p.group(4,"TG: ",":"):
64 p.text("Breaking(")
63 p.text("Breaking(")
65 p.break_()
64 p.break_()
66 p.text(")")
65 p.text(")")
67
66
68 class BreakingRepr(object):
67 class BreakingRepr(object):
69 def __repr__(self):
68 def __repr__(self):
70 return "Breaking(\n)"
69 return "Breaking(\n)"
71
70
72 class BadRepr(object):
71 class BadRepr(object):
73
74 def __repr__(self):
72 def __repr__(self):
75 return 1/0
73 return 1/0
76
74
77
75
78 def test_indentation():
76 def test_indentation():
79 """Test correct indentation in groups"""
77 """Test correct indentation in groups"""
80 count = 40
78 count = 40
81 gotoutput = pretty.pretty(MyList(range(count)))
79 gotoutput = pretty.pretty(MyList(range(count)))
82 expectedoutput = "MyList(\n" + ",\n".join(" %d" % i for i in range(count)) + ")"
80 expectedoutput = "MyList(\n" + ",\n".join(" %d" % i for i in range(count)) + ")"
83
81
84 assert gotoutput == expectedoutput
82 assert gotoutput == expectedoutput
85
83
86
84
87 def test_dispatch():
85 def test_dispatch():
88 """
86 """
89 Test correct dispatching: The _repr_pretty_ method for MyDict
87 Test correct dispatching: The _repr_pretty_ method for MyDict
90 must be found before the registered printer for dict.
88 must be found before the registered printer for dict.
91 """
89 """
92 gotoutput = pretty.pretty(MyDict())
90 gotoutput = pretty.pretty(MyDict())
93 expectedoutput = "MyDict(...)"
91 expectedoutput = "MyDict(...)"
94
92
95 assert gotoutput == expectedoutput
93 assert gotoutput == expectedoutput
96
94
97
95
98 def test_callability_checking():
96 def test_callability_checking():
99 """
97 """
100 Test that the _repr_pretty_ method is tested for callability and skipped if
98 Test that the _repr_pretty_ method is tested for callability and skipped if
101 not.
99 not.
102 """
100 """
103 gotoutput = pretty.pretty(Dummy2())
101 gotoutput = pretty.pretty(Dummy2())
104 expectedoutput = "Dummy1(...)"
102 expectedoutput = "Dummy1(...)"
105
103
106 assert gotoutput == expectedoutput
104 assert gotoutput == expectedoutput
107
105
108
106
109 @pytest.mark.parametrize(
107 @pytest.mark.parametrize(
110 "obj,expected_output",
108 "obj,expected_output",
111 zip(
109 zip(
112 [
110 [
113 set(),
111 set(),
114 frozenset(),
112 frozenset(),
115 set([1]),
113 set([1]),
116 frozenset([1]),
114 frozenset([1]),
117 set([1, 2]),
115 set([1, 2]),
118 frozenset([1, 2]),
116 frozenset([1, 2]),
119 set([-1, -2, -3]),
117 set([-1, -2, -3]),
120 ],
118 ],
121 [
119 [
122 "set()",
120 "set()",
123 "frozenset()",
121 "frozenset()",
124 "{1}",
122 "{1}",
125 "frozenset({1})",
123 "frozenset({1})",
126 "{1, 2}",
124 "{1, 2}",
127 "frozenset({1, 2})",
125 "frozenset({1, 2})",
128 "{-3, -2, -1}",
126 "{-3, -2, -1}",
129 ],
127 ],
130 ),
128 ),
131 )
129 )
132 @skip_iptest_but_not_pytest
130 @skip_iptest_but_not_pytest
133 def test_sets(obj, expected_output):
131 def test_sets(obj, expected_output):
134 """
132 """
135 Test that set and frozenset use Python 3 formatting.
133 Test that set and frozenset use Python 3 formatting.
136 """
134 """
137 got_output = pretty.pretty(obj)
135 got_output = pretty.pretty(obj)
138 assert got_output == expected_output
136 assert got_output == expected_output
139
137
140
138
141 @skip_without('xxlimited')
139 @skip_without('xxlimited')
142 def test_pprint_heap_allocated_type():
140 def test_pprint_heap_allocated_type():
143 """
141 """
144 Test that pprint works for heap allocated types.
142 Test that pprint works for heap allocated types.
145 """
143 """
146 import xxlimited
144 import xxlimited
147 output = pretty.pretty(xxlimited.Null)
145 output = pretty.pretty(xxlimited.Null)
148 assert output == "xxlimited.Null"
146 assert output == "xxlimited.Null"
149
147
150
148
151 def test_pprint_nomod():
149 def test_pprint_nomod():
152 """
150 """
153 Test that pprint works for classes with no __module__.
151 Test that pprint works for classes with no __module__.
154 """
152 """
155 output = pretty.pretty(NoModule)
153 output = pretty.pretty(NoModule)
156 assert output == "NoModule"
154 assert output == "NoModule"
157
155
158
156
159 def test_pprint_break():
157 def test_pprint_break():
160 """
158 """
161 Test that p.break_ produces expected output
159 Test that p.break_ produces expected output
162 """
160 """
163 output = pretty.pretty(Breaking())
161 output = pretty.pretty(Breaking())
164 expected = "TG: Breaking(\n ):"
162 expected = "TG: Breaking(\n ):"
165 assert output == expected
163 assert output == expected
166
164
167 def test_pprint_break_repr():
165 def test_pprint_break_repr():
168 """
166 """
169 Test that p.break_ is used in repr
167 Test that p.break_ is used in repr
170 """
168 """
171 output = pretty.pretty([[BreakingRepr()]])
169 output = pretty.pretty([[BreakingRepr()]])
172 expected = "[[Breaking(\n )]]"
170 expected = "[[Breaking(\n )]]"
173 assert output == expected
171 assert output == expected
174
172
175 output = pretty.pretty([[BreakingRepr()]*2])
173 output = pretty.pretty([[BreakingRepr()]*2])
176 expected = "[[Breaking(\n ),\n Breaking(\n )]]"
174 expected = "[[Breaking(\n ),\n Breaking(\n )]]"
177 assert output == expected
175 assert output == expected
178
176
179 def test_bad_repr():
177 def test_bad_repr():
180 """Don't catch bad repr errors"""
178 """Don't catch bad repr errors"""
181 with nt.assert_raises(ZeroDivisionError):
179 with pytest.raises(ZeroDivisionError):
182 pretty.pretty(BadRepr())
180 pretty.pretty(BadRepr())
183
181
184 class BadException(Exception):
182 class BadException(Exception):
185 def __str__(self):
183 def __str__(self):
186 return -1
184 return -1
187
185
188 class ReallyBadRepr(object):
186 class ReallyBadRepr(object):
189 __module__ = 1
187 __module__ = 1
190 @property
188 @property
191 def __class__(self):
189 def __class__(self):
192 raise ValueError("I am horrible")
190 raise ValueError("I am horrible")
193
191
194 def __repr__(self):
192 def __repr__(self):
195 raise BadException()
193 raise BadException()
196
194
197 def test_really_bad_repr():
195 def test_really_bad_repr():
198 with nt.assert_raises(BadException):
196 with pytest.raises(BadException):
199 pretty.pretty(ReallyBadRepr())
197 pretty.pretty(ReallyBadRepr())
200
198
201
199
202 class SA(object):
200 class SA(object):
203 pass
201 pass
204
202
205 class SB(SA):
203 class SB(SA):
206 pass
204 pass
207
205
208 class TestsPretty(unittest.TestCase):
206 class TestsPretty(unittest.TestCase):
209
207
210 def test_super_repr(self):
208 def test_super_repr(self):
211 # "<super: module_name.SA, None>"
209 # "<super: module_name.SA, None>"
212 output = pretty.pretty(super(SA))
210 output = pretty.pretty(super(SA))
213 self.assertRegex(output, r"<super: \S+.SA, None>")
211 self.assertRegex(output, r"<super: \S+.SA, None>")
214
212
215 # "<super: module_name.SA, <module_name.SB at 0x...>>"
213 # "<super: module_name.SA, <module_name.SB at 0x...>>"
216 sb = SB()
214 sb = SB()
217 output = pretty.pretty(super(SA, sb))
215 output = pretty.pretty(super(SA, sb))
218 self.assertRegex(output, r"<super: \S+.SA,\s+<\S+.SB at 0x\S+>>")
216 self.assertRegex(output, r"<super: \S+.SA,\s+<\S+.SB at 0x\S+>>")
219
217
220
218
221 def test_long_list(self):
219 def test_long_list(self):
222 lis = list(range(10000))
220 lis = list(range(10000))
223 p = pretty.pretty(lis)
221 p = pretty.pretty(lis)
224 last2 = p.rsplit('\n', 2)[-2:]
222 last2 = p.rsplit('\n', 2)[-2:]
225 self.assertEqual(last2, [' 999,', ' ...]'])
223 self.assertEqual(last2, [' 999,', ' ...]'])
226
224
227 def test_long_set(self):
225 def test_long_set(self):
228 s = set(range(10000))
226 s = set(range(10000))
229 p = pretty.pretty(s)
227 p = pretty.pretty(s)
230 last2 = p.rsplit('\n', 2)[-2:]
228 last2 = p.rsplit('\n', 2)[-2:]
231 self.assertEqual(last2, [' 999,', ' ...}'])
229 self.assertEqual(last2, [' 999,', ' ...}'])
232
230
233 def test_long_tuple(self):
231 def test_long_tuple(self):
234 tup = tuple(range(10000))
232 tup = tuple(range(10000))
235 p = pretty.pretty(tup)
233 p = pretty.pretty(tup)
236 last2 = p.rsplit('\n', 2)[-2:]
234 last2 = p.rsplit('\n', 2)[-2:]
237 self.assertEqual(last2, [' 999,', ' ...)'])
235 self.assertEqual(last2, [' 999,', ' ...)'])
238
236
239 def test_long_dict(self):
237 def test_long_dict(self):
240 d = { n:n for n in range(10000) }
238 d = { n:n for n in range(10000) }
241 p = pretty.pretty(d)
239 p = pretty.pretty(d)
242 last2 = p.rsplit('\n', 2)[-2:]
240 last2 = p.rsplit('\n', 2)[-2:]
243 self.assertEqual(last2, [' 999: 999,', ' ...}'])
241 self.assertEqual(last2, [' 999: 999,', ' ...}'])
244
242
245 def test_unbound_method(self):
243 def test_unbound_method(self):
246 output = pretty.pretty(MyObj.somemethod)
244 output = pretty.pretty(MyObj.somemethod)
247 self.assertIn('MyObj.somemethod', output)
245 self.assertIn('MyObj.somemethod', output)
248
246
249
247
250 class MetaClass(type):
248 class MetaClass(type):
251 def __new__(cls, name):
249 def __new__(cls, name):
252 return type.__new__(cls, name, (object,), {'name': name})
250 return type.__new__(cls, name, (object,), {'name': name})
253
251
254 def __repr__(self):
252 def __repr__(self):
255 return "[CUSTOM REPR FOR CLASS %s]" % self.name
253 return "[CUSTOM REPR FOR CLASS %s]" % self.name
256
254
257
255
258 ClassWithMeta = MetaClass('ClassWithMeta')
256 ClassWithMeta = MetaClass('ClassWithMeta')
259
257
260
258
261 def test_metaclass_repr():
259 def test_metaclass_repr():
262 output = pretty.pretty(ClassWithMeta)
260 output = pretty.pretty(ClassWithMeta)
263 assert output == "[CUSTOM REPR FOR CLASS ClassWithMeta]"
261 assert output == "[CUSTOM REPR FOR CLASS ClassWithMeta]"
264
262
265
263
266 def test_unicode_repr():
264 def test_unicode_repr():
267 u = u"üniçodé"
265 u = u"üniçodé"
268 ustr = u
266 ustr = u
269
267
270 class C(object):
268 class C(object):
271 def __repr__(self):
269 def __repr__(self):
272 return ustr
270 return ustr
273
271
274 c = C()
272 c = C()
275 p = pretty.pretty(c)
273 p = pretty.pretty(c)
276 assert p == u
274 assert p == u
277 p = pretty.pretty([c])
275 p = pretty.pretty([c])
278 assert p == u"[%s]" % u
276 assert p == u"[%s]" % u
279
277
280
278
281 def test_basic_class():
279 def test_basic_class():
282 def type_pprint_wrapper(obj, p, cycle):
280 def type_pprint_wrapper(obj, p, cycle):
283 if obj is MyObj:
281 if obj is MyObj:
284 type_pprint_wrapper.called = True
282 type_pprint_wrapper.called = True
285 return pretty._type_pprint(obj, p, cycle)
283 return pretty._type_pprint(obj, p, cycle)
286 type_pprint_wrapper.called = False
284 type_pprint_wrapper.called = False
287
285
288 stream = StringIO()
286 stream = StringIO()
289 printer = pretty.RepresentationPrinter(stream)
287 printer = pretty.RepresentationPrinter(stream)
290 printer.type_pprinters[type] = type_pprint_wrapper
288 printer.type_pprinters[type] = type_pprint_wrapper
291 printer.pretty(MyObj)
289 printer.pretty(MyObj)
292 printer.flush()
290 printer.flush()
293 output = stream.getvalue()
291 output = stream.getvalue()
294
292
295 assert output == "%s.MyObj" % __name__
293 assert output == "%s.MyObj" % __name__
296 nt.assert_true(type_pprint_wrapper.called)
294 assert type_pprint_wrapper.called is True
297
295
298
296
299 # TODO : pytest.mark.parametrise once nose is gone.
297 # TODO : pytest.mark.parametrise once nose is gone.
300 def test_collections_defaultdict():
298 def test_collections_defaultdict():
301 # Create defaultdicts with cycles
299 # Create defaultdicts with cycles
302 a = defaultdict()
300 a = defaultdict()
303 a.default_factory = a
301 a.default_factory = a
304 b = defaultdict(list)
302 b = defaultdict(list)
305 b['key'] = b
303 b['key'] = b
306
304
307 # Dictionary order cannot be relied on, test against single keys.
305 # Dictionary order cannot be relied on, test against single keys.
308 cases = [
306 cases = [
309 (defaultdict(list), 'defaultdict(list, {})'),
307 (defaultdict(list), 'defaultdict(list, {})'),
310 (defaultdict(list, {'key': '-' * 50}),
308 (defaultdict(list, {'key': '-' * 50}),
311 "defaultdict(list,\n"
309 "defaultdict(list,\n"
312 " {'key': '--------------------------------------------------'})"),
310 " {'key': '--------------------------------------------------'})"),
313 (a, 'defaultdict(defaultdict(...), {})'),
311 (a, 'defaultdict(defaultdict(...), {})'),
314 (b, "defaultdict(list, {'key': defaultdict(...)})"),
312 (b, "defaultdict(list, {'key': defaultdict(...)})"),
315 ]
313 ]
316 for obj, expected in cases:
314 for obj, expected in cases:
317 assert pretty.pretty(obj) == expected
315 assert pretty.pretty(obj) == expected
318
316
319
317
320 # TODO : pytest.mark.parametrise once nose is gone.
318 # TODO : pytest.mark.parametrise once nose is gone.
321 def test_collections_ordereddict():
319 def test_collections_ordereddict():
322 # Create OrderedDict with cycle
320 # Create OrderedDict with cycle
323 a = OrderedDict()
321 a = OrderedDict()
324 a['key'] = a
322 a['key'] = a
325
323
326 cases = [
324 cases = [
327 (OrderedDict(), 'OrderedDict()'),
325 (OrderedDict(), 'OrderedDict()'),
328 (OrderedDict((i, i) for i in range(1000, 1010)),
326 (OrderedDict((i, i) for i in range(1000, 1010)),
329 'OrderedDict([(1000, 1000),\n'
327 'OrderedDict([(1000, 1000),\n'
330 ' (1001, 1001),\n'
328 ' (1001, 1001),\n'
331 ' (1002, 1002),\n'
329 ' (1002, 1002),\n'
332 ' (1003, 1003),\n'
330 ' (1003, 1003),\n'
333 ' (1004, 1004),\n'
331 ' (1004, 1004),\n'
334 ' (1005, 1005),\n'
332 ' (1005, 1005),\n'
335 ' (1006, 1006),\n'
333 ' (1006, 1006),\n'
336 ' (1007, 1007),\n'
334 ' (1007, 1007),\n'
337 ' (1008, 1008),\n'
335 ' (1008, 1008),\n'
338 ' (1009, 1009)])'),
336 ' (1009, 1009)])'),
339 (a, "OrderedDict([('key', OrderedDict(...))])"),
337 (a, "OrderedDict([('key', OrderedDict(...))])"),
340 ]
338 ]
341 for obj, expected in cases:
339 for obj, expected in cases:
342 assert pretty.pretty(obj) == expected
340 assert pretty.pretty(obj) == expected
343
341
344
342
345 # TODO : pytest.mark.parametrise once nose is gone.
343 # TODO : pytest.mark.parametrise once nose is gone.
346 def test_collections_deque():
344 def test_collections_deque():
347 # Create deque with cycle
345 # Create deque with cycle
348 a = deque()
346 a = deque()
349 a.append(a)
347 a.append(a)
350
348
351 cases = [
349 cases = [
352 (deque(), 'deque([])'),
350 (deque(), 'deque([])'),
353 (deque(i for i in range(1000, 1020)),
351 (deque(i for i in range(1000, 1020)),
354 'deque([1000,\n'
352 'deque([1000,\n'
355 ' 1001,\n'
353 ' 1001,\n'
356 ' 1002,\n'
354 ' 1002,\n'
357 ' 1003,\n'
355 ' 1003,\n'
358 ' 1004,\n'
356 ' 1004,\n'
359 ' 1005,\n'
357 ' 1005,\n'
360 ' 1006,\n'
358 ' 1006,\n'
361 ' 1007,\n'
359 ' 1007,\n'
362 ' 1008,\n'
360 ' 1008,\n'
363 ' 1009,\n'
361 ' 1009,\n'
364 ' 1010,\n'
362 ' 1010,\n'
365 ' 1011,\n'
363 ' 1011,\n'
366 ' 1012,\n'
364 ' 1012,\n'
367 ' 1013,\n'
365 ' 1013,\n'
368 ' 1014,\n'
366 ' 1014,\n'
369 ' 1015,\n'
367 ' 1015,\n'
370 ' 1016,\n'
368 ' 1016,\n'
371 ' 1017,\n'
369 ' 1017,\n'
372 ' 1018,\n'
370 ' 1018,\n'
373 ' 1019])'),
371 ' 1019])'),
374 (a, 'deque([deque(...)])'),
372 (a, 'deque([deque(...)])'),
375 ]
373 ]
376 for obj, expected in cases:
374 for obj, expected in cases:
377 assert pretty.pretty(obj) == expected
375 assert pretty.pretty(obj) == expected
378
376
379
377
380 # TODO : pytest.mark.parametrise once nose is gone.
378 # TODO : pytest.mark.parametrise once nose is gone.
381 def test_collections_counter():
379 def test_collections_counter():
382 class MyCounter(Counter):
380 class MyCounter(Counter):
383 pass
381 pass
384 cases = [
382 cases = [
385 (Counter(), 'Counter()'),
383 (Counter(), 'Counter()'),
386 (Counter(a=1), "Counter({'a': 1})"),
384 (Counter(a=1), "Counter({'a': 1})"),
387 (MyCounter(a=1), "MyCounter({'a': 1})"),
385 (MyCounter(a=1), "MyCounter({'a': 1})"),
388 ]
386 ]
389 for obj, expected in cases:
387 for obj, expected in cases:
390 assert pretty.pretty(obj) == expected
388 assert pretty.pretty(obj) == expected
391
389
392 # TODO : pytest.mark.parametrise once nose is gone.
390 # TODO : pytest.mark.parametrise once nose is gone.
393 def test_mappingproxy():
391 def test_mappingproxy():
394 MP = types.MappingProxyType
392 MP = types.MappingProxyType
395 underlying_dict = {}
393 underlying_dict = {}
396 mp_recursive = MP(underlying_dict)
394 mp_recursive = MP(underlying_dict)
397 underlying_dict[2] = mp_recursive
395 underlying_dict[2] = mp_recursive
398 underlying_dict[3] = underlying_dict
396 underlying_dict[3] = underlying_dict
399
397
400 cases = [
398 cases = [
401 (MP({}), "mappingproxy({})"),
399 (MP({}), "mappingproxy({})"),
402 (MP({None: MP({})}), "mappingproxy({None: mappingproxy({})})"),
400 (MP({None: MP({})}), "mappingproxy({None: mappingproxy({})})"),
403 (MP({k: k.upper() for k in string.ascii_lowercase}),
401 (MP({k: k.upper() for k in string.ascii_lowercase}),
404 "mappingproxy({'a': 'A',\n"
402 "mappingproxy({'a': 'A',\n"
405 " 'b': 'B',\n"
403 " 'b': 'B',\n"
406 " 'c': 'C',\n"
404 " 'c': 'C',\n"
407 " 'd': 'D',\n"
405 " 'd': 'D',\n"
408 " 'e': 'E',\n"
406 " 'e': 'E',\n"
409 " 'f': 'F',\n"
407 " 'f': 'F',\n"
410 " 'g': 'G',\n"
408 " 'g': 'G',\n"
411 " 'h': 'H',\n"
409 " 'h': 'H',\n"
412 " 'i': 'I',\n"
410 " 'i': 'I',\n"
413 " 'j': 'J',\n"
411 " 'j': 'J',\n"
414 " 'k': 'K',\n"
412 " 'k': 'K',\n"
415 " 'l': 'L',\n"
413 " 'l': 'L',\n"
416 " 'm': 'M',\n"
414 " 'm': 'M',\n"
417 " 'n': 'N',\n"
415 " 'n': 'N',\n"
418 " 'o': 'O',\n"
416 " 'o': 'O',\n"
419 " 'p': 'P',\n"
417 " 'p': 'P',\n"
420 " 'q': 'Q',\n"
418 " 'q': 'Q',\n"
421 " 'r': 'R',\n"
419 " 'r': 'R',\n"
422 " 's': 'S',\n"
420 " 's': 'S',\n"
423 " 't': 'T',\n"
421 " 't': 'T',\n"
424 " 'u': 'U',\n"
422 " 'u': 'U',\n"
425 " 'v': 'V',\n"
423 " 'v': 'V',\n"
426 " 'w': 'W',\n"
424 " 'w': 'W',\n"
427 " 'x': 'X',\n"
425 " 'x': 'X',\n"
428 " 'y': 'Y',\n"
426 " 'y': 'Y',\n"
429 " 'z': 'Z'})"),
427 " 'z': 'Z'})"),
430 (mp_recursive, "mappingproxy({2: {...}, 3: {2: {...}, 3: {...}}})"),
428 (mp_recursive, "mappingproxy({2: {...}, 3: {2: {...}, 3: {...}}})"),
431 (underlying_dict,
429 (underlying_dict,
432 "{2: mappingproxy({2: {...}, 3: {...}}), 3: {...}}"),
430 "{2: mappingproxy({2: {...}, 3: {...}}), 3: {...}}"),
433 ]
431 ]
434 for obj, expected in cases:
432 for obj, expected in cases:
435 assert pretty.pretty(obj) == expected
433 assert pretty.pretty(obj) == expected
436
434
437
435
438 # TODO : pytest.mark.parametrise once nose is gone.
436 # TODO : pytest.mark.parametrise once nose is gone.
439 def test_simplenamespace():
437 def test_simplenamespace():
440 SN = types.SimpleNamespace
438 SN = types.SimpleNamespace
441
439
442 sn_recursive = SN()
440 sn_recursive = SN()
443 sn_recursive.first = sn_recursive
441 sn_recursive.first = sn_recursive
444 sn_recursive.second = sn_recursive
442 sn_recursive.second = sn_recursive
445 cases = [
443 cases = [
446 (SN(), "namespace()"),
444 (SN(), "namespace()"),
447 (SN(x=SN()), "namespace(x=namespace())"),
445 (SN(x=SN()), "namespace(x=namespace())"),
448 (SN(a_long_name=[SN(s=string.ascii_lowercase)]*3, a_short_name=None),
446 (SN(a_long_name=[SN(s=string.ascii_lowercase)]*3, a_short_name=None),
449 "namespace(a_long_name=[namespace(s='abcdefghijklmnopqrstuvwxyz'),\n"
447 "namespace(a_long_name=[namespace(s='abcdefghijklmnopqrstuvwxyz'),\n"
450 " namespace(s='abcdefghijklmnopqrstuvwxyz'),\n"
448 " namespace(s='abcdefghijklmnopqrstuvwxyz'),\n"
451 " namespace(s='abcdefghijklmnopqrstuvwxyz')],\n"
449 " namespace(s='abcdefghijklmnopqrstuvwxyz')],\n"
452 " a_short_name=None)"),
450 " a_short_name=None)"),
453 (sn_recursive, "namespace(first=namespace(...), second=namespace(...))"),
451 (sn_recursive, "namespace(first=namespace(...), second=namespace(...))"),
454 ]
452 ]
455 for obj, expected in cases:
453 for obj, expected in cases:
456 assert pretty.pretty(obj) == expected
454 assert pretty.pretty(obj) == expected
457
455
458
456
459 def test_pretty_environ():
457 def test_pretty_environ():
460 dict_repr = pretty.pretty(dict(os.environ))
458 dict_repr = pretty.pretty(dict(os.environ))
461 # reindent to align with 'environ' prefix
459 # reindent to align with 'environ' prefix
462 dict_indented = dict_repr.replace('\n', '\n' + (' ' * len('environ')))
460 dict_indented = dict_repr.replace('\n', '\n' + (' ' * len('environ')))
463 env_repr = pretty.pretty(os.environ)
461 env_repr = pretty.pretty(os.environ)
464 assert env_repr == "environ" + dict_indented
462 assert env_repr == "environ" + dict_indented
465
463
466
464
467 def test_function_pretty():
465 def test_function_pretty():
468 "Test pretty print of function"
466 "Test pretty print of function"
469 # posixpath is a pure python module, its interface is consistent
467 # posixpath is a pure python module, its interface is consistent
470 # across Python distributions
468 # across Python distributions
471 import posixpath
469 import posixpath
472
470
473 assert pretty.pretty(posixpath.join) == "<function posixpath.join(a, *p)>"
471 assert pretty.pretty(posixpath.join) == "<function posixpath.join(a, *p)>"
474
472
475 # custom function
473 # custom function
476 def meaning_of_life(question=None):
474 def meaning_of_life(question=None):
477 if question:
475 if question:
478 return 42
476 return 42
479 return "Don't panic"
477 return "Don't panic"
480
478
481 nt.assert_in('meaning_of_life(question=None)', pretty.pretty(meaning_of_life))
479 assert "meaning_of_life(question=None)" in pretty.pretty(meaning_of_life)
482
480
483
481
484 class OrderedCounter(Counter, OrderedDict):
482 class OrderedCounter(Counter, OrderedDict):
485 'Counter that remembers the order elements are first encountered'
483 'Counter that remembers the order elements are first encountered'
486
484
487 def __repr__(self):
485 def __repr__(self):
488 return '%s(%r)' % (self.__class__.__name__, OrderedDict(self))
486 return '%s(%r)' % (self.__class__.__name__, OrderedDict(self))
489
487
490 def __reduce__(self):
488 def __reduce__(self):
491 return self.__class__, (OrderedDict(self),)
489 return self.__class__, (OrderedDict(self),)
492
490
493 class MySet(set): # Override repr of a basic type
491 class MySet(set): # Override repr of a basic type
494 def __repr__(self):
492 def __repr__(self):
495 return 'mine'
493 return 'mine'
496
494
497 def test_custom_repr():
495 def test_custom_repr():
498 """A custom repr should override a pretty printer for a parent type"""
496 """A custom repr should override a pretty printer for a parent type"""
499 oc = OrderedCounter("abracadabra")
497 oc = OrderedCounter("abracadabra")
500 nt.assert_in("OrderedCounter(OrderedDict", pretty.pretty(oc))
498 assert "OrderedCounter(OrderedDict" in pretty.pretty(oc)
501
499
502 assert pretty.pretty(MySet()) == "mine"
500 assert pretty.pretty(MySet()) == "mine"
@@ -1,136 +1,137 b''
1 """Test embedding of IPython"""
1 """Test embedding of IPython"""
2
2
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (C) 2013 The IPython Development Team
4 # Copyright (C) 2013 The IPython Development Team
5 #
5 #
6 # Distributed under the terms of the BSD License. The full license is in
6 # Distributed under the terms of the BSD License. The full license is in
7 # the file COPYING, distributed as part of this software.
7 # the file COPYING, distributed as part of this software.
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Imports
11 # Imports
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 import os
14 import os
15 import subprocess
15 import subprocess
16 import sys
16 import sys
17 import nose.tools as nt
17
18 from IPython.utils.tempdir import NamedFileInTemporaryDirectory
18 from IPython.utils.tempdir import NamedFileInTemporaryDirectory
19 from IPython.testing.decorators import skip_win32
19 from IPython.testing.decorators import skip_win32
20 from IPython.testing import IPYTHON_TESTING_TIMEOUT_SCALE
20 from IPython.testing import IPYTHON_TESTING_TIMEOUT_SCALE
21
21
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 # Tests
23 # Tests
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26
26
27 _sample_embed = b"""
27 _sample_embed = b"""
28 import IPython
28 import IPython
29
29
30 a = 3
30 a = 3
31 b = 14
31 b = 14
32 print(a, '.', b)
32 print(a, '.', b)
33
33
34 IPython.embed()
34 IPython.embed()
35
35
36 print('bye!')
36 print('bye!')
37 """
37 """
38
38
39 _exit = b"exit\r"
39 _exit = b"exit\r"
40
40
41 def test_ipython_embed():
41 def test_ipython_embed():
42 """test that `IPython.embed()` works"""
42 """test that `IPython.embed()` works"""
43 with NamedFileInTemporaryDirectory('file_with_embed.py') as f:
43 with NamedFileInTemporaryDirectory('file_with_embed.py') as f:
44 f.write(_sample_embed)
44 f.write(_sample_embed)
45 f.flush()
45 f.flush()
46 f.close() # otherwise msft won't be able to read the file
46 f.close() # otherwise msft won't be able to read the file
47
47
48 # run `python file_with_embed.py`
48 # run `python file_with_embed.py`
49 cmd = [sys.executable, f.name]
49 cmd = [sys.executable, f.name]
50 env = os.environ.copy()
50 env = os.environ.copy()
51 env['IPY_TEST_SIMPLE_PROMPT'] = '1'
51 env['IPY_TEST_SIMPLE_PROMPT'] = '1'
52
52
53 p = subprocess.Popen(cmd, env=env, stdin=subprocess.PIPE,
53 p = subprocess.Popen(cmd, env=env, stdin=subprocess.PIPE,
54 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
54 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
55 out, err = p.communicate(_exit)
55 out, err = p.communicate(_exit)
56 std = out.decode('UTF-8')
56 std = out.decode('UTF-8')
57
57
58 nt.assert_equal(p.returncode, 0)
58 assert p.returncode == 0
59 nt.assert_in('3 . 14', std)
59 assert "3 . 14" in std
60 if os.name != 'nt':
60 if os.name != "nt":
61 # TODO: Fix up our different stdout references, see issue gh-14
61 # TODO: Fix up our different stdout references, see issue gh-14
62 nt.assert_in('IPython', std)
62 assert "IPython" in std
63 nt.assert_in('bye!', std)
63 assert "bye!" in std
64
64
65
65 @skip_win32
66 @skip_win32
66 def test_nest_embed():
67 def test_nest_embed():
67 """test that `IPython.embed()` is nestable"""
68 """test that `IPython.embed()` is nestable"""
68 import pexpect
69 import pexpect
69 ipy_prompt = r']:' #ansi color codes give problems matching beyond this
70 ipy_prompt = r']:' #ansi color codes give problems matching beyond this
70 env = os.environ.copy()
71 env = os.environ.copy()
71 env['IPY_TEST_SIMPLE_PROMPT'] = '1'
72 env['IPY_TEST_SIMPLE_PROMPT'] = '1'
72
73
73
74
74 child = pexpect.spawn(sys.executable, ['-m', 'IPython', '--colors=nocolor'],
75 child = pexpect.spawn(sys.executable, ['-m', 'IPython', '--colors=nocolor'],
75 env=env)
76 env=env)
76 child.timeout = 5 * IPYTHON_TESTING_TIMEOUT_SCALE
77 child.timeout = 5 * IPYTHON_TESTING_TIMEOUT_SCALE
77 child.expect(ipy_prompt)
78 child.expect(ipy_prompt)
78 child.sendline("import IPython")
79 child.sendline("import IPython")
79 child.expect(ipy_prompt)
80 child.expect(ipy_prompt)
80 child.sendline("ip0 = get_ipython()")
81 child.sendline("ip0 = get_ipython()")
81 #enter first nested embed
82 #enter first nested embed
82 child.sendline("IPython.embed()")
83 child.sendline("IPython.embed()")
83 #skip the banner until we get to a prompt
84 #skip the banner until we get to a prompt
84 try:
85 try:
85 prompted = -1
86 prompted = -1
86 while prompted != 0:
87 while prompted != 0:
87 prompted = child.expect([ipy_prompt, '\r\n'])
88 prompted = child.expect([ipy_prompt, '\r\n'])
88 except pexpect.TIMEOUT as e:
89 except pexpect.TIMEOUT as e:
89 print(e)
90 print(e)
90 #child.interact()
91 #child.interact()
91 child.sendline("embed1 = get_ipython()")
92 child.sendline("embed1 = get_ipython()")
92 child.expect(ipy_prompt)
93 child.expect(ipy_prompt)
93 child.sendline("print('true' if embed1 is not ip0 else 'false')")
94 child.sendline("print('true' if embed1 is not ip0 else 'false')")
94 assert(child.expect(['true\r\n', 'false\r\n']) == 0)
95 assert(child.expect(['true\r\n', 'false\r\n']) == 0)
95 child.expect(ipy_prompt)
96 child.expect(ipy_prompt)
96 child.sendline("print('true' if IPython.get_ipython() is embed1 else 'false')")
97 child.sendline("print('true' if IPython.get_ipython() is embed1 else 'false')")
97 assert(child.expect(['true\r\n', 'false\r\n']) == 0)
98 assert(child.expect(['true\r\n', 'false\r\n']) == 0)
98 child.expect(ipy_prompt)
99 child.expect(ipy_prompt)
99 #enter second nested embed
100 #enter second nested embed
100 child.sendline("IPython.embed()")
101 child.sendline("IPython.embed()")
101 #skip the banner until we get to a prompt
102 #skip the banner until we get to a prompt
102 try:
103 try:
103 prompted = -1
104 prompted = -1
104 while prompted != 0:
105 while prompted != 0:
105 prompted = child.expect([ipy_prompt, '\r\n'])
106 prompted = child.expect([ipy_prompt, '\r\n'])
106 except pexpect.TIMEOUT as e:
107 except pexpect.TIMEOUT as e:
107 print(e)
108 print(e)
108 #child.interact()
109 #child.interact()
109 child.sendline("embed2 = get_ipython()")
110 child.sendline("embed2 = get_ipython()")
110 child.expect(ipy_prompt)
111 child.expect(ipy_prompt)
111 child.sendline("print('true' if embed2 is not embed1 else 'false')")
112 child.sendline("print('true' if embed2 is not embed1 else 'false')")
112 assert(child.expect(['true\r\n', 'false\r\n']) == 0)
113 assert(child.expect(['true\r\n', 'false\r\n']) == 0)
113 child.expect(ipy_prompt)
114 child.expect(ipy_prompt)
114 child.sendline("print('true' if embed2 is IPython.get_ipython() else 'false')")
115 child.sendline("print('true' if embed2 is IPython.get_ipython() else 'false')")
115 assert(child.expect(['true\r\n', 'false\r\n']) == 0)
116 assert(child.expect(['true\r\n', 'false\r\n']) == 0)
116 child.expect(ipy_prompt)
117 child.expect(ipy_prompt)
117 child.sendline('exit')
118 child.sendline('exit')
118 #back at first embed
119 #back at first embed
119 child.expect(ipy_prompt)
120 child.expect(ipy_prompt)
120 child.sendline("print('true' if get_ipython() is embed1 else 'false')")
121 child.sendline("print('true' if get_ipython() is embed1 else 'false')")
121 assert(child.expect(['true\r\n', 'false\r\n']) == 0)
122 assert(child.expect(['true\r\n', 'false\r\n']) == 0)
122 child.expect(ipy_prompt)
123 child.expect(ipy_prompt)
123 child.sendline("print('true' if IPython.get_ipython() is embed1 else 'false')")
124 child.sendline("print('true' if IPython.get_ipython() is embed1 else 'false')")
124 assert(child.expect(['true\r\n', 'false\r\n']) == 0)
125 assert(child.expect(['true\r\n', 'false\r\n']) == 0)
125 child.expect(ipy_prompt)
126 child.expect(ipy_prompt)
126 child.sendline('exit')
127 child.sendline('exit')
127 #back at launching scope
128 #back at launching scope
128 child.expect(ipy_prompt)
129 child.expect(ipy_prompt)
129 child.sendline("print('true' if get_ipython() is ip0 else 'false')")
130 child.sendline("print('true' if get_ipython() is ip0 else 'false')")
130 assert(child.expect(['true\r\n', 'false\r\n']) == 0)
131 assert(child.expect(['true\r\n', 'false\r\n']) == 0)
131 child.expect(ipy_prompt)
132 child.expect(ipy_prompt)
132 child.sendline("print('true' if IPython.get_ipython() is ip0 else 'false')")
133 child.sendline("print('true' if IPython.get_ipython() is ip0 else 'false')")
133 assert(child.expect(['true\r\n', 'false\r\n']) == 0)
134 assert(child.expect(['true\r\n', 'false\r\n']) == 0)
134 child.expect(ipy_prompt)
135 child.expect(ipy_prompt)
135 child.sendline('exit')
136 child.sendline('exit')
136 child.close()
137 child.close()
@@ -1,193 +1,225 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for the TerminalInteractiveShell and related pieces."""
2 """Tests for the TerminalInteractiveShell and related pieces."""
3 # Copyright (c) IPython Development Team.
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5
5
6 import sys
6 import sys
7 import unittest
7 import unittest
8 import os
8 import os
9
9
10 from IPython.core.inputtransformer import InputTransformer
10 from IPython.core.inputtransformer import InputTransformer
11 from IPython.testing import tools as tt
11 from IPython.testing import tools as tt
12 from IPython.utils.capture import capture_output
12 from IPython.utils.capture import capture_output
13
13
14 from IPython.terminal.ptutils import _elide, _adjust_completion_text_based_on_context
14 from IPython.terminal.ptutils import _elide, _adjust_completion_text_based_on_context
15 import nose.tools as nt
16
15
17 class TestElide(unittest.TestCase):
18
16
17 class TestElide(unittest.TestCase):
19 def test_elide(self):
18 def test_elide(self):
20 _elide('concatenate((a1, a2, ...), axis', '') # do not raise
19 _elide("concatenate((a1, a2, ...), axis", "") # do not raise
21 _elide('concatenate((a1, a2, ..), . axis', '') # do not raise
20 _elide("concatenate((a1, a2, ..), . axis", "") # do not raise
22 nt.assert_equal(_elide('aaaa.bbbb.ccccc.dddddd.eeeee.fffff.gggggg.hhhhhh',''), 'aaaa.b…g.hhhhhh')
21 self.assertEqual(
23
22 _elide("aaaa.bbbb.ccccc.dddddd.eeeee.fffff.gggggg.hhhhhh", ""),
24 test_string = os.sep.join(['', 10*'a', 10*'b', 10*'c', ''])
23 "aaaa.b…g.hhhhhh",
25 expect_stirng = os.sep + 'a' + '\N{HORIZONTAL ELLIPSIS}' + 'b' + os.sep + 10*'c'
24 )
26 nt.assert_equal(_elide(test_string, ''), expect_stirng)
25
26 test_string = os.sep.join(["", 10 * "a", 10 * "b", 10 * "c", ""])
27 expect_stirng = (
28 os.sep + "a" + "\N{HORIZONTAL ELLIPSIS}" + "b" + os.sep + 10 * "c"
29 )
30 self.assertEqual(_elide(test_string, ""), expect_stirng)
27
31
28 def test_elide_typed_normal(self):
32 def test_elide_typed_normal(self):
29 nt.assert_equal(_elide('the quick brown fox jumped over the lazy dog', 'the quick brown fox', min_elide=10), 'the…fox jumped over the lazy dog')
33 self.assertEqual(
30
34 _elide(
35 "the quick brown fox jumped over the lazy dog",
36 "the quick brown fox",
37 min_elide=10,
38 ),
39 "the…fox jumped over the lazy dog",
40 )
31
41
32 def test_elide_typed_short_match(self):
42 def test_elide_typed_short_match(self):
33 """
43 """
34 if the match is too short we don't elide.
44 if the match is too short we don't elide.
35 avoid the "the...the"
45 avoid the "the...the"
36 """
46 """
37 nt.assert_equal(_elide('the quick brown fox jumped over the lazy dog', 'the', min_elide=10), 'the quick brown fox jumped over the lazy dog')
47 self.assertEqual(
48 _elide("the quick brown fox jumped over the lazy dog", "the", min_elide=10),
49 "the quick brown fox jumped over the lazy dog",
50 )
38
51
39 def test_elide_typed_no_match(self):
52 def test_elide_typed_no_match(self):
40 """
53 """
41 if the match is too short we don't elide.
54 if the match is too short we don't elide.
42 avoid the "the...the"
55 avoid the "the...the"
43 """
56 """
44 # here we typed red instead of brown
57 # here we typed red instead of brown
45 nt.assert_equal(_elide('the quick brown fox jumped over the lazy dog', 'the quick red fox', min_elide=10), 'the quick brown fox jumped over the lazy dog')
58 self.assertEqual(
59 _elide(
60 "the quick brown fox jumped over the lazy dog",
61 "the quick red fox",
62 min_elide=10,
63 ),
64 "the quick brown fox jumped over the lazy dog",
65 )
46
66
47 class TestContextAwareCompletion(unittest.TestCase):
48
67
68 class TestContextAwareCompletion(unittest.TestCase):
49 def test_adjust_completion_text_based_on_context(self):
69 def test_adjust_completion_text_based_on_context(self):
50 # Adjusted case
70 # Adjusted case
51 nt.assert_equal(_adjust_completion_text_based_on_context('arg1=', 'func1(a=)', 7), 'arg1')
71 self.assertEqual(
72 _adjust_completion_text_based_on_context("arg1=", "func1(a=)", 7), "arg1"
73 )
52
74
53 # Untouched cases
75 # Untouched cases
54 nt.assert_equal(_adjust_completion_text_based_on_context('arg1=', 'func1(a)', 7), 'arg1=')
76 self.assertEqual(
55 nt.assert_equal(_adjust_completion_text_based_on_context('arg1=', 'func1(a', 7), 'arg1=')
77 _adjust_completion_text_based_on_context("arg1=", "func1(a)", 7), "arg1="
56 nt.assert_equal(_adjust_completion_text_based_on_context('%magic', 'func1(a=)', 7), '%magic')
78 )
57 nt.assert_equal(_adjust_completion_text_based_on_context('func2', 'func1(a=)', 7), 'func2')
79 self.assertEqual(
80 _adjust_completion_text_based_on_context("arg1=", "func1(a", 7), "arg1="
81 )
82 self.assertEqual(
83 _adjust_completion_text_based_on_context("%magic", "func1(a=)", 7), "%magic"
84 )
85 self.assertEqual(
86 _adjust_completion_text_based_on_context("func2", "func1(a=)", 7), "func2"
87 )
88
58
89
59 # Decorator for interaction loop tests -----------------------------------------
90 # Decorator for interaction loop tests -----------------------------------------
60
91
92
61 class mock_input_helper(object):
93 class mock_input_helper(object):
62 """Machinery for tests of the main interact loop.
94 """Machinery for tests of the main interact loop.
63
95
64 Used by the mock_input decorator.
96 Used by the mock_input decorator.
65 """
97 """
66 def __init__(self, testgen):
98 def __init__(self, testgen):
67 self.testgen = testgen
99 self.testgen = testgen
68 self.exception = None
100 self.exception = None
69 self.ip = get_ipython()
101 self.ip = get_ipython()
70
102
71 def __enter__(self):
103 def __enter__(self):
72 self.orig_prompt_for_code = self.ip.prompt_for_code
104 self.orig_prompt_for_code = self.ip.prompt_for_code
73 self.ip.prompt_for_code = self.fake_input
105 self.ip.prompt_for_code = self.fake_input
74 return self
106 return self
75
107
76 def __exit__(self, etype, value, tb):
108 def __exit__(self, etype, value, tb):
77 self.ip.prompt_for_code = self.orig_prompt_for_code
109 self.ip.prompt_for_code = self.orig_prompt_for_code
78
110
79 def fake_input(self):
111 def fake_input(self):
80 try:
112 try:
81 return next(self.testgen)
113 return next(self.testgen)
82 except StopIteration:
114 except StopIteration:
83 self.ip.keep_running = False
115 self.ip.keep_running = False
84 return u''
116 return u''
85 except:
117 except:
86 self.exception = sys.exc_info()
118 self.exception = sys.exc_info()
87 self.ip.keep_running = False
119 self.ip.keep_running = False
88 return u''
120 return u''
89
121
90 def mock_input(testfunc):
122 def mock_input(testfunc):
91 """Decorator for tests of the main interact loop.
123 """Decorator for tests of the main interact loop.
92
124
93 Write the test as a generator, yield-ing the input strings, which IPython
125 Write the test as a generator, yield-ing the input strings, which IPython
94 will see as if they were typed in at the prompt.
126 will see as if they were typed in at the prompt.
95 """
127 """
96 def test_method(self):
128 def test_method(self):
97 testgen = testfunc(self)
129 testgen = testfunc(self)
98 with mock_input_helper(testgen) as mih:
130 with mock_input_helper(testgen) as mih:
99 mih.ip.interact()
131 mih.ip.interact()
100
132
101 if mih.exception is not None:
133 if mih.exception is not None:
102 # Re-raise captured exception
134 # Re-raise captured exception
103 etype, value, tb = mih.exception
135 etype, value, tb = mih.exception
104 import traceback
136 import traceback
105 traceback.print_tb(tb, file=sys.stdout)
137 traceback.print_tb(tb, file=sys.stdout)
106 del tb # Avoid reference loop
138 del tb # Avoid reference loop
107 raise value
139 raise value
108
140
109 return test_method
141 return test_method
110
142
111 # Test classes -----------------------------------------------------------------
143 # Test classes -----------------------------------------------------------------
112
144
113 class InteractiveShellTestCase(unittest.TestCase):
145 class InteractiveShellTestCase(unittest.TestCase):
114 def rl_hist_entries(self, rl, n):
146 def rl_hist_entries(self, rl, n):
115 """Get last n readline history entries as a list"""
147 """Get last n readline history entries as a list"""
116 return [rl.get_history_item(rl.get_current_history_length() - x)
148 return [rl.get_history_item(rl.get_current_history_length() - x)
117 for x in range(n - 1, -1, -1)]
149 for x in range(n - 1, -1, -1)]
118
150
119 @mock_input
151 @mock_input
120 def test_inputtransformer_syntaxerror(self):
152 def test_inputtransformer_syntaxerror(self):
121 ip = get_ipython()
153 ip = get_ipython()
122 ip.input_transformers_post.append(syntax_error_transformer)
154 ip.input_transformers_post.append(syntax_error_transformer)
123
155
124 try:
156 try:
125 #raise Exception
157 #raise Exception
126 with tt.AssertPrints('4', suppress=False):
158 with tt.AssertPrints('4', suppress=False):
127 yield u'print(2*2)'
159 yield u'print(2*2)'
128
160
129 with tt.AssertPrints('SyntaxError: input contains', suppress=False):
161 with tt.AssertPrints('SyntaxError: input contains', suppress=False):
130 yield u'print(2345) # syntaxerror'
162 yield u'print(2345) # syntaxerror'
131
163
132 with tt.AssertPrints('16', suppress=False):
164 with tt.AssertPrints('16', suppress=False):
133 yield u'print(4*4)'
165 yield u'print(4*4)'
134
166
135 finally:
167 finally:
136 ip.input_transformers_post.remove(syntax_error_transformer)
168 ip.input_transformers_post.remove(syntax_error_transformer)
137
169
138 def test_plain_text_only(self):
170 def test_plain_text_only(self):
139 ip = get_ipython()
171 ip = get_ipython()
140 formatter = ip.display_formatter
172 formatter = ip.display_formatter
141 assert formatter.active_types == ['text/plain']
173 assert formatter.active_types == ['text/plain']
142 assert not formatter.ipython_display_formatter.enabled
174 assert not formatter.ipython_display_formatter.enabled
143
175
144 class Test(object):
176 class Test(object):
145 def __repr__(self):
177 def __repr__(self):
146 return "<Test %i>" % id(self)
178 return "<Test %i>" % id(self)
147
179
148 def _repr_html_(self):
180 def _repr_html_(self):
149 return '<html>'
181 return '<html>'
150
182
151 # verify that HTML repr isn't computed
183 # verify that HTML repr isn't computed
152 obj = Test()
184 obj = Test()
153 data, _ = formatter.format(obj)
185 data, _ = formatter.format(obj)
154 self.assertEqual(data, {'text/plain': repr(obj)})
186 self.assertEqual(data, {'text/plain': repr(obj)})
155
187
156 class Test2(Test):
188 class Test2(Test):
157 def _ipython_display_(self):
189 def _ipython_display_(self):
158 from IPython.display import display
190 from IPython.display import display
159 display('<custom>')
191 display('<custom>')
160
192
161 # verify that _ipython_display_ shortcut isn't called
193 # verify that _ipython_display_ shortcut isn't called
162 obj = Test2()
194 obj = Test2()
163 with capture_output() as captured:
195 with capture_output() as captured:
164 data, _ = formatter.format(obj)
196 data, _ = formatter.format(obj)
165
197
166 self.assertEqual(data, {'text/plain': repr(obj)})
198 self.assertEqual(data, {'text/plain': repr(obj)})
167 assert captured.stdout == ''
199 assert captured.stdout == ''
168
200
169 def syntax_error_transformer(lines):
201 def syntax_error_transformer(lines):
170 """Transformer that throws SyntaxError if 'syntaxerror' is in the code."""
202 """Transformer that throws SyntaxError if 'syntaxerror' is in the code."""
171 for line in lines:
203 for line in lines:
172 pos = line.find('syntaxerror')
204 pos = line.find('syntaxerror')
173 if pos >= 0:
205 if pos >= 0:
174 e = SyntaxError('input contains "syntaxerror"')
206 e = SyntaxError('input contains "syntaxerror"')
175 e.text = line
207 e.text = line
176 e.offset = pos + 1
208 e.offset = pos + 1
177 raise e
209 raise e
178 return lines
210 return lines
179
211
180
212
181 class TerminalMagicsTestCase(unittest.TestCase):
213 class TerminalMagicsTestCase(unittest.TestCase):
182 def test_paste_magics_blankline(self):
214 def test_paste_magics_blankline(self):
183 """Test that code with a blank line doesn't get split (gh-3246)."""
215 """Test that code with a blank line doesn't get split (gh-3246)."""
184 ip = get_ipython()
216 ip = get_ipython()
185 s = ('def pasted_func(a):\n'
217 s = ('def pasted_func(a):\n'
186 ' b = a+1\n'
218 ' b = a+1\n'
187 '\n'
219 '\n'
188 ' return b')
220 ' return b')
189
221
190 tm = ip.magics_manager.registry['TerminalMagics']
222 tm = ip.magics_manager.registry['TerminalMagics']
191 tm.store_or_execute(s, name=None)
223 tm.store_or_execute(s, name=None)
192
224
193 self.assertEqual(ip.user_ns['pasted_func'](54), 55)
225 self.assertEqual(ip.user_ns['pasted_func'](54), 55)
@@ -1,168 +1,166 b''
1 """Tests for the decorators we've created for IPython.
1 """Tests for the decorators we've created for IPython.
2 """
2 """
3
3
4 # Module imports
4 # Module imports
5 # Std lib
5 # Std lib
6 import inspect
6 import inspect
7 import sys
7 import sys
8
8
9 # Third party
10 import nose.tools as nt
11
12 # Our own
9 # Our own
13 from IPython.testing import decorators as dec
10 from IPython.testing import decorators as dec
14 from IPython.testing.skipdoctest import skip_doctest
11 from IPython.testing.skipdoctest import skip_doctest
15
12
16 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
17 # Utilities
14 # Utilities
18
15
19 # Note: copied from OInspect, kept here so the testing stuff doesn't create
16 # Note: copied from OInspect, kept here so the testing stuff doesn't create
20 # circular dependencies and is easier to reuse.
17 # circular dependencies and is easier to reuse.
21 def getargspec(obj):
18 def getargspec(obj):
22 """Get the names and default values of a function's arguments.
19 """Get the names and default values of a function's arguments.
23
20
24 A tuple of four things is returned: (args, varargs, varkw, defaults).
21 A tuple of four things is returned: (args, varargs, varkw, defaults).
25 'args' is a list of the argument names (it may contain nested lists).
22 'args' is a list of the argument names (it may contain nested lists).
26 'varargs' and 'varkw' are the names of the * and ** arguments or None.
23 'varargs' and 'varkw' are the names of the * and ** arguments or None.
27 'defaults' is an n-tuple of the default values of the last n arguments.
24 'defaults' is an n-tuple of the default values of the last n arguments.
28
25
29 Modified version of inspect.getargspec from the Python Standard
26 Modified version of inspect.getargspec from the Python Standard
30 Library."""
27 Library."""
31
28
32 if inspect.isfunction(obj):
29 if inspect.isfunction(obj):
33 func_obj = obj
30 func_obj = obj
34 elif inspect.ismethod(obj):
31 elif inspect.ismethod(obj):
35 func_obj = obj.__func__
32 func_obj = obj.__func__
36 else:
33 else:
37 raise TypeError('arg is not a Python function')
34 raise TypeError('arg is not a Python function')
38 args, varargs, varkw = inspect.getargs(func_obj.__code__)
35 args, varargs, varkw = inspect.getargs(func_obj.__code__)
39 return args, varargs, varkw, func_obj.__defaults__
36 return args, varargs, varkw, func_obj.__defaults__
40
37
41 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
42 # Testing functions
39 # Testing functions
43
40
44 @dec.as_unittest
41 @dec.as_unittest
45 def trivial():
42 def trivial():
46 """A trivial test"""
43 """A trivial test"""
47 pass
44 pass
48
45
49
46
50 @dec.skip()
47 @dec.skip()
51 def test_deliberately_broken():
48 def test_deliberately_broken():
52 """A deliberately broken test - we want to skip this one."""
49 """A deliberately broken test - we want to skip this one."""
53 1/0
50 1/0
54
51
55 @dec.skip('Testing the skip decorator')
52 @dec.skip('Testing the skip decorator')
56 def test_deliberately_broken2():
53 def test_deliberately_broken2():
57 """Another deliberately broken test - we want to skip this one."""
54 """Another deliberately broken test - we want to skip this one."""
58 1/0
55 1/0
59
56
60
57
61 # Verify that we can correctly skip the doctest for a function at will, but
58 # Verify that we can correctly skip the doctest for a function at will, but
62 # that the docstring itself is NOT destroyed by the decorator.
59 # that the docstring itself is NOT destroyed by the decorator.
63 @skip_doctest
60 @skip_doctest
64 def doctest_bad(x,y=1,**k):
61 def doctest_bad(x,y=1,**k):
65 """A function whose doctest we need to skip.
62 """A function whose doctest we need to skip.
66
63
67 >>> 1+1
64 >>> 1+1
68 3
65 3
69 """
66 """
70 print('x:',x)
67 print('x:',x)
71 print('y:',y)
68 print('y:',y)
72 print('k:',k)
69 print('k:',k)
73
70
74
71
75 def call_doctest_bad():
72 def call_doctest_bad():
76 """Check that we can still call the decorated functions.
73 """Check that we can still call the decorated functions.
77
74
78 >>> doctest_bad(3,y=4)
75 >>> doctest_bad(3,y=4)
79 x: 3
76 x: 3
80 y: 4
77 y: 4
81 k: {}
78 k: {}
82 """
79 """
83 pass
80 pass
84
81
85
82
86 def test_skip_dt_decorator():
83 def test_skip_dt_decorator():
87 """Doctest-skipping decorator should preserve the docstring.
84 """Doctest-skipping decorator should preserve the docstring.
88 """
85 """
89 # Careful: 'check' must be a *verbatim* copy of the doctest_bad docstring!
86 # Careful: 'check' must be a *verbatim* copy of the doctest_bad docstring!
90 check = """A function whose doctest we need to skip.
87 check = """A function whose doctest we need to skip.
91
88
92 >>> 1+1
89 >>> 1+1
93 3
90 3
94 """
91 """
95 # Fetch the docstring from doctest_bad after decoration.
92 # Fetch the docstring from doctest_bad after decoration.
96 val = doctest_bad.__doc__
93 val = doctest_bad.__doc__
97
94
98 nt.assert_equal(check,val,"doctest_bad docstrings don't match")
95 assert check == val, "doctest_bad docstrings don't match"
99
96
100
97
101 # Doctest skipping should work for class methods too
98 # Doctest skipping should work for class methods too
102 class FooClass(object):
99 class FooClass(object):
103 """FooClass
100 """FooClass
104
101
105 Example:
102 Example:
106
103
107 >>> 1+1
104 >>> 1+1
108 2
105 2
109 """
106 """
110
107
111 @skip_doctest
108 @skip_doctest
112 def __init__(self,x):
109 def __init__(self,x):
113 """Make a FooClass.
110 """Make a FooClass.
114
111
115 Example:
112 Example:
116
113
117 >>> f = FooClass(3)
114 >>> f = FooClass(3)
118 junk
115 junk
119 """
116 """
120 print('Making a FooClass.')
117 print('Making a FooClass.')
121 self.x = x
118 self.x = x
122
119
123 @skip_doctest
120 @skip_doctest
124 def bar(self,y):
121 def bar(self,y):
125 """Example:
122 """Example:
126
123
127 >>> ff = FooClass(3)
124 >>> ff = FooClass(3)
128 >>> ff.bar(0)
125 >>> ff.bar(0)
129 boom!
126 boom!
130 >>> 1/0
127 >>> 1/0
131 bam!
128 bam!
132 """
129 """
133 return 1/y
130 return 1/y
134
131
135 def baz(self,y):
132 def baz(self,y):
136 """Example:
133 """Example:
137
134
138 >>> ff2 = FooClass(3)
135 >>> ff2 = FooClass(3)
139 Making a FooClass.
136 Making a FooClass.
140 >>> ff2.baz(3)
137 >>> ff2.baz(3)
141 True
138 True
142 """
139 """
143 return self.x==y
140 return self.x==y
144
141
145
142
146 def test_skip_dt_decorator2():
143 def test_skip_dt_decorator2():
147 """Doctest-skipping decorator should preserve function signature.
144 """Doctest-skipping decorator should preserve function signature.
148 """
145 """
149 # Hardcoded correct answer
146 # Hardcoded correct answer
150 dtargs = (['x', 'y'], None, 'k', (1,))
147 dtargs = (['x', 'y'], None, 'k', (1,))
151 # Introspect out the value
148 # Introspect out the value
152 dtargsr = getargspec(doctest_bad)
149 dtargsr = getargspec(doctest_bad)
153 assert dtargsr==dtargs, \
150 assert dtargsr==dtargs, \
154 "Incorrectly reconstructed args for doctest_bad: %s" % (dtargsr,)
151 "Incorrectly reconstructed args for doctest_bad: %s" % (dtargsr,)
155
152
156
153
157 @dec.skip_linux
154 @dec.skip_linux
158 def test_linux():
155 def test_linux():
159 nt.assert_false(sys.platform.startswith('linux'),"This test can't run under linux")
156 assert sys.platform.startswith("linux") is False, "This test can't run under linux"
157
160
158
161 @dec.skip_win32
159 @dec.skip_win32
162 def test_win32():
160 def test_win32():
163 nt.assert_not_equal(sys.platform,'win32',"This test can't run under windows")
161 assert sys.platform != "win32", "This test can't run under windows"
162
164
163
165 @dec.skip_osx
164 @dec.skip_osx
166 def test_osx():
165 def test_osx():
167 nt.assert_not_equal(sys.platform,'darwin',"This test can't run under osx")
166 assert sys.platform != "darwin", "This test can't run under osx"
168
@@ -1,135 +1,133 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Tests for testing.tools
3 Tests for testing.tools
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2011 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 import os
17 import os
18 import unittest
18 import unittest
19
19
20 import nose.tools as nt
21
22 from IPython.testing import decorators as dec
20 from IPython.testing import decorators as dec
23 from IPython.testing import tools as tt
21 from IPython.testing import tools as tt
24
22
25 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
26 # Tests
24 # Tests
27 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
28
26
29 @dec.skip_win32
27 @dec.skip_win32
30 def test_full_path_posix():
28 def test_full_path_posix():
31 spath = '/foo/bar.py'
29 spath = "/foo/bar.py"
32 result = tt.full_path(spath,['a.txt','b.txt'])
30 result = tt.full_path(spath, ["a.txt", "b.txt"])
33 nt.assert_equal(result, ['/foo/a.txt', '/foo/b.txt'])
31 assert result, ["/foo/a.txt" == "/foo/b.txt"]
34 spath = '/foo'
32 spath = "/foo"
35 result = tt.full_path(spath,['a.txt','b.txt'])
33 result = tt.full_path(spath, ["a.txt", "b.txt"])
36 nt.assert_equal(result, ['/a.txt', '/b.txt'])
34 assert result, ["/a.txt" == "/b.txt"]
37 result = tt.full_path(spath,'a.txt')
35 result = tt.full_path(spath, "a.txt")
38 nt.assert_equal(result, ['/a.txt'])
36 assert result == ["/a.txt"]
39
37
40
38
41 @dec.skip_if_not_win32
39 @dec.skip_if_not_win32
42 def test_full_path_win32():
40 def test_full_path_win32():
43 spath = 'c:\\foo\\bar.py'
41 spath = "c:\\foo\\bar.py"
44 result = tt.full_path(spath,['a.txt','b.txt'])
42 result = tt.full_path(spath, ["a.txt", "b.txt"])
45 nt.assert_equal(result, ['c:\\foo\\a.txt', 'c:\\foo\\b.txt'])
43 assert result, ["c:\\foo\\a.txt" == "c:\\foo\\b.txt"]
46 spath = 'c:\\foo'
44 spath = "c:\\foo"
47 result = tt.full_path(spath,['a.txt','b.txt'])
45 result = tt.full_path(spath, ["a.txt", "b.txt"])
48 nt.assert_equal(result, ['c:\\a.txt', 'c:\\b.txt'])
46 assert result, ["c:\\a.txt" == "c:\\b.txt"]
49 result = tt.full_path(spath,'a.txt')
47 result = tt.full_path(spath, "a.txt")
50 nt.assert_equal(result, ['c:\\a.txt'])
48 assert result == ["c:\\a.txt"]
51
49
52
50
53 def test_parser():
51 def test_parser():
54 err = ("FAILED (errors=1)", 1, 0)
52 err = ("FAILED (errors=1)", 1, 0)
55 fail = ("FAILED (failures=1)", 0, 1)
53 fail = ("FAILED (failures=1)", 0, 1)
56 both = ("FAILED (errors=1, failures=1)", 1, 1)
54 both = ("FAILED (errors=1, failures=1)", 1, 1)
57 for txt, nerr, nfail in [err, fail, both]:
55 for txt, nerr, nfail in [err, fail, both]:
58 nerr1, nfail1 = tt.parse_test_output(txt)
56 nerr1, nfail1 = tt.parse_test_output(txt)
59 nt.assert_equal(nerr, nerr1)
57 assert nerr == nerr1
60 nt.assert_equal(nfail, nfail1)
58 assert nfail == nfail1
61
59
62
60
63 def test_temp_pyfile():
61 def test_temp_pyfile():
64 src = 'pass\n'
62 src = 'pass\n'
65 fname = tt.temp_pyfile(src)
63 fname = tt.temp_pyfile(src)
66 assert os.path.isfile(fname)
64 assert os.path.isfile(fname)
67 with open(fname) as fh2:
65 with open(fname) as fh2:
68 src2 = fh2.read()
66 src2 = fh2.read()
69 nt.assert_equal(src2, src)
67 assert src2 == src
70
68
71 class TestAssertPrints(unittest.TestCase):
69 class TestAssertPrints(unittest.TestCase):
72 def test_passing(self):
70 def test_passing(self):
73 with tt.AssertPrints("abc"):
71 with tt.AssertPrints("abc"):
74 print("abcd")
72 print("abcd")
75 print("def")
73 print("def")
76 print(b"ghi")
74 print(b"ghi")
77
75
78 def test_failing(self):
76 def test_failing(self):
79 def func():
77 def func():
80 with tt.AssertPrints("abc"):
78 with tt.AssertPrints("abc"):
81 print("acd")
79 print("acd")
82 print("def")
80 print("def")
83 print(b"ghi")
81 print(b"ghi")
84
82
85 self.assertRaises(AssertionError, func)
83 self.assertRaises(AssertionError, func)
86
84
87
85
88 class Test_ipexec_validate(tt.TempFileMixin):
86 class Test_ipexec_validate(tt.TempFileMixin):
89 def test_main_path(self):
87 def test_main_path(self):
90 """Test with only stdout results.
88 """Test with only stdout results.
91 """
89 """
92 self.mktmp("print('A')\n"
90 self.mktmp("print('A')\n"
93 "print('B')\n"
91 "print('B')\n"
94 )
92 )
95 out = "A\nB"
93 out = "A\nB"
96 tt.ipexec_validate(self.fname, out)
94 tt.ipexec_validate(self.fname, out)
97
95
98 def test_main_path2(self):
96 def test_main_path2(self):
99 """Test with only stdout results, expecting windows line endings.
97 """Test with only stdout results, expecting windows line endings.
100 """
98 """
101 self.mktmp("print('A')\n"
99 self.mktmp("print('A')\n"
102 "print('B')\n"
100 "print('B')\n"
103 )
101 )
104 out = "A\r\nB"
102 out = "A\r\nB"
105 tt.ipexec_validate(self.fname, out)
103 tt.ipexec_validate(self.fname, out)
106
104
107 def test_exception_path(self):
105 def test_exception_path(self):
108 """Test exception path in exception_validate.
106 """Test exception path in exception_validate.
109 """
107 """
110 self.mktmp("import sys\n"
108 self.mktmp("import sys\n"
111 "print('A')\n"
109 "print('A')\n"
112 "print('B')\n"
110 "print('B')\n"
113 "print('C', file=sys.stderr)\n"
111 "print('C', file=sys.stderr)\n"
114 "print('D', file=sys.stderr)\n"
112 "print('D', file=sys.stderr)\n"
115 )
113 )
116 out = "A\nB"
114 out = "A\nB"
117 tt.ipexec_validate(self.fname, expected_out=out, expected_err="C\nD")
115 tt.ipexec_validate(self.fname, expected_out=out, expected_err="C\nD")
118
116
119 def test_exception_path2(self):
117 def test_exception_path2(self):
120 """Test exception path in exception_validate, expecting windows line endings.
118 """Test exception path in exception_validate, expecting windows line endings.
121 """
119 """
122 self.mktmp("import sys\n"
120 self.mktmp("import sys\n"
123 "print('A')\n"
121 "print('A')\n"
124 "print('B')\n"
122 "print('B')\n"
125 "print('C', file=sys.stderr)\n"
123 "print('C', file=sys.stderr)\n"
126 "print('D', file=sys.stderr)\n"
124 "print('D', file=sys.stderr)\n"
127 )
125 )
128 out = "A\r\nB"
126 out = "A\r\nB"
129 tt.ipexec_validate(self.fname, expected_out=out, expected_err="C\r\nD")
127 tt.ipexec_validate(self.fname, expected_out=out, expected_err="C\r\nD")
130
128
131
129
132 def tearDown(self):
130 def tearDown(self):
133 # tear down correctly the mixin,
131 # tear down correctly the mixin,
134 # unittest.TestCase.tearDown does nothing
132 # unittest.TestCase.tearDown does nothing
135 tt.TempFileMixin.tearDown(self)
133 tt.TempFileMixin.tearDown(self)
@@ -1,58 +1,67 b''
1 import nose.tools as nt
2 from IPython.utils.dir2 import dir2
1 from IPython.utils.dir2 import dir2
3
2
3 import pytest
4
4
5
5 class Base(object):
6 class Base(object):
6 x = 1
7 x = 1
7 z = 23
8 z = 23
8
9
9
10
10 def test_base():
11 def test_base():
11 res = dir2(Base())
12 res = dir2(Base())
12 assert ('x' in res)
13 assert "x" in res
13 assert ('z' in res)
14 assert "z" in res
14 assert ('y' not in res)
15 assert "y" not in res
15 assert ('__class__' in res)
16 assert "__class__" in res
16 nt.assert_equal(res.count('x'), 1)
17 assert res.count("x") == 1
17 nt.assert_equal(res.count('__class__'), 1)
18 assert res.count("__class__") == 1
19
18
20
19 def test_SubClass():
21 def test_SubClass():
20
22
21 class SubClass(Base):
23 class SubClass(Base):
22 y = 2
24 y = 2
23
25
24 res = dir2(SubClass())
26 res = dir2(SubClass())
25 assert ('y' in res)
27 assert "y" in res
26 nt.assert_equal(res.count('y'), 1)
28 assert res.count("y") == 1
27 nt.assert_equal(res.count('x'), 1)
29 assert res.count("x") == 1
28
30
29
31
30 def test_SubClass_with_trait_names_attr():
32 def test_SubClass_with_trait_names_attr():
31 # usecase: trait_names is used in a class describing psychological classification
33 # usecase: trait_names is used in a class describing psychological classification
32
34
33 class SubClass(Base):
35 class SubClass(Base):
34 y = 2
36 y = 2
35 trait_names = 44
37 trait_names = 44
36
38
37 res = dir2(SubClass())
39 res = dir2(SubClass())
38 assert('trait_names' in res)
40 assert "trait_names" in res
39
41
40
42
41 def test_misbehaving_object_without_trait_names():
43 def test_misbehaving_object_without_trait_names():
42 # dir2 shouldn't raise even when objects are dumb and raise
44 # dir2 shouldn't raise even when objects are dumb and raise
43 # something other than AttribteErrors on bad getattr.
45 # something other than AttribteErrors on bad getattr.
44
46
45 class MisbehavingGetattr(object):
47 class MisbehavingGetattr:
46 def __getattr__(self):
48 def __getattr__(self, attr):
47 raise KeyError("I should be caught")
49 raise KeyError("I should be caught")
48
50
49 def some_method(self):
51 def some_method(self):
50 pass
52 return True
51
53
52 class SillierWithDir(MisbehavingGetattr):
54 class SillierWithDir(MisbehavingGetattr):
53 def __dir__(self):
55 def __dir__(self):
54 return ['some_method']
56 return ['some_method']
55
57
56 for bad_klass in (MisbehavingGetattr, SillierWithDir):
58 for bad_klass in (MisbehavingGetattr, SillierWithDir):
57 res = dir2(bad_klass())
59 obj = bad_klass()
58 assert('some_method' in res)
60
61 assert obj.some_method()
62
63 with pytest.raises(KeyError):
64 obj.other_method()
65
66 res = dir2(obj)
67 assert "some_method" in res
@@ -1,39 +1,40 b''
1 """Tests for IPython.utils.importstring."""
1 """Tests for IPython.utils.importstring."""
2
2
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (C) 2013 The IPython Development Team
4 # Copyright (C) 2013 The IPython Development Team
5 #
5 #
6 # Distributed under the terms of the BSD License. The full license is in
6 # Distributed under the terms of the BSD License. The full license is in
7 # the file COPYING, distributed as part of this software.
7 # the file COPYING, distributed as part of this software.
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Imports
11 # Imports
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 import nose.tools as nt
14 import pytest
15
15
16 from IPython.utils.importstring import import_item
16 from IPython.utils.importstring import import_item
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Tests
19 # Tests
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 def test_import_plain():
22 def test_import_plain():
23 "Test simple imports"
23 "Test simple imports"
24 import os
24 import os
25 os2 = import_item('os')
25
26 nt.assert_true(os is os2)
26 os2 = import_item("os")
27 assert os is os2
27
28
28
29
29 def test_import_nested():
30 def test_import_nested():
30 "Test nested imports from the stdlib"
31 "Test nested imports from the stdlib"
31 from os import path
32 from os import path
32 path2 = import_item('os.path')
33
33 nt.assert_true(path is path2)
34 path2 = import_item("os.path")
35 assert path is path2
34
36
35
37
36 def test_import_raises():
38 def test_import_raises():
37 "Test that failing imports raise the right exception"
39 "Test that failing imports raise the right exception"
38 nt.assert_raises(ImportError, import_item, 'IPython.foobar')
40 pytest.raises(ImportError, import_item, "IPython.foobar")
39
@@ -1,89 +1,87 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """Tests for io.py"""
2 """Tests for io.py"""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7
7
8 import sys
8 import sys
9 from io import StringIO
9 from io import StringIO
10
10
11 from subprocess import Popen, PIPE
11 from subprocess import Popen, PIPE
12 import unittest
12 import unittest
13
13
14 import nose.tools as nt
15
16 from IPython.utils.io import IOStream, Tee, capture_output
14 from IPython.utils.io import IOStream, Tee, capture_output
17
15
18
16
19 def test_tee_simple():
17 def test_tee_simple():
20 "Very simple check with stdout only"
18 "Very simple check with stdout only"
21 chan = StringIO()
19 chan = StringIO()
22 text = 'Hello'
20 text = 'Hello'
23 tee = Tee(chan, channel='stdout')
21 tee = Tee(chan, channel='stdout')
24 print(text, file=chan)
22 print(text, file=chan)
25 nt.assert_equal(chan.getvalue(), text+"\n")
23 assert chan.getvalue() == text + "\n"
26
24
27
25
28 class TeeTestCase(unittest.TestCase):
26 class TeeTestCase(unittest.TestCase):
29
27
30 def tchan(self, channel):
28 def tchan(self, channel):
31 trap = StringIO()
29 trap = StringIO()
32 chan = StringIO()
30 chan = StringIO()
33 text = 'Hello'
31 text = 'Hello'
34
32
35 std_ori = getattr(sys, channel)
33 std_ori = getattr(sys, channel)
36 setattr(sys, channel, trap)
34 setattr(sys, channel, trap)
37
35
38 tee = Tee(chan, channel=channel)
36 tee = Tee(chan, channel=channel)
39
37
40 print(text, end='', file=chan)
38 print(text, end='', file=chan)
41 trap_val = trap.getvalue()
39 trap_val = trap.getvalue()
42 nt.assert_equal(chan.getvalue(), text)
40 self.assertEqual(chan.getvalue(), text)
43
41
44 tee.close()
42 tee.close()
45
43
46 setattr(sys, channel, std_ori)
44 setattr(sys, channel, std_ori)
47 assert getattr(sys, channel) == std_ori
45 assert getattr(sys, channel) == std_ori
48
46
49 def test(self):
47 def test(self):
50 for chan in ['stdout', 'stderr']:
48 for chan in ['stdout', 'stderr']:
51 self.tchan(chan)
49 self.tchan(chan)
52
50
53 def test_io_init():
51 def test_io_init():
54 """Test that io.stdin/out/err exist at startup"""
52 """Test that io.stdin/out/err exist at startup"""
55 for name in ('stdin', 'stdout', 'stderr'):
53 for name in ('stdin', 'stdout', 'stderr'):
56 cmd = "from IPython.utils import io;print(io.%s.__class__)"%name
54 cmd = "from IPython.utils import io;print(io.%s.__class__)"%name
57 with Popen([sys.executable, '-c', cmd], stdout=PIPE) as p:
55 with Popen([sys.executable, '-c', cmd], stdout=PIPE) as p:
58 p.wait()
56 p.wait()
59 classname = p.stdout.read().strip().decode('ascii')
57 classname = p.stdout.read().strip().decode('ascii')
60 # __class__ is a reference to the class object in Python 3, so we can't
58 # __class__ is a reference to the class object in Python 3, so we can't
61 # just test for string equality.
59 # just test for string equality.
62 assert 'IPython.utils.io.IOStream' in classname, classname
60 assert 'IPython.utils.io.IOStream' in classname, classname
63
61
64 class TestIOStream(unittest.TestCase):
62 class TestIOStream(unittest.TestCase):
65
63
66 def test_IOStream_init(self):
64 def test_IOStream_init(self):
67 """IOStream initializes from a file-like object missing attributes. """
65 """IOStream initializes from a file-like object missing attributes. """
68 # Cause a failure from getattr and dir(). (Issue #6386)
66 # Cause a failure from getattr and dir(). (Issue #6386)
69 class BadStringIO(StringIO):
67 class BadStringIO(StringIO):
70 def __dir__(self):
68 def __dir__(self):
71 attrs = super().__dir__()
69 attrs = super().__dir__()
72 attrs.append('name')
70 attrs.append('name')
73 return attrs
71 return attrs
74 with self.assertWarns(DeprecationWarning):
72 with self.assertWarns(DeprecationWarning):
75 iostream = IOStream(BadStringIO())
73 iostream = IOStream(BadStringIO())
76 iostream.write('hi, bad iostream\n')
74 iostream.write('hi, bad iostream\n')
77
75
78 assert not hasattr(iostream, 'name')
76 assert not hasattr(iostream, 'name')
79 iostream.close()
77 iostream.close()
80
78
81 def test_capture_output(self):
79 def test_capture_output(self):
82 """capture_output() context works"""
80 """capture_output() context works"""
83
81
84 with capture_output() as io:
82 with capture_output() as io:
85 print('hi, stdout')
83 print("hi, stdout")
86 print('hi, stderr', file=sys.stderr)
84 print("hi, stderr", file=sys.stderr)
87
85
88 nt.assert_equal(io.stdout, 'hi, stdout\n')
86 self.assertEqual(io.stdout, "hi, stdout\n")
89 nt.assert_equal(io.stderr, 'hi, stderr\n')
87 self.assertEqual(io.stderr, "hi, stderr\n")
@@ -1,111 +1,109 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """Tests for IPython.utils.module_paths.py"""
2 """Tests for IPython.utils.module_paths.py"""
3
3
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (C) 2008-2011 The IPython Development Team
5 # Copyright (C) 2008-2011 The IPython Development Team
6 #
6 #
7 # Distributed under the terms of the BSD License. The full license is in
7 # Distributed under the terms of the BSD License. The full license is in
8 # the file COPYING, distributed as part of this software.
8 # the file COPYING, distributed as part of this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 import shutil
15 import shutil
16 import sys
16 import sys
17 import tempfile
17 import tempfile
18
18
19 from pathlib import Path
19 from pathlib import Path
20
20
21 from IPython.testing.tools import make_tempfile
21 from IPython.testing.tools import make_tempfile
22
22
23 import IPython.utils.module_paths as mp
23 import IPython.utils.module_paths as mp
24
24
25 import nose.tools as nt
26
27 TEST_FILE_PATH = Path(__file__).resolve().parent
25 TEST_FILE_PATH = Path(__file__).resolve().parent
28
26
29 TMP_TEST_DIR = Path(tempfile.mkdtemp(suffix="with.dot"))
27 TMP_TEST_DIR = Path(tempfile.mkdtemp(suffix="with.dot"))
30 #
28 #
31 # Setup/teardown functions/decorators
29 # Setup/teardown functions/decorators
32 #
30 #
33
31
34 old_syspath = sys.path
32 old_syspath = sys.path
35
33
36 def make_empty_file(fname):
34 def make_empty_file(fname):
37 open(fname, 'w').close()
35 open(fname, 'w').close()
38
36
39
37
40 def setup_module():
38 def setup_module():
41 """Setup testenvironment for the module:
39 """Setup testenvironment for the module:
42
40
43 """
41 """
44 # Do not mask exceptions here. In particular, catching WindowsError is a
42 # Do not mask exceptions here. In particular, catching WindowsError is a
45 # problem because that exception is only defined on Windows...
43 # problem because that exception is only defined on Windows...
46 Path(TMP_TEST_DIR / "xmod").mkdir(parents=True)
44 Path(TMP_TEST_DIR / "xmod").mkdir(parents=True)
47 Path(TMP_TEST_DIR / "nomod").mkdir(parents=True)
45 Path(TMP_TEST_DIR / "nomod").mkdir(parents=True)
48 make_empty_file(TMP_TEST_DIR / "xmod/__init__.py")
46 make_empty_file(TMP_TEST_DIR / "xmod/__init__.py")
49 make_empty_file(TMP_TEST_DIR / "xmod/sub.py")
47 make_empty_file(TMP_TEST_DIR / "xmod/sub.py")
50 make_empty_file(TMP_TEST_DIR / "pack.py")
48 make_empty_file(TMP_TEST_DIR / "pack.py")
51 make_empty_file(TMP_TEST_DIR / "packpyc.pyc")
49 make_empty_file(TMP_TEST_DIR / "packpyc.pyc")
52 sys.path = [str(TMP_TEST_DIR)]
50 sys.path = [str(TMP_TEST_DIR)]
53
51
54 def teardown_module():
52 def teardown_module():
55 """Teardown testenvironment for the module:
53 """Teardown testenvironment for the module:
56
54
57 - Remove tempdir
55 - Remove tempdir
58 - restore sys.path
56 - restore sys.path
59 """
57 """
60 # Note: we remove the parent test dir, which is the root of all test
58 # Note: we remove the parent test dir, which is the root of all test
61 # subdirs we may have created. Use shutil instead of os.removedirs, so
59 # subdirs we may have created. Use shutil instead of os.removedirs, so
62 # that non-empty directories are all recursively removed.
60 # that non-empty directories are all recursively removed.
63 shutil.rmtree(TMP_TEST_DIR)
61 shutil.rmtree(TMP_TEST_DIR)
64 sys.path = old_syspath
62 sys.path = old_syspath
65
63
66 def test_tempdir():
64 def test_tempdir():
67 """
65 """
68 Ensure the test are done with a temporary file that have a dot somewhere.
66 Ensure the test are done with a temporary file that have a dot somewhere.
69 """
67 """
70 nt.assert_in(".", str(TMP_TEST_DIR))
68 assert "." in str(TMP_TEST_DIR)
71
69
72
70
73 def test_find_mod_1():
71 def test_find_mod_1():
74 """
72 """
75 Search for a directory's file path.
73 Search for a directory's file path.
76 Expected output: a path to that directory's __init__.py file.
74 Expected output: a path to that directory's __init__.py file.
77 """
75 """
78 modpath = TMP_TEST_DIR / "xmod" / "__init__.py"
76 modpath = TMP_TEST_DIR / "xmod" / "__init__.py"
79 nt.assert_equal(Path(mp.find_mod("xmod")), modpath)
77 assert Path(mp.find_mod("xmod")) == modpath
80
78
81 def test_find_mod_2():
79 def test_find_mod_2():
82 """
80 """
83 Search for a directory's file path.
81 Search for a directory's file path.
84 Expected output: a path to that directory's __init__.py file.
82 Expected output: a path to that directory's __init__.py file.
85 TODO: Confirm why this is a duplicate test.
83 TODO: Confirm why this is a duplicate test.
86 """
84 """
87 modpath = TMP_TEST_DIR / "xmod" / "__init__.py"
85 modpath = TMP_TEST_DIR / "xmod" / "__init__.py"
88 nt.assert_equal(Path(mp.find_mod("xmod")), modpath)
86 assert Path(mp.find_mod("xmod")) == modpath
89
87
90 def test_find_mod_3():
88 def test_find_mod_3():
91 """
89 """
92 Search for a directory + a filename without its .py extension
90 Search for a directory + a filename without its .py extension
93 Expected output: full path with .py extension.
91 Expected output: full path with .py extension.
94 """
92 """
95 modpath = TMP_TEST_DIR / "xmod" / "sub.py"
93 modpath = TMP_TEST_DIR / "xmod" / "sub.py"
96 nt.assert_equal(Path(mp.find_mod("xmod.sub")), modpath)
94 assert Path(mp.find_mod("xmod.sub")) == modpath
97
95
98 def test_find_mod_4():
96 def test_find_mod_4():
99 """
97 """
100 Search for a filename without its .py extension
98 Search for a filename without its .py extension
101 Expected output: full path with .py extension
99 Expected output: full path with .py extension
102 """
100 """
103 modpath = TMP_TEST_DIR / "pack.py"
101 modpath = TMP_TEST_DIR / "pack.py"
104 nt.assert_equal(Path(mp.find_mod("pack")), modpath)
102 assert Path(mp.find_mod("pack")) == modpath
105
103
106 def test_find_mod_5():
104 def test_find_mod_5():
107 """
105 """
108 Search for a filename with a .pyc extension
106 Search for a filename with a .pyc extension
109 Expected output: TODO: do we exclude or include .pyc files?
107 Expected output: TODO: do we exclude or include .pyc files?
110 """
108 """
111 nt.assert_equal(mp.find_mod("packpyc"), None)
109 assert mp.find_mod("packpyc") == None
@@ -1,39 +1,38 b''
1 import io
1 import io
2 import os.path
2 import os.path
3 import nose.tools as nt
4
3
5 from IPython.utils import openpy
4 from IPython.utils import openpy
6
5
7 mydir = os.path.dirname(__file__)
6 mydir = os.path.dirname(__file__)
8 nonascii_path = os.path.join(mydir, "../../core/tests/nonascii.py")
7 nonascii_path = os.path.join(mydir, "../../core/tests/nonascii.py")
9
8
10
9
11 def test_detect_encoding():
10 def test_detect_encoding():
12 with open(nonascii_path, "rb") as f:
11 with open(nonascii_path, "rb") as f:
13 enc, lines = openpy.detect_encoding(f.readline)
12 enc, lines = openpy.detect_encoding(f.readline)
14 nt.assert_equal(enc, "iso-8859-5")
13 assert enc == "iso-8859-5"
15
14
16
15
17 def test_read_file():
16 def test_read_file():
18 with io.open(nonascii_path, encoding="iso-8859-5") as f:
17 with io.open(nonascii_path, encoding="iso-8859-5") as f:
19 read_specified_enc = f.read()
18 read_specified_enc = f.read()
20 read_detected_enc = openpy.read_py_file(nonascii_path, skip_encoding_cookie=False)
19 read_detected_enc = openpy.read_py_file(nonascii_path, skip_encoding_cookie=False)
21 nt.assert_equal(read_detected_enc, read_specified_enc)
20 assert read_detected_enc == read_specified_enc
22 assert "coding: iso-8859-5" in read_detected_enc
21 assert "coding: iso-8859-5" in read_detected_enc
23
22
24 read_strip_enc_cookie = openpy.read_py_file(
23 read_strip_enc_cookie = openpy.read_py_file(
25 nonascii_path, skip_encoding_cookie=True
24 nonascii_path, skip_encoding_cookie=True
26 )
25 )
27 assert "coding: iso-8859-5" not in read_strip_enc_cookie
26 assert "coding: iso-8859-5" not in read_strip_enc_cookie
28
27
29
28
30 def test_source_to_unicode():
29 def test_source_to_unicode():
31 with io.open(nonascii_path, "rb") as f:
30 with io.open(nonascii_path, "rb") as f:
32 source_bytes = f.read()
31 source_bytes = f.read()
33 nt.assert_equal(
32 assert (
34 openpy.source_to_unicode(source_bytes, skip_encoding_cookie=False).splitlines(),
33 openpy.source_to_unicode(source_bytes, skip_encoding_cookie=False).splitlines()
35 source_bytes.decode("iso-8859-5").splitlines(),
34 == source_bytes.decode("iso-8859-5").splitlines()
36 )
35 )
37
36
38 source_no_cookie = openpy.source_to_unicode(source_bytes, skip_encoding_cookie=True)
37 source_no_cookie = openpy.source_to_unicode(source_bytes, skip_encoding_cookie=True)
39 nt.assert_not_in("coding: iso-8859-5", source_no_cookie)
38 assert "coding: iso-8859-5" not in source_no_cookie
@@ -1,494 +1,493 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """Tests for IPython.utils.path.py"""
2 """Tests for IPython.utils.path.py"""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7 import os
7 import os
8 import shutil
8 import shutil
9 import sys
9 import sys
10 import tempfile
10 import tempfile
11 import unittest
11 import unittest
12 from contextlib import contextmanager
12 from contextlib import contextmanager
13 from unittest.mock import patch
13 from unittest.mock import patch
14 from os.path import join, abspath
14 from os.path import join, abspath
15 from imp import reload
15 from imp import reload
16
16
17 from nose import SkipTest, with_setup
17 from nose import SkipTest, with_setup
18 import nose.tools as nt
18 import pytest
19
19
20 import IPython
20 import IPython
21 from IPython import paths
21 from IPython import paths
22 from IPython.testing import decorators as dec
22 from IPython.testing import decorators as dec
23 from IPython.testing.decorators import (skip_if_not_win32, skip_win32,
23 from IPython.testing.decorators import (skip_if_not_win32, skip_win32,
24 onlyif_unicode_paths,
24 onlyif_unicode_paths,
25 skip_win32_py38,)
25 skip_win32_py38,)
26 from IPython.testing.tools import make_tempfile
26 from IPython.testing.tools import make_tempfile
27 from IPython.utils import path
27 from IPython.utils import path
28 from IPython.utils.tempdir import TemporaryDirectory
28 from IPython.utils.tempdir import TemporaryDirectory
29
29
30
30
31 # Platform-dependent imports
31 # Platform-dependent imports
32 try:
32 try:
33 import winreg as wreg
33 import winreg as wreg
34 except ImportError:
34 except ImportError:
35 #Fake _winreg module on non-windows platforms
35 #Fake _winreg module on non-windows platforms
36 import types
36 import types
37 wr_name = "winreg"
37 wr_name = "winreg"
38 sys.modules[wr_name] = types.ModuleType(wr_name)
38 sys.modules[wr_name] = types.ModuleType(wr_name)
39 try:
39 try:
40 import winreg as wreg
40 import winreg as wreg
41 except ImportError:
41 except ImportError:
42 import _winreg as wreg
42 import _winreg as wreg
43 #Add entries that needs to be stubbed by the testing code
43 #Add entries that needs to be stubbed by the testing code
44 (wreg.OpenKey, wreg.QueryValueEx,) = (None, None)
44 (wreg.OpenKey, wreg.QueryValueEx,) = (None, None)
45
45
46 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
47 # Globals
47 # Globals
48 #-----------------------------------------------------------------------------
48 #-----------------------------------------------------------------------------
49 env = os.environ
49 env = os.environ
50 TMP_TEST_DIR = tempfile.mkdtemp()
50 TMP_TEST_DIR = tempfile.mkdtemp()
51 HOME_TEST_DIR = join(TMP_TEST_DIR, "home_test_dir")
51 HOME_TEST_DIR = join(TMP_TEST_DIR, "home_test_dir")
52 #
52 #
53 # Setup/teardown functions/decorators
53 # Setup/teardown functions/decorators
54 #
54 #
55
55
56 def setup_module():
56 def setup_module():
57 """Setup testenvironment for the module:
57 """Setup testenvironment for the module:
58
58
59 - Adds dummy home dir tree
59 - Adds dummy home dir tree
60 """
60 """
61 # Do not mask exceptions here. In particular, catching WindowsError is a
61 # Do not mask exceptions here. In particular, catching WindowsError is a
62 # problem because that exception is only defined on Windows...
62 # problem because that exception is only defined on Windows...
63 os.makedirs(os.path.join(HOME_TEST_DIR, 'ipython'))
63 os.makedirs(os.path.join(HOME_TEST_DIR, 'ipython'))
64
64
65
65
66 def teardown_module():
66 def teardown_module():
67 """Teardown testenvironment for the module:
67 """Teardown testenvironment for the module:
68
68
69 - Remove dummy home dir tree
69 - Remove dummy home dir tree
70 """
70 """
71 # Note: we remove the parent test dir, which is the root of all test
71 # Note: we remove the parent test dir, which is the root of all test
72 # subdirs we may have created. Use shutil instead of os.removedirs, so
72 # subdirs we may have created. Use shutil instead of os.removedirs, so
73 # that non-empty directories are all recursively removed.
73 # that non-empty directories are all recursively removed.
74 shutil.rmtree(TMP_TEST_DIR)
74 shutil.rmtree(TMP_TEST_DIR)
75
75
76
76
77 def setup_environment():
77 def setup_environment():
78 """Setup testenvironment for some functions that are tested
78 """Setup testenvironment for some functions that are tested
79 in this module. In particular this functions stores attributes
79 in this module. In particular this functions stores attributes
80 and other things that we need to stub in some test functions.
80 and other things that we need to stub in some test functions.
81 This needs to be done on a function level and not module level because
81 This needs to be done on a function level and not module level because
82 each testfunction needs a pristine environment.
82 each testfunction needs a pristine environment.
83 """
83 """
84 global oldstuff, platformstuff
84 global oldstuff, platformstuff
85 oldstuff = (env.copy(), os.name, sys.platform, path.get_home_dir, IPython.__file__, os.getcwd())
85 oldstuff = (env.copy(), os.name, sys.platform, path.get_home_dir, IPython.__file__, os.getcwd())
86
86
87 def teardown_environment():
87 def teardown_environment():
88 """Restore things that were remembered by the setup_environment function
88 """Restore things that were remembered by the setup_environment function
89 """
89 """
90 (oldenv, os.name, sys.platform, path.get_home_dir, IPython.__file__, old_wd) = oldstuff
90 (oldenv, os.name, sys.platform, path.get_home_dir, IPython.__file__, old_wd) = oldstuff
91 os.chdir(old_wd)
91 os.chdir(old_wd)
92 reload(path)
92 reload(path)
93
93
94 for key in list(env):
94 for key in list(env):
95 if key not in oldenv:
95 if key not in oldenv:
96 del env[key]
96 del env[key]
97 env.update(oldenv)
97 env.update(oldenv)
98 if hasattr(sys, 'frozen'):
98 if hasattr(sys, 'frozen'):
99 del sys.frozen
99 del sys.frozen
100
100
101 # Build decorator that uses the setup_environment/setup_environment
101 # Build decorator that uses the setup_environment/setup_environment
102 with_environment = with_setup(setup_environment, teardown_environment)
102 with_environment = with_setup(setup_environment, teardown_environment)
103
103
104 @skip_if_not_win32
104 @skip_if_not_win32
105 @with_environment
105 @with_environment
106 def test_get_home_dir_1():
106 def test_get_home_dir_1():
107 """Testcase for py2exe logic, un-compressed lib
107 """Testcase for py2exe logic, un-compressed lib
108 """
108 """
109 unfrozen = path.get_home_dir()
109 unfrozen = path.get_home_dir()
110 sys.frozen = True
110 sys.frozen = True
111
111
112 #fake filename for IPython.__init__
112 #fake filename for IPython.__init__
113 IPython.__file__ = abspath(join(HOME_TEST_DIR, "Lib/IPython/__init__.py"))
113 IPython.__file__ = abspath(join(HOME_TEST_DIR, "Lib/IPython/__init__.py"))
114
114
115 home_dir = path.get_home_dir()
115 home_dir = path.get_home_dir()
116 assert home_dir == unfrozen
116 assert home_dir == unfrozen
117
117
118
118
119 @skip_if_not_win32
119 @skip_if_not_win32
120 @with_environment
120 @with_environment
121 def test_get_home_dir_2():
121 def test_get_home_dir_2():
122 """Testcase for py2exe logic, compressed lib
122 """Testcase for py2exe logic, compressed lib
123 """
123 """
124 unfrozen = path.get_home_dir()
124 unfrozen = path.get_home_dir()
125 sys.frozen = True
125 sys.frozen = True
126 #fake filename for IPython.__init__
126 #fake filename for IPython.__init__
127 IPython.__file__ = abspath(join(HOME_TEST_DIR, "Library.zip/IPython/__init__.py")).lower()
127 IPython.__file__ = abspath(join(HOME_TEST_DIR, "Library.zip/IPython/__init__.py")).lower()
128
128
129 home_dir = path.get_home_dir(True)
129 home_dir = path.get_home_dir(True)
130 assert home_dir == unfrozen
130 assert home_dir == unfrozen
131
131
132
132
133 @skip_win32_py38
133 @skip_win32_py38
134 @with_environment
134 @with_environment
135 def test_get_home_dir_3():
135 def test_get_home_dir_3():
136 """get_home_dir() uses $HOME if set"""
136 """get_home_dir() uses $HOME if set"""
137 env["HOME"] = HOME_TEST_DIR
137 env["HOME"] = HOME_TEST_DIR
138 home_dir = path.get_home_dir(True)
138 home_dir = path.get_home_dir(True)
139 # get_home_dir expands symlinks
139 # get_home_dir expands symlinks
140 assert home_dir == os.path.realpath(env["HOME"])
140 assert home_dir == os.path.realpath(env["HOME"])
141
141
142
142
143 @with_environment
143 @with_environment
144 def test_get_home_dir_4():
144 def test_get_home_dir_4():
145 """get_home_dir() still works if $HOME is not set"""
145 """get_home_dir() still works if $HOME is not set"""
146
146
147 if 'HOME' in env: del env['HOME']
147 if 'HOME' in env: del env['HOME']
148 # this should still succeed, but we don't care what the answer is
148 # this should still succeed, but we don't care what the answer is
149 home = path.get_home_dir(False)
149 home = path.get_home_dir(False)
150
150
151 @skip_win32_py38
151 @skip_win32_py38
152 @with_environment
152 @with_environment
153 def test_get_home_dir_5():
153 def test_get_home_dir_5():
154 """raise HomeDirError if $HOME is specified, but not a writable dir"""
154 """raise HomeDirError if $HOME is specified, but not a writable dir"""
155 env['HOME'] = abspath(HOME_TEST_DIR+'garbage')
155 env['HOME'] = abspath(HOME_TEST_DIR+'garbage')
156 # set os.name = posix, to prevent My Documents fallback on Windows
156 # set os.name = posix, to prevent My Documents fallback on Windows
157 os.name = 'posix'
157 os.name = 'posix'
158 nt.assert_raises(path.HomeDirError, path.get_home_dir, True)
158 pytest.raises(path.HomeDirError, path.get_home_dir, True)
159
159
160 # Should we stub wreg fully so we can run the test on all platforms?
160 # Should we stub wreg fully so we can run the test on all platforms?
161 @skip_if_not_win32
161 @skip_if_not_win32
162 @with_environment
162 @with_environment
163 def test_get_home_dir_8():
163 def test_get_home_dir_8():
164 """Using registry hack for 'My Documents', os=='nt'
164 """Using registry hack for 'My Documents', os=='nt'
165
165
166 HOMESHARE, HOMEDRIVE, HOMEPATH, USERPROFILE and others are missing.
166 HOMESHARE, HOMEDRIVE, HOMEPATH, USERPROFILE and others are missing.
167 """
167 """
168 os.name = 'nt'
168 os.name = 'nt'
169 # Remove from stub environment all keys that may be set
169 # Remove from stub environment all keys that may be set
170 for key in ['HOME', 'HOMESHARE', 'HOMEDRIVE', 'HOMEPATH', 'USERPROFILE']:
170 for key in ['HOME', 'HOMESHARE', 'HOMEDRIVE', 'HOMEPATH', 'USERPROFILE']:
171 env.pop(key, None)
171 env.pop(key, None)
172
172
173 class key:
173 class key:
174 def __enter__(self):
174 def __enter__(self):
175 pass
175 pass
176 def Close(self):
176 def Close(self):
177 pass
177 pass
178 def __exit__(*args, **kwargs):
178 def __exit__(*args, **kwargs):
179 pass
179 pass
180
180
181 with patch.object(wreg, 'OpenKey', return_value=key()), \
181 with patch.object(wreg, 'OpenKey', return_value=key()), \
182 patch.object(wreg, 'QueryValueEx', return_value=[abspath(HOME_TEST_DIR)]):
182 patch.object(wreg, 'QueryValueEx', return_value=[abspath(HOME_TEST_DIR)]):
183 home_dir = path.get_home_dir()
183 home_dir = path.get_home_dir()
184 assert home_dir == abspath(HOME_TEST_DIR)
184 assert home_dir == abspath(HOME_TEST_DIR)
185
185
186 @with_environment
186 @with_environment
187 def test_get_xdg_dir_0():
187 def test_get_xdg_dir_0():
188 """test_get_xdg_dir_0, check xdg_dir"""
188 """test_get_xdg_dir_0, check xdg_dir"""
189 reload(path)
189 reload(path)
190 path._writable_dir = lambda path: True
190 path._writable_dir = lambda path: True
191 path.get_home_dir = lambda : 'somewhere'
191 path.get_home_dir = lambda : 'somewhere'
192 os.name = "posix"
192 os.name = "posix"
193 sys.platform = "linux2"
193 sys.platform = "linux2"
194 env.pop('IPYTHON_DIR', None)
194 env.pop('IPYTHON_DIR', None)
195 env.pop('IPYTHONDIR', None)
195 env.pop('IPYTHONDIR', None)
196 env.pop('XDG_CONFIG_HOME', None)
196 env.pop('XDG_CONFIG_HOME', None)
197
197
198 assert path.get_xdg_dir() == os.path.join("somewhere", ".config")
198 assert path.get_xdg_dir() == os.path.join("somewhere", ".config")
199
199
200
200
201 @with_environment
201 @with_environment
202 def test_get_xdg_dir_1():
202 def test_get_xdg_dir_1():
203 """test_get_xdg_dir_1, check nonexistent xdg_dir"""
203 """test_get_xdg_dir_1, check nonexistent xdg_dir"""
204 reload(path)
204 reload(path)
205 path.get_home_dir = lambda : HOME_TEST_DIR
205 path.get_home_dir = lambda : HOME_TEST_DIR
206 os.name = "posix"
206 os.name = "posix"
207 sys.platform = "linux2"
207 sys.platform = "linux2"
208 env.pop('IPYTHON_DIR', None)
208 env.pop('IPYTHON_DIR', None)
209 env.pop('IPYTHONDIR', None)
209 env.pop('IPYTHONDIR', None)
210 env.pop('XDG_CONFIG_HOME', None)
210 env.pop('XDG_CONFIG_HOME', None)
211 assert path.get_xdg_dir() is None
211 assert path.get_xdg_dir() is None
212
212
213 @with_environment
213 @with_environment
214 def test_get_xdg_dir_2():
214 def test_get_xdg_dir_2():
215 """test_get_xdg_dir_2, check xdg_dir default to ~/.config"""
215 """test_get_xdg_dir_2, check xdg_dir default to ~/.config"""
216 reload(path)
216 reload(path)
217 path.get_home_dir = lambda : HOME_TEST_DIR
217 path.get_home_dir = lambda : HOME_TEST_DIR
218 os.name = "posix"
218 os.name = "posix"
219 sys.platform = "linux2"
219 sys.platform = "linux2"
220 env.pop('IPYTHON_DIR', None)
220 env.pop('IPYTHON_DIR', None)
221 env.pop('IPYTHONDIR', None)
221 env.pop('IPYTHONDIR', None)
222 env.pop('XDG_CONFIG_HOME', None)
222 env.pop('XDG_CONFIG_HOME', None)
223 cfgdir=os.path.join(path.get_home_dir(), '.config')
223 cfgdir=os.path.join(path.get_home_dir(), '.config')
224 if not os.path.exists(cfgdir):
224 if not os.path.exists(cfgdir):
225 os.makedirs(cfgdir)
225 os.makedirs(cfgdir)
226
226
227 assert path.get_xdg_dir() == cfgdir
227 assert path.get_xdg_dir() == cfgdir
228
228
229 @with_environment
229 @with_environment
230 def test_get_xdg_dir_3():
230 def test_get_xdg_dir_3():
231 """test_get_xdg_dir_3, check xdg_dir not used on OS X"""
231 """test_get_xdg_dir_3, check xdg_dir not used on OS X"""
232 reload(path)
232 reload(path)
233 path.get_home_dir = lambda : HOME_TEST_DIR
233 path.get_home_dir = lambda : HOME_TEST_DIR
234 os.name = "posix"
234 os.name = "posix"
235 sys.platform = "darwin"
235 sys.platform = "darwin"
236 env.pop('IPYTHON_DIR', None)
236 env.pop('IPYTHON_DIR', None)
237 env.pop('IPYTHONDIR', None)
237 env.pop('IPYTHONDIR', None)
238 env.pop('XDG_CONFIG_HOME', None)
238 env.pop('XDG_CONFIG_HOME', None)
239 cfgdir=os.path.join(path.get_home_dir(), '.config')
239 cfgdir=os.path.join(path.get_home_dir(), '.config')
240 if not os.path.exists(cfgdir):
240 os.makedirs(cfgdir, exist_ok=True)
241 os.makedirs(cfgdir)
242
241
243 assert path.get_xdg_dir() is None
242 assert path.get_xdg_dir() is None
244
243
245 def test_filefind():
244 def test_filefind():
246 """Various tests for filefind"""
245 """Various tests for filefind"""
247 f = tempfile.NamedTemporaryFile()
246 f = tempfile.NamedTemporaryFile()
248 # print 'fname:',f.name
247 # print 'fname:',f.name
249 alt_dirs = paths.get_ipython_dir()
248 alt_dirs = paths.get_ipython_dir()
250 t = path.filefind(f.name, alt_dirs)
249 t = path.filefind(f.name, alt_dirs)
251 # print 'found:',t
250 # print 'found:',t
252
251
253
252
254 @dec.skip_if_not_win32
253 @dec.skip_if_not_win32
255 def test_get_long_path_name_win32():
254 def test_get_long_path_name_win32():
256 with TemporaryDirectory() as tmpdir:
255 with TemporaryDirectory() as tmpdir:
257
256
258 # Make a long path. Expands the path of tmpdir prematurely as it may already have a long
257 # Make a long path. Expands the path of tmpdir prematurely as it may already have a long
259 # path component, so ensure we include the long form of it
258 # path component, so ensure we include the long form of it
260 long_path = os.path.join(path.get_long_path_name(tmpdir), 'this is my long path name')
259 long_path = os.path.join(path.get_long_path_name(tmpdir), 'this is my long path name')
261 os.makedirs(long_path)
260 os.makedirs(long_path)
262
261
263 # Test to see if the short path evaluates correctly.
262 # Test to see if the short path evaluates correctly.
264 short_path = os.path.join(tmpdir, 'THISIS~1')
263 short_path = os.path.join(tmpdir, 'THISIS~1')
265 evaluated_path = path.get_long_path_name(short_path)
264 evaluated_path = path.get_long_path_name(short_path)
266 assert evaluated_path.lower() == long_path.lower()
265 assert evaluated_path.lower() == long_path.lower()
267
266
268
267
269 @dec.skip_win32
268 @dec.skip_win32
270 def test_get_long_path_name():
269 def test_get_long_path_name():
271 p = path.get_long_path_name("/usr/local")
270 p = path.get_long_path_name("/usr/local")
272 assert p == "/usr/local"
271 assert p == "/usr/local"
273
272
274
273
275 class TestRaiseDeprecation(unittest.TestCase):
274 class TestRaiseDeprecation(unittest.TestCase):
276
275
277 @dec.skip_win32 # can't create not-user-writable dir on win
276 @dec.skip_win32 # can't create not-user-writable dir on win
278 @with_environment
277 @with_environment
279 def test_not_writable_ipdir(self):
278 def test_not_writable_ipdir(self):
280 tmpdir = tempfile.mkdtemp()
279 tmpdir = tempfile.mkdtemp()
281 os.name = "posix"
280 os.name = "posix"
282 env.pop('IPYTHON_DIR', None)
281 env.pop('IPYTHON_DIR', None)
283 env.pop('IPYTHONDIR', None)
282 env.pop('IPYTHONDIR', None)
284 env.pop('XDG_CONFIG_HOME', None)
283 env.pop('XDG_CONFIG_HOME', None)
285 env['HOME'] = tmpdir
284 env['HOME'] = tmpdir
286 ipdir = os.path.join(tmpdir, '.ipython')
285 ipdir = os.path.join(tmpdir, '.ipython')
287 os.mkdir(ipdir, 0o555)
286 os.mkdir(ipdir, 0o555)
288 try:
287 try:
289 open(os.path.join(ipdir, "_foo_"), 'w').close()
288 open(os.path.join(ipdir, "_foo_"), 'w').close()
290 except IOError:
289 except IOError:
291 pass
290 pass
292 else:
291 else:
293 # I can still write to an unwritable dir,
292 # I can still write to an unwritable dir,
294 # assume I'm root and skip the test
293 # assume I'm root and skip the test
295 raise SkipTest("I can't create directories that I can't write to")
294 raise SkipTest("I can't create directories that I can't write to")
296 with self.assertWarnsRegex(UserWarning, 'is not a writable location'):
295 with self.assertWarnsRegex(UserWarning, 'is not a writable location'):
297 ipdir = paths.get_ipython_dir()
296 ipdir = paths.get_ipython_dir()
298 env.pop('IPYTHON_DIR', None)
297 env.pop('IPYTHON_DIR', None)
299
298
300 @with_environment
299 @with_environment
301 def test_get_py_filename():
300 def test_get_py_filename():
302 os.chdir(TMP_TEST_DIR)
301 os.chdir(TMP_TEST_DIR)
303 with make_tempfile("foo.py"):
302 with make_tempfile("foo.py"):
304 assert path.get_py_filename("foo.py") == "foo.py"
303 assert path.get_py_filename("foo.py") == "foo.py"
305 assert path.get_py_filename("foo") == "foo.py"
304 assert path.get_py_filename("foo") == "foo.py"
306 with make_tempfile("foo"):
305 with make_tempfile("foo"):
307 assert path.get_py_filename("foo") == "foo"
306 assert path.get_py_filename("foo") == "foo"
308 nt.assert_raises(IOError, path.get_py_filename, "foo.py")
307 pytest.raises(IOError, path.get_py_filename, "foo.py")
309 nt.assert_raises(IOError, path.get_py_filename, "foo")
308 pytest.raises(IOError, path.get_py_filename, "foo")
310 nt.assert_raises(IOError, path.get_py_filename, "foo.py")
309 pytest.raises(IOError, path.get_py_filename, "foo.py")
311 true_fn = "foo with spaces.py"
310 true_fn = "foo with spaces.py"
312 with make_tempfile(true_fn):
311 with make_tempfile(true_fn):
313 assert path.get_py_filename("foo with spaces") == true_fn
312 assert path.get_py_filename("foo with spaces") == true_fn
314 assert path.get_py_filename("foo with spaces.py") == true_fn
313 assert path.get_py_filename("foo with spaces.py") == true_fn
315 nt.assert_raises(IOError, path.get_py_filename, '"foo with spaces.py"')
314 pytest.raises(IOError, path.get_py_filename, '"foo with spaces.py"')
316 nt.assert_raises(IOError, path.get_py_filename, "'foo with spaces.py'")
315 pytest.raises(IOError, path.get_py_filename, "'foo with spaces.py'")
317
316
318 @onlyif_unicode_paths
317 @onlyif_unicode_paths
319 def test_unicode_in_filename():
318 def test_unicode_in_filename():
320 """When a file doesn't exist, the exception raised should be safe to call
319 """When a file doesn't exist, the exception raised should be safe to call
321 str() on - i.e. in Python 2 it must only have ASCII characters.
320 str() on - i.e. in Python 2 it must only have ASCII characters.
322
321
323 https://github.com/ipython/ipython/issues/875
322 https://github.com/ipython/ipython/issues/875
324 """
323 """
325 try:
324 try:
326 # these calls should not throw unicode encode exceptions
325 # these calls should not throw unicode encode exceptions
327 path.get_py_filename('fooéè.py')
326 path.get_py_filename('fooéè.py')
328 except IOError as ex:
327 except IOError as ex:
329 str(ex)
328 str(ex)
330
329
331
330
332 class TestShellGlob(unittest.TestCase):
331 class TestShellGlob(unittest.TestCase):
333
332
334 @classmethod
333 @classmethod
335 def setUpClass(cls):
334 def setUpClass(cls):
336 cls.filenames_start_with_a = ['a0', 'a1', 'a2']
335 cls.filenames_start_with_a = ['a0', 'a1', 'a2']
337 cls.filenames_end_with_b = ['0b', '1b', '2b']
336 cls.filenames_end_with_b = ['0b', '1b', '2b']
338 cls.filenames = cls.filenames_start_with_a + cls.filenames_end_with_b
337 cls.filenames = cls.filenames_start_with_a + cls.filenames_end_with_b
339 cls.tempdir = TemporaryDirectory()
338 cls.tempdir = TemporaryDirectory()
340 td = cls.tempdir.name
339 td = cls.tempdir.name
341
340
342 with cls.in_tempdir():
341 with cls.in_tempdir():
343 # Create empty files
342 # Create empty files
344 for fname in cls.filenames:
343 for fname in cls.filenames:
345 open(os.path.join(td, fname), 'w').close()
344 open(os.path.join(td, fname), 'w').close()
346
345
347 @classmethod
346 @classmethod
348 def tearDownClass(cls):
347 def tearDownClass(cls):
349 cls.tempdir.cleanup()
348 cls.tempdir.cleanup()
350
349
351 @classmethod
350 @classmethod
352 @contextmanager
351 @contextmanager
353 def in_tempdir(cls):
352 def in_tempdir(cls):
354 save = os.getcwd()
353 save = os.getcwd()
355 try:
354 try:
356 os.chdir(cls.tempdir.name)
355 os.chdir(cls.tempdir.name)
357 yield
356 yield
358 finally:
357 finally:
359 os.chdir(save)
358 os.chdir(save)
360
359
361 def check_match(self, patterns, matches):
360 def check_match(self, patterns, matches):
362 with self.in_tempdir():
361 with self.in_tempdir():
363 # glob returns unordered list. that's why sorted is required.
362 # glob returns unordered list. that's why sorted is required.
364 assert sorted(path.shellglob(patterns)) == sorted(matches)
363 assert sorted(path.shellglob(patterns)) == sorted(matches)
365
364
366 def common_cases(self):
365 def common_cases(self):
367 return [
366 return [
368 (['*'], self.filenames),
367 (['*'], self.filenames),
369 (['a*'], self.filenames_start_with_a),
368 (['a*'], self.filenames_start_with_a),
370 (['*c'], ['*c']),
369 (['*c'], ['*c']),
371 (['*', 'a*', '*b', '*c'], self.filenames
370 (['*', 'a*', '*b', '*c'], self.filenames
372 + self.filenames_start_with_a
371 + self.filenames_start_with_a
373 + self.filenames_end_with_b
372 + self.filenames_end_with_b
374 + ['*c']),
373 + ['*c']),
375 (['a[012]'], self.filenames_start_with_a),
374 (['a[012]'], self.filenames_start_with_a),
376 ]
375 ]
377
376
378 @skip_win32
377 @skip_win32
379 def test_match_posix(self):
378 def test_match_posix(self):
380 for (patterns, matches) in self.common_cases() + [
379 for (patterns, matches) in self.common_cases() + [
381 ([r'\*'], ['*']),
380 ([r'\*'], ['*']),
382 ([r'a\*', 'a*'], ['a*'] + self.filenames_start_with_a),
381 ([r'a\*', 'a*'], ['a*'] + self.filenames_start_with_a),
383 ([r'a\[012]'], ['a[012]']),
382 ([r'a\[012]'], ['a[012]']),
384 ]:
383 ]:
385 yield (self.check_match, patterns, matches)
384 yield (self.check_match, patterns, matches)
386
385
387 @skip_if_not_win32
386 @skip_if_not_win32
388 def test_match_windows(self):
387 def test_match_windows(self):
389 for (patterns, matches) in self.common_cases() + [
388 for (patterns, matches) in self.common_cases() + [
390 # In windows, backslash is interpreted as path
389 # In windows, backslash is interpreted as path
391 # separator. Therefore, you can't escape glob
390 # separator. Therefore, you can't escape glob
392 # using it.
391 # using it.
393 ([r'a\*', 'a*'], [r'a\*'] + self.filenames_start_with_a),
392 ([r'a\*', 'a*'], [r'a\*'] + self.filenames_start_with_a),
394 ([r'a\[012]'], [r'a\[012]']),
393 ([r'a\[012]'], [r'a\[012]']),
395 ]:
394 ]:
396 yield (self.check_match, patterns, matches)
395 yield (self.check_match, patterns, matches)
397
396
398
397
399 # TODO : pytest.mark.parametrise once nose is gone.
398 # TODO : pytest.mark.parametrise once nose is gone.
400 def test_unescape_glob():
399 def test_unescape_glob():
401 assert path.unescape_glob(r"\*\[\!\]\?") == "*[!]?"
400 assert path.unescape_glob(r"\*\[\!\]\?") == "*[!]?"
402 assert path.unescape_glob(r"\\*") == r"\*"
401 assert path.unescape_glob(r"\\*") == r"\*"
403 assert path.unescape_glob(r"\\\*") == r"\*"
402 assert path.unescape_glob(r"\\\*") == r"\*"
404 assert path.unescape_glob(r"\\a") == r"\a"
403 assert path.unescape_glob(r"\\a") == r"\a"
405 assert path.unescape_glob(r"\a") == r"\a"
404 assert path.unescape_glob(r"\a") == r"\a"
406
405
407
406
408 @onlyif_unicode_paths
407 @onlyif_unicode_paths
409 def test_ensure_dir_exists():
408 def test_ensure_dir_exists():
410 with TemporaryDirectory() as td:
409 with TemporaryDirectory() as td:
411 d = os.path.join(td, '∂ir')
410 d = os.path.join(td, '∂ir')
412 path.ensure_dir_exists(d) # create it
411 path.ensure_dir_exists(d) # create it
413 assert os.path.isdir(d)
412 assert os.path.isdir(d)
414 path.ensure_dir_exists(d) # no-op
413 path.ensure_dir_exists(d) # no-op
415 f = os.path.join(td, 'ƒile')
414 f = os.path.join(td, 'ƒile')
416 open(f, 'w').close() # touch
415 open(f, 'w').close() # touch
417 with nt.assert_raises(IOError):
416 with pytest.raises(IOError):
418 path.ensure_dir_exists(f)
417 path.ensure_dir_exists(f)
419
418
420 class TestLinkOrCopy(unittest.TestCase):
419 class TestLinkOrCopy(unittest.TestCase):
421 def setUp(self):
420 def setUp(self):
422 self.tempdir = TemporaryDirectory()
421 self.tempdir = TemporaryDirectory()
423 self.src = self.dst("src")
422 self.src = self.dst("src")
424 with open(self.src, "w") as f:
423 with open(self.src, "w") as f:
425 f.write("Hello, world!")
424 f.write("Hello, world!")
426
425
427 def tearDown(self):
426 def tearDown(self):
428 self.tempdir.cleanup()
427 self.tempdir.cleanup()
429
428
430 def dst(self, *args):
429 def dst(self, *args):
431 return os.path.join(self.tempdir.name, *args)
430 return os.path.join(self.tempdir.name, *args)
432
431
433 def assert_inode_not_equal(self, a, b):
432 def assert_inode_not_equal(self, a, b):
434 assert (
433 assert (
435 os.stat(a).st_ino != os.stat(b).st_ino
434 os.stat(a).st_ino != os.stat(b).st_ino
436 ), "%r and %r do reference the same indoes" % (a, b)
435 ), "%r and %r do reference the same indoes" % (a, b)
437
436
438 def assert_inode_equal(self, a, b):
437 def assert_inode_equal(self, a, b):
439 assert (
438 assert (
440 os.stat(a).st_ino == os.stat(b).st_ino
439 os.stat(a).st_ino == os.stat(b).st_ino
441 ), "%r and %r do not reference the same indoes" % (a, b)
440 ), "%r and %r do not reference the same indoes" % (a, b)
442
441
443 def assert_content_equal(self, a, b):
442 def assert_content_equal(self, a, b):
444 with open(a) as a_f:
443 with open(a) as a_f:
445 with open(b) as b_f:
444 with open(b) as b_f:
446 assert a_f.read() == b_f.read()
445 assert a_f.read() == b_f.read()
447
446
448 @skip_win32
447 @skip_win32
449 def test_link_successful(self):
448 def test_link_successful(self):
450 dst = self.dst("target")
449 dst = self.dst("target")
451 path.link_or_copy(self.src, dst)
450 path.link_or_copy(self.src, dst)
452 self.assert_inode_equal(self.src, dst)
451 self.assert_inode_equal(self.src, dst)
453
452
454 @skip_win32
453 @skip_win32
455 def test_link_into_dir(self):
454 def test_link_into_dir(self):
456 dst = self.dst("some_dir")
455 dst = self.dst("some_dir")
457 os.mkdir(dst)
456 os.mkdir(dst)
458 path.link_or_copy(self.src, dst)
457 path.link_or_copy(self.src, dst)
459 expected_dst = self.dst("some_dir", os.path.basename(self.src))
458 expected_dst = self.dst("some_dir", os.path.basename(self.src))
460 self.assert_inode_equal(self.src, expected_dst)
459 self.assert_inode_equal(self.src, expected_dst)
461
460
462 @skip_win32
461 @skip_win32
463 def test_target_exists(self):
462 def test_target_exists(self):
464 dst = self.dst("target")
463 dst = self.dst("target")
465 open(dst, "w").close()
464 open(dst, "w").close()
466 path.link_or_copy(self.src, dst)
465 path.link_or_copy(self.src, dst)
467 self.assert_inode_equal(self.src, dst)
466 self.assert_inode_equal(self.src, dst)
468
467
469 @skip_win32
468 @skip_win32
470 def test_no_link(self):
469 def test_no_link(self):
471 real_link = os.link
470 real_link = os.link
472 try:
471 try:
473 del os.link
472 del os.link
474 dst = self.dst("target")
473 dst = self.dst("target")
475 path.link_or_copy(self.src, dst)
474 path.link_or_copy(self.src, dst)
476 self.assert_content_equal(self.src, dst)
475 self.assert_content_equal(self.src, dst)
477 self.assert_inode_not_equal(self.src, dst)
476 self.assert_inode_not_equal(self.src, dst)
478 finally:
477 finally:
479 os.link = real_link
478 os.link = real_link
480
479
481 @skip_if_not_win32
480 @skip_if_not_win32
482 def test_windows(self):
481 def test_windows(self):
483 dst = self.dst("target")
482 dst = self.dst("target")
484 path.link_or_copy(self.src, dst)
483 path.link_or_copy(self.src, dst)
485 self.assert_content_equal(self.src, dst)
484 self.assert_content_equal(self.src, dst)
486
485
487 def test_link_twice(self):
486 def test_link_twice(self):
488 # Linking the same file twice shouldn't leave duplicates around.
487 # Linking the same file twice shouldn't leave duplicates around.
489 # See https://github.com/ipython/ipython/issues/6450
488 # See https://github.com/ipython/ipython/issues/6450
490 dst = self.dst('target')
489 dst = self.dst('target')
491 path.link_or_copy(self.src, dst)
490 path.link_or_copy(self.src, dst)
492 path.link_or_copy(self.src, dst)
491 path.link_or_copy(self.src, dst)
493 self.assert_inode_equal(self.src, dst)
492 self.assert_inode_equal(self.src, dst)
494 assert sorted(os.listdir(self.tempdir.name)) == ["src", "target"]
493 assert sorted(os.listdir(self.tempdir.name)) == ["src", "target"]
@@ -1,198 +1,197 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Tests for platutils.py
3 Tests for platutils.py
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2011 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 import sys
17 import sys
18 import signal
18 import signal
19 import os
19 import os
20 import time
20 import time
21 from _thread import interrupt_main # Py 3
21 from _thread import interrupt_main # Py 3
22 import threading
22 import threading
23 from unittest import SkipTest
24
23
25 import nose.tools as nt
24 import pytest
26
25
27 from IPython.utils.process import (find_cmd, FindCmdError, arg_split,
26 from IPython.utils.process import (find_cmd, FindCmdError, arg_split,
28 system, getoutput, getoutputerror,
27 system, getoutput, getoutputerror,
29 get_output_error_code)
28 get_output_error_code)
30 from IPython.utils.capture import capture_output
29 from IPython.utils.capture import capture_output
31 from IPython.testing import decorators as dec
30 from IPython.testing import decorators as dec
32 from IPython.testing import tools as tt
31 from IPython.testing import tools as tt
33
32
34 python = os.path.basename(sys.executable)
33 python = os.path.basename(sys.executable)
35
34
36 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
37 # Tests
36 # Tests
38 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
39
38
40
39
41 @dec.skip_win32
40 @dec.skip_win32
42 def test_find_cmd_ls():
41 def test_find_cmd_ls():
43 """Make sure we can find the full path to ls."""
42 """Make sure we can find the full path to ls."""
44 path = find_cmd('ls')
43 path = find_cmd("ls")
45 nt.assert_true(path.endswith('ls'))
44 assert path.endswith("ls")
46
45
47
46
48 def has_pywin32():
47 def has_pywin32():
49 try:
48 try:
50 import win32api
49 import win32api
51 except ImportError:
50 except ImportError:
52 return False
51 return False
53 return True
52 return True
54
53
55
54
56 @dec.onlyif(has_pywin32, "This test requires win32api to run")
55 @dec.onlyif(has_pywin32, "This test requires win32api to run")
57 def test_find_cmd_pythonw():
56 def test_find_cmd_pythonw():
58 """Try to find pythonw on Windows."""
57 """Try to find pythonw on Windows."""
59 path = find_cmd('pythonw')
58 path = find_cmd('pythonw')
60 assert path.lower().endswith('pythonw.exe'), path
59 assert path.lower().endswith('pythonw.exe'), path
61
60
62
61
63 @dec.onlyif(lambda : sys.platform != 'win32' or has_pywin32(),
62 @dec.onlyif(lambda : sys.platform != 'win32' or has_pywin32(),
64 "This test runs on posix or in win32 with win32api installed")
63 "This test runs on posix or in win32 with win32api installed")
65 def test_find_cmd_fail():
64 def test_find_cmd_fail():
66 """Make sure that FindCmdError is raised if we can't find the cmd."""
65 """Make sure that FindCmdError is raised if we can't find the cmd."""
67 nt.assert_raises(FindCmdError,find_cmd,'asdfasdf')
66 pytest.raises(FindCmdError, find_cmd, "asdfasdf")
68
67
69
68
70 # TODO: move to pytest.mark.parametrize once nose gone
69 # TODO: move to pytest.mark.parametrize once nose gone
71 @dec.skip_win32
70 @dec.skip_win32
72 def test_arg_split():
71 def test_arg_split():
73 """Ensure that argument lines are correctly split like in a shell."""
72 """Ensure that argument lines are correctly split like in a shell."""
74 tests = [['hi', ['hi']],
73 tests = [['hi', ['hi']],
75 [u'hi', [u'hi']],
74 [u'hi', [u'hi']],
76 ['hello there', ['hello', 'there']],
75 ['hello there', ['hello', 'there']],
77 # \u01ce == \N{LATIN SMALL LETTER A WITH CARON}
76 # \u01ce == \N{LATIN SMALL LETTER A WITH CARON}
78 # Do not use \N because the tests crash with syntax error in
77 # Do not use \N because the tests crash with syntax error in
79 # some cases, for example windows python2.6.
78 # some cases, for example windows python2.6.
80 [u'h\u01cello', [u'h\u01cello']],
79 [u'h\u01cello', [u'h\u01cello']],
81 ['something "with quotes"', ['something', '"with quotes"']],
80 ['something "with quotes"', ['something', '"with quotes"']],
82 ]
81 ]
83 for argstr, argv in tests:
82 for argstr, argv in tests:
84 assert arg_split(argstr) == argv
83 assert arg_split(argstr) == argv
85
84
86
85
87 # TODO: move to pytest.mark.parametrize once nose gone
86 # TODO: move to pytest.mark.parametrize once nose gone
88 @dec.skip_if_not_win32
87 @dec.skip_if_not_win32
89 def test_arg_split_win32():
88 def test_arg_split_win32():
90 """Ensure that argument lines are correctly split like in a shell."""
89 """Ensure that argument lines are correctly split like in a shell."""
91 tests = [['hi', ['hi']],
90 tests = [['hi', ['hi']],
92 [u'hi', [u'hi']],
91 [u'hi', [u'hi']],
93 ['hello there', ['hello', 'there']],
92 ['hello there', ['hello', 'there']],
94 [u'h\u01cello', [u'h\u01cello']],
93 [u'h\u01cello', [u'h\u01cello']],
95 ['something "with quotes"', ['something', 'with quotes']],
94 ['something "with quotes"', ['something', 'with quotes']],
96 ]
95 ]
97 for argstr, argv in tests:
96 for argstr, argv in tests:
98 assert arg_split(argstr) == argv
97 assert arg_split(argstr) == argv
99
98
100
99
101 class SubProcessTestCase(tt.TempFileMixin):
100 class SubProcessTestCase(tt.TempFileMixin):
102 def setUp(self):
101 def setUp(self):
103 """Make a valid python temp file."""
102 """Make a valid python temp file."""
104 lines = [ "import sys",
103 lines = [ "import sys",
105 "print('on stdout', end='', file=sys.stdout)",
104 "print('on stdout', end='', file=sys.stdout)",
106 "print('on stderr', end='', file=sys.stderr)",
105 "print('on stderr', end='', file=sys.stderr)",
107 "sys.stdout.flush()",
106 "sys.stdout.flush()",
108 "sys.stderr.flush()"]
107 "sys.stderr.flush()"]
109 self.mktmp('\n'.join(lines))
108 self.mktmp('\n'.join(lines))
110
109
111 def test_system(self):
110 def test_system(self):
112 status = system('%s "%s"' % (python, self.fname))
111 status = system('%s "%s"' % (python, self.fname))
113 self.assertEqual(status, 0)
112 self.assertEqual(status, 0)
114
113
115 def test_system_quotes(self):
114 def test_system_quotes(self):
116 status = system('%s -c "import sys"' % python)
115 status = system('%s -c "import sys"' % python)
117 self.assertEqual(status, 0)
116 self.assertEqual(status, 0)
118
117
119 def assert_interrupts(self, command):
118 def assert_interrupts(self, command):
120 """
119 """
121 Interrupt a subprocess after a second.
120 Interrupt a subprocess after a second.
122 """
121 """
123 if threading.main_thread() != threading.current_thread():
122 if threading.main_thread() != threading.current_thread():
124 raise nt.SkipTest("Can't run this test if not in main thread.")
123 raise pytest.skip("Can't run this test if not in main thread.")
125
124
126 # Some tests can overwrite SIGINT handler (by using pdb for example),
125 # Some tests can overwrite SIGINT handler (by using pdb for example),
127 # which then breaks this test, so just make sure it's operating
126 # which then breaks this test, so just make sure it's operating
128 # normally.
127 # normally.
129 signal.signal(signal.SIGINT, signal.default_int_handler)
128 signal.signal(signal.SIGINT, signal.default_int_handler)
130
129
131 def interrupt():
130 def interrupt():
132 # Wait for subprocess to start:
131 # Wait for subprocess to start:
133 time.sleep(0.5)
132 time.sleep(0.5)
134 interrupt_main()
133 interrupt_main()
135
134
136 threading.Thread(target=interrupt).start()
135 threading.Thread(target=interrupt).start()
137 start = time.time()
136 start = time.time()
138 try:
137 try:
139 result = command()
138 result = command()
140 except KeyboardInterrupt:
139 except KeyboardInterrupt:
141 # Success!
140 # Success!
142 pass
141 pass
143 end = time.time()
142 end = time.time()
144 self.assertTrue(
143 self.assertTrue(
145 end - start < 2, "Process didn't die quickly: %s" % (end - start)
144 end - start < 2, "Process didn't die quickly: %s" % (end - start)
146 )
145 )
147 return result
146 return result
148
147
149 def test_system_interrupt(self):
148 def test_system_interrupt(self):
150 """
149 """
151 When interrupted in the way ipykernel interrupts IPython, the
150 When interrupted in the way ipykernel interrupts IPython, the
152 subprocess is interrupted.
151 subprocess is interrupted.
153 """
152 """
154 def command():
153 def command():
155 return system('%s -c "import time; time.sleep(5)"' % python)
154 return system('%s -c "import time; time.sleep(5)"' % python)
156
155
157 status = self.assert_interrupts(command)
156 status = self.assert_interrupts(command)
158 self.assertNotEqual(
157 self.assertNotEqual(
159 status, 0, "The process wasn't interrupted. Status: %s" % (status,)
158 status, 0, "The process wasn't interrupted. Status: %s" % (status,)
160 )
159 )
161
160
162 def test_getoutput(self):
161 def test_getoutput(self):
163 out = getoutput('%s "%s"' % (python, self.fname))
162 out = getoutput('%s "%s"' % (python, self.fname))
164 # we can't rely on the order the line buffered streams are flushed
163 # we can't rely on the order the line buffered streams are flushed
165 try:
164 try:
166 self.assertEqual(out, 'on stderron stdout')
165 self.assertEqual(out, 'on stderron stdout')
167 except AssertionError:
166 except AssertionError:
168 self.assertEqual(out, 'on stdouton stderr')
167 self.assertEqual(out, 'on stdouton stderr')
169
168
170 def test_getoutput_quoted(self):
169 def test_getoutput_quoted(self):
171 out = getoutput('%s -c "print (1)"' % python)
170 out = getoutput('%s -c "print (1)"' % python)
172 self.assertEqual(out.strip(), '1')
171 self.assertEqual(out.strip(), '1')
173
172
174 #Invalid quoting on windows
173 #Invalid quoting on windows
175 @dec.skip_win32
174 @dec.skip_win32
176 def test_getoutput_quoted2(self):
175 def test_getoutput_quoted2(self):
177 out = getoutput("%s -c 'print (1)'" % python)
176 out = getoutput("%s -c 'print (1)'" % python)
178 self.assertEqual(out.strip(), '1')
177 self.assertEqual(out.strip(), '1')
179 out = getoutput("%s -c 'print (\"1\")'" % python)
178 out = getoutput("%s -c 'print (\"1\")'" % python)
180 self.assertEqual(out.strip(), '1')
179 self.assertEqual(out.strip(), '1')
181
180
182 def test_getoutput_error(self):
181 def test_getoutput_error(self):
183 out, err = getoutputerror('%s "%s"' % (python, self.fname))
182 out, err = getoutputerror('%s "%s"' % (python, self.fname))
184 self.assertEqual(out, 'on stdout')
183 self.assertEqual(out, 'on stdout')
185 self.assertEqual(err, 'on stderr')
184 self.assertEqual(err, 'on stderr')
186
185
187 def test_get_output_error_code(self):
186 def test_get_output_error_code(self):
188 quiet_exit = '%s -c "import sys; sys.exit(1)"' % python
187 quiet_exit = '%s -c "import sys; sys.exit(1)"' % python
189 out, err, code = get_output_error_code(quiet_exit)
188 out, err, code = get_output_error_code(quiet_exit)
190 self.assertEqual(out, '')
189 self.assertEqual(out, '')
191 self.assertEqual(err, '')
190 self.assertEqual(err, '')
192 self.assertEqual(code, 1)
191 self.assertEqual(code, 1)
193 out, err, code = get_output_error_code('%s "%s"' % (python, self.fname))
192 out, err, code = get_output_error_code('%s "%s"' % (python, self.fname))
194 self.assertEqual(out, 'on stdout')
193 self.assertEqual(out, 'on stdout')
195 self.assertEqual(err, 'on stderr')
194 self.assertEqual(err, 'on stderr')
196 self.assertEqual(code, 0)
195 self.assertEqual(code, 0)
197
196
198
197
@@ -1,76 +1,73 b''
1 # coding: utf-8
1 # coding: utf-8
2 """Test suite for our color utilities.
2 """Test suite for our color utilities.
3
3
4 Authors
4 Authors
5 -------
5 -------
6
6
7 * Min RK
7 * Min RK
8 """
8 """
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2011 The IPython Development Team
10 # Copyright (C) 2011 The IPython Development Team
11 #
11 #
12 # Distributed under the terms of the BSD License. The full license is in
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING.txt, distributed as part of this software.
13 # the file COPYING.txt, distributed as part of this software.
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 # Imports
17 # Imports
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 # third party
21 import nose.tools as nt
22
23 from IPython.testing.decorators import skip_iptest_but_not_pytest
20 from IPython.testing.decorators import skip_iptest_but_not_pytest
24
21
25 # our own
22 # our own
26 from IPython.utils.PyColorize import Parser
23 from IPython.utils.PyColorize import Parser
27 import io
24 import io
28 import pytest
25 import pytest
29
26
30
27
31 @pytest.fixture(scope="module", params=("Linux", "NoColor", "LightBG", "Neutral"))
28 @pytest.fixture(scope="module", params=("Linux", "NoColor", "LightBG", "Neutral"))
32 def style(request):
29 def style(request):
33 yield request.param
30 yield request.param
34
31
35 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
36 # Test functions
33 # Test functions
37 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
38
35
39 sample = """
36 sample = """
40 def function(arg, *args, kwarg=True, **kwargs):
37 def function(arg, *args, kwarg=True, **kwargs):
41 '''
38 '''
42 this is docs
39 this is docs
43 '''
40 '''
44 pass is True
41 pass is True
45 False == None
42 False == None
46
43
47 with io.open(ru'unicode'):
44 with io.open(ru'unicode'):
48 raise ValueError("\n escape \r sequence")
45 raise ValueError("\n escape \r sequence")
49
46
50 print("wěird ünicoðe")
47 print("wěird ünicoðe")
51
48
52 class Bar(Super):
49 class Bar(Super):
53
50
54 def __init__(self):
51 def __init__(self):
55 super(Bar, self).__init__(1**2, 3^4, 5 or 6)
52 super(Bar, self).__init__(1**2, 3^4, 5 or 6)
56 """
53 """
57
54
58
55
59 @skip_iptest_but_not_pytest
56 @skip_iptest_but_not_pytest
60 def test_parse_sample(style):
57 def test_parse_sample(style):
61 """and test writing to a buffer"""
58 """and test writing to a buffer"""
62 buf = io.StringIO()
59 buf = io.StringIO()
63 p = Parser(style=style)
60 p = Parser(style=style)
64 p.format(sample, buf)
61 p.format(sample, buf)
65 buf.seek(0)
62 buf.seek(0)
66 f1 = buf.read()
63 f1 = buf.read()
67
64
68 nt.assert_not_in("ERROR", f1)
65 assert "ERROR" not in f1
69
66
70
67
71 @skip_iptest_but_not_pytest
68 @skip_iptest_but_not_pytest
72 def test_parse_error(style):
69 def test_parse_error(style):
73 p = Parser(style=style)
70 p = Parser(style=style)
74 f1 = p.format(")", "str")
71 f1 = p.format(")", "str")
75 if style != "NoColor":
72 if style != "NoColor":
76 nt.assert_in("ERROR", f1)
73 assert "ERROR" in f1
@@ -1,17 +1,16 b''
1 # coding: utf-8
1 # coding: utf-8
2 """Test suite for our sysinfo utilities."""
2 """Test suite for our sysinfo utilities."""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7 import json
7 import json
8 import nose.tools as nt
9
8
10 from IPython.utils import sysinfo
9 from IPython.utils import sysinfo
11
10
12
11
13 def test_json_getsysinfo():
12 def test_json_getsysinfo():
14 """
13 """
15 test that it is easily jsonable and don't return bytes somewhere.
14 test that it is easily jsonable and don't return bytes somewhere.
16 """
15 """
17 json.dumps(sysinfo.get_sys_info())
16 json.dumps(sysinfo.get_sys_info())
@@ -1,205 +1,207 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """Tests for IPython.utils.text"""
2 """Tests for IPython.utils.text"""
3
3
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (C) 2011 The IPython Development Team
5 # Copyright (C) 2011 The IPython Development Team
6 #
6 #
7 # Distributed under the terms of the BSD License. The full license is in
7 # Distributed under the terms of the BSD License. The full license is in
8 # the file COPYING, distributed as part of this software.
8 # the file COPYING, distributed as part of this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 import os
15 import os
16 import math
16 import math
17 import random
17 import random
18 import sys
18 import sys
19
19
20 import nose.tools as nt
21 from pathlib import Path
20 from pathlib import Path
22
21
22 import pytest
23
23 from IPython.utils import text
24 from IPython.utils import text
24
25
25 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
26 # Globals
27 # Globals
27 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
28
29
29 def test_columnize():
30 def test_columnize():
30 """Basic columnize tests."""
31 """Basic columnize tests."""
31 size = 5
32 size = 5
32 items = [l*size for l in 'abcd']
33 items = [l*size for l in 'abcd']
33
34
34 out = text.columnize(items, displaywidth=80)
35 out = text.columnize(items, displaywidth=80)
35 assert out == "aaaaa bbbbb ccccc ddddd\n"
36 assert out == "aaaaa bbbbb ccccc ddddd\n"
36 out = text.columnize(items, displaywidth=25)
37 out = text.columnize(items, displaywidth=25)
37 assert out == "aaaaa ccccc\nbbbbb ddddd\n"
38 assert out == "aaaaa ccccc\nbbbbb ddddd\n"
38 out = text.columnize(items, displaywidth=12)
39 out = text.columnize(items, displaywidth=12)
39 assert out == "aaaaa ccccc\nbbbbb ddddd\n"
40 assert out == "aaaaa ccccc\nbbbbb ddddd\n"
40 out = text.columnize(items, displaywidth=10)
41 out = text.columnize(items, displaywidth=10)
41 assert out == "aaaaa\nbbbbb\nccccc\nddddd\n"
42 assert out == "aaaaa\nbbbbb\nccccc\nddddd\n"
42
43
43 out = text.columnize(items, row_first=True, displaywidth=80)
44 out = text.columnize(items, row_first=True, displaywidth=80)
44 assert out == "aaaaa bbbbb ccccc ddddd\n"
45 assert out == "aaaaa bbbbb ccccc ddddd\n"
45 out = text.columnize(items, row_first=True, displaywidth=25)
46 out = text.columnize(items, row_first=True, displaywidth=25)
46 assert out == "aaaaa bbbbb\nccccc ddddd\n"
47 assert out == "aaaaa bbbbb\nccccc ddddd\n"
47 out = text.columnize(items, row_first=True, displaywidth=12)
48 out = text.columnize(items, row_first=True, displaywidth=12)
48 assert out == "aaaaa bbbbb\nccccc ddddd\n"
49 assert out == "aaaaa bbbbb\nccccc ddddd\n"
49 out = text.columnize(items, row_first=True, displaywidth=10)
50 out = text.columnize(items, row_first=True, displaywidth=10)
50 assert out == "aaaaa\nbbbbb\nccccc\nddddd\n"
51 assert out == "aaaaa\nbbbbb\nccccc\nddddd\n"
51
52
52 out = text.columnize(items, displaywidth=40, spread=True)
53 out = text.columnize(items, displaywidth=40, spread=True)
53 assert out == "aaaaa bbbbb ccccc ddddd\n"
54 assert out == "aaaaa bbbbb ccccc ddddd\n"
54 out = text.columnize(items, displaywidth=20, spread=True)
55 out = text.columnize(items, displaywidth=20, spread=True)
55 assert out == "aaaaa ccccc\nbbbbb ddddd\n"
56 assert out == "aaaaa ccccc\nbbbbb ddddd\n"
56 out = text.columnize(items, displaywidth=12, spread=True)
57 out = text.columnize(items, displaywidth=12, spread=True)
57 assert out == "aaaaa ccccc\nbbbbb ddddd\n"
58 assert out == "aaaaa ccccc\nbbbbb ddddd\n"
58 out = text.columnize(items, displaywidth=10, spread=True)
59 out = text.columnize(items, displaywidth=10, spread=True)
59 assert out == "aaaaa\nbbbbb\nccccc\nddddd\n"
60 assert out == "aaaaa\nbbbbb\nccccc\nddddd\n"
60
61
61
62
62 def test_columnize_random():
63 def test_columnize_random():
63 """Test with random input to hopefully catch edge case """
64 """Test with random input to hopefully catch edge case """
64 for row_first in [True, False]:
65 for row_first in [True, False]:
65 for nitems in [random.randint(2,70) for i in range(2,20)]:
66 for nitems in [random.randint(2,70) for i in range(2,20)]:
66 displaywidth = random.randint(20,200)
67 displaywidth = random.randint(20,200)
67 rand_len = [random.randint(2,displaywidth) for i in range(nitems)]
68 rand_len = [random.randint(2,displaywidth) for i in range(nitems)]
68 items = ['x'*l for l in rand_len]
69 items = ['x'*l for l in rand_len]
69 out = text.columnize(items, row_first=row_first, displaywidth=displaywidth)
70 out = text.columnize(items, row_first=row_first, displaywidth=displaywidth)
70 longer_line = max([len(x) for x in out.split('\n')])
71 longer_line = max([len(x) for x in out.split('\n')])
71 longer_element = max(rand_len)
72 longer_element = max(rand_len)
72 if longer_line > displaywidth:
73 if longer_line > displaywidth:
73 print("Columnize displayed something lager than displaywidth : %s " % longer_line)
74 print("Columnize displayed something lager than displaywidth : %s " % longer_line)
74 print("longer element : %s " % longer_element)
75 print("longer element : %s " % longer_element)
75 print("displaywidth : %s " % displaywidth)
76 print("displaywidth : %s " % displaywidth)
76 print("number of element : %s " % nitems)
77 print("number of element : %s " % nitems)
77 print("size of each element :\n %s" % rand_len)
78 print("size of each element :\n %s" % rand_len)
78 assert False, "row_first={0}".format(row_first)
79 assert False, "row_first={0}".format(row_first)
79
80
80
81
81 # TODO: pytest mark.parametrize once nose removed.
82 # TODO: pytest mark.parametrize once nose removed.
82 def test_columnize_medium():
83 def test_columnize_medium():
83 """Test with inputs than shouldn't be wider than 80"""
84 """Test with inputs than shouldn't be wider than 80"""
84 size = 40
85 size = 40
85 items = [l*size for l in 'abc']
86 items = [l*size for l in 'abc']
86 for row_first in [True, False]:
87 for row_first in [True, False]:
87 out = text.columnize(items, row_first=row_first, displaywidth=80)
88 out = text.columnize(items, row_first=row_first, displaywidth=80)
88 assert out == "\n".join(items + [""]), "row_first={0}".format(row_first)
89 assert out == "\n".join(items + [""]), "row_first={0}".format(row_first)
89
90
90
91
91 # TODO: pytest mark.parametrize once nose removed.
92 # TODO: pytest mark.parametrize once nose removed.
92 def test_columnize_long():
93 def test_columnize_long():
93 """Test columnize with inputs longer than the display window"""
94 """Test columnize with inputs longer than the display window"""
94 size = 11
95 size = 11
95 items = [l*size for l in 'abc']
96 items = [l*size for l in 'abc']
96 for row_first in [True, False]:
97 for row_first in [True, False]:
97 out = text.columnize(items, row_first=row_first, displaywidth=size - 1)
98 out = text.columnize(items, row_first=row_first, displaywidth=size - 1)
98 assert out == "\n".join(items + [""]), "row_first={0}".format(row_first)
99 assert out == "\n".join(items + [""]), "row_first={0}".format(row_first)
99
100
100
101
101 def eval_formatter_check(f):
102 def eval_formatter_check(f):
102 ns = dict(n=12, pi=math.pi, stuff='hello there', os=os, u=u"café", b="café")
103 ns = dict(n=12, pi=math.pi, stuff='hello there', os=os, u=u"café", b="café")
103 s = f.format("{n} {n//4} {stuff.split()[0]}", **ns)
104 s = f.format("{n} {n//4} {stuff.split()[0]}", **ns)
104 assert s == "12 3 hello"
105 assert s == "12 3 hello"
105 s = f.format(' '.join(['{n//%i}'%i for i in range(1,8)]), **ns)
106 s = f.format(' '.join(['{n//%i}'%i for i in range(1,8)]), **ns)
106 assert s == "12 6 4 3 2 2 1"
107 assert s == "12 6 4 3 2 2 1"
107 s = f.format('{[n//i for i in range(1,8)]}', **ns)
108 s = f.format('{[n//i for i in range(1,8)]}', **ns)
108 assert s == "[12, 6, 4, 3, 2, 2, 1]"
109 assert s == "[12, 6, 4, 3, 2, 2, 1]"
109 s = f.format("{stuff!s}", **ns)
110 s = f.format("{stuff!s}", **ns)
110 assert s == ns["stuff"]
111 assert s == ns["stuff"]
111 s = f.format("{stuff!r}", **ns)
112 s = f.format("{stuff!r}", **ns)
112 assert s == repr(ns["stuff"])
113 assert s == repr(ns["stuff"])
113
114
114 # Check with unicode:
115 # Check with unicode:
115 s = f.format("{u}", **ns)
116 s = f.format("{u}", **ns)
116 assert s == ns["u"]
117 assert s == ns["u"]
117 # This decodes in a platform dependent manner, but it shouldn't error out
118 # This decodes in a platform dependent manner, but it shouldn't error out
118 s = f.format("{b}", **ns)
119 s = f.format("{b}", **ns)
119
120
120 nt.assert_raises(NameError, f.format, '{dne}', **ns)
121 pytest.raises(NameError, f.format, "{dne}", **ns)
122
121
123
122 def eval_formatter_slicing_check(f):
124 def eval_formatter_slicing_check(f):
123 ns = dict(n=12, pi=math.pi, stuff='hello there', os=os)
125 ns = dict(n=12, pi=math.pi, stuff='hello there', os=os)
124 s = f.format(" {stuff.split()[:]} ", **ns)
126 s = f.format(" {stuff.split()[:]} ", **ns)
125 assert s == " ['hello', 'there'] "
127 assert s == " ['hello', 'there'] "
126 s = f.format(" {stuff.split()[::-1]} ", **ns)
128 s = f.format(" {stuff.split()[::-1]} ", **ns)
127 assert s == " ['there', 'hello'] "
129 assert s == " ['there', 'hello'] "
128 s = f.format("{stuff[::2]}", **ns)
130 s = f.format("{stuff[::2]}", **ns)
129 assert s == ns["stuff"][::2]
131 assert s == ns["stuff"][::2]
130
132
131 nt.assert_raises(SyntaxError, f.format, "{n:x}", **ns)
133 pytest.raises(SyntaxError, f.format, "{n:x}", **ns)
132
134
133 def eval_formatter_no_slicing_check(f):
135 def eval_formatter_no_slicing_check(f):
134 ns = dict(n=12, pi=math.pi, stuff='hello there', os=os)
136 ns = dict(n=12, pi=math.pi, stuff='hello there', os=os)
135
137
136 s = f.format('{n:x} {pi**2:+f}', **ns)
138 s = f.format('{n:x} {pi**2:+f}', **ns)
137 assert s == "c +9.869604"
139 assert s == "c +9.869604"
138
140
139 s = f.format("{stuff[slice(1,4)]}", **ns)
141 s = f.format("{stuff[slice(1,4)]}", **ns)
140 assert s == "ell"
142 assert s == "ell"
141
143
142 s = f.format("{a[:]}", a=[1, 2])
144 s = f.format("{a[:]}", a=[1, 2])
143 assert s == "[1, 2]"
145 assert s == "[1, 2]"
144
146
145 def test_eval_formatter():
147 def test_eval_formatter():
146 f = text.EvalFormatter()
148 f = text.EvalFormatter()
147 eval_formatter_check(f)
149 eval_formatter_check(f)
148 eval_formatter_no_slicing_check(f)
150 eval_formatter_no_slicing_check(f)
149
151
150 def test_full_eval_formatter():
152 def test_full_eval_formatter():
151 f = text.FullEvalFormatter()
153 f = text.FullEvalFormatter()
152 eval_formatter_check(f)
154 eval_formatter_check(f)
153 eval_formatter_slicing_check(f)
155 eval_formatter_slicing_check(f)
154
156
155 def test_dollar_formatter():
157 def test_dollar_formatter():
156 f = text.DollarFormatter()
158 f = text.DollarFormatter()
157 eval_formatter_check(f)
159 eval_formatter_check(f)
158 eval_formatter_slicing_check(f)
160 eval_formatter_slicing_check(f)
159
161
160 ns = dict(n=12, pi=math.pi, stuff='hello there', os=os)
162 ns = dict(n=12, pi=math.pi, stuff='hello there', os=os)
161 s = f.format("$n", **ns)
163 s = f.format("$n", **ns)
162 assert s == "12"
164 assert s == "12"
163 s = f.format("$n.real", **ns)
165 s = f.format("$n.real", **ns)
164 assert s == "12"
166 assert s == "12"
165 s = f.format("$n/{stuff[:5]}", **ns)
167 s = f.format("$n/{stuff[:5]}", **ns)
166 assert s == "12/hello"
168 assert s == "12/hello"
167 s = f.format("$n $$HOME", **ns)
169 s = f.format("$n $$HOME", **ns)
168 assert s == "12 $HOME"
170 assert s == "12 $HOME"
169 s = f.format("${foo}", foo="HOME")
171 s = f.format("${foo}", foo="HOME")
170 assert s == "$HOME"
172 assert s == "$HOME"
171
173
172
174
173 def test_strip_email():
175 def test_strip_email():
174 src = """\
176 src = """\
175 >> >>> def f(x):
177 >> >>> def f(x):
176 >> ... return x+1
178 >> ... return x+1
177 >> ...
179 >> ...
178 >> >>> zz = f(2.5)"""
180 >> >>> zz = f(2.5)"""
179 cln = """\
181 cln = """\
180 >>> def f(x):
182 >>> def f(x):
181 ... return x+1
183 ... return x+1
182 ...
184 ...
183 >>> zz = f(2.5)"""
185 >>> zz = f(2.5)"""
184 assert text.strip_email_quotes(src) == cln
186 assert text.strip_email_quotes(src) == cln
185
187
186
188
187 def test_strip_email2():
189 def test_strip_email2():
188 src = '> > > list()'
190 src = '> > > list()'
189 cln = 'list()'
191 cln = 'list()'
190 assert text.strip_email_quotes(src) == cln
192 assert text.strip_email_quotes(src) == cln
191
193
192 def test_LSString():
194 def test_LSString():
193 lss = text.LSString("abc\ndef")
195 lss = text.LSString("abc\ndef")
194 assert lss.l == ["abc", "def"]
196 assert lss.l == ["abc", "def"]
195 assert lss.s == "abc def"
197 assert lss.s == "abc def"
196 lss = text.LSString(os.getcwd())
198 lss = text.LSString(os.getcwd())
197 nt.assert_is_instance(lss.p[0], Path)
199 assert isinstance(lss.p[0], Path)
198
200
199 def test_SList():
201 def test_SList():
200 sl = text.SList(["a 11", "b 1", "a 2"])
202 sl = text.SList(["a 11", "b 1", "a 2"])
201 assert sl.n == "a 11\nb 1\na 2"
203 assert sl.n == "a 11\nb 1\na 2"
202 assert sl.s == "a 11 b 1 a 2"
204 assert sl.s == "a 11 b 1 a 2"
203 assert sl.grep(lambda x: x.startswith("a")) == text.SList(["a 11", "a 2"])
205 assert sl.grep(lambda x: x.startswith("a")) == text.SList(["a 11", "a 2"])
204 assert sl.fields(0) == text.SList(["a", "b", "a"])
206 assert sl.fields(0) == text.SList(["a", "b", "a"])
205 assert sl.sort(field=1, nums=True) == text.SList(["b 1", "a 2", "a 11"])
207 assert sl.sort(field=1, nums=True) == text.SList(["b 1", "a 2", "a 11"])
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now