##// END OF EJS Templates
Merge pull request #13303 from Kojoley/remove-skip_iptest_but_not_pytest...
Matthias Bussonnier -
r27111:6a25628e merge
parent child Browse files
Show More
@@ -1,388 +1,385
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 7 import string
8 8 import sys
9 9 from textwrap import dedent
10 10
11 11 import pytest
12 12
13 13 from IPython.core import inputtransformer2 as ipt2
14 14 from IPython.core.inputtransformer2 import _find_assign_op, make_tokens_by_line
15 from IPython.testing.decorators import skip_iptest_but_not_pytest
16 15
17 16 MULTILINE_MAGIC = ("""\
18 17 a = f()
19 18 %foo \\
20 19 bar
21 20 g()
22 21 """.splitlines(keepends=True), (2, 0), """\
23 22 a = f()
24 23 get_ipython().run_line_magic('foo', ' bar')
25 24 g()
26 25 """.splitlines(keepends=True))
27 26
28 27 INDENTED_MAGIC = ("""\
29 28 for a in range(5):
30 29 %ls
31 30 """.splitlines(keepends=True), (2, 4), """\
32 31 for a in range(5):
33 32 get_ipython().run_line_magic('ls', '')
34 33 """.splitlines(keepends=True))
35 34
36 35 CRLF_MAGIC = ([
37 36 "a = f()\n",
38 37 "%ls\r\n",
39 38 "g()\n"
40 39 ], (2, 0), [
41 40 "a = f()\n",
42 41 "get_ipython().run_line_magic('ls', '')\n",
43 42 "g()\n"
44 43 ])
45 44
46 45 MULTILINE_MAGIC_ASSIGN = ("""\
47 46 a = f()
48 47 b = %foo \\
49 48 bar
50 49 g()
51 50 """.splitlines(keepends=True), (2, 4), """\
52 51 a = f()
53 52 b = get_ipython().run_line_magic('foo', ' bar')
54 53 g()
55 54 """.splitlines(keepends=True))
56 55
57 56 MULTILINE_SYSTEM_ASSIGN = ("""\
58 57 a = f()
59 58 b = !foo \\
60 59 bar
61 60 g()
62 61 """.splitlines(keepends=True), (2, 4), """\
63 62 a = f()
64 63 b = get_ipython().getoutput('foo bar')
65 64 g()
66 65 """.splitlines(keepends=True))
67 66
68 67 #####
69 68
70 69 MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT = ("""\
71 70 def test():
72 71 for i in range(1):
73 72 print(i)
74 73 res =! ls
75 74 """.splitlines(keepends=True), (4, 7), '''\
76 75 def test():
77 76 for i in range(1):
78 77 print(i)
79 78 res =get_ipython().getoutput(\' ls\')
80 79 '''.splitlines(keepends=True))
81 80
82 81 ######
83 82
84 83 AUTOCALL_QUOTE = (
85 84 [",f 1 2 3\n"], (1, 0),
86 85 ['f("1", "2", "3")\n']
87 86 )
88 87
89 88 AUTOCALL_QUOTE2 = (
90 89 [";f 1 2 3\n"], (1, 0),
91 90 ['f("1 2 3")\n']
92 91 )
93 92
94 93 AUTOCALL_PAREN = (
95 94 ["/f 1 2 3\n"], (1, 0),
96 95 ['f(1, 2, 3)\n']
97 96 )
98 97
99 98 SIMPLE_HELP = (
100 99 ["foo?\n"], (1, 0),
101 100 ["get_ipython().run_line_magic('pinfo', 'foo')\n"]
102 101 )
103 102
104 103 DETAILED_HELP = (
105 104 ["foo??\n"], (1, 0),
106 105 ["get_ipython().run_line_magic('pinfo2', 'foo')\n"]
107 106 )
108 107
109 108 MAGIC_HELP = (
110 109 ["%foo?\n"], (1, 0),
111 110 ["get_ipython().run_line_magic('pinfo', '%foo')\n"]
112 111 )
113 112
114 113 HELP_IN_EXPR = (
115 114 ["a = b + c?\n"], (1, 0),
116 115 ["get_ipython().set_next_input('a = b + c');"
117 116 "get_ipython().run_line_magic('pinfo', 'c')\n"]
118 117 )
119 118
120 119 HELP_CONTINUED_LINE = ("""\
121 120 a = \\
122 121 zip?
123 122 """.splitlines(keepends=True), (1, 0),
124 123 [r"get_ipython().set_next_input('a = \\\nzip');get_ipython().run_line_magic('pinfo', 'zip')" + "\n"]
125 124 )
126 125
127 126 HELP_MULTILINE = ("""\
128 127 (a,
129 128 b) = zip?
130 129 """.splitlines(keepends=True), (1, 0),
131 130 [r"get_ipython().set_next_input('(a,\nb) = zip');get_ipython().run_line_magic('pinfo', 'zip')" + "\n"]
132 131 )
133 132
134 133 HELP_UNICODE = (
135 134 ["Ο€.foo?\n"], (1, 0),
136 135 ["get_ipython().run_line_magic('pinfo', 'Ο€.foo')\n"]
137 136 )
138 137
139 138
140 139 def null_cleanup_transformer(lines):
141 140 """
142 141 A cleanup transform that returns an empty list.
143 142 """
144 143 return []
145 144
146 145
147 146 def test_check_make_token_by_line_never_ends_empty():
148 147 """
149 148 Check that not sequence of single or double characters ends up leading to en empty list of tokens
150 149 """
151 150 from string import printable
152 151 for c in printable:
153 152 assert make_tokens_by_line(c)[-1] != []
154 153 for k in printable:
155 154 assert make_tokens_by_line(c + k)[-1] != []
156 155
157 156
158 157 def check_find(transformer, case, match=True):
159 158 sample, expected_start, _ = case
160 159 tbl = make_tokens_by_line(sample)
161 160 res = transformer.find(tbl)
162 161 if match:
163 162 # start_line is stored 0-indexed, expected values are 1-indexed
164 163 assert (res.start_line + 1, res.start_col) == expected_start
165 164 return res
166 165 else:
167 166 assert res is None
168 167
169 168 def check_transform(transformer_cls, case):
170 169 lines, start, expected = case
171 170 transformer = transformer_cls(start)
172 171 assert transformer.transform(lines) == expected
173 172
174 173 def test_continued_line():
175 174 lines = MULTILINE_MAGIC_ASSIGN[0]
176 175 assert ipt2.find_end_of_continued_line(lines, 1) == 2
177 176
178 177 assert ipt2.assemble_continued_line(lines, (1, 5), 2) == "foo bar"
179 178
180 179 def test_find_assign_magic():
181 180 check_find(ipt2.MagicAssign, MULTILINE_MAGIC_ASSIGN)
182 181 check_find(ipt2.MagicAssign, MULTILINE_SYSTEM_ASSIGN, match=False)
183 182 check_find(ipt2.MagicAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT, match=False)
184 183
185 184 def test_transform_assign_magic():
186 185 check_transform(ipt2.MagicAssign, MULTILINE_MAGIC_ASSIGN)
187 186
188 187 def test_find_assign_system():
189 188 check_find(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN)
190 189 check_find(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT)
191 190 check_find(ipt2.SystemAssign, (["a = !ls\n"], (1, 5), None))
192 191 check_find(ipt2.SystemAssign, (["a=!ls\n"], (1, 2), None))
193 192 check_find(ipt2.SystemAssign, MULTILINE_MAGIC_ASSIGN, match=False)
194 193
195 194 def test_transform_assign_system():
196 195 check_transform(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN)
197 196 check_transform(ipt2.SystemAssign, MULTILINE_SYSTEM_ASSIGN_AFTER_DEDENT)
198 197
199 198 def test_find_magic_escape():
200 199 check_find(ipt2.EscapedCommand, MULTILINE_MAGIC)
201 200 check_find(ipt2.EscapedCommand, INDENTED_MAGIC)
202 201 check_find(ipt2.EscapedCommand, MULTILINE_MAGIC_ASSIGN, match=False)
203 202
204 203 def test_transform_magic_escape():
205 204 check_transform(ipt2.EscapedCommand, MULTILINE_MAGIC)
206 205 check_transform(ipt2.EscapedCommand, INDENTED_MAGIC)
207 206 check_transform(ipt2.EscapedCommand, CRLF_MAGIC)
208 207
209 208 def test_find_autocalls():
210 209 for case in [AUTOCALL_QUOTE, AUTOCALL_QUOTE2, AUTOCALL_PAREN]:
211 210 print("Testing %r" % case[0])
212 211 check_find(ipt2.EscapedCommand, case)
213 212
214 213 def test_transform_autocall():
215 214 for case in [AUTOCALL_QUOTE, AUTOCALL_QUOTE2, AUTOCALL_PAREN]:
216 215 print("Testing %r" % case[0])
217 216 check_transform(ipt2.EscapedCommand, case)
218 217
219 218 def test_find_help():
220 219 for case in [SIMPLE_HELP, DETAILED_HELP, MAGIC_HELP, HELP_IN_EXPR]:
221 220 check_find(ipt2.HelpEnd, case)
222 221
223 222 tf = check_find(ipt2.HelpEnd, HELP_CONTINUED_LINE)
224 223 assert tf.q_line == 1
225 224 assert tf.q_col == 3
226 225
227 226 tf = check_find(ipt2.HelpEnd, HELP_MULTILINE)
228 227 assert tf.q_line == 1
229 228 assert tf.q_col == 8
230 229
231 230 # ? in a comment does not trigger help
232 231 check_find(ipt2.HelpEnd, (["foo # bar?\n"], None, None), match=False)
233 232 # Nor in a string
234 233 check_find(ipt2.HelpEnd, (["foo = '''bar?\n"], None, None), match=False)
235 234
236 235 def test_transform_help():
237 236 tf = ipt2.HelpEnd((1, 0), (1, 9))
238 237 assert tf.transform(HELP_IN_EXPR[0]) == HELP_IN_EXPR[2]
239 238
240 239 tf = ipt2.HelpEnd((1, 0), (2, 3))
241 240 assert tf.transform(HELP_CONTINUED_LINE[0]) == HELP_CONTINUED_LINE[2]
242 241
243 242 tf = ipt2.HelpEnd((1, 0), (2, 8))
244 243 assert tf.transform(HELP_MULTILINE[0]) == HELP_MULTILINE[2]
245 244
246 245 tf = ipt2.HelpEnd((1, 0), (1, 0))
247 246 assert tf.transform(HELP_UNICODE[0]) == HELP_UNICODE[2]
248 247
249 248 def test_find_assign_op_dedent():
250 249 """
251 250 be careful that empty token like dedent are not counted as parens
252 251 """
253 252 class Tk:
254 253 def __init__(self, s):
255 254 self.string = s
256 255
257 256 assert _find_assign_op([Tk(s) for s in ("", "a", "=", "b")]) == 2
258 257 assert (
259 258 _find_assign_op([Tk(s) for s in ("", "(", "a", "=", "b", ")", "=", "5")]) == 6
260 259 )
261 260
262 261
263 262 examples = [
264 263 pytest.param("a = 1", "complete", None),
265 264 pytest.param("for a in range(5):", "incomplete", 4),
266 265 pytest.param("for a in range(5):\n if a > 0:", "incomplete", 8),
267 266 pytest.param("raise = 2", "invalid", None),
268 267 pytest.param("a = [1,\n2,", "incomplete", 0),
269 268 pytest.param("(\n))", "incomplete", 0),
270 269 pytest.param("\\\r\n", "incomplete", 0),
271 270 pytest.param("a = '''\n hi", "incomplete", 3),
272 271 pytest.param("def a():\n x=1\n global x", "invalid", None),
273 272 pytest.param(
274 273 "a \\ ",
275 274 "invalid",
276 275 None,
277 276 marks=pytest.mark.xfail(
278 277 reason="Bug in python 3.9.8 – bpo 45738",
279 278 condition=sys.version_info[:3] == (3, 9, 8),
280 279 raises=SystemError,
281 280 strict=True,
282 281 ),
283 282 ), # Nothing allowed after backslash,
284 283 pytest.param("1\\\n+2", "complete", None),
285 284 ]
286 285
287 286
288 @skip_iptest_but_not_pytest
289 287 @pytest.mark.parametrize("code, expected, number", examples)
290 288 def test_check_complete_param(code, expected, number):
291 289 cc = ipt2.TransformerManager().check_complete
292 290 assert cc(code) == (expected, number)
293 291
294 292
295 @skip_iptest_but_not_pytest
296 293 @pytest.mark.xfail(
297 294 reason="Bug in python 3.9.8 – bpo 45738",
298 295 condition=sys.version_info[:3] == (3, 9, 8),
299 296 )
300 297 def test_check_complete():
301 298 cc = ipt2.TransformerManager().check_complete
302 299
303 300 example = dedent("""
304 301 if True:
305 302 a=1""" )
306 303
307 304 assert cc(example) == ("incomplete", 4)
308 305 assert cc(example + "\n") == ("complete", None)
309 306 assert cc(example + "\n ") == ("complete", None)
310 307
311 308 # no need to loop on all the letters/numbers.
312 309 short = '12abAB'+string.printable[62:]
313 310 for c in short:
314 311 # test does not raise:
315 312 cc(c)
316 313 for k in short:
317 314 cc(c+k)
318 315
319 316 assert cc("def f():\n x=0\n \\\n ") == ("incomplete", 2)
320 317
321 318
322 319 def test_check_complete_II():
323 320 """
324 321 Test that multiple line strings are properly handled.
325 322
326 323 Separate test function for convenience
327 324
328 325 """
329 326 cc = ipt2.TransformerManager().check_complete
330 327 assert cc('''def foo():\n """''') == ("incomplete", 4)
331 328
332 329
333 330 def test_check_complete_invalidates_sunken_brackets():
334 331 """
335 332 Test that a single line with more closing brackets than the opening ones is
336 333 interpreted as invalid
337 334 """
338 335 cc = ipt2.TransformerManager().check_complete
339 336 assert cc(")") == ("invalid", None)
340 337 assert cc("]") == ("invalid", None)
341 338 assert cc("}") == ("invalid", None)
342 339 assert cc(")(") == ("invalid", None)
343 340 assert cc("][") == ("invalid", None)
344 341 assert cc("}{") == ("invalid", None)
345 342 assert cc("]()(") == ("invalid", None)
346 343 assert cc("())(") == ("invalid", None)
347 344 assert cc(")[](") == ("invalid", None)
348 345 assert cc("()](") == ("invalid", None)
349 346
350 347
351 348 def test_null_cleanup_transformer():
352 349 manager = ipt2.TransformerManager()
353 350 manager.cleanup_transforms.insert(0, null_cleanup_transformer)
354 351 assert manager.transform_cell("") == ""
355 352
356 353
357 354
358 355
359 356 def test_side_effects_I():
360 357 count = 0
361 358 def counter(lines):
362 359 nonlocal count
363 360 count += 1
364 361 return lines
365 362
366 363 counter.has_side_effects = True
367 364
368 365 manager = ipt2.TransformerManager()
369 366 manager.cleanup_transforms.insert(0, counter)
370 367 assert manager.check_complete("a=1\n") == ('complete', None)
371 368 assert count == 0
372 369
373 370
374 371
375 372
376 373 def test_side_effects_II():
377 374 count = 0
378 375 def counter(lines):
379 376 nonlocal count
380 377 count += 1
381 378 return lines
382 379
383 380 counter.has_side_effects = True
384 381
385 382 manager = ipt2.TransformerManager()
386 383 manager.line_transforms.insert(0, counter)
387 384 assert manager.check_complete("b=1\n") == ('complete', None)
388 385 assert count == 0
@@ -1,1364 +1,1358
1 1 # -*- coding: utf-8 -*-
2 2 """Tests for various magic functions."""
3 3
4 4 import asyncio
5 5 import io
6 6 import os
7 7 import re
8 8 import shlex
9 9 import sys
10 10 import warnings
11 11 from importlib import invalidate_caches
12 12 from io import StringIO
13 13 from pathlib import Path
14 14 from textwrap import dedent
15 15 from unittest import TestCase, mock
16 16
17 17 import pytest
18 18
19 19 from IPython import get_ipython
20 20 from IPython.core import magic
21 21 from IPython.core.error import UsageError
22 22 from IPython.core.magic import (
23 23 Magics,
24 24 cell_magic,
25 25 line_magic,
26 26 magics_class,
27 27 register_cell_magic,
28 28 register_line_magic,
29 29 )
30 30 from IPython.core.magics import code, execution, logging, osm, script
31 31 from IPython.testing import decorators as dec
32 32 from IPython.testing import tools as tt
33 33 from IPython.utils.io import capture_output
34 34 from IPython.utils.process import find_cmd
35 35 from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory
36 36
37 37 from .test_debugger import PdbTestInput
38 38
39 39
40 40 @magic.magics_class
41 41 class DummyMagics(magic.Magics): pass
42 42
43 43 def test_extract_code_ranges():
44 44 instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
45 45 expected = [
46 46 (0, 1),
47 47 (2, 3),
48 48 (4, 6),
49 49 (6, 9),
50 50 (9, 14),
51 51 (16, None),
52 52 (None, 9),
53 53 (9, None),
54 54 (None, 13),
55 55 (None, None),
56 56 ]
57 57 actual = list(code.extract_code_ranges(instr))
58 58 assert actual == expected
59 59
60 60 def test_extract_symbols():
61 61 source = """import foo\na = 10\ndef b():\n return 42\n\n\nclass A: pass\n\n\n"""
62 62 symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
63 63 expected = [([], ['a']),
64 64 (["def b():\n return 42\n"], []),
65 65 (["class A: pass\n"], []),
66 66 (["class A: pass\n", "def b():\n return 42\n"], []),
67 67 (["class A: pass\n"], ['a']),
68 68 ([], ['z'])]
69 69 for symbols, exp in zip(symbols_args, expected):
70 70 assert code.extract_symbols(source, symbols) == exp
71 71
72 72
73 73 def test_extract_symbols_raises_exception_with_non_python_code():
74 74 source = ("=begin A Ruby program :)=end\n"
75 75 "def hello\n"
76 76 "puts 'Hello world'\n"
77 77 "end")
78 78 with pytest.raises(SyntaxError):
79 79 code.extract_symbols(source, "hello")
80 80
81 81
82 82 def test_magic_not_found():
83 83 # magic not found raises UsageError
84 84 with pytest.raises(UsageError):
85 85 _ip.magic('doesntexist')
86 86
87 87 # ensure result isn't success when a magic isn't found
88 88 result = _ip.run_cell('%doesntexist')
89 89 assert isinstance(result.error_in_exec, UsageError)
90 90
91 91
92 92 def test_cell_magic_not_found():
93 93 # magic not found raises UsageError
94 94 with pytest.raises(UsageError):
95 95 _ip.run_cell_magic('doesntexist', 'line', 'cell')
96 96
97 97 # ensure result isn't success when a magic isn't found
98 98 result = _ip.run_cell('%%doesntexist')
99 99 assert isinstance(result.error_in_exec, UsageError)
100 100
101 101
102 102 def test_magic_error_status():
103 103 def fail(shell):
104 104 1/0
105 105 _ip.register_magic_function(fail)
106 106 result = _ip.run_cell('%fail')
107 107 assert isinstance(result.error_in_exec, ZeroDivisionError)
108 108
109 109
110 110 def test_config():
111 111 """ test that config magic does not raise
112 112 can happen if Configurable init is moved too early into
113 113 Magics.__init__ as then a Config object will be registered as a
114 114 magic.
115 115 """
116 116 ## should not raise.
117 117 _ip.magic('config')
118 118
119 119 def test_config_available_configs():
120 120 """ test that config magic prints available configs in unique and
121 121 sorted order. """
122 122 with capture_output() as captured:
123 123 _ip.magic('config')
124 124
125 125 stdout = captured.stdout
126 126 config_classes = stdout.strip().split('\n')[1:]
127 127 assert config_classes == sorted(set(config_classes))
128 128
129 129 def test_config_print_class():
130 130 """ test that config with a classname prints the class's options. """
131 131 with capture_output() as captured:
132 132 _ip.magic('config TerminalInteractiveShell')
133 133
134 134 stdout = captured.stdout
135 135 assert re.match(
136 136 "TerminalInteractiveShell.* options", stdout.splitlines()[0]
137 137 ), f"{stdout}\n\n1st line of stdout not like 'TerminalInteractiveShell.* options'"
138 138
139 139
140 140 def test_rehashx():
141 141 # clear up everything
142 142 _ip.alias_manager.clear_aliases()
143 143 del _ip.db['syscmdlist']
144 144
145 145 _ip.magic('rehashx')
146 146 # Practically ALL ipython development systems will have more than 10 aliases
147 147
148 148 assert len(_ip.alias_manager.aliases) > 10
149 149 for name, cmd in _ip.alias_manager.aliases:
150 150 # we must strip dots from alias names
151 151 assert "." not in name
152 152
153 153 # rehashx must fill up syscmdlist
154 154 scoms = _ip.db['syscmdlist']
155 155 assert len(scoms) > 10
156 156
157 157
158 158 def test_magic_parse_options():
159 159 """Test that we don't mangle paths when parsing magic options."""
160 160 ip = get_ipython()
161 161 path = 'c:\\x'
162 162 m = DummyMagics(ip)
163 163 opts = m.parse_options('-f %s' % path,'f:')[0]
164 164 # argv splitting is os-dependent
165 165 if os.name == 'posix':
166 166 expected = 'c:x'
167 167 else:
168 168 expected = path
169 169 assert opts["f"] == expected
170 170
171 171
172 172 def test_magic_parse_long_options():
173 173 """Magic.parse_options can handle --foo=bar long options"""
174 174 ip = get_ipython()
175 175 m = DummyMagics(ip)
176 176 opts, _ = m.parse_options("--foo --bar=bubble", "a", "foo", "bar=")
177 177 assert "foo" in opts
178 178 assert "bar" in opts
179 179 assert opts["bar"] == "bubble"
180 180
181 181
182 182 def doctest_hist_f():
183 183 """Test %hist -f with temporary filename.
184 184
185 185 In [9]: import tempfile
186 186
187 187 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
188 188
189 189 In [11]: %hist -nl -f $tfile 3
190 190
191 191 In [13]: import os; os.unlink(tfile)
192 192 """
193 193
194 194
195 195 def doctest_hist_op():
196 196 """Test %hist -op
197 197
198 198 In [1]: class b(float):
199 199 ...: pass
200 200 ...:
201 201
202 202 In [2]: class s(object):
203 203 ...: def __str__(self):
204 204 ...: return 's'
205 205 ...:
206 206
207 207 In [3]:
208 208
209 209 In [4]: class r(b):
210 210 ...: def __repr__(self):
211 211 ...: return 'r'
212 212 ...:
213 213
214 214 In [5]: class sr(s,r): pass
215 215 ...:
216 216
217 217 In [6]:
218 218
219 219 In [7]: bb=b()
220 220
221 221 In [8]: ss=s()
222 222
223 223 In [9]: rr=r()
224 224
225 225 In [10]: ssrr=sr()
226 226
227 227 In [11]: 4.5
228 228 Out[11]: 4.5
229 229
230 230 In [12]: str(ss)
231 231 Out[12]: 's'
232 232
233 233 In [13]:
234 234
235 235 In [14]: %hist -op
236 236 >>> class b:
237 237 ... pass
238 238 ...
239 239 >>> class s(b):
240 240 ... def __str__(self):
241 241 ... return 's'
242 242 ...
243 243 >>>
244 244 >>> class r(b):
245 245 ... def __repr__(self):
246 246 ... return 'r'
247 247 ...
248 248 >>> class sr(s,r): pass
249 249 >>>
250 250 >>> bb=b()
251 251 >>> ss=s()
252 252 >>> rr=r()
253 253 >>> ssrr=sr()
254 254 >>> 4.5
255 255 4.5
256 256 >>> str(ss)
257 257 's'
258 258 >>>
259 259 """
260 260
261 261 def test_hist_pof():
262 262 ip = get_ipython()
263 263 ip.run_cell("1+2", store_history=True)
264 264 #raise Exception(ip.history_manager.session_number)
265 265 #raise Exception(list(ip.history_manager._get_range_session()))
266 266 with TemporaryDirectory() as td:
267 267 tf = os.path.join(td, 'hist.py')
268 268 ip.run_line_magic('history', '-pof %s' % tf)
269 269 assert os.path.isfile(tf)
270 270
271 271
272 272 def test_macro():
273 273 ip = get_ipython()
274 274 ip.history_manager.reset() # Clear any existing history.
275 275 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
276 276 for i, cmd in enumerate(cmds, start=1):
277 277 ip.history_manager.store_inputs(i, cmd)
278 278 ip.magic("macro test 1-3")
279 279 assert ip.user_ns["test"].value == "\n".join(cmds) + "\n"
280 280
281 281 # List macros
282 282 assert "test" in ip.magic("macro")
283 283
284 284
285 285 def test_macro_run():
286 286 """Test that we can run a multi-line macro successfully."""
287 287 ip = get_ipython()
288 288 ip.history_manager.reset()
289 289 cmds = ["a=10", "a+=1", "print(a)", "%macro test 2-3"]
290 290 for cmd in cmds:
291 291 ip.run_cell(cmd, store_history=True)
292 292 assert ip.user_ns["test"].value == "a+=1\nprint(a)\n"
293 293 with tt.AssertPrints("12"):
294 294 ip.run_cell("test")
295 295 with tt.AssertPrints("13"):
296 296 ip.run_cell("test")
297 297
298 298
299 299 def test_magic_magic():
300 300 """Test %magic"""
301 301 ip = get_ipython()
302 302 with capture_output() as captured:
303 303 ip.magic("magic")
304 304
305 305 stdout = captured.stdout
306 306 assert "%magic" in stdout
307 307 assert "IPython" in stdout
308 308 assert "Available" in stdout
309 309
310 310
311 311 @dec.skipif_not_numpy
312 312 def test_numpy_reset_array_undec():
313 313 "Test '%reset array' functionality"
314 314 _ip.ex("import numpy as np")
315 315 _ip.ex("a = np.empty(2)")
316 316 assert "a" in _ip.user_ns
317 317 _ip.magic("reset -f array")
318 318 assert "a" not in _ip.user_ns
319 319
320 320
321 321 def test_reset_out():
322 322 "Test '%reset out' magic"
323 323 _ip.run_cell("parrot = 'dead'", store_history=True)
324 324 # test '%reset -f out', make an Out prompt
325 325 _ip.run_cell("parrot", store_history=True)
326 326 assert "dead" in [_ip.user_ns[x] for x in ("_", "__", "___")]
327 327 _ip.magic("reset -f out")
328 328 assert "dead" not in [_ip.user_ns[x] for x in ("_", "__", "___")]
329 329 assert len(_ip.user_ns["Out"]) == 0
330 330
331 331
332 332 def test_reset_in():
333 333 "Test '%reset in' magic"
334 334 # test '%reset -f in'
335 335 _ip.run_cell("parrot", store_history=True)
336 336 assert "parrot" in [_ip.user_ns[x] for x in ("_i", "_ii", "_iii")]
337 337 _ip.magic("%reset -f in")
338 338 assert "parrot" not in [_ip.user_ns[x] for x in ("_i", "_ii", "_iii")]
339 339 assert len(set(_ip.user_ns["In"])) == 1
340 340
341 341
342 342 def test_reset_dhist():
343 343 "Test '%reset dhist' magic"
344 344 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
345 345 _ip.magic("cd " + os.path.dirname(pytest.__file__))
346 346 _ip.magic("cd -")
347 347 assert len(_ip.user_ns["_dh"]) > 0
348 348 _ip.magic("reset -f dhist")
349 349 assert len(_ip.user_ns["_dh"]) == 0
350 350 _ip.run_cell("_dh = [d for d in tmp]") # restore
351 351
352 352
353 353 def test_reset_in_length():
354 354 "Test that '%reset in' preserves In[] length"
355 355 _ip.run_cell("print 'foo'")
356 356 _ip.run_cell("reset -f in")
357 357 assert len(_ip.user_ns["In"]) == _ip.displayhook.prompt_count + 1
358 358
359 359
360 360 class TestResetErrors(TestCase):
361 361
362 362 def test_reset_redefine(self):
363 363
364 364 @magics_class
365 365 class KernelMagics(Magics):
366 366 @line_magic
367 367 def less(self, shell): pass
368 368
369 369 _ip.register_magics(KernelMagics)
370 370
371 371 with self.assertLogs() as cm:
372 372 # hack, we want to just capture logs, but assertLogs fails if not
373 373 # logs get produce.
374 374 # so log one things we ignore.
375 375 import logging as log_mod
376 376 log = log_mod.getLogger()
377 377 log.info('Nothing')
378 378 # end hack.
379 379 _ip.run_cell("reset -f")
380 380
381 381 assert len(cm.output) == 1
382 382 for out in cm.output:
383 383 assert "Invalid alias" not in out
384 384
385 385 def test_tb_syntaxerror():
386 386 """test %tb after a SyntaxError"""
387 387 ip = get_ipython()
388 388 ip.run_cell("for")
389 389
390 390 # trap and validate stdout
391 391 save_stdout = sys.stdout
392 392 try:
393 393 sys.stdout = StringIO()
394 394 ip.run_cell("%tb")
395 395 out = sys.stdout.getvalue()
396 396 finally:
397 397 sys.stdout = save_stdout
398 398 # trim output, and only check the last line
399 399 last_line = out.rstrip().splitlines()[-1].strip()
400 400 assert last_line == "SyntaxError: invalid syntax"
401 401
402 402
403 403 def test_time():
404 404 ip = get_ipython()
405 405
406 406 with tt.AssertPrints("Wall time: "):
407 407 ip.run_cell("%time None")
408 408
409 409 ip.run_cell("def f(kmjy):\n"
410 410 " %time print (2*kmjy)")
411 411
412 412 with tt.AssertPrints("Wall time: "):
413 413 with tt.AssertPrints("hihi", suppress=False):
414 414 ip.run_cell("f('hi')")
415 415
416 416 def test_time_last_not_expression():
417 417 ip.run_cell("%%time\n"
418 418 "var_1 = 1\n"
419 419 "var_2 = 2\n")
420 420 assert ip.user_ns['var_1'] == 1
421 421 del ip.user_ns['var_1']
422 422 assert ip.user_ns['var_2'] == 2
423 423 del ip.user_ns['var_2']
424 424
425 425
426 426 @dec.skip_win32
427 427 def test_time2():
428 428 ip = get_ipython()
429 429
430 430 with tt.AssertPrints("CPU times: user "):
431 431 ip.run_cell("%time None")
432 432
433 433 def test_time3():
434 434 """Erroneous magic function calls, issue gh-3334"""
435 435 ip = get_ipython()
436 436 ip.user_ns.pop('run', None)
437 437
438 438 with tt.AssertNotPrints("not found", channel='stderr'):
439 439 ip.run_cell("%%time\n"
440 440 "run = 0\n"
441 441 "run += 1")
442 442
443 443 def test_multiline_time():
444 444 """Make sure last statement from time return a value."""
445 445 ip = get_ipython()
446 446 ip.user_ns.pop('run', None)
447 447
448 448 ip.run_cell(dedent("""\
449 449 %%time
450 450 a = "ho"
451 451 b = "hey"
452 452 a+b
453 453 """
454 454 )
455 455 )
456 456 assert ip.user_ns_hidden["_"] == "hohey"
457 457
458 458
459 459 def test_time_local_ns():
460 460 """
461 461 Test that local_ns is actually global_ns when running a cell magic
462 462 """
463 463 ip = get_ipython()
464 464 ip.run_cell("%%time\n" "myvar = 1")
465 465 assert ip.user_ns["myvar"] == 1
466 466 del ip.user_ns["myvar"]
467 467
468 468
469 469 def test_doctest_mode():
470 470 "Toggle doctest_mode twice, it should be a no-op and run without error"
471 471 _ip.magic('doctest_mode')
472 472 _ip.magic('doctest_mode')
473 473
474 474
475 475 def test_parse_options():
476 476 """Tests for basic options parsing in magics."""
477 477 # These are only the most minimal of tests, more should be added later. At
478 478 # the very least we check that basic text/unicode calls work OK.
479 479 m = DummyMagics(_ip)
480 480 assert m.parse_options("foo", "")[1] == "foo"
481 481 assert m.parse_options("foo", "")[1] == "foo"
482 482
483 483
484 484 def test_parse_options_preserve_non_option_string():
485 485 """Test to assert preservation of non-option part of magic-block, while parsing magic options."""
486 486 m = DummyMagics(_ip)
487 487 opts, stmt = m.parse_options(
488 488 " -n1 -r 13 _ = 314 + foo", "n:r:", preserve_non_opts=True
489 489 )
490 490 assert opts == {"n": "1", "r": "13"}
491 491 assert stmt == "_ = 314 + foo"
492 492
493 493
494 494 def test_run_magic_preserve_code_block():
495 495 """Test to assert preservation of non-option part of magic-block, while running magic."""
496 496 _ip.user_ns["spaces"] = []
497 497 _ip.magic("timeit -n1 -r1 spaces.append([s.count(' ') for s in ['document']])")
498 498 assert _ip.user_ns["spaces"] == [[0]]
499 499
500 500
501 501 def test_dirops():
502 502 """Test various directory handling operations."""
503 503 # curpath = lambda :os.path.splitdrive(os.getcwd())[1].replace('\\','/')
504 504 curpath = os.getcwd
505 505 startdir = os.getcwd()
506 506 ipdir = os.path.realpath(_ip.ipython_dir)
507 507 try:
508 508 _ip.magic('cd "%s"' % ipdir)
509 509 assert curpath() == ipdir
510 510 _ip.magic('cd -')
511 511 assert curpath() == startdir
512 512 _ip.magic('pushd "%s"' % ipdir)
513 513 assert curpath() == ipdir
514 514 _ip.magic('popd')
515 515 assert curpath() == startdir
516 516 finally:
517 517 os.chdir(startdir)
518 518
519 519
520 520 def test_cd_force_quiet():
521 521 """Test OSMagics.cd_force_quiet option"""
522 522 _ip.config.OSMagics.cd_force_quiet = True
523 523 osmagics = osm.OSMagics(shell=_ip)
524 524
525 525 startdir = os.getcwd()
526 526 ipdir = os.path.realpath(_ip.ipython_dir)
527 527
528 528 try:
529 529 with tt.AssertNotPrints(ipdir):
530 530 osmagics.cd('"%s"' % ipdir)
531 531 with tt.AssertNotPrints(startdir):
532 532 osmagics.cd('-')
533 533 finally:
534 534 os.chdir(startdir)
535 535
536 536
537 537 def test_xmode():
538 538 # Calling xmode three times should be a no-op
539 539 xmode = _ip.InteractiveTB.mode
540 540 for i in range(4):
541 541 _ip.magic("xmode")
542 542 assert _ip.InteractiveTB.mode == xmode
543 543
544 544 def test_reset_hard():
545 545 monitor = []
546 546 class A(object):
547 547 def __del__(self):
548 548 monitor.append(1)
549 549 def __repr__(self):
550 550 return "<A instance>"
551 551
552 552 _ip.user_ns["a"] = A()
553 553 _ip.run_cell("a")
554 554
555 555 assert monitor == []
556 556 _ip.magic("reset -f")
557 557 assert monitor == [1]
558 558
559 559 class TestXdel(tt.TempFileMixin):
560 560 def test_xdel(self):
561 561 """Test that references from %run are cleared by xdel."""
562 562 src = ("class A(object):\n"
563 563 " monitor = []\n"
564 564 " def __del__(self):\n"
565 565 " self.monitor.append(1)\n"
566 566 "a = A()\n")
567 567 self.mktmp(src)
568 568 # %run creates some hidden references...
569 569 _ip.magic("run %s" % self.fname)
570 570 # ... as does the displayhook.
571 571 _ip.run_cell("a")
572 572
573 573 monitor = _ip.user_ns["A"].monitor
574 574 assert monitor == []
575 575
576 576 _ip.magic("xdel a")
577 577
578 578 # Check that a's __del__ method has been called.
579 579 assert monitor == [1]
580 580
581 581 def doctest_who():
582 582 """doctest for %who
583 583
584 584 In [1]: %reset -sf
585 585
586 586 In [2]: alpha = 123
587 587
588 588 In [3]: beta = 'beta'
589 589
590 590 In [4]: %who int
591 591 alpha
592 592
593 593 In [5]: %who str
594 594 beta
595 595
596 596 In [6]: %whos
597 597 Variable Type Data/Info
598 598 ----------------------------
599 599 alpha int 123
600 600 beta str beta
601 601
602 602 In [7]: %who_ls
603 603 Out[7]: ['alpha', 'beta']
604 604 """
605 605
606 606 def test_whos():
607 607 """Check that whos is protected against objects where repr() fails."""
608 608 class A(object):
609 609 def __repr__(self):
610 610 raise Exception()
611 611 _ip.user_ns['a'] = A()
612 612 _ip.magic("whos")
613 613
614 614 def doctest_precision():
615 615 """doctest for %precision
616 616
617 617 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
618 618
619 619 In [2]: %precision 5
620 620 Out[2]: '%.5f'
621 621
622 622 In [3]: f.float_format
623 623 Out[3]: '%.5f'
624 624
625 625 In [4]: %precision %e
626 626 Out[4]: '%e'
627 627
628 628 In [5]: f(3.1415927)
629 629 Out[5]: '3.141593e+00'
630 630 """
631 631
632 632 def test_debug_magic():
633 633 """Test debugging a small code with %debug
634 634
635 635 In [1]: with PdbTestInput(['c']):
636 636 ...: %debug print("a b") #doctest: +ELLIPSIS
637 637 ...:
638 638 ...
639 639 ipdb> c
640 640 a b
641 641 In [2]:
642 642 """
643 643
644 644 def test_psearch():
645 645 with tt.AssertPrints("dict.fromkeys"):
646 646 _ip.run_cell("dict.fr*?")
647 647 with tt.AssertPrints("Ο€.is_integer"):
648 648 _ip.run_cell("Ο€ = 3.14;\nΟ€.is_integ*?")
649 649
650 650 def test_timeit_shlex():
651 651 """test shlex issues with timeit (#1109)"""
652 652 _ip.ex("def f(*a,**kw): pass")
653 653 _ip.magic('timeit -n1 "this is a bug".count(" ")')
654 654 _ip.magic('timeit -r1 -n1 f(" ", 1)')
655 655 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
656 656 _ip.magic('timeit -r1 -n1 ("a " + "b")')
657 657 _ip.magic('timeit -r1 -n1 f("a " + "b")')
658 658 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
659 659
660 660
661 661 def test_timeit_special_syntax():
662 662 "Test %%timeit with IPython special syntax"
663 663 @register_line_magic
664 664 def lmagic(line):
665 665 ip = get_ipython()
666 666 ip.user_ns['lmagic_out'] = line
667 667
668 668 # line mode test
669 669 _ip.run_line_magic("timeit", "-n1 -r1 %lmagic my line")
670 670 assert _ip.user_ns["lmagic_out"] == "my line"
671 671 # cell mode test
672 672 _ip.run_cell_magic("timeit", "-n1 -r1", "%lmagic my line2")
673 673 assert _ip.user_ns["lmagic_out"] == "my line2"
674 674
675 675
676 676 def test_timeit_return():
677 677 """
678 678 test whether timeit -o return object
679 679 """
680 680
681 681 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
682 682 assert(res is not None)
683 683
684 684 def test_timeit_quiet():
685 685 """
686 686 test quiet option of timeit magic
687 687 """
688 688 with tt.AssertNotPrints("loops"):
689 689 _ip.run_cell("%timeit -n1 -r1 -q 1")
690 690
691 691 def test_timeit_return_quiet():
692 692 with tt.AssertNotPrints("loops"):
693 693 res = _ip.run_line_magic('timeit', '-n1 -r1 -q -o 1')
694 694 assert (res is not None)
695 695
696 696 def test_timeit_invalid_return():
697 697 with pytest.raises(SyntaxError):
698 698 _ip.run_line_magic('timeit', 'return')
699 699
700 700 @dec.skipif(execution.profile is None)
701 701 def test_prun_special_syntax():
702 702 "Test %%prun with IPython special syntax"
703 703 @register_line_magic
704 704 def lmagic(line):
705 705 ip = get_ipython()
706 706 ip.user_ns['lmagic_out'] = line
707 707
708 708 # line mode test
709 709 _ip.run_line_magic("prun", "-q %lmagic my line")
710 710 assert _ip.user_ns["lmagic_out"] == "my line"
711 711 # cell mode test
712 712 _ip.run_cell_magic("prun", "-q", "%lmagic my line2")
713 713 assert _ip.user_ns["lmagic_out"] == "my line2"
714 714
715 715
716 716 @dec.skipif(execution.profile is None)
717 717 def test_prun_quotes():
718 718 "Test that prun does not clobber string escapes (GH #1302)"
719 719 _ip.magic(r"prun -q x = '\t'")
720 720 assert _ip.user_ns["x"] == "\t"
721 721
722 722
723 723 def test_extension():
724 724 # Debugging information for failures of this test
725 725 print('sys.path:')
726 726 for p in sys.path:
727 727 print(' ', p)
728 728 print('CWD', os.getcwd())
729 729
730 730 pytest.raises(ImportError, _ip.magic, "load_ext daft_extension")
731 731 daft_path = os.path.join(os.path.dirname(__file__), "daft_extension")
732 732 sys.path.insert(0, daft_path)
733 733 try:
734 734 _ip.user_ns.pop('arq', None)
735 735 invalidate_caches() # Clear import caches
736 736 _ip.magic("load_ext daft_extension")
737 737 assert _ip.user_ns["arq"] == 185
738 738 _ip.magic("unload_ext daft_extension")
739 739 assert 'arq' not in _ip.user_ns
740 740 finally:
741 741 sys.path.remove(daft_path)
742 742
743 743
744 744 def test_notebook_export_json():
745 745 _ip = get_ipython()
746 746 _ip.history_manager.reset() # Clear any existing history.
747 747 cmds = ["a=1", "def b():\n return a**2", "print('noΓ«l, Γ©tΓ©', b())"]
748 748 for i, cmd in enumerate(cmds, start=1):
749 749 _ip.history_manager.store_inputs(i, cmd)
750 750 with TemporaryDirectory() as td:
751 751 outfile = os.path.join(td, "nb.ipynb")
752 752 _ip.magic("notebook -e %s" % outfile)
753 753
754 754
755 755 class TestEnv(TestCase):
756 756
757 757 def test_env(self):
758 758 env = _ip.magic("env")
759 759 self.assertTrue(isinstance(env, dict))
760 760
761 761 def test_env_secret(self):
762 762 env = _ip.magic("env")
763 763 hidden = "<hidden>"
764 764 with mock.patch.dict(
765 765 os.environ,
766 766 {
767 767 "API_KEY": "abc123",
768 768 "SECRET_THING": "ssshhh",
769 769 "JUPYTER_TOKEN": "",
770 770 "VAR": "abc"
771 771 }
772 772 ):
773 773 env = _ip.magic("env")
774 774 assert env["API_KEY"] == hidden
775 775 assert env["SECRET_THING"] == hidden
776 776 assert env["JUPYTER_TOKEN"] == hidden
777 777 assert env["VAR"] == "abc"
778 778
779 779 def test_env_get_set_simple(self):
780 780 env = _ip.magic("env var val1")
781 781 self.assertEqual(env, None)
782 782 self.assertEqual(os.environ['var'], 'val1')
783 783 self.assertEqual(_ip.magic("env var"), 'val1')
784 784 env = _ip.magic("env var=val2")
785 785 self.assertEqual(env, None)
786 786 self.assertEqual(os.environ['var'], 'val2')
787 787
788 788 def test_env_get_set_complex(self):
789 789 env = _ip.magic("env var 'val1 '' 'val2")
790 790 self.assertEqual(env, None)
791 791 self.assertEqual(os.environ['var'], "'val1 '' 'val2")
792 792 self.assertEqual(_ip.magic("env var"), "'val1 '' 'val2")
793 793 env = _ip.magic('env var=val2 val3="val4')
794 794 self.assertEqual(env, None)
795 795 self.assertEqual(os.environ['var'], 'val2 val3="val4')
796 796
797 797 def test_env_set_bad_input(self):
798 798 self.assertRaises(UsageError, lambda: _ip.magic("set_env var"))
799 799
800 800 def test_env_set_whitespace(self):
801 801 self.assertRaises(UsageError, lambda: _ip.magic("env var A=B"))
802 802
803 803
804 804 class CellMagicTestCase(TestCase):
805 805
806 806 def check_ident(self, magic):
807 807 # Manually called, we get the result
808 808 out = _ip.run_cell_magic(magic, "a", "b")
809 809 assert out == ("a", "b")
810 810 # Via run_cell, it goes into the user's namespace via displayhook
811 811 _ip.run_cell("%%" + magic + " c\nd\n")
812 812 assert _ip.user_ns["_"] == ("c", "d\n")
813 813
814 814 def test_cell_magic_func_deco(self):
815 815 "Cell magic using simple decorator"
816 816 @register_cell_magic
817 817 def cellm(line, cell):
818 818 return line, cell
819 819
820 820 self.check_ident('cellm')
821 821
822 822 def test_cell_magic_reg(self):
823 823 "Cell magic manually registered"
824 824 def cellm(line, cell):
825 825 return line, cell
826 826
827 827 _ip.register_magic_function(cellm, 'cell', 'cellm2')
828 828 self.check_ident('cellm2')
829 829
830 830 def test_cell_magic_class(self):
831 831 "Cell magics declared via a class"
832 832 @magics_class
833 833 class MyMagics(Magics):
834 834
835 835 @cell_magic
836 836 def cellm3(self, line, cell):
837 837 return line, cell
838 838
839 839 _ip.register_magics(MyMagics)
840 840 self.check_ident('cellm3')
841 841
842 842 def test_cell_magic_class2(self):
843 843 "Cell magics declared via a class, #2"
844 844 @magics_class
845 845 class MyMagics2(Magics):
846 846
847 847 @cell_magic('cellm4')
848 848 def cellm33(self, line, cell):
849 849 return line, cell
850 850
851 851 _ip.register_magics(MyMagics2)
852 852 self.check_ident('cellm4')
853 853 # Check that nothing is registered as 'cellm33'
854 854 c33 = _ip.find_cell_magic('cellm33')
855 855 assert c33 == None
856 856
857 857 def test_file():
858 858 """Basic %%writefile"""
859 859 ip = get_ipython()
860 860 with TemporaryDirectory() as td:
861 861 fname = os.path.join(td, 'file1')
862 862 ip.run_cell_magic("writefile", fname, u'\n'.join([
863 863 'line1',
864 864 'line2',
865 865 ]))
866 866 s = Path(fname).read_text()
867 867 assert "line1\n" in s
868 868 assert "line2" in s
869 869
870 870
871 871 @dec.skip_win32
872 872 def test_file_single_quote():
873 873 """Basic %%writefile with embedded single quotes"""
874 874 ip = get_ipython()
875 875 with TemporaryDirectory() as td:
876 876 fname = os.path.join(td, '\'file1\'')
877 877 ip.run_cell_magic("writefile", fname, u'\n'.join([
878 878 'line1',
879 879 'line2',
880 880 ]))
881 881 s = Path(fname).read_text()
882 882 assert "line1\n" in s
883 883 assert "line2" in s
884 884
885 885
886 886 @dec.skip_win32
887 887 def test_file_double_quote():
888 888 """Basic %%writefile with embedded double quotes"""
889 889 ip = get_ipython()
890 890 with TemporaryDirectory() as td:
891 891 fname = os.path.join(td, '"file1"')
892 892 ip.run_cell_magic("writefile", fname, u'\n'.join([
893 893 'line1',
894 894 'line2',
895 895 ]))
896 896 s = Path(fname).read_text()
897 897 assert "line1\n" in s
898 898 assert "line2" in s
899 899
900 900
901 901 def test_file_var_expand():
902 902 """%%writefile $filename"""
903 903 ip = get_ipython()
904 904 with TemporaryDirectory() as td:
905 905 fname = os.path.join(td, 'file1')
906 906 ip.user_ns['filename'] = fname
907 907 ip.run_cell_magic("writefile", '$filename', u'\n'.join([
908 908 'line1',
909 909 'line2',
910 910 ]))
911 911 s = Path(fname).read_text()
912 912 assert "line1\n" in s
913 913 assert "line2" in s
914 914
915 915
916 916 def test_file_unicode():
917 917 """%%writefile with unicode cell"""
918 918 ip = get_ipython()
919 919 with TemporaryDirectory() as td:
920 920 fname = os.path.join(td, 'file1')
921 921 ip.run_cell_magic("writefile", fname, u'\n'.join([
922 922 u'linΓ©1',
923 923 u'linΓ©2',
924 924 ]))
925 925 with io.open(fname, encoding='utf-8') as f:
926 926 s = f.read()
927 927 assert "linΓ©1\n" in s
928 928 assert "linΓ©2" in s
929 929
930 930
931 931 def test_file_amend():
932 932 """%%writefile -a amends files"""
933 933 ip = get_ipython()
934 934 with TemporaryDirectory() as td:
935 935 fname = os.path.join(td, 'file2')
936 936 ip.run_cell_magic("writefile", fname, u'\n'.join([
937 937 'line1',
938 938 'line2',
939 939 ]))
940 940 ip.run_cell_magic("writefile", "-a %s" % fname, u'\n'.join([
941 941 'line3',
942 942 'line4',
943 943 ]))
944 944 s = Path(fname).read_text()
945 945 assert "line1\n" in s
946 946 assert "line3\n" in s
947 947
948 948
949 949 def test_file_spaces():
950 950 """%%file with spaces in filename"""
951 951 ip = get_ipython()
952 952 with TemporaryWorkingDirectory() as td:
953 953 fname = "file name"
954 954 ip.run_cell_magic("file", '"%s"'%fname, u'\n'.join([
955 955 'line1',
956 956 'line2',
957 957 ]))
958 958 s = Path(fname).read_text()
959 959 assert "line1\n" in s
960 960 assert "line2" in s
961 961
962 962
963 963 def test_script_config():
964 964 ip = get_ipython()
965 965 ip.config.ScriptMagics.script_magics = ['whoda']
966 966 sm = script.ScriptMagics(shell=ip)
967 967 assert "whoda" in sm.magics["cell"]
968 968
969 969
970 970 @pytest.fixture
971 971 def event_loop():
972 972 yield asyncio.get_event_loop_policy().get_event_loop()
973 973
974 974
975 @dec.skip_iptest_but_not_pytest
976 975 @dec.skip_win32
977 976 @pytest.mark.skipif(
978 977 sys.platform == "win32", reason="This test does not run under Windows"
979 978 )
980 979 def test_script_out(event_loop):
981 980 assert event_loop.is_running() is False
982 981
983 982 ip = get_ipython()
984 983 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
985 984 assert event_loop.is_running() is False
986 985 assert ip.user_ns["output"] == "hi\n"
987 986
988 987
989 @dec.skip_iptest_but_not_pytest
990 988 @dec.skip_win32
991 989 @pytest.mark.skipif(
992 990 sys.platform == "win32", reason="This test does not run under Windows"
993 991 )
994 992 def test_script_err(event_loop):
995 993 ip = get_ipython()
996 994 assert event_loop.is_running() is False
997 995 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
998 996 assert event_loop.is_running() is False
999 997 assert ip.user_ns["error"] == "hello\n"
1000 998
1001 999
1002 @dec.skip_iptest_but_not_pytest
1003 1000 @dec.skip_win32
1004 1001 @pytest.mark.skipif(
1005 1002 sys.platform == "win32", reason="This test does not run under Windows"
1006 1003 )
1007 1004 def test_script_out_err():
1008 1005
1009 1006 ip = get_ipython()
1010 1007 ip.run_cell_magic(
1011 1008 "script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2"
1012 1009 )
1013 1010 assert ip.user_ns["output"] == "hi\n"
1014 1011 assert ip.user_ns["error"] == "hello\n"
1015 1012
1016 1013
1017 @dec.skip_iptest_but_not_pytest
1018 1014 @dec.skip_win32
1019 1015 @pytest.mark.skipif(
1020 1016 sys.platform == "win32", reason="This test does not run under Windows"
1021 1017 )
1022 1018 async def test_script_bg_out(event_loop):
1023 1019 ip = get_ipython()
1024 1020 ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
1025 1021 assert (await ip.user_ns["output"].read()) == b"hi\n"
1026 1022 ip.user_ns["output"].close()
1027 1023 event_loop.stop()
1028 1024
1029 1025
1030 @dec.skip_iptest_but_not_pytest
1031 1026 @dec.skip_win32
1032 1027 @pytest.mark.skipif(
1033 1028 sys.platform == "win32", reason="This test does not run under Windows"
1034 1029 )
1035 1030 async def test_script_bg_err():
1036 1031 ip = get_ipython()
1037 1032 ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2")
1038 1033 assert (await ip.user_ns["error"].read()) == b"hello\n"
1039 1034 ip.user_ns["error"].close()
1040 1035
1041 1036
1042 @dec.skip_iptest_but_not_pytest
1043 1037 @dec.skip_win32
1044 1038 @pytest.mark.skipif(
1045 1039 sys.platform == "win32", reason="This test does not run under Windows"
1046 1040 )
1047 1041 async def test_script_bg_out_err():
1048 1042 ip = get_ipython()
1049 1043 ip.run_cell_magic(
1050 1044 "script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2"
1051 1045 )
1052 1046 assert (await ip.user_ns["output"].read()) == b"hi\n"
1053 1047 assert (await ip.user_ns["error"].read()) == b"hello\n"
1054 1048 ip.user_ns["output"].close()
1055 1049 ip.user_ns["error"].close()
1056 1050
1057 1051
1058 1052 def test_script_defaults():
1059 1053 ip = get_ipython()
1060 1054 for cmd in ['sh', 'bash', 'perl', 'ruby']:
1061 1055 try:
1062 1056 find_cmd(cmd)
1063 1057 except Exception:
1064 1058 pass
1065 1059 else:
1066 1060 assert cmd in ip.magics_manager.magics["cell"]
1067 1061
1068 1062
1069 1063 @magics_class
1070 1064 class FooFoo(Magics):
1071 1065 """class with both %foo and %%foo magics"""
1072 1066 @line_magic('foo')
1073 1067 def line_foo(self, line):
1074 1068 "I am line foo"
1075 1069 pass
1076 1070
1077 1071 @cell_magic("foo")
1078 1072 def cell_foo(self, line, cell):
1079 1073 "I am cell foo, not line foo"
1080 1074 pass
1081 1075
1082 1076 def test_line_cell_info():
1083 1077 """%%foo and %foo magics are distinguishable to inspect"""
1084 1078 ip = get_ipython()
1085 1079 ip.magics_manager.register(FooFoo)
1086 1080 oinfo = ip.object_inspect("foo")
1087 1081 assert oinfo["found"] is True
1088 1082 assert oinfo["ismagic"] is True
1089 1083
1090 1084 oinfo = ip.object_inspect("%%foo")
1091 1085 assert oinfo["found"] is True
1092 1086 assert oinfo["ismagic"] is True
1093 1087 assert oinfo["docstring"] == FooFoo.cell_foo.__doc__
1094 1088
1095 1089 oinfo = ip.object_inspect("%foo")
1096 1090 assert oinfo["found"] is True
1097 1091 assert oinfo["ismagic"] is True
1098 1092 assert oinfo["docstring"] == FooFoo.line_foo.__doc__
1099 1093
1100 1094
1101 1095 def test_multiple_magics():
1102 1096 ip = get_ipython()
1103 1097 foo1 = FooFoo(ip)
1104 1098 foo2 = FooFoo(ip)
1105 1099 mm = ip.magics_manager
1106 1100 mm.register(foo1)
1107 1101 assert mm.magics["line"]["foo"].__self__ is foo1
1108 1102 mm.register(foo2)
1109 1103 assert mm.magics["line"]["foo"].__self__ is foo2
1110 1104
1111 1105
1112 1106 def test_alias_magic():
1113 1107 """Test %alias_magic."""
1114 1108 ip = get_ipython()
1115 1109 mm = ip.magics_manager
1116 1110
1117 1111 # Basic operation: both cell and line magics are created, if possible.
1118 1112 ip.run_line_magic("alias_magic", "timeit_alias timeit")
1119 1113 assert "timeit_alias" in mm.magics["line"]
1120 1114 assert "timeit_alias" in mm.magics["cell"]
1121 1115
1122 1116 # --cell is specified, line magic not created.
1123 1117 ip.run_line_magic("alias_magic", "--cell timeit_cell_alias timeit")
1124 1118 assert "timeit_cell_alias" not in mm.magics["line"]
1125 1119 assert "timeit_cell_alias" in mm.magics["cell"]
1126 1120
1127 1121 # Test that line alias is created successfully.
1128 1122 ip.run_line_magic("alias_magic", "--line env_alias env")
1129 1123 assert ip.run_line_magic("env", "") == ip.run_line_magic("env_alias", "")
1130 1124
1131 1125 # Test that line alias with parameters passed in is created successfully.
1132 1126 ip.run_line_magic(
1133 1127 "alias_magic", "--line history_alias history --params " + shlex.quote("3")
1134 1128 )
1135 1129 assert "history_alias" in mm.magics["line"]
1136 1130
1137 1131
1138 1132 def test_save():
1139 1133 """Test %save."""
1140 1134 ip = get_ipython()
1141 1135 ip.history_manager.reset() # Clear any existing history.
1142 1136 cmds = ["a=1", "def b():\n return a**2", "print(a, b())"]
1143 1137 for i, cmd in enumerate(cmds, start=1):
1144 1138 ip.history_manager.store_inputs(i, cmd)
1145 1139 with TemporaryDirectory() as tmpdir:
1146 1140 file = os.path.join(tmpdir, "testsave.py")
1147 1141 ip.run_line_magic("save", "%s 1-10" % file)
1148 1142 content = Path(file).read_text()
1149 1143 assert content.count(cmds[0]) == 1
1150 1144 assert "coding: utf-8" in content
1151 1145 ip.run_line_magic("save", "-a %s 1-10" % file)
1152 1146 content = Path(file).read_text()
1153 1147 assert content.count(cmds[0]) == 2
1154 1148 assert "coding: utf-8" in content
1155 1149
1156 1150
1157 1151 def test_save_with_no_args():
1158 1152 ip = get_ipython()
1159 1153 ip.history_manager.reset() # Clear any existing history.
1160 1154 cmds = ["a=1", "def b():\n return a**2", "print(a, b())", "%save"]
1161 1155 for i, cmd in enumerate(cmds, start=1):
1162 1156 ip.history_manager.store_inputs(i, cmd)
1163 1157
1164 1158 with TemporaryDirectory() as tmpdir:
1165 1159 path = os.path.join(tmpdir, "testsave.py")
1166 1160 ip.run_line_magic("save", path)
1167 1161 content = Path(path).read_text()
1168 1162 expected_content = dedent(
1169 1163 """\
1170 1164 # coding: utf-8
1171 1165 a=1
1172 1166 def b():
1173 1167 return a**2
1174 1168 print(a, b())
1175 1169 """
1176 1170 )
1177 1171 assert content == expected_content
1178 1172
1179 1173
1180 1174 def test_store():
1181 1175 """Test %store."""
1182 1176 ip = get_ipython()
1183 1177 ip.run_line_magic('load_ext', 'storemagic')
1184 1178
1185 1179 # make sure the storage is empty
1186 1180 ip.run_line_magic("store", "-z")
1187 1181 ip.user_ns["var"] = 42
1188 1182 ip.run_line_magic("store", "var")
1189 1183 ip.user_ns["var"] = 39
1190 1184 ip.run_line_magic("store", "-r")
1191 1185 assert ip.user_ns["var"] == 42
1192 1186
1193 1187 ip.run_line_magic("store", "-d var")
1194 1188 ip.user_ns["var"] = 39
1195 1189 ip.run_line_magic("store", "-r")
1196 1190 assert ip.user_ns["var"] == 39
1197 1191
1198 1192
1199 1193 def _run_edit_test(arg_s, exp_filename=None,
1200 1194 exp_lineno=-1,
1201 1195 exp_contents=None,
1202 1196 exp_is_temp=None):
1203 1197 ip = get_ipython()
1204 1198 M = code.CodeMagics(ip)
1205 1199 last_call = ['','']
1206 1200 opts,args = M.parse_options(arg_s,'prxn:')
1207 1201 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
1208 1202
1209 1203 if exp_filename is not None:
1210 1204 assert exp_filename == filename
1211 1205 if exp_contents is not None:
1212 1206 with io.open(filename, 'r', encoding='utf-8') as f:
1213 1207 contents = f.read()
1214 1208 assert exp_contents == contents
1215 1209 if exp_lineno != -1:
1216 1210 assert exp_lineno == lineno
1217 1211 if exp_is_temp is not None:
1218 1212 assert exp_is_temp == is_temp
1219 1213
1220 1214
1221 1215 def test_edit_interactive():
1222 1216 """%edit on interactively defined objects"""
1223 1217 ip = get_ipython()
1224 1218 n = ip.execution_count
1225 1219 ip.run_cell("def foo(): return 1", store_history=True)
1226 1220
1227 1221 with pytest.raises(code.InteractivelyDefined) as e:
1228 1222 _run_edit_test("foo")
1229 1223 assert e.value.index == n
1230 1224
1231 1225
1232 1226 def test_edit_cell():
1233 1227 """%edit [cell id]"""
1234 1228 ip = get_ipython()
1235 1229
1236 1230 ip.run_cell("def foo(): return 1", store_history=True)
1237 1231
1238 1232 # test
1239 1233 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
1240 1234
1241 1235 def test_edit_fname():
1242 1236 """%edit file"""
1243 1237 # test
1244 1238 _run_edit_test("test file.py", exp_filename="test file.py")
1245 1239
1246 1240 def test_bookmark():
1247 1241 ip = get_ipython()
1248 1242 ip.run_line_magic('bookmark', 'bmname')
1249 1243 with tt.AssertPrints('bmname'):
1250 1244 ip.run_line_magic('bookmark', '-l')
1251 1245 ip.run_line_magic('bookmark', '-d bmname')
1252 1246
1253 1247 def test_ls_magic():
1254 1248 ip = get_ipython()
1255 1249 json_formatter = ip.display_formatter.formatters['application/json']
1256 1250 json_formatter.enabled = True
1257 1251 lsmagic = ip.magic('lsmagic')
1258 1252 with warnings.catch_warnings(record=True) as w:
1259 1253 j = json_formatter(lsmagic)
1260 1254 assert sorted(j) == ["cell", "line"]
1261 1255 assert w == [] # no warnings
1262 1256
1263 1257
1264 1258 def test_strip_initial_indent():
1265 1259 def sii(s):
1266 1260 lines = s.splitlines()
1267 1261 return '\n'.join(code.strip_initial_indent(lines))
1268 1262
1269 1263 assert sii(" a = 1\nb = 2") == "a = 1\nb = 2"
1270 1264 assert sii(" a\n b\nc") == "a\n b\nc"
1271 1265 assert sii("a\n b") == "a\n b"
1272 1266
1273 1267 def test_logging_magic_quiet_from_arg():
1274 1268 _ip.config.LoggingMagics.quiet = False
1275 1269 lm = logging.LoggingMagics(shell=_ip)
1276 1270 with TemporaryDirectory() as td:
1277 1271 try:
1278 1272 with tt.AssertNotPrints(re.compile("Activating.*")):
1279 1273 lm.logstart('-q {}'.format(
1280 1274 os.path.join(td, "quiet_from_arg.log")))
1281 1275 finally:
1282 1276 _ip.logger.logstop()
1283 1277
1284 1278 def test_logging_magic_quiet_from_config():
1285 1279 _ip.config.LoggingMagics.quiet = True
1286 1280 lm = logging.LoggingMagics(shell=_ip)
1287 1281 with TemporaryDirectory() as td:
1288 1282 try:
1289 1283 with tt.AssertNotPrints(re.compile("Activating.*")):
1290 1284 lm.logstart(os.path.join(td, "quiet_from_config.log"))
1291 1285 finally:
1292 1286 _ip.logger.logstop()
1293 1287
1294 1288
1295 1289 def test_logging_magic_not_quiet():
1296 1290 _ip.config.LoggingMagics.quiet = False
1297 1291 lm = logging.LoggingMagics(shell=_ip)
1298 1292 with TemporaryDirectory() as td:
1299 1293 try:
1300 1294 with tt.AssertPrints(re.compile("Activating.*")):
1301 1295 lm.logstart(os.path.join(td, "not_quiet.log"))
1302 1296 finally:
1303 1297 _ip.logger.logstop()
1304 1298
1305 1299
1306 1300 def test_time_no_var_expand():
1307 1301 _ip.user_ns['a'] = 5
1308 1302 _ip.user_ns['b'] = []
1309 1303 _ip.magic('time b.append("{a}")')
1310 1304 assert _ip.user_ns['b'] == ['{a}']
1311 1305
1312 1306
1313 1307 # this is slow, put at the end for local testing.
1314 1308 def test_timeit_arguments():
1315 1309 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
1316 1310 if sys.version_info < (3,7):
1317 1311 _ip.magic("timeit -n1 -r1 ('#')")
1318 1312 else:
1319 1313 # 3.7 optimize no-op statement like above out, and complain there is
1320 1314 # nothing in the for loop.
1321 1315 _ip.magic("timeit -n1 -r1 a=('#')")
1322 1316
1323 1317
1324 1318 TEST_MODULE = """
1325 1319 print('Loaded my_tmp')
1326 1320 if __name__ == "__main__":
1327 1321 print('I just ran a script')
1328 1322 """
1329 1323
1330 1324
1331 1325 def test_run_module_from_import_hook():
1332 1326 "Test that a module can be loaded via an import hook"
1333 1327 with TemporaryDirectory() as tmpdir:
1334 1328 fullpath = os.path.join(tmpdir, 'my_tmp.py')
1335 1329 Path(fullpath).write_text(TEST_MODULE)
1336 1330
1337 1331 import importlib.abc
1338 1332 import importlib.util
1339 1333
1340 1334 class MyTempImporter(importlib.abc.MetaPathFinder, importlib.abc.SourceLoader):
1341 1335 def find_spec(self, fullname, path, target=None):
1342 1336 if fullname == "my_tmp":
1343 1337 return importlib.util.spec_from_loader(fullname, self)
1344 1338
1345 1339 def get_filename(self, fullname):
1346 1340 if fullname != "my_tmp":
1347 1341 raise ImportError(f"unexpected module name '{fullname}'")
1348 1342 return fullpath
1349 1343
1350 1344 def get_data(self, path):
1351 1345 if not Path(path).samefile(fullpath):
1352 1346 raise OSError(f"expected path '{fullpath}', got '{path}'")
1353 1347 return Path(fullpath).read_text()
1354 1348
1355 1349 sys.meta_path.insert(0, MyTempImporter())
1356 1350
1357 1351 with capture_output() as captured:
1358 1352 _ip.magic("run -m my_tmp")
1359 1353 _ip.run_cell("import my_tmp")
1360 1354
1361 1355 output = "Loaded my_tmp\nI just ran a script\nLoaded my_tmp\n"
1362 1356 assert output == captured.stdout
1363 1357
1364 1358 sys.meta_path.pop(0)
@@ -1,196 +1,192
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 8 import pytest
9 9
10 10 from IPython.lib import latextools
11 11 from IPython.testing.decorators import (
12 12 onlyif_cmds_exist,
13 13 skipif_not_matplotlib,
14 skip_iptest_but_not_pytest,
15 14 )
16 15 from IPython.utils.process import FindCmdError
17 16
18 17
19 18 @pytest.mark.parametrize('command', ['latex', 'dvipng'])
20 @skip_iptest_but_not_pytest
21 19 def test_check_latex_to_png_dvipng_fails_when_no_cmd(command):
22 20 def mock_find_cmd(arg):
23 21 if arg == command:
24 22 raise FindCmdError
25 23
26 24 with patch.object(latextools, "find_cmd", mock_find_cmd):
27 25 assert latextools.latex_to_png_dvipng("whatever", True) is None
28 26
29 27
30 28 @contextmanager
31 29 def no_op(*args, **kwargs):
32 30 yield
33 31
34 32
35 @skip_iptest_but_not_pytest
36 33 @onlyif_cmds_exist("latex", "dvipng")
37 34 @pytest.mark.parametrize("s, wrap", [(u"$$x^2$$", False), (u"x^2", True)])
38 35 def test_latex_to_png_dvipng_runs(s, wrap):
39 36 """
40 37 Test that latex_to_png_dvipng just runs without error.
41 38 """
42 39 def mock_kpsewhich(filename):
43 40 assert filename == "breqn.sty"
44 41 return None
45 42
46 43 latextools.latex_to_png_dvipng(s, wrap)
47 44
48 45 with patch_latextool(mock_kpsewhich):
49 46 latextools.latex_to_png_dvipng(s, wrap)
50 47
51 48
52 49 def mock_kpsewhich(filename):
53 50 assert filename == "breqn.sty"
54 51 return None
55 52
56 53 @contextmanager
57 54 def patch_latextool(mock=mock_kpsewhich):
58 55 with patch.object(latextools, "kpsewhich", mock):
59 56 yield
60 57
61 58 @pytest.mark.parametrize('context', [no_op, patch_latextool])
62 59 @pytest.mark.parametrize('s_wrap', [("$x^2$", False), ("x^2", True)])
63 @skip_iptest_but_not_pytest
64 60 def test_latex_to_png_mpl_runs(s_wrap, context):
65 61 """
66 62 Test that latex_to_png_mpl just runs without error.
67 63 """
68 64 try:
69 65 import matplotlib
70 66 except ImportError:
71 67 pytest.skip("This needs matplotlib to be available")
72 68 return
73 69 s, wrap = s_wrap
74 70 with context():
75 71 latextools.latex_to_png_mpl(s, wrap)
76 72
77 73 @skipif_not_matplotlib
78 74 def test_latex_to_html():
79 75 img = latextools.latex_to_html("$x^2$")
80 76 assert "data:image/png;base64,iVBOR" in img
81 77
82 78
83 79 def test_genelatex_no_wrap():
84 80 """
85 81 Test genelatex with wrap=False.
86 82 """
87 83 def mock_kpsewhich(filename):
88 84 assert False, ("kpsewhich should not be called "
89 85 "(called with {0})".format(filename))
90 86
91 87 with patch_latextool(mock_kpsewhich):
92 88 assert '\n'.join(latextools.genelatex("body text", False)) == r'''\documentclass{article}
93 89 \usepackage{amsmath}
94 90 \usepackage{amsthm}
95 91 \usepackage{amssymb}
96 92 \usepackage{bm}
97 93 \pagestyle{empty}
98 94 \begin{document}
99 95 body text
100 96 \end{document}'''
101 97
102 98
103 99 def test_genelatex_wrap_with_breqn():
104 100 """
105 101 Test genelatex with wrap=True for the case breqn.sty is installed.
106 102 """
107 103 def mock_kpsewhich(filename):
108 104 assert filename == "breqn.sty"
109 105 return "path/to/breqn.sty"
110 106
111 107 with patch_latextool(mock_kpsewhich):
112 108 assert '\n'.join(latextools.genelatex("x^2", True)) == r'''\documentclass{article}
113 109 \usepackage{amsmath}
114 110 \usepackage{amsthm}
115 111 \usepackage{amssymb}
116 112 \usepackage{bm}
117 113 \usepackage{breqn}
118 114 \pagestyle{empty}
119 115 \begin{document}
120 116 \begin{dmath*}
121 117 x^2
122 118 \end{dmath*}
123 119 \end{document}'''
124 120
125 121
126 122 def test_genelatex_wrap_without_breqn():
127 123 """
128 124 Test genelatex with wrap=True for the case breqn.sty is not installed.
129 125 """
130 126 def mock_kpsewhich(filename):
131 127 assert filename == "breqn.sty"
132 128 return None
133 129
134 130 with patch_latextool(mock_kpsewhich):
135 131 assert '\n'.join(latextools.genelatex("x^2", True)) == r'''\documentclass{article}
136 132 \usepackage{amsmath}
137 133 \usepackage{amsthm}
138 134 \usepackage{amssymb}
139 135 \usepackage{bm}
140 136 \pagestyle{empty}
141 137 \begin{document}
142 138 $$x^2$$
143 139 \end{document}'''
144 140
145 141
146 142 @skipif_not_matplotlib
147 143 @onlyif_cmds_exist('latex', 'dvipng')
148 144 def test_latex_to_png_color():
149 145 """
150 146 Test color settings for latex_to_png.
151 147 """
152 148 latex_string = "$x^2$"
153 149 default_value = latextools.latex_to_png(latex_string, wrap=False)
154 150 default_hexblack = latextools.latex_to_png(latex_string, wrap=False,
155 151 color='#000000')
156 152 dvipng_default = latextools.latex_to_png_dvipng(latex_string, False)
157 153 dvipng_black = latextools.latex_to_png_dvipng(latex_string, False, 'Black')
158 154 assert dvipng_default == dvipng_black
159 155 mpl_default = latextools.latex_to_png_mpl(latex_string, False)
160 156 mpl_black = latextools.latex_to_png_mpl(latex_string, False, 'Black')
161 157 assert mpl_default == mpl_black
162 158 assert default_value in [dvipng_black, mpl_black]
163 159 assert default_hexblack in [dvipng_black, mpl_black]
164 160
165 161 # Test that dvips name colors can be used without error
166 162 dvipng_maroon = latextools.latex_to_png_dvipng(latex_string, False,
167 163 'Maroon')
168 164 # And that it doesn't return the black one
169 165 assert dvipng_black != dvipng_maroon
170 166
171 167 mpl_maroon = latextools.latex_to_png_mpl(latex_string, False, 'Maroon')
172 168 assert mpl_black != mpl_maroon
173 169 mpl_white = latextools.latex_to_png_mpl(latex_string, False, 'White')
174 170 mpl_hexwhite = latextools.latex_to_png_mpl(latex_string, False, '#FFFFFF')
175 171 assert mpl_white == mpl_hexwhite
176 172
177 173 mpl_white_scale = latextools.latex_to_png_mpl(latex_string, False,
178 174 'White', 1.2)
179 175 assert mpl_white != mpl_white_scale
180 176
181 177
182 178 def test_latex_to_png_invalid_hex_colors():
183 179 """
184 180 Test that invalid hex colors provided to dvipng gives an exception.
185 181 """
186 182 latex_string = "$x^2$"
187 183 pytest.raises(
188 184 ValueError,
189 185 lambda: latextools.latex_to_png(
190 186 latex_string, backend="dvipng", color="#f00bar"
191 187 ),
192 188 )
193 189 pytest.raises(
194 190 ValueError,
195 191 lambda: latextools.latex_to_png(latex_string, backend="dvipng", color="#f00"),
196 192 )
@@ -1,502 +1,500
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 pytest
11 11 import types
12 12 import string
13 13 import sys
14 14 import unittest
15 15
16 16 import pytest
17 17
18 18 from IPython.lib import pretty
19 from IPython.testing.decorators import skip_iptest_but_not_pytest
20 19
21 20 from io import StringIO
22 21
23 22
24 23 class MyList(object):
25 24 def __init__(self, content):
26 25 self.content = content
27 26 def _repr_pretty_(self, p, cycle):
28 27 if cycle:
29 28 p.text("MyList(...)")
30 29 else:
31 30 with p.group(3, "MyList(", ")"):
32 31 for (i, child) in enumerate(self.content):
33 32 if i:
34 33 p.text(",")
35 34 p.breakable()
36 35 else:
37 36 p.breakable("")
38 37 p.pretty(child)
39 38
40 39
41 40 class MyDict(dict):
42 41 def _repr_pretty_(self, p, cycle):
43 42 p.text("MyDict(...)")
44 43
45 44 class MyObj(object):
46 45 def somemethod(self):
47 46 pass
48 47
49 48
50 49 class Dummy1(object):
51 50 def _repr_pretty_(self, p, cycle):
52 51 p.text("Dummy1(...)")
53 52
54 53 class Dummy2(Dummy1):
55 54 _repr_pretty_ = None
56 55
57 56 class NoModule(object):
58 57 pass
59 58
60 59 NoModule.__module__ = None
61 60
62 61 class Breaking(object):
63 62 def _repr_pretty_(self, p, cycle):
64 63 with p.group(4,"TG: ",":"):
65 64 p.text("Breaking(")
66 65 p.break_()
67 66 p.text(")")
68 67
69 68 class BreakingRepr(object):
70 69 def __repr__(self):
71 70 return "Breaking(\n)"
72 71
73 72 class BadRepr(object):
74 73 def __repr__(self):
75 74 return 1/0
76 75
77 76
78 77 def test_indentation():
79 78 """Test correct indentation in groups"""
80 79 count = 40
81 80 gotoutput = pretty.pretty(MyList(range(count)))
82 81 expectedoutput = "MyList(\n" + ",\n".join(" %d" % i for i in range(count)) + ")"
83 82
84 83 assert gotoutput == expectedoutput
85 84
86 85
87 86 def test_dispatch():
88 87 """
89 88 Test correct dispatching: The _repr_pretty_ method for MyDict
90 89 must be found before the registered printer for dict.
91 90 """
92 91 gotoutput = pretty.pretty(MyDict())
93 92 expectedoutput = "MyDict(...)"
94 93
95 94 assert gotoutput == expectedoutput
96 95
97 96
98 97 def test_callability_checking():
99 98 """
100 99 Test that the _repr_pretty_ method is tested for callability and skipped if
101 100 not.
102 101 """
103 102 gotoutput = pretty.pretty(Dummy2())
104 103 expectedoutput = "Dummy1(...)"
105 104
106 105 assert gotoutput == expectedoutput
107 106
108 107
109 108 @pytest.mark.parametrize(
110 109 "obj,expected_output",
111 110 zip(
112 111 [
113 112 set(),
114 113 frozenset(),
115 114 set([1]),
116 115 frozenset([1]),
117 116 set([1, 2]),
118 117 frozenset([1, 2]),
119 118 set([-1, -2, -3]),
120 119 ],
121 120 [
122 121 "set()",
123 122 "frozenset()",
124 123 "{1}",
125 124 "frozenset({1})",
126 125 "{1, 2}",
127 126 "frozenset({1, 2})",
128 127 "{-3, -2, -1}",
129 128 ],
130 129 ),
131 130 )
132 @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 def test_pprint_heap_allocated_type():
142 140 """
143 141 Test that pprint works for heap allocated types.
144 142 """
145 143 module_name = "xxlimited" if sys.version_info < (3, 10) else "xxlimited_35"
146 144 xxlimited = pytest.importorskip(module_name)
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 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 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 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 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 498 assert "OrderedCounter(OrderedDict" in pretty.pretty(oc)
501 499
502 500 assert pretty.pretty(MySet()) == "mine"
@@ -1,342 +1,331
1 1 # -*- coding: utf-8 -*-
2 2 """Decorators for labeling test objects.
3 3
4 4 Decorators that merely return a modified version of the original function
5 5 object are straightforward. Decorators that return a new function object need
6 6 to use nose.tools.make_decorator(original_function)(decorator) in returning the
7 7 decorator, in order to preserve metadata such as function name, setup and
8 8 teardown functions and so on - see nose.tools for more information.
9 9
10 10 This module provides a set of useful decorators meant to be ready to use in
11 11 your own tests. See the bottom of the file for the ready-made ones, and if you
12 12 find yourself writing a new one that may be of generic use, add it here.
13 13
14 14 Included decorators:
15 15
16 16
17 17 Lightweight testing that remains unittest-compatible.
18 18
19 19 - An @as_unittest decorator can be used to tag any normal parameter-less
20 20 function as a unittest TestCase. Then, both nose and normal unittest will
21 21 recognize it as such. This will make it easier to migrate away from Nose if
22 22 we ever need/want to while maintaining very lightweight tests.
23 23
24 24 NOTE: This file contains IPython-specific decorators. Using the machinery in
25 25 IPython.external.decorators, we import either numpy.testing.decorators if numpy is
26 26 available, OR use equivalent code in IPython.external._decorators, which
27 27 we've copied verbatim from numpy.
28 28
29 29 """
30 30
31 31 # Copyright (c) IPython Development Team.
32 32 # Distributed under the terms of the Modified BSD License.
33 33
34 34 import os
35 35 import shutil
36 36 import sys
37 37 import tempfile
38 38 import unittest
39 39 import warnings
40 40 from importlib import import_module
41 41
42 42 from decorator import decorator
43 43
44 44 # Expose the unittest-driven decorators
45 45 from .ipunittest import ipdoctest, ipdocstring
46 46
47 47 #-----------------------------------------------------------------------------
48 48 # Classes and functions
49 49 #-----------------------------------------------------------------------------
50 50
51 51 # Simple example of the basic idea
52 52 def as_unittest(func):
53 53 """Decorator to make a simple function into a normal test via unittest."""
54 54 class Tester(unittest.TestCase):
55 55 def test(self):
56 56 func()
57 57
58 58 Tester.__name__ = func.__name__
59 59
60 60 return Tester
61 61
62 62 # Utility functions
63 63
64 64 def apply_wrapper(wrapper, func):
65 65 """Apply a wrapper to a function for decoration.
66 66
67 67 This mixes Michele Simionato's decorator tool with nose's make_decorator,
68 68 to apply a wrapper in a decorator so that all nose attributes, as well as
69 69 function signature and other properties, survive the decoration cleanly.
70 70 This will ensure that wrapped functions can still be well introspected via
71 71 IPython, for example.
72 72 """
73 73 warnings.warn("The function `apply_wrapper` is deprecated since IPython 4.0",
74 74 DeprecationWarning, stacklevel=2)
75 75 import nose.tools
76 76
77 77 return decorator(wrapper,nose.tools.make_decorator(func)(wrapper))
78 78
79 79
80 80 def make_label_dec(label, ds=None):
81 81 """Factory function to create a decorator that applies one or more labels.
82 82
83 83 Parameters
84 84 ----------
85 85 label : string or sequence
86 86 One or more labels that will be applied by the decorator to the functions
87 87 it decorates. Labels are attributes of the decorated function with their
88 88 value set to True.
89 89
90 90 ds : string
91 91 An optional docstring for the resulting decorator. If not given, a
92 92 default docstring is auto-generated.
93 93
94 94 Returns
95 95 -------
96 96 A decorator.
97 97
98 98 Examples
99 99 --------
100 100
101 101 A simple labeling decorator:
102 102
103 103 >>> slow = make_label_dec('slow')
104 104 >>> slow.__doc__
105 105 "Labels a test as 'slow'."
106 106
107 107 And one that uses multiple labels and a custom docstring:
108 108
109 109 >>> rare = make_label_dec(['slow','hard'],
110 110 ... "Mix labels 'slow' and 'hard' for rare tests.")
111 111 >>> rare.__doc__
112 112 "Mix labels 'slow' and 'hard' for rare tests."
113 113
114 114 Now, let's test using this one:
115 115 >>> @rare
116 116 ... def f(): pass
117 117 ...
118 118 >>>
119 119 >>> f.slow
120 120 True
121 121 >>> f.hard
122 122 True
123 123 """
124 124
125 125 warnings.warn("The function `make_label_dec` is deprecated since IPython 4.0",
126 126 DeprecationWarning, stacklevel=2)
127 127 if isinstance(label, str):
128 128 labels = [label]
129 129 else:
130 130 labels = label
131 131
132 132 # Validate that the given label(s) are OK for use in setattr() by doing a
133 133 # dry run on a dummy function.
134 134 tmp = lambda : None
135 135 for label in labels:
136 136 setattr(tmp,label,True)
137 137
138 138 # This is the actual decorator we'll return
139 139 def decor(f):
140 140 for label in labels:
141 141 setattr(f,label,True)
142 142 return f
143 143
144 144 # Apply the user's docstring, or autogenerate a basic one
145 145 if ds is None:
146 146 ds = "Labels a test as %r." % label
147 147 decor.__doc__ = ds
148 148
149 149 return decor
150 150
151 151
152 def skip_iptest_but_not_pytest(f):
153 """
154 Warning this will make the test invisible to iptest.
155 """
156 import os
157
158 if os.environ.get("IPTEST_WORKING_DIR", None) is not None:
159 f.__test__ = False
160 return f
161
162
163 152 def skipif(skip_condition, msg=None):
164 153 """Make function raise SkipTest exception if skip_condition is true
165 154
166 155 Parameters
167 156 ----------
168 157
169 158 skip_condition : bool or callable
170 159 Flag to determine whether to skip test. If the condition is a
171 160 callable, it is used at runtime to dynamically make the decision. This
172 161 is useful for tests that may require costly imports, to delay the cost
173 162 until the test suite is actually executed.
174 163 msg : string
175 164 Message to give on raising a SkipTest exception.
176 165
177 166 Returns
178 167 -------
179 168 decorator : function
180 169 Decorator, which, when applied to a function, causes SkipTest
181 170 to be raised when the skip_condition was True, and the function
182 171 to be called normally otherwise.
183 172 """
184 173 if msg is None:
185 174 msg = "Test skipped due to test condition."
186 175
187 176 import pytest
188 177
189 178 assert isinstance(skip_condition, bool)
190 179 return pytest.mark.skipif(skip_condition, reason=msg)
191 180
192 181
193 182 # A version with the condition set to true, common case just to attach a message
194 183 # to a skip decorator
195 184 def skip(msg=None):
196 185 """Decorator factory - mark a test function for skipping from test suite.
197 186
198 187 Parameters
199 188 ----------
200 189 msg : string
201 190 Optional message to be added.
202 191
203 192 Returns
204 193 -------
205 194 decorator : function
206 195 Decorator, which, when applied to a function, causes SkipTest
207 196 to be raised, with the optional message added.
208 197 """
209 198 if msg and not isinstance(msg, str):
210 199 raise ValueError('invalid object passed to `@skip` decorator, did you '
211 200 'meant `@skip()` with brackets ?')
212 201 return skipif(True, msg)
213 202
214 203
215 204 def onlyif(condition, msg):
216 205 """The reverse from skipif, see skipif for details."""
217 206
218 207 return skipif(not condition, msg)
219 208
220 209 #-----------------------------------------------------------------------------
221 210 # Utility functions for decorators
222 211 def module_not_available(module):
223 212 """Can module be imported? Returns true if module does NOT import.
224 213
225 214 This is used to make a decorator to skip tests that require module to be
226 215 available, but delay the 'import numpy' to test execution time.
227 216 """
228 217 try:
229 218 mod = import_module(module)
230 219 mod_not_avail = False
231 220 except ImportError:
232 221 mod_not_avail = True
233 222
234 223 return mod_not_avail
235 224
236 225
237 226 def decorated_dummy(dec, name):
238 227 """Return a dummy function decorated with dec, with the given name.
239 228
240 229 Examples
241 230 --------
242 231 import IPython.testing.decorators as dec
243 232 setup = dec.decorated_dummy(dec.skip_if_no_x11, __name__)
244 233 """
245 234 warnings.warn("The function `decorated_dummy` is deprecated since IPython 4.0",
246 235 DeprecationWarning, stacklevel=2)
247 236 dummy = lambda: None
248 237 dummy.__name__ = name
249 238 return dec(dummy)
250 239
251 240 #-----------------------------------------------------------------------------
252 241 # Decorators for public use
253 242
254 243 # Decorators to skip certain tests on specific platforms.
255 244 skip_win32 = skipif(sys.platform == 'win32',
256 245 "This test does not run under Windows")
257 246 skip_linux = skipif(sys.platform.startswith('linux'),
258 247 "This test does not run under Linux")
259 248 skip_osx = skipif(sys.platform == 'darwin',"This test does not run under OS X")
260 249
261 250
262 251 # Decorators to skip tests if not on specific platforms.
263 252 skip_if_not_win32 = skipif(sys.platform != 'win32',
264 253 "This test only runs under Windows")
265 254 skip_if_not_linux = skipif(not sys.platform.startswith('linux'),
266 255 "This test only runs under Linux")
267 256 skip_if_not_osx = skipif(sys.platform != 'darwin',
268 257 "This test only runs under OSX")
269 258
270 259
271 260 _x11_skip_cond = (sys.platform not in ('darwin', 'win32') and
272 261 os.environ.get('DISPLAY', '') == '')
273 262 _x11_skip_msg = "Skipped under *nix when X11/XOrg not available"
274 263
275 264 skip_if_no_x11 = skipif(_x11_skip_cond, _x11_skip_msg)
276 265
277 266
278 267 # Decorators to skip certain tests on specific platform/python combinations
279 268 skip_win32_py38 = skipif(sys.version_info > (3,8) and os.name == 'nt')
280 269
281 270
282 271 # not a decorator itself, returns a dummy function to be used as setup
283 272 def skip_file_no_x11(name):
284 273 warnings.warn("The function `skip_file_no_x11` is deprecated since IPython 4.0",
285 274 DeprecationWarning, stacklevel=2)
286 275 return decorated_dummy(skip_if_no_x11, name) if _x11_skip_cond else None
287 276
288 277 # Other skip decorators
289 278
290 279 # generic skip without module
291 280 skip_without = lambda mod: skipif(module_not_available(mod), "This test requires %s" % mod)
292 281
293 282 skipif_not_numpy = skip_without('numpy')
294 283
295 284 skipif_not_matplotlib = skip_without('matplotlib')
296 285
297 286 skipif_not_sympy = skip_without('sympy')
298 287
299 288 # A null 'decorator', useful to make more readable code that needs to pick
300 289 # between different decorators based on OS or other conditions
301 290 null_deco = lambda f: f
302 291
303 292 # Some tests only run where we can use unicode paths. Note that we can't just
304 293 # check os.path.supports_unicode_filenames, which is always False on Linux.
305 294 try:
306 295 f = tempfile.NamedTemporaryFile(prefix=u"tmp€")
307 296 except UnicodeEncodeError:
308 297 unicode_paths = False
309 298 else:
310 299 unicode_paths = True
311 300 f.close()
312 301
313 302 onlyif_unicode_paths = onlyif(unicode_paths, ("This test is only applicable "
314 303 "where we can use unicode in filenames."))
315 304
316 305
317 306 def onlyif_cmds_exist(*commands):
318 307 """
319 308 Decorator to skip test when at least one of `commands` is not found.
320 309 """
321 310 for cmd in commands:
322 311 reason = f"This test runs only if command '{cmd}' is installed"
323 312 if not shutil.which(cmd):
324 313 if os.environ.get("IPTEST_WORKING_DIR", None) is not None:
325 314 return skip(reason)
326 315 else:
327 316 import pytest
328 317
329 318 return pytest.mark.skip(reason=reason)
330 319 return null_deco
331 320
332 321 def onlyif_any_cmd_exists(*commands):
333 322 """
334 323 Decorator to skip test unless at least one of `commands` is found.
335 324 """
336 325 warnings.warn("The function `onlyif_any_cmd_exists` is deprecated since IPython 4.0",
337 326 DeprecationWarning, stacklevel=2)
338 327 for cmd in commands:
339 328 if shutil.which(cmd):
340 329 return null_deco
341 330 return skip("This test runs only if one of the commands {0} "
342 331 "is installed".format(commands))
@@ -1,171 +1,166
1 1 # encoding: utf-8
2 2 """Tests for IPython.utils.capture"""
3 3
4 4 #-----------------------------------------------------------------------------
5 5 # Copyright (C) 2013 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
16 16 import sys
17 17
18 18 import pytest
19 19
20 from IPython.testing.decorators import skip_iptest_but_not_pytest
21
22 20 from IPython.utils import capture
23 21
24 22 #-----------------------------------------------------------------------------
25 23 # Globals
26 24 #-----------------------------------------------------------------------------
27 25
28 26 _mime_map = dict(
29 27 _repr_png_="image/png",
30 28 _repr_jpeg_="image/jpeg",
31 29 _repr_svg_="image/svg+xml",
32 30 _repr_html_="text/html",
33 31 _repr_json_="application/json",
34 32 _repr_javascript_="application/javascript",
35 33 )
36 34
37 35 basic_data = {
38 36 'image/png' : b'binarydata',
39 37 'text/html' : "<b>bold</b>",
40 38 }
41 39 basic_metadata = {
42 40 'image/png' : {
43 41 'width' : 10,
44 42 'height' : 20,
45 43 },
46 44 }
47 45
48 46 full_data = {
49 47 'image/png' : b'binarydata',
50 48 'image/jpeg' : b'binarydata',
51 49 'image/svg+xml' : "<svg>",
52 50 'text/html' : "<b>bold</b>",
53 51 'application/javascript' : "alert();",
54 52 'application/json' : "{}",
55 53 }
56 54 full_metadata = {
57 55 'image/png' : {"png" : "exists"},
58 56 'image/jpeg' : {"jpeg" : "exists"},
59 57 'image/svg+xml' : {"svg" : "exists"},
60 58 'text/html' : {"html" : "exists"},
61 59 'application/javascript' : {"js" : "exists"},
62 60 'application/json' : {"json" : "exists"},
63 61 }
64 62
65 63 hello_stdout = "hello, stdout"
66 64 hello_stderr = "hello, stderr"
67 65
68 66 #-----------------------------------------------------------------------------
69 67 # Test Functions
70 68 #-----------------------------------------------------------------------------
71 69 @pytest.mark.parametrize("method_mime", _mime_map.items())
72 @skip_iptest_but_not_pytest
73 70 def test_rich_output_empty(method_mime):
74 71 """RichOutput with no args"""
75 72 rich = capture.RichOutput()
76 73 method, mime = method_mime
77 74 assert getattr(rich, method)() is None
78 75
79 76 def test_rich_output():
80 77 """test RichOutput basics"""
81 78 data = basic_data
82 79 metadata = basic_metadata
83 80 rich = capture.RichOutput(data=data, metadata=metadata)
84 81 assert rich._repr_html_() == data["text/html"]
85 82 assert rich._repr_png_() == (data["image/png"], metadata["image/png"])
86 83 assert rich._repr_latex_() is None
87 84 assert rich._repr_javascript_() is None
88 85 assert rich._repr_svg_() is None
89 86
90 87
91 @skip_iptest_but_not_pytest
92 88 @pytest.mark.parametrize("method_mime", _mime_map.items())
93 89 def test_rich_output_no_metadata(method_mime):
94 90 """test RichOutput with no metadata"""
95 91 data = full_data
96 92 rich = capture.RichOutput(data=data)
97 93 method, mime = method_mime
98 94 assert getattr(rich, method)() == data[mime]
99 95
100 96
101 @skip_iptest_but_not_pytest
102 97 @pytest.mark.parametrize("method_mime", _mime_map.items())
103 98 def test_rich_output_metadata(method_mime):
104 99 """test RichOutput with metadata"""
105 100 data = full_data
106 101 metadata = full_metadata
107 102 rich = capture.RichOutput(data=data, metadata=metadata)
108 103 method, mime = method_mime
109 104 assert getattr(rich, method)() == (data[mime], metadata[mime])
110 105
111 106 def test_rich_output_display():
112 107 """test RichOutput.display
113 108
114 109 This is a bit circular, because we are actually using the capture code we are testing
115 110 to test itself.
116 111 """
117 112 data = full_data
118 113 rich = capture.RichOutput(data=data)
119 114 with capture.capture_output() as cap:
120 115 rich.display()
121 116 assert len(cap.outputs) == 1
122 117 rich2 = cap.outputs[0]
123 118 assert rich2.data == rich.data
124 119 assert rich2.metadata == rich.metadata
125 120
126 121 def test_capture_output():
127 122 """capture_output works"""
128 123 rich = capture.RichOutput(data=full_data)
129 124 with capture.capture_output() as cap:
130 125 print(hello_stdout, end="")
131 126 print(hello_stderr, end="", file=sys.stderr)
132 127 rich.display()
133 128 assert hello_stdout == cap.stdout
134 129 assert hello_stderr == cap.stderr
135 130
136 131
137 132 def test_capture_output_no_stdout():
138 133 """test capture_output(stdout=False)"""
139 134 rich = capture.RichOutput(data=full_data)
140 135 with capture.capture_output(stdout=False) as cap:
141 136 print(hello_stdout, end="")
142 137 print(hello_stderr, end="", file=sys.stderr)
143 138 rich.display()
144 139 assert "" == cap.stdout
145 140 assert hello_stderr == cap.stderr
146 141 assert len(cap.outputs) == 1
147 142
148 143
149 144 def test_capture_output_no_stderr():
150 145 """test capture_output(stderr=False)"""
151 146 rich = capture.RichOutput(data=full_data)
152 147 # add nested capture_output so stderr doesn't make it to nose output
153 148 with capture.capture_output(), capture.capture_output(stderr=False) as cap:
154 149 print(hello_stdout, end="")
155 150 print(hello_stderr, end="", file=sys.stderr)
156 151 rich.display()
157 152 assert hello_stdout == cap.stdout
158 153 assert "" == cap.stderr
159 154 assert len(cap.outputs) == 1
160 155
161 156
162 157 def test_capture_output_no_display():
163 158 """test capture_output(display=False)"""
164 159 rich = capture.RichOutput(data=full_data)
165 160 with capture.capture_output(display=False) as cap:
166 161 print(hello_stdout, end="")
167 162 print(hello_stderr, end="", file=sys.stderr)
168 163 rich.display()
169 164 assert hello_stdout == cap.stdout
170 165 assert hello_stderr == cap.stderr
171 166 assert cap.outputs == []
@@ -1,73 +1,69
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 from IPython.testing.decorators import skip_iptest_but_not_pytest
21
22 20 # our own
23 21 from IPython.utils.PyColorize import Parser
24 22 import io
25 23 import pytest
26 24
27 25
28 26 @pytest.fixture(scope="module", params=("Linux", "NoColor", "LightBG", "Neutral"))
29 27 def style(request):
30 28 yield request.param
31 29
32 30 #-----------------------------------------------------------------------------
33 31 # Test functions
34 32 #-----------------------------------------------------------------------------
35 33
36 34 sample = """
37 35 def function(arg, *args, kwarg=True, **kwargs):
38 36 '''
39 37 this is docs
40 38 '''
41 39 pass is True
42 40 False == None
43 41
44 42 with io.open(ru'unicode'):
45 43 raise ValueError("\n escape \r sequence")
46 44
47 45 print("wΔ›ird ΓΌnicoΓ°e")
48 46
49 47 class Bar(Super):
50 48
51 49 def __init__(self):
52 50 super(Bar, self).__init__(1**2, 3^4, 5 or 6)
53 51 """
54 52
55 53
56 @skip_iptest_but_not_pytest
57 54 def test_parse_sample(style):
58 55 """and test writing to a buffer"""
59 56 buf = io.StringIO()
60 57 p = Parser(style=style)
61 58 p.format(sample, buf)
62 59 buf.seek(0)
63 60 f1 = buf.read()
64 61
65 62 assert "ERROR" not in f1
66 63
67 64
68 @skip_iptest_but_not_pytest
69 65 def test_parse_error(style):
70 66 p = Parser(style=style)
71 67 f1 = p.format(")", "str")
72 68 if style != "NoColor":
73 69 assert "ERROR" in f1
@@ -1,143 +1,141
1 1 """Tests for tokenutil"""
2 2 # Copyright (c) IPython Development Team.
3 3 # Distributed under the terms of the Modified BSD License.
4 4
5 5 import pytest
6 from IPython.testing.decorators import skip_iptest_but_not_pytest
7 6
8 7 from IPython.utils.tokenutil import token_at_cursor, line_at_cursor
9 8
10 9 def expect_token(expected, cell, cursor_pos):
11 10 token = token_at_cursor(cell, cursor_pos)
12 11 offset = 0
13 12 for line in cell.splitlines():
14 13 if offset + len(line) >= cursor_pos:
15 14 break
16 15 else:
17 16 offset += len(line)+1
18 17 column = cursor_pos - offset
19 18 line_with_cursor = "%s|%s" % (line[:column], line[column:])
20 19 assert token == expected, "Expected %r, got %r in: %r (pos %i)" % (
21 20 expected,
22 21 token,
23 22 line_with_cursor,
24 23 cursor_pos,
25 24 )
26 25
27 26
28 27 def test_simple():
29 28 cell = "foo"
30 29 for i in range(len(cell)):
31 30 expect_token("foo", cell, i)
32 31
33 32 def test_function():
34 33 cell = "foo(a=5, b='10')"
35 34 expected = 'foo'
36 35 # up to `foo(|a=`
37 36 for i in range(cell.find('a=') + 1):
38 37 expect_token("foo", cell, i)
39 38 # find foo after `=`
40 39 for i in [cell.find('=') + 1, cell.rfind('=') + 1]:
41 40 expect_token("foo", cell, i)
42 41 # in between `5,|` and `|b=`
43 42 for i in range(cell.find(','), cell.find('b=')):
44 43 expect_token("foo", cell, i)
45 44
46 45 def test_multiline():
47 46 cell = '\n'.join([
48 47 'a = 5',
49 48 'b = hello("string", there)'
50 49 ])
51 50 expected = 'hello'
52 51 start = cell.index(expected) + 1
53 52 for i in range(start, start + len(expected)):
54 53 expect_token(expected, cell, i)
55 54 expected = 'hello'
56 55 start = cell.index(expected) + 1
57 56 for i in range(start, start + len(expected)):
58 57 expect_token(expected, cell, i)
59 58
60 59 def test_multiline_token():
61 60 cell = '\n'.join([
62 61 '"""\n\nxxxxxxxxxx\n\n"""',
63 62 '5, """',
64 63 'docstring',
65 64 'multiline token',
66 65 '""", [',
67 66 '2, 3, "complicated"]',
68 67 'b = hello("string", there)'
69 68 ])
70 69 expected = 'hello'
71 70 start = cell.index(expected) + 1
72 71 for i in range(start, start + len(expected)):
73 72 expect_token(expected, cell, i)
74 73 expected = 'hello'
75 74 start = cell.index(expected) + 1
76 75 for i in range(start, start + len(expected)):
77 76 expect_token(expected, cell, i)
78 77
79 78 def test_nested_call():
80 79 cell = "foo(bar(a=5), b=10)"
81 80 expected = 'foo'
82 81 start = cell.index('bar') + 1
83 82 for i in range(start, start + 3):
84 83 expect_token(expected, cell, i)
85 84 expected = 'bar'
86 85 start = cell.index('a=')
87 86 for i in range(start, start + 3):
88 87 expect_token(expected, cell, i)
89 88 expected = 'foo'
90 89 start = cell.index(')') + 1
91 90 for i in range(start, len(cell)-1):
92 91 expect_token(expected, cell, i)
93 92
94 93 def test_attrs():
95 94 cell = "a = obj.attr.subattr"
96 95 expected = 'obj'
97 96 idx = cell.find('obj') + 1
98 97 for i in range(idx, idx + 3):
99 98 expect_token(expected, cell, i)
100 99 idx = cell.find('.attr') + 2
101 100 expected = 'obj.attr'
102 101 for i in range(idx, idx + 4):
103 102 expect_token(expected, cell, i)
104 103 idx = cell.find('.subattr') + 2
105 104 expected = 'obj.attr.subattr'
106 105 for i in range(idx, len(cell)):
107 106 expect_token(expected, cell, i)
108 107
109 108 def test_line_at_cursor():
110 109 cell = ""
111 110 (line, offset) = line_at_cursor(cell, cursor_pos=11)
112 111 assert line == ""
113 112 assert offset == 0
114 113
115 114 # The position after a newline should be the start of the following line.
116 115 cell = "One\nTwo\n"
117 116 (line, offset) = line_at_cursor(cell, cursor_pos=4)
118 117 assert line == "Two\n"
119 118 assert offset == 4
120 119
121 120 # The end of a cell should be on the last line
122 121 cell = "pri\npri"
123 122 (line, offset) = line_at_cursor(cell, cursor_pos=7)
124 123 assert line == "pri"
125 124 assert offset == 4
126 125
127 126
128 127 @pytest.mark.parametrize(
129 128 "c, token",
130 129 zip(
131 130 list(range(16, 22)) + list(range(22, 28)),
132 131 ["int"] * (22 - 16) + ["map"] * (28 - 22),
133 132 ),
134 133 )
135 @skip_iptest_but_not_pytest
136 134 def test_multiline_statement(c, token):
137 135 cell = """a = (1,
138 136 3)
139 137
140 138 int()
141 139 map()
142 140 """
143 141 expect_token(token, cell, c)
General Comments 0
You need to be logged in to leave comments. Login now