##// 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 1 # coding: utf-8
2 2 """Tests for IPython.core.application"""
3 3
4 4 import os
5 5 import tempfile
6 6
7 import nose.tools as nt
8
9 7 from traitlets import Unicode
10 8
11 9 from IPython.core.application import BaseIPythonApplication
12 10 from IPython.testing import decorators as dec
13 11 from IPython.utils.tempdir import TemporaryDirectory
14 12
15 13
16 14 @dec.onlyif_unicode_paths
17 15 def test_unicode_cwd():
18 16 """Check that IPython starts with non-ascii characters in the path."""
19 17 wd = tempfile.mkdtemp(suffix=u"€")
20 18
21 19 old_wd = os.getcwd()
22 20 os.chdir(wd)
23 21 #raise Exception(repr(os.getcwd()))
24 22 try:
25 23 app = BaseIPythonApplication()
26 24 # The lines below are copied from Application.initialize()
27 25 app.init_profile_dir()
28 26 app.init_config_files()
29 27 app.load_config_file(suppress_errors=False)
30 28 finally:
31 29 os.chdir(old_wd)
32 30
33 31 @dec.onlyif_unicode_paths
34 32 def test_unicode_ipdir():
35 33 """Check that IPython starts with non-ascii characters in the IP dir."""
36 34 ipdir = tempfile.mkdtemp(suffix=u"€")
37 35
38 36 # Create the config file, so it tries to load it.
39 37 with open(os.path.join(ipdir, 'ipython_config.py'), "w") as f:
40 38 pass
41 39
42 40 old_ipdir1 = os.environ.pop("IPYTHONDIR", None)
43 41 old_ipdir2 = os.environ.pop("IPYTHON_DIR", None)
44 42 os.environ["IPYTHONDIR"] = ipdir
45 43 try:
46 44 app = BaseIPythonApplication()
47 45 # The lines below are copied from Application.initialize()
48 46 app.init_profile_dir()
49 47 app.init_config_files()
50 48 app.load_config_file(suppress_errors=False)
51 49 finally:
52 50 if old_ipdir1:
53 51 os.environ["IPYTHONDIR"] = old_ipdir1
54 52 if old_ipdir2:
55 53 os.environ["IPYTHONDIR"] = old_ipdir2
56 54
57 55 def test_cli_priority():
58 56 with TemporaryDirectory() as td:
59 57
60 58 class TestApp(BaseIPythonApplication):
61 59 test = Unicode().tag(config=True)
62 60
63 61 # Create the config file, so it tries to load it.
64 62 with open(os.path.join(td, 'ipython_config.py'), "w") as f:
65 63 f.write("c.TestApp.test = 'config file'")
66 64
67 65 app = TestApp()
68 app.initialize(['--profile-dir', td])
69 nt.assert_equal(app.test, 'config file')
66 app.initialize(["--profile-dir", td])
67 assert app.test == "config file"
70 68 app = TestApp()
71 app.initialize(['--profile-dir', td, '--TestApp.test=cli'])
72 nt.assert_equal(app.test, 'cli')
73
69 app.initialize(["--profile-dir", td, "--TestApp.test=cli"])
70 assert app.test == "cli"
@@ -1,316 +1,315 b''
1 1 """
2 2 Test for async helpers.
3 3
4 4 Should only trigger on python 3.5+ or will have syntax errors.
5 5 """
6 6 from itertools import chain, repeat
7 import nose.tools as nt
8 7 from textwrap import dedent, indent
9 8 from unittest import TestCase
10 9 from IPython.testing.decorators import skip_without
11 10 import sys
12 11 from typing import TYPE_CHECKING
13 12
14 13 if TYPE_CHECKING:
15 14 from IPython import get_ipython
16 15
17 16 ip = get_ipython()
18 17
19 18
20 19 iprc = lambda x: ip.run_cell(dedent(x)).raise_error()
21 20 iprc_nr = lambda x: ip.run_cell(dedent(x))
22 21
23 22 from IPython.core.async_helpers import _should_be_async
24 23
25 24 class AsyncTest(TestCase):
26 25 def test_should_be_async(self):
27 nt.assert_false(_should_be_async("False"))
28 nt.assert_true(_should_be_async("await bar()"))
29 nt.assert_true(_should_be_async("x = await bar()"))
30 nt.assert_false(
26 self.assertFalse(_should_be_async("False"))
27 self.assertTrue(_should_be_async("await bar()"))
28 self.assertTrue(_should_be_async("x = await bar()"))
29 self.assertFalse(
31 30 _should_be_async(
32 31 dedent(
33 32 """
34 33 async def awaitable():
35 34 pass
36 35 """
37 36 )
38 37 )
39 38 )
40 39
41 40 def _get_top_level_cases(self):
42 41 # These are test cases that should be valid in a function
43 42 # but invalid outside of a function.
44 43 test_cases = []
45 44 test_cases.append(('basic', "{val}"))
46 45
47 46 # Note, in all conditional cases, I use True instead of
48 47 # False so that the peephole optimizer won't optimize away
49 48 # the return, so CPython will see this as a syntax error:
50 49 #
51 50 # while True:
52 51 # break
53 52 # return
54 53 #
55 54 # But not this:
56 55 #
57 56 # while False:
58 57 # return
59 58 #
60 59 # See https://bugs.python.org/issue1875
61 60
62 61 test_cases.append(('if', dedent("""
63 62 if True:
64 63 {val}
65 64 """)))
66 65
67 66 test_cases.append(('while', dedent("""
68 67 while True:
69 68 {val}
70 69 break
71 70 """)))
72 71
73 72 test_cases.append(('try', dedent("""
74 73 try:
75 74 {val}
76 75 except:
77 76 pass
78 77 """)))
79 78
80 79 test_cases.append(('except', dedent("""
81 80 try:
82 81 pass
83 82 except:
84 83 {val}
85 84 """)))
86 85
87 86 test_cases.append(('finally', dedent("""
88 87 try:
89 88 pass
90 89 except:
91 90 pass
92 91 finally:
93 92 {val}
94 93 """)))
95 94
96 95 test_cases.append(('for', dedent("""
97 96 for _ in range(4):
98 97 {val}
99 98 """)))
100 99
101 100
102 101 test_cases.append(('nested', dedent("""
103 102 if True:
104 103 while True:
105 104 {val}
106 105 break
107 106 """)))
108 107
109 108 test_cases.append(('deep-nested', dedent("""
110 109 if True:
111 110 while True:
112 111 break
113 112 for x in range(3):
114 113 if True:
115 114 while True:
116 115 for x in range(3):
117 116 {val}
118 117 """)))
119 118
120 119 return test_cases
121 120
122 121 def _get_ry_syntax_errors(self):
123 122 # This is a mix of tests that should be a syntax error if
124 123 # return or yield whether or not they are in a function
125 124
126 125 test_cases = []
127 126
128 127 test_cases.append(('class', dedent("""
129 128 class V:
130 129 {val}
131 130 """)))
132 131
133 132 test_cases.append(('nested-class', dedent("""
134 133 class V:
135 134 class C:
136 135 {val}
137 136 """)))
138 137
139 138 return test_cases
140 139
141 140
142 141 def test_top_level_return_error(self):
143 142 tl_err_test_cases = self._get_top_level_cases()
144 143 tl_err_test_cases.extend(self._get_ry_syntax_errors())
145 144
146 145 vals = ('return', 'yield', 'yield from (_ for _ in range(3))',
147 146 dedent('''
148 147 def f():
149 148 pass
150 149 return
151 150 '''),
152 151 )
153 152
154 153 for test_name, test_case in tl_err_test_cases:
155 154 # This example should work if 'pass' is used as the value
156 155 with self.subTest((test_name, 'pass')):
157 156 iprc(test_case.format(val='pass'))
158 157
159 158 # It should fail with all the values
160 159 for val in vals:
161 160 with self.subTest((test_name, val)):
162 161 msg = "Syntax error not raised for %s, %s" % (test_name, val)
163 162 with self.assertRaises(SyntaxError, msg=msg):
164 163 iprc(test_case.format(val=val))
165 164
166 165 def test_in_func_no_error(self):
167 166 # Test that the implementation of top-level return/yield
168 167 # detection isn't *too* aggressive, and works inside a function
169 168 func_contexts = []
170 169
171 170 func_contexts.append(('func', False, dedent("""
172 171 def f():""")))
173 172
174 173 func_contexts.append(('method', False, dedent("""
175 174 class MyClass:
176 175 def __init__(self):
177 176 """)))
178 177
179 178 func_contexts.append(('async-func', True, dedent("""
180 179 async def f():""")))
181 180
182 181 func_contexts.append(('async-method', True, dedent("""
183 182 class MyClass:
184 183 async def f(self):""")))
185 184
186 185 func_contexts.append(('closure', False, dedent("""
187 186 def f():
188 187 def g():
189 188 """)))
190 189
191 190 def nest_case(context, case):
192 191 # Detect indentation
193 192 lines = context.strip().splitlines()
194 193 prefix_len = 0
195 194 for c in lines[-1]:
196 195 if c != ' ':
197 196 break
198 197 prefix_len += 1
199 198
200 199 indented_case = indent(case, ' ' * (prefix_len + 4))
201 200 return context + '\n' + indented_case
202 201
203 202 # Gather and run the tests
204 203
205 204 # yield is allowed in async functions, starting in Python 3.6,
206 205 # and yield from is not allowed in any version
207 206 vals = ('return', 'yield', 'yield from (_ for _ in range(3))')
208 207
209 208 success_tests = zip(self._get_top_level_cases(), repeat(False))
210 209 failure_tests = zip(self._get_ry_syntax_errors(), repeat(True))
211 210
212 211 tests = chain(success_tests, failure_tests)
213 212
214 213 for context_name, async_func, context in func_contexts:
215 214 for (test_name, test_case), should_fail in tests:
216 215 nested_case = nest_case(context, test_case)
217 216
218 217 for val in vals:
219 218 test_id = (context_name, test_name, val)
220 219 cell = nested_case.format(val=val)
221 220
222 221 with self.subTest(test_id):
223 222 if should_fail:
224 223 msg = ("SyntaxError not raised for %s" %
225 224 str(test_id))
226 225 with self.assertRaises(SyntaxError, msg=msg):
227 226 iprc(cell)
228 227
229 228 print(cell)
230 229 else:
231 230 iprc(cell)
232 231
233 232 def test_nonlocal(self):
234 233 # fails if outer scope is not a function scope or if var not defined
235 234 with self.assertRaises(SyntaxError):
236 235 iprc("nonlocal x")
237 236 iprc("""
238 237 x = 1
239 238 def f():
240 239 nonlocal x
241 240 x = 10000
242 241 yield x
243 242 """)
244 243 iprc("""
245 244 def f():
246 245 def g():
247 246 nonlocal x
248 247 x = 10000
249 248 yield x
250 249 """)
251 250
252 251 # works if outer scope is a function scope and var exists
253 252 iprc("""
254 253 def f():
255 254 x = 20
256 255 def g():
257 256 nonlocal x
258 257 x = 10000
259 258 yield x
260 259 """)
261 260
262 261
263 262 def test_execute(self):
264 263 iprc("""
265 264 import asyncio
266 265 await asyncio.sleep(0.001)
267 266 """
268 267 )
269 268
270 269 def test_autoawait(self):
271 270 iprc("%autoawait False")
272 271 iprc("%autoawait True")
273 272 iprc("""
274 273 from asyncio import sleep
275 274 await sleep(0.1)
276 275 """
277 276 )
278 277
279 278 if sys.version_info < (3,9):
280 279 # new pgen parser in 3.9 does not raise MemoryError on too many nested
281 280 # parens anymore
282 281 def test_memory_error(self):
283 282 with self.assertRaises(MemoryError):
284 283 iprc("(" * 200 + ")" * 200)
285 284
286 285 @skip_without('curio')
287 286 def test_autoawait_curio(self):
288 287 iprc("%autoawait curio")
289 288
290 289 @skip_without('trio')
291 290 def test_autoawait_trio(self):
292 291 iprc("%autoawait trio")
293 292
294 293 @skip_without('trio')
295 294 def test_autoawait_trio_wrong_sleep(self):
296 295 iprc("%autoawait trio")
297 296 res = iprc_nr("""
298 297 import asyncio
299 298 await asyncio.sleep(0)
300 299 """)
301 with nt.assert_raises(TypeError):
300 with self.assertRaises(TypeError):
302 301 res.raise_error()
303 302
304 303 @skip_without('trio')
305 304 def test_autoawait_asyncio_wrong_sleep(self):
306 305 iprc("%autoawait asyncio")
307 306 res = iprc_nr("""
308 307 import trio
309 308 await trio.sleep(0)
310 309 """)
311 with nt.assert_raises(RuntimeError):
310 with self.assertRaises(RuntimeError):
312 311 res.raise_error()
313 312
314 313
315 314 def tearDown(self):
316 315 ip.loop_runner = "asyncio"
@@ -1,1278 +1,1274 b''
1 1 # encoding: utf-8
2 2 """Tests for the IPython tab-completion machinery."""
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7 import os
8 8 import sys
9 9 import textwrap
10 10 import unittest
11 11
12 12 from contextlib import contextmanager
13 13
14 import nose.tools as nt
15
16 14 from traitlets.config.loader import Config
17 15 from IPython import get_ipython
18 16 from IPython.core import completer
19 17 from IPython.external import decorators
20 18 from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory
21 19 from IPython.utils.generics import complete_object
22 20 from IPython.testing import decorators as dec
23 21
24 22 from IPython.core.completer import (
25 23 Completion,
26 24 provisionalcompleter,
27 25 match_dict_keys,
28 26 _deduplicate_completions,
29 27 )
30 from nose.tools import assert_in, assert_not_in
31 28
32 29 # -----------------------------------------------------------------------------
33 30 # Test functions
34 31 # -----------------------------------------------------------------------------
35 32
36 33 def recompute_unicode_ranges():
37 34 """
38 35 utility to recompute the largest unicode range without any characters
39 36
40 37 use to recompute the gap in the global _UNICODE_RANGES of completer.py
41 38 """
42 39 import itertools
43 40 import unicodedata
44 41 valid = []
45 42 for c in range(0,0x10FFFF + 1):
46 43 try:
47 44 unicodedata.name(chr(c))
48 45 except ValueError:
49 46 continue
50 47 valid.append(c)
51 48
52 49 def ranges(i):
53 50 for a, b in itertools.groupby(enumerate(i), lambda pair: pair[1] - pair[0]):
54 51 b = list(b)
55 52 yield b[0][1], b[-1][1]
56 53
57 54 rg = list(ranges(valid))
58 55 lens = []
59 56 gap_lens = []
60 57 pstart, pstop = 0,0
61 58 for start, stop in rg:
62 59 lens.append(stop-start)
63 60 gap_lens.append((start - pstop, hex(pstop), hex(start), f'{round((start - pstop)/0xe01f0*100)}%'))
64 61 pstart, pstop = start, stop
65 62
66 63 return sorted(gap_lens)[-1]
67 64
68 65
69 66
70 67 def test_unicode_range():
71 68 """
72 69 Test that the ranges we test for unicode names give the same number of
73 70 results than testing the full length.
74 71 """
75 72 from IPython.core.completer import _unicode_name_compute, _UNICODE_RANGES
76 73
77 74 expected_list = _unicode_name_compute([(0, 0x110000)])
78 75 test = _unicode_name_compute(_UNICODE_RANGES)
79 76 len_exp = len(expected_list)
80 77 len_test = len(test)
81 78
82 79 # do not inline the len() or on error pytest will try to print the 130 000 +
83 80 # elements.
84 81 message = None
85 82 if len_exp != len_test or len_exp > 131808:
86 83 size, start, stop, prct = recompute_unicode_ranges()
87 84 message = f"""_UNICODE_RANGES likely wrong and need updating. This is
88 85 likely due to a new release of Python. We've find that the biggest gap
89 86 in unicode characters has reduces in size to be {size} characters
90 87 ({prct}), from {start}, to {stop}. In completer.py likely update to
91 88
92 89 _UNICODE_RANGES = [(32, {start}), ({stop}, 0xe01f0)]
93 90
94 91 And update the assertion below to use
95 92
96 93 len_exp <= {len_exp}
97 94 """
98 95 assert len_exp == len_test, message
99 96
100 97 # fail if new unicode symbols have been added.
101 98 assert len_exp <= 137714, message
102 99
103 100
104 101 @contextmanager
105 102 def greedy_completion():
106 103 ip = get_ipython()
107 104 greedy_original = ip.Completer.greedy
108 105 try:
109 106 ip.Completer.greedy = True
110 107 yield
111 108 finally:
112 109 ip.Completer.greedy = greedy_original
113 110
114 111
115 112 def test_protect_filename():
116 113 if sys.platform == "win32":
117 114 pairs = [
118 115 ("abc", "abc"),
119 116 (" abc", '" abc"'),
120 117 ("a bc", '"a bc"'),
121 118 ("a bc", '"a bc"'),
122 119 (" bc", '" bc"'),
123 120 ]
124 121 else:
125 122 pairs = [
126 123 ("abc", "abc"),
127 124 (" abc", r"\ abc"),
128 125 ("a bc", r"a\ bc"),
129 126 ("a bc", r"a\ \ bc"),
130 127 (" bc", r"\ \ bc"),
131 128 # On posix, we also protect parens and other special characters.
132 129 ("a(bc", r"a\(bc"),
133 130 ("a)bc", r"a\)bc"),
134 131 ("a( )bc", r"a\(\ \)bc"),
135 132 ("a[1]bc", r"a\[1\]bc"),
136 133 ("a{1}bc", r"a\{1\}bc"),
137 134 ("a#bc", r"a\#bc"),
138 135 ("a?bc", r"a\?bc"),
139 136 ("a=bc", r"a\=bc"),
140 137 ("a\\bc", r"a\\bc"),
141 138 ("a|bc", r"a\|bc"),
142 139 ("a;bc", r"a\;bc"),
143 140 ("a:bc", r"a\:bc"),
144 141 ("a'bc", r"a\'bc"),
145 142 ("a*bc", r"a\*bc"),
146 143 ('a"bc', r"a\"bc"),
147 144 ("a^bc", r"a\^bc"),
148 145 ("a&bc", r"a\&bc"),
149 146 ]
150 147 # run the actual tests
151 148 for s1, s2 in pairs:
152 149 s1p = completer.protect_filename(s1)
153 nt.assert_equal(s1p, s2)
150 assert s1p == s2
154 151
155 152
156 153 def check_line_split(splitter, test_specs):
157 154 for part1, part2, split in test_specs:
158 155 cursor_pos = len(part1)
159 156 line = part1 + part2
160 157 out = splitter.split_line(line, cursor_pos)
161 nt.assert_equal(out, split)
158 assert out == split
162 159
163 160
164 161 def test_line_split():
165 162 """Basic line splitter test with default specs."""
166 163 sp = completer.CompletionSplitter()
167 164 # The format of the test specs is: part1, part2, expected answer. Parts 1
168 165 # and 2 are joined into the 'line' sent to the splitter, as if the cursor
169 166 # was at the end of part1. So an empty part2 represents someone hitting
170 167 # tab at the end of the line, the most common case.
171 168 t = [
172 169 ("run some/scrip", "", "some/scrip"),
173 170 ("run scripts/er", "ror.py foo", "scripts/er"),
174 171 ("echo $HOM", "", "HOM"),
175 172 ("print sys.pa", "", "sys.pa"),
176 173 ("print(sys.pa", "", "sys.pa"),
177 174 ("execfile('scripts/er", "", "scripts/er"),
178 175 ("a[x.", "", "x."),
179 176 ("a[x.", "y", "x."),
180 177 ('cd "some_file/', "", "some_file/"),
181 178 ]
182 179 check_line_split(sp, t)
183 180 # Ensure splitting works OK with unicode by re-running the tests with
184 181 # all inputs turned into unicode
185 182 check_line_split(sp, [map(str, p) for p in t])
186 183
187 184
188 185 class NamedInstanceMetaclass(type):
189 186 def __getitem__(cls, item):
190 187 return cls.get_instance(item)
191 188
192 189
193 190 class NamedInstanceClass(metaclass=NamedInstanceMetaclass):
194 191 def __init__(self, name):
195 192 if not hasattr(self.__class__, "instances"):
196 193 self.__class__.instances = {}
197 194 self.__class__.instances[name] = self
198 195
199 196 @classmethod
200 197 def _ipython_key_completions_(cls):
201 198 return cls.instances.keys()
202 199
203 200 @classmethod
204 201 def get_instance(cls, name):
205 202 return cls.instances[name]
206 203
207 204
208 205 class KeyCompletable:
209 206 def __init__(self, things=()):
210 207 self.things = things
211 208
212 209 def _ipython_key_completions_(self):
213 210 return list(self.things)
214 211
215 212
216 213 class TestCompleter(unittest.TestCase):
217 214 def setUp(self):
218 215 """
219 216 We want to silence all PendingDeprecationWarning when testing the completer
220 217 """
221 218 self._assertwarns = self.assertWarns(PendingDeprecationWarning)
222 219 self._assertwarns.__enter__()
223 220
224 221 def tearDown(self):
225 222 try:
226 223 self._assertwarns.__exit__(None, None, None)
227 224 except AssertionError:
228 225 pass
229 226
230 227 def test_custom_completion_error(self):
231 228 """Test that errors from custom attribute completers are silenced."""
232 229 ip = get_ipython()
233 230
234 231 class A:
235 232 pass
236 233
237 234 ip.user_ns["x"] = A()
238 235
239 236 @complete_object.register(A)
240 237 def complete_A(a, existing_completions):
241 238 raise TypeError("this should be silenced")
242 239
243 240 ip.complete("x.")
244 241
245 242 def test_custom_completion_ordering(self):
246 243 """Test that errors from custom attribute completers are silenced."""
247 244 ip = get_ipython()
248 245
249 246 _, matches = ip.complete('in')
250 247 assert matches.index('input') < matches.index('int')
251 248
252 249 def complete_example(a):
253 250 return ['example2', 'example1']
254 251
255 252 ip.Completer.custom_completers.add_re('ex*', complete_example)
256 253 _, matches = ip.complete('ex')
257 254 assert matches.index('example2') < matches.index('example1')
258 255
259 256 def test_unicode_completions(self):
260 257 ip = get_ipython()
261 258 # Some strings that trigger different types of completion. Check them both
262 259 # in str and unicode forms
263 260 s = ["ru", "%ru", "cd /", "floa", "float(x)/"]
264 261 for t in s + list(map(str, s)):
265 262 # We don't need to check exact completion values (they may change
266 263 # depending on the state of the namespace, but at least no exceptions
267 264 # should be thrown and the return value should be a pair of text, list
268 265 # values.
269 266 text, matches = ip.complete(t)
270 nt.assert_true(isinstance(text, str))
271 nt.assert_true(isinstance(matches, list))
267 self.assertIsInstance(text, str)
268 self.assertIsInstance(matches, list)
272 269
273 270 def test_latex_completions(self):
274 271 from IPython.core.latex_symbols import latex_symbols
275 272 import random
276 273
277 274 ip = get_ipython()
278 275 # Test some random unicode symbols
279 276 keys = random.sample(latex_symbols.keys(), 10)
280 277 for k in keys:
281 278 text, matches = ip.complete(k)
282 nt.assert_equal(text, k)
283 nt.assert_equal(matches, [latex_symbols[k]])
279 self.assertEqual(text, k)
280 self.assertEqual(matches, [latex_symbols[k]])
284 281 # Test a more complex line
285 282 text, matches = ip.complete("print(\\alpha")
286 nt.assert_equal(text, "\\alpha")
287 nt.assert_equal(matches[0], latex_symbols["\\alpha"])
283 self.assertEqual(text, "\\alpha")
284 self.assertEqual(matches[0], latex_symbols["\\alpha"])
288 285 # Test multiple matching latex symbols
289 286 text, matches = ip.complete("\\al")
290 nt.assert_in("\\alpha", matches)
291 nt.assert_in("\\aleph", matches)
287 self.assertIn("\\alpha", matches)
288 self.assertIn("\\aleph", matches)
292 289
293 290 def test_latex_no_results(self):
294 291 """
295 292 forward latex should really return nothing in either field if nothing is found.
296 293 """
297 294 ip = get_ipython()
298 295 text, matches = ip.Completer.latex_matches("\\really_i_should_match_nothing")
299 nt.assert_equal(text, "")
300 nt.assert_equal(matches, ())
296 self.assertEqual(text, "")
297 self.assertEqual(matches, ())
301 298
302 299 def test_back_latex_completion(self):
303 300 ip = get_ipython()
304 301
305 302 # do not return more than 1 matches for \beta, only the latex one.
306 303 name, matches = ip.complete("\\β")
307 nt.assert_equal(matches, ['\\beta'])
304 self.assertEqual(matches, ["\\beta"])
308 305
309 306 def test_back_unicode_completion(self):
310 307 ip = get_ipython()
311 308
312 309 name, matches = ip.complete("\\Ⅴ")
313 nt.assert_equal(matches, ("\\ROMAN NUMERAL FIVE",))
310 self.assertEqual(matches, ("\\ROMAN NUMERAL FIVE",))
314 311
315 312 def test_forward_unicode_completion(self):
316 313 ip = get_ipython()
317 314
318 315 name, matches = ip.complete("\\ROMAN NUMERAL FIVE")
319 nt.assert_equal(matches, ["Ⅴ"] ) # This is not a V
320 nt.assert_equal(matches, ["\u2164"] ) # same as above but explicit.
316 self.assertEqual(matches, ["Ⅴ"]) # This is not a V
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 320 @decorators.knownfailureif(
324 321 sys.platform == "win32", "Fails if there is a C:\\j... path"
325 322 )
326 323 def test_no_ascii_back_completion(self):
327 324 ip = get_ipython()
328 325 with TemporaryWorkingDirectory(): # Avoid any filename completions
329 326 # single ascii letter that don't have yet completions
330 327 for letter in "jJ":
331 328 name, matches = ip.complete("\\" + letter)
332 nt.assert_equal(matches, [])
329 self.assertEqual(matches, [])
333 330
334 331 class CompletionSplitterTestCase(unittest.TestCase):
335 332 def setUp(self):
336 333 self.sp = completer.CompletionSplitter()
337 334
338 335 def test_delim_setting(self):
339 336 self.sp.delims = " "
340 nt.assert_equal(self.sp.delims, " ")
341 nt.assert_equal(self.sp._delim_expr, r"[\ ]")
337 self.assertEqual(self.sp.delims, " ")
338 self.assertEqual(self.sp._delim_expr, r"[\ ]")
342 339
343 340 def test_spaces(self):
344 341 """Test with only spaces as split chars."""
345 342 self.sp.delims = " "
346 343 t = [("foo", "", "foo"), ("run foo", "", "foo"), ("run foo", "bar", "foo")]
347 344 check_line_split(self.sp, t)
348 345
349 346 def test_has_open_quotes1(self):
350 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 350 def test_has_open_quotes2(self):
354 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 354 def test_has_open_quotes3(self):
358 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 358 def test_has_open_quotes4(self):
362 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 362 @decorators.knownfailureif(
366 363 sys.platform == "win32", "abspath completions fail on Windows"
367 364 )
368 365 def test_abspath_file_completions(self):
369 366 ip = get_ipython()
370 367 with TemporaryDirectory() as tmpdir:
371 368 prefix = os.path.join(tmpdir, "foo")
372 369 suffixes = ["1", "2"]
373 370 names = [prefix + s for s in suffixes]
374 371 for n in names:
375 372 open(n, "w").close()
376 373
377 374 # Check simple completion
378 375 c = ip.complete(prefix)[1]
379 nt.assert_equal(c, names)
376 self.assertEqual(c, names)
380 377
381 378 # Now check with a function call
382 379 cmd = 'a = f("%s' % prefix
383 380 c = ip.complete(prefix, cmd)[1]
384 381 comp = [prefix + s for s in suffixes]
385 nt.assert_equal(c, comp)
382 self.assertEqual(c, comp)
386 383
387 384 def test_local_file_completions(self):
388 385 ip = get_ipython()
389 386 with TemporaryWorkingDirectory():
390 387 prefix = "./foo"
391 388 suffixes = ["1", "2"]
392 389 names = [prefix + s for s in suffixes]
393 390 for n in names:
394 391 open(n, "w").close()
395 392
396 393 # Check simple completion
397 394 c = ip.complete(prefix)[1]
398 nt.assert_equal(c, names)
395 self.assertEqual(c, names)
399 396
400 397 # Now check with a function call
401 398 cmd = 'a = f("%s' % prefix
402 399 c = ip.complete(prefix, cmd)[1]
403 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 403 def test_quoted_file_completions(self):
407 404 ip = get_ipython()
408 405 with TemporaryWorkingDirectory():
409 406 name = "foo'bar"
410 407 open(name, "w").close()
411 408
412 409 # Don't escape Windows
413 410 escaped = name if sys.platform == "win32" else "foo\\'bar"
414 411
415 412 # Single quote matches embedded single quote
416 413 text = "open('foo"
417 414 c = ip.Completer._complete(
418 415 cursor_line=0, cursor_pos=len(text), full_text=text
419 416 )[1]
420 nt.assert_equal(c, [escaped])
417 self.assertEqual(c, [escaped])
421 418
422 419 # Double quote requires no escape
423 420 text = 'open("foo'
424 421 c = ip.Completer._complete(
425 422 cursor_line=0, cursor_pos=len(text), full_text=text
426 423 )[1]
427 nt.assert_equal(c, [name])
424 self.assertEqual(c, [name])
428 425
429 426 # No quote requires an escape
430 427 text = "%ls foo"
431 428 c = ip.Completer._complete(
432 429 cursor_line=0, cursor_pos=len(text), full_text=text
433 430 )[1]
434 nt.assert_equal(c, [escaped])
431 self.assertEqual(c, [escaped])
435 432
436 433 def test_all_completions_dups(self):
437 434 """
438 435 Make sure the output of `IPCompleter.all_completions` does not have
439 436 duplicated prefixes.
440 437 """
441 438 ip = get_ipython()
442 439 c = ip.Completer
443 440 ip.ex("class TestClass():\n\ta=1\n\ta1=2")
444 441 for jedi_status in [True, False]:
445 442 with provisionalcompleter():
446 443 ip.Completer.use_jedi = jedi_status
447 444 matches = c.all_completions("TestCl")
448 445 assert matches == ['TestClass'], jedi_status
449 446 matches = c.all_completions("TestClass.")
450 447 assert len(matches) > 2, jedi_status
451 448 matches = c.all_completions("TestClass.a")
452 449 assert matches == ['TestClass.a', 'TestClass.a1'], jedi_status
453 450
454 451 def test_jedi(self):
455 452 """
456 453 A couple of issue we had with Jedi
457 454 """
458 455 ip = get_ipython()
459 456
460 457 def _test_complete(reason, s, comp, start=None, end=None):
461 458 l = len(s)
462 459 start = start if start is not None else l
463 460 end = end if end is not None else l
464 461 with provisionalcompleter():
465 462 ip.Completer.use_jedi = True
466 463 completions = set(ip.Completer.completions(s, l))
467 464 ip.Completer.use_jedi = False
468 465 assert_in(Completion(start, end, comp), completions, reason)
469 466
470 467 def _test_not_complete(reason, s, comp):
471 468 l = len(s)
472 469 with provisionalcompleter():
473 470 ip.Completer.use_jedi = True
474 471 completions = set(ip.Completer.completions(s, l))
475 472 ip.Completer.use_jedi = False
476 473 assert_not_in(Completion(l, l, comp), completions, reason)
477 474
478 475 import jedi
479 476
480 477 jedi_version = tuple(int(i) for i in jedi.__version__.split(".")[:3])
481 478 if jedi_version > (0, 10):
482 479 yield _test_complete, "jedi >0.9 should complete and not crash", "a=1;a.", "real"
483 480 yield _test_complete, "can infer first argument", 'a=(1,"foo");a[0].', "real"
484 481 yield _test_complete, "can infer second argument", 'a=(1,"foo");a[1].', "capitalize"
485 482 yield _test_complete, "cover duplicate completions", "im", "import", 0, 2
486 483
487 484 yield _test_not_complete, "does not mix types", 'a=(1,"foo");a[0].', "capitalize"
488 485
489 486 def test_completion_have_signature(self):
490 487 """
491 488 Lets make sure jedi is capable of pulling out the signature of the function we are completing.
492 489 """
493 490 ip = get_ipython()
494 491 with provisionalcompleter():
495 492 ip.Completer.use_jedi = True
496 493 completions = ip.Completer.completions("ope", 3)
497 494 c = next(completions) # should be `open`
498 495 ip.Completer.use_jedi = False
499 496 assert "file" in c.signature, "Signature of function was not found by completer"
500 497 assert (
501 498 "encoding" in c.signature
502 499 ), "Signature of function was not found by completer"
503 500
504 501 def test_deduplicate_completions(self):
505 502 """
506 503 Test that completions are correctly deduplicated (even if ranges are not the same)
507 504 """
508 505 ip = get_ipython()
509 506 ip.ex(
510 507 textwrap.dedent(
511 508 """
512 509 class Z:
513 510 zoo = 1
514 511 """
515 512 )
516 513 )
517 514 with provisionalcompleter():
518 515 ip.Completer.use_jedi = True
519 516 l = list(
520 517 _deduplicate_completions("Z.z", ip.Completer.completions("Z.z", 3))
521 518 )
522 519 ip.Completer.use_jedi = False
523 520
524 521 assert len(l) == 1, "Completions (Z.z<tab>) correctly deduplicate: %s " % l
525 522 assert l[0].text == "zoo" # and not `it.accumulate`
526 523
527 524 def test_greedy_completions(self):
528 525 """
529 526 Test the capability of the Greedy completer.
530 527
531 528 Most of the test here does not really show off the greedy completer, for proof
532 529 each of the text below now pass with Jedi. The greedy completer is capable of more.
533 530
534 531 See the :any:`test_dict_key_completion_contexts`
535 532
536 533 """
537 534 ip = get_ipython()
538 535 ip.ex("a=list(range(5))")
539 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 539 def _(line, cursor_pos, expect, message, completion):
543 540 with greedy_completion(), provisionalcompleter():
544 541 ip.Completer.use_jedi = False
545 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 545 ip.Completer.use_jedi = True
549 546 with provisionalcompleter():
550 547 completions = ip.Completer.completions(line, cursor_pos)
551 nt.assert_in(completion, completions)
548 self.assertIn(completion, completions)
552 549
553 550 with provisionalcompleter():
554 551 yield _, "a[0].", 5, "a[0].real", "Should have completed on a[0].: %s", Completion(
555 552 5, 5, "real"
556 553 )
557 554 yield _, "a[0].r", 6, "a[0].real", "Should have completed on a[0].r: %s", Completion(
558 555 5, 6, "real"
559 556 )
560 557
561 558 yield _, "a[0].from_", 10, "a[0].from_bytes", "Should have completed on a[0].from_: %s", Completion(
562 559 5, 10, "from_bytes"
563 560 )
564 561
565 562 def test_omit__names(self):
566 563 # also happens to test IPCompleter as a configurable
567 564 ip = get_ipython()
568 565 ip._hidden_attr = 1
569 566 ip._x = {}
570 567 c = ip.Completer
571 568 ip.ex("ip=get_ipython()")
572 569 cfg = Config()
573 570 cfg.IPCompleter.omit__names = 0
574 571 c.update_config(cfg)
575 572 with provisionalcompleter():
576 573 c.use_jedi = False
577 574 s, matches = c.complete("ip.")
578 nt.assert_in("ip.__str__", matches)
579 nt.assert_in("ip._hidden_attr", matches)
575 self.assertIn("ip.__str__", matches)
576 self.assertIn("ip._hidden_attr", matches)
580 577
581 578 # c.use_jedi = True
582 579 # completions = set(c.completions('ip.', 3))
583 # nt.assert_in(Completion(3, 3, '__str__'), completions)
584 # nt.assert_in(Completion(3,3, "_hidden_attr"), completions)
580 # self.assertIn(Completion(3, 3, '__str__'), completions)
581 # self.assertIn(Completion(3,3, "_hidden_attr"), completions)
585 582
586 583 cfg = Config()
587 584 cfg.IPCompleter.omit__names = 1
588 585 c.update_config(cfg)
589 586 with provisionalcompleter():
590 587 c.use_jedi = False
591 588 s, matches = c.complete("ip.")
592 nt.assert_not_in("ip.__str__", matches)
593 # nt.assert_in('ip._hidden_attr', matches)
589 self.assertNotIn("ip.__str__", matches)
590 # self.assertIn('ip._hidden_attr', matches)
594 591
595 592 # c.use_jedi = True
596 593 # completions = set(c.completions('ip.', 3))
597 # nt.assert_not_in(Completion(3,3,'__str__'), completions)
598 # nt.assert_in(Completion(3,3, "_hidden_attr"), completions)
594 # self.assertNotIn(Completion(3,3,'__str__'), completions)
595 # self.assertIn(Completion(3,3, "_hidden_attr"), completions)
599 596
600 597 cfg = Config()
601 598 cfg.IPCompleter.omit__names = 2
602 599 c.update_config(cfg)
603 600 with provisionalcompleter():
604 601 c.use_jedi = False
605 602 s, matches = c.complete("ip.")
606 nt.assert_not_in("ip.__str__", matches)
607 nt.assert_not_in("ip._hidden_attr", matches)
603 self.assertNotIn("ip.__str__", matches)
604 self.assertNotIn("ip._hidden_attr", matches)
608 605
609 606 # c.use_jedi = True
610 607 # completions = set(c.completions('ip.', 3))
611 # nt.assert_not_in(Completion(3,3,'__str__'), completions)
612 # nt.assert_not_in(Completion(3,3, "_hidden_attr"), completions)
608 # self.assertNotIn(Completion(3,3,'__str__'), completions)
609 # self.assertNotIn(Completion(3,3, "_hidden_attr"), completions)
613 610
614 611 with provisionalcompleter():
615 612 c.use_jedi = False
616 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 616 # c.use_jedi = True
620 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 620 del ip._hidden_attr
624 621 del ip._x
625 622
626 623 def test_limit_to__all__False_ok(self):
627 624 """
628 625 Limit to all is deprecated, once we remove it this test can go away.
629 626 """
630 627 ip = get_ipython()
631 628 c = ip.Completer
632 629 c.use_jedi = False
633 630 ip.ex("class D: x=24")
634 631 ip.ex("d=D()")
635 632 cfg = Config()
636 633 cfg.IPCompleter.limit_to__all__ = False
637 634 c.update_config(cfg)
638 635 s, matches = c.complete("d.")
639 nt.assert_in("d.x", matches)
636 self.assertIn("d.x", matches)
640 637
641 638 def test_get__all__entries_ok(self):
642 639 class A:
643 640 __all__ = ["x", 1]
644 641
645 642 words = completer.get__all__entries(A())
646 nt.assert_equal(words, ["x"])
643 self.assertEqual(words, ["x"])
647 644
648 645 def test_get__all__entries_no__all__ok(self):
649 646 class A:
650 647 pass
651 648
652 649 words = completer.get__all__entries(A())
653 nt.assert_equal(words, [])
650 self.assertEqual(words, [])
654 651
655 652 def test_func_kw_completions(self):
656 653 ip = get_ipython()
657 654 c = ip.Completer
658 655 c.use_jedi = False
659 656 ip.ex("def myfunc(a=1,b=2): return a+b")
660 657 s, matches = c.complete(None, "myfunc(1,b")
661 nt.assert_in("b=", matches)
658 self.assertIn("b=", matches)
662 659 # Simulate completing with cursor right after b (pos==10):
663 660 s, matches = c.complete(None, "myfunc(1,b)", 10)
664 nt.assert_in("b=", matches)
661 self.assertIn("b=", matches)
665 662 s, matches = c.complete(None, 'myfunc(a="escaped\\")string",b')
666 nt.assert_in("b=", matches)
663 self.assertIn("b=", matches)
667 664 # builtin function
668 665 s, matches = c.complete(None, "min(k, k")
669 nt.assert_in("key=", matches)
666 self.assertIn("key=", matches)
670 667
671 668 def test_default_arguments_from_docstring(self):
672 669 ip = get_ipython()
673 670 c = ip.Completer
674 671 kwd = c._default_arguments_from_docstring("min(iterable[, key=func]) -> value")
675 nt.assert_equal(kwd, ["key"])
672 self.assertEqual(kwd, ["key"])
676 673 # with cython type etc
677 674 kwd = c._default_arguments_from_docstring(
678 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 678 # white spaces
682 679 kwd = c._default_arguments_from_docstring(
683 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 684 def test_line_magics(self):
688 685 ip = get_ipython()
689 686 c = ip.Completer
690 687 s, matches = c.complete(None, "lsmag")
691 nt.assert_in("%lsmagic", matches)
688 self.assertIn("%lsmagic", matches)
692 689 s, matches = c.complete(None, "%lsmag")
693 nt.assert_in("%lsmagic", matches)
690 self.assertIn("%lsmagic", matches)
694 691
695 692 def test_cell_magics(self):
696 693 from IPython.core.magic import register_cell_magic
697 694
698 695 @register_cell_magic
699 696 def _foo_cellm(line, cell):
700 697 pass
701 698
702 699 ip = get_ipython()
703 700 c = ip.Completer
704 701
705 702 s, matches = c.complete(None, "_foo_ce")
706 nt.assert_in("%%_foo_cellm", matches)
703 self.assertIn("%%_foo_cellm", matches)
707 704 s, matches = c.complete(None, "%%_foo_ce")
708 nt.assert_in("%%_foo_cellm", matches)
705 self.assertIn("%%_foo_cellm", matches)
709 706
710 707 def test_line_cell_magics(self):
711 708 from IPython.core.magic import register_line_cell_magic
712 709
713 710 @register_line_cell_magic
714 711 def _bar_cellm(line, cell):
715 712 pass
716 713
717 714 ip = get_ipython()
718 715 c = ip.Completer
719 716
720 717 # The policy here is trickier, see comments in completion code. The
721 718 # returned values depend on whether the user passes %% or not explicitly,
722 719 # and this will show a difference if the same name is both a line and cell
723 720 # magic.
724 721 s, matches = c.complete(None, "_bar_ce")
725 nt.assert_in("%_bar_cellm", matches)
726 nt.assert_in("%%_bar_cellm", matches)
722 self.assertIn("%_bar_cellm", matches)
723 self.assertIn("%%_bar_cellm", matches)
727 724 s, matches = c.complete(None, "%_bar_ce")
728 nt.assert_in("%_bar_cellm", matches)
729 nt.assert_in("%%_bar_cellm", matches)
725 self.assertIn("%_bar_cellm", matches)
726 self.assertIn("%%_bar_cellm", matches)
730 727 s, matches = c.complete(None, "%%_bar_ce")
731 nt.assert_not_in("%_bar_cellm", matches)
732 nt.assert_in("%%_bar_cellm", matches)
728 self.assertNotIn("%_bar_cellm", matches)
729 self.assertIn("%%_bar_cellm", matches)
733 730
734 731 def test_magic_completion_order(self):
735 732 ip = get_ipython()
736 733 c = ip.Completer
737 734
738 735 # Test ordering of line and cell magics.
739 736 text, matches = c.complete("timeit")
740 nt.assert_equal(matches, ["%timeit", "%%timeit"])
737 self.assertEqual(matches, ["%timeit", "%%timeit"])
741 738
742 739 def test_magic_completion_shadowing(self):
743 740 ip = get_ipython()
744 741 c = ip.Completer
745 742 c.use_jedi = False
746 743
747 744 # Before importing matplotlib, %matplotlib magic should be the only option.
748 745 text, matches = c.complete("mat")
749 nt.assert_equal(matches, ["%matplotlib"])
746 self.assertEqual(matches, ["%matplotlib"])
750 747
751 748 # The newly introduced name should shadow the magic.
752 749 ip.run_cell("matplotlib = 1")
753 750 text, matches = c.complete("mat")
754 nt.assert_equal(matches, ["matplotlib"])
751 self.assertEqual(matches, ["matplotlib"])
755 752
756 753 # After removing matplotlib from namespace, the magic should again be
757 754 # the only option.
758 755 del ip.user_ns["matplotlib"]
759 756 text, matches = c.complete("mat")
760 nt.assert_equal(matches, ["%matplotlib"])
757 self.assertEqual(matches, ["%matplotlib"])
761 758
762 759 def test_magic_completion_shadowing_explicit(self):
763 760 """
764 761 If the user try to complete a shadowed magic, and explicit % start should
765 762 still return the completions.
766 763 """
767 764 ip = get_ipython()
768 765 c = ip.Completer
769 766
770 767 # Before importing matplotlib, %matplotlib magic should be the only option.
771 768 text, matches = c.complete("%mat")
772 nt.assert_equal(matches, ["%matplotlib"])
769 self.assertEqual(matches, ["%matplotlib"])
773 770
774 771 ip.run_cell("matplotlib = 1")
775 772
776 773 # After removing matplotlib from namespace, the magic should still be
777 774 # the only option.
778 775 text, matches = c.complete("%mat")
779 nt.assert_equal(matches, ["%matplotlib"])
776 self.assertEqual(matches, ["%matplotlib"])
780 777
781 778 def test_magic_config(self):
782 779 ip = get_ipython()
783 780 c = ip.Completer
784 781
785 782 s, matches = c.complete(None, "conf")
786 nt.assert_in("%config", matches)
783 self.assertIn("%config", matches)
787 784 s, matches = c.complete(None, "conf")
788 nt.assert_not_in("AliasManager", matches)
785 self.assertNotIn("AliasManager", matches)
789 786 s, matches = c.complete(None, "config ")
790 nt.assert_in("AliasManager", matches)
787 self.assertIn("AliasManager", matches)
791 788 s, matches = c.complete(None, "%config ")
792 nt.assert_in("AliasManager", matches)
789 self.assertIn("AliasManager", matches)
793 790 s, matches = c.complete(None, "config Ali")
794 nt.assert_list_equal(["AliasManager"], matches)
791 self.assertListEqual(["AliasManager"], matches)
795 792 s, matches = c.complete(None, "%config Ali")
796 nt.assert_list_equal(["AliasManager"], matches)
793 self.assertListEqual(["AliasManager"], matches)
797 794 s, matches = c.complete(None, "config AliasManager")
798 nt.assert_list_equal(["AliasManager"], matches)
795 self.assertListEqual(["AliasManager"], matches)
799 796 s, matches = c.complete(None, "%config AliasManager")
800 nt.assert_list_equal(["AliasManager"], matches)
797 self.assertListEqual(["AliasManager"], matches)
801 798 s, matches = c.complete(None, "config AliasManager.")
802 nt.assert_in("AliasManager.default_aliases", matches)
799 self.assertIn("AliasManager.default_aliases", matches)
803 800 s, matches = c.complete(None, "%config AliasManager.")
804 nt.assert_in("AliasManager.default_aliases", matches)
801 self.assertIn("AliasManager.default_aliases", matches)
805 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 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 807 def test_magic_color(self):
811 808 ip = get_ipython()
812 809 c = ip.Completer
813 810
814 811 s, matches = c.complete(None, "colo")
815 nt.assert_in("%colors", matches)
812 self.assertIn("%colors", matches)
816 813 s, matches = c.complete(None, "colo")
817 nt.assert_not_in("NoColor", matches)
814 self.assertNotIn("NoColor", matches)
818 815 s, matches = c.complete(None, "%colors") # No trailing space
819 nt.assert_not_in("NoColor", matches)
816 self.assertNotIn("NoColor", matches)
820 817 s, matches = c.complete(None, "colors ")
821 nt.assert_in("NoColor", matches)
818 self.assertIn("NoColor", matches)
822 819 s, matches = c.complete(None, "%colors ")
823 nt.assert_in("NoColor", matches)
820 self.assertIn("NoColor", matches)
824 821 s, matches = c.complete(None, "colors NoCo")
825 nt.assert_list_equal(["NoColor"], matches)
822 self.assertListEqual(["NoColor"], matches)
826 823 s, matches = c.complete(None, "%colors NoCo")
827 nt.assert_list_equal(["NoColor"], matches)
824 self.assertListEqual(["NoColor"], matches)
828 825
829 826 def test_match_dict_keys(self):
830 827 """
831 828 Test that match_dict_keys works on a couple of use case does return what
832 829 expected, and does not crash
833 830 """
834 831 delims = " \t\n`!@#$^&*()=+[{]}\\|;:'\",<>?"
835 832
836 833 keys = ["foo", b"far"]
837 834 assert match_dict_keys(keys, "b'", delims=delims) == ("'", 2, ["far"])
838 835 assert match_dict_keys(keys, "b'f", delims=delims) == ("'", 2, ["far"])
839 836 assert match_dict_keys(keys, 'b"', delims=delims) == ('"', 2, ["far"])
840 837 assert match_dict_keys(keys, 'b"f', delims=delims) == ('"', 2, ["far"])
841 838
842 839 assert match_dict_keys(keys, "'", delims=delims) == ("'", 1, ["foo"])
843 840 assert match_dict_keys(keys, "'f", delims=delims) == ("'", 1, ["foo"])
844 841 assert match_dict_keys(keys, '"', delims=delims) == ('"', 1, ["foo"])
845 842 assert match_dict_keys(keys, '"f', delims=delims) == ('"', 1, ["foo"])
846 843
847 844 match_dict_keys
848 845
849 846 def test_match_dict_keys_tuple(self):
850 847 """
851 848 Test that match_dict_keys called with extra prefix works on a couple of use case,
852 849 does return what expected, and does not crash.
853 850 """
854 851 delims = " \t\n`!@#$^&*()=+[{]}\\|;:'\",<>?"
855 852
856 853 keys = [("foo", "bar"), ("foo", "oof"), ("foo", b"bar"), ('other', 'test')]
857 854
858 855 # Completion on first key == "foo"
859 856 assert match_dict_keys(keys, "'", delims=delims, extra_prefix=("foo",)) == ("'", 1, ["bar", "oof"])
860 857 assert match_dict_keys(keys, "\"", delims=delims, extra_prefix=("foo",)) == ("\"", 1, ["bar", "oof"])
861 858 assert match_dict_keys(keys, "'o", delims=delims, extra_prefix=("foo",)) == ("'", 1, ["oof"])
862 859 assert match_dict_keys(keys, "\"o", delims=delims, extra_prefix=("foo",)) == ("\"", 1, ["oof"])
863 860 assert match_dict_keys(keys, "b'", delims=delims, extra_prefix=("foo",)) == ("'", 2, ["bar"])
864 861 assert match_dict_keys(keys, "b\"", delims=delims, extra_prefix=("foo",)) == ("\"", 2, ["bar"])
865 862 assert match_dict_keys(keys, "b'b", delims=delims, extra_prefix=("foo",)) == ("'", 2, ["bar"])
866 863 assert match_dict_keys(keys, "b\"b", delims=delims, extra_prefix=("foo",)) == ("\"", 2, ["bar"])
867 864
868 865 # No Completion
869 866 assert match_dict_keys(keys, "'", delims=delims, extra_prefix=("no_foo",)) == ("'", 1, [])
870 867 assert match_dict_keys(keys, "'", delims=delims, extra_prefix=("fo",)) == ("'", 1, [])
871 868
872 869 keys = [('foo1', 'foo2', 'foo3', 'foo4'), ('foo1', 'foo2', 'bar', 'foo4')]
873 870 assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1',)) == ("'", 1, ["foo2", "foo2"])
874 871 assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1', 'foo2')) == ("'", 1, ["foo3"])
875 872 assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1', 'foo2', 'foo3')) == ("'", 1, ["foo4"])
876 873 assert match_dict_keys(keys, "'foo", delims=delims, extra_prefix=('foo1', 'foo2', 'foo3', 'foo4')) == ("'", 1, [])
877 874
878 875 def test_dict_key_completion_string(self):
879 876 """Test dictionary key completion for string keys"""
880 877 ip = get_ipython()
881 878 complete = ip.Completer.complete
882 879
883 880 ip.user_ns["d"] = {"abc": None}
884 881
885 882 # check completion at different stages
886 883 _, matches = complete(line_buffer="d[")
887 nt.assert_in("'abc'", matches)
888 nt.assert_not_in("'abc']", matches)
884 self.assertIn("'abc'", matches)
885 self.assertNotIn("'abc']", matches)
889 886
890 887 _, matches = complete(line_buffer="d['")
891 nt.assert_in("abc", matches)
892 nt.assert_not_in("abc']", matches)
888 self.assertIn("abc", matches)
889 self.assertNotIn("abc']", matches)
893 890
894 891 _, matches = complete(line_buffer="d['a")
895 nt.assert_in("abc", matches)
896 nt.assert_not_in("abc']", matches)
892 self.assertIn("abc", matches)
893 self.assertNotIn("abc']", matches)
897 894
898 895 # check use of different quoting
899 896 _, matches = complete(line_buffer='d["')
900 nt.assert_in("abc", matches)
901 nt.assert_not_in('abc"]', matches)
897 self.assertIn("abc", matches)
898 self.assertNotIn('abc"]', matches)
902 899
903 900 _, matches = complete(line_buffer='d["a')
904 nt.assert_in("abc", matches)
905 nt.assert_not_in('abc"]', matches)
901 self.assertIn("abc", matches)
902 self.assertNotIn('abc"]', matches)
906 903
907 904 # check sensitivity to following context
908 905 _, matches = complete(line_buffer="d[]", cursor_pos=2)
909 nt.assert_in("'abc'", matches)
906 self.assertIn("'abc'", matches)
910 907
911 908 _, matches = complete(line_buffer="d['']", cursor_pos=3)
912 nt.assert_in("abc", matches)
913 nt.assert_not_in("abc'", matches)
914 nt.assert_not_in("abc']", matches)
909 self.assertIn("abc", matches)
910 self.assertNotIn("abc'", matches)
911 self.assertNotIn("abc']", matches)
915 912
916 913 # check multiple solutions are correctly returned and that noise is not
917 914 ip.user_ns["d"] = {
918 915 "abc": None,
919 916 "abd": None,
920 917 "bad": None,
921 918 object(): None,
922 919 5: None,
923 920 ("abe", None): None,
924 921 (None, "abf"): None
925 922 }
926 923
927 924 _, matches = complete(line_buffer="d['a")
928 nt.assert_in("abc", matches)
929 nt.assert_in("abd", matches)
930 nt.assert_not_in("bad", matches)
931 nt.assert_not_in("abe", matches)
932 nt.assert_not_in("abf", matches)
925 self.assertIn("abc", matches)
926 self.assertIn("abd", matches)
927 self.assertNotIn("bad", matches)
928 self.assertNotIn("abe", matches)
929 self.assertNotIn("abf", matches)
933 930 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
934 931
935 932 # check escaping and whitespace
936 933 ip.user_ns["d"] = {"a\nb": None, "a'b": None, 'a"b': None, "a word": None}
937 934 _, matches = complete(line_buffer="d['a")
938 nt.assert_in("a\\nb", matches)
939 nt.assert_in("a\\'b", matches)
940 nt.assert_in('a"b', matches)
941 nt.assert_in("a word", matches)
935 self.assertIn("a\\nb", matches)
936 self.assertIn("a\\'b", matches)
937 self.assertIn('a"b', matches)
938 self.assertIn("a word", matches)
942 939 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
943 940
944 941 # - can complete on non-initial word of the string
945 942 _, matches = complete(line_buffer="d['a w")
946 nt.assert_in("word", matches)
943 self.assertIn("word", matches)
947 944
948 945 # - understands quote escaping
949 946 _, matches = complete(line_buffer="d['a\\'")
950 nt.assert_in("b", matches)
947 self.assertIn("b", matches)
951 948
952 949 # - default quoting should work like repr
953 950 _, matches = complete(line_buffer="d[")
954 nt.assert_in('"a\'b"', matches)
951 self.assertIn('"a\'b"', matches)
955 952
956 953 # - when opening quote with ", possible to match with unescaped apostrophe
957 954 _, matches = complete(line_buffer="d[\"a'")
958 nt.assert_in("b", matches)
955 self.assertIn("b", matches)
959 956
960 957 # need to not split at delims that readline won't split at
961 958 if "-" not in ip.Completer.splitter.delims:
962 959 ip.user_ns["d"] = {"before-after": None}
963 960 _, matches = complete(line_buffer="d['before-af")
964 nt.assert_in("before-after", matches)
961 self.assertIn("before-after", matches)
965 962
966 963 # check completion on tuple-of-string keys at different stage - on first key
967 964 ip.user_ns["d"] = {('foo', 'bar'): None}
968 965 _, matches = complete(line_buffer="d[")
969 nt.assert_in("'foo'", matches)
970 nt.assert_not_in("'foo']", matches)
971 nt.assert_not_in("'bar'", matches)
972 nt.assert_not_in("foo", matches)
973 nt.assert_not_in("bar", matches)
966 self.assertIn("'foo'", matches)
967 self.assertNotIn("'foo']", matches)
968 self.assertNotIn("'bar'", matches)
969 self.assertNotIn("foo", matches)
970 self.assertNotIn("bar", matches)
974 971
975 972 # - match the prefix
976 973 _, matches = complete(line_buffer="d['f")
977 nt.assert_in("foo", matches)
978 nt.assert_not_in("foo']", matches)
979 nt.assert_not_in("foo\"]", matches)
974 self.assertIn("foo", matches)
975 self.assertNotIn("foo']", matches)
976 self.assertNotIn('foo"]', matches)
980 977 _, matches = complete(line_buffer="d['foo")
981 nt.assert_in("foo", matches)
978 self.assertIn("foo", matches)
982 979
983 980 # - can complete on second key
984 981 _, matches = complete(line_buffer="d['foo', ")
985 nt.assert_in("'bar'", matches)
982 self.assertIn("'bar'", matches)
986 983 _, matches = complete(line_buffer="d['foo', 'b")
987 nt.assert_in("bar", matches)
988 nt.assert_not_in("foo", matches)
984 self.assertIn("bar", matches)
985 self.assertNotIn("foo", matches)
989 986
990 987 # - does not propose missing keys
991 988 _, matches = complete(line_buffer="d['foo', 'f")
992 nt.assert_not_in("bar", matches)
993 nt.assert_not_in("foo", matches)
989 self.assertNotIn("bar", matches)
990 self.assertNotIn("foo", matches)
994 991
995 992 # check sensitivity to following context
996 993 _, matches = complete(line_buffer="d['foo',]", cursor_pos=8)
997 nt.assert_in("'bar'", matches)
998 nt.assert_not_in("bar", matches)
999 nt.assert_not_in("'foo'", matches)
1000 nt.assert_not_in("foo", matches)
994 self.assertIn("'bar'", matches)
995 self.assertNotIn("bar", matches)
996 self.assertNotIn("'foo'", matches)
997 self.assertNotIn("foo", matches)
1001 998
1002 999 _, matches = complete(line_buffer="d['']", cursor_pos=3)
1003 nt.assert_in("foo", matches)
1000 self.assertIn("foo", matches)
1004 1001 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
1005 1002
1006 1003 _, matches = complete(line_buffer='d[""]', cursor_pos=3)
1007 nt.assert_in("foo", matches)
1004 self.assertIn("foo", matches)
1008 1005 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
1009 1006
1010 1007 _, matches = complete(line_buffer='d["foo","]', cursor_pos=9)
1011 nt.assert_in("bar", matches)
1008 self.assertIn("bar", matches)
1012 1009 assert not any(m.endswith(("]", '"', "'")) for m in matches), matches
1013 1010
1014 1011 _, matches = complete(line_buffer='d["foo",]', cursor_pos=8)
1015 nt.assert_in("'bar'", matches)
1016 nt.assert_not_in("bar", matches)
1012 self.assertIn("'bar'", matches)
1013 self.assertNotIn("bar", matches)
1017 1014
1018 1015 # Can complete with longer tuple keys
1019 1016 ip.user_ns["d"] = {('foo', 'bar', 'foobar'): None}
1020 1017
1021 1018 # - can complete second key
1022 1019 _, matches = complete(line_buffer="d['foo', 'b")
1023 nt.assert_in('bar', matches)
1024 nt.assert_not_in('foo', matches)
1025 nt.assert_not_in('foobar', matches)
1020 self.assertIn("bar", matches)
1021 self.assertNotIn("foo", matches)
1022 self.assertNotIn("foobar", matches)
1026 1023
1027 1024 # - can complete third key
1028 1025 _, matches = complete(line_buffer="d['foo', 'bar', 'fo")
1029 nt.assert_in('foobar', matches)
1030 nt.assert_not_in('foo', matches)
1031 nt.assert_not_in('bar', matches)
1032
1026 self.assertIn("foobar", matches)
1027 self.assertNotIn("foo", matches)
1028 self.assertNotIn("bar", matches)
1033 1029
1034 1030 def test_dict_key_completion_contexts(self):
1035 1031 """Test expression contexts in which dict key completion occurs"""
1036 1032 ip = get_ipython()
1037 1033 complete = ip.Completer.complete
1038 1034 d = {"abc": None}
1039 1035 ip.user_ns["d"] = d
1040 1036
1041 1037 class C:
1042 1038 data = d
1043 1039
1044 1040 ip.user_ns["C"] = C
1045 1041 ip.user_ns["get"] = lambda: d
1046 1042
1047 1043 def assert_no_completion(**kwargs):
1048 1044 _, matches = complete(**kwargs)
1049 nt.assert_not_in("abc", matches)
1050 nt.assert_not_in("abc'", matches)
1051 nt.assert_not_in("abc']", matches)
1052 nt.assert_not_in("'abc'", matches)
1053 nt.assert_not_in("'abc']", matches)
1045 self.assertNotIn("abc", matches)
1046 self.assertNotIn("abc'", matches)
1047 self.assertNotIn("abc']", matches)
1048 self.assertNotIn("'abc'", matches)
1049 self.assertNotIn("'abc']", matches)
1054 1050
1055 1051 def assert_completion(**kwargs):
1056 1052 _, matches = complete(**kwargs)
1057 nt.assert_in("'abc'", matches)
1058 nt.assert_not_in("'abc']", matches)
1053 self.assertIn("'abc'", matches)
1054 self.assertNotIn("'abc']", matches)
1059 1055
1060 1056 # no completion after string closed, even if reopened
1061 1057 assert_no_completion(line_buffer="d['a'")
1062 1058 assert_no_completion(line_buffer='d["a"')
1063 1059 assert_no_completion(line_buffer="d['a' + ")
1064 1060 assert_no_completion(line_buffer="d['a' + '")
1065 1061
1066 1062 # completion in non-trivial expressions
1067 1063 assert_completion(line_buffer="+ d[")
1068 1064 assert_completion(line_buffer="(d[")
1069 1065 assert_completion(line_buffer="C.data[")
1070 1066
1071 1067 # greedy flag
1072 1068 def assert_completion(**kwargs):
1073 1069 _, matches = complete(**kwargs)
1074 nt.assert_in("get()['abc']", matches)
1070 self.assertIn("get()['abc']", matches)
1075 1071
1076 1072 assert_no_completion(line_buffer="get()[")
1077 1073 with greedy_completion():
1078 1074 assert_completion(line_buffer="get()[")
1079 1075 assert_completion(line_buffer="get()['")
1080 1076 assert_completion(line_buffer="get()['a")
1081 1077 assert_completion(line_buffer="get()['ab")
1082 1078 assert_completion(line_buffer="get()['abc")
1083 1079
1084 1080 def test_dict_key_completion_bytes(self):
1085 1081 """Test handling of bytes in dict key completion"""
1086 1082 ip = get_ipython()
1087 1083 complete = ip.Completer.complete
1088 1084
1089 1085 ip.user_ns["d"] = {"abc": None, b"abd": None}
1090 1086
1091 1087 _, matches = complete(line_buffer="d[")
1092 nt.assert_in("'abc'", matches)
1093 nt.assert_in("b'abd'", matches)
1088 self.assertIn("'abc'", matches)
1089 self.assertIn("b'abd'", matches)
1094 1090
1095 1091 if False: # not currently implemented
1096 1092 _, matches = complete(line_buffer="d[b")
1097 nt.assert_in("b'abd'", matches)
1098 nt.assert_not_in("b'abc'", matches)
1093 self.assertIn("b'abd'", matches)
1094 self.assertNotIn("b'abc'", matches)
1099 1095
1100 1096 _, matches = complete(line_buffer="d[b'")
1101 nt.assert_in("abd", matches)
1102 nt.assert_not_in("abc", matches)
1097 self.assertIn("abd", matches)
1098 self.assertNotIn("abc", matches)
1103 1099
1104 1100 _, matches = complete(line_buffer="d[B'")
1105 nt.assert_in("abd", matches)
1106 nt.assert_not_in("abc", matches)
1101 self.assertIn("abd", matches)
1102 self.assertNotIn("abc", matches)
1107 1103
1108 1104 _, matches = complete(line_buffer="d['")
1109 nt.assert_in("abc", matches)
1110 nt.assert_not_in("abd", matches)
1105 self.assertIn("abc", matches)
1106 self.assertNotIn("abd", matches)
1111 1107
1112 1108 def test_dict_key_completion_unicode_py3(self):
1113 1109 """Test handling of unicode in dict key completion"""
1114 1110 ip = get_ipython()
1115 1111 complete = ip.Completer.complete
1116 1112
1117 1113 ip.user_ns["d"] = {"a\u05d0": None}
1118 1114
1119 1115 # query using escape
1120 1116 if sys.platform != "win32":
1121 1117 # Known failure on Windows
1122 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 1121 # query using character
1126 1122 _, matches = complete(line_buffer="d['a\u05d0")
1127 nt.assert_in("a\u05d0", matches)
1123 self.assertIn("a\u05d0", matches)
1128 1124
1129 1125 with greedy_completion():
1130 1126 # query using escape
1131 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 1130 # query using character
1135 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 1134 @dec.skip_without("numpy")
1139 1135 def test_struct_array_key_completion(self):
1140 1136 """Test dict key completion applies to numpy struct arrays"""
1141 1137 import numpy
1142 1138
1143 1139 ip = get_ipython()
1144 1140 complete = ip.Completer.complete
1145 1141 ip.user_ns["d"] = numpy.array([], dtype=[("hello", "f"), ("world", "f")])
1146 1142 _, matches = complete(line_buffer="d['")
1147 nt.assert_in("hello", matches)
1148 nt.assert_in("world", matches)
1143 self.assertIn("hello", matches)
1144 self.assertIn("world", matches)
1149 1145 # complete on the numpy struct itself
1150 1146 dt = numpy.dtype(
1151 1147 [("my_head", [("my_dt", ">u4"), ("my_df", ">u4")]), ("my_data", ">f4", 5)]
1152 1148 )
1153 1149 x = numpy.zeros(2, dtype=dt)
1154 1150 ip.user_ns["d"] = x[1]
1155 1151 _, matches = complete(line_buffer="d['")
1156 nt.assert_in("my_head", matches)
1157 nt.assert_in("my_data", matches)
1152 self.assertIn("my_head", matches)
1153 self.assertIn("my_data", matches)
1158 1154 # complete on a nested level
1159 1155 with greedy_completion():
1160 1156 ip.user_ns["d"] = numpy.zeros(2, dtype=dt)
1161 1157 _, matches = complete(line_buffer="d[1]['my_head']['")
1162 nt.assert_true(any(["my_dt" in m for m in matches]))
1163 nt.assert_true(any(["my_df" in m for m in matches]))
1158 self.assertTrue(any(["my_dt" in m for m in matches]))
1159 self.assertTrue(any(["my_df" in m for m in matches]))
1164 1160
1165 1161 @dec.skip_without("pandas")
1166 1162 def test_dataframe_key_completion(self):
1167 1163 """Test dict key completion applies to pandas DataFrames"""
1168 1164 import pandas
1169 1165
1170 1166 ip = get_ipython()
1171 1167 complete = ip.Completer.complete
1172 1168 ip.user_ns["d"] = pandas.DataFrame({"hello": [1], "world": [2]})
1173 1169 _, matches = complete(line_buffer="d['")
1174 nt.assert_in("hello", matches)
1175 nt.assert_in("world", matches)
1170 self.assertIn("hello", matches)
1171 self.assertIn("world", matches)
1176 1172
1177 1173 def test_dict_key_completion_invalids(self):
1178 1174 """Smoke test cases dict key completion can't handle"""
1179 1175 ip = get_ipython()
1180 1176 complete = ip.Completer.complete
1181 1177
1182 1178 ip.user_ns["no_getitem"] = None
1183 1179 ip.user_ns["no_keys"] = []
1184 1180 ip.user_ns["cant_call_keys"] = dict
1185 1181 ip.user_ns["empty"] = {}
1186 1182 ip.user_ns["d"] = {"abc": 5}
1187 1183
1188 1184 _, matches = complete(line_buffer="no_getitem['")
1189 1185 _, matches = complete(line_buffer="no_keys['")
1190 1186 _, matches = complete(line_buffer="cant_call_keys['")
1191 1187 _, matches = complete(line_buffer="empty['")
1192 1188 _, matches = complete(line_buffer="name_error['")
1193 1189 _, matches = complete(line_buffer="d['\\") # incomplete escape
1194 1190
1195 1191 def test_object_key_completion(self):
1196 1192 ip = get_ipython()
1197 1193 ip.user_ns["key_completable"] = KeyCompletable(["qwerty", "qwick"])
1198 1194
1199 1195 _, matches = ip.Completer.complete(line_buffer="key_completable['qw")
1200 nt.assert_in("qwerty", matches)
1201 nt.assert_in("qwick", matches)
1196 self.assertIn("qwerty", matches)
1197 self.assertIn("qwick", matches)
1202 1198
1203 1199 def test_class_key_completion(self):
1204 1200 ip = get_ipython()
1205 1201 NamedInstanceClass("qwerty")
1206 1202 NamedInstanceClass("qwick")
1207 1203 ip.user_ns["named_instance_class"] = NamedInstanceClass
1208 1204
1209 1205 _, matches = ip.Completer.complete(line_buffer="named_instance_class['qw")
1210 nt.assert_in("qwerty", matches)
1211 nt.assert_in("qwick", matches)
1206 self.assertIn("qwerty", matches)
1207 self.assertIn("qwick", matches)
1212 1208
1213 1209 def test_tryimport(self):
1214 1210 """
1215 1211 Test that try-import don't crash on trailing dot, and import modules before
1216 1212 """
1217 1213 from IPython.core.completerlib import try_import
1218 1214
1219 1215 assert try_import("IPython.")
1220 1216
1221 1217 def test_aimport_module_completer(self):
1222 1218 ip = get_ipython()
1223 1219 _, matches = ip.complete("i", "%aimport i")
1224 nt.assert_in("io", matches)
1225 nt.assert_not_in("int", matches)
1220 self.assertIn("io", matches)
1221 self.assertNotIn("int", matches)
1226 1222
1227 1223 def test_nested_import_module_completer(self):
1228 1224 ip = get_ipython()
1229 1225 _, matches = ip.complete(None, "import IPython.co", 17)
1230 nt.assert_in("IPython.core", matches)
1231 nt.assert_not_in("import IPython.core", matches)
1232 nt.assert_not_in("IPython.display", matches)
1226 self.assertIn("IPython.core", matches)
1227 self.assertNotIn("import IPython.core", matches)
1228 self.assertNotIn("IPython.display", matches)
1233 1229
1234 1230 def test_import_module_completer(self):
1235 1231 ip = get_ipython()
1236 1232 _, matches = ip.complete("i", "import i")
1237 nt.assert_in("io", matches)
1238 nt.assert_not_in("int", matches)
1233 self.assertIn("io", matches)
1234 self.assertNotIn("int", matches)
1239 1235
1240 1236 def test_from_module_completer(self):
1241 1237 ip = get_ipython()
1242 1238 _, matches = ip.complete("B", "from io import B", 16)
1243 nt.assert_in("BytesIO", matches)
1244 nt.assert_not_in("BaseException", matches)
1239 self.assertIn("BytesIO", matches)
1240 self.assertNotIn("BaseException", matches)
1245 1241
1246 1242 def test_snake_case_completion(self):
1247 1243 ip = get_ipython()
1248 1244 ip.Completer.use_jedi = False
1249 1245 ip.user_ns["some_three"] = 3
1250 1246 ip.user_ns["some_four"] = 4
1251 1247 _, matches = ip.complete("s_", "print(s_f")
1252 nt.assert_in("some_three", matches)
1253 nt.assert_in("some_four", matches)
1248 self.assertIn("some_three", matches)
1249 self.assertIn("some_four", matches)
1254 1250
1255 1251 def test_mix_terms(self):
1256 1252 ip = get_ipython()
1257 1253 from textwrap import dedent
1258 1254
1259 1255 ip.Completer.use_jedi = False
1260 1256 ip.ex(
1261 1257 dedent(
1262 1258 """
1263 1259 class Test:
1264 1260 def meth(self, meth_arg1):
1265 1261 print("meth")
1266 1262
1267 1263 def meth_1(self, meth1_arg1, meth1_arg2):
1268 1264 print("meth1")
1269 1265
1270 1266 def meth_2(self, meth2_arg1, meth2_arg2):
1271 1267 print("meth2")
1272 1268 test = Test()
1273 1269 """
1274 1270 )
1275 1271 )
1276 1272 _, matches = ip.complete(None, "test.meth(")
1277 nt.assert_in("meth_arg1=", matches)
1278 nt.assert_not_in("meth2_arg1=", matches)
1273 self.assertIn("meth_arg1=", matches)
1274 self.assertNotIn("meth2_arg1=", matches)
@@ -1,194 +1,192 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Tests for completerlib.
3 3
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 7 # Imports
8 8 #-----------------------------------------------------------------------------
9 9
10 10 import os
11 11 import shutil
12 12 import sys
13 13 import tempfile
14 14 import unittest
15 15 from os.path import join
16 16
17 import nose.tools as nt
18
19 17 from IPython.core.completerlib import magic_run_completer, module_completion, try_import
20 18 from IPython.utils.tempdir import TemporaryDirectory
21 19 from IPython.testing.decorators import onlyif_unicode_paths
22 20
23 21
24 22 class MockEvent(object):
25 23 def __init__(self, line):
26 24 self.line = line
27 25
28 26 #-----------------------------------------------------------------------------
29 27 # Test functions begin
30 28 #-----------------------------------------------------------------------------
31 29 class Test_magic_run_completer(unittest.TestCase):
32 30 files = [u"aao.py", u"a.py", u"b.py", u"aao.txt"]
33 31 dirs = [u"adir/", "bdir/"]
34 32
35 33 def setUp(self):
36 34 self.BASETESTDIR = tempfile.mkdtemp()
37 35 for fil in self.files:
38 36 with open(join(self.BASETESTDIR, fil), "w") as sfile:
39 37 sfile.write("pass\n")
40 38 for d in self.dirs:
41 39 os.mkdir(join(self.BASETESTDIR, d))
42 40
43 41 self.oldpath = os.getcwd()
44 42 os.chdir(self.BASETESTDIR)
45 43
46 44 def tearDown(self):
47 45 os.chdir(self.oldpath)
48 46 shutil.rmtree(self.BASETESTDIR)
49 47
50 48 def test_1(self):
51 49 """Test magic_run_completer, should match two alternatives
52 50 """
53 51 event = MockEvent(u"%run a")
54 52 mockself = None
55 53 match = set(magic_run_completer(mockself, event))
56 54 self.assertEqual(match, {u"a.py", u"aao.py", u"adir/"})
57 55
58 56 def test_2(self):
59 57 """Test magic_run_completer, should match one alternative
60 58 """
61 59 event = MockEvent(u"%run aa")
62 60 mockself = None
63 61 match = set(magic_run_completer(mockself, event))
64 62 self.assertEqual(match, {u"aao.py"})
65 63
66 64 def test_3(self):
67 65 """Test magic_run_completer with unterminated " """
68 66 event = MockEvent(u'%run "a')
69 67 mockself = None
70 68 match = set(magic_run_completer(mockself, event))
71 69 self.assertEqual(match, {u"a.py", u"aao.py", u"adir/"})
72 70
73 71 def test_completion_more_args(self):
74 72 event = MockEvent(u'%run a.py ')
75 73 match = set(magic_run_completer(None, event))
76 74 self.assertEqual(match, set(self.files + self.dirs))
77 75
78 76 def test_completion_in_dir(self):
79 77 # Github issue #3459
80 78 event = MockEvent(u'%run a.py {}'.format(join(self.BASETESTDIR, 'a')))
81 79 print(repr(event.line))
82 80 match = set(magic_run_completer(None, event))
83 81 # We specifically use replace here rather than normpath, because
84 82 # at one point there were duplicates 'adir' and 'adir/', and normpath
85 83 # would hide the failure for that.
86 84 self.assertEqual(match, {join(self.BASETESTDIR, f).replace('\\','/')
87 85 for f in (u'a.py', u'aao.py', u'aao.txt', u'adir/')})
88 86
89 87 class Test_magic_run_completer_nonascii(unittest.TestCase):
90 88 @onlyif_unicode_paths
91 89 def setUp(self):
92 90 self.BASETESTDIR = tempfile.mkdtemp()
93 91 for fil in [u"aaø.py", u"a.py", u"b.py"]:
94 92 with open(join(self.BASETESTDIR, fil), "w") as sfile:
95 93 sfile.write("pass\n")
96 94 self.oldpath = os.getcwd()
97 95 os.chdir(self.BASETESTDIR)
98 96
99 97 def tearDown(self):
100 98 os.chdir(self.oldpath)
101 99 shutil.rmtree(self.BASETESTDIR)
102 100
103 101 @onlyif_unicode_paths
104 102 def test_1(self):
105 103 """Test magic_run_completer, should match two alternatives
106 104 """
107 105 event = MockEvent(u"%run a")
108 106 mockself = None
109 107 match = set(magic_run_completer(mockself, event))
110 108 self.assertEqual(match, {u"a.py", u"aaø.py"})
111 109
112 110 @onlyif_unicode_paths
113 111 def test_2(self):
114 112 """Test magic_run_completer, should match one alternative
115 113 """
116 114 event = MockEvent(u"%run aa")
117 115 mockself = None
118 116 match = set(magic_run_completer(mockself, event))
119 117 self.assertEqual(match, {u"aaø.py"})
120 118
121 119 @onlyif_unicode_paths
122 120 def test_3(self):
123 121 """Test magic_run_completer with unterminated " """
124 122 event = MockEvent(u'%run "a')
125 123 mockself = None
126 124 match = set(magic_run_completer(mockself, event))
127 125 self.assertEqual(match, {u"a.py", u"aaø.py"})
128 126
129 127 # module_completer:
130 128
131 129 def test_import_invalid_module():
132 130 """Testing of issue https://github.com/ipython/ipython/issues/1107"""
133 131 invalid_module_names = {'foo-bar', 'foo:bar', '10foo'}
134 132 valid_module_names = {'foobar'}
135 133 with TemporaryDirectory() as tmpdir:
136 134 sys.path.insert( 0, tmpdir )
137 135 for name in invalid_module_names | valid_module_names:
138 136 filename = os.path.join(tmpdir, name + '.py')
139 137 open(filename, 'w').close()
140 138
141 139 s = set( module_completion('import foo') )
142 140 intersection = s.intersection(invalid_module_names)
143 nt.assert_equal(intersection, set())
141 assert intersection == set()
144 142
145 143 assert valid_module_names.issubset(s), valid_module_names.intersection(s)
146 144
147 145
148 146 def test_bad_module_all():
149 147 """Test module with invalid __all__
150 148
151 149 https://github.com/ipython/ipython/issues/9678
152 150 """
153 151 testsdir = os.path.dirname(__file__)
154 152 sys.path.insert(0, testsdir)
155 153 try:
156 results = module_completion('from bad_all import ')
157 nt.assert_in('puppies', results)
154 results = module_completion("from bad_all import ")
155 assert "puppies" in results
158 156 for r in results:
159 nt.assert_is_instance(r, str)
157 assert isinstance(r, str)
160 158
161 159 # bad_all doesn't contain submodules, but this completion
162 160 # should finish without raising an exception:
163 161 results = module_completion("import bad_all.")
164 nt.assert_equal(results, [])
162 assert results == []
165 163 finally:
166 164 sys.path.remove(testsdir)
167 165
168 166
169 167 def test_module_without_init():
170 168 """
171 169 Test module without __init__.py.
172 170
173 171 https://github.com/ipython/ipython/issues/11226
174 172 """
175 173 fake_module_name = "foo"
176 174 with TemporaryDirectory() as tmpdir:
177 175 sys.path.insert(0, tmpdir)
178 176 try:
179 177 os.makedirs(os.path.join(tmpdir, fake_module_name))
180 178 s = try_import(mod=fake_module_name)
181 179 assert s == []
182 180 finally:
183 181 sys.path.remove(tmpdir)
184 182
185 183
186 184 def test_valid_exported_submodules():
187 185 """
188 186 Test checking exported (__all__) objects are submodules
189 187 """
190 188 results = module_completion("import os.pa")
191 189 # ensure we get a valid submodule:
192 nt.assert_in("os.path", results)
190 assert "os.path" in results
193 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 1 """Tests for debugging machinery.
2 2 """
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7 import bdb
8 8 import builtins
9 9 import os
10 10 import signal
11 11 import subprocess
12 12 import sys
13 13 import time
14 14 import warnings
15 15
16 16 from subprocess import PIPE, CalledProcessError, check_output
17 17 from tempfile import NamedTemporaryFile
18 18 from textwrap import dedent
19 19 from unittest.mock import patch
20 20
21 import nose.tools as nt
22
23 21 from IPython.core import debugger
24 22 from IPython.testing import IPYTHON_TESTING_TIMEOUT_SCALE
25 23 from IPython.testing.decorators import skip_win32
26 24
27 25 #-----------------------------------------------------------------------------
28 26 # Helper classes, from CPython's Pdb test suite
29 27 #-----------------------------------------------------------------------------
30 28
31 29 class _FakeInput(object):
32 30 """
33 31 A fake input stream for pdb's interactive debugger. Whenever a
34 32 line is read, print it (to simulate the user typing it), and then
35 33 return it. The set of lines to return is specified in the
36 34 constructor; they should not have trailing newlines.
37 35 """
38 36 def __init__(self, lines):
39 37 self.lines = iter(lines)
40 38
41 39 def readline(self):
42 40 line = next(self.lines)
43 41 print(line)
44 42 return line+'\n'
45 43
46 44 class PdbTestInput(object):
47 45 """Context manager that makes testing Pdb in doctests easier."""
48 46
49 47 def __init__(self, input):
50 48 self.input = input
51 49
52 50 def __enter__(self):
53 51 self.real_stdin = sys.stdin
54 52 sys.stdin = _FakeInput(self.input)
55 53
56 54 def __exit__(self, *exc):
57 55 sys.stdin = self.real_stdin
58 56
59 57 #-----------------------------------------------------------------------------
60 58 # Tests
61 59 #-----------------------------------------------------------------------------
62 60
63 61 def test_longer_repr():
64 62 from reprlib import repr as trepr
65 63
66 64 a = '1234567890'* 7
67 65 ar = "'1234567890123456789012345678901234567890123456789012345678901234567890'"
68 66 a_trunc = "'123456789012...8901234567890'"
69 nt.assert_equal(trepr(a), a_trunc)
67 assert trepr(a) == a_trunc
70 68 # The creation of our tracer modifies the repr module's repr function
71 69 # in-place, since that global is used directly by the stdlib's pdb module.
72 70 with warnings.catch_warnings():
73 71 warnings.simplefilter('ignore', DeprecationWarning)
74 72 debugger.Tracer()
75 nt.assert_equal(trepr(a), ar)
73 assert trepr(a) == ar
76 74
77 75 def test_ipdb_magics():
78 76 '''Test calling some IPython magics from ipdb.
79 77
80 78 First, set up some test functions and classes which we can inspect.
81 79
82 80 >>> class ExampleClass(object):
83 81 ... """Docstring for ExampleClass."""
84 82 ... def __init__(self):
85 83 ... """Docstring for ExampleClass.__init__"""
86 84 ... pass
87 85 ... def __str__(self):
88 86 ... return "ExampleClass()"
89 87
90 88 >>> def example_function(x, y, z="hello"):
91 89 ... """Docstring for example_function."""
92 90 ... pass
93 91
94 92 >>> old_trace = sys.gettrace()
95 93
96 94 Create a function which triggers ipdb.
97 95
98 96 >>> def trigger_ipdb():
99 97 ... a = ExampleClass()
100 98 ... debugger.Pdb().set_trace()
101 99
102 100 >>> with PdbTestInput([
103 101 ... 'pdef example_function',
104 102 ... 'pdoc ExampleClass',
105 103 ... 'up',
106 104 ... 'down',
107 105 ... 'list',
108 106 ... 'pinfo a',
109 107 ... 'll',
110 108 ... 'continue',
111 109 ... ]):
112 110 ... trigger_ipdb()
113 111 --Return--
114 112 None
115 113 > <doctest ...>(3)trigger_ipdb()
116 114 1 def trigger_ipdb():
117 115 2 a = ExampleClass()
118 116 ----> 3 debugger.Pdb().set_trace()
119 117 <BLANKLINE>
120 118 ipdb> pdef example_function
121 119 example_function(x, y, z='hello')
122 120 ipdb> pdoc ExampleClass
123 121 Class docstring:
124 122 Docstring for ExampleClass.
125 123 Init docstring:
126 124 Docstring for ExampleClass.__init__
127 125 ipdb> up
128 126 > <doctest ...>(11)<module>()
129 127 7 'pinfo a',
130 128 8 'll',
131 129 9 'continue',
132 130 10 ]):
133 131 ---> 11 trigger_ipdb()
134 132 <BLANKLINE>
135 133 ipdb> down
136 134 None
137 135 > <doctest ...>(3)trigger_ipdb()
138 136 1 def trigger_ipdb():
139 137 2 a = ExampleClass()
140 138 ----> 3 debugger.Pdb().set_trace()
141 139 <BLANKLINE>
142 140 ipdb> list
143 141 1 def trigger_ipdb():
144 142 2 a = ExampleClass()
145 143 ----> 3 debugger.Pdb().set_trace()
146 144 <BLANKLINE>
147 145 ipdb> pinfo a
148 146 Type: ExampleClass
149 147 String form: ExampleClass()
150 148 Namespace: Local...
151 149 Docstring: Docstring for ExampleClass.
152 150 Init docstring: Docstring for ExampleClass.__init__
153 151 ipdb> ll
154 152 1 def trigger_ipdb():
155 153 2 a = ExampleClass()
156 154 ----> 3 debugger.Pdb().set_trace()
157 155 <BLANKLINE>
158 156 ipdb> continue
159 157
160 158 Restore previous trace function, e.g. for coverage.py
161 159
162 160 >>> sys.settrace(old_trace)
163 161 '''
164 162
165 163 def test_ipdb_magics2():
166 164 '''Test ipdb with a very short function.
167 165
168 166 >>> old_trace = sys.gettrace()
169 167
170 168 >>> def bar():
171 169 ... pass
172 170
173 171 Run ipdb.
174 172
175 173 >>> with PdbTestInput([
176 174 ... 'continue',
177 175 ... ]):
178 176 ... debugger.Pdb().runcall(bar)
179 177 > <doctest ...>(2)bar()
180 178 1 def bar():
181 179 ----> 2 pass
182 180 <BLANKLINE>
183 181 ipdb> continue
184 182
185 183 Restore previous trace function, e.g. for coverage.py
186 184
187 185 >>> sys.settrace(old_trace)
188 186 '''
189 187
190 188 def can_quit():
191 189 '''Test that quit work in ipydb
192 190
193 191 >>> old_trace = sys.gettrace()
194 192
195 193 >>> def bar():
196 194 ... pass
197 195
198 196 >>> with PdbTestInput([
199 197 ... 'quit',
200 198 ... ]):
201 199 ... debugger.Pdb().runcall(bar)
202 200 > <doctest ...>(2)bar()
203 201 1 def bar():
204 202 ----> 2 pass
205 203 <BLANKLINE>
206 204 ipdb> quit
207 205
208 206 Restore previous trace function, e.g. for coverage.py
209 207
210 208 >>> sys.settrace(old_trace)
211 209 '''
212 210
213 211
214 212 def can_exit():
215 213 '''Test that quit work in ipydb
216 214
217 215 >>> old_trace = sys.gettrace()
218 216
219 217 >>> def bar():
220 218 ... pass
221 219
222 220 >>> with PdbTestInput([
223 221 ... 'exit',
224 222 ... ]):
225 223 ... debugger.Pdb().runcall(bar)
226 224 > <doctest ...>(2)bar()
227 225 1 def bar():
228 226 ----> 2 pass
229 227 <BLANKLINE>
230 228 ipdb> exit
231 229
232 230 Restore previous trace function, e.g. for coverage.py
233 231
234 232 >>> sys.settrace(old_trace)
235 233 '''
236 234
237 235
238 236 def test_interruptible_core_debugger():
239 237 """The debugger can be interrupted.
240 238
241 239 The presumption is there is some mechanism that causes a KeyboardInterrupt
242 240 (this is implemented in ipykernel). We want to ensure the
243 241 KeyboardInterrupt cause debugging to cease.
244 242 """
245 243 def raising_input(msg="", called=[0]):
246 244 called[0] += 1
247 245 if called[0] == 1:
248 246 raise KeyboardInterrupt()
249 247 else:
250 248 raise AssertionError("input() should only be called once!")
251 249
252 250 with patch.object(builtins, "input", raising_input):
253 251 debugger.InterruptiblePdb().set_trace()
254 252 # The way this test will fail is by set_trace() never exiting,
255 253 # resulting in a timeout by the test runner. The alternative
256 254 # implementation would involve a subprocess, but that adds issues with
257 255 # interrupting subprocesses that are rather complex, so it's simpler
258 256 # just to do it this way.
259 257
260 258 @skip_win32
261 259 def test_xmode_skip():
262 260 """that xmode skip frames
263 261
264 262 Not as a doctest as pytest does not run doctests.
265 263 """
266 264 import pexpect
267 265 env = os.environ.copy()
268 266 env["IPY_TEST_SIMPLE_PROMPT"] = "1"
269 267
270 268 child = pexpect.spawn(
271 269 sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
272 270 )
273 271 child.timeout = 15 * IPYTHON_TESTING_TIMEOUT_SCALE
274 272
275 273 child.expect("IPython")
276 274 child.expect("\n")
277 275 child.expect_exact("In [1]")
278 276
279 277 block = dedent(
280 278 """
281 279 def f():
282 280 __tracebackhide__ = True
283 281 g()
284 282
285 283 def g():
286 284 raise ValueError
287 285
288 286 f()
289 287 """
290 288 )
291 289
292 290 for line in block.splitlines():
293 291 child.sendline(line)
294 292 child.expect_exact(line)
295 293 child.expect_exact("skipping")
296 294
297 295 block = dedent(
298 296 """
299 297 def f():
300 298 __tracebackhide__ = True
301 299 g()
302 300
303 301 def g():
304 302 from IPython.core.debugger import set_trace
305 303 set_trace()
306 304
307 305 f()
308 306 """
309 307 )
310 308
311 309 for line in block.splitlines():
312 310 child.sendline(line)
313 311 child.expect_exact(line)
314 312
315 313 child.expect("ipdb>")
316 314 child.sendline("w")
317 315 child.expect("hidden")
318 316 child.expect("ipdb>")
319 317 child.sendline("skip_hidden false")
320 318 child.sendline("w")
321 319 child.expect("__traceba")
322 320 child.expect("ipdb>")
323 321
324 322 child.close()
325 323
326 324
327 325 skip_decorators_blocks = (
328 326 """
329 327 def helpers_helper():
330 328 pass # should not stop here except breakpoint
331 329 """,
332 330 """
333 331 def helper_1():
334 332 helpers_helper() # should not stop here
335 333 """,
336 334 """
337 335 def helper_2():
338 336 pass # should not stop here
339 337 """,
340 338 """
341 339 def pdb_skipped_decorator2(function):
342 340 def wrapped_fn(*args, **kwargs):
343 341 __debuggerskip__ = True
344 342 helper_2()
345 343 __debuggerskip__ = False
346 344 result = function(*args, **kwargs)
347 345 __debuggerskip__ = True
348 346 helper_2()
349 347 return result
350 348 return wrapped_fn
351 349 """,
352 350 """
353 351 def pdb_skipped_decorator(function):
354 352 def wrapped_fn(*args, **kwargs):
355 353 __debuggerskip__ = True
356 354 helper_1()
357 355 __debuggerskip__ = False
358 356 result = function(*args, **kwargs)
359 357 __debuggerskip__ = True
360 358 helper_2()
361 359 return result
362 360 return wrapped_fn
363 361 """,
364 362 """
365 363 @pdb_skipped_decorator
366 364 @pdb_skipped_decorator2
367 365 def bar(x, y):
368 366 return x * y
369 367 """,
370 368 """import IPython.terminal.debugger as ipdb""",
371 369 """
372 370 def f():
373 371 ipdb.set_trace()
374 372 bar(3, 4)
375 373 """,
376 374 """
377 375 f()
378 376 """,
379 377 )
380 378
381 379
382 380 def _decorator_skip_setup():
383 381 import pexpect
384 382
385 383 env = os.environ.copy()
386 384 env["IPY_TEST_SIMPLE_PROMPT"] = "1"
387 385
388 386 child = pexpect.spawn(
389 387 sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
390 388 )
391 389 child.timeout = 5 * IPYTHON_TESTING_TIMEOUT_SCALE
392 390
393 391 child.expect("IPython")
394 392 child.expect("\n")
395 393
396 394 dedented_blocks = [dedent(b).strip() for b in skip_decorators_blocks]
397 395 in_prompt_number = 1
398 396 for cblock in dedented_blocks:
399 397 child.expect_exact(f"In [{in_prompt_number}]:")
400 398 in_prompt_number += 1
401 399 for line in cblock.splitlines():
402 400 child.sendline(line)
403 401 child.expect_exact(line)
404 402 child.sendline("")
405 403 return child
406 404
407 405
408 406 @skip_win32
409 407 def test_decorator_skip():
410 408 """test that decorator frames can be skipped."""
411 409
412 410 child = _decorator_skip_setup()
413 411
414 412 child.expect_exact("3 bar(3, 4)")
415 413 child.expect("ipdb>")
416 414
417 415 child.expect("ipdb>")
418 416 child.sendline("step")
419 417 child.expect_exact("step")
420 418
421 419 child.expect_exact("1 @pdb_skipped_decorator")
422 420
423 421 child.sendline("s")
424 422 child.expect_exact("return x * y")
425 423
426 424 child.close()
427 425
428 426
429 427 @skip_win32
430 428 def test_decorator_skip_disabled():
431 429 """test that decorator frame skipping can be disabled"""
432 430
433 431 child = _decorator_skip_setup()
434 432
435 433 child.expect_exact("3 bar(3, 4)")
436 434
437 435 for input_, expected in [
438 436 ("skip_predicates debuggerskip False", ""),
439 437 ("skip_predicates", "debuggerskip : False"),
440 438 ("step", "---> 2 def wrapped_fn"),
441 439 ("step", "----> 3 __debuggerskip__"),
442 440 ("step", "----> 4 helper_1()"),
443 441 ("step", "---> 1 def helper_1():"),
444 442 ("next", "----> 2 helpers_helper()"),
445 443 ("next", "--Return--"),
446 444 ("next", "----> 5 __debuggerskip__ = False"),
447 445 ]:
448 446 child.expect("ipdb>")
449 447 child.sendline(input_)
450 448 child.expect_exact(input_)
451 449 child.expect_exact(expected)
452 450
453 451 child.close()
454 452
455 453
456 454 @skip_win32
457 455 def test_decorator_skip_with_breakpoint():
458 456 """test that decorator frame skipping can be disabled"""
459 457
460 458 import pexpect
461 459
462 460 env = os.environ.copy()
463 461 env["IPY_TEST_SIMPLE_PROMPT"] = "1"
464 462
465 463 child = pexpect.spawn(
466 464 sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
467 465 )
468 466 child.timeout = 5 * IPYTHON_TESTING_TIMEOUT_SCALE
469 467
470 468 child.expect("IPython")
471 469 child.expect("\n")
472 470
473 471 ### we need a filename, so we need to exec the full block with a filename
474 472 with NamedTemporaryFile(suffix=".py", dir=".", delete=True) as tf:
475 473
476 474 name = tf.name[:-3].split("/")[-1]
477 475 tf.write("\n".join([dedent(x) for x in skip_decorators_blocks[:-1]]).encode())
478 476 tf.flush()
479 477 codeblock = f"from {name} import f"
480 478
481 479 dedented_blocks = [
482 480 codeblock,
483 481 "f()",
484 482 ]
485 483
486 484 in_prompt_number = 1
487 485 for cblock in dedented_blocks:
488 486 child.expect_exact(f"In [{in_prompt_number}]:")
489 487 in_prompt_number += 1
490 488 for line in cblock.splitlines():
491 489 child.sendline(line)
492 490 child.expect_exact(line)
493 491 child.sendline("")
494 492
495 493 # as the filename does not exists, we'll rely on the filename prompt
496 494 child.expect_exact("47 bar(3, 4)")
497 495
498 496 for input_, expected in [
499 497 (f"b {name}.py:3", ""),
500 498 ("step", "1---> 3 pass # should not stop here except"),
501 499 ("step", "---> 38 @pdb_skipped_decorator"),
502 500 ("continue", ""),
503 501 ]:
504 502 child.expect("ipdb>")
505 503 child.sendline(input_)
506 504 child.expect_exact(input_)
507 505 child.expect_exact(expected)
508 506
509 507 child.close()
510 508
511 509
512 510 @skip_win32
513 511 def test_where_erase_value():
514 512 """Test that `where` does not access f_locals and erase values."""
515 513 import pexpect
516 514
517 515 env = os.environ.copy()
518 516 env["IPY_TEST_SIMPLE_PROMPT"] = "1"
519 517
520 518 child = pexpect.spawn(
521 519 sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
522 520 )
523 521 child.timeout = 15 * IPYTHON_TESTING_TIMEOUT_SCALE
524 522
525 523 child.expect("IPython")
526 524 child.expect("\n")
527 525 child.expect_exact("In [1]")
528 526
529 527 block = dedent(
530 528 """
531 529 def simple_f():
532 530 myvar = 1
533 531 print(myvar)
534 532 1/0
535 533 print(myvar)
536 534 simple_f() """
537 535 )
538 536
539 537 for line in block.splitlines():
540 538 child.sendline(line)
541 539 child.expect_exact(line)
542 540 child.expect_exact("ZeroDivisionError")
543 541 child.expect_exact("In [2]:")
544 542
545 543 child.sendline("%debug")
546 544
547 545 ##
548 546 child.expect("ipdb>")
549 547
550 548 child.sendline("myvar")
551 549 child.expect("1")
552 550
553 551 ##
554 552 child.expect("ipdb>")
555 553
556 554 child.sendline("myvar = 2")
557 555
558 556 ##
559 557 child.expect_exact("ipdb>")
560 558
561 559 child.sendline("myvar")
562 560
563 561 child.expect_exact("2")
564 562
565 563 ##
566 564 child.expect("ipdb>")
567 565 child.sendline("where")
568 566
569 567 ##
570 568 child.expect("ipdb>")
571 569 child.sendline("myvar")
572 570
573 571 child.expect_exact("2")
574 572 child.expect("ipdb>")
575 573
576 574 child.close()
@@ -1,490 +1,511 b''
1 1 # Copyright (c) IPython Development Team.
2 2 # Distributed under the terms of the Modified BSD License.
3 3
4 4 import json
5 5 import os
6 6 import warnings
7 7
8 8 from unittest import mock
9 9
10 import nose.tools as nt
10 import pytest
11 11
12 12 from IPython import display
13 13 from IPython.core.getipython import get_ipython
14 14 from IPython.utils.io import capture_output
15 15 from IPython.utils.tempdir import NamedFileInTemporaryDirectory
16 16 from IPython import paths as ipath
17 17 from IPython.testing.tools import AssertNotPrints
18 18
19 19 import IPython.testing.decorators as dec
20 20
21 21 def test_image_size():
22 22 """Simple test for display.Image(args, width=x,height=y)"""
23 23 thisurl = 'http://www.google.fr/images/srpr/logo3w.png'
24 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 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 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 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 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 36 def test_image_mimes():
37 37 fmt = get_ipython().display_formatter.format
38 38 for format in display.Image._ACCEPTABLE_EMBEDDINGS:
39 39 mime = display.Image._MIMETYPES[format]
40 40 img = display.Image(b'garbage', format=format)
41 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 45 def test_geojson():
46 46
47 47 gj = display.GeoJSON(data={
48 48 "type": "Feature",
49 49 "geometry": {
50 50 "type": "Point",
51 51 "coordinates": [-81.327, 296.038]
52 52 },
53 53 "properties": {
54 54 "name": "Inca City"
55 55 }
56 56 },
57 57 url_template="http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/{basemap_id}/{z}/{x}/{y}.png",
58 58 layer_options={
59 59 "basemap_id": "celestia_mars-shaded-16k_global",
60 60 "attribution": "Celestia/praesepe",
61 61 "minZoom": 0,
62 62 "maxZoom": 18,
63 })
64 nt.assert_equal(u'<IPython.core.display.GeoJSON object>', str(gj))
63 },
64 )
65 assert "<IPython.core.display.GeoJSON object>" == str(gj)
66
65 67
66 68 def test_retina_png():
67 69 here = os.path.dirname(__file__)
68 70 img = display.Image(os.path.join(here, "2x2.png"), retina=True)
69 nt.assert_equal(img.height, 1)
70 nt.assert_equal(img.width, 1)
71 assert img.height == 1
72 assert img.width == 1
71 73 data, md = img._repr_png_()
72 nt.assert_equal(md['width'], 1)
73 nt.assert_equal(md['height'], 1)
74 assert md["width"] == 1
75 assert md["height"] == 1
76
74 77
75 78 def test_embed_svg_url():
76 79 import gzip
77 80 from io import BytesIO
78 81 svg_data = b'<svg><circle x="0" y="0" r="1"/></svg>'
79 82 url = 'http://test.com/circle.svg'
80 83
81 84 gzip_svg = BytesIO()
82 85 with gzip.open(gzip_svg, 'wb') as fp:
83 86 fp.write(svg_data)
84 87 gzip_svg = gzip_svg.getvalue()
85 88
86 89 def mocked_urlopen(*args, **kwargs):
87 90 class MockResponse:
88 91 def __init__(self, svg):
89 92 self._svg_data = svg
90 93 self.headers = {'content-type': 'image/svg+xml'}
91 94
92 95 def read(self):
93 96 return self._svg_data
94 97
95 98 if args[0] == url:
96 99 return MockResponse(svg_data)
97 100 elif args[0] == url + "z":
98 101 ret = MockResponse(gzip_svg)
99 102 ret.headers["content-encoding"] = "gzip"
100 103 return ret
101 104 return MockResponse(None)
102 105
103 106 with mock.patch('urllib.request.urlopen', side_effect=mocked_urlopen):
104 107 svg = display.SVG(url=url)
105 nt.assert_true(svg._repr_svg_().startswith('<svg'))
106 svg = display.SVG(url=url + 'z')
107 nt.assert_true(svg._repr_svg_().startswith('<svg'))
108 assert svg._repr_svg_().startswith("<svg") is True
109 svg = display.SVG(url=url + "z")
110 assert svg._repr_svg_().startswith("<svg") is True
111
108 112
109 113 def test_retina_jpeg():
110 114 here = os.path.dirname(__file__)
111 115 img = display.Image(os.path.join(here, "2x2.jpg"), retina=True)
112 nt.assert_equal(img.height, 1)
113 nt.assert_equal(img.width, 1)
116 assert img.height == 1
117 assert img.width == 1
114 118 data, md = img._repr_jpeg_()
115 nt.assert_equal(md['width'], 1)
116 nt.assert_equal(md['height'], 1)
119 assert md["width"] == 1
120 assert md["height"] == 1
121
117 122
118 123 def test_base64image():
119 124 display.Image("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB94BCRQnOqNu0b4AAAAKSURBVAjXY2AAAAACAAHiIbwzAAAAAElFTkSuQmCC")
120 125
121 126 def test_image_filename_defaults():
122 127 '''test format constraint, and validity of jpeg and png'''
123 128 tpath = ipath.get_ipython_package_dir()
124 nt.assert_raises(ValueError, display.Image, filename=os.path.join(tpath, 'testing/tests/badformat.zip'),
125 embed=True)
126 nt.assert_raises(ValueError, display.Image)
127 nt.assert_raises(ValueError, display.Image, data='this is not an image', format='badformat', embed=True)
128 # check both paths to allow packages to test at build and install time
129 pytest.raises(
130 ValueError,
131 display.Image,
132 filename=os.path.join(tpath, "testing/tests/badformat.zip"),
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 144 imgfile = os.path.join(tpath, 'core/tests/2x2.png')
130 145 img = display.Image(filename=imgfile)
131 nt.assert_equal('png', img.format)
132 nt.assert_is_not_none(img._repr_png_())
133 img = display.Image(filename=os.path.join(tpath, 'testing/tests/logo.jpg'), embed=False)
134 nt.assert_equal('jpeg', img.format)
135 nt.assert_is_none(img._repr_jpeg_())
146 assert "png" == img.format
147 assert img._repr_png_() is not None
148 img = display.Image(
149 filename=os.path.join(tpath, "testing/tests/logo.jpg"), embed=False
150 )
151 assert "jpeg" == img.format
152 assert img._repr_jpeg_() is None
136 153
137 154 def _get_inline_config():
138 155 from matplotlib_inline.config import InlineBackend
139 156 return InlineBackend.instance()
140 157
141 158
142 159 @dec.skip_without("ipykernel")
143 160 @dec.skip_without("matplotlib")
144 161 def test_set_matplotlib_close():
145 162 cfg = _get_inline_config()
146 163 cfg.close_figures = False
147 164 display.set_matplotlib_close()
148 165 assert cfg.close_figures
149 166 display.set_matplotlib_close(False)
150 167 assert not cfg.close_figures
151 168
152 169 _fmt_mime_map = {
153 170 'png': 'image/png',
154 171 'jpeg': 'image/jpeg',
155 172 'pdf': 'application/pdf',
156 173 'retina': 'image/png',
157 174 'svg': 'image/svg+xml',
158 175 }
159 176
160 177 @dec.skip_without('matplotlib')
161 178 def test_set_matplotlib_formats():
162 179 from matplotlib.figure import Figure
163 180 formatters = get_ipython().display_formatter.formatters
164 181 for formats in [
165 182 ('png',),
166 183 ('pdf', 'svg'),
167 184 ('jpeg', 'retina', 'png'),
168 185 (),
169 186 ]:
170 187 active_mimes = {_fmt_mime_map[fmt] for fmt in formats}
171 188 display.set_matplotlib_formats(*formats)
172 189 for mime, f in formatters.items():
173 190 if mime in active_mimes:
174 nt.assert_in(Figure, f)
191 assert Figure in f
175 192 else:
176 nt.assert_not_in(Figure, f)
193 assert Figure not in f
177 194
178 195
179 196 @dec.skip_without("ipykernel")
180 197 @dec.skip_without("matplotlib")
181 198 def test_set_matplotlib_formats_kwargs():
182 199 from matplotlib.figure import Figure
183 200 ip = get_ipython()
184 201 cfg = _get_inline_config()
185 202 cfg.print_figure_kwargs.update(dict(foo='bar'))
186 203 kwargs = dict(dpi=150)
187 204 display.set_matplotlib_formats('png', **kwargs)
188 205 formatter = ip.display_formatter.formatters['image/png']
189 206 f = formatter.lookup_by_type(Figure)
190 207 formatter_kwargs = f.keywords
191 208 expected = kwargs
192 209 expected["base64"] = True
193 210 expected["fmt"] = "png"
194 211 expected.update(cfg.print_figure_kwargs)
195 nt.assert_equal(formatter_kwargs, expected)
212 assert formatter_kwargs == expected
196 213
197 214 def test_display_available():
198 215 """
199 216 Test that display is available without import
200 217
201 218 We don't really care if it's in builtin or anything else, but it should
202 219 always be available.
203 220 """
204 221 ip = get_ipython()
205 222 with AssertNotPrints('NameError'):
206 223 ip.run_cell('display')
207 224 try:
208 225 ip.run_cell('del display')
209 226 except NameError:
210 227 pass # it's ok, it might be in builtins
211 228 # even if deleted it should be back
212 229 with AssertNotPrints('NameError'):
213 230 ip.run_cell('display')
214 231
215 232 def test_textdisplayobj_pretty_repr():
216 p = display.Pretty("This is a simple test")
217 nt.assert_equal(repr(p), '<IPython.core.display.Pretty object>')
218 nt.assert_equal(p.data, 'This is a simple test')
233 p = display.Pretty("This is a simple test")
234 assert repr(p) == "<IPython.core.display.Pretty object>"
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 241 def test_displayobject_repr():
224 h = display.HTML('<br />')
225 nt.assert_equal(repr(h), '<IPython.core.display.HTML object>')
242 h = display.HTML("<br />")
243 assert repr(h) == "<IPython.core.display.HTML object>"
226 244 h._show_mem_addr = True
227 nt.assert_equal(repr(h), object.__repr__(h))
245 assert repr(h) == object.__repr__(h)
228 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('')
232 nt.assert_equal(repr(j), '<IPython.core.display.Javascript object>')
249 j = display.Javascript("")
250 assert repr(j) == "<IPython.core.display.Javascript object>"
233 251 j._show_mem_addr = True
234 nt.assert_equal(repr(j), object.__repr__(j))
252 assert repr(j) == object.__repr__(j)
235 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 256 @mock.patch('warnings.warn')
239 257 def test_encourage_iframe_over_html(m_warn):
240 258 display.HTML()
241 259 m_warn.assert_not_called()
242 260
243 261 display.HTML('<br />')
244 262 m_warn.assert_not_called()
245 263
246 264 display.HTML('<html><p>Lots of content here</p><iframe src="http://a.com"></iframe>')
247 265 m_warn.assert_not_called()
248 266
249 267 display.HTML('<iframe src="http://a.com"></iframe>')
250 268 m_warn.assert_called_with('Consider using IPython.display.IFrame instead')
251 269
252 270 m_warn.reset_mock()
253 271 display.HTML('<IFRAME SRC="http://a.com"></IFRAME>')
254 272 m_warn.assert_called_with('Consider using IPython.display.IFrame instead')
255 273
256 274 def test_progress():
257 275 p = display.ProgressBar(10)
258 nt.assert_in('0/10',repr(p))
259 p.html_width = '100%'
276 assert "0/10" in repr(p)
277 p.html_width = "100%"
260 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 284 def test_progress_iter():
264 285 with capture_output(display=False) as captured:
265 286 for i in display.ProgressBar(5):
266 287 out = captured.stdout
267 nt.assert_in('{0}/5'.format(i), out)
288 assert "{0}/5".format(i) in out
268 289 out = captured.stdout
269 nt.assert_in('5/5', out)
290 assert "5/5" in out
291
270 292
271 293 def test_json():
272 294 d = {'a': 5}
273 295 lis = [d]
274 296 metadata = [
275 297 {'expanded': False, 'root': 'root'},
276 298 {'expanded': True, 'root': 'root'},
277 299 {'expanded': False, 'root': 'custom'},
278 300 {'expanded': True, 'root': 'custom'},
279 301 ]
280 302 json_objs = [
281 303 display.JSON(d),
282 304 display.JSON(d, expanded=True),
283 305 display.JSON(d, root='custom'),
284 306 display.JSON(d, expanded=True, root='custom'),
285 307 ]
286 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 311 with warnings.catch_warnings(record=True) as w:
290 312 warnings.simplefilter("always")
291 313 j = display.JSON(json.dumps(d))
292 nt.assert_equal(len(w), 1)
293 nt.assert_equal(j._repr_json_(), (d, metadata[0]))
314 assert len(w) == 1
315 assert j._repr_json_() == (d, metadata[0])
294 316
295 317 json_objs = [
296 318 display.JSON(lis),
297 319 display.JSON(lis, expanded=True),
298 320 display.JSON(lis, root='custom'),
299 321 display.JSON(lis, expanded=True, root='custom'),
300 322 ]
301 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 326 with warnings.catch_warnings(record=True) as w:
305 327 warnings.simplefilter("always")
306 328 j = display.JSON(json.dumps(lis))
307 nt.assert_equal(len(w), 1)
308 nt.assert_equal(j._repr_json_(), (lis, metadata[0]))
329 assert len(w) == 1
330 assert j._repr_json_() == (lis, metadata[0])
331
309 332
310 333 def test_video_embedding():
311 334 """use a tempfile, with dummy-data, to ensure that video embedding doesn't crash"""
312 335 v = display.Video("http://ignored")
313 336 assert not v.embed
314 337 html = v._repr_html_()
315 nt.assert_not_in('src="data:', html)
316 nt.assert_in('src="http://ignored"', html)
338 assert 'src="data:' not in html
339 assert 'src="http://ignored"' in html
317 340
318 with nt.assert_raises(ValueError):
341 with pytest.raises(ValueError):
319 342 v = display.Video(b'abc')
320 343
321 344 with NamedFileInTemporaryDirectory('test.mp4') as f:
322 345 f.write(b'abc')
323 346 f.close()
324 347
325 348 v = display.Video(f.name)
326 349 assert not v.embed
327 350 html = v._repr_html_()
328 nt.assert_not_in('src="data:', html)
351 assert 'src="data:' not in html
329 352
330 353 v = display.Video(f.name, embed=True)
331 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 357 v = display.Video(f.name, embed=True, mimetype='video/other')
335 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 361 v = display.Video(b'abc', embed=True, mimetype='video/mp4')
339 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 365 v = display.Video(u'YWJj', embed=True, mimetype='video/xyz')
343 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 369 def test_html_metadata():
347 370 s = "<h1>Test</h1>"
348 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 375 def test_display_id():
352 376 ip = get_ipython()
353 377 with mock.patch.object(ip.display_pub, 'publish') as pub:
354 378 handle = display.display('x')
355 nt.assert_is(handle, None)
379 assert handle is None
356 380 handle = display.display('y', display_id='secret')
357 nt.assert_is_instance(handle, display.DisplayHandle)
381 assert isinstance(handle, display.DisplayHandle)
358 382 handle2 = display.display('z', display_id=True)
359 nt.assert_is_instance(handle2, display.DisplayHandle)
360 nt.assert_not_equal(handle.display_id, handle2.display_id)
383 assert isinstance(handle2, display.DisplayHandle)
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 387 args, kwargs = pub.call_args_list[0]
364 nt.assert_equal(args, ())
365 nt.assert_equal(kwargs, {
388 assert args == ()
389 assert kwargs == {
366 390 'data': {
367 391 'text/plain': repr('x')
368 392 },
369 393 'metadata': {},
370 })
394 }
371 395 args, kwargs = pub.call_args_list[1]
372 nt.assert_equal(args, ())
373 nt.assert_equal(kwargs, {
396 assert args == ()
397 assert kwargs == {
374 398 'data': {
375 399 'text/plain': repr('y')
376 400 },
377 401 'metadata': {},
378 402 'transient': {
379 403 'display_id': handle.display_id,
380 404 },
381 })
405 }
382 406 args, kwargs = pub.call_args_list[2]
383 nt.assert_equal(args, ())
384 nt.assert_equal(kwargs, {
407 assert args == ()
408 assert kwargs == {
385 409 'data': {
386 410 'text/plain': repr('z')
387 411 },
388 412 'metadata': {},
389 413 'transient': {
390 414 'display_id': handle2.display_id,
391 415 },
392 })
416 }
393 417
394 418
395 419 def test_update_display():
396 420 ip = get_ipython()
397 421 with mock.patch.object(ip.display_pub, 'publish') as pub:
398 with nt.assert_raises(TypeError):
422 with pytest.raises(TypeError):
399 423 display.update_display('x')
400 424 display.update_display('x', display_id='1')
401 425 display.update_display('y', display_id='2')
402 426 args, kwargs = pub.call_args_list[0]
403 nt.assert_equal(args, ())
404 nt.assert_equal(kwargs, {
427 assert args == ()
428 assert kwargs == {
405 429 'data': {
406 430 'text/plain': repr('x')
407 431 },
408 432 'metadata': {},
409 433 'transient': {
410 434 'display_id': '1',
411 435 },
412 436 'update': True,
413 })
437 }
414 438 args, kwargs = pub.call_args_list[1]
415 nt.assert_equal(args, ())
416 nt.assert_equal(kwargs, {
439 assert args == ()
440 assert kwargs == {
417 441 'data': {
418 442 'text/plain': repr('y')
419 443 },
420 444 'metadata': {},
421 445 'transient': {
422 446 'display_id': '2',
423 447 },
424 448 'update': True,
425 })
449 }
426 450
427 451
428 452 def test_display_handle():
429 453 ip = get_ipython()
430 454 handle = display.DisplayHandle()
431 nt.assert_is_instance(handle.display_id, str)
432 handle = display.DisplayHandle('my-id')
433 nt.assert_equal(handle.display_id, 'my-id')
434 with mock.patch.object(ip.display_pub, 'publish') as pub:
435 handle.display('x')
436 handle.update('y')
455 assert isinstance(handle.display_id, str)
456 handle = display.DisplayHandle("my-id")
457 assert handle.display_id == "my-id"
458 with mock.patch.object(ip.display_pub, "publish") as pub:
459 handle.display("x")
460 handle.update("y")
437 461
438 462 args, kwargs = pub.call_args_list[0]
439 nt.assert_equal(args, ())
440 nt.assert_equal(kwargs, {
463 assert args == ()
464 assert kwargs == {
441 465 'data': {
442 466 'text/plain': repr('x')
443 467 },
444 468 'metadata': {},
445 469 'transient': {
446 470 'display_id': handle.display_id,
447 471 }
448 })
472 }
449 473 args, kwargs = pub.call_args_list[1]
450 nt.assert_equal(args, ())
451 nt.assert_equal(kwargs, {
474 assert args == ()
475 assert kwargs == {
452 476 'data': {
453 477 'text/plain': repr('y')
454 478 },
455 479 'metadata': {},
456 480 'transient': {
457 481 'display_id': handle.display_id,
458 482 },
459 483 'update': True,
460 })
484 }
461 485
462 486
463 487 def test_image_alt_tag():
464 488 """Simple test for display.Image(args, alt=x,)"""
465 489 thisurl = "http://example.com/image.png"
466 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 492 img = display.Image(url=thisurl, unconfined=True, alt="an image")
469 nt.assert_equal(
470 u'<img src="%s" class="unconfined" alt="an image"/>' % (thisurl),
471 img._repr_html_(),
493 assert (
494 '<img src="%s" class="unconfined" alt="an image"/>' % (thisurl)
495 == img._repr_html_()
472 496 )
473 497 img = display.Image(url=thisurl, alt='>"& <')
474 nt.assert_equal(
475 u'<img src="%s" alt="&gt;&quot;&amp; &lt;"/>' % (thisurl), img._repr_html_()
476 )
498 assert '<img src="%s" alt="&gt;&quot;&amp; &lt;"/>' % (thisurl) == img._repr_html_()
477 499
478 500 img = display.Image(url=thisurl, metadata={"alt": "an image"})
479 nt.assert_equal(img.alt, "an image")
480
501 assert img.alt == "an image"
481 502 here = os.path.dirname(__file__)
482 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 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 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 1 import unittest
2 2 from unittest.mock import Mock
3 import nose.tools as nt
4 3
5 4 from IPython.core import events
6 5 import IPython.testing.tools as tt
7 6
8 7
9 8 @events._define_event
10 9 def ping_received():
11 10 pass
12 11
13 12
14 13 @events._define_event
15 14 def event_with_argument(argument):
16 15 pass
17 16
18 17
19 18 class CallbackTests(unittest.TestCase):
20 19 def setUp(self):
21 20 self.em = events.EventManager(get_ipython(),
22 21 {'ping_received': ping_received,
23 22 'event_with_argument': event_with_argument})
24 23
25 24 def test_register_unregister(self):
26 25 cb = Mock()
27 26
28 27 self.em.register('ping_received', cb)
29 28 self.em.trigger('ping_received')
30 29 self.assertEqual(cb.call_count, 1)
31 30
32 31 self.em.unregister('ping_received', cb)
33 32 self.em.trigger('ping_received')
34 33 self.assertEqual(cb.call_count, 1)
35 34
36 35 def test_bare_function_missed_unregister(self):
37 36 def cb1():
38 37 ...
39 38
40 39 def cb2():
41 40 ...
42 41
43 self.em.register('ping_received', cb1)
44 nt.assert_raises(ValueError, self.em.unregister, 'ping_received', cb2)
45 self.em.unregister('ping_received', cb1)
42 self.em.register("ping_received", cb1)
43 self.assertRaises(ValueError, self.em.unregister, "ping_received", cb2)
44 self.em.unregister("ping_received", cb1)
46 45
47 46 def test_cb_error(self):
48 47 cb = Mock(side_effect=ValueError)
49 48 self.em.register('ping_received', cb)
50 49 with tt.AssertPrints("Error in callback"):
51 50 self.em.trigger('ping_received')
52 51
53 52 def test_cb_keyboard_interrupt(self):
54 53 cb = Mock(side_effect=KeyboardInterrupt)
55 54 self.em.register('ping_received', cb)
56 55 with tt.AssertPrints("Error in callback"):
57 56 self.em.trigger('ping_received')
58 57
59 58 def test_unregister_during_callback(self):
60 59 invoked = [False] * 3
61 60
62 61 def func1(*_):
63 62 invoked[0] = True
64 63 self.em.unregister('ping_received', func1)
65 64 self.em.register('ping_received', func3)
66 65
67 66 def func2(*_):
68 67 invoked[1] = True
69 68 self.em.unregister('ping_received', func2)
70 69
71 70 def func3(*_):
72 71 invoked[2] = True
73 72
74 73 self.em.register('ping_received', func1)
75 74 self.em.register('ping_received', func2)
76 75
77 76 self.em.trigger('ping_received')
78 77 self.assertEqual([True, True, False], invoked)
79 78 self.assertEqual([func3], self.em.callbacks['ping_received'])
80 79
81 80 def test_ignore_event_arguments_if_no_argument_required(self):
82 81 call_count = [0]
83 82 def event_with_no_argument():
84 83 call_count[0] += 1
85 84
86 85 self.em.register('event_with_argument', event_with_no_argument)
87 86 self.em.trigger('event_with_argument', 'the argument')
88 87 self.assertEqual(call_count[0], 1)
89 88
90 89 self.em.unregister('event_with_argument', event_with_no_argument)
91 90 self.em.trigger('ping_received')
92 91 self.assertEqual(call_count[0], 1)
@@ -1,96 +1,94 b''
1 1 import os.path
2 2
3 import nose.tools as nt
4
5 3 import IPython.testing.tools as tt
6 4 from IPython.utils.syspathcontext import prepended_to_syspath
7 5 from IPython.utils.tempdir import TemporaryDirectory
8 6
9 7 ext1_content = """
10 8 def load_ipython_extension(ip):
11 9 print("Running ext1 load")
12 10
13 11 def unload_ipython_extension(ip):
14 12 print("Running ext1 unload")
15 13 """
16 14
17 15 ext2_content = """
18 16 def load_ipython_extension(ip):
19 17 print("Running ext2 load")
20 18 """
21 19
22 20 ext3_content = """
23 21 def load_ipython_extension(ip):
24 22 ip2 = get_ipython()
25 23 print(ip is ip2)
26 24 """
27 25
28 26 def test_extension_loading():
29 27 em = get_ipython().extension_manager
30 28 with TemporaryDirectory() as td:
31 29 ext1 = os.path.join(td, 'ext1.py')
32 30 with open(ext1, 'w') as f:
33 31 f.write(ext1_content)
34 32
35 33 ext2 = os.path.join(td, 'ext2.py')
36 34 with open(ext2, 'w') as f:
37 35 f.write(ext2_content)
38 36
39 37 with prepended_to_syspath(td):
40 38 assert 'ext1' not in em.loaded
41 39 assert 'ext2' not in em.loaded
42 40
43 41 # Load extension
44 42 with tt.AssertPrints("Running ext1 load"):
45 43 assert em.load_extension('ext1') is None
46 44 assert 'ext1' in em.loaded
47 45
48 46 # Should refuse to load it again
49 47 with tt.AssertNotPrints("Running ext1 load"):
50 48 assert em.load_extension('ext1') == 'already loaded'
51 49
52 50 # Reload
53 51 with tt.AssertPrints("Running ext1 unload"):
54 52 with tt.AssertPrints("Running ext1 load", suppress=False):
55 53 em.reload_extension('ext1')
56 54
57 55 # Unload
58 56 with tt.AssertPrints("Running ext1 unload"):
59 57 assert em.unload_extension('ext1') is None
60 58
61 59 # Can't unload again
62 60 with tt.AssertNotPrints("Running ext1 unload"):
63 61 assert em.unload_extension('ext1') == 'not loaded'
64 62 assert em.unload_extension('ext2') == 'not loaded'
65 63
66 64 # Load extension 2
67 65 with tt.AssertPrints("Running ext2 load"):
68 66 assert em.load_extension('ext2') is None
69 67
70 68 # Can't unload this
71 69 assert em.unload_extension('ext2') == 'no unload function'
72 70
73 71 # But can reload it
74 72 with tt.AssertPrints("Running ext2 load"):
75 73 em.reload_extension('ext2')
76 74
77 75
78 76 def test_extension_builtins():
79 77 em = get_ipython().extension_manager
80 78 with TemporaryDirectory() as td:
81 79 ext3 = os.path.join(td, 'ext3.py')
82 80 with open(ext3, 'w') as f:
83 81 f.write(ext3_content)
84 82
85 83 assert 'ext3' not in em.loaded
86 84
87 85 with prepended_to_syspath(td):
88 86 # Load extension
89 87 with tt.AssertPrints("True"):
90 88 assert em.load_extension('ext3') is None
91 89 assert 'ext3' in em.loaded
92 90
93 91
94 92 def test_non_extension():
95 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 1 """Tests for the Formatters."""
2 2
3 3 import warnings
4 4 from math import pi
5 5
6 6 try:
7 7 import numpy
8 8 except:
9 9 numpy = None
10 import nose.tools as nt
10 import pytest
11 11
12 12 from IPython import get_ipython
13 13 from traitlets.config import Config
14 14 from IPython.core.formatters import (
15 15 PlainTextFormatter, HTMLFormatter, PDFFormatter, _mod_name_key,
16 16 DisplayFormatter, JSONFormatter,
17 17 )
18 18 from IPython.utils.io import capture_output
19 19
20 20 class A(object):
21 21 def __repr__(self):
22 22 return 'A()'
23 23
24 24 class B(A):
25 25 def __repr__(self):
26 26 return 'B()'
27 27
28 28 class C:
29 29 pass
30 30
31 31 class BadRepr(object):
32 32 def __repr__(self):
33 33 raise ValueError("bad repr")
34 34
35 35 class BadPretty(object):
36 36 _repr_pretty_ = None
37 37
38 38 class GoodPretty(object):
39 39 def _repr_pretty_(self, pp, cycle):
40 40 pp.text('foo')
41 41
42 42 def __repr__(self):
43 43 return 'GoodPretty()'
44 44
45 45 def foo_printer(obj, pp, cycle):
46 46 pp.text('foo')
47 47
48 48 def test_pretty():
49 49 f = PlainTextFormatter()
50 50 f.for_type(A, foo_printer)
51 51 assert f(A()) == "foo"
52 52 assert f(B()) == "B()"
53 53 assert f(GoodPretty()) == "foo"
54 54 # Just don't raise an exception for the following:
55 55 f(BadPretty())
56 56
57 57 f.pprint = False
58 58 assert f(A()) == "A()"
59 59 assert f(B()) == "B()"
60 60 assert f(GoodPretty()) == "GoodPretty()"
61 61
62 62
63 63 def test_deferred():
64 64 f = PlainTextFormatter()
65 65
66 66 def test_precision():
67 67 """test various values for float_precision."""
68 68 f = PlainTextFormatter()
69 69 assert f(pi) == repr(pi)
70 70 f.float_precision = 0
71 71 if numpy:
72 72 po = numpy.get_printoptions()
73 73 assert po["precision"] == 0
74 74 assert f(pi) == "3"
75 75 f.float_precision = 2
76 76 if numpy:
77 77 po = numpy.get_printoptions()
78 78 assert po["precision"] == 2
79 79 assert f(pi) == "3.14"
80 80 f.float_precision = "%g"
81 81 if numpy:
82 82 po = numpy.get_printoptions()
83 83 assert po["precision"] == 2
84 84 assert f(pi) == "3.14159"
85 85 f.float_precision = "%e"
86 86 assert f(pi) == "3.141593e+00"
87 87 f.float_precision = ""
88 88 if numpy:
89 89 po = numpy.get_printoptions()
90 90 assert po["precision"] == 8
91 91 assert f(pi) == repr(pi)
92 92
93 93
94 94 def test_bad_precision():
95 95 """test various invalid values for float_precision."""
96 96 f = PlainTextFormatter()
97 97 def set_fp(p):
98 f.float_precision=p
99 nt.assert_raises(ValueError, set_fp, '%')
100 nt.assert_raises(ValueError, set_fp, '%.3f%i')
101 nt.assert_raises(ValueError, set_fp, 'foo')
102 nt.assert_raises(ValueError, set_fp, -1)
98 f.float_precision = p
99
100 pytest.raises(ValueError, set_fp, "%")
101 pytest.raises(ValueError, set_fp, "%.3f%i")
102 pytest.raises(ValueError, set_fp, "foo")
103 pytest.raises(ValueError, set_fp, -1)
103 104
104 105 def test_for_type():
105 106 f = PlainTextFormatter()
106 107
107 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 110 # no func queries
110 nt.assert_is(f.for_type(C), foo_printer)
111 assert f.for_type(C) is foo_printer
111 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 114 # None should do the same
114 nt.assert_is(f.for_type(C, None), foo_printer)
115 nt.assert_is(f.for_type(C, None), foo_printer)
115 assert f.for_type(C, None) is foo_printer
116 assert f.for_type(C, None) is foo_printer
116 117
117 118 def test_for_type_string():
118 119 f = PlainTextFormatter()
119 120
120 121 type_str = '%s.%s' % (C.__module__, 'C')
121 122
122 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 125 # no func queries
125 nt.assert_is(f.for_type(type_str), foo_printer)
126 nt.assert_in(_mod_name_key(C), f.deferred_printers)
127 nt.assert_is(f.for_type(C), foo_printer)
128 nt.assert_not_in(_mod_name_key(C), f.deferred_printers)
129 nt.assert_in(C, f.type_printers)
126 assert f.for_type(type_str) is foo_printer
127 assert _mod_name_key(C) in f.deferred_printers
128 assert f.for_type(C) is foo_printer
129 assert _mod_name_key(C) not in f.deferred_printers
130 assert C in f.type_printers
130 131
131 132 def test_for_type_by_name():
132 133 f = PlainTextFormatter()
133 134
134 135 mod = C.__module__
135 136
136 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 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 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 143 # None should do the same
143 nt.assert_is(f.for_type_by_name(mod, 'C', None), foo_printer)
144 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
145 assert f.for_type_by_name(mod, "C", None) is foo_printer
146
145 147
146 148 def test_lookup():
147 149 f = PlainTextFormatter()
148 150
149 151 f.for_type(C, foo_printer)
150 nt.assert_is(f.lookup(C()), foo_printer)
151 with nt.assert_raises(KeyError):
152 assert f.lookup(C()) is foo_printer
153 with pytest.raises(KeyError):
152 154 f.lookup(A())
153 155
154 156 def test_lookup_string():
155 157 f = PlainTextFormatter()
156 158 type_str = '%s.%s' % (C.__module__, 'C')
157 159
158 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 162 # should move from deferred to imported dict
161 nt.assert_not_in(_mod_name_key(C), f.deferred_printers)
162 nt.assert_in(C, f.type_printers)
163 assert _mod_name_key(C) not in f.deferred_printers
164 assert C in f.type_printers
163 165
164 166 def test_lookup_by_type():
165 167 f = PlainTextFormatter()
166 168 f.for_type(C, foo_printer)
167 nt.assert_is(f.lookup_by_type(C), foo_printer)
168 with nt.assert_raises(KeyError):
169 assert f.lookup_by_type(C) is foo_printer
170 with pytest.raises(KeyError):
169 171 f.lookup_by_type(A)
170 172
171 173 def test_lookup_by_type_string():
172 174 f = PlainTextFormatter()
173 175 type_str = '%s.%s' % (C.__module__, 'C')
174 176 f.for_type(type_str, foo_printer)
175 177
176 178 # verify insertion
177 nt.assert_in(_mod_name_key(C), f.deferred_printers)
178 nt.assert_not_in(C, f.type_printers)
179 assert _mod_name_key(C) in f.deferred_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 183 # lookup by string doesn't cause import
182 nt.assert_in(_mod_name_key(C), f.deferred_printers)
183 nt.assert_not_in(C, f.type_printers)
184 assert _mod_name_key(C) in f.deferred_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 188 # should move from deferred to imported dict
187 nt.assert_not_in(_mod_name_key(C), f.deferred_printers)
188 nt.assert_in(C, f.type_printers)
189 assert _mod_name_key(C) not in f.deferred_printers
190 assert C in f.type_printers
189 191
190 192 def test_in_formatter():
191 193 f = PlainTextFormatter()
192 194 f.for_type(C, foo_printer)
193 195 type_str = '%s.%s' % (C.__module__, 'C')
194 nt.assert_in(C, f)
195 nt.assert_in(type_str, f)
196 assert C in f
197 assert type_str in f
196 198
197 199 def test_string_in_formatter():
198 200 f = PlainTextFormatter()
199 201 type_str = '%s.%s' % (C.__module__, 'C')
200 202 f.for_type(type_str, foo_printer)
201 nt.assert_in(type_str, f)
202 nt.assert_in(C, f)
203 assert type_str in f
204 assert C in f
203 205
204 206 def test_pop():
205 207 f = PlainTextFormatter()
206 208 f.for_type(C, foo_printer)
207 nt.assert_is(f.lookup_by_type(C), foo_printer)
208 nt.assert_is(f.pop(C, None), foo_printer)
209 assert f.lookup_by_type(C) is foo_printer
210 assert f.pop(C, None) is foo_printer
209 211 f.for_type(C, foo_printer)
210 nt.assert_is(f.pop(C), foo_printer)
211 with nt.assert_raises(KeyError):
212 assert f.pop(C) is foo_printer
213 with pytest.raises(KeyError):
212 214 f.lookup_by_type(C)
213 with nt.assert_raises(KeyError):
215 with pytest.raises(KeyError):
214 216 f.pop(C)
215 with nt.assert_raises(KeyError):
217 with pytest.raises(KeyError):
216 218 f.pop(A)
217 nt.assert_is(f.pop(A, None), None)
219 assert f.pop(A, None) is None
218 220
219 221 def test_pop_string():
220 222 f = PlainTextFormatter()
221 223 type_str = '%s.%s' % (C.__module__, 'C')
222 224
223 with nt.assert_raises(KeyError):
225 with pytest.raises(KeyError):
224 226 f.pop(type_str)
225 227
226 228 f.for_type(type_str, foo_printer)
227 229 f.pop(type_str)
228 with nt.assert_raises(KeyError):
230 with pytest.raises(KeyError):
229 231 f.lookup_by_type(C)
230 with nt.assert_raises(KeyError):
232 with pytest.raises(KeyError):
231 233 f.pop(type_str)
232 234
233 235 f.for_type(C, foo_printer)
234 nt.assert_is(f.pop(type_str, None), foo_printer)
235 with nt.assert_raises(KeyError):
236 assert f.pop(type_str, None) is foo_printer
237 with pytest.raises(KeyError):
236 238 f.lookup_by_type(C)
237 with nt.assert_raises(KeyError):
239 with pytest.raises(KeyError):
238 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 244 def test_error_method():
243 245 f = HTMLFormatter()
244 246 class BadHTML(object):
245 247 def _repr_html_(self):
246 248 raise ValueError("Bad HTML")
247 249 bad = BadHTML()
248 250 with capture_output() as captured:
249 251 result = f(bad)
250 nt.assert_is(result, None)
251 nt.assert_in("Traceback", captured.stdout)
252 nt.assert_in("Bad HTML", captured.stdout)
253 nt.assert_in("_repr_html_", captured.stdout)
252 assert result is None
253 assert "Traceback" in captured.stdout
254 assert "Bad HTML" in captured.stdout
255 assert "_repr_html_" in captured.stdout
254 256
255 257 def test_nowarn_notimplemented():
256 258 f = HTMLFormatter()
257 259 class HTMLNotImplemented(object):
258 260 def _repr_html_(self):
259 261 raise NotImplementedError
260 262 h = HTMLNotImplemented()
261 263 with capture_output() as captured:
262 264 result = f(h)
263 nt.assert_is(result, None)
265 assert result is None
264 266 assert "" == captured.stderr
265 267 assert "" == captured.stdout
266 268
267 269
268 270 def test_warn_error_for_type():
269 271 f = HTMLFormatter()
270 272 f.for_type(int, lambda i: name_error)
271 273 with capture_output() as captured:
272 274 result = f(5)
273 nt.assert_is(result, None)
274 nt.assert_in("Traceback", captured.stdout)
275 nt.assert_in("NameError", captured.stdout)
276 nt.assert_in("name_error", captured.stdout)
275 assert result is None
276 assert "Traceback" in captured.stdout
277 assert "NameError" in captured.stdout
278 assert "name_error" in captured.stdout
277 279
278 280 def test_error_pretty_method():
279 281 f = PlainTextFormatter()
280 282 class BadPretty(object):
281 283 def _repr_pretty_(self):
282 284 return "hello"
283 285 bad = BadPretty()
284 286 with capture_output() as captured:
285 287 result = f(bad)
286 nt.assert_is(result, None)
287 nt.assert_in("Traceback", captured.stdout)
288 nt.assert_in("_repr_pretty_", captured.stdout)
289 nt.assert_in("given", captured.stdout)
290 nt.assert_in("argument", captured.stdout)
288 assert result is None
289 assert "Traceback" in captured.stdout
290 assert "_repr_pretty_" in captured.stdout
291 assert "given" in captured.stdout
292 assert "argument" in captured.stdout
291 293
292 294
293 295 def test_bad_repr_traceback():
294 296 f = PlainTextFormatter()
295 297 bad = BadRepr()
296 298 with capture_output() as captured:
297 299 result = f(bad)
298 300 # catches error, returns None
299 nt.assert_is(result, None)
300 nt.assert_in("Traceback", captured.stdout)
301 nt.assert_in("__repr__", captured.stdout)
302 nt.assert_in("ValueError", captured.stdout)
301 assert result is None
302 assert "Traceback" in captured.stdout
303 assert "__repr__" in captured.stdout
304 assert "ValueError" in captured.stdout
303 305
304 306
305 307 class MakePDF(object):
306 308 def _repr_pdf_(self):
307 309 return 'PDF'
308 310
309 311 def test_pdf_formatter():
310 312 pdf = MakePDF()
311 313 f = PDFFormatter()
312 314 assert f(pdf) == "PDF"
313 315
314 316
315 317 def test_print_method_bound():
316 318 f = HTMLFormatter()
317 319 class MyHTML(object):
318 320 def _repr_html_(self):
319 321 return "hello"
320 322 with capture_output() as captured:
321 323 result = f(MyHTML)
322 nt.assert_is(result, None)
323 nt.assert_not_in("FormatterWarning", captured.stderr)
324 assert result is None
325 assert "FormatterWarning" not in captured.stderr
324 326
325 327 with capture_output() as captured:
326 328 result = f(MyHTML())
327 329 assert result == "hello"
328 330 assert captured.stderr == ""
329 331
330 332
331 333 def test_print_method_weird():
332 334
333 335 class TextMagicHat(object):
334 336 def __getattr__(self, key):
335 337 return key
336 338
337 339 f = HTMLFormatter()
338 340
339 341 text_hat = TextMagicHat()
340 342 assert text_hat._repr_html_ == "_repr_html_"
341 343 with capture_output() as captured:
342 344 result = f(text_hat)
343 345
344 nt.assert_is(result, None)
345 nt.assert_not_in("FormatterWarning", captured.stderr)
346 assert result is None
347 assert "FormatterWarning" not in captured.stderr
346 348
347 349 class CallableMagicHat(object):
348 350 def __getattr__(self, key):
349 351 return lambda : key
350 352
351 353 call_hat = CallableMagicHat()
352 354 with capture_output() as captured:
353 355 result = f(call_hat)
354 356
355 357 assert result is None
356 358
357 359 class BadReprArgs(object):
358 360 def _repr_html_(self, extra, args):
359 361 return "html"
360 362
361 363 bad = BadReprArgs()
362 364 with capture_output() as captured:
363 365 result = f(bad)
364 366
365 nt.assert_is(result, None)
366 nt.assert_not_in("FormatterWarning", captured.stderr)
367 assert result is None
368 assert "FormatterWarning" not in captured.stderr
367 369
368 370
369 371 def test_format_config():
370 372 """config objects don't pretend to support fancy reprs with lazy attrs"""
371 373 f = HTMLFormatter()
372 374 cfg = Config()
373 375 with capture_output() as captured:
374 376 result = f(cfg)
375 nt.assert_is(result, None)
377 assert result is None
376 378 assert captured.stderr == ""
377 379
378 380 with capture_output() as captured:
379 381 result = f(Config)
380 nt.assert_is(result, None)
382 assert result is None
381 383 assert captured.stderr == ""
382 384
383 385
384 386 def test_pretty_max_seq_length():
385 387 f = PlainTextFormatter(max_seq_length=1)
386 388 lis = list(range(3))
387 389 text = f(lis)
388 390 assert text == "[0, ...]"
389 391 f.max_seq_length = 0
390 392 text = f(lis)
391 393 assert text == "[0, 1, 2]"
392 394 text = f(list(range(1024)))
393 395 lines = text.splitlines()
394 396 assert len(lines) == 1024
395 397
396 398
397 399 def test_ipython_display_formatter():
398 400 """Objects with _ipython_display_ defined bypass other formatters"""
399 401 f = get_ipython().display_formatter
400 402 catcher = []
401 403 class SelfDisplaying(object):
402 404 def _ipython_display_(self):
403 405 catcher.append(self)
404 406
405 407 class NotSelfDisplaying(object):
406 408 def __repr__(self):
407 409 return "NotSelfDisplaying"
408 410
409 411 def _ipython_display_(self):
410 412 raise NotImplementedError
411 413
412 414 save_enabled = f.ipython_display_formatter.enabled
413 415 f.ipython_display_formatter.enabled = True
414 416
415 417 yes = SelfDisplaying()
416 418 no = NotSelfDisplaying()
417 419
418 420 d, md = f.format(no)
419 421 assert d == {"text/plain": repr(no)}
420 422 assert md == {}
421 423 assert catcher == []
422 424
423 425 d, md = f.format(yes)
424 426 assert d == {}
425 427 assert md == {}
426 428 assert catcher == [yes]
427 429
428 430 f.ipython_display_formatter.enabled = save_enabled
429 431
430 432
431 433 def test_json_as_string_deprecated():
432 434 class JSONString(object):
433 435 def _repr_json_(self):
434 436 return '{}'
435 437
436 438 f = JSONFormatter()
437 439 with warnings.catch_warnings(record=True) as w:
438 440 d = f(JSONString())
439 441 assert d == {}
440 442 assert len(w) == 1
441 443
442 444
443 445 def test_repr_mime():
444 446 class HasReprMime(object):
445 447 def _repr_mimebundle_(self, include=None, exclude=None):
446 448 return {
447 449 'application/json+test.v2': {
448 450 'x': 'y'
449 451 },
450 452 'plain/text' : '<HasReprMime>',
451 453 'image/png' : 'i-overwrite'
452 454 }
453 455
454 456 def _repr_png_(self):
455 457 return 'should-be-overwritten'
456 458 def _repr_html_(self):
457 459 return '<b>hi!</b>'
458 460
459 461 f = get_ipython().display_formatter
460 462 html_f = f.formatters['text/html']
461 463 save_enabled = html_f.enabled
462 464 html_f.enabled = True
463 465 obj = HasReprMime()
464 466 d, md = f.format(obj)
465 467 html_f.enabled = save_enabled
466 468
467 469 assert sorted(d) == [
468 470 "application/json+test.v2",
469 471 "image/png",
470 472 "plain/text",
471 473 "text/html",
472 474 "text/plain",
473 475 ]
474 476 assert md == {}
475 477
476 478 d, md = f.format(obj, include={"image/png"})
477 479 assert list(d.keys()) == [
478 480 "image/png"
479 481 ], "Include should filter out even things from repr_mimebundle"
480 482
481 483 assert d["image/png"] == "i-overwrite", "_repr_mimebundle_ take precedence"
482 484
483 485
484 486 def test_pass_correct_include_exclude():
485 487 class Tester(object):
486 488
487 489 def __init__(self, include=None, exclude=None):
488 490 self.include = include
489 491 self.exclude = exclude
490 492
491 493 def _repr_mimebundle_(self, include, exclude, **kwargs):
492 494 if include and (include != self.include):
493 495 raise ValueError('include got modified: display() may be broken.')
494 496 if exclude and (exclude != self.exclude):
495 497 raise ValueError('exclude got modified: display() may be broken.')
496 498
497 499 return None
498 500
499 501 include = {'a', 'b', 'c'}
500 502 exclude = {'c', 'e' , 'f'}
501 503
502 504 f = get_ipython().display_formatter
503 505 f.format(Tester(include=include, exclude=exclude), include=include, exclude=exclude)
504 506 f.format(Tester(exclude=exclude), exclude=exclude)
505 507 f.format(Tester(include=include), include=include)
506 508
507 509
508 510 def test_repr_mime_meta():
509 511 class HasReprMimeMeta(object):
510 512 def _repr_mimebundle_(self, include=None, exclude=None):
511 513 data = {
512 514 'image/png': 'base64-image-data',
513 515 }
514 516 metadata = {
515 517 'image/png': {
516 518 'width': 5,
517 519 'height': 10,
518 520 }
519 521 }
520 522 return (data, metadata)
521 523
522 524 f = get_ipython().display_formatter
523 525 obj = HasReprMimeMeta()
524 526 d, md = f.format(obj)
525 527 assert sorted(d) == ["image/png", "text/plain"]
526 528 assert md == {
527 529 "image/png": {
528 530 "width": 5,
529 531 "height": 10,
530 532 }
531 533 }
532 534
533 535
534 536 def test_repr_mime_failure():
535 537 class BadReprMime(object):
536 538 def _repr_mimebundle_(self, include=None, exclude=None):
537 539 raise RuntimeError
538 540
539 541 f = get_ipython().display_formatter
540 542 obj = BadReprMime()
541 543 d, md = f.format(obj)
542 544 assert "text/plain" in d
@@ -1,94 +1,91 b''
1 1 """Tests for input handlers.
2 2 """
3 3 #-----------------------------------------------------------------------------
4 4 # Module imports
5 5 #-----------------------------------------------------------------------------
6 6
7 # third party
8 import nose.tools as nt
9
10 7 # our own packages
11 8 from IPython.core import autocall
12 9 from IPython.testing import tools as tt
13 10
14 11 #-----------------------------------------------------------------------------
15 12 # Globals
16 13 #-----------------------------------------------------------------------------
17 14
18 15 # Get the public instance of IPython
19 16
20 17 failures = []
21 18 num_tests = 0
22 19
23 20 #-----------------------------------------------------------------------------
24 21 # Test functions
25 22 #-----------------------------------------------------------------------------
26 23
27 24 class CallableIndexable(object):
28 25 def __getitem__(self, idx): return True
29 26 def __call__(self, *args, **kws): return True
30 27
31 28
32 29 class Autocallable(autocall.IPyAutocall):
33 30 def __call__(self):
34 31 return "called"
35 32
36 33
37 34 def run(tests):
38 35 """Loop through a list of (pre, post) inputs, where pre is the string
39 36 handed to ipython, and post is how that string looks after it's been
40 37 transformed (i.e. ipython's notion of _i)"""
41 38 tt.check_pairs(ip.prefilter_manager.prefilter_lines, tests)
42 39
43 40
44 41 def test_handlers():
45 42 call_idx = CallableIndexable()
46 43 ip.user_ns['call_idx'] = call_idx
47 44
48 45 # For many of the below, we're also checking that leading whitespace
49 46 # turns off the esc char, which it should unless there is a continuation
50 47 # line.
51 48 run(
52 49 [('"no change"', '"no change"'), # normal
53 50 (u"lsmagic", "get_ipython().run_line_magic('lsmagic', '')"), # magic
54 51 #("a = b # PYTHON-MODE", '_i'), # emacs -- avoids _in cache
55 52 ])
56 53
57 54 # Objects which are instances of IPyAutocall are *always* autocalled
58 55 autocallable = Autocallable()
59 56 ip.user_ns['autocallable'] = autocallable
60 57
61 58 # auto
62 59 ip.magic('autocall 0')
63 60 # Only explicit escapes or instances of IPyAutocallable should get
64 61 # expanded
65 62 run([
66 63 ('len "abc"', 'len "abc"'),
67 64 ('autocallable', 'autocallable()'),
68 65 # Don't add extra brackets (gh-1117)
69 66 ('autocallable()', 'autocallable()'),
70 67 ])
71 68 ip.magic('autocall 1')
72 69 run([
73 70 ('len "abc"', 'len("abc")'),
74 71 ('len "abc";', 'len("abc");'), # ; is special -- moves out of parens
75 72 # Autocall is turned off if first arg is [] and the object
76 73 # is both callable and indexable. Like so:
77 74 ('len [1,2]', 'len([1,2])'), # len doesn't support __getitem__...
78 75 ('call_idx [1]', 'call_idx [1]'), # call_idx *does*..
79 76 ('call_idx 1', 'call_idx(1)'),
80 77 ('len', 'len'), # only at 2 does it auto-call on single args
81 78 ])
82 79 ip.magic('autocall 2')
83 80 run([
84 81 ('len "abc"', 'len("abc")'),
85 82 ('len "abc";', 'len("abc");'),
86 83 ('len [1,2]', 'len([1,2])'),
87 84 ('call_idx [1]', 'call_idx [1]'),
88 85 ('call_idx 1', 'call_idx(1)'),
89 86 # This is what's different:
90 87 ('len', 'len()'), # only at 2 does it auto-call on single args
91 88 ])
92 89 ip.magic('autocall 1')
93 90
94 nt.assert_equal(failures, [])
91 assert failures == []
@@ -1,223 +1,218 b''
1 1 # coding: utf-8
2 2 """Tests for the IPython tab-completion machinery.
3 3 """
4 4 #-----------------------------------------------------------------------------
5 5 # Module imports
6 6 #-----------------------------------------------------------------------------
7 7
8 8 # stdlib
9 9 import io
10 10 from pathlib import Path
11 11 import sys
12 12 import tempfile
13 13 from datetime import datetime
14 14 import sqlite3
15 15
16 # third party
17 import nose.tools as nt
18
19 16 # our own packages
20 17 from traitlets.config.loader import Config
21 18 from IPython.utils.tempdir import TemporaryDirectory
22 19 from IPython.core.history import HistoryManager, extract_hist_ranges
23 20 from IPython.testing.decorators import skipif
24 21
25 22 def test_proper_default_encoding():
26 nt.assert_equal(sys.getdefaultencoding(), "utf-8")
23 assert sys.getdefaultencoding() == "utf-8"
27 24
28 25 @skipif(sqlite3.sqlite_version_info > (3,24,0))
29 26 def test_history():
30 27 ip = get_ipython()
31 28 with TemporaryDirectory() as tmpdir:
32 29 tmp_path = Path(tmpdir)
33 30 hist_manager_ori = ip.history_manager
34 31 hist_file = tmp_path / "history.sqlite"
35 32 try:
36 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 35 for i, h in enumerate(hist, start=1):
39 36 ip.history_manager.store_inputs(i, h)
40 37
41 38 ip.history_manager.db_log_output = True
42 39 # Doesn't match the input, but we'll just check it's stored.
43 40 ip.history_manager.output_hist_reprs[3] = "spam"
44 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 45 # Detailed tests for _get_range_session
49 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])))
51 nt.assert_equal(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']))))
47 assert list(grs(start=2, stop=-1)) == list(zip([0], [2], hist[1:-1]))
48 assert list(grs(start=-2)) == list(zip([0, 0], [2, 3], hist[-2:]))
49 assert list(grs(output=True)) == list(
50 zip([0, 0, 0], [1, 2, 3], zip(hist, [None, None, "spam"]))
51 )
53 52
54 53 # Check whether specifying a range beyond the end of the current
55 54 # session results in an error (gh-804)
56 55 ip.magic('%hist 2-500')
57 56
58 57 # Check that we can write non-ascii characters to a file
59 58 ip.magic("%%hist -f %s" % (tmp_path / "test1"))
60 59 ip.magic("%%hist -pf %s" % (tmp_path / "test2"))
61 60 ip.magic("%%hist -nf %s" % (tmp_path / "test3"))
62 61 ip.magic("%%save %s 1-10" % (tmp_path / "test4"))
63 62
64 63 # New session
65 64 ip.history_manager.reset()
66 newcmds = [u"z=5",
67 u"class X(object):\n pass",
68 u"k='p'",
69 u"z=5"]
65 newcmds = ["z=5", "class X(object):\n pass", "k='p'", "z=5"]
70 66 for i, cmd in enumerate(newcmds, start=1):
71 67 ip.history_manager.store_inputs(i, cmd)
72 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 70 # Previous session:
75 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 74 newhist = [(2, i, c) for (i, c) in enumerate(newcmds, 1)]
79 75
80 76 # Check get_hist_tail
81 77 gothist = ip.history_manager.get_tail(5, output=True,
82 78 include_latest=True)
83 79 expected = [(1, 3, (hist[-1], "spam"))] \
84 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 83 gothist = ip.history_manager.get_tail(2)
88 84 expected = newhist[-3:-1]
89 nt.assert_equal(list(gothist), expected)
85 assert list(gothist) == expected
90 86
91 87 # Check get_hist_search
92 88
93 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 92 gothist = ip.history_manager.search("*=*")
97 nt.assert_equal(list(gothist),
98 [(1, 1, hist[0]),
99 (1, 2, hist[1]),
100 (1, 3, hist[2]),
101 newhist[0],
102 newhist[2],
103 newhist[3]])
93 assert list(gothist) == [
94 (1, 1, hist[0]),
95 (1, 2, hist[1]),
96 (1, 3, hist[2]),
97 newhist[0],
98 newhist[2],
99 newhist[3],
100 ]
104 101
105 102 gothist = ip.history_manager.search("*=*", n=4)
106 nt.assert_equal(list(gothist),
107 [(1, 3, hist[2]),
108 newhist[0],
109 newhist[2],
110 newhist[3]])
103 assert list(gothist) == [
104 (1, 3, hist[2]),
105 newhist[0],
106 newhist[2],
107 newhist[3],
108 ]
111 109
112 110 gothist = ip.history_manager.search("*=*", unique=True)
113 nt.assert_equal(list(gothist),
114 [(1, 1, hist[0]),
115 (1, 2, hist[1]),
116 (1, 3, hist[2]),
117 newhist[2],
118 newhist[3]])
111 assert list(gothist) == [
112 (1, 1, hist[0]),
113 (1, 2, hist[1]),
114 (1, 3, hist[2]),
115 newhist[2],
116 newhist[3],
117 ]
119 118
120 119 gothist = ip.history_manager.search("*=*", unique=True, n=3)
121 nt.assert_equal(list(gothist),
122 [(1, 3, hist[2]),
123 newhist[2],
124 newhist[3]])
120 assert list(gothist) == [(1, 3, hist[2]), newhist[2], newhist[3]]
125 121
126 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 125 # Cross testing: check that magic %save can get previous session.
130 126 testfilename = (tmp_path / "test.py").resolve()
131 127 ip.magic("save " + str(testfilename) + " ~1/1-3")
132 with io.open(testfilename, encoding='utf-8') as testfile:
133 nt.assert_equal(testfile.read(),
134 u"# coding: utf-8\n" + u"\n".join(hist)+u"\n")
128 with io.open(testfilename, encoding="utf-8") as testfile:
129 assert testfile.read() == "# coding: utf-8\n" + "\n".join(hist) + "\n"
135 130
136 131 # Duplicate line numbers - check that it doesn't crash, and
137 132 # gets a new session
138 133 ip.history_manager.store_inputs(1, "rogue")
139 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 136 finally:
142 137 # Ensure saving thread is shut down before we try to clean up the files
143 138 ip.history_manager.save_thread.stop()
144 139 # Forcibly close database rather than relying on garbage collection
145 140 ip.history_manager.db.close()
146 141 # Restore history manager
147 142 ip.history_manager = hist_manager_ori
148 143
149 144
150 145 def test_extract_hist_ranges():
151 146 instr = "1 2/3 ~4/5-6 ~4/7-~4/9 ~9/2-~7/5 ~10/"
152 147 expected = [(0, 1, 2), # 0 == current session
153 148 (2, 3, 4),
154 149 (-4, 5, 7),
155 150 (-4, 7, 10),
156 151 (-9, 2, None), # None == to end
157 152 (-8, 1, None),
158 153 (-7, 1, 6),
159 154 (-10, 1, None)]
160 155 actual = list(extract_hist_ranges(instr))
161 nt.assert_equal(actual, expected)
156 assert actual == expected
162 157
163 158
164 159 def test_extract_hist_ranges_empty_str():
165 160 instr = ""
166 161 expected = [(0, 1, None)] # 0 == current session, None == to end
167 162 actual = list(extract_hist_ranges(instr))
168 nt.assert_equal(actual, expected)
163 assert actual == expected
169 164
170 165
171 166 def test_magic_rerun():
172 167 """Simple test for %rerun (no args -> rerun last line)"""
173 168 ip = get_ipython()
174 169 ip.run_cell("a = 10", store_history=True)
175 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 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 175 def test_timestamp_type():
181 176 ip = get_ipython()
182 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 180 def test_hist_file_config():
186 181 cfg = Config()
187 182 tfile = tempfile.NamedTemporaryFile(delete=False)
188 183 cfg.HistoryManager.hist_file = Path(tfile.name)
189 184 try:
190 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 187 finally:
193 188 try:
194 189 Path(tfile.name).unlink()
195 190 except OSError:
196 191 # same catch as in testing.tools.TempFileMixin
197 192 # On Windows, even though we close the file, we still can't
198 193 # delete it. I have no clue why
199 194 pass
200 195
201 196 def test_histmanager_disabled():
202 197 """Ensure that disabling the history manager doesn't create a database."""
203 198 cfg = Config()
204 199 cfg.HistoryAccessor.enabled = False
205 200
206 201 ip = get_ipython()
207 202 with TemporaryDirectory() as tmpdir:
208 203 hist_manager_ori = ip.history_manager
209 204 hist_file = Path(tmpdir) / "history.sqlite"
210 205 cfg.HistoryManager.hist_file = hist_file
211 206 try:
212 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 209 for i, h in enumerate(hist, start=1):
215 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 212 ip.history_manager.reset()
218 213 ip.history_manager.end_session()
219 214 finally:
220 215 ip.history_manager = hist_manager_ori
221 216
222 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 1 # -*- coding: utf-8 -*-
2 2 """Tests for CommandChainDispatcher."""
3 3
4 4
5 5 #-----------------------------------------------------------------------------
6 6 # Imports
7 7 #-----------------------------------------------------------------------------
8 8
9 import nose.tools as nt
10 9 from IPython.core.error import TryNext
11 10 from IPython.core.hooks import CommandChainDispatcher
12 11
13 12 #-----------------------------------------------------------------------------
14 13 # Local utilities
15 14 #-----------------------------------------------------------------------------
16 15
17 16 # Define two classes, one which succeeds and one which raises TryNext. Each
18 17 # sets the attribute `called` to True when it is called.
19 18 class Okay(object):
20 19 def __init__(self, message):
21 20 self.message = message
22 21 self.called = False
23 22 def __call__(self):
24 23 self.called = True
25 24 return self.message
26 25
27 26 class Fail(object):
28 27 def __init__(self, message):
29 28 self.message = message
30 29 self.called = False
31 30 def __call__(self):
32 31 self.called = True
33 32 raise TryNext(self.message)
34 33
35 34 #-----------------------------------------------------------------------------
36 35 # Test functions
37 36 #-----------------------------------------------------------------------------
38 37
39 38 def test_command_chain_dispatcher_ff():
40 39 """Test two failing hooks"""
41 fail1 = Fail(u'fail1')
42 fail2 = Fail(u'fail2')
43 dp = CommandChainDispatcher([(0, fail1),
44 (10, fail2)])
40 fail1 = Fail("fail1")
41 fail2 = Fail("fail2")
42 dp = CommandChainDispatcher([(0, fail1), (10, fail2)])
45 43
46 44 try:
47 45 dp()
48 46 except TryNext as e:
49 nt.assert_equal(str(e), u'fail2')
47 assert str(e) == "fail2"
50 48 else:
51 49 assert False, "Expected exception was not raised."
52 50
53 nt.assert_true(fail1.called)
54 nt.assert_true(fail2.called)
51 assert fail1.called is True
52 assert fail2.called is True
55 53
56 54 def test_command_chain_dispatcher_fofo():
57 55 """Test a mixture of failing and succeeding hooks."""
58 fail1 = Fail(u'fail1')
59 fail2 = Fail(u'fail2')
60 okay1 = Okay(u'okay1')
61 okay2 = Okay(u'okay2')
56 fail1 = Fail("fail1")
57 fail2 = Fail("fail2")
58 okay1 = Okay("okay1")
59 okay2 = Okay("okay2")
62 60
63 61 dp = CommandChainDispatcher([(0, fail1),
64 62 # (5, okay1), # add this later
65 63 (10, fail2),
66 64 (15, okay2)])
67 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)
72 nt.assert_true(okay1.called)
73 nt.assert_false(fail2.called)
74 nt.assert_false(okay2.called)
69 assert fail1.called is True
70 assert okay1.called is True
71 assert fail2.called is False
72 assert okay2.called is False
75 73
76 74 def test_command_chain_dispatcher_eq_priority():
77 75 okay1 = Okay(u'okay1')
78 76 okay2 = Okay(u'okay2')
79 77 dp = CommandChainDispatcher([(1, okay1)])
80 78 dp.add(okay2, 1)
@@ -1,639 +1,638 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Tests for the inputsplitter module."""
3 3
4 4
5 5 # Copyright (c) IPython Development Team.
6 6 # Distributed under the terms of the Modified BSD License.
7 7
8 8 import unittest
9 9 import sys
10 10
11 import nose.tools as nt
12
13 11 from IPython.core import inputsplitter as isp
14 12 from IPython.core.inputtransformer import InputTransformer
15 13 from IPython.core.tests.test_inputtransformer import syntax, syntax_ml
16 14 from IPython.testing import tools as tt
17 15
18 16 #-----------------------------------------------------------------------------
19 17 # Semi-complete examples (also used as tests)
20 18 #-----------------------------------------------------------------------------
21 19
22 20 # Note: at the bottom, there's a slightly more complete version of this that
23 21 # can be useful during development of code here.
24 22
25 23 def mini_interactive_loop(input_func):
26 24 """Minimal example of the logic of an interactive interpreter loop.
27 25
28 26 This serves as an example, and it is used by the test system with a fake
29 27 raw_input that simulates interactive input."""
30 28
31 29 from IPython.core.inputsplitter import InputSplitter
32 30
33 31 isp = InputSplitter()
34 32 # In practice, this input loop would be wrapped in an outside loop to read
35 33 # input indefinitely, until some exit/quit command was issued. Here we
36 34 # only illustrate the basic inner loop.
37 35 while isp.push_accepts_more():
38 36 indent = ' '*isp.get_indent_spaces()
39 37 prompt = '>>> ' + indent
40 38 line = indent + input_func(prompt)
41 39 isp.push(line)
42 40
43 41 # Here we just return input so we can use it in a test suite, but a real
44 42 # interpreter would instead send it for execution somewhere.
45 43 src = isp.source_reset()
46 44 #print 'Input source was:\n', src # dbg
47 45 return src
48 46
49 47 #-----------------------------------------------------------------------------
50 48 # Test utilities, just for local use
51 49 #-----------------------------------------------------------------------------
52 50
53 51 def assemble(block):
54 52 """Assemble a block into multi-line sub-blocks."""
55 53 return ['\n'.join(sub_block)+'\n' for sub_block in block]
56 54
57 55
58 56 def pseudo_input(lines):
59 57 """Return a function that acts like raw_input but feeds the input list."""
60 58 ilines = iter(lines)
61 59 def raw_in(prompt):
62 60 try:
63 61 return next(ilines)
64 62 except StopIteration:
65 63 return ''
66 64 return raw_in
67 65
68 66 #-----------------------------------------------------------------------------
69 67 # Tests
70 68 #-----------------------------------------------------------------------------
71 69 def test_spaces():
72 70 tests = [('', 0),
73 71 (' ', 1),
74 72 ('\n', 0),
75 73 (' \n', 1),
76 74 ('x', 0),
77 75 (' x', 1),
78 76 (' x',2),
79 77 (' x',4),
80 78 # Note: tabs are counted as a single whitespace!
81 79 ('\tx', 1),
82 80 ('\t x', 2),
83 81 ]
84 82 tt.check_pairs(isp.num_ini_spaces, tests)
85 83
86 84
87 85 def test_remove_comments():
88 86 tests = [('text', 'text'),
89 87 ('text # comment', 'text '),
90 88 ('text # comment\n', 'text \n'),
91 89 ('text # comment \n', 'text \n'),
92 90 ('line # c \nline\n','line \nline\n'),
93 91 ('line # c \nline#c2 \nline\nline #c\n\n',
94 92 'line \nline\nline\nline \n\n'),
95 93 ]
96 94 tt.check_pairs(isp.remove_comments, tests)
97 95
98 96
99 97 def test_get_input_encoding():
100 98 encoding = isp.get_input_encoding()
101 nt.assert_true(isinstance(encoding, str))
99 assert isinstance(encoding, str)
102 100 # simple-minded check that at least encoding a simple string works with the
103 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 105 class NoInputEncodingTestCase(unittest.TestCase):
108 106 def setUp(self):
109 107 self.old_stdin = sys.stdin
110 108 class X: pass
111 109 fake_stdin = X()
112 110 sys.stdin = fake_stdin
113 111
114 112 def test(self):
115 113 # Verify that if sys.stdin has no 'encoding' attribute we do the right
116 114 # thing
117 115 enc = isp.get_input_encoding()
118 116 self.assertEqual(enc, 'ascii')
119 117
120 118 def tearDown(self):
121 119 sys.stdin = self.old_stdin
122 120
123 121
124 122 class InputSplitterTestCase(unittest.TestCase):
125 123 def setUp(self):
126 124 self.isp = isp.InputSplitter()
127 125
128 126 def test_reset(self):
129 127 isp = self.isp
130 128 isp.push('x=1')
131 129 isp.reset()
132 130 self.assertEqual(isp._buffer, [])
133 131 self.assertEqual(isp.get_indent_spaces(), 0)
134 132 self.assertEqual(isp.source, '')
135 133 self.assertEqual(isp.code, None)
136 134 self.assertEqual(isp._is_complete, False)
137 135
138 136 def test_source(self):
139 137 self.isp._store('1')
140 138 self.isp._store('2')
141 139 self.assertEqual(self.isp.source, '1\n2\n')
142 140 self.assertEqual(len(self.isp._buffer)>0, True)
143 141 self.assertEqual(self.isp.source_reset(), '1\n2\n')
144 142 self.assertEqual(self.isp._buffer, [])
145 143 self.assertEqual(self.isp.source, '')
146 144
147 145 def test_indent(self):
148 146 isp = self.isp # shorthand
149 147 isp.push('x=1')
150 148 self.assertEqual(isp.get_indent_spaces(), 0)
151 149 isp.push('if 1:\n x=1')
152 150 self.assertEqual(isp.get_indent_spaces(), 4)
153 151 isp.push('y=2\n')
154 152 self.assertEqual(isp.get_indent_spaces(), 0)
155 153
156 154 def test_indent2(self):
157 155 isp = self.isp
158 156 isp.push('if 1:')
159 157 self.assertEqual(isp.get_indent_spaces(), 4)
160 158 isp.push(' x=1')
161 159 self.assertEqual(isp.get_indent_spaces(), 4)
162 160 # Blank lines shouldn't change the indent level
163 161 isp.push(' '*2)
164 162 self.assertEqual(isp.get_indent_spaces(), 4)
165 163
166 164 def test_indent3(self):
167 165 isp = self.isp
168 166 # When a multiline statement contains parens or multiline strings, we
169 167 # shouldn't get confused.
170 168 isp.push("if 1:")
171 169 isp.push(" x = (1+\n 2)")
172 170 self.assertEqual(isp.get_indent_spaces(), 4)
173 171
174 172 def test_indent4(self):
175 173 isp = self.isp
176 174 # whitespace after ':' should not screw up indent level
177 175 isp.push('if 1: \n x=1')
178 176 self.assertEqual(isp.get_indent_spaces(), 4)
179 177 isp.push('y=2\n')
180 178 self.assertEqual(isp.get_indent_spaces(), 0)
181 179 isp.push('if 1:\t\n x=1')
182 180 self.assertEqual(isp.get_indent_spaces(), 4)
183 181 isp.push('y=2\n')
184 182 self.assertEqual(isp.get_indent_spaces(), 0)
185 183
186 184 def test_dedent_pass(self):
187 185 isp = self.isp # shorthand
188 186 # should NOT cause dedent
189 187 isp.push('if 1:\n passes = 5')
190 188 self.assertEqual(isp.get_indent_spaces(), 4)
191 189 isp.push('if 1:\n pass')
192 190 self.assertEqual(isp.get_indent_spaces(), 0)
193 191 isp.push('if 1:\n pass ')
194 192 self.assertEqual(isp.get_indent_spaces(), 0)
195 193
196 194 def test_dedent_break(self):
197 195 isp = self.isp # shorthand
198 196 # should NOT cause dedent
199 197 isp.push('while 1:\n breaks = 5')
200 198 self.assertEqual(isp.get_indent_spaces(), 4)
201 199 isp.push('while 1:\n break')
202 200 self.assertEqual(isp.get_indent_spaces(), 0)
203 201 isp.push('while 1:\n break ')
204 202 self.assertEqual(isp.get_indent_spaces(), 0)
205 203
206 204 def test_dedent_continue(self):
207 205 isp = self.isp # shorthand
208 206 # should NOT cause dedent
209 207 isp.push('while 1:\n continues = 5')
210 208 self.assertEqual(isp.get_indent_spaces(), 4)
211 209 isp.push('while 1:\n continue')
212 210 self.assertEqual(isp.get_indent_spaces(), 0)
213 211 isp.push('while 1:\n continue ')
214 212 self.assertEqual(isp.get_indent_spaces(), 0)
215 213
216 214 def test_dedent_raise(self):
217 215 isp = self.isp # shorthand
218 216 # should NOT cause dedent
219 217 isp.push('if 1:\n raised = 4')
220 218 self.assertEqual(isp.get_indent_spaces(), 4)
221 219 isp.push('if 1:\n raise TypeError()')
222 220 self.assertEqual(isp.get_indent_spaces(), 0)
223 221 isp.push('if 1:\n raise')
224 222 self.assertEqual(isp.get_indent_spaces(), 0)
225 223 isp.push('if 1:\n raise ')
226 224 self.assertEqual(isp.get_indent_spaces(), 0)
227 225
228 226 def test_dedent_return(self):
229 227 isp = self.isp # shorthand
230 228 # should NOT cause dedent
231 229 isp.push('if 1:\n returning = 4')
232 230 self.assertEqual(isp.get_indent_spaces(), 4)
233 231 isp.push('if 1:\n return 5 + 493')
234 232 self.assertEqual(isp.get_indent_spaces(), 0)
235 233 isp.push('if 1:\n return')
236 234 self.assertEqual(isp.get_indent_spaces(), 0)
237 235 isp.push('if 1:\n return ')
238 236 self.assertEqual(isp.get_indent_spaces(), 0)
239 237 isp.push('if 1:\n return(0)')
240 238 self.assertEqual(isp.get_indent_spaces(), 0)
241 239
242 240 def test_push(self):
243 241 isp = self.isp
244 242 self.assertEqual(isp.push('x=1'), True)
245 243
246 244 def test_push2(self):
247 245 isp = self.isp
248 246 self.assertEqual(isp.push('if 1:'), False)
249 247 for line in [' x=1', '# a comment', ' y=2']:
250 248 print(line)
251 249 self.assertEqual(isp.push(line), True)
252 250
253 251 def test_push3(self):
254 252 isp = self.isp
255 253 isp.push('if True:')
256 254 isp.push(' a = 1')
257 255 self.assertEqual(isp.push('b = [1,'), False)
258 256
259 257 def test_push_accepts_more(self):
260 258 isp = self.isp
261 259 isp.push('x=1')
262 260 self.assertEqual(isp.push_accepts_more(), False)
263 261
264 262 def test_push_accepts_more2(self):
265 263 isp = self.isp
266 264 isp.push('if 1:')
267 265 self.assertEqual(isp.push_accepts_more(), True)
268 266 isp.push(' x=1')
269 267 self.assertEqual(isp.push_accepts_more(), True)
270 268 isp.push('')
271 269 self.assertEqual(isp.push_accepts_more(), False)
272 270
273 271 def test_push_accepts_more3(self):
274 272 isp = self.isp
275 273 isp.push("x = (2+\n3)")
276 274 self.assertEqual(isp.push_accepts_more(), False)
277 275
278 276 def test_push_accepts_more4(self):
279 277 isp = self.isp
280 278 # When a multiline statement contains parens or multiline strings, we
281 279 # shouldn't get confused.
282 280 # FIXME: we should be able to better handle de-dents in statements like
283 281 # multiline strings and multiline expressions (continued with \ or
284 282 # parens). Right now we aren't handling the indentation tracking quite
285 283 # correctly with this, though in practice it may not be too much of a
286 284 # problem. We'll need to see.
287 285 isp.push("if 1:")
288 286 isp.push(" x = (2+")
289 287 isp.push(" 3)")
290 288 self.assertEqual(isp.push_accepts_more(), True)
291 289 isp.push(" y = 3")
292 290 self.assertEqual(isp.push_accepts_more(), True)
293 291 isp.push('')
294 292 self.assertEqual(isp.push_accepts_more(), False)
295 293
296 294 def test_push_accepts_more5(self):
297 295 isp = self.isp
298 296 isp.push('try:')
299 297 isp.push(' a = 5')
300 298 isp.push('except:')
301 299 isp.push(' raise')
302 300 # We want to be able to add an else: block at this point, so it should
303 301 # wait for a blank line.
304 302 self.assertEqual(isp.push_accepts_more(), True)
305 303
306 304 def test_continuation(self):
307 305 isp = self.isp
308 306 isp.push("import os, \\")
309 307 self.assertEqual(isp.push_accepts_more(), True)
310 308 isp.push("sys")
311 309 self.assertEqual(isp.push_accepts_more(), False)
312 310
313 311 def test_syntax_error(self):
314 312 isp = self.isp
315 313 # Syntax errors immediately produce a 'ready' block, so the invalid
316 314 # Python can be sent to the kernel for evaluation with possible ipython
317 315 # special-syntax conversion.
318 316 isp.push('run foo')
319 317 self.assertEqual(isp.push_accepts_more(), False)
320 318
321 319 def test_unicode(self):
322 320 self.isp.push(u"Pérez")
323 321 self.isp.push(u'\xc3\xa9')
324 322 self.isp.push(u"u'\xc3\xa9'")
325 323
326 324 def test_line_continuation(self):
327 325 """ Test issue #2108."""
328 326 isp = self.isp
329 327 # A blank line after a line continuation should not accept more
330 328 isp.push("1 \\\n\n")
331 329 self.assertEqual(isp.push_accepts_more(), False)
332 330 # Whitespace after a \ is a SyntaxError. The only way to test that
333 331 # here is to test that push doesn't accept more (as with
334 332 # test_syntax_error() above).
335 333 isp.push(r"1 \ ")
336 334 self.assertEqual(isp.push_accepts_more(), False)
337 335 # Even if the line is continuable (c.f. the regular Python
338 336 # interpreter)
339 337 isp.push(r"(1 \ ")
340 338 self.assertEqual(isp.push_accepts_more(), False)
341 339
342 340 def test_check_complete(self):
343 341 isp = self.isp
344 342 self.assertEqual(isp.check_complete("a = 1"), ('complete', None))
345 343 self.assertEqual(isp.check_complete("for a in range(5):"), ('incomplete', 4))
346 344 self.assertEqual(isp.check_complete("raise = 2"), ('invalid', None))
347 345 self.assertEqual(isp.check_complete("a = [1,\n2,"), ('incomplete', 0))
348 346 self.assertEqual(isp.check_complete("def a():\n x=1\n global x"), ('invalid', None))
349 347
350 348 class InteractiveLoopTestCase(unittest.TestCase):
351 349 """Tests for an interactive loop like a python shell.
352 350 """
353 351 def check_ns(self, lines, ns):
354 352 """Validate that the given input lines produce the resulting namespace.
355 353
356 354 Note: the input lines are given exactly as they would be typed in an
357 355 auto-indenting environment, as mini_interactive_loop above already does
358 356 auto-indenting and prepends spaces to the input.
359 357 """
360 358 src = mini_interactive_loop(pseudo_input(lines))
361 359 test_ns = {}
362 360 exec(src, test_ns)
363 361 # We can't check that the provided ns is identical to the test_ns,
364 362 # because Python fills test_ns with extra keys (copyright, etc). But
365 363 # we can check that the given dict is *contained* in test_ns
366 364 for k,v in ns.items():
367 365 self.assertEqual(test_ns[k], v)
368 366
369 367 def test_simple(self):
370 368 self.check_ns(['x=1'], dict(x=1))
371 369
372 370 def test_simple2(self):
373 371 self.check_ns(['if 1:', 'x=2'], dict(x=2))
374 372
375 373 def test_xy(self):
376 374 self.check_ns(['x=1; y=2'], dict(x=1, y=2))
377 375
378 376 def test_abc(self):
379 377 self.check_ns(['if 1:','a=1','b=2','c=3'], dict(a=1, b=2, c=3))
380 378
381 379 def test_multi(self):
382 380 self.check_ns(['x =(1+','1+','2)'], dict(x=4))
383 381
384 382
385 383 class IPythonInputTestCase(InputSplitterTestCase):
386 384 """By just creating a new class whose .isp is a different instance, we
387 385 re-run the same test battery on the new input splitter.
388 386
389 387 In addition, this runs the tests over the syntax and syntax_ml dicts that
390 388 were tested by individual functions, as part of the OO interface.
391 389
392 390 It also makes some checks on the raw buffer storage.
393 391 """
394 392
395 393 def setUp(self):
396 394 self.isp = isp.IPythonInputSplitter()
397 395
398 396 def test_syntax(self):
399 397 """Call all single-line syntax tests from the main object"""
400 398 isp = self.isp
401 399 for example in syntax.values():
402 400 for raw, out_t in example:
403 401 if raw.startswith(' '):
404 402 continue
405 403
406 404 isp.push(raw+'\n')
407 405 out_raw = isp.source_raw
408 406 out = isp.source_reset()
409 407 self.assertEqual(out.rstrip(), out_t,
410 408 tt.pair_fail_msg.format("inputsplitter",raw, out_t, out))
411 409 self.assertEqual(out_raw.rstrip(), raw.rstrip())
412 410
413 411 def test_syntax_multiline(self):
414 412 isp = self.isp
415 413 for example in syntax_ml.values():
416 414 for line_pairs in example:
417 415 out_t_parts = []
418 416 raw_parts = []
419 417 for lraw, out_t_part in line_pairs:
420 418 if out_t_part is not None:
421 419 out_t_parts.append(out_t_part)
422
420
423 421 if lraw is not None:
424 422 isp.push(lraw)
425 423 raw_parts.append(lraw)
426 424
427 425 out_raw = isp.source_raw
428 426 out = isp.source_reset()
429 427 out_t = '\n'.join(out_t_parts).rstrip()
430 428 raw = '\n'.join(raw_parts).rstrip()
431 429 self.assertEqual(out.rstrip(), out_t)
432 430 self.assertEqual(out_raw.rstrip(), raw)
433 431
434 432 def test_syntax_multiline_cell(self):
435 433 isp = self.isp
436 434 for example in syntax_ml.values():
437 435
438 436 out_t_parts = []
439 437 for line_pairs in example:
440 438 raw = '\n'.join(r for r, _ in line_pairs if r is not None)
441 439 out_t = '\n'.join(t for _,t in line_pairs if t is not None)
442 440 out = isp.transform_cell(raw)
443 441 # Match ignoring trailing whitespace
444 442 self.assertEqual(out.rstrip(), out_t.rstrip())
445
443
446 444 def test_cellmagic_preempt(self):
447 445 isp = self.isp
448 446 for raw, name, line, cell in [
449 447 ("%%cellm a\nIn[1]:", u'cellm', u'a', u'In[1]:'),
450 448 ("%%cellm \nline\n>>> hi", u'cellm', u'', u'line\n>>> hi'),
451 449 (">>> %%cellm \nline\n>>> hi", u'cellm', u'', u'line\nhi'),
452 450 ("%%cellm \n>>> hi", u'cellm', u'', u'>>> hi'),
453 451 ("%%cellm \nline1\nline2", u'cellm', u'', u'line1\nline2'),
454 452 ("%%cellm \nline1\\\\\nline2", u'cellm', u'', u'line1\\\\\nline2'),
455 453 ]:
456 454 expected = "get_ipython().run_cell_magic(%r, %r, %r)" % (
457 455 name, line, cell
458 456 )
459 457 out = isp.transform_cell(raw)
460 458 self.assertEqual(out.rstrip(), expected.rstrip())
461 459
462 460 def test_multiline_passthrough(self):
463 461 isp = self.isp
464 462 class CommentTransformer(InputTransformer):
465 463 def __init__(self):
466 464 self._lines = []
467
465
468 466 def push(self, line):
469 467 self._lines.append(line + '#')
470
468
471 469 def reset(self):
472 470 text = '\n'.join(self._lines)
473 471 self._lines = []
474 472 return text
475
473
476 474 isp.physical_line_transforms.insert(0, CommentTransformer())
477
475
478 476 for raw, expected in [
479 477 ("a=5", "a=5#"),
480 478 ("%ls foo", "get_ipython().run_line_magic(%r, %r)" % (u'ls', u'foo#')),
481 479 ("!ls foo\n%ls bar", "get_ipython().system(%r)\nget_ipython().run_line_magic(%r, %r)" % (
482 480 u'ls foo#', u'ls', u'bar#'
483 481 )),
484 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 484 out = isp.transform_cell(raw)
487 485 self.assertEqual(out.rstrip(), expected.rstrip())
488 486
489 487 #-----------------------------------------------------------------------------
490 488 # Main - use as a script, mostly for developer experiments
491 489 #-----------------------------------------------------------------------------
492 490
493 491 if __name__ == '__main__':
494 492 # A simple demo for interactive experimentation. This code will not get
495 493 # picked up by any test suite.
496 494 from IPython.core.inputsplitter import IPythonInputSplitter
497 495
498 496 # configure here the syntax to use, prompt and whether to autoindent
499 497 #isp, start_prompt = InputSplitter(), '>>> '
500 498 isp, start_prompt = IPythonInputSplitter(), 'In> '
501 499
502 500 autoindent = True
503 501 #autoindent = False
504 502
505 503 try:
506 504 while True:
507 505 prompt = start_prompt
508 506 while isp.push_accepts_more():
509 507 indent = ' '*isp.get_indent_spaces()
510 508 if autoindent:
511 509 line = indent + input(prompt+indent)
512 510 else:
513 511 line = input(prompt)
514 512 isp.push(line)
515 513 prompt = '... '
516 514
517 515 # Here we just return input so we can use it in a test suite, but a
518 516 # real interpreter would instead send it for execution somewhere.
519 517 #src = isp.source; raise EOFError # dbg
520 518 raw = isp.source_raw
521 519 src = isp.source_reset()
522 520 print('Input source was:\n', src)
523 521 print('Raw source was:\n', raw)
524 522 except EOFError:
525 523 print('Bye')
526 524
527 525 # Tests for cell magics support
528 526
529 527 def test_last_blank():
530 nt.assert_false(isp.last_blank(''))
531 nt.assert_false(isp.last_blank('abc'))
532 nt.assert_false(isp.last_blank('abc\n'))
533 nt.assert_false(isp.last_blank('abc\na'))
528 assert isp.last_blank("") is False
529 assert isp.last_blank("abc") is False
530 assert isp.last_blank("abc\n") is False
531 assert isp.last_blank("abc\na") is False
534 532
535 nt.assert_true(isp.last_blank('\n'))
536 nt.assert_true(isp.last_blank('\n '))
537 nt.assert_true(isp.last_blank('abc\n '))
538 nt.assert_true(isp.last_blank('abc\n\n'))
539 nt.assert_true(isp.last_blank('abc\nd\n\n'))
540 nt.assert_true(isp.last_blank('abc\nd\ne\n\n'))
541 nt.assert_true(isp.last_blank('abc \n \n \n\n'))
533 assert isp.last_blank("\n") is True
534 assert isp.last_blank("\n ") is True
535 assert isp.last_blank("abc\n ") is True
536 assert isp.last_blank("abc\n\n") is True
537 assert isp.last_blank("abc\nd\n\n") is True
538 assert isp.last_blank("abc\nd\ne\n\n") is True
539 assert isp.last_blank("abc \n \n \n\n") is True
542 540
543 541
544 542 def test_last_two_blanks():
545 nt.assert_false(isp.last_two_blanks(''))
546 nt.assert_false(isp.last_two_blanks('abc'))
547 nt.assert_false(isp.last_two_blanks('abc\n'))
548 nt.assert_false(isp.last_two_blanks('abc\n\na'))
549 nt.assert_false(isp.last_two_blanks('abc\n \n'))
550 nt.assert_false(isp.last_two_blanks('abc\n\n'))
551
552 nt.assert_true(isp.last_two_blanks('\n\n'))
553 nt.assert_true(isp.last_two_blanks('\n\n '))
554 nt.assert_true(isp.last_two_blanks('\n \n'))
555 nt.assert_true(isp.last_two_blanks('abc\n\n '))
556 nt.assert_true(isp.last_two_blanks('abc\n\n\n'))
557 nt.assert_true(isp.last_two_blanks('abc\n\n \n'))
558 nt.assert_true(isp.last_two_blanks('abc\n\n \n '))
559 nt.assert_true(isp.last_two_blanks('abc\n\n \n \n'))
560 nt.assert_true(isp.last_two_blanks('abc\nd\n\n\n'))
561 nt.assert_true(isp.last_two_blanks('abc\nd\ne\nf\n\n\n'))
543 assert isp.last_two_blanks("") is False
544 assert isp.last_two_blanks("abc") is False
545 assert isp.last_two_blanks("abc\n") is False
546 assert isp.last_two_blanks("abc\n\na") is False
547 assert isp.last_two_blanks("abc\n \n") is False
548 assert isp.last_two_blanks("abc\n\n") is False
549
550 assert isp.last_two_blanks("\n\n") is True
551 assert isp.last_two_blanks("\n\n ") is True
552 assert isp.last_two_blanks("\n \n") is True
553 assert isp.last_two_blanks("abc\n\n ") is True
554 assert isp.last_two_blanks("abc\n\n\n") is True
555 assert isp.last_two_blanks("abc\n\n \n") is True
556 assert isp.last_two_blanks("abc\n\n \n ") is True
557 assert isp.last_two_blanks("abc\n\n \n \n") is True
558 assert isp.last_two_blanks("abc\nd\n\n\n") is True
559 assert isp.last_two_blanks("abc\nd\ne\nf\n\n\n") is True
562 560
563 561
564 562 class CellMagicsCommon(object):
565 563
566 564 def test_whole_cell(self):
567 565 src = "%%cellm line\nbody\n"
568 566 out = self.sp.transform_cell(src)
569 567 ref = "get_ipython().run_cell_magic('cellm', 'line', 'body')\n"
570 nt.assert_equal(out, ref)
571
568 assert out == ref
569
572 570 def test_cellmagic_help(self):
573 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 574 def tearDown(self):
577 575 self.sp.reset()
578 576
579 577
580 578 class CellModeCellMagics(CellMagicsCommon, unittest.TestCase):
581 579 sp = isp.IPythonInputSplitter(line_input_checker=False)
582 580
583 581 def test_incremental(self):
584 582 sp = self.sp
585 sp.push('%%cellm firstline\n')
586 nt.assert_true(sp.push_accepts_more()) #1
587 sp.push('line2\n')
588 nt.assert_true(sp.push_accepts_more()) #2
589 sp.push('\n')
583 sp.push("%%cellm firstline\n")
584 assert sp.push_accepts_more() is True # 1
585 sp.push("line2\n")
586 assert sp.push_accepts_more() is True # 2
587 sp.push("\n")
590 588 # This should accept a blank line and carry on until the cell is reset
591 nt.assert_true(sp.push_accepts_more()) #3
592
589 assert sp.push_accepts_more() is True # 3
590
593 591 def test_no_strip_coding(self):
594 592 src = '\n'.join([
595 593 '%%writefile foo.py',
596 594 '# coding: utf-8',
597 595 'print(u"üñîçø∂é")',
598 596 ])
599 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 601 class LineModeCellMagics(CellMagicsCommon, unittest.TestCase):
604 602 sp = isp.IPythonInputSplitter(line_input_checker=True)
605 603
606 604 def test_incremental(self):
607 605 sp = self.sp
608 sp.push('%%cellm line2\n')
609 nt.assert_true(sp.push_accepts_more()) #1
610 sp.push('\n')
606 sp.push("%%cellm line2\n")
607 assert sp.push_accepts_more() is True # 1
608 sp.push("\n")
611 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 613 indentation_samples = [
615 614 ('a = 1', 0),
616 615 ('for a in b:', 4),
617 616 ('def f():', 4),
618 617 ('def f(): #comment', 4),
619 618 ('a = ":#not a comment"', 0),
620 619 ('def f():\n a = 1', 4),
621 620 ('def f():\n return 1', 0),
622 621 ('for a in b:\n'
623 622 ' if a < 0:'
624 623 ' continue', 3),
625 624 ('a = {', 4),
626 625 ('a = {\n'
627 626 ' 1,', 5),
628 627 ('b = """123', 0),
629 628 ('', 0),
630 629 ('def f():\n pass', 0),
631 630 ('class Bar:\n def f():\n pass', 4),
632 631 ('class Bar:\n def f():\n raise', 4),
633 632 ]
634 633
635 634 def test_find_next_indent():
636 635 for code, exp in indentation_samples:
637 636 res = isp.find_next_indent(code)
638 637 msg = "{!r} != {!r} (expected)\n Code: {!r}".format(res, exp, code)
639 638 assert res == exp, msg
@@ -1,485 +1,484 b''
1 1 import tokenize
2 import nose.tools as nt
3 2
4 3 from IPython.testing import tools as tt
5 4
6 5 from IPython.core import inputtransformer as ipt
7 6
8 7 def transform_and_reset(transformer):
9 8 transformer = transformer()
10 9 def transform(inp):
11 10 try:
12 11 return transformer.push(inp)
13 12 finally:
14 13 transformer.reset()
15 14
16 15 return transform
17 16
18 17 # Transformer tests
19 18 def transform_checker(tests, transformer, **kwargs):
20 19 """Utility to loop over test inputs"""
21 20 transformer = transformer(**kwargs)
22 21 try:
23 22 for inp, tr in tests:
24 23 if inp is None:
25 24 out = transformer.reset()
26 25 else:
27 26 out = transformer.push(inp)
28 nt.assert_equal(out, tr)
27 assert out == tr
29 28 finally:
30 29 transformer.reset()
31 30
32 31 # Data for all the syntax tests in the form of lists of pairs of
33 32 # raw/transformed input. We store it here as a global dict so that we can use
34 33 # it both within single-function tests and also to validate the behavior of the
35 34 # larger objects
36 35
37 36 syntax = \
38 37 dict(assign_system =
39 38 [('a =! ls', "a = get_ipython().getoutput('ls')"),
40 39 ('b = !ls', "b = get_ipython().getoutput('ls')"),
41 40 ('c= !ls', "c = get_ipython().getoutput('ls')"),
42 41 ('d == !ls', 'd == !ls'), # Invalid syntax, but we leave == alone.
43 42 ('x=1', 'x=1'), # normal input is unmodified
44 43 (' ',' '), # blank lines are kept intact
45 44 # Tuple unpacking
46 45 ("a, b = !echo 'a\\nb'", "a, b = get_ipython().getoutput(\"echo 'a\\\\nb'\")"),
47 46 ("a,= !echo 'a'", "a, = get_ipython().getoutput(\"echo 'a'\")"),
48 47 ("a, *bc = !echo 'a\\nb\\nc'", "a, *bc = get_ipython().getoutput(\"echo 'a\\\\nb\\\\nc'\")"),
49 48 # Tuple unpacking with regular Python expressions, not our syntax.
50 49 ("a, b = range(2)", "a, b = range(2)"),
51 50 ("a, = range(1)", "a, = range(1)"),
52 51 ("a, *bc = range(3)", "a, *bc = range(3)"),
53 52 ],
54 53
55 54 assign_magic =
56 55 [('a =% who', "a = get_ipython().run_line_magic('who', '')"),
57 56 ('b = %who', "b = get_ipython().run_line_magic('who', '')"),
58 57 ('c= %ls', "c = get_ipython().run_line_magic('ls', '')"),
59 58 ('d == %ls', 'd == %ls'), # Invalid syntax, but we leave == alone.
60 59 ('x=1', 'x=1'), # normal input is unmodified
61 60 (' ',' '), # blank lines are kept intact
62 61 ("a, b = %foo", "a, b = get_ipython().run_line_magic('foo', '')"),
63 62 ],
64 63
65 64 classic_prompt =
66 65 [('>>> x=1', 'x=1'),
67 66 ('x=1', 'x=1'), # normal input is unmodified
68 67 (' ', ' '), # blank lines are kept intact
69 68 ],
70 69
71 70 ipy_prompt =
72 71 [('In [1]: x=1', 'x=1'),
73 72 ('x=1', 'x=1'), # normal input is unmodified
74 73 (' ',' '), # blank lines are kept intact
75 74 ],
76 75
77 76 # Tests for the escape transformer to leave normal code alone
78 77 escaped_noesc =
79 78 [ (' ', ' '),
80 79 ('x=1', 'x=1'),
81 80 ],
82 81
83 82 # System calls
84 83 escaped_shell =
85 84 [ ('!ls', "get_ipython().system('ls')"),
86 85 # Double-escape shell, this means to capture the output of the
87 86 # subprocess and return it
88 87 ('!!ls', "get_ipython().getoutput('ls')"),
89 88 ],
90 89
91 90 # Help/object info
92 91 escaped_help =
93 92 [ ('?', 'get_ipython().show_usage()'),
94 93 ('?x1', "get_ipython().run_line_magic('pinfo', 'x1')"),
95 94 ('??x2', "get_ipython().run_line_magic('pinfo2', 'x2')"),
96 95 ('?a.*s', "get_ipython().run_line_magic('psearch', 'a.*s')"),
97 96 ('?%hist1', "get_ipython().run_line_magic('pinfo', '%hist1')"),
98 97 ('?%%hist2', "get_ipython().run_line_magic('pinfo', '%%hist2')"),
99 98 ('?abc = qwe', "get_ipython().run_line_magic('pinfo', 'abc')"),
100 99 ],
101 100
102 101 end_help =
103 102 [ ('x3?', "get_ipython().run_line_magic('pinfo', 'x3')"),
104 103 ('x4??', "get_ipython().run_line_magic('pinfo2', 'x4')"),
105 104 ('%hist1?', "get_ipython().run_line_magic('pinfo', '%hist1')"),
106 105 ('%hist2??', "get_ipython().run_line_magic('pinfo2', '%hist2')"),
107 106 ('%%hist3?', "get_ipython().run_line_magic('pinfo', '%%hist3')"),
108 107 ('%%hist4??', "get_ipython().run_line_magic('pinfo2', '%%hist4')"),
109 108 ('π.foo?', "get_ipython().run_line_magic('pinfo', 'π.foo')"),
110 109 ('f*?', "get_ipython().run_line_magic('psearch', 'f*')"),
111 110 ('ax.*aspe*?', "get_ipython().run_line_magic('psearch', 'ax.*aspe*')"),
112 111 ('a = abc?', "get_ipython().set_next_input('a = abc');"
113 112 "get_ipython().run_line_magic('pinfo', 'abc')"),
114 113 ('a = abc.qe??', "get_ipython().set_next_input('a = abc.qe');"
115 114 "get_ipython().run_line_magic('pinfo2', 'abc.qe')"),
116 115 ('a = *.items?', "get_ipython().set_next_input('a = *.items');"
117 116 "get_ipython().run_line_magic('psearch', '*.items')"),
118 117 ('plot(a?', "get_ipython().set_next_input('plot(a');"
119 118 "get_ipython().run_line_magic('pinfo', 'a')"),
120 119 ('a*2 #comment?', 'a*2 #comment?'),
121 120 ],
122 121
123 122 # Explicit magic calls
124 123 escaped_magic =
125 124 [ ('%cd', "get_ipython().run_line_magic('cd', '')"),
126 125 ('%cd /home', "get_ipython().run_line_magic('cd', '/home')"),
127 126 # Backslashes need to be escaped.
128 127 ('%cd C:\\User', "get_ipython().run_line_magic('cd', 'C:\\\\User')"),
129 128 (' %magic', " get_ipython().run_line_magic('magic', '')"),
130 129 ],
131 130
132 131 # Quoting with separate arguments
133 132 escaped_quote =
134 133 [ (',f', 'f("")'),
135 134 (',f x', 'f("x")'),
136 135 (' ,f y', ' f("y")'),
137 136 (',f a b', 'f("a", "b")'),
138 137 ],
139 138
140 139 # Quoting with single argument
141 140 escaped_quote2 =
142 141 [ (';f', 'f("")'),
143 142 (';f x', 'f("x")'),
144 143 (' ;f y', ' f("y")'),
145 144 (';f a b', 'f("a b")'),
146 145 ],
147 146
148 147 # Simply apply parens
149 148 escaped_paren =
150 149 [ ('/f', 'f()'),
151 150 ('/f x', 'f(x)'),
152 151 (' /f y', ' f(y)'),
153 152 ('/f a b', 'f(a, b)'),
154 153 ],
155 154
156 155 # Check that we transform prompts before other transforms
157 156 mixed =
158 157 [ ('In [1]: %lsmagic', "get_ipython().run_line_magic('lsmagic', '')"),
159 158 ('>>> %lsmagic', "get_ipython().run_line_magic('lsmagic', '')"),
160 159 ('In [2]: !ls', "get_ipython().system('ls')"),
161 160 ('In [3]: abs?', "get_ipython().run_line_magic('pinfo', 'abs')"),
162 161 ('In [4]: b = %who', "b = get_ipython().run_line_magic('who', '')"),
163 162 ],
164 163 )
165 164
166 165 # multiline syntax examples. Each of these should be a list of lists, with
167 166 # each entry itself having pairs of raw/transformed input. The union (with
168 167 # '\n'.join() of the transformed inputs is what the splitter should produce
169 168 # when fed the raw lines one at a time via push.
170 169 syntax_ml = \
171 170 dict(classic_prompt =
172 171 [ [('>>> for i in range(10):','for i in range(10):'),
173 172 ('... print i',' print i'),
174 173 ('... ', ''),
175 174 ],
176 175 [('>>> a="""','a="""'),
177 176 ('... 123"""','123"""'),
178 177 ],
179 178 [('a="""','a="""'),
180 179 ('... 123','123'),
181 180 ('... 456"""','456"""'),
182 181 ],
183 182 [('a="""','a="""'),
184 183 ('>>> 123','123'),
185 184 ('... 456"""','456"""'),
186 185 ],
187 186 [('a="""','a="""'),
188 187 ('123','123'),
189 188 ('... 456"""','... 456"""'),
190 189 ],
191 190 [('....__class__','....__class__'),
192 191 ],
193 192 [('a=5', 'a=5'),
194 193 ('...', ''),
195 194 ],
196 195 [('>>> def f(x):', 'def f(x):'),
197 196 ('...', ''),
198 197 ('... return x', ' return x'),
199 198 ],
200 199 [('board = """....', 'board = """....'),
201 200 ('....', '....'),
202 201 ('...."""', '...."""'),
203 202 ],
204 203 ],
205 204
206 205 ipy_prompt =
207 206 [ [('In [24]: for i in range(10):','for i in range(10):'),
208 207 (' ....: print i',' print i'),
209 208 (' ....: ', ''),
210 209 ],
211 210 [('In [24]: for i in range(10):','for i in range(10):'),
212 211 # Qt console prompts expand with spaces, not dots
213 212 (' ...: print i',' print i'),
214 213 (' ...: ', ''),
215 214 ],
216 215 [('In [24]: for i in range(10):','for i in range(10):'),
217 216 # Sometimes whitespace preceding '...' has been removed
218 217 ('...: print i',' print i'),
219 218 ('...: ', ''),
220 219 ],
221 220 [('In [24]: for i in range(10):','for i in range(10):'),
222 221 # Space after last continuation prompt has been removed (issue #6674)
223 222 ('...: print i',' print i'),
224 223 ('...:', ''),
225 224 ],
226 225 [('In [2]: a="""','a="""'),
227 226 (' ...: 123"""','123"""'),
228 227 ],
229 228 [('a="""','a="""'),
230 229 (' ...: 123','123'),
231 230 (' ...: 456"""','456"""'),
232 231 ],
233 232 [('a="""','a="""'),
234 233 ('In [1]: 123','123'),
235 234 (' ...: 456"""','456"""'),
236 235 ],
237 236 [('a="""','a="""'),
238 237 ('123','123'),
239 238 (' ...: 456"""',' ...: 456"""'),
240 239 ],
241 240 ],
242 241
243 242 multiline_datastructure_prompt =
244 243 [ [('>>> a = [1,','a = [1,'),
245 244 ('... 2]','2]'),
246 245 ],
247 246 ],
248 247
249 248 multiline_datastructure =
250 249 [ [('b = ("%s"', None),
251 250 ('# comment', None),
252 251 ('%foo )', 'b = ("%s"\n# comment\n%foo )'),
253 252 ],
254 253 ],
255 254
256 255 multiline_string =
257 256 [ [("'''foo?", None),
258 257 ("bar'''", "'''foo?\nbar'''"),
259 258 ],
260 259 ],
261 260
262 261 leading_indent =
263 262 [ [(' print "hi"','print "hi"'),
264 263 ],
265 264 [(' for a in range(5):','for a in range(5):'),
266 265 (' a*2',' a*2'),
267 266 ],
268 267 [(' a="""','a="""'),
269 268 (' 123"""','123"""'),
270 269 ],
271 270 [('a="""','a="""'),
272 271 (' 123"""',' 123"""'),
273 272 ],
274 273 ],
275 274
276 275 cellmagic =
277 276 [ [('%%foo a', None),
278 277 (None, "get_ipython().run_cell_magic('foo', 'a', '')"),
279 278 ],
280 279 [('%%bar 123', None),
281 280 ('hello', None),
282 281 (None , "get_ipython().run_cell_magic('bar', '123', 'hello')"),
283 282 ],
284 283 [('a=5', 'a=5'),
285 284 ('%%cellmagic', '%%cellmagic'),
286 285 ],
287 286 ],
288 287
289 288 escaped =
290 289 [ [('%abc def \\', None),
291 290 ('ghi', "get_ipython().run_line_magic('abc', 'def ghi')"),
292 291 ],
293 292 [('%abc def \\', None),
294 293 ('ghi\\', None),
295 294 (None, "get_ipython().run_line_magic('abc', 'def ghi')"),
296 295 ],
297 296 ],
298 297
299 298 assign_magic =
300 299 [ [('a = %bc de \\', None),
301 300 ('fg', "a = get_ipython().run_line_magic('bc', 'de fg')"),
302 301 ],
303 302 [('a = %bc de \\', None),
304 303 ('fg\\', None),
305 304 (None, "a = get_ipython().run_line_magic('bc', 'de fg')"),
306 305 ],
307 306 ],
308 307
309 308 assign_system =
310 309 [ [('a = !bc de \\', None),
311 310 ('fg', "a = get_ipython().getoutput('bc de fg')"),
312 311 ],
313 312 [('a = !bc de \\', None),
314 313 ('fg\\', None),
315 314 (None, "a = get_ipython().getoutput('bc de fg')"),
316 315 ],
317 316 ],
318 317 )
319 318
320 319
321 320 def test_assign_system():
322 321 tt.check_pairs(transform_and_reset(ipt.assign_from_system), syntax['assign_system'])
323 322
324 323 def test_assign_magic():
325 324 tt.check_pairs(transform_and_reset(ipt.assign_from_magic), syntax['assign_magic'])
326 325
327 326 def test_classic_prompt():
328 327 tt.check_pairs(transform_and_reset(ipt.classic_prompt), syntax['classic_prompt'])
329 328 for example in syntax_ml['classic_prompt']:
330 329 transform_checker(example, ipt.classic_prompt)
331 330 for example in syntax_ml['multiline_datastructure_prompt']:
332 331 transform_checker(example, ipt.classic_prompt)
333 332
334 333 # Check that we don't transform the second line if the first is obviously
335 334 # IPython syntax
336 335 transform_checker([
337 336 ('%foo', '%foo'),
338 337 ('>>> bar', '>>> bar'),
339 338 ], ipt.classic_prompt)
340 339
341 340
342 341 def test_ipy_prompt():
343 342 tt.check_pairs(transform_and_reset(ipt.ipy_prompt), syntax['ipy_prompt'])
344 343 for example in syntax_ml['ipy_prompt']:
345 344 transform_checker(example, ipt.ipy_prompt)
346 345
347 346 # Check that we don't transform the second line if we're inside a cell magic
348 347 transform_checker([
349 348 ('%%foo', '%%foo'),
350 349 ('In [1]: bar', 'In [1]: bar'),
351 350 ], ipt.ipy_prompt)
352 351
353 352 def test_assemble_logical_lines():
354 353 tests = \
355 354 [ [("a = \\", None),
356 355 ("123", "a = 123"),
357 356 ],
358 357 [("a = \\", None), # Test resetting when within a multi-line string
359 358 ("12 *\\", None),
360 359 (None, "a = 12 *"),
361 360 ],
362 361 [("# foo\\", "# foo\\"), # Comments can't be continued like this
363 362 ],
364 363 ]
365 364 for example in tests:
366 365 transform_checker(example, ipt.assemble_logical_lines)
367 366
368 367 def test_assemble_python_lines():
369 368 tests = \
370 369 [ [("a = '''", None),
371 370 ("abc'''", "a = '''\nabc'''"),
372 371 ],
373 372 [("a = '''", None), # Test resetting when within a multi-line string
374 373 ("def", None),
375 374 (None, "a = '''\ndef"),
376 375 ],
377 376 [("a = [1,", None),
378 377 ("2]", "a = [1,\n2]"),
379 378 ],
380 379 [("a = [1,", None), # Test resetting when within a multi-line string
381 380 ("2,", None),
382 381 (None, "a = [1,\n2,"),
383 382 ],
384 383 [("a = '''", None), # Test line continuation within a multi-line string
385 384 ("abc\\", None),
386 385 ("def", None),
387 386 ("'''", "a = '''\nabc\\\ndef\n'''"),
388 387 ],
389 388 ] + syntax_ml['multiline_datastructure']
390 389 for example in tests:
391 390 transform_checker(example, ipt.assemble_python_lines)
392 391
393 392
394 393 def test_help_end():
395 394 tt.check_pairs(transform_and_reset(ipt.help_end), syntax['end_help'])
396 395
397 396 def test_escaped_noesc():
398 397 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_noesc'])
399 398
400 399
401 400 def test_escaped_shell():
402 401 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_shell'])
403 402
404 403
405 404 def test_escaped_help():
406 405 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_help'])
407 406
408 407
409 408 def test_escaped_magic():
410 409 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_magic'])
411 410
412 411
413 412 def test_escaped_quote():
414 413 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_quote'])
415 414
416 415
417 416 def test_escaped_quote2():
418 417 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_quote2'])
419 418
420 419
421 420 def test_escaped_paren():
422 421 tt.check_pairs(transform_and_reset(ipt.escaped_commands), syntax['escaped_paren'])
423 422
424 423
425 424 def test_cellmagic():
426 425 for example in syntax_ml['cellmagic']:
427 426 transform_checker(example, ipt.cellmagic)
428 427
429 428 line_example = [('%%bar 123', None),
430 429 ('hello', None),
431 430 ('' , "get_ipython().run_cell_magic('bar', '123', 'hello')"),
432 431 ]
433 432 transform_checker(line_example, ipt.cellmagic, end_on_blank_line=True)
434 433
435 434 def test_has_comment():
436 435 tests = [('text', False),
437 436 ('text #comment', True),
438 437 ('text #comment\n', True),
439 438 ('#comment', True),
440 439 ('#comment\n', True),
441 440 ('a = "#string"', False),
442 441 ('a = "#string" # comment', True),
443 442 ('a #comment not "string"', True),
444 443 ]
445 444 tt.check_pairs(ipt.has_comment, tests)
446 445
447 446 @ipt.TokenInputTransformer.wrap
448 447 def decistmt(tokens):
449 448 """Substitute Decimals for floats in a string of statements.
450 449
451 450 Based on an example from the tokenize module docs.
452 451 """
453 452 result = []
454 453 for toknum, tokval, _, _, _ in tokens:
455 454 if toknum == tokenize.NUMBER and '.' in tokval: # replace NUMBER tokens
456 455 yield from [
457 456 (tokenize.NAME, 'Decimal'),
458 457 (tokenize.OP, '('),
459 458 (tokenize.STRING, repr(tokval)),
460 459 (tokenize.OP, ')')
461 460 ]
462 461 else:
463 462 yield (toknum, tokval)
464 463
465 464
466 465
467 466 def test_token_input_transformer():
468 467 tests = [('1.2', "Decimal ('1.2')"),
469 468 ('"1.2"', '"1.2"'),
470 469 ]
471 470 tt.check_pairs(transform_and_reset(decistmt), tests)
472 471 ml_tests = \
473 472 [ [("a = 1.2; b = '''x", None),
474 473 ("y'''", "a =Decimal ('1.2');b ='''x\ny'''"),
475 474 ],
476 475 [("a = [1.2,", None),
477 476 ("3]", "a =[Decimal ('1.2'),\n3 ]"),
478 477 ],
479 478 [("a = '''foo", None), # Test resetting when within a multi-line string
480 479 ("bar", None),
481 480 (None, "a = '''foo\nbar"),
482 481 ],
483 482 ]
484 483 for example in ml_tests:
485 484 transform_checker(example, decistmt)
@@ -1,355 +1,359 b''
1 1 """Tests for the token-based transformers in IPython.core.inputtransformer2
2 2
3 3 Line-based transformers are the simpler ones; token-based transformers are
4 4 more complex. See test_inputtransformer2_line for tests for line-based
5 5 transformations.
6 6 """
7 import nose.tools as nt
8 7 import string
9 8
10 9 from IPython.core import inputtransformer2 as ipt2
11 10 from IPython.core.inputtransformer2 import make_tokens_by_line, _find_assign_op
12 11
13 12 from textwrap import dedent
14 13
15 14 MULTILINE_MAGIC = ("""\
16 15 a = f()
17 16 %foo \\
18 17 bar
19 18 g()
20 19 """.splitlines(keepends=True), (2, 0), """\
21 20 a = f()
22 21 get_ipython().run_line_magic('foo', ' bar')
23 22 g()
24 23 """.splitlines(keepends=True))
25 24
26 25 INDENTED_MAGIC = ("""\
27 26 for a in range(5):
28 27 %ls
29 28 """.splitlines(keepends=True), (2, 4), """\
30 29 for a in range(5):
31 30 get_ipython().run_line_magic('ls', '')
32 31 """.splitlines(keepends=True))
33 32
34 33 CRLF_MAGIC = ([
35 34 "a = f()\n",
36 35 "%ls\r\n",
37 36 "g()\n"
38 37 ], (2, 0), [
39 38 "a = f()\n",
40 39 "get_ipython().run_line_magic('ls', '')\n",
41 40 "g()\n"
42 41 ])
43 42
44 43 MULTILINE_MAGIC_ASSIGN = ("""\
45 44 a = f()
46 45 b = %foo \\
47 46 bar
48 47 g()
49 48 """.splitlines(keepends=True), (2, 4), """\
50 49 a = f()
51 50 b = get_ipython().run_line_magic('foo', ' bar')
52 51 g()
53 52 """.splitlines(keepends=True))
54 53
55 54 MULTILINE_SYSTEM_ASSIGN = ("""\
56 55 a = f()
57 56 b = !foo \\
58 57 bar
59 58 g()
60 59 """.splitlines(keepends=True), (2, 4), """\
61 60 a = f()
62 61 b = get_ipython().getoutput('foo bar')
63 62 g()
64 63 """.splitlines(keepends=True))
65 64
66 65 #####
67 66
68 67 MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT = ("""\
69 68 def test():
70 69 for i in range(1):
71 70 print(i)
72 71 res =! ls
73 72 """.splitlines(keepends=True), (4, 7), '''\
74 73 def test():
75 74 for i in range(1):
76 75 print(i)
77 76 res =get_ipython().getoutput(\' ls\')
78 77 '''.splitlines(keepends=True))
79 78
80 79 ######
81 80
82 81 AUTOCALL_QUOTE = (
83 82 [",f 1 2 3\n"], (1, 0),
84 83 ['f("1", "2", "3")\n']
85 84 )
86 85
87 86 AUTOCALL_QUOTE2 = (
88 87 [";f 1 2 3\n"], (1, 0),
89 88 ['f("1 2 3")\n']
90 89 )
91 90
92 91 AUTOCALL_PAREN = (
93 92 ["/f 1 2 3\n"], (1, 0),
94 93 ['f(1, 2, 3)\n']
95 94 )
96 95
97 96 SIMPLE_HELP = (
98 97 ["foo?\n"], (1, 0),
99 98 ["get_ipython().run_line_magic('pinfo', 'foo')\n"]
100 99 )
101 100
102 101 DETAILED_HELP = (
103 102 ["foo??\n"], (1, 0),
104 103 ["get_ipython().run_line_magic('pinfo2', 'foo')\n"]
105 104 )
106 105
107 106 MAGIC_HELP = (
108 107 ["%foo?\n"], (1, 0),
109 108 ["get_ipython().run_line_magic('pinfo', '%foo')\n"]
110 109 )
111 110
112 111 HELP_IN_EXPR = (
113 112 ["a = b + c?\n"], (1, 0),
114 113 ["get_ipython().set_next_input('a = b + c');"
115 114 "get_ipython().run_line_magic('pinfo', 'c')\n"]
116 115 )
117 116
118 117 HELP_CONTINUED_LINE = ("""\
119 118 a = \\
120 119 zip?
121 120 """.splitlines(keepends=True), (1, 0),
122 121 [r"get_ipython().set_next_input('a = \\\nzip');get_ipython().run_line_magic('pinfo', 'zip')" + "\n"]
123 122 )
124 123
125 124 HELP_MULTILINE = ("""\
126 125 (a,
127 126 b) = zip?
128 127 """.splitlines(keepends=True), (1, 0),
129 128 [r"get_ipython().set_next_input('(a,\nb) = zip');get_ipython().run_line_magic('pinfo', 'zip')" + "\n"]
130 129 )
131 130
132 131 HELP_UNICODE = (
133 132 ["π.foo?\n"], (1, 0),
134 133 ["get_ipython().run_line_magic('pinfo', 'π.foo')\n"]
135 134 )
136 135
137 136
138 137 def null_cleanup_transformer(lines):
139 138 """
140 139 A cleanup transform that returns an empty list.
141 140 """
142 141 return []
143 142
144 143 def check_make_token_by_line_never_ends_empty():
145 144 """
146 145 Check that not sequence of single or double characters ends up leading to en empty list of tokens
147 146 """
148 147 from string import printable
149 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 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 154 def check_find(transformer, case, match=True):
155 155 sample, expected_start, _ = case
156 156 tbl = make_tokens_by_line(sample)
157 157 res = transformer.find(tbl)
158 158 if match:
159 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 161 return res
162 162 else:
163 nt.assert_is(res, None)
163 assert res is None
164 164
165 165 def check_transform(transformer_cls, case):
166 166 lines, start, expected = case
167 167 transformer = transformer_cls(start)
168 nt.assert_equal(transformer.transform(lines), expected)
168 assert transformer.transform(lines) == expected
169 169
170 170 def test_continued_line():
171 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 176 def test_find_assign_magic():
177 177 check_find(ipt2.MagicAssign, MULTILINE_MAGIC_ASSIGN)
178 178 check_find(ipt2.MagicAssign, MULTILINE_SYSTEM_ASSIGN, match=False)
179 179 check_find(ipt2.MagicAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT, match=False)
180 180
181 181 def test_transform_assign_magic():
182 182 check_transform(ipt2.MagicAssign, MULTILINE_MAGIC_ASSIGN)
183 183
184 184 def test_find_assign_system():
185 185 check_find(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN)
186 186 check_find(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT)
187 187 check_find(ipt2.SystemAssign, (["a = !ls\n"], (1, 5), None))
188 188 check_find(ipt2.SystemAssign, (["a=!ls\n"], (1, 2), None))
189 189 check_find(ipt2.SystemAssign, MULTILINE_MAGIC_ASSIGN, match=False)
190 190
191 191 def test_transform_assign_system():
192 192 check_transform(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN)
193 193 check_transform(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT)
194 194
195 195 def test_find_magic_escape():
196 196 check_find(ipt2.EscapedCommand, MULTILINE_MAGIC)
197 197 check_find(ipt2.EscapedCommand, INDENTED_MAGIC)
198 198 check_find(ipt2.EscapedCommand, MULTILINE_MAGIC_ASSIGN, match=False)
199 199
200 200 def test_transform_magic_escape():
201 201 check_transform(ipt2.EscapedCommand, MULTILINE_MAGIC)
202 202 check_transform(ipt2.EscapedCommand, INDENTED_MAGIC)
203 203 check_transform(ipt2.EscapedCommand, CRLF_MAGIC)
204 204
205 205 def test_find_autocalls():
206 206 for case in [AUTOCALL_QUOTE, AUTOCALL_QUOTE2, AUTOCALL_PAREN]:
207 207 print("Testing %r" % case[0])
208 208 check_find(ipt2.EscapedCommand, case)
209 209
210 210 def test_transform_autocall():
211 211 for case in [AUTOCALL_QUOTE, AUTOCALL_QUOTE2, AUTOCALL_PAREN]:
212 212 print("Testing %r" % case[0])
213 213 check_transform(ipt2.EscapedCommand, case)
214 214
215 215 def test_find_help():
216 216 for case in [SIMPLE_HELP, DETAILED_HELP, MAGIC_HELP, HELP_IN_EXPR]:
217 217 check_find(ipt2.HelpEnd, case)
218 218
219 219 tf = check_find(ipt2.HelpEnd, HELP_CONTINUED_LINE)
220 nt.assert_equal(tf.q_line, 1)
221 nt.assert_equal(tf.q_col, 3)
220 assert tf.q_line == 1
221 assert tf.q_col == 3
222 222
223 223 tf = check_find(ipt2.HelpEnd, HELP_MULTILINE)
224 nt.assert_equal(tf.q_line, 1)
225 nt.assert_equal(tf.q_col, 8)
224 assert tf.q_line == 1
225 assert tf.q_col == 8
226 226
227 227 # ? in a comment does not trigger help
228 228 check_find(ipt2.HelpEnd, (["foo # bar?\n"], None, None), match=False)
229 229 # Nor in a string
230 230 check_find(ipt2.HelpEnd, (["foo = '''bar?\n"], None, None), match=False)
231 231
232 232 def test_transform_help():
233 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 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 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 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 245 def test_find_assign_op_dedent():
246 246 """
247 247 be careful that empty token like dedent are not counted as parens
248 248 """
249 249 class Tk:
250 250 def __init__(self, s):
251 251 self.string = s
252 252
253 nt.assert_equal(_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)
253 assert _find_assign_op([Tk(s) for s in ("", "a", "=", "b")]) == 2
254 assert (
255 _find_assign_op([Tk(s) for s in ("", "(", "a", "=", "b", ")", "=", "5")]) == 6
256 )
257
255 258
256 259 def test_check_complete():
257 260 cc = ipt2.TransformerManager().check_complete
258 nt.assert_equal(cc("a = 1"), ("complete", None))
259 nt.assert_equal(cc("for a in range(5):"), ("incomplete", 4))
260 nt.assert_equal(cc("for a in range(5):\n if a > 0:"), ("incomplete", 8))
261 nt.assert_equal(cc("raise = 2"), ("invalid", None))
262 nt.assert_equal(cc("a = [1,\n2,"), ("incomplete", 0))
263 nt.assert_equal(cc("(\n))"), ("incomplete", 0))
264 nt.assert_equal(cc("\\\r\n"), ("incomplete", 0))
265 nt.assert_equal(cc("a = '''\n hi"), ("incomplete", 3))
266 nt.assert_equal(cc("def a():\n x=1\n global x"), ("invalid", None))
267 nt.assert_equal(cc("a \\ "), ("invalid", None)) # Nothing allowed after backslash
268 nt.assert_equal(cc("1\\\n+2"), ("complete", None))
269 nt.assert_equal(cc("exit"), ("complete", None))
261 assert cc("a = 1") == ("complete", None)
262 assert cc("for a in range(5):") == ("incomplete", 4)
263 assert cc("for a in range(5):\n if a > 0:") == ("incomplete", 8)
264 assert cc("raise = 2") == ("invalid", None)
265 assert cc("a = [1,\n2,") == ("incomplete", 0)
266 assert cc("(\n))") == ("incomplete", 0)
267 assert cc("\\\r\n") == ("incomplete", 0)
268 assert cc("a = '''\n hi") == ("incomplete", 3)
269 assert cc("def a():\n x=1\n global x") == ("invalid", None)
270 assert cc("a \\ ") == ("invalid", None) # Nothing allowed after backslash
271 assert cc("1\\\n+2") == ("complete", None)
272 assert cc("exit") == ("complete", None)
270 273
271 274 example = dedent("""
272 275 if True:
273 276 a=1""" )
274 277
275 nt.assert_equal(cc(example), ('incomplete', 4))
276 nt.assert_equal(cc(example+'\n'), ('complete', None))
277 nt.assert_equal(cc(example+'\n '), ('complete', None))
278 assert cc(example) == ("incomplete", 4)
279 assert cc(example + "\n") == ("complete", None)
280 assert cc(example + "\n ") == ("complete", None)
278 281
279 282 # no need to loop on all the letters/numbers.
280 283 short = '12abAB'+string.printable[62:]
281 284 for c in short:
282 285 # test does not raise:
283 286 cc(c)
284 287 for k in short:
285 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 293 def test_check_complete_II():
290 294 """
291 295 Test that multiple line strings are properly handled.
292 296
293 297 Separate test function for convenience
294 298
295 299 """
296 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 304 def test_check_complete_invalidates_sunken_brackets():
301 305 """
302 306 Test that a single line with more closing brackets than the opening ones is
303 307 interpreted as invalid
304 308 """
305 309 cc = ipt2.TransformerManager().check_complete
306 nt.assert_equal(cc(")"), ("invalid", None))
307 nt.assert_equal(cc("]"), ("invalid", None))
308 nt.assert_equal(cc("}"), ("invalid", None))
309 nt.assert_equal(cc(")("), ("invalid", None))
310 nt.assert_equal(cc("]["), ("invalid", None))
311 nt.assert_equal(cc("}{"), ("invalid", None))
312 nt.assert_equal(cc("]()("), ("invalid", None))
313 nt.assert_equal(cc("())("), ("invalid", None))
314 nt.assert_equal(cc(")[]("), ("invalid", None))
315 nt.assert_equal(cc("()]("), ("invalid", None))
310 assert cc(")") == ("invalid", None)
311 assert cc("]") == ("invalid", None)
312 assert cc("}") == ("invalid", None)
313 assert cc(")(") == ("invalid", None)
314 assert cc("][") == ("invalid", None)
315 assert cc("}{") == ("invalid", None)
316 assert cc("]()(") == ("invalid", None)
317 assert cc("())(") == ("invalid", None)
318 assert cc(")[](") == ("invalid", None)
319 assert cc("()](") == ("invalid", None)
316 320
317 321
318 322 def test_null_cleanup_transformer():
319 323 manager = ipt2.TransformerManager()
320 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 330 def test_side_effects_I():
327 331 count = 0
328 332 def counter(lines):
329 333 nonlocal count
330 334 count += 1
331 335 return lines
332 336
333 337 counter.has_side_effects = True
334 338
335 339 manager = ipt2.TransformerManager()
336 340 manager.cleanup_transforms.insert(0, counter)
337 341 assert manager.check_complete("a=1\n") == ('complete', None)
338 342 assert count == 0
339 343
340 344
341 345
342 346
343 347 def test_side_effects_II():
344 348 count = 0
345 349 def counter(lines):
346 350 nonlocal count
347 351 count += 1
348 352 return lines
349 353
350 354 counter.has_side_effects = True
351 355
352 356 manager = ipt2.TransformerManager()
353 357 manager.line_transforms.insert(0, counter)
354 358 assert manager.check_complete("b=1\n") == ('complete', None)
355 359 assert count == 0
@@ -1,1068 +1,1072 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Tests for the key interactiveshell module.
3 3
4 4 Historically the main classes in interactiveshell have been under-tested. This
5 5 module should grow as many single-method tests as possible to trap many of the
6 6 recurring bugs we seem to encounter with high-level interaction.
7 7 """
8 8
9 9 # Copyright (c) IPython Development Team.
10 10 # Distributed under the terms of the Modified BSD License.
11 11
12 12 import asyncio
13 13 import ast
14 14 import os
15 15 import signal
16 16 import shutil
17 17 import sys
18 18 import tempfile
19 19 import unittest
20 20 from unittest import mock
21 21
22 22 from os.path import join
23 23
24 import nose.tools as nt
25
26 24 from IPython.core.error import InputRejected
27 25 from IPython.core.inputtransformer import InputTransformer
28 26 from IPython.core import interactiveshell
29 27 from IPython.testing.decorators import (
30 28 skipif, skip_win32, onlyif_unicode_paths, onlyif_cmds_exist,
31 29 )
32 30 from IPython.testing import tools as tt
33 31 from IPython.utils.process import find_cmd
34 32
35 33 #-----------------------------------------------------------------------------
36 34 # Globals
37 35 #-----------------------------------------------------------------------------
38 36 # This is used by every single test, no point repeating it ad nauseam
39 37
40 38 #-----------------------------------------------------------------------------
41 39 # Tests
42 40 #-----------------------------------------------------------------------------
43 41
44 42 class DerivedInterrupt(KeyboardInterrupt):
45 43 pass
46 44
47 45 class InteractiveShellTestCase(unittest.TestCase):
48 46 def test_naked_string_cells(self):
49 47 """Test that cells with only naked strings are fully executed"""
50 48 # First, single-line inputs
51 49 ip.run_cell('"a"\n')
52 50 self.assertEqual(ip.user_ns['_'], 'a')
53 51 # And also multi-line cells
54 52 ip.run_cell('"""a\nb"""\n')
55 53 self.assertEqual(ip.user_ns['_'], 'a\nb')
56 54
57 55 def test_run_empty_cell(self):
58 56 """Just make sure we don't get a horrible error with a blank
59 57 cell of input. Yes, I did overlook that."""
60 58 old_xc = ip.execution_count
61 59 res = ip.run_cell('')
62 60 self.assertEqual(ip.execution_count, old_xc)
63 61 self.assertEqual(res.execution_count, None)
64 62
65 63 def test_run_cell_multiline(self):
66 64 """Multi-block, multi-line cells must execute correctly.
67 65 """
68 66 src = '\n'.join(["x=1",
69 67 "y=2",
70 68 "if 1:",
71 69 " x += 1",
72 70 " y += 1",])
73 71 res = ip.run_cell(src)
74 72 self.assertEqual(ip.user_ns['x'], 2)
75 73 self.assertEqual(ip.user_ns['y'], 3)
76 74 self.assertEqual(res.success, True)
77 75 self.assertEqual(res.result, None)
78 76
79 77 def test_multiline_string_cells(self):
80 78 "Code sprinkled with multiline strings should execute (GH-306)"
81 79 ip.run_cell('tmp=0')
82 80 self.assertEqual(ip.user_ns['tmp'], 0)
83 81 res = ip.run_cell('tmp=1;"""a\nb"""\n')
84 82 self.assertEqual(ip.user_ns['tmp'], 1)
85 83 self.assertEqual(res.success, True)
86 84 self.assertEqual(res.result, "a\nb")
87 85
88 86 def test_dont_cache_with_semicolon(self):
89 87 "Ending a line with semicolon should not cache the returned object (GH-307)"
90 88 oldlen = len(ip.user_ns['Out'])
91 89 for cell in ['1;', '1;1;']:
92 90 res = ip.run_cell(cell, store_history=True)
93 91 newlen = len(ip.user_ns['Out'])
94 92 self.assertEqual(oldlen, newlen)
95 93 self.assertIsNone(res.result)
96 94 i = 0
97 95 #also test the default caching behavior
98 96 for cell in ['1', '1;1']:
99 97 ip.run_cell(cell, store_history=True)
100 98 newlen = len(ip.user_ns['Out'])
101 99 i += 1
102 100 self.assertEqual(oldlen+i, newlen)
103 101
104 102 def test_syntax_error(self):
105 103 res = ip.run_cell("raise = 3")
106 104 self.assertIsInstance(res.error_before_exec, SyntaxError)
107 105
108 106 def test_In_variable(self):
109 107 "Verify that In variable grows with user input (GH-284)"
110 108 oldlen = len(ip.user_ns['In'])
111 109 ip.run_cell('1;', store_history=True)
112 110 newlen = len(ip.user_ns['In'])
113 111 self.assertEqual(oldlen+1, newlen)
114 112 self.assertEqual(ip.user_ns['In'][-1],'1;')
115 113
116 114 def test_magic_names_in_string(self):
117 115 ip.run_cell('a = """\n%exit\n"""')
118 116 self.assertEqual(ip.user_ns['a'], '\n%exit\n')
119 117
120 118 def test_trailing_newline(self):
121 119 """test that running !(command) does not raise a SyntaxError"""
122 120 ip.run_cell('!(true)\n', False)
123 121 ip.run_cell('!(true)\n\n\n', False)
124 122
125 123 def test_gh_597(self):
126 124 """Pretty-printing lists of objects with non-ascii reprs may cause
127 125 problems."""
128 126 class Spam(object):
129 127 def __repr__(self):
130 128 return "\xe9"*50
131 129 import IPython.core.formatters
132 130 f = IPython.core.formatters.PlainTextFormatter()
133 131 f([Spam(),Spam()])
134 132
135 133
136 134 def test_future_flags(self):
137 135 """Check that future flags are used for parsing code (gh-777)"""
138 136 ip.run_cell('from __future__ import barry_as_FLUFL')
139 137 try:
140 138 ip.run_cell('prfunc_return_val = 1 <> 2')
141 139 assert 'prfunc_return_val' in ip.user_ns
142 140 finally:
143 141 # Reset compiler flags so we don't mess up other tests.
144 142 ip.compile.reset_compiler_flags()
145 143
146 144 def test_can_pickle(self):
147 145 "Can we pickle objects defined interactively (GH-29)"
148 146 ip = get_ipython()
149 147 ip.reset()
150 148 ip.run_cell(("class Mylist(list):\n"
151 149 " def __init__(self,x=[]):\n"
152 150 " list.__init__(self,x)"))
153 151 ip.run_cell("w=Mylist([1,2,3])")
154 152
155 153 from pickle import dumps
156 154
157 155 # We need to swap in our main module - this is only necessary
158 156 # inside the test framework, because IPython puts the interactive module
159 157 # in place (but the test framework undoes this).
160 158 _main = sys.modules['__main__']
161 159 sys.modules['__main__'] = ip.user_module
162 160 try:
163 161 res = dumps(ip.user_ns["w"])
164 162 finally:
165 163 sys.modules['__main__'] = _main
166 164 self.assertTrue(isinstance(res, bytes))
167 165
168 166 def test_global_ns(self):
169 167 "Code in functions must be able to access variables outside them."
170 168 ip = get_ipython()
171 169 ip.run_cell("a = 10")
172 170 ip.run_cell(("def f(x):\n"
173 171 " return x + a"))
174 172 ip.run_cell("b = f(12)")
175 173 self.assertEqual(ip.user_ns["b"], 22)
176 174
177 175 def test_bad_custom_tb(self):
178 176 """Check that InteractiveShell is protected from bad custom exception handlers"""
179 177 ip.set_custom_exc((IOError,), lambda etype,value,tb: 1/0)
180 178 self.assertEqual(ip.custom_exceptions, (IOError,))
181 179 with tt.AssertPrints("Custom TB Handler failed", channel='stderr'):
182 180 ip.run_cell(u'raise IOError("foo")')
183 181 self.assertEqual(ip.custom_exceptions, ())
184 182
185 183 def test_bad_custom_tb_return(self):
186 184 """Check that InteractiveShell is protected from bad return types in custom exception handlers"""
187 185 ip.set_custom_exc((NameError,),lambda etype,value,tb, tb_offset=None: 1)
188 186 self.assertEqual(ip.custom_exceptions, (NameError,))
189 187 with tt.AssertPrints("Custom TB Handler failed", channel='stderr'):
190 188 ip.run_cell(u'a=abracadabra')
191 189 self.assertEqual(ip.custom_exceptions, ())
192 190
193 191 def test_drop_by_id(self):
194 192 myvars = {"a":object(), "b":object(), "c": object()}
195 193 ip.push(myvars, interactive=False)
196 194 for name in myvars:
197 195 assert name in ip.user_ns, name
198 196 assert name in ip.user_ns_hidden, name
199 197 ip.user_ns['b'] = 12
200 198 ip.drop_by_id(myvars)
201 199 for name in ["a", "c"]:
202 200 assert name not in ip.user_ns, name
203 201 assert name not in ip.user_ns_hidden, name
204 202 assert ip.user_ns['b'] == 12
205 203 ip.reset()
206 204
207 205 def test_var_expand(self):
208 206 ip.user_ns['f'] = u'Ca\xf1o'
209 207 self.assertEqual(ip.var_expand(u'echo $f'), u'echo Ca\xf1o')
210 208 self.assertEqual(ip.var_expand(u'echo {f}'), u'echo Ca\xf1o')
211 209 self.assertEqual(ip.var_expand(u'echo {f[:-1]}'), u'echo Ca\xf1')
212 210 self.assertEqual(ip.var_expand(u'echo {1*2}'), u'echo 2')
213 211
214 212 self.assertEqual(ip.var_expand(u"grep x | awk '{print $1}'"), u"grep x | awk '{print $1}'")
215 213
216 214 ip.user_ns['f'] = b'Ca\xc3\xb1o'
217 215 # This should not raise any exception:
218 216 ip.var_expand(u'echo $f')
219 217
220 218 def test_var_expand_local(self):
221 219 """Test local variable expansion in !system and %magic calls"""
222 220 # !system
223 ip.run_cell('def test():\n'
224 ' lvar = "ttt"\n'
225 ' ret = !echo {lvar}\n'
226 ' return ret[0]\n')
227 res = ip.user_ns['test']()
228 nt.assert_in('ttt', res)
229
221 ip.run_cell(
222 "def test():\n"
223 ' lvar = "ttt"\n'
224 " ret = !echo {lvar}\n"
225 " return ret[0]\n"
226 )
227 res = ip.user_ns["test"]()
228 self.assertIn("ttt", res)
229
230 230 # %magic
231 ip.run_cell('def makemacro():\n'
232 ' macroname = "macro_var_expand_locals"\n'
233 ' %macro {macroname} codestr\n')
234 ip.user_ns['codestr'] = "str(12)"
235 ip.run_cell('makemacro()')
236 nt.assert_in('macro_var_expand_locals', ip.user_ns)
237
231 ip.run_cell(
232 "def makemacro():\n"
233 ' macroname = "macro_var_expand_locals"\n'
234 " %macro {macroname} codestr\n"
235 )
236 ip.user_ns["codestr"] = "str(12)"
237 ip.run_cell("makemacro()")
238 self.assertIn("macro_var_expand_locals", ip.user_ns)
239
238 240 def test_var_expand_self(self):
239 241 """Test variable expansion with the name 'self', which was failing.
240 242
241 243 See https://github.com/ipython/ipython/issues/1878#issuecomment-7698218
242 244 """
243 ip.run_cell('class cTest:\n'
244 ' classvar="see me"\n'
245 ' def test(self):\n'
246 ' res = !echo Variable: {self.classvar}\n'
247 ' return res[0]\n')
248 nt.assert_in('see me', ip.user_ns['cTest']().test())
249
245 ip.run_cell(
246 "class cTest:\n"
247 ' classvar="see me"\n'
248 " def test(self):\n"
249 " res = !echo Variable: {self.classvar}\n"
250 " return res[0]\n"
251 )
252 self.assertIn("see me", ip.user_ns["cTest"]().test())
253
250 254 def test_bad_var_expand(self):
251 255 """var_expand on invalid formats shouldn't raise"""
252 256 # SyntaxError
253 257 self.assertEqual(ip.var_expand(u"{'a':5}"), u"{'a':5}")
254 258 # NameError
255 259 self.assertEqual(ip.var_expand(u"{asdf}"), u"{asdf}")
256 260 # ZeroDivisionError
257 261 self.assertEqual(ip.var_expand(u"{1/0}"), u"{1/0}")
258 262
259 263 def test_silent_postexec(self):
260 264 """run_cell(silent=True) doesn't invoke pre/post_run_cell callbacks"""
261 265 pre_explicit = mock.Mock()
262 266 pre_always = mock.Mock()
263 267 post_explicit = mock.Mock()
264 268 post_always = mock.Mock()
265 269 all_mocks = [pre_explicit, pre_always, post_explicit, post_always]
266 270
267 271 ip.events.register('pre_run_cell', pre_explicit)
268 272 ip.events.register('pre_execute', pre_always)
269 273 ip.events.register('post_run_cell', post_explicit)
270 274 ip.events.register('post_execute', post_always)
271 275
272 276 try:
273 277 ip.run_cell("1", silent=True)
274 278 assert pre_always.called
275 279 assert not pre_explicit.called
276 280 assert post_always.called
277 281 assert not post_explicit.called
278 282 # double-check that non-silent exec did what we expected
279 283 # silent to avoid
280 284 ip.run_cell("1")
281 285 assert pre_explicit.called
282 286 assert post_explicit.called
283 287 info, = pre_explicit.call_args[0]
284 288 result, = post_explicit.call_args[0]
285 289 self.assertEqual(info, result.info)
286 290 # check that post hooks are always called
287 291 [m.reset_mock() for m in all_mocks]
288 292 ip.run_cell("syntax error")
289 293 assert pre_always.called
290 294 assert pre_explicit.called
291 295 assert post_always.called
292 296 assert post_explicit.called
293 297 info, = pre_explicit.call_args[0]
294 298 result, = post_explicit.call_args[0]
295 299 self.assertEqual(info, result.info)
296 300 finally:
297 301 # remove post-exec
298 302 ip.events.unregister('pre_run_cell', pre_explicit)
299 303 ip.events.unregister('pre_execute', pre_always)
300 304 ip.events.unregister('post_run_cell', post_explicit)
301 305 ip.events.unregister('post_execute', post_always)
302 306
303 307 def test_silent_noadvance(self):
304 308 """run_cell(silent=True) doesn't advance execution_count"""
305 309 ec = ip.execution_count
306 310 # silent should force store_history=False
307 311 ip.run_cell("1", store_history=True, silent=True)
308 312
309 313 self.assertEqual(ec, ip.execution_count)
310 314 # double-check that non-silent exec did what we expected
311 315 # silent to avoid
312 316 ip.run_cell("1", store_history=True)
313 317 self.assertEqual(ec+1, ip.execution_count)
314 318
315 319 def test_silent_nodisplayhook(self):
316 320 """run_cell(silent=True) doesn't trigger displayhook"""
317 321 d = dict(called=False)
318 322
319 323 trap = ip.display_trap
320 324 save_hook = trap.hook
321 325
322 326 def failing_hook(*args, **kwargs):
323 327 d['called'] = True
324 328
325 329 try:
326 330 trap.hook = failing_hook
327 331 res = ip.run_cell("1", silent=True)
328 332 self.assertFalse(d['called'])
329 333 self.assertIsNone(res.result)
330 334 # double-check that non-silent exec did what we expected
331 335 # silent to avoid
332 336 ip.run_cell("1")
333 337 self.assertTrue(d['called'])
334 338 finally:
335 339 trap.hook = save_hook
336 340
337 341 def test_ofind_line_magic(self):
338 342 from IPython.core.magic import register_line_magic
339 343
340 344 @register_line_magic
341 345 def lmagic(line):
342 346 "A line magic"
343 347
344 348 # Get info on line magic
345 349 lfind = ip._ofind('lmagic')
346 350 info = dict(found=True, isalias=False, ismagic=True,
347 351 namespace = 'IPython internal', obj= lmagic.__wrapped__,
348 352 parent = None)
349 nt.assert_equal(lfind, info)
353 self.assertEqual(lfind, info)
350 354
351 355 def test_ofind_cell_magic(self):
352 356 from IPython.core.magic import register_cell_magic
353 357
354 358 @register_cell_magic
355 359 def cmagic(line, cell):
356 360 "A cell magic"
357 361
358 362 # Get info on cell magic
359 363 find = ip._ofind('cmagic')
360 364 info = dict(found=True, isalias=False, ismagic=True,
361 365 namespace = 'IPython internal', obj= cmagic.__wrapped__,
362 366 parent = None)
363 nt.assert_equal(find, info)
367 self.assertEqual(find, info)
364 368
365 369 def test_ofind_property_with_error(self):
366 370 class A(object):
367 371 @property
368 372 def foo(self):
369 373 raise NotImplementedError()
370 374 a = A()
371 375
372 376 found = ip._ofind('a.foo', [('locals', locals())])
373 377 info = dict(found=True, isalias=False, ismagic=False,
374 378 namespace='locals', obj=A.foo, parent=a)
375 nt.assert_equal(found, info)
379 self.assertEqual(found, info)
376 380
377 381 def test_ofind_multiple_attribute_lookups(self):
378 382 class A(object):
379 383 @property
380 384 def foo(self):
381 385 raise NotImplementedError()
382 386
383 387 a = A()
384 388 a.a = A()
385 389 a.a.a = A()
386 390
387 391 found = ip._ofind('a.a.a.foo', [('locals', locals())])
388 392 info = dict(found=True, isalias=False, ismagic=False,
389 393 namespace='locals', obj=A.foo, parent=a.a.a)
390 nt.assert_equal(found, info)
394 self.assertEqual(found, info)
391 395
392 396 def test_ofind_slotted_attributes(self):
393 397 class A(object):
394 398 __slots__ = ['foo']
395 399 def __init__(self):
396 400 self.foo = 'bar'
397 401
398 402 a = A()
399 403 found = ip._ofind('a.foo', [('locals', locals())])
400 404 info = dict(found=True, isalias=False, ismagic=False,
401 405 namespace='locals', obj=a.foo, parent=a)
402 nt.assert_equal(found, info)
406 self.assertEqual(found, info)
403 407
404 408 found = ip._ofind('a.bar', [('locals', locals())])
405 409 info = dict(found=False, isalias=False, ismagic=False,
406 410 namespace=None, obj=None, parent=a)
407 nt.assert_equal(found, info)
411 self.assertEqual(found, info)
408 412
409 413 def test_ofind_prefers_property_to_instance_level_attribute(self):
410 414 class A(object):
411 415 @property
412 416 def foo(self):
413 417 return 'bar'
414 418 a = A()
415 a.__dict__['foo'] = 'baz'
416 nt.assert_equal(a.foo, 'bar')
417 found = ip._ofind('a.foo', [('locals', locals())])
418 nt.assert_is(found['obj'], A.foo)
419 a.__dict__["foo"] = "baz"
420 self.assertEqual(a.foo, "bar")
421 found = ip._ofind("a.foo", [("locals", locals())])
422 self.assertIs(found["obj"], A.foo)
419 423
420 424 def test_custom_syntaxerror_exception(self):
421 425 called = []
422 426 def my_handler(shell, etype, value, tb, tb_offset=None):
423 427 called.append(etype)
424 428 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
425 429
426 430 ip.set_custom_exc((SyntaxError,), my_handler)
427 431 try:
428 432 ip.run_cell("1f")
429 433 # Check that this was called, and only once.
430 434 self.assertEqual(called, [SyntaxError])
431 435 finally:
432 436 # Reset the custom exception hook
433 437 ip.set_custom_exc((), None)
434 438
435 439 def test_custom_exception(self):
436 440 called = []
437 441 def my_handler(shell, etype, value, tb, tb_offset=None):
438 442 called.append(etype)
439 443 shell.showtraceback((etype, value, tb), tb_offset=tb_offset)
440 444
441 445 ip.set_custom_exc((ValueError,), my_handler)
442 446 try:
443 447 res = ip.run_cell("raise ValueError('test')")
444 448 # Check that this was called, and only once.
445 449 self.assertEqual(called, [ValueError])
446 450 # Check that the error is on the result object
447 451 self.assertIsInstance(res.error_in_exec, ValueError)
448 452 finally:
449 453 # Reset the custom exception hook
450 454 ip.set_custom_exc((), None)
451 455
452 456 @mock.patch("builtins.print")
453 457 def test_showtraceback_with_surrogates(self, mocked_print):
454 458 values = []
455 459
456 460 def mock_print_func(value, sep=" ", end="\n", file=sys.stdout, flush=False):
457 461 values.append(value)
458 462 if value == chr(0xD8FF):
459 463 raise UnicodeEncodeError("utf-8", chr(0xD8FF), 0, 1, "")
460 464
461 465 # mock builtins.print
462 466 mocked_print.side_effect = mock_print_func
463 467
464 468 # ip._showtraceback() is replaced in globalipapp.py.
465 469 # Call original method to test.
466 470 interactiveshell.InteractiveShell._showtraceback(ip, None, None, chr(0xD8FF))
467 471
468 472 self.assertEqual(mocked_print.call_count, 2)
469 473 self.assertEqual(values, [chr(0xD8FF), "\\ud8ff"])
470 474
471 475 def test_mktempfile(self):
472 476 filename = ip.mktempfile()
473 477 # Check that we can open the file again on Windows
474 478 with open(filename, 'w') as f:
475 479 f.write('abc')
476 480
477 481 filename = ip.mktempfile(data='blah')
478 482 with open(filename, 'r') as f:
479 483 self.assertEqual(f.read(), 'blah')
480 484
481 485 def test_new_main_mod(self):
482 486 # Smoketest to check that this accepts a unicode module name
483 487 name = u'jiefmw'
484 488 mod = ip.new_main_mod(u'%s.py' % name, name)
485 489 self.assertEqual(mod.__name__, name)
486 490
487 491 def test_get_exception_only(self):
488 492 try:
489 493 raise KeyboardInterrupt
490 494 except KeyboardInterrupt:
491 495 msg = ip.get_exception_only()
492 496 self.assertEqual(msg, 'KeyboardInterrupt\n')
493 497
494 498 try:
495 499 raise DerivedInterrupt("foo")
496 500 except KeyboardInterrupt:
497 501 msg = ip.get_exception_only()
498 502 self.assertEqual(msg, 'IPython.core.tests.test_interactiveshell.DerivedInterrupt: foo\n')
499 503
500 504 def test_inspect_text(self):
501 505 ip.run_cell('a = 5')
502 506 text = ip.object_inspect_text('a')
503 507 self.assertIsInstance(text, str)
504 508
505 509 def test_last_execution_result(self):
506 510 """ Check that last execution result gets set correctly (GH-10702) """
507 511 result = ip.run_cell('a = 5; a')
508 512 self.assertTrue(ip.last_execution_succeeded)
509 513 self.assertEqual(ip.last_execution_result.result, 5)
510 514
511 515 result = ip.run_cell('a = x_invalid_id_x')
512 516 self.assertFalse(ip.last_execution_succeeded)
513 517 self.assertFalse(ip.last_execution_result.success)
514 518 self.assertIsInstance(ip.last_execution_result.error_in_exec, NameError)
515 519
516 520 def test_reset_aliasing(self):
517 521 """ Check that standard posix aliases work after %reset. """
518 522 if os.name != 'posix':
519 523 return
520 524
521 525 ip.reset()
522 526 for cmd in ('clear', 'more', 'less', 'man'):
523 527 res = ip.run_cell('%' + cmd)
524 528 self.assertEqual(res.success, True)
525 529
526 530
527 531 class TestSafeExecfileNonAsciiPath(unittest.TestCase):
528 532
529 533 @onlyif_unicode_paths
530 534 def setUp(self):
531 535 self.BASETESTDIR = tempfile.mkdtemp()
532 536 self.TESTDIR = join(self.BASETESTDIR, u"åäö")
533 537 os.mkdir(self.TESTDIR)
534 538 with open(join(self.TESTDIR, u"åäötestscript.py"), "w") as sfile:
535 539 sfile.write("pass\n")
536 540 self.oldpath = os.getcwd()
537 541 os.chdir(self.TESTDIR)
538 542 self.fname = u"åäötestscript.py"
539 543
540 544 def tearDown(self):
541 545 os.chdir(self.oldpath)
542 546 shutil.rmtree(self.BASETESTDIR)
543 547
544 548 @onlyif_unicode_paths
545 549 def test_1(self):
546 550 """Test safe_execfile with non-ascii path
547 551 """
548 552 ip.safe_execfile(self.fname, {}, raise_exceptions=True)
549 553
550 554 class ExitCodeChecks(tt.TempFileMixin):
551 555
552 556 def setUp(self):
553 557 self.system = ip.system_raw
554 558
555 559 def test_exit_code_ok(self):
556 560 self.system('exit 0')
557 561 self.assertEqual(ip.user_ns['_exit_code'], 0)
558 562
559 563 def test_exit_code_error(self):
560 564 self.system('exit 1')
561 565 self.assertEqual(ip.user_ns['_exit_code'], 1)
562 566
563 567 @skipif(not hasattr(signal, 'SIGALRM'))
564 568 def test_exit_code_signal(self):
565 569 self.mktmp("import signal, time\n"
566 570 "signal.setitimer(signal.ITIMER_REAL, 0.1)\n"
567 571 "time.sleep(1)\n")
568 572 self.system("%s %s" % (sys.executable, self.fname))
569 573 self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGALRM)
570 574
571 575 @onlyif_cmds_exist("csh")
572 576 def test_exit_code_signal_csh(self):
573 577 SHELL = os.environ.get('SHELL', None)
574 578 os.environ['SHELL'] = find_cmd("csh")
575 579 try:
576 580 self.test_exit_code_signal()
577 581 finally:
578 582 if SHELL is not None:
579 583 os.environ['SHELL'] = SHELL
580 584 else:
581 585 del os.environ['SHELL']
582 586
583 587
584 588 class TestSystemRaw(ExitCodeChecks):
585 589
586 590 def setUp(self):
587 591 super().setUp()
588 592 self.system = ip.system_raw
589 593
590 594 @onlyif_unicode_paths
591 595 def test_1(self):
592 596 """Test system_raw with non-ascii cmd
593 597 """
594 598 cmd = u'''python -c "'åäö'" '''
595 599 ip.system_raw(cmd)
596 600
597 601 @mock.patch('subprocess.call', side_effect=KeyboardInterrupt)
598 602 @mock.patch('os.system', side_effect=KeyboardInterrupt)
599 603 def test_control_c(self, *mocks):
600 604 try:
601 605 self.system("sleep 1 # wont happen")
602 606 except KeyboardInterrupt:
603 607 self.fail(
604 608 "system call should intercept "
605 609 "keyboard interrupt from subprocess.call"
606 610 )
607 611 self.assertEqual(ip.user_ns["_exit_code"], -signal.SIGINT)
608 612
609 613 def test_magic_warnings(self):
610 614 for magic_cmd in ("ls", "pip", "conda", "cd"):
611 615 with self.assertWarnsRegex(Warning, "You executed the system command"):
612 616 ip.system_raw(magic_cmd)
613 617
614 618 # TODO: Exit codes are currently ignored on Windows.
615 619 class TestSystemPipedExitCode(ExitCodeChecks):
616 620
617 621 def setUp(self):
618 622 super().setUp()
619 623 self.system = ip.system_piped
620 624
621 625 @skip_win32
622 626 def test_exit_code_ok(self):
623 627 ExitCodeChecks.test_exit_code_ok(self)
624 628
625 629 @skip_win32
626 630 def test_exit_code_error(self):
627 631 ExitCodeChecks.test_exit_code_error(self)
628 632
629 633 @skip_win32
630 634 def test_exit_code_signal(self):
631 635 ExitCodeChecks.test_exit_code_signal(self)
632 636
633 637 class TestModules(tt.TempFileMixin):
634 638 def test_extraneous_loads(self):
635 639 """Test we're not loading modules on startup that we shouldn't.
636 640 """
637 641 self.mktmp("import sys\n"
638 642 "print('numpy' in sys.modules)\n"
639 643 "print('ipyparallel' in sys.modules)\n"
640 644 "print('ipykernel' in sys.modules)\n"
641 645 )
642 646 out = "False\nFalse\nFalse\n"
643 647 tt.ipexec_validate(self.fname, out)
644 648
645 649 class Negator(ast.NodeTransformer):
646 650 """Negates all number literals in an AST."""
647 651
648 652 # for python 3.7 and earlier
649 653 def visit_Num(self, node):
650 654 node.n = -node.n
651 655 return node
652 656
653 657 # for python 3.8+
654 658 def visit_Constant(self, node):
655 659 if isinstance(node.value, int):
656 660 return self.visit_Num(node)
657 661 return node
658 662
659 663 class TestAstTransform(unittest.TestCase):
660 664 def setUp(self):
661 665 self.negator = Negator()
662 666 ip.ast_transformers.append(self.negator)
663 667
664 668 def tearDown(self):
665 669 ip.ast_transformers.remove(self.negator)
666 670
667 671 def test_run_cell(self):
668 672 with tt.AssertPrints('-34'):
669 673 ip.run_cell('print (12 + 22)')
670 674
671 675 # A named reference to a number shouldn't be transformed.
672 676 ip.user_ns['n'] = 55
673 677 with tt.AssertNotPrints('-55'):
674 678 ip.run_cell('print (n)')
675 679
676 680 def test_timeit(self):
677 681 called = set()
678 682 def f(x):
679 683 called.add(x)
680 684 ip.push({'f':f})
681 685
682 686 with tt.AssertPrints("std. dev. of"):
683 687 ip.run_line_magic("timeit", "-n1 f(1)")
684 688 self.assertEqual(called, {-1})
685 689 called.clear()
686 690
687 691 with tt.AssertPrints("std. dev. of"):
688 692 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
689 693 self.assertEqual(called, {-2, -3})
690 694
691 695 def test_time(self):
692 696 called = []
693 697 def f(x):
694 698 called.append(x)
695 699 ip.push({'f':f})
696 700
697 701 # Test with an expression
698 702 with tt.AssertPrints("Wall time: "):
699 703 ip.run_line_magic("time", "f(5+9)")
700 704 self.assertEqual(called, [-14])
701 705 called[:] = []
702 706
703 707 # Test with a statement (different code path)
704 708 with tt.AssertPrints("Wall time: "):
705 709 ip.run_line_magic("time", "a = f(-3 + -2)")
706 710 self.assertEqual(called, [5])
707 711
708 712 def test_macro(self):
709 713 ip.push({'a':10})
710 714 # The AST transformation makes this do a+=-1
711 715 ip.define_macro("amacro", "a+=1\nprint(a)")
712 716
713 717 with tt.AssertPrints("9"):
714 718 ip.run_cell("amacro")
715 719 with tt.AssertPrints("8"):
716 720 ip.run_cell("amacro")
717 721
718 722 class TestMiscTransform(unittest.TestCase):
719 723
720 724
721 725 def test_transform_only_once(self):
722 726 cleanup = 0
723 727 line_t = 0
724 728 def count_cleanup(lines):
725 729 nonlocal cleanup
726 730 cleanup += 1
727 731 return lines
728 732
729 733 def count_line_t(lines):
730 734 nonlocal line_t
731 735 line_t += 1
732 736 return lines
733 737
734 738 ip.input_transformer_manager.cleanup_transforms.append(count_cleanup)
735 739 ip.input_transformer_manager.line_transforms.append(count_line_t)
736 740
737 741 ip.run_cell('1')
738 742
739 743 assert cleanup == 1
740 744 assert line_t == 1
741 745
742 746 class IntegerWrapper(ast.NodeTransformer):
743 747 """Wraps all integers in a call to Integer()"""
744 748
745 749 # for Python 3.7 and earlier
746 750
747 751 # for Python 3.7 and earlier
748 752 def visit_Num(self, node):
749 753 if isinstance(node.n, int):
750 754 return ast.Call(func=ast.Name(id='Integer', ctx=ast.Load()),
751 755 args=[node], keywords=[])
752 756 return node
753 757
754 758 # For Python 3.8+
755 759 def visit_Constant(self, node):
756 760 if isinstance(node.value, int):
757 761 return self.visit_Num(node)
758 762 return node
759 763
760 764
761 765 class TestAstTransform2(unittest.TestCase):
762 766 def setUp(self):
763 767 self.intwrapper = IntegerWrapper()
764 768 ip.ast_transformers.append(self.intwrapper)
765 769
766 770 self.calls = []
767 771 def Integer(*args):
768 772 self.calls.append(args)
769 773 return args
770 774 ip.push({"Integer": Integer})
771 775
772 776 def tearDown(self):
773 777 ip.ast_transformers.remove(self.intwrapper)
774 778 del ip.user_ns['Integer']
775 779
776 780 def test_run_cell(self):
777 781 ip.run_cell("n = 2")
778 782 self.assertEqual(self.calls, [(2,)])
779 783
780 784 # This shouldn't throw an error
781 785 ip.run_cell("o = 2.0")
782 786 self.assertEqual(ip.user_ns['o'], 2.0)
783 787
784 788 def test_timeit(self):
785 789 called = set()
786 790 def f(x):
787 791 called.add(x)
788 792 ip.push({'f':f})
789 793
790 794 with tt.AssertPrints("std. dev. of"):
791 795 ip.run_line_magic("timeit", "-n1 f(1)")
792 796 self.assertEqual(called, {(1,)})
793 797 called.clear()
794 798
795 799 with tt.AssertPrints("std. dev. of"):
796 800 ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)")
797 801 self.assertEqual(called, {(2,), (3,)})
798 802
799 803 class ErrorTransformer(ast.NodeTransformer):
800 804 """Throws an error when it sees a number."""
801 805
802 806 # for Python 3.7 and earlier
803 807 def visit_Num(self, node):
804 808 raise ValueError("test")
805 809
806 810 # for Python 3.8+
807 811 def visit_Constant(self, node):
808 812 if isinstance(node.value, int):
809 813 return self.visit_Num(node)
810 814 return node
811 815
812 816
813 817 class TestAstTransformError(unittest.TestCase):
814 818 def test_unregistering(self):
815 819 err_transformer = ErrorTransformer()
816 820 ip.ast_transformers.append(err_transformer)
817 821
818 822 with self.assertWarnsRegex(UserWarning, "It will be unregistered"):
819 823 ip.run_cell("1 + 2")
820 824
821 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 829 class StringRejector(ast.NodeTransformer):
826 830 """Throws an InputRejected when it sees a string literal.
827 831
828 832 Used to verify that NodeTransformers can signal that a piece of code should
829 833 not be executed by throwing an InputRejected.
830 834 """
831 835
832 836 #for python 3.7 and earlier
833 837 def visit_Str(self, node):
834 838 raise InputRejected("test")
835 839
836 840 # 3.8 only
837 841 def visit_Constant(self, node):
838 842 if isinstance(node.value, str):
839 843 raise InputRejected("test")
840 844 return node
841 845
842 846
843 847 class TestAstTransformInputRejection(unittest.TestCase):
844 848
845 849 def setUp(self):
846 850 self.transformer = StringRejector()
847 851 ip.ast_transformers.append(self.transformer)
848 852
849 853 def tearDown(self):
850 854 ip.ast_transformers.remove(self.transformer)
851 855
852 856 def test_input_rejection(self):
853 857 """Check that NodeTransformers can reject input."""
854 858
855 859 expect_exception_tb = tt.AssertPrints("InputRejected: test")
856 860 expect_no_cell_output = tt.AssertNotPrints("'unsafe'", suppress=False)
857 861
858 862 # Run the same check twice to verify that the transformer is not
859 863 # disabled after raising.
860 864 with expect_exception_tb, expect_no_cell_output:
861 865 ip.run_cell("'unsafe'")
862 866
863 867 with expect_exception_tb, expect_no_cell_output:
864 868 res = ip.run_cell("'unsafe'")
865 869
866 870 self.assertIsInstance(res.error_before_exec, InputRejected)
867 871
868 872 def test__IPYTHON__():
869 873 # This shouldn't raise a NameError, that's all
870 874 __IPYTHON__
871 875
872 876
873 877 class DummyRepr(object):
874 878 def __repr__(self):
875 879 return "DummyRepr"
876 880
877 881 def _repr_html_(self):
878 882 return "<b>dummy</b>"
879 883
880 884 def _repr_javascript_(self):
881 885 return "console.log('hi');", {'key': 'value'}
882 886
883 887
884 888 def test_user_variables():
885 889 # enable all formatters
886 890 ip.display_formatter.active_types = ip.display_formatter.format_types
887 891
888 892 ip.user_ns['dummy'] = d = DummyRepr()
889 893 keys = {'dummy', 'doesnotexist'}
890 894 r = ip.user_expressions({ key:key for key in keys})
891 895
892 nt.assert_equal(keys, set(r.keys()))
893 dummy = r['dummy']
894 nt.assert_equal({'status', 'data', 'metadata'}, set(dummy.keys()))
895 nt.assert_equal(dummy['status'], 'ok')
896 data = dummy['data']
897 metadata = dummy['metadata']
898 nt.assert_equal(data.get('text/html'), d._repr_html_())
896 assert keys == set(r.keys())
897 dummy = r["dummy"]
898 assert {"status", "data", "metadata"} == set(dummy.keys())
899 assert dummy["status"] == "ok"
900 data = dummy["data"]
901 metadata = dummy["metadata"]
902 assert data.get("text/html") == d._repr_html_()
899 903 js, jsmd = d._repr_javascript_()
900 nt.assert_equal(data.get('application/javascript'), js)
901 nt.assert_equal(metadata.get('application/javascript'), jsmd)
902
903 dne = r['doesnotexist']
904 nt.assert_equal(dne['status'], 'error')
905 nt.assert_equal(dne['ename'], 'NameError')
906
904 assert data.get("application/javascript") == js
905 assert metadata.get("application/javascript") == jsmd
906
907 dne = r["doesnotexist"]
908 assert dne["status"] == "error"
909 assert dne["ename"] == "NameError"
910
907 911 # back to text only
908 912 ip.display_formatter.active_types = ['text/plain']
909 913
910 914 def test_user_expression():
911 915 # enable all formatters
912 916 ip.display_formatter.active_types = ip.display_formatter.format_types
913 917 query = {
914 918 'a' : '1 + 2',
915 919 'b' : '1/0',
916 920 }
917 921 r = ip.user_expressions(query)
918 922 import pprint
919 923 pprint.pprint(r)
920 nt.assert_equal(set(r.keys()), set(query.keys()))
921 a = r['a']
922 nt.assert_equal({'status', 'data', 'metadata'}, set(a.keys()))
923 nt.assert_equal(a['status'], 'ok')
924 data = a['data']
925 metadata = a['metadata']
926 nt.assert_equal(data.get('text/plain'), '3')
927
928 b = r['b']
929 nt.assert_equal(b['status'], 'error')
930 nt.assert_equal(b['ename'], 'ZeroDivisionError')
931
924 assert set(r.keys()) == set(query.keys())
925 a = r["a"]
926 assert {"status", "data", "metadata"} == set(a.keys())
927 assert a["status"] == "ok"
928 data = a["data"]
929 metadata = a["metadata"]
930 assert data.get("text/plain") == "3"
931
932 b = r["b"]
933 assert b["status"] == "error"
934 assert b["ename"] == "ZeroDivisionError"
935
932 936 # back to text only
933 937 ip.display_formatter.active_types = ['text/plain']
934 938
935 939
936 940 class TestSyntaxErrorTransformer(unittest.TestCase):
937 941 """Check that SyntaxError raised by an input transformer is handled by run_cell()"""
938 942
939 943 @staticmethod
940 944 def transformer(lines):
941 945 for line in lines:
942 946 pos = line.find('syntaxerror')
943 947 if pos >= 0:
944 948 e = SyntaxError('input contains "syntaxerror"')
945 949 e.text = line
946 950 e.offset = pos + 1
947 951 raise e
948 952 return lines
949 953
950 954 def setUp(self):
951 955 ip.input_transformers_post.append(self.transformer)
952 956
953 957 def tearDown(self):
954 958 ip.input_transformers_post.remove(self.transformer)
955 959
956 960 def test_syntaxerror_input_transformer(self):
957 961 with tt.AssertPrints('1234'):
958 962 ip.run_cell('1234')
959 963 with tt.AssertPrints('SyntaxError: invalid syntax'):
960 964 ip.run_cell('1 2 3') # plain python syntax error
961 965 with tt.AssertPrints('SyntaxError: input contains "syntaxerror"'):
962 966 ip.run_cell('2345 # syntaxerror') # input transformer syntax error
963 967 with tt.AssertPrints('3456'):
964 968 ip.run_cell('3456')
965 969
966 970
967 971 class TestWarningSuppression(unittest.TestCase):
968 972 def test_warning_suppression(self):
969 973 ip.run_cell("import warnings")
970 974 try:
971 975 with self.assertWarnsRegex(UserWarning, "asdf"):
972 976 ip.run_cell("warnings.warn('asdf')")
973 977 # Here's the real test -- if we run that again, we should get the
974 978 # warning again. Traditionally, each warning was only issued once per
975 979 # IPython session (approximately), even if the user typed in new and
976 980 # different code that should have also triggered the warning, leading
977 981 # to much confusion.
978 982 with self.assertWarnsRegex(UserWarning, "asdf"):
979 983 ip.run_cell("warnings.warn('asdf')")
980 984 finally:
981 985 ip.run_cell("del warnings")
982 986
983 987
984 988 def test_deprecation_warning(self):
985 989 ip.run_cell("""
986 990 import warnings
987 991 def wrn():
988 992 warnings.warn(
989 993 "I AM A WARNING",
990 994 DeprecationWarning
991 995 )
992 996 """)
993 997 try:
994 998 with self.assertWarnsRegex(DeprecationWarning, "I AM A WARNING"):
995 999 ip.run_cell("wrn()")
996 1000 finally:
997 1001 ip.run_cell("del warnings")
998 1002 ip.run_cell("del wrn")
999 1003
1000 1004
1001 1005 class TestImportNoDeprecate(tt.TempFileMixin):
1002 1006
1003 1007 def setUp(self):
1004 1008 """Make a valid python temp file."""
1005 1009 self.mktmp("""
1006 1010 import warnings
1007 1011 def wrn():
1008 1012 warnings.warn(
1009 1013 "I AM A WARNING",
1010 1014 DeprecationWarning
1011 1015 )
1012 1016 """)
1013 1017 super().setUp()
1014 1018
1015 1019 def test_no_dep(self):
1016 1020 """
1017 1021 No deprecation warning should be raised from imported functions
1018 1022 """
1019 1023 ip.run_cell("from {} import wrn".format(self.fname))
1020 1024
1021 1025 with tt.AssertNotPrints("I AM A WARNING"):
1022 1026 ip.run_cell("wrn()")
1023 1027 ip.run_cell("del wrn")
1024 1028
1025 1029
1026 1030 def test_custom_exc_count():
1027 1031 hook = mock.Mock(return_value=None)
1028 1032 ip.set_custom_exc((SyntaxError,), hook)
1029 1033 before = ip.execution_count
1030 1034 ip.run_cell("def foo()", store_history=True)
1031 1035 # restore default excepthook
1032 1036 ip.set_custom_exc((), None)
1033 nt.assert_equal(hook.call_count, 1)
1034 nt.assert_equal(ip.execution_count, before + 1)
1037 assert hook.call_count == 1
1038 assert ip.execution_count == before + 1
1035 1039
1036 1040
1037 1041 def test_run_cell_async():
1038 1042 loop = asyncio.get_event_loop()
1039 1043 ip.run_cell("import asyncio")
1040 1044 coro = ip.run_cell_async("await asyncio.sleep(0.01)\n5")
1041 1045 assert asyncio.iscoroutine(coro)
1042 1046 result = loop.run_until_complete(coro)
1043 1047 assert isinstance(result, interactiveshell.ExecutionResult)
1044 1048 assert result.result == 5
1045 1049
1046 1050
1047 1051 def test_should_run_async():
1048 1052 assert not ip.should_run_async("a = 5")
1049 1053 assert ip.should_run_async("await x")
1050 1054 assert ip.should_run_async("import asyncio; await asyncio.sleep(1)")
1051 1055
1052 1056
1053 1057 def test_set_custom_completer():
1054 1058 num_completers = len(ip.Completer.matchers)
1055 1059
1056 1060 def foo(*args, **kwargs):
1057 1061 return "I'm a completer!"
1058 1062
1059 1063 ip.set_custom_completer(foo, 0)
1060 1064
1061 1065 # check that we've really added a new completer
1062 1066 assert len(ip.Completer.matchers) == num_completers + 1
1063 1067
1064 1068 # check that the first completer is the function we defined
1065 1069 assert ip.Completer.matchers[0]() == "I'm a completer!"
1066 1070
1067 1071 # clean up
1068 1072 ip.Completer.custom_matchers.pop()
@@ -1,1341 +1,1366 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Tests for various magic functions.
3 3
4 4 Needs to be run by nose (to make ipython session available).
5 5 """
6 6
7 7 import asyncio
8 8 import io
9 9 import os
10 10 import re
11 11 import shlex
12 12 import sys
13 13 import warnings
14 14 from importlib import invalidate_caches
15 15 from io import StringIO
16 16 from pathlib import Path
17 17 from textwrap import dedent
18 18 from unittest import TestCase, mock
19 19
20 import nose.tools as nt
21
22 20 import pytest
23 21
24 22 from IPython import get_ipython
25 23 from IPython.core import magic
26 24 from IPython.core.error import UsageError
27 25 from IPython.core.magic import (
28 26 Magics,
29 27 cell_magic,
30 28 line_magic,
31 29 magics_class,
32 30 register_cell_magic,
33 31 register_line_magic,
34 32 )
35 33 from IPython.core.magics import code, execution, logging, osm, script
36 34 from IPython.testing import decorators as dec
37 35 from IPython.testing import tools as tt
38 36 from IPython.utils.io import capture_output
39 37 from IPython.utils.process import find_cmd
40 38 from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory
41 39
42 40 from .test_debugger import PdbTestInput
43 41
44 42
45 43 @magic.magics_class
46 44 class DummyMagics(magic.Magics): pass
47 45
48 46 def test_extract_code_ranges():
49 47 instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
50 expected = [(0, 1),
51 (2, 3),
52 (4, 6),
53 (6, 9),
54 (9, 14),
55 (16, None),
56 (None, 9),
57 (9, None),
58 (None, 13),
59 (None, None)]
48 expected = [
49 (0, 1),
50 (2, 3),
51 (4, 6),
52 (6, 9),
53 (9, 14),
54 (16, None),
55 (None, 9),
56 (9, None),
57 (None, 13),
58 (None, None),
59 ]
60 60 actual = list(code.extract_code_ranges(instr))
61 nt.assert_equal(actual, expected)
61 assert actual == expected
62 62
63 63 def test_extract_symbols():
64 64 source = """import foo\na = 10\ndef b():\n return 42\n\n\nclass A: pass\n\n\n"""
65 65 symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
66 66 expected = [([], ['a']),
67 67 (["def b():\n return 42\n"], []),
68 68 (["class A: pass\n"], []),
69 69 (["class A: pass\n", "def b():\n return 42\n"], []),
70 70 (["class A: pass\n"], ['a']),
71 71 ([], ['z'])]
72 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 76 def test_extract_symbols_raises_exception_with_non_python_code():
77 77 source = ("=begin A Ruby program :)=end\n"
78 78 "def hello\n"
79 79 "puts 'Hello world'\n"
80 80 "end")
81 with nt.assert_raises(SyntaxError):
81 with pytest.raises(SyntaxError):
82 82 code.extract_symbols(source, "hello")
83 83
84 84
85 85 def test_magic_not_found():
86 86 # magic not found raises UsageError
87 with nt.assert_raises(UsageError):
87 with pytest.raises(UsageError):
88 88 _ip.magic('doesntexist')
89 89
90 90 # ensure result isn't success when a magic isn't found
91 91 result = _ip.run_cell('%doesntexist')
92 92 assert isinstance(result.error_in_exec, UsageError)
93 93
94 94
95 95 def test_cell_magic_not_found():
96 96 # magic not found raises UsageError
97 with nt.assert_raises(UsageError):
97 with pytest.raises(UsageError):
98 98 _ip.run_cell_magic('doesntexist', 'line', 'cell')
99 99
100 100 # ensure result isn't success when a magic isn't found
101 101 result = _ip.run_cell('%%doesntexist')
102 102 assert isinstance(result.error_in_exec, UsageError)
103 103
104 104
105 105 def test_magic_error_status():
106 106 def fail(shell):
107 107 1/0
108 108 _ip.register_magic_function(fail)
109 109 result = _ip.run_cell('%fail')
110 110 assert isinstance(result.error_in_exec, ZeroDivisionError)
111 111
112 112
113 113 def test_config():
114 114 """ test that config magic does not raise
115 115 can happen if Configurable init is moved too early into
116 116 Magics.__init__ as then a Config object will be registered as a
117 117 magic.
118 118 """
119 119 ## should not raise.
120 120 _ip.magic('config')
121 121
122 122 def test_config_available_configs():
123 123 """ test that config magic prints available configs in unique and
124 124 sorted order. """
125 125 with capture_output() as captured:
126 126 _ip.magic('config')
127 127
128 128 stdout = captured.stdout
129 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 132 def test_config_print_class():
133 133 """ test that config with a classname prints the class's options. """
134 134 with capture_output() as captured:
135 135 _ip.magic('config TerminalInteractiveShell')
136 136
137 137 stdout = captured.stdout
138 138 if not re.match("TerminalInteractiveShell.* options", stdout.splitlines()[0]):
139 139 print(stdout)
140 140 raise AssertionError("1st line of stdout not like "
141 141 "'TerminalInteractiveShell.* options'")
142 142
143 143 def test_rehashx():
144 144 # clear up everything
145 145 _ip.alias_manager.clear_aliases()
146 146 del _ip.db['syscmdlist']
147
147
148 148 _ip.magic('rehashx')
149 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 152 for name, cmd in _ip.alias_manager.aliases:
153 153 # we must strip dots from alias names
154 nt.assert_not_in('.', name)
154 assert "." not in name
155 155
156 156 # rehashx must fill up syscmdlist
157 157 scoms = _ip.db['syscmdlist']
158 nt.assert_true(len(scoms) > 10)
159
158 assert len(scoms) > 10
160 159
161 160
162 161 def test_magic_parse_options():
163 162 """Test that we don't mangle paths when parsing magic options."""
164 163 ip = get_ipython()
165 164 path = 'c:\\x'
166 165 m = DummyMagics(ip)
167 166 opts = m.parse_options('-f %s' % path,'f:')[0]
168 167 # argv splitting is os-dependent
169 168 if os.name == 'posix':
170 169 expected = 'c:x'
171 170 else:
172 171 expected = path
173 nt.assert_equal(opts['f'], expected)
172 assert opts["f"] == expected
173
174 174
175 175 def test_magic_parse_long_options():
176 176 """Magic.parse_options can handle --foo=bar long options"""
177 177 ip = get_ipython()
178 178 m = DummyMagics(ip)
179 opts, _ = m.parse_options('--foo --bar=bubble', 'a', 'foo', 'bar=')
180 nt.assert_in('foo', opts)
181 nt.assert_in('bar', opts)
182 nt.assert_equal(opts['bar'], "bubble")
179 opts, _ = m.parse_options("--foo --bar=bubble", "a", "foo", "bar=")
180 assert "foo" in opts
181 assert "bar" in opts
182 assert opts["bar"] == "bubble"
183 183
184 184
185 185 def doctest_hist_f():
186 186 """Test %hist -f with temporary filename.
187 187
188 188 In [9]: import tempfile
189 189
190 190 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
191 191
192 192 In [11]: %hist -nl -f $tfile 3
193 193
194 194 In [13]: import os; os.unlink(tfile)
195 195 """
196 196
197 197
198 198 def doctest_hist_op():
199 199 """Test %hist -op
200 200
201 201 In [1]: class b(float):
202 202 ...: pass
203 ...:
203 ...:
204 204
205 205 In [2]: class s(object):
206 206 ...: def __str__(self):
207 207 ...: return 's'
208 ...:
208 ...:
209 209
210 In [3]:
210 In [3]:
211 211
212 212 In [4]: class r(b):
213 213 ...: def __repr__(self):
214 214 ...: return 'r'
215 ...:
215 ...:
216 216
217 217 In [5]: class sr(s,r): pass
218 ...:
218 ...:
219 219
220 In [6]:
220 In [6]:
221 221
222 222 In [7]: bb=b()
223 223
224 224 In [8]: ss=s()
225 225
226 226 In [9]: rr=r()
227 227
228 228 In [10]: ssrr=sr()
229 229
230 230 In [11]: 4.5
231 231 Out[11]: 4.5
232 232
233 233 In [12]: str(ss)
234 234 Out[12]: 's'
235 235
236 In [13]:
236 In [13]:
237 237
238 238 In [14]: %hist -op
239 239 >>> class b:
240 240 ... pass
241 ...
241 ...
242 242 >>> class s(b):
243 243 ... def __str__(self):
244 244 ... return 's'
245 ...
246 >>>
245 ...
246 >>>
247 247 >>> class r(b):
248 248 ... def __repr__(self):
249 249 ... return 'r'
250 ...
250 ...
251 251 >>> class sr(s,r): pass
252 >>>
252 >>>
253 253 >>> bb=b()
254 254 >>> ss=s()
255 255 >>> rr=r()
256 256 >>> ssrr=sr()
257 257 >>> 4.5
258 258 4.5
259 259 >>> str(ss)
260 260 's'
261 >>>
261 >>>
262 262 """
263 263
264 264 def test_hist_pof():
265 265 ip = get_ipython()
266 ip.run_cell(u"1+2", store_history=True)
266 ip.run_cell("1+2", store_history=True)
267 267 #raise Exception(ip.history_manager.session_number)
268 268 #raise Exception(list(ip.history_manager._get_range_session()))
269 269 with TemporaryDirectory() as td:
270 270 tf = os.path.join(td, 'hist.py')
271 271 ip.run_line_magic('history', '-pof %s' % tf)
272 272 assert os.path.isfile(tf)
273 273
274 274
275 275 def test_macro():
276 276 ip = get_ipython()
277 277 ip.history_manager.reset() # Clear any existing history.
278 278 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
279 279 for i, cmd in enumerate(cmds, start=1):
280 280 ip.history_manager.store_inputs(i, cmd)
281 281 ip.magic("macro test 1-3")
282 nt.assert_equal(ip.user_ns["test"].value, "\n".join(cmds)+"\n")
283
282 assert ip.user_ns["test"].value == "\n".join(cmds) + "\n"
283
284 284 # List macros
285 nt.assert_in("test", ip.magic("macro"))
285 assert "test" in ip.magic("macro")
286 286
287 287
288 288 def test_macro_run():
289 289 """Test that we can run a multi-line macro successfully."""
290 290 ip = get_ipython()
291 291 ip.history_manager.reset()
292 292 cmds = ["a=10", "a+=1", "print(a)", "%macro test 2-3"]
293 293 for cmd in cmds:
294 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 296 with tt.AssertPrints("12"):
297 297 ip.run_cell("test")
298 298 with tt.AssertPrints("13"):
299 299 ip.run_cell("test")
300 300
301 301
302 302 def test_magic_magic():
303 303 """Test %magic"""
304 304 ip = get_ipython()
305 305 with capture_output() as captured:
306 306 ip.magic("magic")
307
307
308 308 stdout = captured.stdout
309 nt.assert_in('%magic', stdout)
310 nt.assert_in('IPython', stdout)
311 nt.assert_in('Available', stdout)
309 assert "%magic" in stdout
310 assert "IPython" in stdout
311 assert "Available" in stdout
312 312
313 313
314 314 @dec.skipif_not_numpy
315 315 def test_numpy_reset_array_undec():
316 316 "Test '%reset array' functionality"
317 _ip.ex('import numpy as np')
318 _ip.ex('a = np.empty(2)')
319 nt.assert_in('a', _ip.user_ns)
320 _ip.magic('reset -f array')
321 nt.assert_not_in('a', _ip.user_ns)
317 _ip.ex("import numpy as np")
318 _ip.ex("a = np.empty(2)")
319 assert "a" in _ip.user_ns
320 _ip.magic("reset -f array")
321 assert "a" not in _ip.user_ns
322
322 323
323 324 def test_reset_out():
324 325 "Test '%reset out' magic"
325 326 _ip.run_cell("parrot = 'dead'", store_history=True)
326 327 # test '%reset -f out', make an Out prompt
327 328 _ip.run_cell("parrot", store_history=True)
328 nt.assert_true('dead' in [_ip.user_ns[x] for x in ('_','__','___')])
329 _ip.magic('reset -f out')
330 nt.assert_false('dead' in [_ip.user_ns[x] for x in ('_','__','___')])
331 nt.assert_equal(len(_ip.user_ns['Out']), 0)
329 assert "dead" in [_ip.user_ns[x] for x in ("_", "__", "___")]
330 _ip.magic("reset -f out")
331 assert "dead" not in [_ip.user_ns[x] for x in ("_", "__", "___")]
332 assert len(_ip.user_ns["Out"]) == 0
333
332 334
333 335 def test_reset_in():
334 336 "Test '%reset in' magic"
335 337 # test '%reset -f in'
336 338 _ip.run_cell("parrot", store_history=True)
337 nt.assert_true('parrot' in [_ip.user_ns[x] for x in ('_i','_ii','_iii')])
338 _ip.magic('%reset -f in')
339 nt.assert_false('parrot' in [_ip.user_ns[x] for x in ('_i','_ii','_iii')])
340 nt.assert_equal(len(set(_ip.user_ns['In'])), 1)
339 assert "parrot" in [_ip.user_ns[x] for x in ("_i", "_ii", "_iii")]
340 _ip.magic("%reset -f in")
341 assert "parrot" not in [_ip.user_ns[x] for x in ("_i", "_ii", "_iii")]
342 assert len(set(_ip.user_ns["In"])) == 1
343
341 344
342 345 def test_reset_dhist():
343 346 "Test '%reset dhist' magic"
344 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
345 _ip.magic('cd ' + os.path.dirname(nt.__file__))
346 _ip.magic('cd -')
347 nt.assert_true(len(_ip.user_ns['_dh']) > 0)
348 _ip.magic('reset -f dhist')
349 nt.assert_equal(len(_ip.user_ns['_dh']), 0)
350 _ip.run_cell("_dh = [d for d in tmp]") #restore
347 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
348 _ip.magic("cd " + os.path.dirname(pytest.__file__))
349 _ip.magic("cd -")
350 assert len(_ip.user_ns["_dh"]) > 0
351 _ip.magic("reset -f dhist")
352 assert len(_ip.user_ns["_dh"]) == 0
353 _ip.run_cell("_dh = [d for d in tmp]") # restore
354
351 355
352 356 def test_reset_in_length():
353 357 "Test that '%reset in' preserves In[] length"
354 358 _ip.run_cell("print 'foo'")
355 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 363 class TestResetErrors(TestCase):
359 364
360 365 def test_reset_redefine(self):
361 366
362 367 @magics_class
363 368 class KernelMagics(Magics):
364 369 @line_magic
365 370 def less(self, shell): pass
366 371
367 372 _ip.register_magics(KernelMagics)
368 373
369 374 with self.assertLogs() as cm:
370 375 # hack, we want to just capture logs, but assertLogs fails if not
371 376 # logs get produce.
372 377 # so log one things we ignore.
373 378 import logging as log_mod
374 379 log = log_mod.getLogger()
375 380 log.info('Nothing')
376 381 # end hack.
377 382 _ip.run_cell("reset -f")
378 383
379 384 assert len(cm.output) == 1
380 385 for out in cm.output:
381 386 assert "Invalid alias" not in out
382 387
383 388 def test_tb_syntaxerror():
384 389 """test %tb after a SyntaxError"""
385 390 ip = get_ipython()
386 391 ip.run_cell("for")
387
392
388 393 # trap and validate stdout
389 394 save_stdout = sys.stdout
390 395 try:
391 396 sys.stdout = StringIO()
392 397 ip.run_cell("%tb")
393 398 out = sys.stdout.getvalue()
394 399 finally:
395 400 sys.stdout = save_stdout
396 401 # trim output, and only check the last line
397 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 406 def test_time():
402 407 ip = get_ipython()
403
408
404 409 with tt.AssertPrints("Wall time: "):
405 410 ip.run_cell("%time None")
406
411
407 412 ip.run_cell("def f(kmjy):\n"
408 413 " %time print (2*kmjy)")
409
414
410 415 with tt.AssertPrints("Wall time: "):
411 416 with tt.AssertPrints("hihi", suppress=False):
412 417 ip.run_cell("f('hi')")
413 418
414 419 def test_time_last_not_expression():
415 420 ip.run_cell("%%time\n"
416 421 "var_1 = 1\n"
417 422 "var_2 = 2\n")
418 423 assert ip.user_ns['var_1'] == 1
419 424 del ip.user_ns['var_1']
420 425 assert ip.user_ns['var_2'] == 2
421 426 del ip.user_ns['var_2']
422
427
423 428
424 429 @dec.skip_win32
425 430 def test_time2():
426 431 ip = get_ipython()
427
432
428 433 with tt.AssertPrints("CPU times: user "):
429 434 ip.run_cell("%time None")
430 435
431 436 def test_time3():
432 437 """Erroneous magic function calls, issue gh-3334"""
433 438 ip = get_ipython()
434 439 ip.user_ns.pop('run', None)
435
440
436 441 with tt.AssertNotPrints("not found", channel='stderr'):
437 442 ip.run_cell("%%time\n"
438 443 "run = 0\n"
439 444 "run += 1")
440 445
441 446 def test_multiline_time():
442 447 """Make sure last statement from time return a value."""
443 448 ip = get_ipython()
444 449 ip.user_ns.pop('run', None)
445 450
446 451 ip.run_cell(dedent("""\
447 452 %%time
448 453 a = "ho"
449 454 b = "hey"
450 455 a+b
451 """))
452 nt.assert_equal(ip.user_ns_hidden['_'], 'hohey')
456 """
457 )
458 )
459 assert ip.user_ns_hidden["_"] == "hohey"
460
453 461
454 462 def test_time_local_ns():
455 463 """
456 464 Test that local_ns is actually global_ns when running a cell magic
457 465 """
458 466 ip = get_ipython()
459 ip.run_cell("%%time\n"
460 "myvar = 1")
461 nt.assert_equal(ip.user_ns['myvar'], 1)
462 del ip.user_ns['myvar']
467 ip.run_cell("%%time\n" "myvar = 1")
468 assert ip.user_ns["myvar"] == 1
469 del ip.user_ns["myvar"]
470
463 471
464 472 def test_doctest_mode():
465 473 "Toggle doctest_mode twice, it should be a no-op and run without error"
466 474 _ip.magic('doctest_mode')
467 475 _ip.magic('doctest_mode')
468 476
469 477
470 478 def test_parse_options():
471 479 """Tests for basic options parsing in magics."""
472 480 # These are only the most minimal of tests, more should be added later. At
473 481 # the very least we check that basic text/unicode calls work OK.
474 482 m = DummyMagics(_ip)
475 nt.assert_equal(m.parse_options('foo', '')[1], 'foo')
476 nt.assert_equal(m.parse_options(u'foo', '')[1], u'foo')
483 assert m.parse_options("foo", "")[1] == "foo"
484 assert m.parse_options("foo", "")[1] == "foo"
477 485
478 486
479 487 def test_parse_options_preserve_non_option_string():
480 488 """Test to assert preservation of non-option part of magic-block, while parsing magic options."""
481 489 m = DummyMagics(_ip)
482 490 opts, stmt = m.parse_options(
483 491 " -n1 -r 13 _ = 314 + foo", "n:r:", preserve_non_opts=True
484 492 )
485 nt.assert_equal(opts, {"n": "1", "r": "13"})
486 nt.assert_equal(stmt, "_ = 314 + foo")
493 assert opts == {"n": "1", "r": "13"}
494 assert stmt == "_ = 314 + foo"
487 495
488 496
489 497 def test_run_magic_preserve_code_block():
490 498 """Test to assert preservation of non-option part of magic-block, while running magic."""
491 499 _ip.user_ns["spaces"] = []
492 500 _ip.magic("timeit -n1 -r1 spaces.append([s.count(' ') for s in ['document']])")
493 501 assert _ip.user_ns["spaces"] == [[0]]
494 502
495 503
496 504 def test_dirops():
497 505 """Test various directory handling operations."""
498 506 # curpath = lambda :os.path.splitdrive(os.getcwd())[1].replace('\\','/')
499 507 curpath = os.getcwd
500 508 startdir = os.getcwd()
501 509 ipdir = os.path.realpath(_ip.ipython_dir)
502 510 try:
503 511 _ip.magic('cd "%s"' % ipdir)
504 nt.assert_equal(curpath(), ipdir)
512 assert curpath() == ipdir
505 513 _ip.magic('cd -')
506 nt.assert_equal(curpath(), startdir)
514 assert curpath() == startdir
507 515 _ip.magic('pushd "%s"' % ipdir)
508 nt.assert_equal(curpath(), ipdir)
516 assert curpath() == ipdir
509 517 _ip.magic('popd')
510 nt.assert_equal(curpath(), startdir)
518 assert curpath() == startdir
511 519 finally:
512 520 os.chdir(startdir)
513 521
514 522
515 523 def test_cd_force_quiet():
516 524 """Test OSMagics.cd_force_quiet option"""
517 525 _ip.config.OSMagics.cd_force_quiet = True
518 526 osmagics = osm.OSMagics(shell=_ip)
519 527
520 528 startdir = os.getcwd()
521 529 ipdir = os.path.realpath(_ip.ipython_dir)
522 530
523 531 try:
524 532 with tt.AssertNotPrints(ipdir):
525 533 osmagics.cd('"%s"' % ipdir)
526 534 with tt.AssertNotPrints(startdir):
527 535 osmagics.cd('-')
528 536 finally:
529 537 os.chdir(startdir)
530 538
531 539
532 540 def test_xmode():
533 541 # Calling xmode three times should be a no-op
534 542 xmode = _ip.InteractiveTB.mode
535 543 for i in range(4):
536 544 _ip.magic("xmode")
537 nt.assert_equal(_ip.InteractiveTB.mode, xmode)
538
545 assert _ip.InteractiveTB.mode == xmode
546
539 547 def test_reset_hard():
540 548 monitor = []
541 549 class A(object):
542 550 def __del__(self):
543 551 monitor.append(1)
544 552 def __repr__(self):
545 553 return "<A instance>"
546
554
547 555 _ip.user_ns["a"] = A()
548 556 _ip.run_cell("a")
549
550 nt.assert_equal(monitor, [])
557
558 assert monitor == []
551 559 _ip.magic("reset -f")
552 nt.assert_equal(monitor, [1])
553
560 assert monitor == [1]
561
554 562 class TestXdel(tt.TempFileMixin):
555 563 def test_xdel(self):
556 564 """Test that references from %run are cleared by xdel."""
557 565 src = ("class A(object):\n"
558 566 " monitor = []\n"
559 567 " def __del__(self):\n"
560 568 " self.monitor.append(1)\n"
561 569 "a = A()\n")
562 570 self.mktmp(src)
563 571 # %run creates some hidden references...
564 572 _ip.magic("run %s" % self.fname)
565 573 # ... as does the displayhook.
566 574 _ip.run_cell("a")
567
575
568 576 monitor = _ip.user_ns["A"].monitor
569 nt.assert_equal(monitor, [])
570
577 assert monitor == []
578
571 579 _ip.magic("xdel a")
572
580
573 581 # Check that a's __del__ method has been called.
574 nt.assert_equal(monitor, [1])
582 assert monitor == [1]
575 583
576 584 def doctest_who():
577 585 """doctest for %who
578
586
579 587 In [1]: %reset -f
580
588
581 589 In [2]: alpha = 123
582
590
583 591 In [3]: beta = 'beta'
584
592
585 593 In [4]: %who int
586 594 alpha
587
595
588 596 In [5]: %who str
589 597 beta
590
598
591 599 In [6]: %whos
592 600 Variable Type Data/Info
593 601 ----------------------------
594 602 alpha int 123
595 603 beta str beta
596
604
597 605 In [7]: %who_ls
598 606 Out[7]: ['alpha', 'beta']
599 607 """
600 608
601 609 def test_whos():
602 610 """Check that whos is protected against objects where repr() fails."""
603 611 class A(object):
604 612 def __repr__(self):
605 613 raise Exception()
606 614 _ip.user_ns['a'] = A()
607 615 _ip.magic("whos")
608 616
609 617 def doctest_precision():
610 618 """doctest for %precision
611
619
612 620 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
613
621
614 622 In [2]: %precision 5
615 623 Out[2]: '%.5f'
616
624
617 625 In [3]: f.float_format
618 626 Out[3]: '%.5f'
619
627
620 628 In [4]: %precision %e
621 629 Out[4]: '%e'
622
630
623 631 In [5]: f(3.1415927)
624 632 Out[5]: '3.141593e+00'
625 633 """
626 634
627 635 def test_debug_magic():
628 636 """Test debugging a small code with %debug
629
637
630 638 In [1]: with PdbTestInput(['c']):
631 639 ...: %debug print("a b") #doctest: +ELLIPSIS
632 640 ...:
633 641 ...
634 642 ipdb> c
635 643 a b
636 644 In [2]:
637 645 """
638 646
639 647 def test_psearch():
640 648 with tt.AssertPrints("dict.fromkeys"):
641 649 _ip.run_cell("dict.fr*?")
642 650 with tt.AssertPrints("π.is_integer"):
643 651 _ip.run_cell("π = 3.14;\nπ.is_integ*?")
644 652
645 653 def test_timeit_shlex():
646 654 """test shlex issues with timeit (#1109)"""
647 655 _ip.ex("def f(*a,**kw): pass")
648 656 _ip.magic('timeit -n1 "this is a bug".count(" ")')
649 657 _ip.magic('timeit -r1 -n1 f(" ", 1)')
650 658 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
651 659 _ip.magic('timeit -r1 -n1 ("a " + "b")')
652 660 _ip.magic('timeit -r1 -n1 f("a " + "b")')
653 661 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
654 662
655 663
656 664 def test_timeit_special_syntax():
657 665 "Test %%timeit with IPython special syntax"
658 666 @register_line_magic
659 667 def lmagic(line):
660 668 ip = get_ipython()
661 669 ip.user_ns['lmagic_out'] = line
662 670
663 671 # line mode test
664 _ip.run_line_magic('timeit', '-n1 -r1 %lmagic my line')
665 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
672 _ip.run_line_magic("timeit", "-n1 -r1 %lmagic my line")
673 assert _ip.user_ns["lmagic_out"] == "my line"
666 674 # cell mode test
667 _ip.run_cell_magic('timeit', '-n1 -r1', '%lmagic my line2')
668 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
675 _ip.run_cell_magic("timeit", "-n1 -r1", "%lmagic my line2")
676 assert _ip.user_ns["lmagic_out"] == "my line2"
677
669 678
670 679 def test_timeit_return():
671 680 """
672 681 test whether timeit -o return object
673 682 """
674 683
675 684 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
676 685 assert(res is not None)
677 686
678 687 def test_timeit_quiet():
679 688 """
680 689 test quiet option of timeit magic
681 690 """
682 691 with tt.AssertNotPrints("loops"):
683 692 _ip.run_cell("%timeit -n1 -r1 -q 1")
684 693
685 694 def test_timeit_return_quiet():
686 695 with tt.AssertNotPrints("loops"):
687 696 res = _ip.run_line_magic('timeit', '-n1 -r1 -q -o 1')
688 697 assert (res is not None)
689 698
690 699 def test_timeit_invalid_return():
691 with nt.assert_raises_regex(SyntaxError, "outside function"):
700 with pytest.raises(SyntaxError):
692 701 _ip.run_line_magic('timeit', 'return')
693 702
694 703 @dec.skipif(execution.profile is None)
695 704 def test_prun_special_syntax():
696 705 "Test %%prun with IPython special syntax"
697 706 @register_line_magic
698 707 def lmagic(line):
699 708 ip = get_ipython()
700 709 ip.user_ns['lmagic_out'] = line
701 710
702 711 # line mode test
703 _ip.run_line_magic('prun', '-q %lmagic my line')
704 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
712 _ip.run_line_magic("prun", "-q %lmagic my line")
713 assert _ip.user_ns["lmagic_out"] == "my line"
705 714 # cell mode test
706 _ip.run_cell_magic('prun', '-q', '%lmagic my line2')
707 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
715 _ip.run_cell_magic("prun", "-q", "%lmagic my line2")
716 assert _ip.user_ns["lmagic_out"] == "my line2"
717
708 718
709 719 @dec.skipif(execution.profile is None)
710 720 def test_prun_quotes():
711 721 "Test that prun does not clobber string escapes (GH #1302)"
712 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 726 def test_extension():
716 727 # Debugging information for failures of this test
717 728 print('sys.path:')
718 729 for p in sys.path:
719 730 print(' ', p)
720 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 734 daft_path = os.path.join(os.path.dirname(__file__), "daft_extension")
724 735 sys.path.insert(0, daft_path)
725 736 try:
726 737 _ip.user_ns.pop('arq', None)
727 738 invalidate_caches() # Clear import caches
728 739 _ip.magic("load_ext daft_extension")
729 nt.assert_equal(_ip.user_ns['arq'], 185)
740 assert _ip.user_ns["arq"] == 185
730 741 _ip.magic("unload_ext daft_extension")
731 742 assert 'arq' not in _ip.user_ns
732 743 finally:
733 744 sys.path.remove(daft_path)
734 745
735 746
736 747 def test_notebook_export_json():
737 748 _ip = get_ipython()
738 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 751 for i, cmd in enumerate(cmds, start=1):
741 752 _ip.history_manager.store_inputs(i, cmd)
742 753 with TemporaryDirectory() as td:
743 754 outfile = os.path.join(td, "nb.ipynb")
744 755 _ip.magic("notebook -e %s" % outfile)
745 756
746 757
747 758 class TestEnv(TestCase):
748 759
749 760 def test_env(self):
750 761 env = _ip.magic("env")
751 762 self.assertTrue(isinstance(env, dict))
752 763
753 764 def test_env_secret(self):
754 765 env = _ip.magic("env")
755 766 hidden = "<hidden>"
756 767 with mock.patch.dict(
757 768 os.environ,
758 769 {
759 770 "API_KEY": "abc123",
760 771 "SECRET_THING": "ssshhh",
761 772 "JUPYTER_TOKEN": "",
762 773 "VAR": "abc"
763 774 }
764 775 ):
765 776 env = _ip.magic("env")
766 777 assert env["API_KEY"] == hidden
767 778 assert env["SECRET_THING"] == hidden
768 779 assert env["JUPYTER_TOKEN"] == hidden
769 780 assert env["VAR"] == "abc"
770 781
771 782 def test_env_get_set_simple(self):
772 783 env = _ip.magic("env var val1")
773 784 self.assertEqual(env, None)
774 785 self.assertEqual(os.environ['var'], 'val1')
775 786 self.assertEqual(_ip.magic("env var"), 'val1')
776 787 env = _ip.magic("env var=val2")
777 788 self.assertEqual(env, None)
778 789 self.assertEqual(os.environ['var'], 'val2')
779 790
780 791 def test_env_get_set_complex(self):
781 792 env = _ip.magic("env var 'val1 '' 'val2")
782 793 self.assertEqual(env, None)
783 794 self.assertEqual(os.environ['var'], "'val1 '' 'val2")
784 795 self.assertEqual(_ip.magic("env var"), "'val1 '' 'val2")
785 796 env = _ip.magic('env var=val2 val3="val4')
786 797 self.assertEqual(env, None)
787 798 self.assertEqual(os.environ['var'], 'val2 val3="val4')
788 799
789 800 def test_env_set_bad_input(self):
790 801 self.assertRaises(UsageError, lambda: _ip.magic("set_env var"))
791 802
792 803 def test_env_set_whitespace(self):
793 804 self.assertRaises(UsageError, lambda: _ip.magic("env var A=B"))
794 805
795 806
796 807 class CellMagicTestCase(TestCase):
797 808
798 809 def check_ident(self, magic):
799 810 # Manually called, we get the result
800 out = _ip.run_cell_magic(magic, 'a', 'b')
801 nt.assert_equal(out, ('a','b'))
811 out = _ip.run_cell_magic(magic, "a", "b")
812 assert out == ("a", "b")
802 813 # Via run_cell, it goes into the user's namespace via displayhook
803 _ip.run_cell('%%' + magic +' c\nd\n')
804 nt.assert_equal(_ip.user_ns['_'], ('c','d\n'))
814 _ip.run_cell("%%" + magic + " c\nd\n")
815 assert _ip.user_ns["_"] == ("c", "d\n")
805 816
806 817 def test_cell_magic_func_deco(self):
807 818 "Cell magic using simple decorator"
808 819 @register_cell_magic
809 820 def cellm(line, cell):
810 821 return line, cell
811 822
812 823 self.check_ident('cellm')
813 824
814 825 def test_cell_magic_reg(self):
815 826 "Cell magic manually registered"
816 827 def cellm(line, cell):
817 828 return line, cell
818 829
819 830 _ip.register_magic_function(cellm, 'cell', 'cellm2')
820 831 self.check_ident('cellm2')
821 832
822 833 def test_cell_magic_class(self):
823 834 "Cell magics declared via a class"
824 835 @magics_class
825 836 class MyMagics(Magics):
826 837
827 838 @cell_magic
828 839 def cellm3(self, line, cell):
829 840 return line, cell
830 841
831 842 _ip.register_magics(MyMagics)
832 843 self.check_ident('cellm3')
833 844
834 845 def test_cell_magic_class2(self):
835 846 "Cell magics declared via a class, #2"
836 847 @magics_class
837 848 class MyMagics2(Magics):
838 849
839 850 @cell_magic('cellm4')
840 851 def cellm33(self, line, cell):
841 852 return line, cell
842
853
843 854 _ip.register_magics(MyMagics2)
844 855 self.check_ident('cellm4')
845 856 # Check that nothing is registered as 'cellm33'
846 857 c33 = _ip.find_cell_magic('cellm33')
847 nt.assert_equal(c33, None)
858 assert c33 == None
848 859
849 860 def test_file():
850 861 """Basic %%writefile"""
851 862 ip = get_ipython()
852 863 with TemporaryDirectory() as td:
853 864 fname = os.path.join(td, 'file1')
854 865 ip.run_cell_magic("writefile", fname, u'\n'.join([
855 866 'line1',
856 867 'line2',
857 868 ]))
858 869 s = Path(fname).read_text()
859 nt.assert_in('line1\n', s)
860 nt.assert_in('line2', s)
870 assert "line1\n" in s
871 assert "line2" in s
872
861 873
862 874 @dec.skip_win32
863 875 def test_file_single_quote():
864 876 """Basic %%writefile with embedded single quotes"""
865 877 ip = get_ipython()
866 878 with TemporaryDirectory() as td:
867 879 fname = os.path.join(td, '\'file1\'')
868 880 ip.run_cell_magic("writefile", fname, u'\n'.join([
869 881 'line1',
870 882 'line2',
871 883 ]))
872 884 s = Path(fname).read_text()
873 nt.assert_in('line1\n', s)
874 nt.assert_in('line2', s)
885 assert "line1\n" in s
886 assert "line2" in s
887
875 888
876 889 @dec.skip_win32
877 890 def test_file_double_quote():
878 891 """Basic %%writefile with embedded double quotes"""
879 892 ip = get_ipython()
880 893 with TemporaryDirectory() as td:
881 894 fname = os.path.join(td, '"file1"')
882 895 ip.run_cell_magic("writefile", fname, u'\n'.join([
883 896 'line1',
884 897 'line2',
885 898 ]))
886 899 s = Path(fname).read_text()
887 nt.assert_in('line1\n', s)
888 nt.assert_in('line2', s)
900 assert "line1\n" in s
901 assert "line2" in s
902
889 903
890 904 def test_file_var_expand():
891 905 """%%writefile $filename"""
892 906 ip = get_ipython()
893 907 with TemporaryDirectory() as td:
894 908 fname = os.path.join(td, 'file1')
895 909 ip.user_ns['filename'] = fname
896 910 ip.run_cell_magic("writefile", '$filename', u'\n'.join([
897 911 'line1',
898 912 'line2',
899 913 ]))
900 914 s = Path(fname).read_text()
901 nt.assert_in('line1\n', s)
902 nt.assert_in('line2', s)
915 assert "line1\n" in s
916 assert "line2" in s
917
903 918
904 919 def test_file_unicode():
905 920 """%%writefile with unicode cell"""
906 921 ip = get_ipython()
907 922 with TemporaryDirectory() as td:
908 923 fname = os.path.join(td, 'file1')
909 924 ip.run_cell_magic("writefile", fname, u'\n'.join([
910 925 u'liné1',
911 926 u'liné2',
912 927 ]))
913 928 with io.open(fname, encoding='utf-8') as f:
914 929 s = f.read()
915 nt.assert_in(u'liné1\n', s)
916 nt.assert_in(u'liné2', s)
930 assert "liné1\n" in s
931 assert "liné2" in s
932
917 933
918 934 def test_file_amend():
919 935 """%%writefile -a amends files"""
920 936 ip = get_ipython()
921 937 with TemporaryDirectory() as td:
922 938 fname = os.path.join(td, 'file2')
923 939 ip.run_cell_magic("writefile", fname, u'\n'.join([
924 940 'line1',
925 941 'line2',
926 942 ]))
927 943 ip.run_cell_magic("writefile", "-a %s" % fname, u'\n'.join([
928 944 'line3',
929 945 'line4',
930 946 ]))
931 947 s = Path(fname).read_text()
932 nt.assert_in('line1\n', s)
933 nt.assert_in('line3\n', s)
948 assert "line1\n" in s
949 assert "line3\n" in s
950
934 951
935 952 def test_file_spaces():
936 953 """%%file with spaces in filename"""
937 954 ip = get_ipython()
938 955 with TemporaryWorkingDirectory() as td:
939 956 fname = "file name"
940 957 ip.run_cell_magic("file", '"%s"'%fname, u'\n'.join([
941 958 'line1',
942 959 'line2',
943 960 ]))
944 961 s = Path(fname).read_text()
945 nt.assert_in('line1\n', s)
946 nt.assert_in('line2', s)
947
962 assert "line1\n" in s
963 assert "line2" in s
964
965
948 966 def test_script_config():
949 967 ip = get_ipython()
950 968 ip.config.ScriptMagics.script_magics = ['whoda']
951 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 973 @dec.skip_iptest_but_not_pytest
955 974 @dec.skip_win32
956 975 @pytest.mark.skipif(
957 976 sys.platform == "win32", reason="This test does not run under Windows"
958 977 )
959 978 def test_script_out():
960 979 assert asyncio.get_event_loop().is_running() is False
961 980
962 981 ip = get_ipython()
963 982 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
964 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 987 @dec.skip_iptest_but_not_pytest
968 988 @dec.skip_win32
969 989 @pytest.mark.skipif(
970 990 sys.platform == "win32", reason="This test does not run under Windows"
971 991 )
972 992 def test_script_err():
973 993 ip = get_ipython()
974 994 assert asyncio.get_event_loop().is_running() is False
975 995 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
976 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 1000 @dec.skip_iptest_but_not_pytest
981 1001 @dec.skip_win32
982 1002 @pytest.mark.skipif(
983 1003 sys.platform == "win32", reason="This test does not run under Windows"
984 1004 )
985 1005 def test_script_out_err():
986 1006
987 1007 ip = get_ipython()
988 1008 ip.run_cell_magic(
989 1009 "script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2"
990 1010 )
991 nt.assert_equal(ip.user_ns["output"], "hi\n")
992 nt.assert_equal(ip.user_ns["error"], "hello\n")
1011 assert ip.user_ns["output"] == "hi\n"
1012 assert ip.user_ns["error"] == "hello\n"
993 1013
994 1014
995 1015 @dec.skip_iptest_but_not_pytest
996 1016 @dec.skip_win32
997 1017 @pytest.mark.skipif(
998 1018 sys.platform == "win32", reason="This test does not run under Windows"
999 1019 )
1000 1020 async def test_script_bg_out():
1001 1021 ip = get_ipython()
1002 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 1024 ip.user_ns["output"].close()
1005 1025 asyncio.get_event_loop().stop()
1006 1026
1027
1007 1028 @dec.skip_iptest_but_not_pytest
1008 1029 @dec.skip_win32
1009 1030 @pytest.mark.skipif(
1010 1031 sys.platform == "win32", reason="This test does not run under Windows"
1011 1032 )
1012 1033 async def test_script_bg_err():
1013 1034 ip = get_ipython()
1014 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 1037 ip.user_ns["error"].close()
1017 1038
1018 1039
1019 1040 @dec.skip_iptest_but_not_pytest
1020 1041 @dec.skip_win32
1021 1042 @pytest.mark.skipif(
1022 1043 sys.platform == "win32", reason="This test does not run under Windows"
1023 1044 )
1024 1045 async def test_script_bg_out_err():
1025 1046 ip = get_ipython()
1026 1047 ip.run_cell_magic(
1027 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")
1030 nt.assert_equal((await ip.user_ns["error"].read()), b"hello\n")
1050 assert (await ip.user_ns["output"].read()) == b"hi\n"
1051 assert (await ip.user_ns["error"].read()) == b"hello\n"
1031 1052 ip.user_ns["output"].close()
1032 1053 ip.user_ns["error"].close()
1033 1054
1034 1055
1035 1056 def test_script_defaults():
1036 1057 ip = get_ipython()
1037 1058 for cmd in ['sh', 'bash', 'perl', 'ruby']:
1038 1059 try:
1039 1060 find_cmd(cmd)
1040 1061 except Exception:
1041 1062 pass
1042 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 1067 @magics_class
1047 1068 class FooFoo(Magics):
1048 1069 """class with both %foo and %%foo magics"""
1049 1070 @line_magic('foo')
1050 1071 def line_foo(self, line):
1051 1072 "I am line foo"
1052 1073 pass
1053 1074
1054 1075 @cell_magic("foo")
1055 1076 def cell_foo(self, line, cell):
1056 1077 "I am cell foo, not line foo"
1057 1078 pass
1058 1079
1059 1080 def test_line_cell_info():
1060 1081 """%%foo and %foo magics are distinguishable to inspect"""
1061 1082 ip = get_ipython()
1062 1083 ip.magics_manager.register(FooFoo)
1063 oinfo = ip.object_inspect('foo')
1064 nt.assert_true(oinfo['found'])
1065 nt.assert_true(oinfo['ismagic'])
1066
1067 oinfo = ip.object_inspect('%%foo')
1068 nt.assert_true(oinfo['found'])
1069 nt.assert_true(oinfo['ismagic'])
1070 nt.assert_equal(oinfo['docstring'], FooFoo.cell_foo.__doc__)
1071
1072 oinfo = ip.object_inspect('%foo')
1073 nt.assert_true(oinfo['found'])
1074 nt.assert_true(oinfo['ismagic'])
1075 nt.assert_equal(oinfo['docstring'], FooFoo.line_foo.__doc__)
1084 oinfo = ip.object_inspect("foo")
1085 assert oinfo["found"] is True
1086 assert oinfo["ismagic"] is True
1087
1088 oinfo = ip.object_inspect("%%foo")
1089 assert oinfo["found"] is True
1090 assert oinfo["ismagic"] is True
1091 assert oinfo["docstring"] == FooFoo.cell_foo.__doc__
1092
1093 oinfo = ip.object_inspect("%foo")
1094 assert oinfo["found"] is True
1095 assert oinfo["ismagic"] is True
1096 assert oinfo["docstring"] == FooFoo.line_foo.__doc__
1097
1076 1098
1077 1099 def test_multiple_magics():
1078 1100 ip = get_ipython()
1079 1101 foo1 = FooFoo(ip)
1080 1102 foo2 = FooFoo(ip)
1081 1103 mm = ip.magics_manager
1082 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 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 1110 def test_alias_magic():
1088 1111 """Test %alias_magic."""
1089 1112 ip = get_ipython()
1090 1113 mm = ip.magics_manager
1091 1114
1092 1115 # Basic operation: both cell and line magics are created, if possible.
1093 ip.run_line_magic('alias_magic', 'timeit_alias timeit')
1094 nt.assert_in('timeit_alias', mm.magics['line'])
1095 nt.assert_in('timeit_alias', mm.magics['cell'])
1116 ip.run_line_magic("alias_magic", "timeit_alias timeit")
1117 assert "timeit_alias" in mm.magics["line"]
1118 assert "timeit_alias" in mm.magics["cell"]
1096 1119
1097 1120 # --cell is specified, line magic not created.
1098 ip.run_line_magic('alias_magic', '--cell timeit_cell_alias timeit')
1099 nt.assert_not_in('timeit_cell_alias', mm.magics['line'])
1100 nt.assert_in('timeit_cell_alias', mm.magics['cell'])
1121 ip.run_line_magic("alias_magic", "--cell timeit_cell_alias timeit")
1122 assert "timeit_cell_alias" not in mm.magics["line"]
1123 assert "timeit_cell_alias" in mm.magics["cell"]
1101 1124
1102 1125 # Test that line alias is created successfully.
1103 ip.run_line_magic('alias_magic', '--line env_alias env')
1104 nt.assert_equal(ip.run_line_magic('env', ''),
1105 ip.run_line_magic('env_alias', ''))
1126 ip.run_line_magic("alias_magic", "--line env_alias env")
1127 assert ip.run_line_magic("env", "") == ip.run_line_magic("env_alias", "")
1106 1128
1107 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'))
1109 nt.assert_in('history_alias', mm.magics['line'])
1130 ip.run_line_magic(
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 1136 def test_save():
1113 1137 """Test %save."""
1114 1138 ip = get_ipython()
1115 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 1141 for i, cmd in enumerate(cmds, start=1):
1118 1142 ip.history_manager.store_inputs(i, cmd)
1119 1143 with TemporaryDirectory() as tmpdir:
1120 1144 file = os.path.join(tmpdir, "testsave.py")
1121 1145 ip.run_line_magic("save", "%s 1-10" % file)
1122 1146 content = Path(file).read_text()
1123 nt.assert_equal(content.count(cmds[0]), 1)
1124 nt.assert_in("coding: utf-8", content)
1147 assert content.count(cmds[0]) == 1
1148 assert "coding: utf-8" in content
1125 1149 ip.run_line_magic("save", "-a %s 1-10" % file)
1126 1150 content = Path(file).read_text()
1127 nt.assert_equal(content.count(cmds[0]), 2)
1128 nt.assert_in("coding: utf-8", content)
1151 assert content.count(cmds[0]) == 2
1152 assert "coding: utf-8" in content
1129 1153
1130 1154
1131 1155 def test_save_with_no_args():
1132 1156 ip = get_ipython()
1133 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 1159 for i, cmd in enumerate(cmds, start=1):
1136 1160 ip.history_manager.store_inputs(i, cmd)
1137 1161
1138 1162 with TemporaryDirectory() as tmpdir:
1139 1163 path = os.path.join(tmpdir, "testsave.py")
1140 1164 ip.run_line_magic("save", path)
1141 1165 content = Path(path).read_text()
1142 1166 expected_content = dedent(
1143 1167 """\
1144 1168 # coding: utf-8
1145 1169 a=1
1146 1170 def b():
1147 1171 return a**2
1148 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 1178 def test_store():
1155 1179 """Test %store."""
1156 1180 ip = get_ipython()
1157 1181 ip.run_line_magic('load_ext', 'storemagic')
1158
1182
1159 1183 # make sure the storage is empty
1160 ip.run_line_magic('store', '-z')
1161 ip.user_ns['var'] = 42
1162 ip.run_line_magic('store', 'var')
1163 ip.user_ns['var'] = 39
1164 ip.run_line_magic('store', '-r')
1165 nt.assert_equal(ip.user_ns['var'], 42)
1184 ip.run_line_magic("store", "-z")
1185 ip.user_ns["var"] = 42
1186 ip.run_line_magic("store", "var")
1187 ip.user_ns["var"] = 39
1188 ip.run_line_magic("store", "-r")
1189 assert ip.user_ns["var"] == 42
1166 1190
1167 ip.run_line_magic('store', '-d var')
1168 ip.user_ns['var'] = 39
1169 ip.run_line_magic('store' , '-r')
1170 nt.assert_equal(ip.user_ns['var'], 39)
1191 ip.run_line_magic("store", "-d var")
1192 ip.user_ns["var"] = 39
1193 ip.run_line_magic("store", "-r")
1194 assert ip.user_ns["var"] == 39
1171 1195
1172 1196
1173 1197 def _run_edit_test(arg_s, exp_filename=None,
1174 1198 exp_lineno=-1,
1175 1199 exp_contents=None,
1176 1200 exp_is_temp=None):
1177 1201 ip = get_ipython()
1178 1202 M = code.CodeMagics(ip)
1179 1203 last_call = ['','']
1180 1204 opts,args = M.parse_options(arg_s,'prxn:')
1181 1205 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
1182
1206
1183 1207 if exp_filename is not None:
1184 nt.assert_equal(exp_filename, filename)
1208 assert exp_filename == filename
1185 1209 if exp_contents is not None:
1186 1210 with io.open(filename, 'r', encoding='utf-8') as f:
1187 1211 contents = f.read()
1188 nt.assert_equal(exp_contents, contents)
1212 assert exp_contents == contents
1189 1213 if exp_lineno != -1:
1190 nt.assert_equal(exp_lineno, lineno)
1214 assert exp_lineno == lineno
1191 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 1219 def test_edit_interactive():
1196 1220 """%edit on interactively defined objects"""
1197 1221 ip = get_ipython()
1198 1222 n = ip.execution_count
1199 ip.run_cell(u"def foo(): return 1", store_history=True)
1200
1223 ip.run_cell("def foo(): return 1", store_history=True)
1224
1201 1225 try:
1202 1226 _run_edit_test("foo")
1203 1227 except code.InteractivelyDefined as e:
1204 nt.assert_equal(e.index, n)
1228 assert e.index == n
1205 1229 else:
1206 1230 raise AssertionError("Should have raised InteractivelyDefined")
1207 1231
1208 1232
1209 1233 def test_edit_cell():
1210 1234 """%edit [cell id]"""
1211 1235 ip = get_ipython()
1212
1213 ip.run_cell(u"def foo(): return 1", store_history=True)
1214
1236
1237 ip.run_cell("def foo(): return 1", store_history=True)
1238
1215 1239 # test
1216 1240 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
1217 1241
1218 1242 def test_edit_fname():
1219 1243 """%edit file"""
1220 1244 # test
1221 1245 _run_edit_test("test file.py", exp_filename="test file.py")
1222 1246
1223 1247 def test_bookmark():
1224 1248 ip = get_ipython()
1225 1249 ip.run_line_magic('bookmark', 'bmname')
1226 1250 with tt.AssertPrints('bmname'):
1227 1251 ip.run_line_magic('bookmark', '-l')
1228 1252 ip.run_line_magic('bookmark', '-d bmname')
1229 1253
1230 1254 def test_ls_magic():
1231 1255 ip = get_ipython()
1232 1256 json_formatter = ip.display_formatter.formatters['application/json']
1233 1257 json_formatter.enabled = True
1234 1258 lsmagic = ip.magic('lsmagic')
1235 1259 with warnings.catch_warnings(record=True) as w:
1236 1260 j = json_formatter(lsmagic)
1237 nt.assert_equal(sorted(j), ['cell', 'line'])
1238 nt.assert_equal(w, []) # no warnings
1261 assert sorted(j) == ["cell", "line"]
1262 assert w == [] # no warnings
1263
1239 1264
1240 1265 def test_strip_initial_indent():
1241 1266 def sii(s):
1242 1267 lines = s.splitlines()
1243 1268 return '\n'.join(code.strip_initial_indent(lines))
1244 1269
1245 nt.assert_equal(sii(" a = 1\nb = 2"), "a = 1\nb = 2")
1246 nt.assert_equal(sii(" a\n b\nc"), "a\n b\nc")
1247 nt.assert_equal(sii("a\n b"), "a\n b")
1270 assert sii(" a = 1\nb = 2") == "a = 1\nb = 2"
1271 assert sii(" a\n b\nc") == "a\n b\nc"
1272 assert sii("a\n b") == "a\n b"
1248 1273
1249 1274 def test_logging_magic_quiet_from_arg():
1250 1275 _ip.config.LoggingMagics.quiet = False
1251 1276 lm = logging.LoggingMagics(shell=_ip)
1252 1277 with TemporaryDirectory() as td:
1253 1278 try:
1254 1279 with tt.AssertNotPrints(re.compile("Activating.*")):
1255 1280 lm.logstart('-q {}'.format(
1256 1281 os.path.join(td, "quiet_from_arg.log")))
1257 1282 finally:
1258 1283 _ip.logger.logstop()
1259 1284
1260 1285 def test_logging_magic_quiet_from_config():
1261 1286 _ip.config.LoggingMagics.quiet = True
1262 1287 lm = logging.LoggingMagics(shell=_ip)
1263 1288 with TemporaryDirectory() as td:
1264 1289 try:
1265 1290 with tt.AssertNotPrints(re.compile("Activating.*")):
1266 1291 lm.logstart(os.path.join(td, "quiet_from_config.log"))
1267 1292 finally:
1268 1293 _ip.logger.logstop()
1269 1294
1270 1295
1271 1296 def test_logging_magic_not_quiet():
1272 1297 _ip.config.LoggingMagics.quiet = False
1273 1298 lm = logging.LoggingMagics(shell=_ip)
1274 1299 with TemporaryDirectory() as td:
1275 1300 try:
1276 1301 with tt.AssertPrints(re.compile("Activating.*")):
1277 1302 lm.logstart(os.path.join(td, "not_quiet.log"))
1278 1303 finally:
1279 1304 _ip.logger.logstop()
1280 1305
1281 1306
1282 1307 def test_time_no_var_expand():
1283 1308 _ip.user_ns['a'] = 5
1284 1309 _ip.user_ns['b'] = []
1285 1310 _ip.magic('time b.append("{a}")')
1286 1311 assert _ip.user_ns['b'] == ['{a}']
1287 1312
1288 1313
1289 1314 # this is slow, put at the end for local testing.
1290 1315 def test_timeit_arguments():
1291 1316 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
1292 1317 if sys.version_info < (3,7):
1293 1318 _ip.magic("timeit -n1 -r1 ('#')")
1294 1319 else:
1295 1320 # 3.7 optimize no-op statement like above out, and complain there is
1296 1321 # nothing in the for loop.
1297 1322 _ip.magic("timeit -n1 -r1 a=('#')")
1298 1323
1299 1324
1300 1325 TEST_MODULE = """
1301 1326 print('Loaded my_tmp')
1302 1327 if __name__ == "__main__":
1303 1328 print('I just ran a script')
1304 1329 """
1305 1330
1306 1331
1307 1332 def test_run_module_from_import_hook():
1308 1333 "Test that a module can be loaded via an import hook"
1309 1334 with TemporaryDirectory() as tmpdir:
1310 1335 fullpath = os.path.join(tmpdir, 'my_tmp.py')
1311 1336 Path(fullpath).write_text(TEST_MODULE)
1312 1337
1313 1338 class MyTempImporter(object):
1314 1339 def __init__(self):
1315 1340 pass
1316 1341
1317 1342 def find_module(self, fullname, path=None):
1318 1343 if 'my_tmp' in fullname:
1319 1344 return self
1320 1345 return None
1321 1346
1322 1347 def load_module(self, name):
1323 1348 import imp
1324 1349 return imp.load_source('my_tmp', fullpath)
1325 1350
1326 1351 def get_code(self, fullname):
1327 1352 return compile(Path(fullpath).read_text(), "foo", "exec")
1328 1353
1329 1354 def is_package(self, __):
1330 1355 return False
1331 1356
1332 1357 sys.meta_path.insert(0, MyTempImporter())
1333 1358
1334 1359 with capture_output() as captured:
1335 1360 _ip.magic("run -m my_tmp")
1336 1361 _ip.run_cell("import my_tmp")
1337 1362
1338 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 1366 sys.meta_path.pop(0)
@@ -1,192 +1,193 b''
1 1 """Tests for various magic functions specific to the terminal frontend.
2 2
3 3 Needs to be run by nose (to make ipython session available).
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 7 # Imports
8 8 #-----------------------------------------------------------------------------
9 9
10 10 import sys
11 11 from io import StringIO
12 12 from unittest import TestCase
13 13
14 import nose.tools as nt
15
16 14 from IPython.testing import tools as tt
17 15
18 16 #-----------------------------------------------------------------------------
19 17 # Test functions begin
20 18 #-----------------------------------------------------------------------------
21 19
22 20 def check_cpaste(code, should_fail=False):
23 21 """Execute code via 'cpaste' and ensure it was executed, unless
24 22 should_fail is set.
25 23 """
26 24 ip.user_ns['code_ran'] = False
27 25
28 26 src = StringIO()
29 27 if not hasattr(src, 'encoding'):
30 28 # IPython expects stdin to have an encoding attribute
31 29 src.encoding = None
32 30 src.write(code)
33 31 src.write('\n--\n')
34 32 src.seek(0)
35 33
36 34 stdin_save = sys.stdin
37 35 sys.stdin = src
38 36
39 37 try:
40 38 context = tt.AssertPrints if should_fail else tt.AssertNotPrints
41 39 with context("Traceback (most recent call last)"):
42 40 ip.magic('cpaste')
43 41
44 42 if not should_fail:
45 43 assert ip.user_ns['code_ran'], "%r failed" % code
46 44 finally:
47 45 sys.stdin = stdin_save
48 46
49 47 def test_cpaste():
50 48 """Test cpaste magic"""
51 49
52 50 def runf():
53 51 """Marker function: sets a flag when executed.
54 52 """
55 53 ip.user_ns['code_ran'] = True
56 54 return 'runf' # return string so '+ runf()' doesn't result in success
57 55
58 56 tests = {'pass': ["runf()",
59 57 "In [1]: runf()",
60 58 "In [1]: if 1:\n ...: runf()",
61 59 "> > > runf()",
62 60 ">>> runf()",
63 61 " >>> runf()",
64 62 ],
65 63
66 64 'fail': ["1 + runf()",
67 65 "++ runf()",
68 66 ]}
69 67
70 68 ip.user_ns['runf'] = runf
71 69
72 70 for code in tests['pass']:
73 71 check_cpaste(code)
74 72
75 73 for code in tests['fail']:
76 74 check_cpaste(code, should_fail=True)
77 75
78 76
79 77 class PasteTestCase(TestCase):
80 78 """Multiple tests for clipboard pasting"""
81 79
82 80 def paste(self, txt, flags='-q'):
83 81 """Paste input text, by default in quiet mode"""
84 82 ip.hooks.clipboard_get = lambda : txt
85 83 ip.magic('paste '+flags)
86 84
87 85 def setUp(self):
88 86 # Inject fake clipboard hook but save original so we can restore it later
89 87 self.original_clip = ip.hooks.clipboard_get
90 88
91 89 def tearDown(self):
92 90 # Restore original hook
93 91 ip.hooks.clipboard_get = self.original_clip
94 92
95 93 def test_paste(self):
96 ip.user_ns.pop('x', None)
97 self.paste('x = 1')
98 nt.assert_equal(ip.user_ns['x'], 1)
99 ip.user_ns.pop('x')
94 ip.user_ns.pop("x", None)
95 self.paste("x = 1")
96 self.assertEqual(ip.user_ns["x"], 1)
97 ip.user_ns.pop("x")
100 98
101 99 def test_paste_pyprompt(self):
102 ip.user_ns.pop('x', None)
103 self.paste('>>> x=2')
104 nt.assert_equal(ip.user_ns['x'], 2)
105 ip.user_ns.pop('x')
100 ip.user_ns.pop("x", None)
101 self.paste(">>> x=2")
102 self.assertEqual(ip.user_ns["x"], 2)
103 ip.user_ns.pop("x")
106 104
107 105 def test_paste_py_multi(self):
108 106 self.paste("""
109 107 >>> x = [1,2,3]
110 108 >>> y = []
111 109 >>> for i in x:
112 110 ... y.append(i**2)
113 111 ...
114 """)
115 nt.assert_equal(ip.user_ns['x'], [1,2,3])
116 nt.assert_equal(ip.user_ns['y'], [1,4,9])
112 """
113 )
114 self.assertEqual(ip.user_ns["x"], [1, 2, 3])
115 self.assertEqual(ip.user_ns["y"], [1, 4, 9])
117 116
118 117 def test_paste_py_multi_r(self):
119 118 "Now, test that self.paste -r works"
120 119 self.test_paste_py_multi()
121 nt.assert_equal(ip.user_ns.pop('x'), [1,2,3])
122 nt.assert_equal(ip.user_ns.pop('y'), [1,4,9])
123 nt.assert_false('x' in ip.user_ns)
124 ip.magic('paste -r')
125 nt.assert_equal(ip.user_ns['x'], [1,2,3])
126 nt.assert_equal(ip.user_ns['y'], [1,4,9])
120 self.assertEqual(ip.user_ns.pop("x"), [1, 2, 3])
121 self.assertEqual(ip.user_ns.pop("y"), [1, 4, 9])
122 self.assertFalse("x" in ip.user_ns)
123 ip.magic("paste -r")
124 self.assertEqual(ip.user_ns["x"], [1, 2, 3])
125 self.assertEqual(ip.user_ns["y"], [1, 4, 9])
127 126
128 127 def test_paste_email(self):
129 128 "Test pasting of email-quoted contents"
130 129 self.paste("""\
131 130 >> def foo(x):
132 131 >> return x + 1
133 >> xx = foo(1.1)""")
134 nt.assert_equal(ip.user_ns['xx'], 2.1)
132 >> xx = foo(1.1)"""
133 )
134 self.assertEqual(ip.user_ns["xx"], 2.1)
135 135
136 136 def test_paste_email2(self):
137 137 "Email again; some programs add a space also at each quoting level"
138 138 self.paste("""\
139 139 > > def foo(x):
140 140 > > return x + 1
141 > > yy = foo(2.1) """)
142 nt.assert_equal(ip.user_ns['yy'], 3.1)
141 > > yy = foo(2.1) """
142 )
143 self.assertEqual(ip.user_ns["yy"], 3.1)
143 144
144 145 def test_paste_email_py(self):
145 146 "Email quoting of interactive input"
146 147 self.paste("""\
147 148 >> >>> def f(x):
148 149 >> ... return x+1
149 150 >> ...
150 >> >>> zz = f(2.5) """)
151 nt.assert_equal(ip.user_ns['zz'], 3.5)
151 >> >>> zz = f(2.5) """
152 )
153 self.assertEqual(ip.user_ns["zz"], 3.5)
152 154
153 155 def test_paste_echo(self):
154 156 "Also test self.paste echoing, by temporarily faking the writer"
155 157 w = StringIO()
156 158 writer = ip.write
157 159 ip.write = w.write
158 160 code = """
159 161 a = 100
160 162 b = 200"""
161 163 try:
162 164 self.paste(code,'')
163 165 out = w.getvalue()
164 166 finally:
165 167 ip.write = writer
166 nt.assert_equal(ip.user_ns['a'], 100)
167 nt.assert_equal(ip.user_ns['b'], 200)
168 assert out == code+"\n## -- End pasted text --\n"
168 self.assertEqual(ip.user_ns["a"], 100)
169 self.assertEqual(ip.user_ns["b"], 200)
170 assert out == code + "\n## -- End pasted text --\n"
169 171
170 172 def test_paste_leading_commas(self):
171 173 "Test multiline strings with leading commas"
172 174 tm = ip.magics_manager.registry['TerminalMagics']
173 175 s = '''\
174 176 a = """
175 177 ,1,2,3
176 178 """'''
177 ip.user_ns.pop('foo', None)
178 tm.store_or_execute(s, 'foo')
179 nt.assert_in('foo', ip.user_ns)
180
179 ip.user_ns.pop("foo", None)
180 tm.store_or_execute(s, "foo")
181 self.assertIn("foo", ip.user_ns)
181 182
182 183 def test_paste_trailing_question(self):
183 184 "Test pasting sources with trailing question marks"
184 185 tm = ip.magics_manager.registry['TerminalMagics']
185 186 s = '''\
186 187 def funcfoo():
187 188 if True: #am i true?
188 189 return 'fooresult'
189 190 '''
190 191 ip.user_ns.pop('funcfoo', None)
191 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 1 """Tests for the object inspection functionality.
2 2 """
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7
8 8 from inspect import signature, Signature, Parameter
9 9 import os
10 10 import re
11 11
12 import nose.tools as nt
13
14 12 from .. import oinspect
15 13
16 14 from decorator import decorator
17 15
18 16 from IPython.testing.tools import AssertPrints, AssertNotPrints
19 17 from IPython.utils.path import compress_user
20 18
21 19
22 20 #-----------------------------------------------------------------------------
23 21 # Globals and constants
24 22 #-----------------------------------------------------------------------------
25 23
26 24 inspector = None
27 25
28 26 def setup_module():
29 27 global inspector
30 28 inspector = oinspect.Inspector()
31 29
32 30
33 31 #-----------------------------------------------------------------------------
34 32 # Local utilities
35 33 #-----------------------------------------------------------------------------
36 34
37 35 # WARNING: since this test checks the line number where a function is
38 36 # defined, if any code is inserted above, the following line will need to be
39 37 # updated. Do NOT insert any whitespace between the next line and the function
40 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 41 from unittest import TestCase
44 42
45 43 class Test(TestCase):
46 44
47 45 def test_find_source_lines(self):
48 46 self.assertEqual(oinspect.find_source_lines(Test.test_find_source_lines),
49 47 THIS_LINE_NUMBER+6)
50 48
51 49
52 50 # A couple of utilities to ensure these tests work the same from a source or a
53 51 # binary install
54 52 def pyfile(fname):
55 53 return os.path.normcase(re.sub('.py[co]$', '.py', fname))
56 54
57 55
58 56 def match_pyfiles(f1, f2):
59 57 assert pyfile(f1) == pyfile(f2)
60 58
61 59
62 60 def test_find_file():
63 61 match_pyfiles(oinspect.find_file(test_find_file), os.path.abspath(__file__))
64 62
65 63
66 64 def test_find_file_decorated1():
67 65
68 66 @decorator
69 67 def noop1(f):
70 68 def wrapper(*a, **kw):
71 69 return f(*a, **kw)
72 70 return wrapper
73 71
74 72 @noop1
75 73 def f(x):
76 74 "My docstring"
77
75
78 76 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
79 77 assert f.__doc__ == "My docstring"
80 78
81 79
82 80 def test_find_file_decorated2():
83 81
84 82 @decorator
85 83 def noop2(f, *a, **kw):
86 84 return f(*a, **kw)
87 85
88 86 @noop2
89 87 @noop2
90 88 @noop2
91 89 def f(x):
92 90 "My docstring 2"
93
91
94 92 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
95 93 assert f.__doc__ == "My docstring 2"
96
94
97 95
98 96 def test_find_file_magic():
99 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 101 # A few generic objects we can then inspect in the tests below
104 102
105 103 class Call(object):
106 104 """This is the class docstring."""
107 105
108 106 def __init__(self, x, y=1):
109 107 """This is the constructor docstring."""
110 108
111 109 def __call__(self, *a, **kw):
112 110 """This is the call docstring."""
113 111
114 112 def method(self, x, z=2):
115 113 """Some method's docstring"""
116 114
117 115 class HasSignature(object):
118 116 """This is the class docstring."""
119 117 __signature__ = Signature([Parameter('test', Parameter.POSITIONAL_OR_KEYWORD)])
120 118
121 119 def __init__(self, *args):
122 120 """This is the init docstring"""
123 121
124 122
125 123 class SimpleClass(object):
126 124 def method(self, x, z=2):
127 125 """Some method's docstring"""
128 126
129 127
130 128 class Awkward(object):
131 129 def __getattr__(self, name):
132 130 raise Exception(name)
133 131
134 132 class NoBoolCall:
135 133 """
136 134 callable with `__bool__` raising should still be inspect-able.
137 135 """
138 136
139 137 def __call__(self):
140 138 """does nothing"""
141 139 pass
142 140
143 141 def __bool__(self):
144 142 """just raise NotImplemented"""
145 143 raise NotImplementedError('Must be implemented')
146 144
147 145
148 146 class SerialLiar(object):
149 147 """Attribute accesses always get another copy of the same class.
150 148
151 149 unittest.mock.call does something similar, but it's not ideal for testing
152 150 as the failure mode is to eat all your RAM. This gives up after 10k levels.
153 151 """
154 152 def __init__(self, max_fibbing_twig, lies_told=0):
155 153 if lies_told > 10000:
156 154 raise RuntimeError('Nose too long, honesty is the best policy')
157 155 self.max_fibbing_twig = max_fibbing_twig
158 156 self.lies_told = lies_told
159 157 max_fibbing_twig[0] = max(max_fibbing_twig[0], lies_told)
160 158
161 159 def __getattr__(self, item):
162 160 return SerialLiar(self.max_fibbing_twig, self.lies_told + 1)
163 161
164 162 #-----------------------------------------------------------------------------
165 163 # Tests
166 164 #-----------------------------------------------------------------------------
167 165
168 166 def test_info():
169 167 "Check that Inspector.info fills out various fields as expected."
170 168 i = inspector.info(Call, oname="Call")
171 169 assert i["type_name"] == "type"
172 expted_class = str(type(type)) # <class 'type'> (Python 3) or <type 'type'>
173 assert i["base_class"] == expted_class
174 nt.assert_regex(
175 i["string_form"],
170 expected_class = str(type(type)) # <class 'type'> (Python 3) or <type 'type'>
171 assert i["base_class"] == expected_class
172 assert re.search(
176 173 "<class 'IPython.core.tests.test_oinspect.Call'( at 0x[0-9a-f]{1,9})?>",
174 i["string_form"],
177 175 )
178 176 fname = __file__
179 177 if fname.endswith(".pyc"):
180 178 fname = fname[:-1]
181 179 # case-insensitive comparison needed on some filesystems
182 180 # e.g. Windows:
183 181 assert i["file"].lower() == compress_user(fname).lower()
184 182 assert i["definition"] == None
185 183 assert i["docstring"] == Call.__doc__
186 184 assert i["source"] == None
187 nt.assert_true(i["isclass"])
185 assert i["isclass"] is True
188 186 assert i["init_definition"] == "Call(x, y=1)"
189 187 assert i["init_docstring"] == Call.__init__.__doc__
190 188
191 189 i = inspector.info(Call, detail_level=1)
192 nt.assert_not_equal(i["source"], None)
190 assert i["source"] is not None
193 191 assert i["docstring"] == None
194 192
195 193 c = Call(1)
196 194 c.__doc__ = "Modified instance docstring"
197 195 i = inspector.info(c)
198 196 assert i["type_name"] == "Call"
199 197 assert i["docstring"] == "Modified instance docstring"
200 198 assert i["class_docstring"] == Call.__doc__
201 199 assert i["init_docstring"] == Call.__init__.__doc__
202 200 assert i["call_docstring"] == Call.__call__.__doc__
203 201
204 202
205 203 def test_class_signature():
206 204 info = inspector.info(HasSignature, "HasSignature")
207 205 assert info["init_definition"] == "HasSignature(test)"
208 206 assert info["init_docstring"] == HasSignature.__init__.__doc__
209 207
210 208
211 209 def test_info_awkward():
212 210 # Just test that this doesn't throw an error.
213 211 inspector.info(Awkward())
214 212
215 213 def test_bool_raise():
216 214 inspector.info(NoBoolCall())
217 215
218 216 def test_info_serialliar():
219 217 fib_tracker = [0]
220 218 inspector.info(SerialLiar(fib_tracker))
221 219
222 220 # Nested attribute access should be cut off at 100 levels deep to avoid
223 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 224 def support_function_one(x, y=2, *a, **kw):
227 225 """A simple function."""
228 226
229 227 def test_calldef_none():
230 228 # We should ignore __call__ for all of these.
231 229 for obj in [support_function_one, SimpleClass().method, any, str.upper]:
232 230 i = inspector.info(obj)
233 nt.assert_is(i['call_def'], None)
231 assert i["call_def"] is None
232
234 233
235 234 def f_kwarg(pos, *, kwonly):
236 235 pass
237 236
238 237 def test_definition_kwonlyargs():
239 238 i = inspector.info(f_kwarg, oname="f_kwarg") # analysis:ignore
240 239 assert i["definition"] == "f_kwarg(pos, *, kwonly)"
241 240
242 241
243 242 def test_getdoc():
244 243 class A(object):
245 244 """standard docstring"""
246 245 pass
247 246
248 247 class B(object):
249 248 """standard docstring"""
250 249 def getdoc(self):
251 250 return "custom docstring"
252
251
253 252 class C(object):
254 253 """standard docstring"""
255 254 def getdoc(self):
256 255 return None
257
256
258 257 a = A()
259 258 b = B()
260 259 c = C()
261
260
262 261 assert oinspect.getdoc(a) == "standard docstring"
263 262 assert oinspect.getdoc(b) == "custom docstring"
264 263 assert oinspect.getdoc(c) == "standard docstring"
265 264
266 265
267 266 def test_empty_property_has_no_source():
268 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 271 def test_property_sources():
273 import posixpath
272 import posixpath
274 273 # A simple adder whose source and signature stays
275 274 # the same across Python distributions
276 275 def simple_add(a, b):
277 276 "Adds two numbers"
278 277 return a + b
279
278
280 279 class A(object):
281 280 @property
282 281 def foo(self):
283 282 return 'bar'
284 283
285 284 foo = foo.setter(lambda self, v: setattr(self, 'bar', v))
286 285
287 286 dname = property(posixpath.dirname)
288 adder = property(simple_add)
287 adder = property(simple_add)
289 288
290 289 i = inspector.info(A.foo, detail_level=1)
291 nt.assert_in('def foo(self):', i['source'])
292 nt.assert_in('lambda self, v:', i['source'])
290 assert "def foo(self):" in i["source"]
291 assert "lambda self, v:" in i["source"]
293 292
294 293 i = inspector.info(A.dname, detail_level=1)
295 nt.assert_in('def dirname(p)', i['source'])
296
294 assert "def dirname(p)" in i["source"]
295
297 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 300 def test_property_docstring_is_in_info_for_detail_level_0():
302 301 class A(object):
303 302 @property
304 303 def foobar(self):
305 304 """This is `foobar` property."""
306 305 pass
307 306
308 307 ip.user_ns["a_obj"] = A()
309 308 assert (
310 309 "This is `foobar` property."
311 310 == ip.object_inspect("a_obj.foobar", detail_level=0)["docstring"]
312 311 )
313 312
314 313 ip.user_ns["a_cls"] = A
315 314 assert (
316 315 "This is `foobar` property."
317 316 == ip.object_inspect("a_cls.foobar", detail_level=0)["docstring"]
318 317 )
319 318
320 319
321 320 def test_pdef():
322 321 # See gh-1914
323 322 def foo(): pass
324 323 inspector.pdef(foo, 'foo')
325 324
326 325
327 326 def test_pinfo_nonascii():
328 327 # See gh-1177
329 328 from . import nonascii2
330 329 ip.user_ns['nonascii2'] = nonascii2
331 330 ip._inspect('pinfo', 'nonascii2', detail_level=1)
332 331
333 332 def test_pinfo_type():
334 333 """
335 334 type can fail in various edge case, for example `type.__subclass__()`
336 335 """
337 336 ip._inspect('pinfo', 'type')
338 337
339 338
340 339 def test_pinfo_docstring_no_source():
341 340 """Docstring should be included with detail_level=1 if there is no source"""
342 341 with AssertPrints('Docstring:'):
343 342 ip._inspect('pinfo', 'str.format', detail_level=0)
344 343 with AssertPrints('Docstring:'):
345 344 ip._inspect('pinfo', 'str.format', detail_level=1)
346 345
347 346
348 347 def test_pinfo_no_docstring_if_source():
349 348 """Docstring should not be included with detail_level=1 if source is found"""
350 349 def foo():
351 350 """foo has a docstring"""
352 351
353 352 ip.user_ns['foo'] = foo
354 353
355 354 with AssertPrints('Docstring:'):
356 355 ip._inspect('pinfo', 'foo', detail_level=0)
357 356 with AssertPrints('Source:'):
358 357 ip._inspect('pinfo', 'foo', detail_level=1)
359 358 with AssertNotPrints('Docstring:'):
360 359 ip._inspect('pinfo', 'foo', detail_level=1)
361 360
362 361
363 362 def test_pinfo_docstring_if_detail_and_no_source():
364 363 """ Docstring should be displayed if source info not available """
365 364 obj_def = '''class Foo(object):
366 365 """ This is a docstring for Foo """
367 366 def bar(self):
368 367 """ This is a docstring for Foo.bar """
369 368 pass
370 '''
371
369 '''
370
372 371 ip.run_cell(obj_def)
373 372 ip.run_cell('foo = Foo()')
374
373
375 374 with AssertNotPrints("Source:"):
376 375 with AssertPrints('Docstring:'):
377 376 ip._inspect('pinfo', 'foo', detail_level=0)
378 377 with AssertPrints('Docstring:'):
379 378 ip._inspect('pinfo', 'foo', detail_level=1)
380 379 with AssertPrints('Docstring:'):
381 380 ip._inspect('pinfo', 'foo.bar', detail_level=0)
382 381
383 382 with AssertNotPrints('Docstring:'):
384 383 with AssertPrints('Source:'):
385 384 ip._inspect('pinfo', 'foo.bar', detail_level=1)
386 385
387 386
388 387 def test_pinfo_magic():
389 388 with AssertPrints('Docstring:'):
390 389 ip._inspect('pinfo', 'lsmagic', detail_level=0)
391 390
392 391 with AssertPrints('Source:'):
393 392 ip._inspect('pinfo', 'lsmagic', detail_level=1)
394 393
395 394
396 395 def test_init_colors():
397 396 # ensure colors are not present in signature info
398 397 info = inspector.info(HasSignature)
399 init_def = info['init_definition']
400 nt.assert_not_in('[0m', init_def)
398 init_def = info["init_definition"]
399 assert "[0m" not in init_def
401 400
402 401
403 402 def test_builtin_init():
404 403 info = inspector.info(list)
405 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 408 def test_render_signature_short():
410 409 def short_fun(a=1): pass
411 410 sig = oinspect._render_signature(
412 411 signature(short_fun),
413 412 short_fun.__name__,
414 413 )
415 414 assert sig == "short_fun(a=1)"
416 415
417 416
418 417 def test_render_signature_long():
419 418 from typing import Optional
420 419
421 420 def long_function(
422 421 a_really_long_parameter: int,
423 422 and_another_long_one: bool = False,
424 423 let_us_make_sure_this_is_looong: Optional[str] = None,
425 424 ) -> bool: pass
426 425
427 426 sig = oinspect._render_signature(
428 427 signature(long_function),
429 428 long_function.__name__,
430 429 )
431 nt.assert_in(sig, [
430 assert sig in [
432 431 # Python >=3.9
433 432 '''\
434 433 long_function(
435 434 a_really_long_parameter: int,
436 435 and_another_long_one: bool = False,
437 436 let_us_make_sure_this_is_looong: Optional[str] = None,
438 437 ) -> bool\
439 438 ''',
440 439 # Python >=3.7
441 440 '''\
442 441 long_function(
443 442 a_really_long_parameter: int,
444 443 and_another_long_one: bool = False,
445 444 let_us_make_sure_this_is_looong: Union[str, NoneType] = None,
446 445 ) -> bool\
447 446 ''', # Python <=3.6
448 447 '''\
449 448 long_function(
450 449 a_really_long_parameter:int,
451 450 and_another_long_one:bool=False,
452 451 let_us_make_sure_this_is_looong:Union[str, NoneType]=None,
453 452 ) -> bool\
454 453 ''',
455 ])
454 ]
@@ -1,204 +1,205 b''
1 1 import errno
2 2 import os
3 3 import shutil
4 4 import sys
5 5 import tempfile
6 6 import warnings
7 7 from unittest.mock import patch
8 8
9 import nose.tools as nt
10 9 from testpath import modified_env, assert_isdir, assert_isfile
11 10
12 11 from IPython import paths
13 12 from IPython.testing.decorators import skip_win32
14 13 from IPython.utils.tempdir import TemporaryDirectory
15 14
16 15 TMP_TEST_DIR = os.path.realpath(tempfile.mkdtemp())
17 16 HOME_TEST_DIR = os.path.join(TMP_TEST_DIR, "home_test_dir")
18 17 XDG_TEST_DIR = os.path.join(HOME_TEST_DIR, "xdg_test_dir")
19 18 XDG_CACHE_DIR = os.path.join(HOME_TEST_DIR, "xdg_cache_dir")
20 19 IP_TEST_DIR = os.path.join(HOME_TEST_DIR,'.ipython')
21 20
22 21 def setup_module():
23 22 """Setup testenvironment for the module:
24 23
25 24 - Adds dummy home dir tree
26 25 """
27 26 # Do not mask exceptions here. In particular, catching WindowsError is a
28 27 # problem because that exception is only defined on Windows...
29 28 os.makedirs(IP_TEST_DIR)
30 29 os.makedirs(os.path.join(XDG_TEST_DIR, 'ipython'))
31 30 os.makedirs(os.path.join(XDG_CACHE_DIR, 'ipython'))
32 31
33 32
34 33 def teardown_module():
35 34 """Teardown testenvironment for the module:
36 35
37 36 - Remove dummy home dir tree
38 37 """
39 38 # Note: we remove the parent test dir, which is the root of all test
40 39 # subdirs we may have created. Use shutil instead of os.removedirs, so
41 40 # that non-empty directories are all recursively removed.
42 41 shutil.rmtree(TMP_TEST_DIR)
43 42
44 43 def patch_get_home_dir(dirpath):
45 44 return patch.object(paths, 'get_home_dir', return_value=dirpath)
46 45
47 46
48 47 def test_get_ipython_dir_1():
49 48 """test_get_ipython_dir_1, Testcase to see if we can call get_ipython_dir without Exceptions."""
50 49 env_ipdir = os.path.join("someplace", ".ipython")
51 50 with patch.object(paths, '_writable_dir', return_value=True), \
52 51 modified_env({'IPYTHONDIR': env_ipdir}):
53 52 ipdir = paths.get_ipython_dir()
54 53
55 nt.assert_equal(ipdir, env_ipdir)
54 assert ipdir == env_ipdir
56 55
57 56 def test_get_ipython_dir_2():
58 57 """test_get_ipython_dir_2, Testcase to see if we can call get_ipython_dir without Exceptions."""
59 58 with patch_get_home_dir('someplace'), \
60 59 patch.object(paths, 'get_xdg_dir', return_value=None), \
61 60 patch.object(paths, '_writable_dir', return_value=True), \
62 61 patch('os.name', "posix"), \
63 62 modified_env({'IPYTHON_DIR': None,
64 63 'IPYTHONDIR': None,
65 64 'XDG_CONFIG_HOME': None
66 65 }):
67 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 70 def test_get_ipython_dir_3():
72 71 """test_get_ipython_dir_3, move XDG if defined, and .ipython doesn't exist."""
73 72 tmphome = TemporaryDirectory()
74 73 try:
75 74 with patch_get_home_dir(tmphome.name), \
76 75 patch('os.name', 'posix'), \
77 76 modified_env({
78 77 'IPYTHON_DIR': None,
79 78 'IPYTHONDIR': None,
80 79 'XDG_CONFIG_HOME': XDG_TEST_DIR,
81 80 }), warnings.catch_warnings(record=True) as w:
82 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 84 if sys.platform != 'darwin':
86 nt.assert_equal(len(w), 1)
87 nt.assert_in('Moving', str(w[0]))
85 assert len(w) == 1
86 assert "Moving" in str(w[0])
88 87 finally:
89 88 tmphome.cleanup()
90 89
91 90 def test_get_ipython_dir_4():
92 91 """test_get_ipython_dir_4, warn if XDG and home both exist."""
93 92 with patch_get_home_dir(HOME_TEST_DIR), \
94 93 patch('os.name', 'posix'):
95 94 try:
96 95 os.mkdir(os.path.join(XDG_TEST_DIR, 'ipython'))
97 96 except OSError as e:
98 97 if e.errno != errno.EEXIST:
99 98 raise
100 99
101 100
102 101 with modified_env({
103 102 'IPYTHON_DIR': None,
104 103 'IPYTHONDIR': None,
105 104 'XDG_CONFIG_HOME': XDG_TEST_DIR,
106 105 }), warnings.catch_warnings(record=True) as w:
107 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 109 if sys.platform != 'darwin':
111 nt.assert_equal(len(w), 1)
112 nt.assert_in('Ignoring', str(w[0]))
110 assert len(w) == 1
111 assert "Ignoring" in str(w[0])
112
113 113
114 114 def test_get_ipython_dir_5():
115 115 """test_get_ipython_dir_5, use .ipython if exists and XDG defined, but doesn't exist."""
116 116 with patch_get_home_dir(HOME_TEST_DIR), \
117 117 patch('os.name', 'posix'):
118 118 try:
119 119 os.rmdir(os.path.join(XDG_TEST_DIR, 'ipython'))
120 120 except OSError as e:
121 121 if e.errno != errno.ENOENT:
122 122 raise
123 123
124 124 with modified_env({
125 125 'IPYTHON_DIR': None,
126 126 'IPYTHONDIR': None,
127 127 'XDG_CONFIG_HOME': XDG_TEST_DIR,
128 128 }):
129 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 133 def test_get_ipython_dir_6():
134 134 """test_get_ipython_dir_6, use home over XDG if defined and neither exist."""
135 135 xdg = os.path.join(HOME_TEST_DIR, 'somexdg')
136 136 os.mkdir(xdg)
137 137 shutil.rmtree(os.path.join(HOME_TEST_DIR, '.ipython'))
138 138 print(paths._writable_dir)
139 139 with patch_get_home_dir(HOME_TEST_DIR), \
140 140 patch.object(paths, 'get_xdg_dir', return_value=xdg), \
141 141 patch('os.name', 'posix'), \
142 142 modified_env({
143 143 'IPYTHON_DIR': None,
144 144 'IPYTHONDIR': None,
145 145 'XDG_CONFIG_HOME': None,
146 146 }), warnings.catch_warnings(record=True) as w:
147 147 ipdir = paths.get_ipython_dir()
148 148
149 nt.assert_equal(ipdir, os.path.join(HOME_TEST_DIR, '.ipython'))
150 nt.assert_equal(len(w), 0)
149 assert ipdir == os.path.join(HOME_TEST_DIR, ".ipython")
150 assert len(w) == 0
151 151
152 152 def test_get_ipython_dir_7():
153 153 """test_get_ipython_dir_7, test home directory expansion on IPYTHONDIR"""
154 154 home_dir = os.path.normpath(os.path.expanduser('~'))
155 155 with modified_env({'IPYTHONDIR': os.path.join('~', 'somewhere')}), \
156 156 patch.object(paths, '_writable_dir', return_value=True):
157 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 161 @skip_win32
161 162 def test_get_ipython_dir_8():
162 163 """test_get_ipython_dir_8, test / home directory"""
163 164 if not os.access("/", os.W_OK):
164 165 # test only when HOME directory actually writable
165 166 return
166 167
167 with patch.object(paths, '_writable_dir', lambda path: bool(path)), \
168 patch.object(paths, 'get_xdg_dir', return_value=None), \
169 modified_env({
170 'IPYTHON_DIR': None,
171 'IPYTHONDIR': None,
172 'HOME': '/',
173 }):
174 nt.assert_equal(paths.get_ipython_dir(), '/.ipython')
168 with patch.object(paths, "_writable_dir", lambda path: bool(path)), patch.object(
169 paths, "get_xdg_dir", return_value=None
170 ), modified_env(
171 {
172 "IPYTHON_DIR": None,
173 "IPYTHONDIR": None,
174 "HOME": "/",
175 }
176 ):
177 assert paths.get_ipython_dir() == "/.ipython"
175 178
176 179
177 180 def test_get_ipython_cache_dir():
178 181 with modified_env({'HOME': HOME_TEST_DIR}):
179 182 if os.name == 'posix' and sys.platform != 'darwin':
180 183 # test default
181 184 os.makedirs(os.path.join(HOME_TEST_DIR, ".cache"))
182 185 with modified_env({'XDG_CACHE_HOME': None}):
183 186 ipdir = paths.get_ipython_cache_dir()
184 nt.assert_equal(os.path.join(HOME_TEST_DIR, ".cache", "ipython"),
185 ipdir)
187 assert os.path.join(HOME_TEST_DIR, ".cache", "ipython") == ipdir
186 188 assert_isdir(ipdir)
187 189
188 190 # test env override
189 191 with modified_env({"XDG_CACHE_HOME": XDG_CACHE_DIR}):
190 192 ipdir = paths.get_ipython_cache_dir()
191 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 195 else:
194 nt.assert_equal(paths.get_ipython_cache_dir(),
195 paths.get_ipython_dir())
196 assert paths.get_ipython_cache_dir() == paths.get_ipython_dir()
196 197
197 198 def test_get_ipython_package_dir():
198 199 ipdir = paths.get_ipython_package_dir()
199 200 assert_isdir(ipdir)
200 201
201 202
202 203 def test_get_ipython_module_path():
203 204 ipapp_path = paths.get_ipython_module_path('IPython.terminal.ipapp')
204 205 assert_isfile(ipapp_path)
@@ -1,170 +1,167 b''
1 1 # coding: utf-8
2 2 """Tests for profile-related functions.
3 3
4 4 Currently only the startup-dir functionality is tested, but more tests should
5 5 be added for:
6 6
7 7 * ipython profile create
8 8 * ipython profile list
9 9 * ipython profile create --parallel
10 10 * security dir permissions
11 11
12 12 Authors
13 13 -------
14 14
15 15 * MinRK
16 16
17 17 """
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Imports
21 21 #-----------------------------------------------------------------------------
22 22
23 23 import shutil
24 24 import sys
25 25 import tempfile
26 26
27 27 from pathlib import Path
28 28 from unittest import TestCase
29 29
30 import nose.tools as nt
31
32 30 from IPython.core.profileapp import list_profiles_in, list_bundled_profiles
33 31 from IPython.core.profiledir import ProfileDir
34 32
35 33 from IPython.testing import decorators as dec
36 34 from IPython.testing import tools as tt
37 35 from IPython.utils.process import getoutput
38 36 from IPython.utils.tempdir import TemporaryDirectory
39 37
40 38 #-----------------------------------------------------------------------------
41 39 # Globals
42 40 #-----------------------------------------------------------------------------
43 41 TMP_TEST_DIR = Path(tempfile.mkdtemp())
44 42 HOME_TEST_DIR = TMP_TEST_DIR / "home_test_dir"
45 43 IP_TEST_DIR = HOME_TEST_DIR / ".ipython"
46 44
47 45 #
48 46 # Setup/teardown functions/decorators
49 47 #
50 48
51 49 def setup_module():
52 50 """Setup test environment for the module:
53 51
54 52 - Adds dummy home dir tree
55 53 """
56 54 # Do not mask exceptions here. In particular, catching WindowsError is a
57 55 # problem because that exception is only defined on Windows...
58 56 (Path.cwd() / IP_TEST_DIR).mkdir(parents=True)
59 57
60 58
61 59 def teardown_module():
62 60 """Teardown test environment for the module:
63 61
64 62 - Remove dummy home dir tree
65 63 """
66 64 # Note: we remove the parent test dir, which is the root of all test
67 65 # subdirs we may have created. Use shutil instead of os.removedirs, so
68 66 # that non-empty directories are all recursively removed.
69 67 shutil.rmtree(TMP_TEST_DIR)
70 68
71 69
72 70 #-----------------------------------------------------------------------------
73 71 # Test functions
74 72 #-----------------------------------------------------------------------------
75 73 def win32_without_pywin32():
76 74 if sys.platform == 'win32':
77 75 try:
78 76 import pywin32
79 77 except ImportError:
80 78 return True
81 79 return False
82
80
83 81
84 82 class ProfileStartupTest(TestCase):
85 83 def setUp(self):
86 84 # create profile dir
87 85 self.pd = ProfileDir.create_profile_dir_by_name(IP_TEST_DIR, "test")
88 86 self.options = ["--ipython-dir", IP_TEST_DIR, "--profile", "test"]
89 87 self.fname = TMP_TEST_DIR / "test.py"
90 88
91 89 def tearDown(self):
92 90 # We must remove this profile right away so its presence doesn't
93 91 # confuse other tests.
94 92 shutil.rmtree(self.pd.location)
95 93
96 94 def init(self, startup_file, startup, test):
97 95 # write startup python file
98 96 with open(Path(self.pd.startup_dir) / startup_file, "w") as f:
99 97 f.write(startup)
100 98 # write simple test file, to check that the startup file was run
101 99 with open(self.fname, 'w') as f:
102 100 f.write(test)
103 101
104 102 def validate(self, output):
105 103 tt.ipexec_validate(self.fname, output, '', options=self.options)
106 104
107 105 @dec.skipif(win32_without_pywin32(), "Test requires pywin32 on Windows")
108 106 def test_startup_py(self):
109 107 self.init('00-start.py', 'zzz=123\n', 'print(zzz)\n')
110 108 self.validate('123')
111 109
112 110 @dec.skipif(win32_without_pywin32(), "Test requires pywin32 on Windows")
113 111 def test_startup_ipy(self):
114 112 self.init('00-start.ipy', '%xmode plain\n', '')
115 113 self.validate('Exception reporting mode: Plain')
116 114
117
115
118 116 def test_list_profiles_in():
119 117 # No need to remove these directories and files, as they will get nuked in
120 118 # the module-level teardown.
121 119 td = Path(tempfile.mkdtemp(dir=TMP_TEST_DIR))
122 120 for name in ("profile_foo", "profile_hello", "not_a_profile"):
123 121 Path(td / name).mkdir(parents=True)
124 122 if dec.unicode_paths:
125 123 Path(td / u"profile_ünicode").mkdir(parents=True)
126 124
127 125 with open(td / "profile_file", "w") as f:
128 126 f.write("I am not a profile directory")
129 127 profiles = list_profiles_in(td)
130
128
131 129 # unicode normalization can turn u'ünicode' into u'u\0308nicode',
132 130 # so only check for *nicode, and that creating a ProfileDir from the
133 131 # name remains valid
134 132 found_unicode = False
135 133 for p in list(profiles):
136 134 if p.endswith('nicode'):
137 135 pd = ProfileDir.find_profile_dir_by_name(td, p)
138 136 profiles.remove(p)
139 137 found_unicode = True
140 138 break
141 139 if dec.unicode_paths:
142 nt.assert_true(found_unicode)
143 nt.assert_equal(set(profiles), {'foo', 'hello'})
140 assert found_unicode is True
141 assert set(profiles) == {"foo", "hello"}
144 142
145 143
146 144 def test_list_bundled_profiles():
147 145 # This variable will need to be updated when a new profile gets bundled
148 146 bundled = sorted(list_bundled_profiles())
149 nt.assert_equal(bundled, [])
147 assert bundled == []
150 148
151 149
152 150 def test_profile_create_ipython_dir():
153 151 """ipython profile create respects --ipython-dir"""
154 152 with TemporaryDirectory() as td:
155 153 getoutput(
156 154 [
157 155 sys.executable,
158 156 "-m",
159 157 "IPython",
160 158 "profile",
161 159 "create",
162 160 "foo",
163 161 "--ipython-dir=%s" % td,
164 162 ]
165 163 )
166 164 profile_dir = Path(td) / "profile_foo"
167 165 assert Path(profile_dir).exists()
168 166 ipython_config = profile_dir / "ipython_config.py"
169 167 assert Path(ipython_config).exists()
170
@@ -1,274 +1,273 b''
1 1 """Tests for pylab tools module.
2 2 """
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7
8 8 from binascii import a2b_base64
9 9 from io import BytesIO
10 10
11 11 import matplotlib
12 12 matplotlib.use('Agg')
13 13 from matplotlib.figure import Figure
14 14
15 from nose import SkipTest
16 import nose.tools as nt
17
18 15 from matplotlib import pyplot as plt
19 import matplotlib_inline
16 from matplotlib_inline import backend_inline
20 17 import numpy as np
18 import pytest
21 19
22 20 from IPython.core.getipython import get_ipython
23 21 from IPython.core.interactiveshell import InteractiveShell
24 22 from IPython.core.display import _PNG, _JPEG
25 23 from .. import pylabtools as pt
26 24
27 25 from IPython.testing import decorators as dec
28 26
29 27
30 28 def test_figure_to_svg():
31 29 # simple empty-figure test
32 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 33 plt.close('all')
36 34
37 35 # simple check for at least svg-looking output
38 36 fig = plt.figure()
39 37 ax = fig.add_subplot(1,1,1)
40 38 ax.plot([1,2,3])
41 39 plt.draw()
42 svg = pt.print_figure(fig, 'svg')[:100].lower()
43 nt.assert_in(u'doctype svg', svg)
40 svg = pt.print_figure(fig, "svg")[:100].lower()
41 assert "doctype svg" in svg
42
44 43
45 44 def _check_pil_jpeg_bytes():
46 45 """Skip if PIL can't write JPEGs to BytesIO objects"""
47 46 # PIL's JPEG plugin can't write to BytesIO objects
48 47 # Pillow fixes this
49 48 from PIL import Image
50 49 buf = BytesIO()
51 50 img = Image.new("RGB", (4,4))
52 51 try:
53 52 img.save(buf, 'jpeg')
54 53 except Exception as e:
55 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 57 @dec.skip_without("PIL.Image")
59 58 def test_figure_to_jpeg():
60 59 _check_pil_jpeg_bytes()
61 60 # simple check for at least jpeg-looking output
62 61 fig = plt.figure()
63 62 ax = fig.add_subplot(1,1,1)
64 63 ax.plot([1,2,3])
65 64 plt.draw()
66 65 jpeg = pt.print_figure(fig, 'jpeg', pil_kwargs={'optimize': 50})[:100].lower()
67 66 assert jpeg.startswith(_JPEG)
68 67
69 68 def test_retina_figure():
70 69 # simple empty-figure test
71 70 fig = plt.figure()
72 nt.assert_equal(pt.retina_figure(fig), None)
71 assert pt.retina_figure(fig) == None
73 72 plt.close('all')
74 73
75 74 fig = plt.figure()
76 75 ax = fig.add_subplot(1,1,1)
77 76 ax.plot([1,2,3])
78 77 plt.draw()
79 78 png, md = pt.retina_figure(fig)
80 79 assert png.startswith(_PNG)
81 nt.assert_in('width', md)
82 nt.assert_in('height', md)
80 assert "width" in md
81 assert "height" in md
82
83 83
84 84 _fmt_mime_map = {
85 85 'png': 'image/png',
86 86 'jpeg': 'image/jpeg',
87 87 'pdf': 'application/pdf',
88 88 'retina': 'image/png',
89 89 'svg': 'image/svg+xml',
90 90 }
91 91
92 92 def test_select_figure_formats_str():
93 93 ip = get_ipython()
94 94 for fmt, active_mime in _fmt_mime_map.items():
95 95 pt.select_figure_formats(ip, fmt)
96 96 for mime, f in ip.display_formatter.formatters.items():
97 97 if mime == active_mime:
98 nt.assert_in(Figure, f)
98 assert Figure in f
99 99 else:
100 nt.assert_not_in(Figure, f)
100 assert Figure not in f
101 101
102 102 def test_select_figure_formats_kwargs():
103 103 ip = get_ipython()
104 104 kwargs = dict(quality=10, bbox_inches='tight')
105 105 pt.select_figure_formats(ip, 'png', **kwargs)
106 106 formatter = ip.display_formatter.formatters['image/png']
107 107 f = formatter.lookup_by_type(Figure)
108 108 cell = f.keywords
109 109 expected = kwargs
110 110 expected["base64"] = True
111 111 expected["fmt"] = "png"
112 112 assert cell == expected
113 113
114 114 # check that the formatter doesn't raise
115 115 fig = plt.figure()
116 116 ax = fig.add_subplot(1,1,1)
117 117 ax.plot([1,2,3])
118 118 plt.draw()
119 119 formatter.enabled = True
120 120 png = formatter(fig)
121 121 assert isinstance(png, str)
122 122 png_bytes = a2b_base64(png)
123 123 assert png_bytes.startswith(_PNG)
124 124
125 125 def test_select_figure_formats_set():
126 126 ip = get_ipython()
127 127 for fmts in [
128 128 {'png', 'svg'},
129 129 ['png'],
130 130 ('jpeg', 'pdf', 'retina'),
131 131 {'svg'},
132 132 ]:
133 133 active_mimes = {_fmt_mime_map[fmt] for fmt in fmts}
134 134 pt.select_figure_formats(ip, fmts)
135 135 for mime, f in ip.display_formatter.formatters.items():
136 136 if mime in active_mimes:
137 nt.assert_in(Figure, f)
137 assert Figure in f
138 138 else:
139 nt.assert_not_in(Figure, f)
139 assert Figure not in f
140 140
141 141 def test_select_figure_formats_bad():
142 142 ip = get_ipython()
143 with nt.assert_raises(ValueError):
143 with pytest.raises(ValueError):
144 144 pt.select_figure_formats(ip, 'foo')
145 with nt.assert_raises(ValueError):
145 with pytest.raises(ValueError):
146 146 pt.select_figure_formats(ip, {'png', 'foo'})
147 with nt.assert_raises(ValueError):
147 with pytest.raises(ValueError):
148 148 pt.select_figure_formats(ip, ['retina', 'pdf', 'bar', 'bad'])
149 149
150 150 def test_import_pylab():
151 151 ns = {}
152 152 pt.import_pylab(ns, import_all=False)
153 nt.assert_true('plt' in ns)
154 nt.assert_equal(ns['np'], np)
153 assert "plt" in ns
154 assert ns["np"] == np
155
155 156
156 157 from traitlets.config import Config
157 158
158 159
159 160 class TestPylabSwitch(object):
160 161 class Shell(InteractiveShell):
161 162 def init_history(self):
162 163 """Sets up the command history, and starts regular autosaves."""
163 164 self.config.HistoryManager.hist_file = ":memory:"
164 165 super().init_history()
165 166
166 167 def enable_gui(self, gui):
167 168 pass
168 169
169 170 def setup(self):
170 171 import matplotlib
171 172 def act_mpl(backend):
172 173 matplotlib.rcParams['backend'] = backend
173 174
174 175 # Save rcParams since they get modified
175 176 self._saved_rcParams = matplotlib.rcParams
176 177 self._saved_rcParamsOrig = matplotlib.rcParamsOrig
177 178 matplotlib.rcParams = dict(backend='Qt4Agg')
178 179 matplotlib.rcParamsOrig = dict(backend='Qt4Agg')
179 180
180 181 # Mock out functions
181 182 self._save_am = pt.activate_matplotlib
182 183 pt.activate_matplotlib = act_mpl
183 184 self._save_ip = pt.import_pylab
184 185 pt.import_pylab = lambda *a,**kw:None
185 self._save_cis = matplotlib_inline.backend_inline.configure_inline_support
186 matplotlib_inline.backend_inline.configure_inline_support = (
187 lambda *a, **kw: None
188 )
186 self._save_cis = backend_inline.configure_inline_support
187 backend_inline.configure_inline_support = lambda *a, **kw: None
189 188
190 189 def teardown(self):
191 190 pt.activate_matplotlib = self._save_am
192 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 193 import matplotlib
195 194 matplotlib.rcParams = self._saved_rcParams
196 195 matplotlib.rcParamsOrig = self._saved_rcParamsOrig
197 196
198 197 def test_qt(self):
199 198
200 199 s = self.Shell()
201 200 gui, backend = s.enable_matplotlib(None)
202 nt.assert_equal(gui, 'qt')
203 nt.assert_equal(s.pylab_gui_select, 'qt')
201 assert gui == "qt"
202 assert s.pylab_gui_select == "qt"
204 203
205 gui, backend = s.enable_matplotlib('inline')
206 nt.assert_equal(gui, 'inline')
207 nt.assert_equal(s.pylab_gui_select, 'qt')
204 gui, backend = s.enable_matplotlib("inline")
205 assert gui == "inline"
206 assert s.pylab_gui_select == "qt"
208 207
209 gui, backend = s.enable_matplotlib('qt')
210 nt.assert_equal(gui, 'qt')
211 nt.assert_equal(s.pylab_gui_select, 'qt')
208 gui, backend = s.enable_matplotlib("qt")
209 assert gui == "qt"
210 assert s.pylab_gui_select == "qt"
212 211
213 gui, backend = s.enable_matplotlib('inline')
214 nt.assert_equal(gui, 'inline')
215 nt.assert_equal(s.pylab_gui_select, 'qt')
212 gui, backend = s.enable_matplotlib("inline")
213 assert gui == "inline"
214 assert s.pylab_gui_select == "qt"
216 215
217 216 gui, backend = s.enable_matplotlib()
218 nt.assert_equal(gui, 'qt')
219 nt.assert_equal(s.pylab_gui_select, 'qt')
217 assert gui == "qt"
218 assert s.pylab_gui_select == "qt"
220 219
221 220 def test_inline(self):
222 221 s = self.Shell()
223 gui, backend = s.enable_matplotlib('inline')
224 nt.assert_equal(gui, 'inline')
225 nt.assert_equal(s.pylab_gui_select, None)
222 gui, backend = s.enable_matplotlib("inline")
223 assert gui == "inline"
224 assert s.pylab_gui_select == None
226 225
227 gui, backend = s.enable_matplotlib('inline')
228 nt.assert_equal(gui, 'inline')
229 nt.assert_equal(s.pylab_gui_select, None)
226 gui, backend = s.enable_matplotlib("inline")
227 assert gui == "inline"
228 assert s.pylab_gui_select == None
230 229
231 gui, backend = s.enable_matplotlib('qt')
232 nt.assert_equal(gui, 'qt')
233 nt.assert_equal(s.pylab_gui_select, 'qt')
230 gui, backend = s.enable_matplotlib("qt")
231 assert gui == "qt"
232 assert s.pylab_gui_select == "qt"
234 233
235 234 def test_inline_twice(self):
236 235 "Using '%matplotlib inline' twice should not reset formatters"
237 236
238 237 ip = self.Shell()
239 gui, backend = ip.enable_matplotlib('inline')
240 nt.assert_equal(gui, 'inline')
238 gui, backend = ip.enable_matplotlib("inline")
239 assert gui == "inline"
241 240
242 241 fmts = {'png'}
243 242 active_mimes = {_fmt_mime_map[fmt] for fmt in fmts}
244 243 pt.select_figure_formats(ip, fmts)
245 244
246 gui, backend = ip.enable_matplotlib('inline')
247 nt.assert_equal(gui, 'inline')
245 gui, backend = ip.enable_matplotlib("inline")
246 assert gui == "inline"
248 247
249 248 for mime, f in ip.display_formatter.formatters.items():
250 249 if mime in active_mimes:
251 nt.assert_in(Figure, f)
250 assert Figure in f
252 251 else:
253 nt.assert_not_in(Figure, f)
252 assert Figure not in f
254 253
255 254 def test_qt_gtk(self):
256 255 s = self.Shell()
257 gui, backend = s.enable_matplotlib('qt')
258 nt.assert_equal(gui, 'qt')
259 nt.assert_equal(s.pylab_gui_select, 'qt')
256 gui, backend = s.enable_matplotlib("qt")
257 assert gui == "qt"
258 assert s.pylab_gui_select == "qt"
260 259
261 gui, backend = s.enable_matplotlib('gtk')
262 nt.assert_equal(gui, 'qt')
263 nt.assert_equal(s.pylab_gui_select, 'qt')
260 gui, backend = s.enable_matplotlib("gtk")
261 assert gui == "qt"
262 assert s.pylab_gui_select == "qt"
264 263
265 264
266 265 def test_no_gui_backends():
267 266 for k in ['agg', 'svg', 'pdf', 'ps']:
268 267 assert k not in pt.backend2gui
269 268
270 269
271 270 def test_figure_no_canvas():
272 271 fig = Figure()
273 272 fig.canvas = None
274 273 pt.print_figure(fig)
@@ -1,601 +1,599 b''
1 1 # encoding: utf-8
2 2 """Tests for code execution (%run and related), which is particularly tricky.
3 3
4 4 Because of how %run manages namespaces, and the fact that we are trying here to
5 5 verify subtle object deletion and reference counting issues, the %run tests
6 6 will be kept in this separate file. This makes it easier to aggregate in one
7 7 place the tricks needed to handle it; most other magics are much easier to test
8 8 and we do so in a common test_magic file.
9 9
10 10 Note that any test using `run -i` should make sure to do a `reset` afterwards,
11 11 as otherwise it may influence later tests.
12 12 """
13 13
14 14 # Copyright (c) IPython Development Team.
15 15 # Distributed under the terms of the Modified BSD License.
16 16
17 17
18 18
19 19 import functools
20 20 import os
21 21 from os.path import join as pjoin
22 22 import random
23 23 import string
24 24 import sys
25 25 import textwrap
26 26 import unittest
27 27 from unittest.mock import patch
28 28
29 import nose.tools as nt
30 from nose import SkipTest
29 import pytest
31 30
32 31 from IPython.testing import decorators as dec
33 32 from IPython.testing import tools as tt
34 33 from IPython.utils.io import capture_output
35 34 from IPython.utils.tempdir import TemporaryDirectory
36 35 from IPython.core import debugger
37 36
38 37 def doctest_refbug():
39 38 """Very nasty problem with references held by multiple runs of a script.
40 39 See: https://github.com/ipython/ipython/issues/141
41 40
42 41 In [1]: _ip.clear_main_mod_cache()
43 42 # random
44 43
45 44 In [2]: %run refbug
46 45
47 46 In [3]: call_f()
48 47 lowercased: hello
49 48
50 49 In [4]: %run refbug
51 50
52 51 In [5]: call_f()
53 52 lowercased: hello
54 53 lowercased: hello
55 54 """
56 55
57 56
58 57 def doctest_run_builtins():
59 58 r"""Check that %run doesn't damage __builtins__.
60 59
61 60 In [1]: import tempfile
62 61
63 62 In [2]: bid1 = id(__builtins__)
64 63
65 64 In [3]: fname = tempfile.mkstemp('.py')[1]
66 65
67 66 In [3]: f = open(fname,'w')
68 67
69 68 In [4]: dummy= f.write('pass\n')
70 69
71 70 In [5]: f.flush()
72 71
73 72 In [6]: t1 = type(__builtins__)
74 73
75 74 In [7]: %run $fname
76 75
77 76 In [7]: f.close()
78 77
79 78 In [8]: bid2 = id(__builtins__)
80 79
81 80 In [9]: t2 = type(__builtins__)
82 81
83 82 In [10]: t1 == t2
84 83 Out[10]: True
85 84
86 85 In [10]: bid1 == bid2
87 86 Out[10]: True
88 87
89 88 In [12]: try:
90 89 ....: os.unlink(fname)
91 90 ....: except:
92 91 ....: pass
93 92 ....:
94 93 """
95 94
96 95
97 96 def doctest_run_option_parser():
98 97 r"""Test option parser in %run.
99 98
100 99 In [1]: %run print_argv.py
101 100 []
102 101
103 102 In [2]: %run print_argv.py print*.py
104 103 ['print_argv.py']
105 104
106 105 In [3]: %run -G print_argv.py print*.py
107 106 ['print*.py']
108 107
109 108 """
110 109
111 110
112 111 @dec.skip_win32
113 112 def doctest_run_option_parser_for_posix():
114 113 r"""Test option parser in %run (Linux/OSX specific).
115 114
116 115 You need double quote to escape glob in POSIX systems:
117 116
118 117 In [1]: %run print_argv.py print\\*.py
119 118 ['print*.py']
120 119
121 120 You can't use quote to escape glob in POSIX systems:
122 121
123 122 In [2]: %run print_argv.py 'print*.py'
124 123 ['print_argv.py']
125 124
126 125 """
127 126
128 127
129 128 @dec.skip_if_not_win32
130 129 def doctest_run_option_parser_for_windows():
131 130 r"""Test option parser in %run (Windows specific).
132 131
133 132 In Windows, you can't escape ``*` `by backslash:
134 133
135 134 In [1]: %run print_argv.py print\\*.py
136 135 ['print\\*.py']
137 136
138 137 You can use quote to escape glob:
139 138
140 139 In [2]: %run print_argv.py 'print*.py'
141 140 ['print*.py']
142 141
143 142 """
144 143
145 144
146 145 def doctest_reset_del():
147 146 """Test that resetting doesn't cause errors in __del__ methods.
148 147
149 148 In [2]: class A(object):
150 149 ...: def __del__(self):
151 150 ...: print(str("Hi"))
152 151 ...:
153 152
154 153 In [3]: a = A()
155 154
156 155 In [4]: get_ipython().reset()
157 156 Hi
158 157
159 158 In [5]: 1+1
160 159 Out[5]: 2
161 160 """
162 161
163 162 # For some tests, it will be handy to organize them in a class with a common
164 163 # setup that makes a temp file
165 164
166 165 class TestMagicRunPass(tt.TempFileMixin):
167 166
168 167 def setUp(self):
169 168 content = "a = [1,2,3]\nb = 1"
170 169 self.mktmp(content)
171
170
172 171 def run_tmpfile(self):
173 172 _ip = get_ipython()
174 173 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
175 174 # See below and ticket https://bugs.launchpad.net/bugs/366353
176 175 _ip.magic('run %s' % self.fname)
177
176
178 177 def run_tmpfile_p(self):
179 178 _ip = get_ipython()
180 179 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
181 180 # See below and ticket https://bugs.launchpad.net/bugs/366353
182 181 _ip.magic('run -p %s' % self.fname)
183 182
184 183 def test_builtins_id(self):
185 184 """Check that %run doesn't damage __builtins__ """
186 185 _ip = get_ipython()
187 186 # Test that the id of __builtins__ is not modified by %run
188 187 bid1 = id(_ip.user_ns['__builtins__'])
189 188 self.run_tmpfile()
190 189 bid2 = id(_ip.user_ns['__builtins__'])
191 nt.assert_equal(bid1, bid2)
190 assert bid1 == bid2
192 191
193 192 def test_builtins_type(self):
194 193 """Check that the type of __builtins__ doesn't change with %run.
195 194
196 195 However, the above could pass if __builtins__ was already modified to
197 196 be a dict (it should be a module) by a previous use of %run. So we
198 197 also check explicitly that it really is a module:
199 198 """
200 199 _ip = get_ipython()
201 200 self.run_tmpfile()
202 nt.assert_equal(type(_ip.user_ns['__builtins__']),type(sys))
203
204 def test_run_profile( self ):
201 assert type(_ip.user_ns["__builtins__"]) == type(sys)
202
203 def test_run_profile(self):
205 204 """Test that the option -p, which invokes the profiler, do not
206 205 crash by invoking execfile"""
207 206 self.run_tmpfile_p()
208 207
209 208 def test_run_debug_twice(self):
210 209 # https://github.com/ipython/ipython/issues/10028
211 210 _ip = get_ipython()
212 211 with tt.fake_input(['c']):
213 212 _ip.magic('run -d %s' % self.fname)
214 213 with tt.fake_input(['c']):
215 214 _ip.magic('run -d %s' % self.fname)
216 215
217 216 def test_run_debug_twice_with_breakpoint(self):
218 217 """Make a valid python temp file."""
219 218 _ip = get_ipython()
220 219 with tt.fake_input(['b 2', 'c', 'c']):
221 220 _ip.magic('run -d %s' % self.fname)
222 221
223 222 with tt.fake_input(['c']):
224 223 with tt.AssertNotPrints('KeyError'):
225 224 _ip.magic('run -d %s' % self.fname)
226 225
227 226
228 227 class TestMagicRunSimple(tt.TempFileMixin):
229 228
230 229 def test_simpledef(self):
231 230 """Test that simple class definitions work."""
232 231 src = ("class foo: pass\n"
233 232 "def f(): return foo()")
234 233 self.mktmp(src)
235 _ip.magic('run %s' % self.fname)
236 _ip.run_cell('t = isinstance(f(), foo)')
237 nt.assert_true(_ip.user_ns['t'])
234 _ip.magic("run %s" % self.fname)
235 _ip.run_cell("t = isinstance(f(), foo)")
236 assert _ip.user_ns["t"] is True
238 237
239 238 def test_obj_del(self):
240 239 """Test that object's __del__ methods are called on exit."""
241 240 if sys.platform == 'win32':
242 241 try:
243 242 import win32api
244 243 except ImportError as e:
245 raise SkipTest("Test requires pywin32") from e
244 raise unittest.SkipTest("Test requires pywin32") from e
246 245 src = ("class A(object):\n"
247 246 " def __del__(self):\n"
248 247 " print('object A deleted')\n"
249 248 "a = A()\n")
250 249 self.mktmp(src)
251 250 err = None
252 251 tt.ipexec_validate(self.fname, 'object A deleted', err)
253
252
254 253 def test_aggressive_namespace_cleanup(self):
255 254 """Test that namespace cleanup is not too aggressive GH-238
256 255
257 256 Returning from another run magic deletes the namespace"""
258 257 # see ticket https://github.com/ipython/ipython/issues/238
259
258
260 259 with tt.TempFileMixin() as empty:
261 empty.mktmp('')
260 empty.mktmp("")
262 261 # On Windows, the filename will have \users in it, so we need to use the
263 262 # repr so that the \u becomes \\u.
264 src = ("ip = get_ipython()\n"
265 "for i in range(5):\n"
266 " try:\n"
267 " ip.magic(%r)\n"
268 " except NameError as e:\n"
269 " print(i)\n"
270 " break\n" % ('run ' + empty.fname))
263 src = (
264 "ip = get_ipython()\n"
265 "for i in range(5):\n"
266 " try:\n"
267 " ip.magic(%r)\n"
268 " except NameError as e:\n"
269 " print(i)\n"
270 " break\n" % ("run " + empty.fname)
271 )
271 272 self.mktmp(src)
272 _ip.magic('run %s' % self.fname)
273 _ip.run_cell('ip == get_ipython()')
274 nt.assert_equal(_ip.user_ns['i'], 4)
275
273 _ip.magic("run %s" % self.fname)
274 _ip.run_cell("ip == get_ipython()")
275 assert _ip.user_ns["i"] == 4
276
276 277 def test_run_second(self):
277 """Test that running a second file doesn't clobber the first, gh-3547
278 """
279 self.mktmp("avar = 1\n"
280 "def afunc():\n"
281 " return avar\n")
278 """Test that running a second file doesn't clobber the first, gh-3547"""
279 self.mktmp("avar = 1\n" "def afunc():\n" " return avar\n")
282 280
283 281 with tt.TempFileMixin() as empty:
284 282 empty.mktmp("")
285
286 _ip.magic('run %s' % self.fname)
287 _ip.magic('run %s' % empty.fname)
288 nt.assert_equal(_ip.user_ns['afunc'](), 1)
283
284 _ip.magic("run %s" % self.fname)
285 _ip.magic("run %s" % empty.fname)
286 assert _ip.user_ns["afunc"]() == 1
289 287
290 288 @dec.skip_win32
291 289 def test_tclass(self):
292 290 mydir = os.path.dirname(__file__)
293 291 tc = os.path.join(mydir, 'tclass')
294 292 src = ("%%run '%s' C-first\n"
295 293 "%%run '%s' C-second\n"
296 294 "%%run '%s' C-third\n") % (tc, tc, tc)
297 295 self.mktmp(src, '.ipy')
298 296 out = """\
299 297 ARGV 1-: ['C-first']
300 298 ARGV 1-: ['C-second']
301 299 tclass.py: deleting object: C-first
302 300 ARGV 1-: ['C-third']
303 301 tclass.py: deleting object: C-second
304 302 tclass.py: deleting object: C-third
305 303 """
306 304 err = None
307 305 tt.ipexec_validate(self.fname, out, err)
308 306
309 307 def test_run_i_after_reset(self):
310 308 """Check that %run -i still works after %reset (gh-693)"""
311 309 src = "yy = zz\n"
312 310 self.mktmp(src)
313 311 _ip.run_cell("zz = 23")
314 312 try:
315 _ip.magic('run -i %s' % self.fname)
316 nt.assert_equal(_ip.user_ns['yy'], 23)
313 _ip.magic("run -i %s" % self.fname)
314 assert _ip.user_ns["yy"] == 23
317 315 finally:
318 316 _ip.magic('reset -f')
319
317
320 318 _ip.run_cell("zz = 23")
321 319 try:
322 _ip.magic('run -i %s' % self.fname)
323 nt.assert_equal(_ip.user_ns['yy'], 23)
320 _ip.magic("run -i %s" % self.fname)
321 assert _ip.user_ns["yy"] == 23
324 322 finally:
325 323 _ip.magic('reset -f')
326
324
327 325 def test_unicode(self):
328 326 """Check that files in odd encodings are accepted."""
329 327 mydir = os.path.dirname(__file__)
330 328 na = os.path.join(mydir, 'nonascii.py')
331 329 _ip.magic('run "%s"' % na)
332 nt.assert_equal(_ip.user_ns['u'], u'Ўт№Ф')
330 assert _ip.user_ns["u"] == "Ўт№Ф"
333 331
334 332 def test_run_py_file_attribute(self):
335 333 """Test handling of `__file__` attribute in `%run <file>.py`."""
336 334 src = "t = __file__\n"
337 335 self.mktmp(src)
338 336 _missing = object()
339 337 file1 = _ip.user_ns.get('__file__', _missing)
340 338 _ip.magic('run %s' % self.fname)
341 339 file2 = _ip.user_ns.get('__file__', _missing)
342 340
343 341 # Check that __file__ was equal to the filename in the script's
344 342 # namespace.
345 nt.assert_equal(_ip.user_ns['t'], self.fname)
343 assert _ip.user_ns["t"] == self.fname
346 344
347 345 # Check that __file__ was not leaked back into user_ns.
348 nt.assert_equal(file1, file2)
346 assert file1 == file2
349 347
350 348 def test_run_ipy_file_attribute(self):
351 349 """Test handling of `__file__` attribute in `%run <file.ipy>`."""
352 350 src = "t = __file__\n"
353 351 self.mktmp(src, ext='.ipy')
354 352 _missing = object()
355 353 file1 = _ip.user_ns.get('__file__', _missing)
356 354 _ip.magic('run %s' % self.fname)
357 355 file2 = _ip.user_ns.get('__file__', _missing)
358 356
359 357 # Check that __file__ was equal to the filename in the script's
360 358 # namespace.
361 nt.assert_equal(_ip.user_ns['t'], self.fname)
359 assert _ip.user_ns["t"] == self.fname
362 360
363 361 # Check that __file__ was not leaked back into user_ns.
364 nt.assert_equal(file1, file2)
362 assert file1 == file2
365 363
366 364 def test_run_formatting(self):
367 365 """ Test that %run -t -N<N> does not raise a TypeError for N > 1."""
368 366 src = "pass"
369 367 self.mktmp(src)
370 368 _ip.magic('run -t -N 1 %s' % self.fname)
371 369 _ip.magic('run -t -N 10 %s' % self.fname)
372
370
373 371 def test_ignore_sys_exit(self):
374 372 """Test the -e option to ignore sys.exit()"""
375 373 src = "import sys; sys.exit(1)"
376 374 self.mktmp(src)
377 375 with tt.AssertPrints('SystemExit'):
378 376 _ip.magic('run %s' % self.fname)
379
377
380 378 with tt.AssertNotPrints('SystemExit'):
381 379 _ip.magic('run -e %s' % self.fname)
382 380
383 381 def test_run_nb(self):
384 382 """Test %run notebook.ipynb"""
385 383 from nbformat import v4, writes
386 384 nb = v4.new_notebook(
387 385 cells=[
388 386 v4.new_markdown_cell("The Ultimate Question of Everything"),
389 387 v4.new_code_cell("answer=42")
390 388 ]
391 389 )
392 390 src = writes(nb, version=4)
393 391 self.mktmp(src, ext='.ipynb')
394
392
395 393 _ip.magic("run %s" % self.fname)
396
397 nt.assert_equal(_ip.user_ns['answer'], 42)
394
395 assert _ip.user_ns["answer"] == 42
398 396
399 397 def test_run_nb_error(self):
400 398 """Test %run notebook.ipynb error"""
401 399 from nbformat import v4, writes
402 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 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 406 # %run on a notebook with an error
409 407 nb = v4.new_notebook(
410 408 cells=[
411 409 v4.new_code_cell("0/0")
412 410 ]
413 411 )
414 412 src = writes(nb, version=4)
415 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 416 def test_file_options(self):
419 417 src = ('import sys\n'
420 418 'a = " ".join(sys.argv[1:])\n')
421 419 self.mktmp(src)
422 test_opts = '-x 3 --verbose'
423 _ip.run_line_magic("run", '{0} {1}'.format(self.fname, test_opts))
424 nt.assert_equal(_ip.user_ns['a'], test_opts)
420 test_opts = "-x 3 --verbose"
421 _ip.run_line_magic("run", "{0} {1}".format(self.fname, test_opts))
422 assert _ip.user_ns["a"] == test_opts
425 423
426 424
427 425 class TestMagicRunWithPackage(unittest.TestCase):
428 426
429 427 def writefile(self, name, content):
430 428 path = os.path.join(self.tempdir.name, name)
431 429 d = os.path.dirname(path)
432 430 if not os.path.isdir(d):
433 431 os.makedirs(d)
434 432 with open(path, 'w') as f:
435 433 f.write(textwrap.dedent(content))
436 434
437 435 def setUp(self):
438 436 self.package = package = 'tmp{0}'.format(''.join([random.choice(string.ascii_letters) for i in range(10)]))
439 437 """Temporary (probably) valid python package name."""
440 438
441 439 self.value = int(random.random() * 10000)
442 440
443 441 self.tempdir = TemporaryDirectory()
444 442 self.__orig_cwd = os.getcwd()
445 443 sys.path.insert(0, self.tempdir.name)
446 444
447 445 self.writefile(os.path.join(package, '__init__.py'), '')
448 446 self.writefile(os.path.join(package, 'sub.py'), """
449 447 x = {0!r}
450 448 """.format(self.value))
451 449 self.writefile(os.path.join(package, 'relative.py'), """
452 450 from .sub import x
453 451 """)
454 452 self.writefile(os.path.join(package, 'absolute.py'), """
455 453 from {0}.sub import x
456 454 """.format(package))
457 455 self.writefile(os.path.join(package, 'args.py'), """
458 456 import sys
459 457 a = " ".join(sys.argv[1:])
460 458 """.format(package))
461 459
462 460 def tearDown(self):
463 461 os.chdir(self.__orig_cwd)
464 462 sys.path[:] = [p for p in sys.path if p != self.tempdir.name]
465 463 self.tempdir.cleanup()
466 464
467 465 def check_run_submodule(self, submodule, opts=''):
468 466 _ip.user_ns.pop('x', None)
469 467 _ip.magic('run {2} -m {0}.{1}'.format(self.package, submodule, opts))
470 468 self.assertEqual(_ip.user_ns['x'], self.value,
471 469 'Variable `x` is not loaded from module `{0}`.'
472 470 .format(submodule))
473 471
474 472 def test_run_submodule_with_absolute_import(self):
475 473 self.check_run_submodule('absolute')
476 474
477 475 def test_run_submodule_with_relative_import(self):
478 476 """Run submodule that has a relative import statement (#2727)."""
479 477 self.check_run_submodule('relative')
480 478
481 479 def test_prun_submodule_with_absolute_import(self):
482 480 self.check_run_submodule('absolute', '-p')
483 481
484 482 def test_prun_submodule_with_relative_import(self):
485 483 self.check_run_submodule('relative', '-p')
486 484
487 485 def with_fake_debugger(func):
488 486 @functools.wraps(func)
489 487 def wrapper(*args, **kwds):
490 488 with patch.object(debugger.Pdb, 'run', staticmethod(eval)):
491 489 return func(*args, **kwds)
492 490 return wrapper
493 491
494 492 @with_fake_debugger
495 493 def test_debug_run_submodule_with_absolute_import(self):
496 494 self.check_run_submodule('absolute', '-d')
497 495
498 496 @with_fake_debugger
499 497 def test_debug_run_submodule_with_relative_import(self):
500 498 self.check_run_submodule('relative', '-d')
501 499
502 500 def test_module_options(self):
503 _ip.user_ns.pop('a', None)
504 test_opts = '-x abc -m test'
505 _ip.run_line_magic('run', '-m {0}.args {1}'.format(self.package, test_opts))
506 nt.assert_equal(_ip.user_ns['a'], test_opts)
501 _ip.user_ns.pop("a", None)
502 test_opts = "-x abc -m test"
503 _ip.run_line_magic("run", "-m {0}.args {1}".format(self.package, test_opts))
504 assert _ip.user_ns["a"] == test_opts
507 505
508 506 def test_module_options_with_separator(self):
509 _ip.user_ns.pop('a', None)
510 test_opts = '-x abc -m test'
511 _ip.run_line_magic('run', '-m {0}.args -- {1}'.format(self.package, test_opts))
512 nt.assert_equal(_ip.user_ns['a'], test_opts)
507 _ip.user_ns.pop("a", None)
508 test_opts = "-x abc -m test"
509 _ip.run_line_magic("run", "-m {0}.args -- {1}".format(self.package, test_opts))
510 assert _ip.user_ns["a"] == test_opts
511
513 512
514 513 def test_run__name__():
515 514 with TemporaryDirectory() as td:
516 515 path = pjoin(td, 'foo.py')
517 516 with open(path, 'w') as f:
518 517 f.write("q = __name__")
519
520 _ip.user_ns.pop('q', None)
521 _ip.magic('run {}'.format(path))
522 nt.assert_equal(_ip.user_ns.pop('q'), '__main__')
523
524 _ip.magic('run -n {}'.format(path))
525 nt.assert_equal(_ip.user_ns.pop('q'), 'foo')
518
519 _ip.user_ns.pop("q", None)
520 _ip.magic("run {}".format(path))
521 assert _ip.user_ns.pop("q") == "__main__"
522
523 _ip.magic("run -n {}".format(path))
524 assert _ip.user_ns.pop("q") == "foo"
526 525
527 526 try:
528 _ip.magic('run -i -n {}'.format(path))
529 nt.assert_equal(_ip.user_ns.pop('q'), 'foo')
527 _ip.magic("run -i -n {}".format(path))
528 assert _ip.user_ns.pop("q") == "foo"
530 529 finally:
531 530 _ip.magic('reset -f')
532 531
533 532
534 533 def test_run_tb():
535 534 """Test traceback offset in %run"""
536 535 with TemporaryDirectory() as td:
537 536 path = pjoin(td, 'foo.py')
538 537 with open(path, 'w') as f:
539 538 f.write('\n'.join([
540 539 "def foo():",
541 540 " return bar()",
542 541 "def bar():",
543 542 " raise RuntimeError('hello!')",
544 543 "foo()",
545 544 ]))
546 545 with capture_output() as io:
547 546 _ip.magic('run {}'.format(path))
548 547 out = io.stdout
549 nt.assert_not_in("execfile", out)
550 nt.assert_in("RuntimeError", out)
551 nt.assert_equal(out.count("---->"), 3)
548 assert "execfile" not in out
549 assert "RuntimeError" in out
550 assert out.count("---->") == 3
552 551 del ip.user_ns['bar']
553 552 del ip.user_ns['foo']
554 553
555 554
556 555 def test_multiprocessing_run():
557 556 """Set we can run mutiprocesgin without messing up up main namespace
558 557
559 558 Note that import `nose.tools as nt` mdify the value s
560 559 sys.module['__mp_main__'] so we need to temporarily set it to None to test
561 560 the issue.
562 561 """
563 562 with TemporaryDirectory() as td:
564 563 mpm = sys.modules.get('__mp_main__')
565 564 assert mpm is not None
566 565 sys.modules['__mp_main__'] = None
567 566 try:
568 567 path = pjoin(td, 'test.py')
569 568 with open(path, 'w') as f:
570 569 f.write("import multiprocessing\nprint('hoy')")
571 570 with capture_output() as io:
572 571 _ip.run_line_magic('run', path)
573 572 _ip.run_cell("i_m_undefined")
574 573 out = io.stdout
575 nt.assert_in("hoy", out)
576 nt.assert_not_in("AttributeError", out)
577 nt.assert_in("NameError", out)
578 nt.assert_equal(out.count("---->"), 1)
574 assert "hoy" in out
575 assert "AttributeError" not in out
576 assert "NameError" in out
577 assert out.count("---->") == 1
579 578 except:
580 579 raise
581 580 finally:
582 581 sys.modules['__mp_main__'] = mpm
583 582
584 583 @dec.knownfailureif(sys.platform == 'win32', "writes to io.stdout aren't captured on Windows")
585 584 def test_script_tb():
586 585 """Test traceback offset in `ipython script.py`"""
587 586 with TemporaryDirectory() as td:
588 587 path = pjoin(td, 'foo.py')
589 588 with open(path, 'w') as f:
590 589 f.write('\n'.join([
591 590 "def foo():",
592 591 " return bar()",
593 592 "def bar():",
594 593 " raise RuntimeError('hello!')",
595 594 "foo()",
596 595 ]))
597 596 out, err = tt.ipexec(path)
598 nt.assert_not_in("execfile", out)
599 nt.assert_in("RuntimeError", out)
600 nt.assert_equal(out.count("---->"), 3)
601
597 assert "execfile" not in out
598 assert "RuntimeError" in out
599 assert out.count("---->") == 3
@@ -1,38 +1,38 b''
1 1 # coding: utf-8
2 import nose.tools as nt
3 2
4 3 from IPython.core.splitinput import split_user_input, LineInfo
5 4 from IPython.testing import tools as tt
6 5
7 6 tests = [
8 ('x=1', ('', '', 'x', '=1')),
9 ('?', ('', '?', '', '')),
10 ('??', ('', '??', '', '')),
11 (' ?', (' ', '?', '', '')),
12 (' ??', (' ', '??', '', '')),
13 ('??x', ('', '??', 'x', '')),
14 ('?x=1', ('', '?', 'x', '=1')),
15 ('!ls', ('', '!', 'ls', '')),
16 (' !ls', (' ', '!', 'ls', '')),
17 ('!!ls', ('', '!!', 'ls', '')),
18 (' !!ls', (' ', '!!', 'ls', '')),
19 (',ls', ('', ',', 'ls', '')),
20 (';ls', ('', ';', 'ls', '')),
21 (' ;ls', (' ', ';', 'ls', '')),
22 ('f.g(x)', ('', '', 'f.g', '(x)')),
23 ('f.g (x)', ('', '', 'f.g', '(x)')),
24 ('?%hist1', ('', '?', '%hist1', '')),
25 ('?%%hist2', ('', '?', '%%hist2', '')),
26 ('??%hist3', ('', '??', '%hist3', '')),
27 ('??%%hist4', ('', '??', '%%hist4', '')),
28 ('?x*', ('', '?', 'x*', '')),
29 ]
30 tests.append((u"Pérez Fernando", (u'', u'', u'Pérez', u'Fernando')))
7 ("x=1", ("", "", "x", "=1")),
8 ("?", ("", "?", "", "")),
9 ("??", ("", "??", "", "")),
10 (" ?", (" ", "?", "", "")),
11 (" ??", (" ", "??", "", "")),
12 ("??x", ("", "??", "x", "")),
13 ("?x=1", ("", "?", "x", "=1")),
14 ("!ls", ("", "!", "ls", "")),
15 (" !ls", (" ", "!", "ls", "")),
16 ("!!ls", ("", "!!", "ls", "")),
17 (" !!ls", (" ", "!!", "ls", "")),
18 (",ls", ("", ",", "ls", "")),
19 (";ls", ("", ";", "ls", "")),
20 (" ;ls", (" ", ";", "ls", "")),
21 ("f.g(x)", ("", "", "f.g", "(x)")),
22 ("f.g (x)", ("", "", "f.g", "(x)")),
23 ("?%hist1", ("", "?", "%hist1", "")),
24 ("?%%hist2", ("", "?", "%%hist2", "")),
25 ("??%hist3", ("", "??", "%hist3", "")),
26 ("??%%hist4", ("", "??", "%%hist4", "")),
27 ("?x*", ("", "?", "x*", "")),
28 ]
29 tests.append(("Pérez Fernando", ("", "", "Pérez", "Fernando")))
30
31 31
32 32 def test_split_user_input():
33 33 return tt.check_pairs(split_user_input, tests)
34 34
35 35 def test_LineInfo():
36 36 """Simple test for LineInfo construction and str()"""
37 linfo = LineInfo(' %cd /home')
38 nt.assert_equal(str(linfo), 'LineInfo [ |%|cd|/home]')
37 linfo = LineInfo(" %cd /home")
38 assert str(linfo) == "LineInfo [ |%|cd|/home]"
@@ -1,555 +1,554 b''
1 1 """Tests for autoreload extension.
2 2 """
3 3 # -----------------------------------------------------------------------------
4 4 # Copyright (c) 2012 IPython Development Team.
5 5 #
6 6 # Distributed under the terms of the Modified BSD License.
7 7 #
8 8 # The full license is in the file COPYING.txt, distributed with this software.
9 9 # -----------------------------------------------------------------------------
10 10
11 11 # -----------------------------------------------------------------------------
12 12 # Imports
13 13 # -----------------------------------------------------------------------------
14 14
15 15 import os
16 16 import sys
17 17 import tempfile
18 18 import textwrap
19 19 import shutil
20 20 import random
21 21 import time
22 22 from io import StringIO
23 23
24 import nose.tools as nt
25 24 import IPython.testing.tools as tt
26 25
27 26 from unittest import TestCase
28 27
29 28 from IPython.extensions.autoreload import AutoreloadMagics
30 29 from IPython.core.events import EventManager, pre_run_cell
31 30
32 31 # -----------------------------------------------------------------------------
33 32 # Test fixture
34 33 # -----------------------------------------------------------------------------
35 34
36 35 noop = lambda *a, **kw: None
37 36
38 37
39 38 class FakeShell:
40 39 def __init__(self):
41 40 self.ns = {}
42 41 self.user_ns = self.ns
43 42 self.user_ns_hidden = {}
44 43 self.events = EventManager(self, {"pre_run_cell", pre_run_cell})
45 44 self.auto_magics = AutoreloadMagics(shell=self)
46 45 self.events.register("pre_run_cell", self.auto_magics.pre_run_cell)
47 46
48 47 register_magics = set_hook = noop
49 48
50 49 def run_code(self, code):
51 50 self.events.trigger("pre_run_cell")
52 51 exec(code, self.user_ns)
53 52 self.auto_magics.post_execute_hook()
54 53
55 54 def push(self, items):
56 55 self.ns.update(items)
57 56
58 57 def magic_autoreload(self, parameter):
59 58 self.auto_magics.autoreload(parameter)
60 59
61 60 def magic_aimport(self, parameter, stream=None):
62 61 self.auto_magics.aimport(parameter, stream=stream)
63 62 self.auto_magics.post_execute_hook()
64 63
65 64
66 65 class Fixture(TestCase):
67 66 """Fixture for creating test module files"""
68 67
69 68 test_dir = None
70 69 old_sys_path = None
71 70 filename_chars = "abcdefghijklmopqrstuvwxyz0123456789"
72 71
73 72 def setUp(self):
74 73 self.test_dir = tempfile.mkdtemp()
75 74 self.old_sys_path = list(sys.path)
76 75 sys.path.insert(0, self.test_dir)
77 76 self.shell = FakeShell()
78 77
79 78 def tearDown(self):
80 79 shutil.rmtree(self.test_dir)
81 80 sys.path = self.old_sys_path
82 81
83 82 self.test_dir = None
84 83 self.old_sys_path = None
85 84 self.shell = None
86 85
87 86 def get_module(self):
88 87 module_name = "tmpmod_" + "".join(random.sample(self.filename_chars, 20))
89 88 if module_name in sys.modules:
90 89 del sys.modules[module_name]
91 90 file_name = os.path.join(self.test_dir, module_name + ".py")
92 91 return module_name, file_name
93 92
94 93 def write_file(self, filename, content):
95 94 """
96 95 Write a file, and force a timestamp difference of at least one second
97 96
98 97 Notes
99 98 -----
100 99 Python's .pyc files record the timestamp of their compilation
101 100 with a time resolution of one second.
102 101
103 102 Therefore, we need to force a timestamp difference between .py
104 103 and .pyc, without having the .py file be timestamped in the
105 104 future, and without changing the timestamp of the .pyc file
106 105 (because that is stored in the file). The only reliable way
107 106 to achieve this seems to be to sleep.
108 107 """
109 108 content = textwrap.dedent(content)
110 109 # Sleep one second + eps
111 110 time.sleep(1.05)
112 111
113 112 # Write
114 113 with open(filename, "w") as f:
115 114 f.write(content)
116 115
117 116 def new_module(self, code):
118 117 code = textwrap.dedent(code)
119 118 mod_name, mod_fn = self.get_module()
120 119 with open(mod_fn, "w") as f:
121 120 f.write(code)
122 121 return mod_name, mod_fn
123 122
124 123
125 124 # -----------------------------------------------------------------------------
126 125 # Test automatic reloading
127 126 # -----------------------------------------------------------------------------
128 127
129 128
130 129 def pickle_get_current_class(obj):
131 130 """
132 131 Original issue comes from pickle; hence the name.
133 132 """
134 133 name = obj.__class__.__name__
135 134 module_name = getattr(obj, "__module__", None)
136 135 obj2 = sys.modules[module_name]
137 136 for subpath in name.split("."):
138 137 obj2 = getattr(obj2, subpath)
139 138 return obj2
140 139
141 140
142 141 class TestAutoreload(Fixture):
143 142 def test_reload_enums(self):
144 143 mod_name, mod_fn = self.new_module(
145 144 textwrap.dedent(
146 145 """
147 146 from enum import Enum
148 147 class MyEnum(Enum):
149 148 A = 'A'
150 149 B = 'B'
151 150 """
152 151 )
153 152 )
154 153 self.shell.magic_autoreload("2")
155 154 self.shell.magic_aimport(mod_name)
156 155 self.write_file(
157 156 mod_fn,
158 157 textwrap.dedent(
159 158 """
160 159 from enum import Enum
161 160 class MyEnum(Enum):
162 161 A = 'A'
163 162 B = 'B'
164 163 C = 'C'
165 164 """
166 165 ),
167 166 )
168 167 with tt.AssertNotPrints(
169 168 ("[autoreload of %s failed:" % mod_name), channel="stderr"
170 169 ):
171 170 self.shell.run_code("pass") # trigger another reload
172 171
173 172 def test_reload_class_type(self):
174 173 self.shell.magic_autoreload("2")
175 174 mod_name, mod_fn = self.new_module(
176 175 """
177 176 class Test():
178 177 def meth(self):
179 178 return "old"
180 179 """
181 180 )
182 181 assert "test" not in self.shell.ns
183 182 assert "result" not in self.shell.ns
184 183
185 184 self.shell.run_code("from %s import Test" % mod_name)
186 185 self.shell.run_code("test = Test()")
187 186
188 187 self.write_file(
189 188 mod_fn,
190 189 """
191 190 class Test():
192 191 def meth(self):
193 192 return "new"
194 193 """,
195 194 )
196 195
197 196 test_object = self.shell.ns["test"]
198 197
199 198 # important to trigger autoreload logic !
200 199 self.shell.run_code("pass")
201 200
202 201 test_class = pickle_get_current_class(test_object)
203 202 assert isinstance(test_object, test_class)
204 203
205 204 # extra check.
206 205 self.shell.run_code("import pickle")
207 206 self.shell.run_code("p = pickle.dumps(test)")
208 207
209 208 def test_reload_class_attributes(self):
210 209 self.shell.magic_autoreload("2")
211 210 mod_name, mod_fn = self.new_module(
212 211 textwrap.dedent(
213 212 """
214 213 class MyClass:
215 214
216 215 def __init__(self, a=10):
217 216 self.a = a
218 217 self.b = 22
219 218 # self.toto = 33
220 219
221 220 def square(self):
222 221 print('compute square')
223 222 return self.a*self.a
224 223 """
225 224 )
226 225 )
227 226 self.shell.run_code("from %s import MyClass" % mod_name)
228 227 self.shell.run_code("first = MyClass(5)")
229 228 self.shell.run_code("first.square()")
230 with nt.assert_raises(AttributeError):
229 with self.assertRaises(AttributeError):
231 230 self.shell.run_code("first.cube()")
232 with nt.assert_raises(AttributeError):
231 with self.assertRaises(AttributeError):
233 232 self.shell.run_code("first.power(5)")
234 233 self.shell.run_code("first.b")
235 with nt.assert_raises(AttributeError):
234 with self.assertRaises(AttributeError):
236 235 self.shell.run_code("first.toto")
237 236
238 237 # remove square, add power
239 238
240 239 self.write_file(
241 240 mod_fn,
242 241 textwrap.dedent(
243 242 """
244 243 class MyClass:
245 244
246 245 def __init__(self, a=10):
247 246 self.a = a
248 247 self.b = 11
249 248
250 249 def power(self, p):
251 250 print('compute power '+str(p))
252 251 return self.a**p
253 252 """
254 253 ),
255 254 )
256 255
257 256 self.shell.run_code("second = MyClass(5)")
258 257
259 258 for object_name in {"first", "second"}:
260 259 self.shell.run_code(f"{object_name}.power(5)")
261 with nt.assert_raises(AttributeError):
260 with self.assertRaises(AttributeError):
262 261 self.shell.run_code(f"{object_name}.cube()")
263 with nt.assert_raises(AttributeError):
262 with self.assertRaises(AttributeError):
264 263 self.shell.run_code(f"{object_name}.square()")
265 264 self.shell.run_code(f"{object_name}.b")
266 265 self.shell.run_code(f"{object_name}.a")
267 with nt.assert_raises(AttributeError):
266 with self.assertRaises(AttributeError):
268 267 self.shell.run_code(f"{object_name}.toto")
269 268
270 269 def test_autoload_newly_added_objects(self):
271 270 self.shell.magic_autoreload("3")
272 271 mod_code = """
273 272 def func1(): pass
274 273 """
275 274 mod_name, mod_fn = self.new_module(textwrap.dedent(mod_code))
276 275 self.shell.run_code(f"from {mod_name} import *")
277 276 self.shell.run_code("func1()")
278 with nt.assert_raises(NameError):
277 with self.assertRaises(NameError):
279 278 self.shell.run_code("func2()")
280 with nt.assert_raises(NameError):
279 with self.assertRaises(NameError):
281 280 self.shell.run_code("t = Test()")
282 with nt.assert_raises(NameError):
281 with self.assertRaises(NameError):
283 282 self.shell.run_code("number")
284 283
285 284 # ----------- TEST NEW OBJ LOADED --------------------------
286 285
287 286 new_code = """
288 287 def func1(): pass
289 288 def func2(): pass
290 289 class Test: pass
291 290 number = 0
292 291 from enum import Enum
293 292 class TestEnum(Enum):
294 293 A = 'a'
295 294 """
296 295 self.write_file(mod_fn, textwrap.dedent(new_code))
297 296
298 297 # test function now exists in shell's namespace namespace
299 298 self.shell.run_code("func2()")
300 299 # test function now exists in module's dict
301 300 self.shell.run_code(f"import sys; sys.modules['{mod_name}'].func2()")
302 301 # test class now exists
303 302 self.shell.run_code("t = Test()")
304 303 # test global built-in var now exists
305 304 self.shell.run_code("number")
306 305 # test the enumerations gets loaded successfully
307 306 self.shell.run_code("TestEnum.A")
308 307
309 308 # ----------- TEST NEW OBJ CAN BE CHANGED --------------------
310 309
311 310 new_code = """
312 311 def func1(): return 'changed'
313 312 def func2(): return 'changed'
314 313 class Test:
315 314 def new_func(self):
316 315 return 'changed'
317 316 number = 1
318 317 from enum import Enum
319 318 class TestEnum(Enum):
320 319 A = 'a'
321 320 B = 'added'
322 321 """
323 322 self.write_file(mod_fn, textwrap.dedent(new_code))
324 323 self.shell.run_code("assert func1() == 'changed'")
325 324 self.shell.run_code("assert func2() == 'changed'")
326 325 self.shell.run_code("t = Test(); assert t.new_func() == 'changed'")
327 326 self.shell.run_code("assert number == 1")
328 327 self.shell.run_code("assert TestEnum.B.value == 'added'")
329 328
330 329 # ----------- TEST IMPORT FROM MODULE --------------------------
331 330
332 331 new_mod_code = """
333 332 from enum import Enum
334 333 class Ext(Enum):
335 334 A = 'ext'
336 335 def ext_func():
337 336 return 'ext'
338 337 class ExtTest:
339 338 def meth(self):
340 339 return 'ext'
341 340 ext_int = 2
342 341 """
343 342 new_mod_name, new_mod_fn = self.new_module(textwrap.dedent(new_mod_code))
344 343 current_mod_code = f"""
345 344 from {new_mod_name} import *
346 345 """
347 346 self.write_file(mod_fn, textwrap.dedent(current_mod_code))
348 347 self.shell.run_code("assert Ext.A.value == 'ext'")
349 348 self.shell.run_code("assert ext_func() == 'ext'")
350 349 self.shell.run_code("t = ExtTest(); assert t.meth() == 'ext'")
351 350 self.shell.run_code("assert ext_int == 2")
352 351
353 352 def _check_smoketest(self, use_aimport=True):
354 353 """
355 354 Functional test for the automatic reloader using either
356 355 '%autoreload 1' or '%autoreload 2'
357 356 """
358 357
359 358 mod_name, mod_fn = self.new_module(
360 359 """
361 360 x = 9
362 361
363 362 z = 123 # this item will be deleted
364 363
365 364 def foo(y):
366 365 return y + 3
367 366
368 367 class Baz(object):
369 368 def __init__(self, x):
370 369 self.x = x
371 370 def bar(self, y):
372 371 return self.x + y
373 372 @property
374 373 def quux(self):
375 374 return 42
376 375 def zzz(self):
377 376 '''This method will be deleted below'''
378 377 return 99
379 378
380 379 class Bar: # old-style class: weakref doesn't work for it on Python < 2.7
381 380 def foo(self):
382 381 return 1
383 382 """
384 383 )
385 384
386 385 #
387 386 # Import module, and mark for reloading
388 387 #
389 388 if use_aimport:
390 389 self.shell.magic_autoreload("1")
391 390 self.shell.magic_aimport(mod_name)
392 391 stream = StringIO()
393 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 396 self.shell.magic_aimport("tmpmod_as318989e89ds")
398 397 else:
399 398 self.shell.magic_autoreload("2")
400 399 self.shell.run_code("import %s" % mod_name)
401 400 stream = StringIO()
402 401 self.shell.magic_aimport("", stream=stream)
403 nt.assert_true(
402 self.assertTrue(
404 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 407 mod = sys.modules[mod_name]
409 408
410 409 #
411 410 # Test module contents
412 411 #
413 412 old_foo = mod.foo
414 413 old_obj = mod.Baz(9)
415 414 old_obj2 = mod.Bar()
416 415
417 416 def check_module_contents():
418 nt.assert_equal(mod.x, 9)
419 nt.assert_equal(mod.z, 123)
417 self.assertEqual(mod.x, 9)
418 self.assertEqual(mod.z, 123)
420 419
421 nt.assert_equal(old_foo(0), 3)
422 nt.assert_equal(mod.foo(0), 3)
420 self.assertEqual(old_foo(0), 3)
421 self.assertEqual(mod.foo(0), 3)
423 422
424 423 obj = mod.Baz(9)
425 nt.assert_equal(old_obj.bar(1), 10)
426 nt.assert_equal(obj.bar(1), 10)
427 nt.assert_equal(obj.quux, 42)
428 nt.assert_equal(obj.zzz(), 99)
424 self.assertEqual(old_obj.bar(1), 10)
425 self.assertEqual(obj.bar(1), 10)
426 self.assertEqual(obj.quux, 42)
427 self.assertEqual(obj.zzz(), 99)
429 428
430 429 obj2 = mod.Bar()
431 nt.assert_equal(old_obj2.foo(), 1)
432 nt.assert_equal(obj2.foo(), 1)
430 self.assertEqual(old_obj2.foo(), 1)
431 self.assertEqual(obj2.foo(), 1)
433 432
434 433 check_module_contents()
435 434
436 435 #
437 436 # Simulate a failed reload: no reload should occur and exactly
438 437 # one error message should be printed
439 438 #
440 439 self.write_file(
441 440 mod_fn,
442 441 """
443 442 a syntax error
444 443 """,
445 444 )
446 445
447 446 with tt.AssertPrints(
448 447 ("[autoreload of %s failed:" % mod_name), channel="stderr"
449 448 ):
450 449 self.shell.run_code("pass") # trigger reload
451 450 with tt.AssertNotPrints(
452 451 ("[autoreload of %s failed:" % mod_name), channel="stderr"
453 452 ):
454 453 self.shell.run_code("pass") # trigger another reload
455 454 check_module_contents()
456 455
457 456 #
458 457 # Rewrite module (this time reload should succeed)
459 458 #
460 459 self.write_file(
461 460 mod_fn,
462 461 """
463 462 x = 10
464 463
465 464 def foo(y):
466 465 return y + 4
467 466
468 467 class Baz(object):
469 468 def __init__(self, x):
470 469 self.x = x
471 470 def bar(self, y):
472 471 return self.x + y + 1
473 472 @property
474 473 def quux(self):
475 474 return 43
476 475
477 476 class Bar: # old-style class
478 477 def foo(self):
479 478 return 2
480 479 """,
481 480 )
482 481
483 482 def check_module_contents():
484 nt.assert_equal(mod.x, 10)
485 nt.assert_false(hasattr(mod, "z"))
483 self.assertEqual(mod.x, 10)
484 self.assertFalse(hasattr(mod, "z"))
486 485
487 nt.assert_equal(old_foo(0), 4) # superreload magic!
488 nt.assert_equal(mod.foo(0), 4)
486 self.assertEqual(old_foo(0), 4) # superreload magic!
487 self.assertEqual(mod.foo(0), 4)
489 488
490 489 obj = mod.Baz(9)
491 nt.assert_equal(old_obj.bar(1), 11) # superreload magic!
492 nt.assert_equal(obj.bar(1), 11)
490 self.assertEqual(old_obj.bar(1), 11) # superreload magic!
491 self.assertEqual(obj.bar(1), 11)
493 492
494 nt.assert_equal(old_obj.quux, 43)
495 nt.assert_equal(obj.quux, 43)
493 self.assertEqual(old_obj.quux, 43)
494 self.assertEqual(obj.quux, 43)
496 495
497 nt.assert_false(hasattr(old_obj, "zzz"))
498 nt.assert_false(hasattr(obj, "zzz"))
496 self.assertFalse(hasattr(old_obj, "zzz"))
497 self.assertFalse(hasattr(obj, "zzz"))
499 498
500 499 obj2 = mod.Bar()
501 nt.assert_equal(old_obj2.foo(), 2)
502 nt.assert_equal(obj2.foo(), 2)
500 self.assertEqual(old_obj2.foo(), 2)
501 self.assertEqual(obj2.foo(), 2)
503 502
504 503 self.shell.run_code("pass") # trigger reload
505 504 check_module_contents()
506 505
507 506 #
508 507 # Another failure case: deleted file (shouldn't reload)
509 508 #
510 509 os.unlink(mod_fn)
511 510
512 511 self.shell.run_code("pass") # trigger reload
513 512 check_module_contents()
514 513
515 514 #
516 515 # Disable autoreload and rewrite module: no reload should occur
517 516 #
518 517 if use_aimport:
519 518 self.shell.magic_aimport("-" + mod_name)
520 519 stream = StringIO()
521 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 523 # This should succeed, although no such module exists
525 524 self.shell.magic_aimport("-tmpmod_as318989e89ds")
526 525 else:
527 526 self.shell.magic_autoreload("0")
528 527
529 528 self.write_file(
530 529 mod_fn,
531 530 """
532 531 x = -99
533 532 """,
534 533 )
535 534
536 535 self.shell.run_code("pass") # trigger reload
537 536 self.shell.run_code("pass")
538 537 check_module_contents()
539 538
540 539 #
541 540 # Re-enable autoreload: reload should now occur
542 541 #
543 542 if use_aimport:
544 543 self.shell.magic_aimport(mod_name)
545 544 else:
546 545 self.shell.magic_autoreload("")
547 546
548 547 self.shell.run_code("pass") # trigger reload
549 nt.assert_equal(mod.x, -99)
548 self.assertEqual(mod.x, -99)
550 549
551 550 def test_smoketest_aimport(self):
552 551 self._check_smoketest(use_aimport=True)
553 552
554 553 def test_smoketest_autoreload(self):
555 554 self._check_smoketest(use_aimport=False)
@@ -1,66 +1,65 b''
1 1 import tempfile, os
2 2
3 3 from traitlets.config.loader import Config
4 import nose.tools as nt
5 4
6 5
7 6 def setup_module():
8 7 ip.magic('load_ext storemagic')
9 8
10 9 def test_store_restore():
11 10 assert 'bar' not in ip.user_ns, "Error: some other test leaked `bar` in user_ns"
12 11 assert 'foo' not in ip.user_ns, "Error: some other test leaked `foo` in user_ns"
13 12 assert 'foobar' not in ip.user_ns, "Error: some other test leaked `foobar` in user_ns"
14 13 assert 'foobaz' not in ip.user_ns, "Error: some other test leaked `foobaz` in user_ns"
15 14 ip.user_ns['foo'] = 78
16 15 ip.magic('alias bar echo "hello"')
17 16 ip.user_ns['foobar'] = 79
18 17 ip.user_ns['foobaz'] = '80'
19 18 tmpd = tempfile.mkdtemp()
20 19 ip.magic('cd ' + tmpd)
21 20 ip.magic('store foo')
22 21 ip.magic('store bar')
23 22 ip.magic('store foobar foobaz')
24 23
25 24 # Check storing
26 nt.assert_equal(ip.db['autorestore/foo'], 78)
27 nt.assert_in('bar', ip.db['stored_aliases'])
28 nt.assert_equal(ip.db['autorestore/foobar'], 79)
29 nt.assert_equal(ip.db['autorestore/foobaz'], '80')
25 assert ip.db["autorestore/foo"] == 78
26 assert "bar" in ip.db["stored_aliases"]
27 assert ip.db["autorestore/foobar"] == 79
28 assert ip.db["autorestore/foobaz"] == "80"
30 29
31 30 # Remove those items
32 31 ip.user_ns.pop('foo', None)
33 32 ip.user_ns.pop('foobar', None)
34 33 ip.user_ns.pop('foobaz', None)
35 34 ip.alias_manager.undefine_alias('bar')
36 35 ip.magic('cd -')
37 36 ip.user_ns['_dh'][:] = []
38 37
39 38 # Check restoring
40 ip.magic('store -r foo bar foobar foobaz')
41 nt.assert_equal(ip.user_ns['foo'], 78)
42 assert ip.alias_manager.is_alias('bar')
43 nt.assert_equal(ip.user_ns['foobar'], 79)
44 nt.assert_equal(ip.user_ns['foobaz'], '80')
39 ip.magic("store -r foo bar foobar foobaz")
40 assert ip.user_ns["foo"] == 78
41 assert ip.alias_manager.is_alias("bar")
42 assert ip.user_ns["foobar"] == 79
43 assert ip.user_ns["foobaz"] == "80"
45 44
46 ip.magic('store -r') # restores _dh too
47 nt.assert_in(os.path.realpath(tmpd), ip.user_ns['_dh'])
45 ip.magic("store -r") # restores _dh too
46 assert os.path.realpath(tmpd) in ip.user_ns["_dh"]
48 47
49 48 os.rmdir(tmpd)
50 49
51 50 def test_autorestore():
52 51 ip.user_ns['foo'] = 95
53 52 ip.magic('store foo')
54 53 del ip.user_ns['foo']
55 54 c = Config()
56 55 c.StoreMagics.autorestore = False
57 56 orig_config = ip.config
58 57 try:
59 58 ip.config = c
60 ip.extension_manager.reload_extension('storemagic')
61 nt.assert_not_in('foo', ip.user_ns)
59 ip.extension_manager.reload_extension("storemagic")
60 assert "foo" not in ip.user_ns
62 61 c.StoreMagics.autorestore = True
63 ip.extension_manager.reload_extension('storemagic')
64 nt.assert_equal(ip.user_ns['foo'], 95)
62 ip.extension_manager.reload_extension("storemagic")
63 assert ip.user_ns["foo"] == 95
65 64 finally:
66 65 ip.config = orig_config
@@ -1,21 +1,19 b''
1 import nose.tools as nt
2
3 1 from IPython.core.error import TryNext
4 2 from IPython.lib.clipboard import ClipboardEmpty
5 3 from IPython.testing.decorators import skip_if_no_x11
6 4
7 5 @skip_if_no_x11
8 6 def test_clipboard_get():
9 7 # Smoketest for clipboard access - we can't easily guarantee that the
10 8 # clipboard is accessible and has something on it, but this tries to
11 9 # exercise the relevant code anyway.
12 10 try:
13 11 a = get_ipython().hooks.clipboard_get()
14 12 except ClipboardEmpty:
15 13 # Nothing in clipboard to get
16 14 pass
17 15 except TryNext:
18 16 # No clipboard access API available
19 17 pass
20 18 else:
21 nt.assert_is_instance(a, str)
19 assert isinstance(a, str)
@@ -1,36 +1,34 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Test suite for the deepreload module."""
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7 from pathlib import Path
8 8
9 import nose.tools as nt
10
11 9 from IPython.utils.syspathcontext import prepended_to_syspath
12 10 from IPython.utils.tempdir import TemporaryDirectory
13 11 from IPython.lib.deepreload import reload as dreload
14 12
15 13
16 14 def test_deepreload():
17 15 "Test that dreload does deep reloads and skips excluded modules."
18 16 with TemporaryDirectory() as tmpdir:
19 17 with prepended_to_syspath(tmpdir):
20 18 tmpdirpath = Path(tmpdir)
21 19 with open(tmpdirpath / "A.py", "w") as f:
22 20 f.write("class Object(object):\n pass\n")
23 21 with open(tmpdirpath / "B.py", "w") as f:
24 22 f.write("import A\n")
25 23 import A
26 24 import B
27 25
28 26 # Test that A is not reloaded.
29 27 obj = A.Object()
30 28 dreload(B, exclude=["A"])
31 nt.assert_true(isinstance(obj, A.Object))
29 assert isinstance(obj, A.Object) is True
32 30
33 31 # Test that A is reloaded.
34 32 obj = A.Object()
35 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 1 """Tests for IPython.lib.display.
2 2
3 3 """
4 4 #-----------------------------------------------------------------------------
5 5 # Copyright (c) 2012, the IPython Development Team.
6 6 #
7 7 # Distributed under the terms of the Modified BSD License.
8 8 #
9 9 # The full license is in the file COPYING.txt, distributed with this software.
10 10 #-----------------------------------------------------------------------------
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Imports
14 14 #-----------------------------------------------------------------------------
15 15 from tempfile import NamedTemporaryFile, mkdtemp
16 16 from os.path import split, join as pjoin, dirname
17 17 import pathlib
18 18 from unittest import TestCase, mock
19 19 import struct
20 20 import wave
21 21 from io import BytesIO
22 22
23 23 # Third-party imports
24 import nose.tools as nt
24 import pytest
25 25
26 26 try:
27 27 import numpy
28 28 except ImportError:
29 29 pass
30 30
31 31 # Our own imports
32 32 from IPython.lib import display
33 33
34 34 from IPython.testing.decorators import skipif_not_numpy
35 35
36 36 #-----------------------------------------------------------------------------
37 37 # Classes and functions
38 38 #-----------------------------------------------------------------------------
39 39
40 40 #--------------------------
41 41 # FileLink tests
42 42 #--------------------------
43 43
44 44 def test_instantiation_FileLink():
45 45 """FileLink: Test class can be instantiated"""
46 46 fl = display.FileLink('example.txt')
47 47 # TODO: remove if when only Python >= 3.6 is supported
48 48 fl = display.FileLink(pathlib.PurePath('example.txt'))
49 49
50 50 def test_warning_on_non_existent_path_FileLink():
51 """FileLink: Calling _repr_html_ on non-existent files returns a warning
52 """
53 fl = display.FileLink('example.txt')
54 nt.assert_true(fl._repr_html_().startswith('Path (<tt>example.txt</tt>)'))
51 """FileLink: Calling _repr_html_ on non-existent files returns a warning"""
52 fl = display.FileLink("example.txt")
53 assert fl._repr_html_().startswith("Path (<tt>example.txt</tt>)")
54
55 55
56 56 def test_existing_path_FileLink():
57 57 """FileLink: Calling _repr_html_ functions as expected on existing filepath
58 58 """
59 59 tf = NamedTemporaryFile()
60 60 fl = display.FileLink(tf.name)
61 61 actual = fl._repr_html_()
62 62 expected = "<a href='%s' target='_blank'>%s</a><br>" % (tf.name, tf.name)
63 63 assert actual == expected
64 64
65 65
66 66 def test_existing_path_FileLink_repr():
67 67 """FileLink: Calling repr() functions as expected on existing filepath
68 68 """
69 69 tf = NamedTemporaryFile()
70 70 fl = display.FileLink(tf.name)
71 71 actual = repr(fl)
72 72 expected = tf.name
73 73 assert actual == expected
74 74
75 75
76 76 def test_error_on_directory_to_FileLink():
77 77 """FileLink: Raises error when passed directory
78 78 """
79 79 td = mkdtemp()
80 nt.assert_raises(ValueError,display.FileLink,td)
80 pytest.raises(ValueError, display.FileLink, td)
81 81
82 82 #--------------------------
83 83 # FileLinks tests
84 84 #--------------------------
85 85
86 86 def test_instantiation_FileLinks():
87 87 """FileLinks: Test class can be instantiated
88 88 """
89 89 fls = display.FileLinks('example')
90 90
91 91 def test_warning_on_non_existent_path_FileLinks():
92 """FileLinks: Calling _repr_html_ on non-existent files returns a warning
93 """
94 fls = display.FileLinks('example')
95 nt.assert_true(fls._repr_html_().startswith('Path (<tt>example</tt>)'))
92 """FileLinks: Calling _repr_html_ on non-existent files returns a warning"""
93 fls = display.FileLinks("example")
94 assert fls._repr_html_().startswith("Path (<tt>example</tt>)")
95
96 96
97 97 def test_existing_path_FileLinks():
98 98 """FileLinks: Calling _repr_html_ functions as expected on existing dir
99 99 """
100 100 td = mkdtemp()
101 101 tf1 = NamedTemporaryFile(dir=td)
102 102 tf2 = NamedTemporaryFile(dir=td)
103 103 fl = display.FileLinks(td)
104 104 actual = fl._repr_html_()
105 105 actual = actual.split('\n')
106 106 actual.sort()
107 107 # the links should always have forward slashes, even on windows, so replace
108 108 # backslashes with forward slashes here
109 109 expected = ["%s/<br>" % td,
110 110 "&nbsp;&nbsp;<a href='%s' target='_blank'>%s</a><br>" %\
111 111 (tf2.name.replace("\\","/"),split(tf2.name)[1]),
112 112 "&nbsp;&nbsp;<a href='%s' target='_blank'>%s</a><br>" %\
113 113 (tf1.name.replace("\\","/"),split(tf1.name)[1])]
114 114 expected.sort()
115 115 # We compare the sorted list of links here as that's more reliable
116 116 assert actual == expected
117 117
118 118
119 119 def test_existing_path_FileLinks_alt_formatter():
120 120 """FileLinks: Calling _repr_html_ functions as expected w/ an alt formatter
121 121 """
122 122 td = mkdtemp()
123 123 tf1 = NamedTemporaryFile(dir=td)
124 124 tf2 = NamedTemporaryFile(dir=td)
125 125 def fake_formatter(dirname,fnames,included_suffixes):
126 126 return ["hello","world"]
127 127 fl = display.FileLinks(td,notebook_display_formatter=fake_formatter)
128 128 actual = fl._repr_html_()
129 129 actual = actual.split('\n')
130 130 actual.sort()
131 131 expected = ["hello","world"]
132 132 expected.sort()
133 133 # We compare the sorted list of links here as that's more reliable
134 134 assert actual == expected
135 135
136 136
137 137 def test_existing_path_FileLinks_repr():
138 138 """FileLinks: Calling repr() functions as expected on existing directory """
139 139 td = mkdtemp()
140 140 tf1 = NamedTemporaryFile(dir=td)
141 141 tf2 = NamedTemporaryFile(dir=td)
142 142 fl = display.FileLinks(td)
143 143 actual = repr(fl)
144 144 actual = actual.split('\n')
145 145 actual.sort()
146 146 expected = ['%s/' % td, ' %s' % split(tf1.name)[1],' %s' % split(tf2.name)[1]]
147 147 expected.sort()
148 148 # We compare the sorted list of links here as that's more reliable
149 149 assert actual == expected
150 150
151 151
152 152 def test_existing_path_FileLinks_repr_alt_formatter():
153 153 """FileLinks: Calling repr() functions as expected w/ alt formatter
154 154 """
155 155 td = mkdtemp()
156 156 tf1 = NamedTemporaryFile(dir=td)
157 157 tf2 = NamedTemporaryFile(dir=td)
158 158 def fake_formatter(dirname,fnames,included_suffixes):
159 159 return ["hello","world"]
160 160 fl = display.FileLinks(td,terminal_display_formatter=fake_formatter)
161 161 actual = repr(fl)
162 162 actual = actual.split('\n')
163 163 actual.sort()
164 164 expected = ["hello","world"]
165 165 expected.sort()
166 166 # We compare the sorted list of links here as that's more reliable
167 167 assert actual == expected
168 168
169 169
170 170 def test_error_on_file_to_FileLinks():
171 171 """FileLinks: Raises error when passed file
172 172 """
173 173 td = mkdtemp()
174 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 178 def test_recursive_FileLinks():
178 179 """FileLinks: Does not recurse when recursive=False
179 180 """
180 181 td = mkdtemp()
181 182 tf = NamedTemporaryFile(dir=td)
182 183 subtd = mkdtemp(dir=td)
183 184 subtf = NamedTemporaryFile(dir=subtd)
184 185 fl = display.FileLinks(td)
185 186 actual = str(fl)
186 187 actual = actual.split('\n')
187 188 assert len(actual) == 4, actual
188 189 fl = display.FileLinks(td, recursive=False)
189 190 actual = str(fl)
190 191 actual = actual.split('\n')
191 192 assert len(actual) == 2, actual
192 193
193 194 def test_audio_from_file():
194 195 path = pjoin(dirname(__file__), 'test.wav')
195 196 display.Audio(filename=path)
196 197
197 198 class TestAudioDataWithNumpy(TestCase):
198 199
199 200 @skipif_not_numpy
200 201 def test_audio_from_numpy_array(self):
201 202 test_tone = get_test_tone()
202 203 audio = display.Audio(test_tone, rate=44100)
203 204 assert len(read_wav(audio.data)) == len(test_tone)
204 205
205 206 @skipif_not_numpy
206 207 def test_audio_from_list(self):
207 208 test_tone = get_test_tone()
208 209 audio = display.Audio(list(test_tone), rate=44100)
209 210 assert len(read_wav(audio.data)) == len(test_tone)
210 211
211 212 @skipif_not_numpy
212 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 216 @skipif_not_numpy
216 217 def test_audio_data_normalization(self):
217 218 expected_max_value = numpy.iinfo(numpy.int16).max
218 219 for scale in [1, 0.5, 2]:
219 220 audio = display.Audio(get_test_tone(scale), rate=44100)
220 221 actual_max_value = numpy.max(numpy.abs(read_wav(audio.data)))
221 222 assert actual_max_value == expected_max_value
222 223
223 224 @skipif_not_numpy
224 225 def test_audio_data_without_normalization(self):
225 226 max_int16 = numpy.iinfo(numpy.int16).max
226 227 for scale in [1, 0.5, 0.2]:
227 228 test_tone = get_test_tone(scale)
228 229 test_tone_max_abs = numpy.max(numpy.abs(test_tone))
229 230 expected_max_value = int(max_int16 * test_tone_max_abs)
230 231 audio = display.Audio(test_tone, rate=44100, normalize=False)
231 232 actual_max_value = numpy.max(numpy.abs(read_wav(audio.data)))
232 233 assert actual_max_value == expected_max_value
233 234
234 235 def test_audio_data_without_normalization_raises_for_invalid_data(self):
235 nt.assert_raises(
236 self.assertRaises(
236 237 ValueError,
237 238 lambda: display.Audio([1.001], rate=44100, normalize=False))
238 nt.assert_raises(
239 self.assertRaises(
239 240 ValueError,
240 241 lambda: display.Audio([-1.001], rate=44100, normalize=False))
241 242
242 243 def simulate_numpy_not_installed():
243 244 try:
244 245 import numpy
245 246 return mock.patch('numpy.array', mock.MagicMock(side_effect=ImportError))
246 247 except ModuleNotFoundError:
247 248 return lambda x:x
248 249
249 250 @simulate_numpy_not_installed()
250 251 class TestAudioDataWithoutNumpy(TestAudioDataWithNumpy):
251 252 # All tests from `TestAudioDataWithNumpy` are inherited.
252 253
253 254 @skipif_not_numpy
254 255 def test_audio_raises_for_nested_list(self):
255 256 stereo_signal = [list(get_test_tone())] * 2
256 nt.assert_raises(
257 TypeError,
258 lambda: display.Audio(stereo_signal, rate=44100))
257 self.assertRaises(TypeError, lambda: display.Audio(stereo_signal, rate=44100))
258
259 259
260 260 @skipif_not_numpy
261 261 def get_test_tone(scale=1):
262 262 return numpy.sin(2 * numpy.pi * 440 * numpy.linspace(0, 1, 44100)) * scale
263 263
264 264 def read_wav(data):
265 265 with wave.open(BytesIO(data)) as wave_file:
266 266 wave_data = wave_file.readframes(wave_file.getnframes())
267 267 num_samples = wave_file.getnframes() * wave_file.getnchannels()
268 268 return struct.unpack('<%sh' % num_samples, wave_data)
269 269
270 270 def test_code_from_file():
271 271 c = display.Code(filename=__file__)
272 272 assert c._repr_html_().startswith('<style>')
@@ -1,191 +1,196 b''
1 1 """Tests for IPython.utils.path.py"""
2 2 # Copyright (c) IPython Development Team.
3 3 # Distributed under the terms of the Modified BSD License.
4 4
5 5 from contextlib import contextmanager
6 6 from unittest.mock import patch
7 7
8 import nose.tools as nt
9 8 import pytest
10 9
11 10 from IPython.lib import latextools
12 11 from IPython.testing.decorators import (
13 12 onlyif_cmds_exist,
14 13 skipif_not_matplotlib,
15 14 skip_iptest_but_not_pytest,
16 15 )
17 16 from IPython.utils.process import FindCmdError
18 17
19 18
20 19 @pytest.mark.parametrize('command', ['latex', 'dvipng'])
21 20 @skip_iptest_but_not_pytest
22 21 def test_check_latex_to_png_dvipng_fails_when_no_cmd(command):
23 22 def mock_find_cmd(arg):
24 23 if arg == command:
25 24 raise FindCmdError
26 25
27 26 with patch.object(latextools, "find_cmd", mock_find_cmd):
28 27 assert latextools.latex_to_png_dvipng("whatever", True) is None
29 28
30 29
31 30 @contextmanager
32 31 def no_op(*args, **kwargs):
33 32 yield
34 33
35 34
36 35 @skip_iptest_but_not_pytest
37 36 @onlyif_cmds_exist("latex", "dvipng")
38 37 @pytest.mark.parametrize("s, wrap", [(u"$$x^2$$", False), (u"x^2", True)])
39 38 def test_latex_to_png_dvipng_runs(s, wrap):
40 39 """
41 40 Test that latex_to_png_dvipng just runs without error.
42 41 """
43 42 def mock_kpsewhich(filename):
44 43 assert filename == "breqn.sty"
45 44 return None
46 45
47 46 latextools.latex_to_png_dvipng(s, wrap)
48 47
49 48 with patch_latextool(mock_kpsewhich):
50 49 latextools.latex_to_png_dvipng(s, wrap)
51 50
52 51
53 52 def mock_kpsewhich(filename):
54 53 assert filename == "breqn.sty"
55 54 return None
56 55
57 56 @contextmanager
58 57 def patch_latextool(mock=mock_kpsewhich):
59 58 with patch.object(latextools, "kpsewhich", mock):
60 59 yield
61 60
62 61 @pytest.mark.parametrize('context', [no_op, patch_latextool])
63 62 @pytest.mark.parametrize('s_wrap', [("$x^2$", False), ("x^2", True)])
64 63 @skip_iptest_but_not_pytest
65 64 def test_latex_to_png_mpl_runs(s_wrap, context):
66 65 """
67 66 Test that latex_to_png_mpl just runs without error.
68 67 """
69 68 try:
70 69 import matplotlib
71 70 except ImportError:
72 71 pytest.skip("This needs matplotlib to be available")
73 72 return
74 73 s, wrap = s_wrap
75 74 with context():
76 75 latextools.latex_to_png_mpl(s, wrap)
77 76
78 77 @skipif_not_matplotlib
79 78 def test_latex_to_html():
80 79 img = latextools.latex_to_html("$x^2$")
81 80 assert "data:image/png;base64,iVBOR" in img
82 81
83 82
84 83 def test_genelatex_no_wrap():
85 84 """
86 85 Test genelatex with wrap=False.
87 86 """
88 87 def mock_kpsewhich(filename):
89 88 assert False, ("kpsewhich should not be called "
90 89 "(called with {0})".format(filename))
91 90
92 91 with patch_latextool(mock_kpsewhich):
93 92 assert '\n'.join(latextools.genelatex("body text", False)) == r'''\documentclass{article}
94 93 \usepackage{amsmath}
95 94 \usepackage{amsthm}
96 95 \usepackage{amssymb}
97 96 \usepackage{bm}
98 97 \pagestyle{empty}
99 98 \begin{document}
100 99 body text
101 100 \end{document}'''
102 101
103 102
104 103 def test_genelatex_wrap_with_breqn():
105 104 """
106 105 Test genelatex with wrap=True for the case breqn.sty is installed.
107 106 """
108 107 def mock_kpsewhich(filename):
109 108 assert filename == "breqn.sty"
110 109 return "path/to/breqn.sty"
111 110
112 111 with patch_latextool(mock_kpsewhich):
113 112 assert '\n'.join(latextools.genelatex("x^2", True)) == r'''\documentclass{article}
114 113 \usepackage{amsmath}
115 114 \usepackage{amsthm}
116 115 \usepackage{amssymb}
117 116 \usepackage{bm}
118 117 \usepackage{breqn}
119 118 \pagestyle{empty}
120 119 \begin{document}
121 120 \begin{dmath*}
122 121 x^2
123 122 \end{dmath*}
124 123 \end{document}'''
125 124
126 125
127 126 def test_genelatex_wrap_without_breqn():
128 127 """
129 128 Test genelatex with wrap=True for the case breqn.sty is not installed.
130 129 """
131 130 def mock_kpsewhich(filename):
132 131 assert filename == "breqn.sty"
133 132 return None
134 133
135 134 with patch_latextool(mock_kpsewhich):
136 135 assert '\n'.join(latextools.genelatex("x^2", True)) == r'''\documentclass{article}
137 136 \usepackage{amsmath}
138 137 \usepackage{amsthm}
139 138 \usepackage{amssymb}
140 139 \usepackage{bm}
141 140 \pagestyle{empty}
142 141 \begin{document}
143 142 $$x^2$$
144 143 \end{document}'''
145 144
146 145
147 146 @skipif_not_matplotlib
148 147 @onlyif_cmds_exist('latex', 'dvipng')
149 148 def test_latex_to_png_color():
150 149 """
151 150 Test color settings for latex_to_png.
152 151 """
153 152 latex_string = "$x^2$"
154 153 default_value = latextools.latex_to_png(latex_string, wrap=False)
155 154 default_hexblack = latextools.latex_to_png(latex_string, wrap=False,
156 155 color='#000000')
157 156 dvipng_default = latextools.latex_to_png_dvipng(latex_string, False)
158 157 dvipng_black = latextools.latex_to_png_dvipng(latex_string, False, 'Black')
159 158 assert dvipng_default == dvipng_black
160 159 mpl_default = latextools.latex_to_png_mpl(latex_string, False)
161 160 mpl_black = latextools.latex_to_png_mpl(latex_string, False, 'Black')
162 161 assert mpl_default == mpl_black
163 162 assert default_value in [dvipng_black, mpl_black]
164 163 assert default_hexblack in [dvipng_black, mpl_black]
165 164
166 165 # Test that dvips name colors can be used without error
167 166 dvipng_maroon = latextools.latex_to_png_dvipng(latex_string, False,
168 167 'Maroon')
169 168 # And that it doesn't return the black one
170 169 assert dvipng_black != dvipng_maroon
171 170
172 171 mpl_maroon = latextools.latex_to_png_mpl(latex_string, False, 'Maroon')
173 172 assert mpl_black != mpl_maroon
174 173 mpl_white = latextools.latex_to_png_mpl(latex_string, False, 'White')
175 174 mpl_hexwhite = latextools.latex_to_png_mpl(latex_string, False, '#FFFFFF')
176 175 assert mpl_white == mpl_hexwhite
177 176
178 177 mpl_white_scale = latextools.latex_to_png_mpl(latex_string, False,
179 178 'White', 1.2)
180 179 assert mpl_white != mpl_white_scale
181 180
182 181
183 182 def test_latex_to_png_invalid_hex_colors():
184 183 """
185 184 Test that invalid hex colors provided to dvipng gives an exception.
186 185 """
187 186 latex_string = "$x^2$"
188 nt.assert_raises(ValueError, lambda: latextools.latex_to_png(latex_string,
189 backend='dvipng', color="#f00bar"))
190 nt.assert_raises(ValueError, lambda: latextools.latex_to_png(latex_string,
191 backend='dvipng', color="#f00"))
187 pytest.raises(
188 ValueError,
189 lambda: latextools.latex_to_png(
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 1 # coding: utf-8
2 2 """Tests for IPython.lib.pretty."""
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7
8 8 from collections import Counter, defaultdict, deque, OrderedDict
9 9 import os
10 10 import types
11 11 import string
12 12 import unittest
13 13
14 import nose.tools as nt
15 14 import pytest
16 15
17 16 from IPython.lib import pretty
18 17 from IPython.testing.decorators import skip_without, skip_iptest_but_not_pytest
19 18
20 19 from io import StringIO
21 20
22 21
23 22 class MyList(object):
24 23 def __init__(self, content):
25 24 self.content = content
26 25 def _repr_pretty_(self, p, cycle):
27 26 if cycle:
28 27 p.text("MyList(...)")
29 28 else:
30 29 with p.group(3, "MyList(", ")"):
31 30 for (i, child) in enumerate(self.content):
32 31 if i:
33 32 p.text(",")
34 33 p.breakable()
35 34 else:
36 35 p.breakable("")
37 36 p.pretty(child)
38 37
39 38
40 39 class MyDict(dict):
41 40 def _repr_pretty_(self, p, cycle):
42 41 p.text("MyDict(...)")
43 42
44 43 class MyObj(object):
45 44 def somemethod(self):
46 45 pass
47 46
48 47
49 48 class Dummy1(object):
50 49 def _repr_pretty_(self, p, cycle):
51 50 p.text("Dummy1(...)")
52 51
53 52 class Dummy2(Dummy1):
54 53 _repr_pretty_ = None
55 54
56 55 class NoModule(object):
57 56 pass
58 57
59 58 NoModule.__module__ = None
60 59
61 60 class Breaking(object):
62 61 def _repr_pretty_(self, p, cycle):
63 62 with p.group(4,"TG: ",":"):
64 63 p.text("Breaking(")
65 64 p.break_()
66 65 p.text(")")
67 66
68 67 class BreakingRepr(object):
69 68 def __repr__(self):
70 69 return "Breaking(\n)"
71 70
72 71 class BadRepr(object):
73
74 72 def __repr__(self):
75 73 return 1/0
76 74
77 75
78 76 def test_indentation():
79 77 """Test correct indentation in groups"""
80 78 count = 40
81 79 gotoutput = pretty.pretty(MyList(range(count)))
82 80 expectedoutput = "MyList(\n" + ",\n".join(" %d" % i for i in range(count)) + ")"
83 81
84 82 assert gotoutput == expectedoutput
85 83
86 84
87 85 def test_dispatch():
88 86 """
89 87 Test correct dispatching: The _repr_pretty_ method for MyDict
90 88 must be found before the registered printer for dict.
91 89 """
92 90 gotoutput = pretty.pretty(MyDict())
93 91 expectedoutput = "MyDict(...)"
94 92
95 93 assert gotoutput == expectedoutput
96 94
97 95
98 96 def test_callability_checking():
99 97 """
100 98 Test that the _repr_pretty_ method is tested for callability and skipped if
101 99 not.
102 100 """
103 101 gotoutput = pretty.pretty(Dummy2())
104 102 expectedoutput = "Dummy1(...)"
105 103
106 104 assert gotoutput == expectedoutput
107 105
108 106
109 107 @pytest.mark.parametrize(
110 108 "obj,expected_output",
111 109 zip(
112 110 [
113 111 set(),
114 112 frozenset(),
115 113 set([1]),
116 114 frozenset([1]),
117 115 set([1, 2]),
118 116 frozenset([1, 2]),
119 117 set([-1, -2, -3]),
120 118 ],
121 119 [
122 120 "set()",
123 121 "frozenset()",
124 122 "{1}",
125 123 "frozenset({1})",
126 124 "{1, 2}",
127 125 "frozenset({1, 2})",
128 126 "{-3, -2, -1}",
129 127 ],
130 128 ),
131 129 )
132 130 @skip_iptest_but_not_pytest
133 131 def test_sets(obj, expected_output):
134 132 """
135 133 Test that set and frozenset use Python 3 formatting.
136 134 """
137 135 got_output = pretty.pretty(obj)
138 136 assert got_output == expected_output
139 137
140 138
141 139 @skip_without('xxlimited')
142 140 def test_pprint_heap_allocated_type():
143 141 """
144 142 Test that pprint works for heap allocated types.
145 143 """
146 144 import xxlimited
147 145 output = pretty.pretty(xxlimited.Null)
148 146 assert output == "xxlimited.Null"
149 147
150 148
151 149 def test_pprint_nomod():
152 150 """
153 151 Test that pprint works for classes with no __module__.
154 152 """
155 153 output = pretty.pretty(NoModule)
156 154 assert output == "NoModule"
157 155
158 156
159 157 def test_pprint_break():
160 158 """
161 159 Test that p.break_ produces expected output
162 160 """
163 161 output = pretty.pretty(Breaking())
164 162 expected = "TG: Breaking(\n ):"
165 163 assert output == expected
166 164
167 165 def test_pprint_break_repr():
168 166 """
169 167 Test that p.break_ is used in repr
170 168 """
171 169 output = pretty.pretty([[BreakingRepr()]])
172 170 expected = "[[Breaking(\n )]]"
173 171 assert output == expected
174 172
175 173 output = pretty.pretty([[BreakingRepr()]*2])
176 174 expected = "[[Breaking(\n ),\n Breaking(\n )]]"
177 175 assert output == expected
178 176
179 177 def test_bad_repr():
180 178 """Don't catch bad repr errors"""
181 with nt.assert_raises(ZeroDivisionError):
179 with pytest.raises(ZeroDivisionError):
182 180 pretty.pretty(BadRepr())
183 181
184 182 class BadException(Exception):
185 183 def __str__(self):
186 184 return -1
187 185
188 186 class ReallyBadRepr(object):
189 187 __module__ = 1
190 188 @property
191 189 def __class__(self):
192 190 raise ValueError("I am horrible")
193
191
194 192 def __repr__(self):
195 193 raise BadException()
196 194
197 195 def test_really_bad_repr():
198 with nt.assert_raises(BadException):
196 with pytest.raises(BadException):
199 197 pretty.pretty(ReallyBadRepr())
200 198
201 199
202 200 class SA(object):
203 201 pass
204 202
205 203 class SB(SA):
206 204 pass
207 205
208 206 class TestsPretty(unittest.TestCase):
209 207
210 208 def test_super_repr(self):
211 209 # "<super: module_name.SA, None>"
212 210 output = pretty.pretty(super(SA))
213 211 self.assertRegex(output, r"<super: \S+.SA, None>")
214 212
215 213 # "<super: module_name.SA, <module_name.SB at 0x...>>"
216 214 sb = SB()
217 215 output = pretty.pretty(super(SA, sb))
218 216 self.assertRegex(output, r"<super: \S+.SA,\s+<\S+.SB at 0x\S+>>")
219 217
220 218
221 219 def test_long_list(self):
222 220 lis = list(range(10000))
223 221 p = pretty.pretty(lis)
224 222 last2 = p.rsplit('\n', 2)[-2:]
225 223 self.assertEqual(last2, [' 999,', ' ...]'])
226 224
227 225 def test_long_set(self):
228 226 s = set(range(10000))
229 227 p = pretty.pretty(s)
230 228 last2 = p.rsplit('\n', 2)[-2:]
231 229 self.assertEqual(last2, [' 999,', ' ...}'])
232 230
233 231 def test_long_tuple(self):
234 232 tup = tuple(range(10000))
235 233 p = pretty.pretty(tup)
236 234 last2 = p.rsplit('\n', 2)[-2:]
237 235 self.assertEqual(last2, [' 999,', ' ...)'])
238 236
239 237 def test_long_dict(self):
240 238 d = { n:n for n in range(10000) }
241 239 p = pretty.pretty(d)
242 240 last2 = p.rsplit('\n', 2)[-2:]
243 241 self.assertEqual(last2, [' 999: 999,', ' ...}'])
244 242
245 243 def test_unbound_method(self):
246 244 output = pretty.pretty(MyObj.somemethod)
247 245 self.assertIn('MyObj.somemethod', output)
248 246
249 247
250 248 class MetaClass(type):
251 249 def __new__(cls, name):
252 250 return type.__new__(cls, name, (object,), {'name': name})
253 251
254 252 def __repr__(self):
255 253 return "[CUSTOM REPR FOR CLASS %s]" % self.name
256 254
257 255
258 256 ClassWithMeta = MetaClass('ClassWithMeta')
259 257
260 258
261 259 def test_metaclass_repr():
262 260 output = pretty.pretty(ClassWithMeta)
263 261 assert output == "[CUSTOM REPR FOR CLASS ClassWithMeta]"
264 262
265 263
266 264 def test_unicode_repr():
267 265 u = u"üniçodé"
268 266 ustr = u
269
267
270 268 class C(object):
271 269 def __repr__(self):
272 270 return ustr
273
271
274 272 c = C()
275 273 p = pretty.pretty(c)
276 274 assert p == u
277 275 p = pretty.pretty([c])
278 276 assert p == u"[%s]" % u
279 277
280 278
281 279 def test_basic_class():
282 280 def type_pprint_wrapper(obj, p, cycle):
283 281 if obj is MyObj:
284 282 type_pprint_wrapper.called = True
285 283 return pretty._type_pprint(obj, p, cycle)
286 284 type_pprint_wrapper.called = False
287 285
288 286 stream = StringIO()
289 287 printer = pretty.RepresentationPrinter(stream)
290 288 printer.type_pprinters[type] = type_pprint_wrapper
291 289 printer.pretty(MyObj)
292 290 printer.flush()
293 291 output = stream.getvalue()
294 292
295 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 297 # TODO : pytest.mark.parametrise once nose is gone.
300 298 def test_collections_defaultdict():
301 299 # Create defaultdicts with cycles
302 300 a = defaultdict()
303 301 a.default_factory = a
304 302 b = defaultdict(list)
305 303 b['key'] = b
306 304
307 305 # Dictionary order cannot be relied on, test against single keys.
308 306 cases = [
309 307 (defaultdict(list), 'defaultdict(list, {})'),
310 308 (defaultdict(list, {'key': '-' * 50}),
311 309 "defaultdict(list,\n"
312 310 " {'key': '--------------------------------------------------'})"),
313 311 (a, 'defaultdict(defaultdict(...), {})'),
314 312 (b, "defaultdict(list, {'key': defaultdict(...)})"),
315 313 ]
316 314 for obj, expected in cases:
317 315 assert pretty.pretty(obj) == expected
318 316
319 317
320 318 # TODO : pytest.mark.parametrise once nose is gone.
321 319 def test_collections_ordereddict():
322 320 # Create OrderedDict with cycle
323 321 a = OrderedDict()
324 322 a['key'] = a
325 323
326 324 cases = [
327 325 (OrderedDict(), 'OrderedDict()'),
328 326 (OrderedDict((i, i) for i in range(1000, 1010)),
329 327 'OrderedDict([(1000, 1000),\n'
330 328 ' (1001, 1001),\n'
331 329 ' (1002, 1002),\n'
332 330 ' (1003, 1003),\n'
333 331 ' (1004, 1004),\n'
334 332 ' (1005, 1005),\n'
335 333 ' (1006, 1006),\n'
336 334 ' (1007, 1007),\n'
337 335 ' (1008, 1008),\n'
338 336 ' (1009, 1009)])'),
339 337 (a, "OrderedDict([('key', OrderedDict(...))])"),
340 338 ]
341 339 for obj, expected in cases:
342 340 assert pretty.pretty(obj) == expected
343 341
344 342
345 343 # TODO : pytest.mark.parametrise once nose is gone.
346 344 def test_collections_deque():
347 345 # Create deque with cycle
348 346 a = deque()
349 347 a.append(a)
350 348
351 349 cases = [
352 350 (deque(), 'deque([])'),
353 351 (deque(i for i in range(1000, 1020)),
354 352 'deque([1000,\n'
355 353 ' 1001,\n'
356 354 ' 1002,\n'
357 355 ' 1003,\n'
358 356 ' 1004,\n'
359 357 ' 1005,\n'
360 358 ' 1006,\n'
361 359 ' 1007,\n'
362 360 ' 1008,\n'
363 361 ' 1009,\n'
364 362 ' 1010,\n'
365 363 ' 1011,\n'
366 364 ' 1012,\n'
367 365 ' 1013,\n'
368 366 ' 1014,\n'
369 367 ' 1015,\n'
370 368 ' 1016,\n'
371 369 ' 1017,\n'
372 370 ' 1018,\n'
373 371 ' 1019])'),
374 372 (a, 'deque([deque(...)])'),
375 373 ]
376 374 for obj, expected in cases:
377 375 assert pretty.pretty(obj) == expected
378 376
379 377
380 378 # TODO : pytest.mark.parametrise once nose is gone.
381 379 def test_collections_counter():
382 380 class MyCounter(Counter):
383 381 pass
384 382 cases = [
385 383 (Counter(), 'Counter()'),
386 384 (Counter(a=1), "Counter({'a': 1})"),
387 385 (MyCounter(a=1), "MyCounter({'a': 1})"),
388 386 ]
389 387 for obj, expected in cases:
390 388 assert pretty.pretty(obj) == expected
391 389
392 390 # TODO : pytest.mark.parametrise once nose is gone.
393 391 def test_mappingproxy():
394 392 MP = types.MappingProxyType
395 393 underlying_dict = {}
396 394 mp_recursive = MP(underlying_dict)
397 395 underlying_dict[2] = mp_recursive
398 396 underlying_dict[3] = underlying_dict
399 397
400 398 cases = [
401 399 (MP({}), "mappingproxy({})"),
402 400 (MP({None: MP({})}), "mappingproxy({None: mappingproxy({})})"),
403 401 (MP({k: k.upper() for k in string.ascii_lowercase}),
404 402 "mappingproxy({'a': 'A',\n"
405 403 " 'b': 'B',\n"
406 404 " 'c': 'C',\n"
407 405 " 'd': 'D',\n"
408 406 " 'e': 'E',\n"
409 407 " 'f': 'F',\n"
410 408 " 'g': 'G',\n"
411 409 " 'h': 'H',\n"
412 410 " 'i': 'I',\n"
413 411 " 'j': 'J',\n"
414 412 " 'k': 'K',\n"
415 413 " 'l': 'L',\n"
416 414 " 'm': 'M',\n"
417 415 " 'n': 'N',\n"
418 416 " 'o': 'O',\n"
419 417 " 'p': 'P',\n"
420 418 " 'q': 'Q',\n"
421 419 " 'r': 'R',\n"
422 420 " 's': 'S',\n"
423 421 " 't': 'T',\n"
424 422 " 'u': 'U',\n"
425 423 " 'v': 'V',\n"
426 424 " 'w': 'W',\n"
427 425 " 'x': 'X',\n"
428 426 " 'y': 'Y',\n"
429 427 " 'z': 'Z'})"),
430 428 (mp_recursive, "mappingproxy({2: {...}, 3: {2: {...}, 3: {...}}})"),
431 429 (underlying_dict,
432 430 "{2: mappingproxy({2: {...}, 3: {...}}), 3: {...}}"),
433 431 ]
434 432 for obj, expected in cases:
435 433 assert pretty.pretty(obj) == expected
436 434
437 435
438 436 # TODO : pytest.mark.parametrise once nose is gone.
439 437 def test_simplenamespace():
440 438 SN = types.SimpleNamespace
441 439
442 440 sn_recursive = SN()
443 441 sn_recursive.first = sn_recursive
444 442 sn_recursive.second = sn_recursive
445 443 cases = [
446 444 (SN(), "namespace()"),
447 445 (SN(x=SN()), "namespace(x=namespace())"),
448 446 (SN(a_long_name=[SN(s=string.ascii_lowercase)]*3, a_short_name=None),
449 447 "namespace(a_long_name=[namespace(s='abcdefghijklmnopqrstuvwxyz'),\n"
450 448 " namespace(s='abcdefghijklmnopqrstuvwxyz'),\n"
451 449 " namespace(s='abcdefghijklmnopqrstuvwxyz')],\n"
452 450 " a_short_name=None)"),
453 451 (sn_recursive, "namespace(first=namespace(...), second=namespace(...))"),
454 452 ]
455 453 for obj, expected in cases:
456 454 assert pretty.pretty(obj) == expected
457 455
458 456
459 457 def test_pretty_environ():
460 458 dict_repr = pretty.pretty(dict(os.environ))
461 459 # reindent to align with 'environ' prefix
462 460 dict_indented = dict_repr.replace('\n', '\n' + (' ' * len('environ')))
463 461 env_repr = pretty.pretty(os.environ)
464 462 assert env_repr == "environ" + dict_indented
465 463
466 464
467 465 def test_function_pretty():
468 466 "Test pretty print of function"
469 467 # posixpath is a pure python module, its interface is consistent
470 468 # across Python distributions
471 469 import posixpath
472 470
473 471 assert pretty.pretty(posixpath.join) == "<function posixpath.join(a, *p)>"
474 472
475 473 # custom function
476 474 def meaning_of_life(question=None):
477 475 if question:
478 476 return 42
479 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 482 class OrderedCounter(Counter, OrderedDict):
485 483 'Counter that remembers the order elements are first encountered'
486 484
487 485 def __repr__(self):
488 486 return '%s(%r)' % (self.__class__.__name__, OrderedDict(self))
489 487
490 488 def __reduce__(self):
491 489 return self.__class__, (OrderedDict(self),)
492 490
493 491 class MySet(set): # Override repr of a basic type
494 492 def __repr__(self):
495 493 return 'mine'
496 494
497 495 def test_custom_repr():
498 496 """A custom repr should override a pretty printer for a parent type"""
499 497 oc = OrderedCounter("abracadabra")
500 nt.assert_in("OrderedCounter(OrderedDict", pretty.pretty(oc))
498 assert "OrderedCounter(OrderedDict" in pretty.pretty(oc)
501 499
502 500 assert pretty.pretty(MySet()) == "mine"
@@ -1,136 +1,137 b''
1 1 """Test embedding of IPython"""
2 2
3 3 #-----------------------------------------------------------------------------
4 4 # Copyright (C) 2013 The IPython Development Team
5 5 #
6 6 # Distributed under the terms of the BSD License. The full license is in
7 7 # the file COPYING, distributed as part of this software.
8 8 #-----------------------------------------------------------------------------
9 9
10 10 #-----------------------------------------------------------------------------
11 11 # Imports
12 12 #-----------------------------------------------------------------------------
13 13
14 14 import os
15 15 import subprocess
16 16 import sys
17 import nose.tools as nt
17
18 18 from IPython.utils.tempdir import NamedFileInTemporaryDirectory
19 19 from IPython.testing.decorators import skip_win32
20 20 from IPython.testing import IPYTHON_TESTING_TIMEOUT_SCALE
21 21
22 22 #-----------------------------------------------------------------------------
23 23 # Tests
24 24 #-----------------------------------------------------------------------------
25 25
26 26
27 27 _sample_embed = b"""
28 28 import IPython
29 29
30 30 a = 3
31 31 b = 14
32 32 print(a, '.', b)
33 33
34 34 IPython.embed()
35 35
36 36 print('bye!')
37 37 """
38 38
39 39 _exit = b"exit\r"
40 40
41 41 def test_ipython_embed():
42 42 """test that `IPython.embed()` works"""
43 43 with NamedFileInTemporaryDirectory('file_with_embed.py') as f:
44 44 f.write(_sample_embed)
45 45 f.flush()
46 46 f.close() # otherwise msft won't be able to read the file
47 47
48 48 # run `python file_with_embed.py`
49 49 cmd = [sys.executable, f.name]
50 50 env = os.environ.copy()
51 51 env['IPY_TEST_SIMPLE_PROMPT'] = '1'
52 52
53 53 p = subprocess.Popen(cmd, env=env, stdin=subprocess.PIPE,
54 54 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
55 55 out, err = p.communicate(_exit)
56 56 std = out.decode('UTF-8')
57 57
58 nt.assert_equal(p.returncode, 0)
59 nt.assert_in('3 . 14', std)
60 if os.name != 'nt':
58 assert p.returncode == 0
59 assert "3 . 14" in std
60 if os.name != "nt":
61 61 # TODO: Fix up our different stdout references, see issue gh-14
62 nt.assert_in('IPython', std)
63 nt.assert_in('bye!', std)
62 assert "IPython" in std
63 assert "bye!" in std
64
64 65
65 66 @skip_win32
66 67 def test_nest_embed():
67 68 """test that `IPython.embed()` is nestable"""
68 69 import pexpect
69 70 ipy_prompt = r']:' #ansi color codes give problems matching beyond this
70 71 env = os.environ.copy()
71 72 env['IPY_TEST_SIMPLE_PROMPT'] = '1'
72 73
73 74
74 75 child = pexpect.spawn(sys.executable, ['-m', 'IPython', '--colors=nocolor'],
75 76 env=env)
76 77 child.timeout = 5 * IPYTHON_TESTING_TIMEOUT_SCALE
77 78 child.expect(ipy_prompt)
78 79 child.sendline("import IPython")
79 80 child.expect(ipy_prompt)
80 81 child.sendline("ip0 = get_ipython()")
81 82 #enter first nested embed
82 83 child.sendline("IPython.embed()")
83 84 #skip the banner until we get to a prompt
84 85 try:
85 86 prompted = -1
86 87 while prompted != 0:
87 88 prompted = child.expect([ipy_prompt, '\r\n'])
88 89 except pexpect.TIMEOUT as e:
89 90 print(e)
90 91 #child.interact()
91 92 child.sendline("embed1 = get_ipython()")
92 93 child.expect(ipy_prompt)
93 94 child.sendline("print('true' if embed1 is not ip0 else 'false')")
94 95 assert(child.expect(['true\r\n', 'false\r\n']) == 0)
95 96 child.expect(ipy_prompt)
96 97 child.sendline("print('true' if IPython.get_ipython() is embed1 else 'false')")
97 98 assert(child.expect(['true\r\n', 'false\r\n']) == 0)
98 99 child.expect(ipy_prompt)
99 100 #enter second nested embed
100 101 child.sendline("IPython.embed()")
101 102 #skip the banner until we get to a prompt
102 103 try:
103 104 prompted = -1
104 105 while prompted != 0:
105 106 prompted = child.expect([ipy_prompt, '\r\n'])
106 107 except pexpect.TIMEOUT as e:
107 108 print(e)
108 109 #child.interact()
109 110 child.sendline("embed2 = get_ipython()")
110 111 child.expect(ipy_prompt)
111 112 child.sendline("print('true' if embed2 is not embed1 else 'false')")
112 113 assert(child.expect(['true\r\n', 'false\r\n']) == 0)
113 114 child.expect(ipy_prompt)
114 115 child.sendline("print('true' if embed2 is IPython.get_ipython() else 'false')")
115 116 assert(child.expect(['true\r\n', 'false\r\n']) == 0)
116 117 child.expect(ipy_prompt)
117 118 child.sendline('exit')
118 119 #back at first embed
119 120 child.expect(ipy_prompt)
120 121 child.sendline("print('true' if get_ipython() is embed1 else 'false')")
121 122 assert(child.expect(['true\r\n', 'false\r\n']) == 0)
122 123 child.expect(ipy_prompt)
123 124 child.sendline("print('true' if IPython.get_ipython() is embed1 else 'false')")
124 125 assert(child.expect(['true\r\n', 'false\r\n']) == 0)
125 126 child.expect(ipy_prompt)
126 127 child.sendline('exit')
127 128 #back at launching scope
128 129 child.expect(ipy_prompt)
129 130 child.sendline("print('true' if get_ipython() is ip0 else 'false')")
130 131 assert(child.expect(['true\r\n', 'false\r\n']) == 0)
131 132 child.expect(ipy_prompt)
132 133 child.sendline("print('true' if IPython.get_ipython() is ip0 else 'false')")
133 134 assert(child.expect(['true\r\n', 'false\r\n']) == 0)
134 135 child.expect(ipy_prompt)
135 136 child.sendline('exit')
136 137 child.close()
@@ -1,193 +1,225 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Tests for the TerminalInteractiveShell and related pieces."""
3 3 # Copyright (c) IPython Development Team.
4 4 # Distributed under the terms of the Modified BSD License.
5 5
6 6 import sys
7 7 import unittest
8 8 import os
9 9
10 10 from IPython.core.inputtransformer import InputTransformer
11 11 from IPython.testing import tools as tt
12 12 from IPython.utils.capture import capture_output
13 13
14 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 18 def test_elide(self):
20 _elide('concatenate((a1, a2, ...), axis', '') # do not raise
21 _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')
23
24 test_string = os.sep.join(['', 10*'a', 10*'b', 10*'c', ''])
25 expect_stirng = os.sep + 'a' + '\N{HORIZONTAL ELLIPSIS}' + 'b' + os.sep + 10*'c'
26 nt.assert_equal(_elide(test_string, ''), expect_stirng)
19 _elide("concatenate((a1, a2, ...), axis", "") # do not raise
20 _elide("concatenate((a1, a2, ..), . axis", "") # do not raise
21 self.assertEqual(
22 _elide("aaaa.bbbb.ccccc.dddddd.eeeee.fffff.gggggg.hhhhhh", ""),
23 "aaaa.b…g.hhhhhh",
24 )
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 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')
30
33 self.assertEqual(
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 42 def test_elide_typed_short_match(self):
33 43 """
34 44 if the match is too short we don't elide.
35 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 52 def test_elide_typed_no_match(self):
40 53 """
41 54 if the match is too short we don't elide.
42 55 avoid the "the...the"
43 56 """
44 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 69 def test_adjust_completion_text_based_on_context(self):
50 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 75 # Untouched cases
54 nt.assert_equal(_adjust_completion_text_based_on_context('arg1=', 'func1(a)', 7), 'arg1=')
55 nt.assert_equal(_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')
57 nt.assert_equal(_adjust_completion_text_based_on_context('func2', 'func1(a=)', 7), 'func2')
76 self.assertEqual(
77 _adjust_completion_text_based_on_context("arg1=", "func1(a)", 7), "arg1="
78 )
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 90 # Decorator for interaction loop tests -----------------------------------------
60 91
92
61 93 class mock_input_helper(object):
62 94 """Machinery for tests of the main interact loop.
63 95
64 96 Used by the mock_input decorator.
65 97 """
66 98 def __init__(self, testgen):
67 99 self.testgen = testgen
68 100 self.exception = None
69 101 self.ip = get_ipython()
70 102
71 103 def __enter__(self):
72 104 self.orig_prompt_for_code = self.ip.prompt_for_code
73 105 self.ip.prompt_for_code = self.fake_input
74 106 return self
75 107
76 108 def __exit__(self, etype, value, tb):
77 109 self.ip.prompt_for_code = self.orig_prompt_for_code
78 110
79 111 def fake_input(self):
80 112 try:
81 113 return next(self.testgen)
82 114 except StopIteration:
83 115 self.ip.keep_running = False
84 116 return u''
85 117 except:
86 118 self.exception = sys.exc_info()
87 119 self.ip.keep_running = False
88 120 return u''
89 121
90 122 def mock_input(testfunc):
91 123 """Decorator for tests of the main interact loop.
92 124
93 125 Write the test as a generator, yield-ing the input strings, which IPython
94 126 will see as if they were typed in at the prompt.
95 127 """
96 128 def test_method(self):
97 129 testgen = testfunc(self)
98 130 with mock_input_helper(testgen) as mih:
99 131 mih.ip.interact()
100 132
101 133 if mih.exception is not None:
102 134 # Re-raise captured exception
103 135 etype, value, tb = mih.exception
104 136 import traceback
105 137 traceback.print_tb(tb, file=sys.stdout)
106 138 del tb # Avoid reference loop
107 139 raise value
108 140
109 141 return test_method
110 142
111 143 # Test classes -----------------------------------------------------------------
112 144
113 145 class InteractiveShellTestCase(unittest.TestCase):
114 146 def rl_hist_entries(self, rl, n):
115 147 """Get last n readline history entries as a list"""
116 148 return [rl.get_history_item(rl.get_current_history_length() - x)
117 149 for x in range(n - 1, -1, -1)]
118 150
119 151 @mock_input
120 152 def test_inputtransformer_syntaxerror(self):
121 153 ip = get_ipython()
122 154 ip.input_transformers_post.append(syntax_error_transformer)
123 155
124 156 try:
125 157 #raise Exception
126 158 with tt.AssertPrints('4', suppress=False):
127 159 yield u'print(2*2)'
128 160
129 161 with tt.AssertPrints('SyntaxError: input contains', suppress=False):
130 162 yield u'print(2345) # syntaxerror'
131 163
132 164 with tt.AssertPrints('16', suppress=False):
133 165 yield u'print(4*4)'
134 166
135 167 finally:
136 168 ip.input_transformers_post.remove(syntax_error_transformer)
137 169
138 170 def test_plain_text_only(self):
139 171 ip = get_ipython()
140 172 formatter = ip.display_formatter
141 173 assert formatter.active_types == ['text/plain']
142 174 assert not formatter.ipython_display_formatter.enabled
143 175
144 176 class Test(object):
145 177 def __repr__(self):
146 178 return "<Test %i>" % id(self)
147 179
148 180 def _repr_html_(self):
149 181 return '<html>'
150 182
151 183 # verify that HTML repr isn't computed
152 184 obj = Test()
153 185 data, _ = formatter.format(obj)
154 186 self.assertEqual(data, {'text/plain': repr(obj)})
155 187
156 188 class Test2(Test):
157 189 def _ipython_display_(self):
158 190 from IPython.display import display
159 191 display('<custom>')
160 192
161 193 # verify that _ipython_display_ shortcut isn't called
162 194 obj = Test2()
163 195 with capture_output() as captured:
164 196 data, _ = formatter.format(obj)
165 197
166 198 self.assertEqual(data, {'text/plain': repr(obj)})
167 199 assert captured.stdout == ''
168 200
169 201 def syntax_error_transformer(lines):
170 202 """Transformer that throws SyntaxError if 'syntaxerror' is in the code."""
171 203 for line in lines:
172 204 pos = line.find('syntaxerror')
173 205 if pos >= 0:
174 206 e = SyntaxError('input contains "syntaxerror"')
175 207 e.text = line
176 208 e.offset = pos + 1
177 209 raise e
178 210 return lines
179 211
180 212
181 213 class TerminalMagicsTestCase(unittest.TestCase):
182 214 def test_paste_magics_blankline(self):
183 215 """Test that code with a blank line doesn't get split (gh-3246)."""
184 216 ip = get_ipython()
185 217 s = ('def pasted_func(a):\n'
186 218 ' b = a+1\n'
187 219 '\n'
188 220 ' return b')
189 221
190 222 tm = ip.magics_manager.registry['TerminalMagics']
191 223 tm.store_or_execute(s, name=None)
192 224
193 225 self.assertEqual(ip.user_ns['pasted_func'](54), 55)
@@ -1,168 +1,166 b''
1 1 """Tests for the decorators we've created for IPython.
2 2 """
3 3
4 4 # Module imports
5 5 # Std lib
6 6 import inspect
7 7 import sys
8 8
9 # Third party
10 import nose.tools as nt
11
12 9 # Our own
13 10 from IPython.testing import decorators as dec
14 11 from IPython.testing.skipdoctest import skip_doctest
15 12
16 13 #-----------------------------------------------------------------------------
17 14 # Utilities
18 15
19 16 # Note: copied from OInspect, kept here so the testing stuff doesn't create
20 17 # circular dependencies and is easier to reuse.
21 18 def getargspec(obj):
22 19 """Get the names and default values of a function's arguments.
23 20
24 21 A tuple of four things is returned: (args, varargs, varkw, defaults).
25 22 'args' is a list of the argument names (it may contain nested lists).
26 23 'varargs' and 'varkw' are the names of the * and ** arguments or None.
27 24 'defaults' is an n-tuple of the default values of the last n arguments.
28 25
29 26 Modified version of inspect.getargspec from the Python Standard
30 27 Library."""
31 28
32 29 if inspect.isfunction(obj):
33 30 func_obj = obj
34 31 elif inspect.ismethod(obj):
35 32 func_obj = obj.__func__
36 33 else:
37 34 raise TypeError('arg is not a Python function')
38 35 args, varargs, varkw = inspect.getargs(func_obj.__code__)
39 36 return args, varargs, varkw, func_obj.__defaults__
40 37
41 38 #-----------------------------------------------------------------------------
42 39 # Testing functions
43 40
44 41 @dec.as_unittest
45 42 def trivial():
46 43 """A trivial test"""
47 44 pass
48 45
49 46
50 47 @dec.skip()
51 48 def test_deliberately_broken():
52 49 """A deliberately broken test - we want to skip this one."""
53 50 1/0
54 51
55 52 @dec.skip('Testing the skip decorator')
56 53 def test_deliberately_broken2():
57 54 """Another deliberately broken test - we want to skip this one."""
58 55 1/0
59 56
60 57
61 58 # Verify that we can correctly skip the doctest for a function at will, but
62 59 # that the docstring itself is NOT destroyed by the decorator.
63 60 @skip_doctest
64 61 def doctest_bad(x,y=1,**k):
65 62 """A function whose doctest we need to skip.
66 63
67 64 >>> 1+1
68 65 3
69 66 """
70 67 print('x:',x)
71 68 print('y:',y)
72 69 print('k:',k)
73 70
74 71
75 72 def call_doctest_bad():
76 73 """Check that we can still call the decorated functions.
77 74
78 75 >>> doctest_bad(3,y=4)
79 76 x: 3
80 77 y: 4
81 78 k: {}
82 79 """
83 80 pass
84 81
85 82
86 83 def test_skip_dt_decorator():
87 84 """Doctest-skipping decorator should preserve the docstring.
88 85 """
89 86 # Careful: 'check' must be a *verbatim* copy of the doctest_bad docstring!
90 87 check = """A function whose doctest we need to skip.
91 88
92 89 >>> 1+1
93 90 3
94 91 """
95 92 # Fetch the docstring from doctest_bad after decoration.
96 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 98 # Doctest skipping should work for class methods too
102 99 class FooClass(object):
103 100 """FooClass
104 101
105 102 Example:
106 103
107 104 >>> 1+1
108 105 2
109 106 """
110 107
111 108 @skip_doctest
112 109 def __init__(self,x):
113 110 """Make a FooClass.
114 111
115 112 Example:
116 113
117 114 >>> f = FooClass(3)
118 115 junk
119 116 """
120 117 print('Making a FooClass.')
121 118 self.x = x
122 119
123 120 @skip_doctest
124 121 def bar(self,y):
125 122 """Example:
126 123
127 124 >>> ff = FooClass(3)
128 125 >>> ff.bar(0)
129 126 boom!
130 127 >>> 1/0
131 128 bam!
132 129 """
133 130 return 1/y
134 131
135 132 def baz(self,y):
136 133 """Example:
137 134
138 135 >>> ff2 = FooClass(3)
139 136 Making a FooClass.
140 137 >>> ff2.baz(3)
141 138 True
142 139 """
143 140 return self.x==y
144 141
145 142
146 143 def test_skip_dt_decorator2():
147 144 """Doctest-skipping decorator should preserve function signature.
148 145 """
149 146 # Hardcoded correct answer
150 147 dtargs = (['x', 'y'], None, 'k', (1,))
151 148 # Introspect out the value
152 149 dtargsr = getargspec(doctest_bad)
153 150 assert dtargsr==dtargs, \
154 151 "Incorrectly reconstructed args for doctest_bad: %s" % (dtargsr,)
155 152
156 153
157 154 @dec.skip_linux
158 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 159 @dec.skip_win32
162 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 164 @dec.skip_osx
166 165 def test_osx():
167 nt.assert_not_equal(sys.platform,'darwin',"This test can't run under osx")
168
166 assert sys.platform != "darwin", "This test can't run under osx"
@@ -1,135 +1,133 b''
1 1 # encoding: utf-8
2 2 """
3 3 Tests for testing.tools
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 7 # Copyright (C) 2008-2011 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 import os
18 18 import unittest
19 19
20 import nose.tools as nt
21
22 20 from IPython.testing import decorators as dec
23 21 from IPython.testing import tools as tt
24 22
25 23 #-----------------------------------------------------------------------------
26 24 # Tests
27 25 #-----------------------------------------------------------------------------
28 26
29 27 @dec.skip_win32
30 28 def test_full_path_posix():
31 spath = '/foo/bar.py'
32 result = tt.full_path(spath,['a.txt','b.txt'])
33 nt.assert_equal(result, ['/foo/a.txt', '/foo/b.txt'])
34 spath = '/foo'
35 result = tt.full_path(spath,['a.txt','b.txt'])
36 nt.assert_equal(result, ['/a.txt', '/b.txt'])
37 result = tt.full_path(spath,'a.txt')
38 nt.assert_equal(result, ['/a.txt'])
29 spath = "/foo/bar.py"
30 result = tt.full_path(spath, ["a.txt", "b.txt"])
31 assert result, ["/foo/a.txt" == "/foo/b.txt"]
32 spath = "/foo"
33 result = tt.full_path(spath, ["a.txt", "b.txt"])
34 assert result, ["/a.txt" == "/b.txt"]
35 result = tt.full_path(spath, "a.txt")
36 assert result == ["/a.txt"]
39 37
40 38
41 39 @dec.skip_if_not_win32
42 40 def test_full_path_win32():
43 spath = 'c:\\foo\\bar.py'
44 result = tt.full_path(spath,['a.txt','b.txt'])
45 nt.assert_equal(result, ['c:\\foo\\a.txt', 'c:\\foo\\b.txt'])
46 spath = 'c:\\foo'
47 result = tt.full_path(spath,['a.txt','b.txt'])
48 nt.assert_equal(result, ['c:\\a.txt', 'c:\\b.txt'])
49 result = tt.full_path(spath,'a.txt')
50 nt.assert_equal(result, ['c:\\a.txt'])
41 spath = "c:\\foo\\bar.py"
42 result = tt.full_path(spath, ["a.txt", "b.txt"])
43 assert result, ["c:\\foo\\a.txt" == "c:\\foo\\b.txt"]
44 spath = "c:\\foo"
45 result = tt.full_path(spath, ["a.txt", "b.txt"])
46 assert result, ["c:\\a.txt" == "c:\\b.txt"]
47 result = tt.full_path(spath, "a.txt")
48 assert result == ["c:\\a.txt"]
51 49
52 50
53 51 def test_parser():
54 52 err = ("FAILED (errors=1)", 1, 0)
55 53 fail = ("FAILED (failures=1)", 0, 1)
56 54 both = ("FAILED (errors=1, failures=1)", 1, 1)
57 55 for txt, nerr, nfail in [err, fail, both]:
58 56 nerr1, nfail1 = tt.parse_test_output(txt)
59 nt.assert_equal(nerr, nerr1)
60 nt.assert_equal(nfail, nfail1)
57 assert nerr == nerr1
58 assert nfail == nfail1
61 59
62 60
63 61 def test_temp_pyfile():
64 62 src = 'pass\n'
65 63 fname = tt.temp_pyfile(src)
66 64 assert os.path.isfile(fname)
67 65 with open(fname) as fh2:
68 66 src2 = fh2.read()
69 nt.assert_equal(src2, src)
67 assert src2 == src
70 68
71 69 class TestAssertPrints(unittest.TestCase):
72 70 def test_passing(self):
73 71 with tt.AssertPrints("abc"):
74 72 print("abcd")
75 73 print("def")
76 74 print(b"ghi")
77 75
78 76 def test_failing(self):
79 77 def func():
80 78 with tt.AssertPrints("abc"):
81 79 print("acd")
82 80 print("def")
83 81 print(b"ghi")
84 82
85 83 self.assertRaises(AssertionError, func)
86 84
87 85
88 86 class Test_ipexec_validate(tt.TempFileMixin):
89 87 def test_main_path(self):
90 88 """Test with only stdout results.
91 89 """
92 90 self.mktmp("print('A')\n"
93 91 "print('B')\n"
94 92 )
95 93 out = "A\nB"
96 94 tt.ipexec_validate(self.fname, out)
97 95
98 96 def test_main_path2(self):
99 97 """Test with only stdout results, expecting windows line endings.
100 98 """
101 99 self.mktmp("print('A')\n"
102 100 "print('B')\n"
103 101 )
104 102 out = "A\r\nB"
105 103 tt.ipexec_validate(self.fname, out)
106 104
107 105 def test_exception_path(self):
108 106 """Test exception path in exception_validate.
109 107 """
110 108 self.mktmp("import sys\n"
111 109 "print('A')\n"
112 110 "print('B')\n"
113 111 "print('C', file=sys.stderr)\n"
114 112 "print('D', file=sys.stderr)\n"
115 113 )
116 114 out = "A\nB"
117 115 tt.ipexec_validate(self.fname, expected_out=out, expected_err="C\nD")
118 116
119 117 def test_exception_path2(self):
120 118 """Test exception path in exception_validate, expecting windows line endings.
121 119 """
122 120 self.mktmp("import sys\n"
123 121 "print('A')\n"
124 122 "print('B')\n"
125 123 "print('C', file=sys.stderr)\n"
126 124 "print('D', file=sys.stderr)\n"
127 125 )
128 126 out = "A\r\nB"
129 127 tt.ipexec_validate(self.fname, expected_out=out, expected_err="C\r\nD")
130 128
131 129
132 130 def tearDown(self):
133 131 # tear down correctly the mixin,
134 132 # unittest.TestCase.tearDown does nothing
135 133 tt.TempFileMixin.tearDown(self)
@@ -1,58 +1,67 b''
1 import nose.tools as nt
2 1 from IPython.utils.dir2 import dir2
3 2
3 import pytest
4
4 5
5 6 class Base(object):
6 7 x = 1
7 8 z = 23
8 9
9 10
10 11 def test_base():
11 12 res = dir2(Base())
12 assert ('x' in res)
13 assert ('z' in res)
14 assert ('y' not in res)
15 assert ('__class__' in res)
16 nt.assert_equal(res.count('x'), 1)
17 nt.assert_equal(res.count('__class__'), 1)
13 assert "x" in res
14 assert "z" in res
15 assert "y" not in res
16 assert "__class__" in res
17 assert res.count("x") == 1
18 assert res.count("__class__") == 1
19
18 20
19 21 def test_SubClass():
20 22
21 23 class SubClass(Base):
22 24 y = 2
23 25
24 26 res = dir2(SubClass())
25 assert ('y' in res)
26 nt.assert_equal(res.count('y'), 1)
27 nt.assert_equal(res.count('x'), 1)
27 assert "y" in res
28 assert res.count("y") == 1
29 assert res.count("x") == 1
28 30
29 31
30 32 def test_SubClass_with_trait_names_attr():
31 33 # usecase: trait_names is used in a class describing psychological classification
32 34
33 35 class SubClass(Base):
34 36 y = 2
35 37 trait_names = 44
36 38
37 39 res = dir2(SubClass())
38 assert('trait_names' in res)
40 assert "trait_names" in res
39 41
40 42
41 43 def test_misbehaving_object_without_trait_names():
42 44 # dir2 shouldn't raise even when objects are dumb and raise
43 45 # something other than AttribteErrors on bad getattr.
44 46
45 class MisbehavingGetattr(object):
46 def __getattr__(self):
47 class MisbehavingGetattr:
48 def __getattr__(self, attr):
47 49 raise KeyError("I should be caught")
48 50
49 51 def some_method(self):
50 pass
52 return True
51 53
52 54 class SillierWithDir(MisbehavingGetattr):
53 55 def __dir__(self):
54 56 return ['some_method']
55 57
56 58 for bad_klass in (MisbehavingGetattr, SillierWithDir):
57 res = dir2(bad_klass())
58 assert('some_method' in res)
59 obj = bad_klass()
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 1 """Tests for IPython.utils.importstring."""
2 2
3 3 #-----------------------------------------------------------------------------
4 4 # Copyright (C) 2013 The IPython Development Team
5 5 #
6 6 # Distributed under the terms of the BSD License. The full license is in
7 7 # the file COPYING, distributed as part of this software.
8 8 #-----------------------------------------------------------------------------
9 9
10 10 #-----------------------------------------------------------------------------
11 11 # Imports
12 12 #-----------------------------------------------------------------------------
13 13
14 import nose.tools as nt
14 import pytest
15 15
16 16 from IPython.utils.importstring import import_item
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Tests
20 20 #-----------------------------------------------------------------------------
21 21
22 22 def test_import_plain():
23 23 "Test simple imports"
24 24 import os
25 os2 = import_item('os')
26 nt.assert_true(os is os2)
25
26 os2 = import_item("os")
27 assert os is os2
27 28
28 29
29 30 def test_import_nested():
30 31 "Test nested imports from the stdlib"
31 32 from os import path
32 path2 = import_item('os.path')
33 nt.assert_true(path is path2)
33
34 path2 = import_item("os.path")
35 assert path is path2
34 36
35 37
36 38 def test_import_raises():
37 39 "Test that failing imports raise the right exception"
38 nt.assert_raises(ImportError, import_item, 'IPython.foobar')
39
40 pytest.raises(ImportError, import_item, "IPython.foobar")
@@ -1,89 +1,87 b''
1 1 # encoding: utf-8
2 2 """Tests for io.py"""
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7
8 8 import sys
9 9 from io import StringIO
10 10
11 11 from subprocess import Popen, PIPE
12 12 import unittest
13 13
14 import nose.tools as nt
15
16 14 from IPython.utils.io import IOStream, Tee, capture_output
17 15
18 16
19 17 def test_tee_simple():
20 18 "Very simple check with stdout only"
21 19 chan = StringIO()
22 20 text = 'Hello'
23 21 tee = Tee(chan, channel='stdout')
24 22 print(text, file=chan)
25 nt.assert_equal(chan.getvalue(), text+"\n")
23 assert chan.getvalue() == text + "\n"
26 24
27 25
28 26 class TeeTestCase(unittest.TestCase):
29 27
30 28 def tchan(self, channel):
31 29 trap = StringIO()
32 30 chan = StringIO()
33 31 text = 'Hello'
34 32
35 33 std_ori = getattr(sys, channel)
36 34 setattr(sys, channel, trap)
37 35
38 36 tee = Tee(chan, channel=channel)
39 37
40 38 print(text, end='', file=chan)
41 39 trap_val = trap.getvalue()
42 nt.assert_equal(chan.getvalue(), text)
40 self.assertEqual(chan.getvalue(), text)
43 41
44 42 tee.close()
45 43
46 44 setattr(sys, channel, std_ori)
47 45 assert getattr(sys, channel) == std_ori
48 46
49 47 def test(self):
50 48 for chan in ['stdout', 'stderr']:
51 49 self.tchan(chan)
52 50
53 51 def test_io_init():
54 52 """Test that io.stdin/out/err exist at startup"""
55 53 for name in ('stdin', 'stdout', 'stderr'):
56 54 cmd = "from IPython.utils import io;print(io.%s.__class__)"%name
57 55 with Popen([sys.executable, '-c', cmd], stdout=PIPE) as p:
58 56 p.wait()
59 57 classname = p.stdout.read().strip().decode('ascii')
60 58 # __class__ is a reference to the class object in Python 3, so we can't
61 59 # just test for string equality.
62 60 assert 'IPython.utils.io.IOStream' in classname, classname
63 61
64 62 class TestIOStream(unittest.TestCase):
65 63
66 64 def test_IOStream_init(self):
67 65 """IOStream initializes from a file-like object missing attributes. """
68 66 # Cause a failure from getattr and dir(). (Issue #6386)
69 67 class BadStringIO(StringIO):
70 68 def __dir__(self):
71 69 attrs = super().__dir__()
72 70 attrs.append('name')
73 71 return attrs
74 72 with self.assertWarns(DeprecationWarning):
75 73 iostream = IOStream(BadStringIO())
76 74 iostream.write('hi, bad iostream\n')
77 75
78 76 assert not hasattr(iostream, 'name')
79 77 iostream.close()
80 78
81 79 def test_capture_output(self):
82 80 """capture_output() context works"""
83 81
84 82 with capture_output() as io:
85 print('hi, stdout')
86 print('hi, stderr', file=sys.stderr)
87
88 nt.assert_equal(io.stdout, 'hi, stdout\n')
89 nt.assert_equal(io.stderr, 'hi, stderr\n')
83 print("hi, stdout")
84 print("hi, stderr", file=sys.stderr)
85
86 self.assertEqual(io.stdout, "hi, stdout\n")
87 self.assertEqual(io.stderr, "hi, stderr\n")
@@ -1,111 +1,109 b''
1 1 # encoding: utf-8
2 2 """Tests for IPython.utils.module_paths.py"""
3 3
4 4 #-----------------------------------------------------------------------------
5 5 # Copyright (C) 2008-2011 The IPython Development Team
6 6 #
7 7 # Distributed under the terms of the BSD License. The full license is in
8 8 # the file COPYING, distributed as part of this software.
9 9 #-----------------------------------------------------------------------------
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Imports
13 13 #-----------------------------------------------------------------------------
14 14
15 15 import shutil
16 16 import sys
17 17 import tempfile
18 18
19 19 from pathlib import Path
20 20
21 21 from IPython.testing.tools import make_tempfile
22 22
23 23 import IPython.utils.module_paths as mp
24 24
25 import nose.tools as nt
26
27 25 TEST_FILE_PATH = Path(__file__).resolve().parent
28 26
29 27 TMP_TEST_DIR = Path(tempfile.mkdtemp(suffix="with.dot"))
30 28 #
31 29 # Setup/teardown functions/decorators
32 30 #
33 31
34 32 old_syspath = sys.path
35 33
36 34 def make_empty_file(fname):
37 35 open(fname, 'w').close()
38 36
39 37
40 38 def setup_module():
41 39 """Setup testenvironment for the module:
42 40
43 41 """
44 42 # Do not mask exceptions here. In particular, catching WindowsError is a
45 43 # problem because that exception is only defined on Windows...
46 44 Path(TMP_TEST_DIR / "xmod").mkdir(parents=True)
47 45 Path(TMP_TEST_DIR / "nomod").mkdir(parents=True)
48 46 make_empty_file(TMP_TEST_DIR / "xmod/__init__.py")
49 47 make_empty_file(TMP_TEST_DIR / "xmod/sub.py")
50 48 make_empty_file(TMP_TEST_DIR / "pack.py")
51 49 make_empty_file(TMP_TEST_DIR / "packpyc.pyc")
52 50 sys.path = [str(TMP_TEST_DIR)]
53 51
54 52 def teardown_module():
55 53 """Teardown testenvironment for the module:
56 54
57 55 - Remove tempdir
58 56 - restore sys.path
59 57 """
60 58 # Note: we remove the parent test dir, which is the root of all test
61 59 # subdirs we may have created. Use shutil instead of os.removedirs, so
62 60 # that non-empty directories are all recursively removed.
63 61 shutil.rmtree(TMP_TEST_DIR)
64 62 sys.path = old_syspath
65 63
66 64 def test_tempdir():
67 65 """
68 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 71 def test_find_mod_1():
74 72 """
75 73 Search for a directory's file path.
76 74 Expected output: a path to that directory's __init__.py file.
77 75 """
78 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 79 def test_find_mod_2():
82 80 """
83 81 Search for a directory's file path.
84 82 Expected output: a path to that directory's __init__.py file.
85 83 TODO: Confirm why this is a duplicate test.
86 84 """
87 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 88 def test_find_mod_3():
91 89 """
92 90 Search for a directory + a filename without its .py extension
93 91 Expected output: full path with .py extension.
94 92 """
95 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 96 def test_find_mod_4():
99 97 """
100 98 Search for a filename without its .py extension
101 99 Expected output: full path with .py extension
102 100 """
103 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 104 def test_find_mod_5():
107 105 """
108 106 Search for a filename with a .pyc extension
109 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 1 import io
2 2 import os.path
3 import nose.tools as nt
4 3
5 4 from IPython.utils import openpy
6 5
7 6 mydir = os.path.dirname(__file__)
8 7 nonascii_path = os.path.join(mydir, "../../core/tests/nonascii.py")
9 8
10 9
11 10 def test_detect_encoding():
12 11 with open(nonascii_path, "rb") as f:
13 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 16 def test_read_file():
18 17 with io.open(nonascii_path, encoding="iso-8859-5") as f:
19 18 read_specified_enc = f.read()
20 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 21 assert "coding: iso-8859-5" in read_detected_enc
23 22
24 23 read_strip_enc_cookie = openpy.read_py_file(
25 24 nonascii_path, skip_encoding_cookie=True
26 25 )
27 26 assert "coding: iso-8859-5" not in read_strip_enc_cookie
28 27
29 28
30 29 def test_source_to_unicode():
31 30 with io.open(nonascii_path, "rb") as f:
32 31 source_bytes = f.read()
33 nt.assert_equal(
34 openpy.source_to_unicode(source_bytes, skip_encoding_cookie=False).splitlines(),
35 source_bytes.decode("iso-8859-5").splitlines(),
32 assert (
33 openpy.source_to_unicode(source_bytes, skip_encoding_cookie=False).splitlines()
34 == source_bytes.decode("iso-8859-5").splitlines()
36 35 )
37 36
38 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 1 # encoding: utf-8
2 2 """Tests for IPython.utils.path.py"""
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7 import os
8 8 import shutil
9 9 import sys
10 10 import tempfile
11 11 import unittest
12 12 from contextlib import contextmanager
13 13 from unittest.mock import patch
14 14 from os.path import join, abspath
15 15 from imp import reload
16 16
17 17 from nose import SkipTest, with_setup
18 import nose.tools as nt
18 import pytest
19 19
20 20 import IPython
21 21 from IPython import paths
22 22 from IPython.testing import decorators as dec
23 23 from IPython.testing.decorators import (skip_if_not_win32, skip_win32,
24 24 onlyif_unicode_paths,
25 25 skip_win32_py38,)
26 26 from IPython.testing.tools import make_tempfile
27 27 from IPython.utils import path
28 28 from IPython.utils.tempdir import TemporaryDirectory
29 29
30 30
31 31 # Platform-dependent imports
32 32 try:
33 33 import winreg as wreg
34 34 except ImportError:
35 35 #Fake _winreg module on non-windows platforms
36 36 import types
37 37 wr_name = "winreg"
38 38 sys.modules[wr_name] = types.ModuleType(wr_name)
39 39 try:
40 40 import winreg as wreg
41 41 except ImportError:
42 42 import _winreg as wreg
43 43 #Add entries that needs to be stubbed by the testing code
44 44 (wreg.OpenKey, wreg.QueryValueEx,) = (None, None)
45 45
46 46 #-----------------------------------------------------------------------------
47 47 # Globals
48 48 #-----------------------------------------------------------------------------
49 49 env = os.environ
50 50 TMP_TEST_DIR = tempfile.mkdtemp()
51 51 HOME_TEST_DIR = join(TMP_TEST_DIR, "home_test_dir")
52 52 #
53 53 # Setup/teardown functions/decorators
54 54 #
55 55
56 56 def setup_module():
57 57 """Setup testenvironment for the module:
58 58
59 59 - Adds dummy home dir tree
60 60 """
61 61 # Do not mask exceptions here. In particular, catching WindowsError is a
62 62 # problem because that exception is only defined on Windows...
63 63 os.makedirs(os.path.join(HOME_TEST_DIR, 'ipython'))
64 64
65 65
66 66 def teardown_module():
67 67 """Teardown testenvironment for the module:
68 68
69 69 - Remove dummy home dir tree
70 70 """
71 71 # Note: we remove the parent test dir, which is the root of all test
72 72 # subdirs we may have created. Use shutil instead of os.removedirs, so
73 73 # that non-empty directories are all recursively removed.
74 74 shutil.rmtree(TMP_TEST_DIR)
75 75
76 76
77 77 def setup_environment():
78 78 """Setup testenvironment for some functions that are tested
79 79 in this module. In particular this functions stores attributes
80 80 and other things that we need to stub in some test functions.
81 81 This needs to be done on a function level and not module level because
82 82 each testfunction needs a pristine environment.
83 83 """
84 84 global oldstuff, platformstuff
85 85 oldstuff = (env.copy(), os.name, sys.platform, path.get_home_dir, IPython.__file__, os.getcwd())
86 86
87 87 def teardown_environment():
88 88 """Restore things that were remembered by the setup_environment function
89 89 """
90 90 (oldenv, os.name, sys.platform, path.get_home_dir, IPython.__file__, old_wd) = oldstuff
91 91 os.chdir(old_wd)
92 92 reload(path)
93 93
94 94 for key in list(env):
95 95 if key not in oldenv:
96 96 del env[key]
97 97 env.update(oldenv)
98 98 if hasattr(sys, 'frozen'):
99 99 del sys.frozen
100 100
101 101 # Build decorator that uses the setup_environment/setup_environment
102 102 with_environment = with_setup(setup_environment, teardown_environment)
103 103
104 104 @skip_if_not_win32
105 105 @with_environment
106 106 def test_get_home_dir_1():
107 107 """Testcase for py2exe logic, un-compressed lib
108 108 """
109 109 unfrozen = path.get_home_dir()
110 110 sys.frozen = True
111 111
112 112 #fake filename for IPython.__init__
113 113 IPython.__file__ = abspath(join(HOME_TEST_DIR, "Lib/IPython/__init__.py"))
114 114
115 115 home_dir = path.get_home_dir()
116 116 assert home_dir == unfrozen
117 117
118 118
119 119 @skip_if_not_win32
120 120 @with_environment
121 121 def test_get_home_dir_2():
122 122 """Testcase for py2exe logic, compressed lib
123 123 """
124 124 unfrozen = path.get_home_dir()
125 125 sys.frozen = True
126 126 #fake filename for IPython.__init__
127 127 IPython.__file__ = abspath(join(HOME_TEST_DIR, "Library.zip/IPython/__init__.py")).lower()
128 128
129 129 home_dir = path.get_home_dir(True)
130 130 assert home_dir == unfrozen
131 131
132 132
133 133 @skip_win32_py38
134 134 @with_environment
135 135 def test_get_home_dir_3():
136 136 """get_home_dir() uses $HOME if set"""
137 137 env["HOME"] = HOME_TEST_DIR
138 138 home_dir = path.get_home_dir(True)
139 139 # get_home_dir expands symlinks
140 140 assert home_dir == os.path.realpath(env["HOME"])
141 141
142 142
143 143 @with_environment
144 144 def test_get_home_dir_4():
145 145 """get_home_dir() still works if $HOME is not set"""
146 146
147 147 if 'HOME' in env: del env['HOME']
148 148 # this should still succeed, but we don't care what the answer is
149 149 home = path.get_home_dir(False)
150 150
151 151 @skip_win32_py38
152 152 @with_environment
153 153 def test_get_home_dir_5():
154 154 """raise HomeDirError if $HOME is specified, but not a writable dir"""
155 155 env['HOME'] = abspath(HOME_TEST_DIR+'garbage')
156 156 # set os.name = posix, to prevent My Documents fallback on Windows
157 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 160 # Should we stub wreg fully so we can run the test on all platforms?
161 161 @skip_if_not_win32
162 162 @with_environment
163 163 def test_get_home_dir_8():
164 164 """Using registry hack for 'My Documents', os=='nt'
165 165
166 166 HOMESHARE, HOMEDRIVE, HOMEPATH, USERPROFILE and others are missing.
167 167 """
168 168 os.name = 'nt'
169 169 # Remove from stub environment all keys that may be set
170 170 for key in ['HOME', 'HOMESHARE', 'HOMEDRIVE', 'HOMEPATH', 'USERPROFILE']:
171 171 env.pop(key, None)
172 172
173 173 class key:
174 174 def __enter__(self):
175 175 pass
176 176 def Close(self):
177 177 pass
178 178 def __exit__(*args, **kwargs):
179 179 pass
180 180
181 181 with patch.object(wreg, 'OpenKey', return_value=key()), \
182 182 patch.object(wreg, 'QueryValueEx', return_value=[abspath(HOME_TEST_DIR)]):
183 183 home_dir = path.get_home_dir()
184 184 assert home_dir == abspath(HOME_TEST_DIR)
185 185
186 186 @with_environment
187 187 def test_get_xdg_dir_0():
188 188 """test_get_xdg_dir_0, check xdg_dir"""
189 189 reload(path)
190 190 path._writable_dir = lambda path: True
191 191 path.get_home_dir = lambda : 'somewhere'
192 192 os.name = "posix"
193 193 sys.platform = "linux2"
194 194 env.pop('IPYTHON_DIR', None)
195 195 env.pop('IPYTHONDIR', None)
196 196 env.pop('XDG_CONFIG_HOME', None)
197 197
198 198 assert path.get_xdg_dir() == os.path.join("somewhere", ".config")
199 199
200 200
201 201 @with_environment
202 202 def test_get_xdg_dir_1():
203 203 """test_get_xdg_dir_1, check nonexistent xdg_dir"""
204 204 reload(path)
205 205 path.get_home_dir = lambda : HOME_TEST_DIR
206 206 os.name = "posix"
207 207 sys.platform = "linux2"
208 208 env.pop('IPYTHON_DIR', None)
209 209 env.pop('IPYTHONDIR', None)
210 210 env.pop('XDG_CONFIG_HOME', None)
211 211 assert path.get_xdg_dir() is None
212 212
213 213 @with_environment
214 214 def test_get_xdg_dir_2():
215 215 """test_get_xdg_dir_2, check xdg_dir default to ~/.config"""
216 216 reload(path)
217 217 path.get_home_dir = lambda : HOME_TEST_DIR
218 218 os.name = "posix"
219 219 sys.platform = "linux2"
220 220 env.pop('IPYTHON_DIR', None)
221 221 env.pop('IPYTHONDIR', None)
222 222 env.pop('XDG_CONFIG_HOME', None)
223 223 cfgdir=os.path.join(path.get_home_dir(), '.config')
224 224 if not os.path.exists(cfgdir):
225 225 os.makedirs(cfgdir)
226 226
227 227 assert path.get_xdg_dir() == cfgdir
228 228
229 229 @with_environment
230 230 def test_get_xdg_dir_3():
231 231 """test_get_xdg_dir_3, check xdg_dir not used on OS X"""
232 232 reload(path)
233 233 path.get_home_dir = lambda : HOME_TEST_DIR
234 234 os.name = "posix"
235 235 sys.platform = "darwin"
236 236 env.pop('IPYTHON_DIR', None)
237 237 env.pop('IPYTHONDIR', None)
238 238 env.pop('XDG_CONFIG_HOME', None)
239 239 cfgdir=os.path.join(path.get_home_dir(), '.config')
240 if not os.path.exists(cfgdir):
241 os.makedirs(cfgdir)
240 os.makedirs(cfgdir, exist_ok=True)
242 241
243 242 assert path.get_xdg_dir() is None
244 243
245 244 def test_filefind():
246 245 """Various tests for filefind"""
247 246 f = tempfile.NamedTemporaryFile()
248 247 # print 'fname:',f.name
249 248 alt_dirs = paths.get_ipython_dir()
250 249 t = path.filefind(f.name, alt_dirs)
251 250 # print 'found:',t
252 251
253 252
254 253 @dec.skip_if_not_win32
255 254 def test_get_long_path_name_win32():
256 255 with TemporaryDirectory() as tmpdir:
257 256
258 257 # Make a long path. Expands the path of tmpdir prematurely as it may already have a long
259 258 # path component, so ensure we include the long form of it
260 259 long_path = os.path.join(path.get_long_path_name(tmpdir), 'this is my long path name')
261 260 os.makedirs(long_path)
262 261
263 262 # Test to see if the short path evaluates correctly.
264 263 short_path = os.path.join(tmpdir, 'THISIS~1')
265 264 evaluated_path = path.get_long_path_name(short_path)
266 265 assert evaluated_path.lower() == long_path.lower()
267 266
268 267
269 268 @dec.skip_win32
270 269 def test_get_long_path_name():
271 270 p = path.get_long_path_name("/usr/local")
272 271 assert p == "/usr/local"
273 272
274 273
275 274 class TestRaiseDeprecation(unittest.TestCase):
276 275
277 276 @dec.skip_win32 # can't create not-user-writable dir on win
278 277 @with_environment
279 278 def test_not_writable_ipdir(self):
280 279 tmpdir = tempfile.mkdtemp()
281 280 os.name = "posix"
282 281 env.pop('IPYTHON_DIR', None)
283 282 env.pop('IPYTHONDIR', None)
284 283 env.pop('XDG_CONFIG_HOME', None)
285 284 env['HOME'] = tmpdir
286 285 ipdir = os.path.join(tmpdir, '.ipython')
287 286 os.mkdir(ipdir, 0o555)
288 287 try:
289 288 open(os.path.join(ipdir, "_foo_"), 'w').close()
290 289 except IOError:
291 290 pass
292 291 else:
293 292 # I can still write to an unwritable dir,
294 293 # assume I'm root and skip the test
295 294 raise SkipTest("I can't create directories that I can't write to")
296 295 with self.assertWarnsRegex(UserWarning, 'is not a writable location'):
297 296 ipdir = paths.get_ipython_dir()
298 297 env.pop('IPYTHON_DIR', None)
299 298
300 299 @with_environment
301 300 def test_get_py_filename():
302 301 os.chdir(TMP_TEST_DIR)
303 302 with make_tempfile("foo.py"):
304 303 assert path.get_py_filename("foo.py") == "foo.py"
305 304 assert path.get_py_filename("foo") == "foo.py"
306 305 with make_tempfile("foo"):
307 306 assert path.get_py_filename("foo") == "foo"
308 nt.assert_raises(IOError, path.get_py_filename, "foo.py")
309 nt.assert_raises(IOError, path.get_py_filename, "foo")
310 nt.assert_raises(IOError, path.get_py_filename, "foo.py")
307 pytest.raises(IOError, path.get_py_filename, "foo.py")
308 pytest.raises(IOError, path.get_py_filename, "foo")
309 pytest.raises(IOError, path.get_py_filename, "foo.py")
311 310 true_fn = "foo with spaces.py"
312 311 with make_tempfile(true_fn):
313 312 assert path.get_py_filename("foo with spaces") == true_fn
314 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"')
316 nt.assert_raises(IOError, path.get_py_filename, "'foo with spaces.py'")
314 pytest.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 317 @onlyif_unicode_paths
319 318 def test_unicode_in_filename():
320 319 """When a file doesn't exist, the exception raised should be safe to call
321 320 str() on - i.e. in Python 2 it must only have ASCII characters.
322 321
323 322 https://github.com/ipython/ipython/issues/875
324 323 """
325 324 try:
326 325 # these calls should not throw unicode encode exceptions
327 326 path.get_py_filename('fooéè.py')
328 327 except IOError as ex:
329 328 str(ex)
330 329
331 330
332 331 class TestShellGlob(unittest.TestCase):
333 332
334 333 @classmethod
335 334 def setUpClass(cls):
336 335 cls.filenames_start_with_a = ['a0', 'a1', 'a2']
337 336 cls.filenames_end_with_b = ['0b', '1b', '2b']
338 337 cls.filenames = cls.filenames_start_with_a + cls.filenames_end_with_b
339 338 cls.tempdir = TemporaryDirectory()
340 339 td = cls.tempdir.name
341 340
342 341 with cls.in_tempdir():
343 342 # Create empty files
344 343 for fname in cls.filenames:
345 344 open(os.path.join(td, fname), 'w').close()
346 345
347 346 @classmethod
348 347 def tearDownClass(cls):
349 348 cls.tempdir.cleanup()
350 349
351 350 @classmethod
352 351 @contextmanager
353 352 def in_tempdir(cls):
354 353 save = os.getcwd()
355 354 try:
356 355 os.chdir(cls.tempdir.name)
357 356 yield
358 357 finally:
359 358 os.chdir(save)
360 359
361 360 def check_match(self, patterns, matches):
362 361 with self.in_tempdir():
363 362 # glob returns unordered list. that's why sorted is required.
364 363 assert sorted(path.shellglob(patterns)) == sorted(matches)
365 364
366 365 def common_cases(self):
367 366 return [
368 367 (['*'], self.filenames),
369 368 (['a*'], self.filenames_start_with_a),
370 369 (['*c'], ['*c']),
371 370 (['*', 'a*', '*b', '*c'], self.filenames
372 371 + self.filenames_start_with_a
373 372 + self.filenames_end_with_b
374 373 + ['*c']),
375 374 (['a[012]'], self.filenames_start_with_a),
376 375 ]
377 376
378 377 @skip_win32
379 378 def test_match_posix(self):
380 379 for (patterns, matches) in self.common_cases() + [
381 380 ([r'\*'], ['*']),
382 381 ([r'a\*', 'a*'], ['a*'] + self.filenames_start_with_a),
383 382 ([r'a\[012]'], ['a[012]']),
384 383 ]:
385 384 yield (self.check_match, patterns, matches)
386 385
387 386 @skip_if_not_win32
388 387 def test_match_windows(self):
389 388 for (patterns, matches) in self.common_cases() + [
390 389 # In windows, backslash is interpreted as path
391 390 # separator. Therefore, you can't escape glob
392 391 # using it.
393 392 ([r'a\*', 'a*'], [r'a\*'] + self.filenames_start_with_a),
394 393 ([r'a\[012]'], [r'a\[012]']),
395 394 ]:
396 395 yield (self.check_match, patterns, matches)
397 396
398 397
399 398 # TODO : pytest.mark.parametrise once nose is gone.
400 399 def test_unescape_glob():
401 400 assert path.unescape_glob(r"\*\[\!\]\?") == "*[!]?"
402 401 assert path.unescape_glob(r"\\*") == r"\*"
403 402 assert path.unescape_glob(r"\\\*") == r"\*"
404 403 assert path.unescape_glob(r"\\a") == r"\a"
405 404 assert path.unescape_glob(r"\a") == r"\a"
406 405
407 406
408 407 @onlyif_unicode_paths
409 408 def test_ensure_dir_exists():
410 409 with TemporaryDirectory() as td:
411 410 d = os.path.join(td, '∂ir')
412 411 path.ensure_dir_exists(d) # create it
413 412 assert os.path.isdir(d)
414 413 path.ensure_dir_exists(d) # no-op
415 414 f = os.path.join(td, 'ƒile')
416 415 open(f, 'w').close() # touch
417 with nt.assert_raises(IOError):
416 with pytest.raises(IOError):
418 417 path.ensure_dir_exists(f)
419 418
420 419 class TestLinkOrCopy(unittest.TestCase):
421 420 def setUp(self):
422 421 self.tempdir = TemporaryDirectory()
423 422 self.src = self.dst("src")
424 423 with open(self.src, "w") as f:
425 424 f.write("Hello, world!")
426 425
427 426 def tearDown(self):
428 427 self.tempdir.cleanup()
429 428
430 429 def dst(self, *args):
431 430 return os.path.join(self.tempdir.name, *args)
432 431
433 432 def assert_inode_not_equal(self, a, b):
434 433 assert (
435 434 os.stat(a).st_ino != os.stat(b).st_ino
436 435 ), "%r and %r do reference the same indoes" % (a, b)
437 436
438 437 def assert_inode_equal(self, a, b):
439 438 assert (
440 439 os.stat(a).st_ino == os.stat(b).st_ino
441 440 ), "%r and %r do not reference the same indoes" % (a, b)
442 441
443 442 def assert_content_equal(self, a, b):
444 443 with open(a) as a_f:
445 444 with open(b) as b_f:
446 445 assert a_f.read() == b_f.read()
447 446
448 447 @skip_win32
449 448 def test_link_successful(self):
450 449 dst = self.dst("target")
451 450 path.link_or_copy(self.src, dst)
452 451 self.assert_inode_equal(self.src, dst)
453 452
454 453 @skip_win32
455 454 def test_link_into_dir(self):
456 455 dst = self.dst("some_dir")
457 456 os.mkdir(dst)
458 457 path.link_or_copy(self.src, dst)
459 458 expected_dst = self.dst("some_dir", os.path.basename(self.src))
460 459 self.assert_inode_equal(self.src, expected_dst)
461 460
462 461 @skip_win32
463 462 def test_target_exists(self):
464 463 dst = self.dst("target")
465 464 open(dst, "w").close()
466 465 path.link_or_copy(self.src, dst)
467 466 self.assert_inode_equal(self.src, dst)
468 467
469 468 @skip_win32
470 469 def test_no_link(self):
471 470 real_link = os.link
472 471 try:
473 472 del os.link
474 473 dst = self.dst("target")
475 474 path.link_or_copy(self.src, dst)
476 475 self.assert_content_equal(self.src, dst)
477 476 self.assert_inode_not_equal(self.src, dst)
478 477 finally:
479 478 os.link = real_link
480 479
481 480 @skip_if_not_win32
482 481 def test_windows(self):
483 482 dst = self.dst("target")
484 483 path.link_or_copy(self.src, dst)
485 484 self.assert_content_equal(self.src, dst)
486 485
487 486 def test_link_twice(self):
488 487 # Linking the same file twice shouldn't leave duplicates around.
489 488 # See https://github.com/ipython/ipython/issues/6450
490 489 dst = self.dst('target')
491 490 path.link_or_copy(self.src, dst)
492 491 path.link_or_copy(self.src, dst)
493 492 self.assert_inode_equal(self.src, dst)
494 493 assert sorted(os.listdir(self.tempdir.name)) == ["src", "target"]
@@ -1,198 +1,197 b''
1 1 # encoding: utf-8
2 2 """
3 3 Tests for platutils.py
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 7 # Copyright (C) 2008-2011 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 import sys
18 18 import signal
19 19 import os
20 20 import time
21 21 from _thread import interrupt_main # Py 3
22 22 import threading
23 from unittest import SkipTest
24 23
25 import nose.tools as nt
24 import pytest
26 25
27 26 from IPython.utils.process import (find_cmd, FindCmdError, arg_split,
28 27 system, getoutput, getoutputerror,
29 28 get_output_error_code)
30 29 from IPython.utils.capture import capture_output
31 30 from IPython.testing import decorators as dec
32 31 from IPython.testing import tools as tt
33 32
34 33 python = os.path.basename(sys.executable)
35 34
36 35 #-----------------------------------------------------------------------------
37 36 # Tests
38 37 #-----------------------------------------------------------------------------
39 38
40 39
41 40 @dec.skip_win32
42 41 def test_find_cmd_ls():
43 42 """Make sure we can find the full path to ls."""
44 path = find_cmd('ls')
45 nt.assert_true(path.endswith('ls'))
43 path = find_cmd("ls")
44 assert path.endswith("ls")
46 45
47 46
48 47 def has_pywin32():
49 48 try:
50 49 import win32api
51 50 except ImportError:
52 51 return False
53 52 return True
54 53
55 54
56 55 @dec.onlyif(has_pywin32, "This test requires win32api to run")
57 56 def test_find_cmd_pythonw():
58 57 """Try to find pythonw on Windows."""
59 58 path = find_cmd('pythonw')
60 59 assert path.lower().endswith('pythonw.exe'), path
61 60
62 61
63 62 @dec.onlyif(lambda : sys.platform != 'win32' or has_pywin32(),
64 63 "This test runs on posix or in win32 with win32api installed")
65 64 def test_find_cmd_fail():
66 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 69 # TODO: move to pytest.mark.parametrize once nose gone
71 70 @dec.skip_win32
72 71 def test_arg_split():
73 72 """Ensure that argument lines are correctly split like in a shell."""
74 73 tests = [['hi', ['hi']],
75 74 [u'hi', [u'hi']],
76 75 ['hello there', ['hello', 'there']],
77 76 # \u01ce == \N{LATIN SMALL LETTER A WITH CARON}
78 77 # Do not use \N because the tests crash with syntax error in
79 78 # some cases, for example windows python2.6.
80 79 [u'h\u01cello', [u'h\u01cello']],
81 80 ['something "with quotes"', ['something', '"with quotes"']],
82 81 ]
83 82 for argstr, argv in tests:
84 83 assert arg_split(argstr) == argv
85 84
86 85
87 86 # TODO: move to pytest.mark.parametrize once nose gone
88 87 @dec.skip_if_not_win32
89 88 def test_arg_split_win32():
90 89 """Ensure that argument lines are correctly split like in a shell."""
91 90 tests = [['hi', ['hi']],
92 91 [u'hi', [u'hi']],
93 92 ['hello there', ['hello', 'there']],
94 93 [u'h\u01cello', [u'h\u01cello']],
95 94 ['something "with quotes"', ['something', 'with quotes']],
96 95 ]
97 96 for argstr, argv in tests:
98 97 assert arg_split(argstr) == argv
99 98
100 99
101 100 class SubProcessTestCase(tt.TempFileMixin):
102 101 def setUp(self):
103 102 """Make a valid python temp file."""
104 103 lines = [ "import sys",
105 104 "print('on stdout', end='', file=sys.stdout)",
106 105 "print('on stderr', end='', file=sys.stderr)",
107 106 "sys.stdout.flush()",
108 107 "sys.stderr.flush()"]
109 108 self.mktmp('\n'.join(lines))
110 109
111 110 def test_system(self):
112 111 status = system('%s "%s"' % (python, self.fname))
113 112 self.assertEqual(status, 0)
114 113
115 114 def test_system_quotes(self):
116 115 status = system('%s -c "import sys"' % python)
117 116 self.assertEqual(status, 0)
118 117
119 118 def assert_interrupts(self, command):
120 119 """
121 120 Interrupt a subprocess after a second.
122 121 """
123 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 125 # Some tests can overwrite SIGINT handler (by using pdb for example),
127 126 # which then breaks this test, so just make sure it's operating
128 127 # normally.
129 128 signal.signal(signal.SIGINT, signal.default_int_handler)
130 129
131 130 def interrupt():
132 131 # Wait for subprocess to start:
133 132 time.sleep(0.5)
134 133 interrupt_main()
135 134
136 135 threading.Thread(target=interrupt).start()
137 136 start = time.time()
138 137 try:
139 138 result = command()
140 139 except KeyboardInterrupt:
141 140 # Success!
142 141 pass
143 142 end = time.time()
144 143 self.assertTrue(
145 144 end - start < 2, "Process didn't die quickly: %s" % (end - start)
146 145 )
147 146 return result
148 147
149 148 def test_system_interrupt(self):
150 149 """
151 150 When interrupted in the way ipykernel interrupts IPython, the
152 151 subprocess is interrupted.
153 152 """
154 153 def command():
155 154 return system('%s -c "import time; time.sleep(5)"' % python)
156 155
157 156 status = self.assert_interrupts(command)
158 157 self.assertNotEqual(
159 158 status, 0, "The process wasn't interrupted. Status: %s" % (status,)
160 159 )
161 160
162 161 def test_getoutput(self):
163 162 out = getoutput('%s "%s"' % (python, self.fname))
164 163 # we can't rely on the order the line buffered streams are flushed
165 164 try:
166 165 self.assertEqual(out, 'on stderron stdout')
167 166 except AssertionError:
168 167 self.assertEqual(out, 'on stdouton stderr')
169 168
170 169 def test_getoutput_quoted(self):
171 170 out = getoutput('%s -c "print (1)"' % python)
172 171 self.assertEqual(out.strip(), '1')
173 172
174 173 #Invalid quoting on windows
175 174 @dec.skip_win32
176 175 def test_getoutput_quoted2(self):
177 176 out = getoutput("%s -c 'print (1)'" % python)
178 177 self.assertEqual(out.strip(), '1')
179 178 out = getoutput("%s -c 'print (\"1\")'" % python)
180 179 self.assertEqual(out.strip(), '1')
181 180
182 181 def test_getoutput_error(self):
183 182 out, err = getoutputerror('%s "%s"' % (python, self.fname))
184 183 self.assertEqual(out, 'on stdout')
185 184 self.assertEqual(err, 'on stderr')
186 185
187 186 def test_get_output_error_code(self):
188 187 quiet_exit = '%s -c "import sys; sys.exit(1)"' % python
189 188 out, err, code = get_output_error_code(quiet_exit)
190 189 self.assertEqual(out, '')
191 190 self.assertEqual(err, '')
192 191 self.assertEqual(code, 1)
193 192 out, err, code = get_output_error_code('%s "%s"' % (python, self.fname))
194 193 self.assertEqual(out, 'on stdout')
195 194 self.assertEqual(err, 'on stderr')
196 195 self.assertEqual(code, 0)
197 196
198 197
@@ -1,76 +1,73 b''
1 1 # coding: utf-8
2 2 """Test suite for our color utilities.
3 3
4 4 Authors
5 5 -------
6 6
7 7 * Min RK
8 8 """
9 9 #-----------------------------------------------------------------------------
10 10 # Copyright (C) 2011 The IPython Development Team
11 11 #
12 12 # Distributed under the terms of the BSD License. The full license is in
13 13 # the file COPYING.txt, distributed as part of this software.
14 14 #-----------------------------------------------------------------------------
15 15
16 16 #-----------------------------------------------------------------------------
17 17 # Imports
18 18 #-----------------------------------------------------------------------------
19 19
20 # third party
21 import nose.tools as nt
22
23 20 from IPython.testing.decorators import skip_iptest_but_not_pytest
24 21
25 22 # our own
26 23 from IPython.utils.PyColorize import Parser
27 24 import io
28 25 import pytest
29 26
30 27
31 28 @pytest.fixture(scope="module", params=("Linux", "NoColor", "LightBG", "Neutral"))
32 29 def style(request):
33 30 yield request.param
34 31
35 32 #-----------------------------------------------------------------------------
36 33 # Test functions
37 34 #-----------------------------------------------------------------------------
38 35
39 36 sample = """
40 37 def function(arg, *args, kwarg=True, **kwargs):
41 38 '''
42 39 this is docs
43 40 '''
44 41 pass is True
45 42 False == None
46 43
47 44 with io.open(ru'unicode'):
48 45 raise ValueError("\n escape \r sequence")
49 46
50 47 print("wěird ünicoðe")
51 48
52 49 class Bar(Super):
53 50
54 51 def __init__(self):
55 52 super(Bar, self).__init__(1**2, 3^4, 5 or 6)
56 53 """
57 54
58 55
59 56 @skip_iptest_but_not_pytest
60 57 def test_parse_sample(style):
61 58 """and test writing to a buffer"""
62 59 buf = io.StringIO()
63 60 p = Parser(style=style)
64 61 p.format(sample, buf)
65 62 buf.seek(0)
66 63 f1 = buf.read()
67 64
68 nt.assert_not_in("ERROR", f1)
65 assert "ERROR" not in f1
69 66
70 67
71 68 @skip_iptest_but_not_pytest
72 69 def test_parse_error(style):
73 70 p = Parser(style=style)
74 71 f1 = p.format(")", "str")
75 72 if style != "NoColor":
76 nt.assert_in("ERROR", f1)
73 assert "ERROR" in f1
@@ -1,17 +1,16 b''
1 1 # coding: utf-8
2 2 """Test suite for our sysinfo utilities."""
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7 import json
8 import nose.tools as nt
9 8
10 9 from IPython.utils import sysinfo
11 10
12 11
13 12 def test_json_getsysinfo():
14 13 """
15 14 test that it is easily jsonable and don't return bytes somewhere.
16 15 """
17 16 json.dumps(sysinfo.get_sys_info())
@@ -1,205 +1,207 b''
1 1 # encoding: utf-8
2 2 """Tests for IPython.utils.text"""
3 3
4 4 #-----------------------------------------------------------------------------
5 5 # Copyright (C) 2011 The IPython Development Team
6 6 #
7 7 # Distributed under the terms of the BSD License. The full license is in
8 8 # the file COPYING, distributed as part of this software.
9 9 #-----------------------------------------------------------------------------
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Imports
13 13 #-----------------------------------------------------------------------------
14 14
15 15 import os
16 16 import math
17 17 import random
18 18 import sys
19 19
20 import nose.tools as nt
21 20 from pathlib import Path
22 21
22 import pytest
23
23 24 from IPython.utils import text
24 25
25 26 #-----------------------------------------------------------------------------
26 27 # Globals
27 28 #-----------------------------------------------------------------------------
28 29
29 30 def test_columnize():
30 31 """Basic columnize tests."""
31 32 size = 5
32 33 items = [l*size for l in 'abcd']
33 34
34 35 out = text.columnize(items, displaywidth=80)
35 36 assert out == "aaaaa bbbbb ccccc ddddd\n"
36 37 out = text.columnize(items, displaywidth=25)
37 38 assert out == "aaaaa ccccc\nbbbbb ddddd\n"
38 39 out = text.columnize(items, displaywidth=12)
39 40 assert out == "aaaaa ccccc\nbbbbb ddddd\n"
40 41 out = text.columnize(items, displaywidth=10)
41 42 assert out == "aaaaa\nbbbbb\nccccc\nddddd\n"
42 43
43 44 out = text.columnize(items, row_first=True, displaywidth=80)
44 45 assert out == "aaaaa bbbbb ccccc ddddd\n"
45 46 out = text.columnize(items, row_first=True, displaywidth=25)
46 47 assert out == "aaaaa bbbbb\nccccc ddddd\n"
47 48 out = text.columnize(items, row_first=True, displaywidth=12)
48 49 assert out == "aaaaa bbbbb\nccccc ddddd\n"
49 50 out = text.columnize(items, row_first=True, displaywidth=10)
50 51 assert out == "aaaaa\nbbbbb\nccccc\nddddd\n"
51 52
52 53 out = text.columnize(items, displaywidth=40, spread=True)
53 54 assert out == "aaaaa bbbbb ccccc ddddd\n"
54 55 out = text.columnize(items, displaywidth=20, spread=True)
55 56 assert out == "aaaaa ccccc\nbbbbb ddddd\n"
56 57 out = text.columnize(items, displaywidth=12, spread=True)
57 58 assert out == "aaaaa ccccc\nbbbbb ddddd\n"
58 59 out = text.columnize(items, displaywidth=10, spread=True)
59 60 assert out == "aaaaa\nbbbbb\nccccc\nddddd\n"
60 61
61 62
62 63 def test_columnize_random():
63 64 """Test with random input to hopefully catch edge case """
64 65 for row_first in [True, False]:
65 66 for nitems in [random.randint(2,70) for i in range(2,20)]:
66 67 displaywidth = random.randint(20,200)
67 68 rand_len = [random.randint(2,displaywidth) for i in range(nitems)]
68 69 items = ['x'*l for l in rand_len]
69 70 out = text.columnize(items, row_first=row_first, displaywidth=displaywidth)
70 71 longer_line = max([len(x) for x in out.split('\n')])
71 72 longer_element = max(rand_len)
72 73 if longer_line > displaywidth:
73 74 print("Columnize displayed something lager than displaywidth : %s " % longer_line)
74 75 print("longer element : %s " % longer_element)
75 76 print("displaywidth : %s " % displaywidth)
76 77 print("number of element : %s " % nitems)
77 78 print("size of each element :\n %s" % rand_len)
78 79 assert False, "row_first={0}".format(row_first)
79 80
80 81
81 82 # TODO: pytest mark.parametrize once nose removed.
82 83 def test_columnize_medium():
83 84 """Test with inputs than shouldn't be wider than 80"""
84 85 size = 40
85 86 items = [l*size for l in 'abc']
86 87 for row_first in [True, False]:
87 88 out = text.columnize(items, row_first=row_first, displaywidth=80)
88 89 assert out == "\n".join(items + [""]), "row_first={0}".format(row_first)
89 90
90 91
91 92 # TODO: pytest mark.parametrize once nose removed.
92 93 def test_columnize_long():
93 94 """Test columnize with inputs longer than the display window"""
94 95 size = 11
95 96 items = [l*size for l in 'abc']
96 97 for row_first in [True, False]:
97 98 out = text.columnize(items, row_first=row_first, displaywidth=size - 1)
98 99 assert out == "\n".join(items + [""]), "row_first={0}".format(row_first)
99 100
100 101
101 102 def eval_formatter_check(f):
102 103 ns = dict(n=12, pi=math.pi, stuff='hello there', os=os, u=u"café", b="café")
103 104 s = f.format("{n} {n//4} {stuff.split()[0]}", **ns)
104 105 assert s == "12 3 hello"
105 106 s = f.format(' '.join(['{n//%i}'%i for i in range(1,8)]), **ns)
106 107 assert s == "12 6 4 3 2 2 1"
107 108 s = f.format('{[n//i for i in range(1,8)]}', **ns)
108 109 assert s == "[12, 6, 4, 3, 2, 2, 1]"
109 110 s = f.format("{stuff!s}", **ns)
110 111 assert s == ns["stuff"]
111 112 s = f.format("{stuff!r}", **ns)
112 113 assert s == repr(ns["stuff"])
113 114
114 115 # Check with unicode:
115 116 s = f.format("{u}", **ns)
116 117 assert s == ns["u"]
117 118 # This decodes in a platform dependent manner, but it shouldn't error out
118 119 s = f.format("{b}", **ns)
119
120 nt.assert_raises(NameError, f.format, '{dne}', **ns)
120
121 pytest.raises(NameError, f.format, "{dne}", **ns)
122
121 123
122 124 def eval_formatter_slicing_check(f):
123 125 ns = dict(n=12, pi=math.pi, stuff='hello there', os=os)
124 126 s = f.format(" {stuff.split()[:]} ", **ns)
125 127 assert s == " ['hello', 'there'] "
126 128 s = f.format(" {stuff.split()[::-1]} ", **ns)
127 129 assert s == " ['there', 'hello'] "
128 130 s = f.format("{stuff[::2]}", **ns)
129 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 135 def eval_formatter_no_slicing_check(f):
134 136 ns = dict(n=12, pi=math.pi, stuff='hello there', os=os)
135 137
136 138 s = f.format('{n:x} {pi**2:+f}', **ns)
137 139 assert s == "c +9.869604"
138 140
139 141 s = f.format("{stuff[slice(1,4)]}", **ns)
140 142 assert s == "ell"
141 143
142 144 s = f.format("{a[:]}", a=[1, 2])
143 145 assert s == "[1, 2]"
144 146
145 147 def test_eval_formatter():
146 148 f = text.EvalFormatter()
147 149 eval_formatter_check(f)
148 150 eval_formatter_no_slicing_check(f)
149 151
150 152 def test_full_eval_formatter():
151 153 f = text.FullEvalFormatter()
152 154 eval_formatter_check(f)
153 155 eval_formatter_slicing_check(f)
154 156
155 157 def test_dollar_formatter():
156 158 f = text.DollarFormatter()
157 159 eval_formatter_check(f)
158 160 eval_formatter_slicing_check(f)
159 161
160 162 ns = dict(n=12, pi=math.pi, stuff='hello there', os=os)
161 163 s = f.format("$n", **ns)
162 164 assert s == "12"
163 165 s = f.format("$n.real", **ns)
164 166 assert s == "12"
165 167 s = f.format("$n/{stuff[:5]}", **ns)
166 168 assert s == "12/hello"
167 169 s = f.format("$n $$HOME", **ns)
168 170 assert s == "12 $HOME"
169 171 s = f.format("${foo}", foo="HOME")
170 172 assert s == "$HOME"
171 173
172 174
173 175 def test_strip_email():
174 176 src = """\
175 177 >> >>> def f(x):
176 178 >> ... return x+1
177 179 >> ...
178 180 >> >>> zz = f(2.5)"""
179 181 cln = """\
180 182 >>> def f(x):
181 183 ... return x+1
182 184 ...
183 185 >>> zz = f(2.5)"""
184 186 assert text.strip_email_quotes(src) == cln
185 187
186 188
187 189 def test_strip_email2():
188 190 src = '> > > list()'
189 191 cln = 'list()'
190 192 assert text.strip_email_quotes(src) == cln
191 193
192 194 def test_LSString():
193 195 lss = text.LSString("abc\ndef")
194 196 assert lss.l == ["abc", "def"]
195 197 assert lss.s == "abc def"
196 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 201 def test_SList():
200 202 sl = text.SList(["a 11", "b 1", "a 2"])
201 203 assert sl.n == "a 11\nb 1\na 2"
202 204 assert sl.s == "a 11 b 1 a 2"
203 205 assert sl.grep(lambda x: x.startswith("a")) == text.SList(["a 11", "a 2"])
204 206 assert sl.fields(0) == text.SList(["a", "b", "a"])
205 207 assert sl.sort(field=1, nums=True) == text.SList(["b 1", "a 2", "a 11"])
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 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