##// END OF EJS Templates
do not use .magic(...) that has been deprecated for a decade (#14566)
M Bussonnier -
r28950:ac9ed9c1 merge
parent child Browse files
Show More
@@ -1,666 +1,666
1 """Implementation of basic magic functions."""
1 """Implementation of basic magic functions."""
2
2
3
3
4 from logging import error
4 from logging import error
5 import io
5 import io
6 import os
6 import os
7 from pprint import pformat
7 from pprint import pformat
8 import sys
8 import sys
9 from warnings import warn
9 from warnings import warn
10
10
11 from traitlets.utils.importstring import import_item
11 from traitlets.utils.importstring import import_item
12 from IPython.core import magic_arguments, page
12 from IPython.core import magic_arguments, page
13 from IPython.core.error import UsageError
13 from IPython.core.error import UsageError
14 from IPython.core.magic import Magics, magics_class, line_magic, magic_escapes
14 from IPython.core.magic import Magics, magics_class, line_magic, magic_escapes
15 from IPython.utils.text import format_screen, dedent, indent
15 from IPython.utils.text import format_screen, dedent, indent
16 from IPython.testing.skipdoctest import skip_doctest
16 from IPython.testing.skipdoctest import skip_doctest
17 from IPython.utils.ipstruct import Struct
17 from IPython.utils.ipstruct import Struct
18
18
19
19
20 class MagicsDisplay(object):
20 class MagicsDisplay(object):
21 def __init__(self, magics_manager, ignore=None):
21 def __init__(self, magics_manager, ignore=None):
22 self.ignore = ignore if ignore else []
22 self.ignore = ignore if ignore else []
23 self.magics_manager = magics_manager
23 self.magics_manager = magics_manager
24
24
25 def _lsmagic(self):
25 def _lsmagic(self):
26 """The main implementation of the %lsmagic"""
26 """The main implementation of the %lsmagic"""
27 mesc = magic_escapes['line']
27 mesc = magic_escapes['line']
28 cesc = magic_escapes['cell']
28 cesc = magic_escapes['cell']
29 mman = self.magics_manager
29 mman = self.magics_manager
30 magics = mman.lsmagic()
30 magics = mman.lsmagic()
31 out = ['Available line magics:',
31 out = ['Available line magics:',
32 mesc + (' '+mesc).join(sorted([m for m,v in magics['line'].items() if (v not in self.ignore)])),
32 mesc + (' '+mesc).join(sorted([m for m,v in magics['line'].items() if (v not in self.ignore)])),
33 '',
33 '',
34 'Available cell magics:',
34 'Available cell magics:',
35 cesc + (' '+cesc).join(sorted([m for m,v in magics['cell'].items() if (v not in self.ignore)])),
35 cesc + (' '+cesc).join(sorted([m for m,v in magics['cell'].items() if (v not in self.ignore)])),
36 '',
36 '',
37 mman.auto_status()]
37 mman.auto_status()]
38 return '\n'.join(out)
38 return '\n'.join(out)
39
39
40 def _repr_pretty_(self, p, cycle):
40 def _repr_pretty_(self, p, cycle):
41 p.text(self._lsmagic())
41 p.text(self._lsmagic())
42
42
43 def __repr__(self):
43 def __repr__(self):
44 return self.__str__()
44 return self.__str__()
45
45
46 def __str__(self):
46 def __str__(self):
47 return self._lsmagic()
47 return self._lsmagic()
48
48
49 def _jsonable(self):
49 def _jsonable(self):
50 """turn magics dict into jsonable dict of the same structure
50 """turn magics dict into jsonable dict of the same structure
51
51
52 replaces object instances with their class names as strings
52 replaces object instances with their class names as strings
53 """
53 """
54 magic_dict = {}
54 magic_dict = {}
55 mman = self.magics_manager
55 mman = self.magics_manager
56 magics = mman.lsmagic()
56 magics = mman.lsmagic()
57 for key, subdict in magics.items():
57 for key, subdict in magics.items():
58 d = {}
58 d = {}
59 magic_dict[key] = d
59 magic_dict[key] = d
60 for name, obj in subdict.items():
60 for name, obj in subdict.items():
61 try:
61 try:
62 classname = obj.__self__.__class__.__name__
62 classname = obj.__self__.__class__.__name__
63 except AttributeError:
63 except AttributeError:
64 classname = 'Other'
64 classname = 'Other'
65
65
66 d[name] = classname
66 d[name] = classname
67 return magic_dict
67 return magic_dict
68
68
69 def _repr_json_(self):
69 def _repr_json_(self):
70 return self._jsonable()
70 return self._jsonable()
71
71
72
72
73 @magics_class
73 @magics_class
74 class BasicMagics(Magics):
74 class BasicMagics(Magics):
75 """Magics that provide central IPython functionality.
75 """Magics that provide central IPython functionality.
76
76
77 These are various magics that don't fit into specific categories but that
77 These are various magics that don't fit into specific categories but that
78 are all part of the base 'IPython experience'."""
78 are all part of the base 'IPython experience'."""
79
79
80 @skip_doctest
80 @skip_doctest
81 @magic_arguments.magic_arguments()
81 @magic_arguments.magic_arguments()
82 @magic_arguments.argument(
82 @magic_arguments.argument(
83 '-l', '--line', action='store_true',
83 '-l', '--line', action='store_true',
84 help="""Create a line magic alias."""
84 help="""Create a line magic alias."""
85 )
85 )
86 @magic_arguments.argument(
86 @magic_arguments.argument(
87 '-c', '--cell', action='store_true',
87 '-c', '--cell', action='store_true',
88 help="""Create a cell magic alias."""
88 help="""Create a cell magic alias."""
89 )
89 )
90 @magic_arguments.argument(
90 @magic_arguments.argument(
91 'name',
91 'name',
92 help="""Name of the magic to be created."""
92 help="""Name of the magic to be created."""
93 )
93 )
94 @magic_arguments.argument(
94 @magic_arguments.argument(
95 'target',
95 'target',
96 help="""Name of the existing line or cell magic."""
96 help="""Name of the existing line or cell magic."""
97 )
97 )
98 @magic_arguments.argument(
98 @magic_arguments.argument(
99 '-p', '--params', default=None,
99 '-p', '--params', default=None,
100 help="""Parameters passed to the magic function."""
100 help="""Parameters passed to the magic function."""
101 )
101 )
102 @line_magic
102 @line_magic
103 def alias_magic(self, line=''):
103 def alias_magic(self, line=''):
104 """Create an alias for an existing line or cell magic.
104 """Create an alias for an existing line or cell magic.
105
105
106 Examples
106 Examples
107 --------
107 --------
108 ::
108 ::
109
109
110 In [1]: %alias_magic t timeit
110 In [1]: %alias_magic t timeit
111 Created `%t` as an alias for `%timeit`.
111 Created `%t` as an alias for `%timeit`.
112 Created `%%t` as an alias for `%%timeit`.
112 Created `%%t` as an alias for `%%timeit`.
113
113
114 In [2]: %t -n1 pass
114 In [2]: %t -n1 pass
115 107 ns Β± 43.6 ns per loop (mean Β± std. dev. of 7 runs, 1 loop each)
115 107 ns Β± 43.6 ns per loop (mean Β± std. dev. of 7 runs, 1 loop each)
116
116
117 In [3]: %%t -n1
117 In [3]: %%t -n1
118 ...: pass
118 ...: pass
119 ...:
119 ...:
120 107 ns Β± 58.3 ns per loop (mean Β± std. dev. of 7 runs, 1 loop each)
120 107 ns Β± 58.3 ns per loop (mean Β± std. dev. of 7 runs, 1 loop each)
121
121
122 In [4]: %alias_magic --cell whereami pwd
122 In [4]: %alias_magic --cell whereami pwd
123 UsageError: Cell magic function `%%pwd` not found.
123 UsageError: Cell magic function `%%pwd` not found.
124 In [5]: %alias_magic --line whereami pwd
124 In [5]: %alias_magic --line whereami pwd
125 Created `%whereami` as an alias for `%pwd`.
125 Created `%whereami` as an alias for `%pwd`.
126
126
127 In [6]: %whereami
127 In [6]: %whereami
128 Out[6]: '/home/testuser'
128 Out[6]: '/home/testuser'
129
129
130 In [7]: %alias_magic h history -p "-l 30" --line
130 In [7]: %alias_magic h history -p "-l 30" --line
131 Created `%h` as an alias for `%history -l 30`.
131 Created `%h` as an alias for `%history -l 30`.
132 """
132 """
133
133
134 args = magic_arguments.parse_argstring(self.alias_magic, line)
134 args = magic_arguments.parse_argstring(self.alias_magic, line)
135 shell = self.shell
135 shell = self.shell
136 mman = self.shell.magics_manager
136 mman = self.shell.magics_manager
137 escs = ''.join(magic_escapes.values())
137 escs = ''.join(magic_escapes.values())
138
138
139 target = args.target.lstrip(escs)
139 target = args.target.lstrip(escs)
140 name = args.name.lstrip(escs)
140 name = args.name.lstrip(escs)
141
141
142 params = args.params
142 params = args.params
143 if (params and
143 if (params and
144 ((params.startswith('"') and params.endswith('"'))
144 ((params.startswith('"') and params.endswith('"'))
145 or (params.startswith("'") and params.endswith("'")))):
145 or (params.startswith("'") and params.endswith("'")))):
146 params = params[1:-1]
146 params = params[1:-1]
147
147
148 # Find the requested magics.
148 # Find the requested magics.
149 m_line = shell.find_magic(target, 'line')
149 m_line = shell.find_magic(target, 'line')
150 m_cell = shell.find_magic(target, 'cell')
150 m_cell = shell.find_magic(target, 'cell')
151 if args.line and m_line is None:
151 if args.line and m_line is None:
152 raise UsageError('Line magic function `%s%s` not found.' %
152 raise UsageError('Line magic function `%s%s` not found.' %
153 (magic_escapes['line'], target))
153 (magic_escapes['line'], target))
154 if args.cell and m_cell is None:
154 if args.cell and m_cell is None:
155 raise UsageError('Cell magic function `%s%s` not found.' %
155 raise UsageError('Cell magic function `%s%s` not found.' %
156 (magic_escapes['cell'], target))
156 (magic_escapes['cell'], target))
157
157
158 # If --line and --cell are not specified, default to the ones
158 # If --line and --cell are not specified, default to the ones
159 # that are available.
159 # that are available.
160 if not args.line and not args.cell:
160 if not args.line and not args.cell:
161 if not m_line and not m_cell:
161 if not m_line and not m_cell:
162 raise UsageError(
162 raise UsageError(
163 'No line or cell magic with name `%s` found.' % target
163 'No line or cell magic with name `%s` found.' % target
164 )
164 )
165 args.line = bool(m_line)
165 args.line = bool(m_line)
166 args.cell = bool(m_cell)
166 args.cell = bool(m_cell)
167
167
168 params_str = "" if params is None else " " + params
168 params_str = "" if params is None else " " + params
169
169
170 if args.line:
170 if args.line:
171 mman.register_alias(name, target, 'line', params)
171 mman.register_alias(name, target, 'line', params)
172 print('Created `%s%s` as an alias for `%s%s%s`.' % (
172 print('Created `%s%s` as an alias for `%s%s%s`.' % (
173 magic_escapes['line'], name,
173 magic_escapes['line'], name,
174 magic_escapes['line'], target, params_str))
174 magic_escapes['line'], target, params_str))
175
175
176 if args.cell:
176 if args.cell:
177 mman.register_alias(name, target, 'cell', params)
177 mman.register_alias(name, target, 'cell', params)
178 print('Created `%s%s` as an alias for `%s%s%s`.' % (
178 print('Created `%s%s` as an alias for `%s%s%s`.' % (
179 magic_escapes['cell'], name,
179 magic_escapes['cell'], name,
180 magic_escapes['cell'], target, params_str))
180 magic_escapes['cell'], target, params_str))
181
181
182 @line_magic
182 @line_magic
183 def lsmagic(self, parameter_s=''):
183 def lsmagic(self, parameter_s=''):
184 """List currently available magic functions."""
184 """List currently available magic functions."""
185 return MagicsDisplay(self.shell.magics_manager, ignore=[])
185 return MagicsDisplay(self.shell.magics_manager, ignore=[])
186
186
187 def _magic_docs(self, brief=False, rest=False):
187 def _magic_docs(self, brief=False, rest=False):
188 """Return docstrings from magic functions."""
188 """Return docstrings from magic functions."""
189 mman = self.shell.magics_manager
189 mman = self.shell.magics_manager
190 docs = mman.lsmagic_docs(brief, missing='No documentation')
190 docs = mman.lsmagic_docs(brief, missing='No documentation')
191
191
192 if rest:
192 if rest:
193 format_string = '**%s%s**::\n\n%s\n\n'
193 format_string = '**%s%s**::\n\n%s\n\n'
194 else:
194 else:
195 format_string = '%s%s:\n%s\n'
195 format_string = '%s%s:\n%s\n'
196
196
197 return ''.join(
197 return ''.join(
198 [format_string % (magic_escapes['line'], fname,
198 [format_string % (magic_escapes['line'], fname,
199 indent(dedent(fndoc)))
199 indent(dedent(fndoc)))
200 for fname, fndoc in sorted(docs['line'].items())]
200 for fname, fndoc in sorted(docs['line'].items())]
201 +
201 +
202 [format_string % (magic_escapes['cell'], fname,
202 [format_string % (magic_escapes['cell'], fname,
203 indent(dedent(fndoc)))
203 indent(dedent(fndoc)))
204 for fname, fndoc in sorted(docs['cell'].items())]
204 for fname, fndoc in sorted(docs['cell'].items())]
205 )
205 )
206
206
207 @line_magic
207 @line_magic
208 def magic(self, parameter_s=''):
208 def magic(self, parameter_s=''):
209 """Print information about the magic function system.
209 """Print information about the magic function system.
210
210
211 Supported formats: -latex, -brief, -rest
211 Supported formats: -latex, -brief, -rest
212 """
212 """
213
213
214 mode = ''
214 mode = ''
215 try:
215 try:
216 mode = parameter_s.split()[0][1:]
216 mode = parameter_s.split()[0][1:]
217 except IndexError:
217 except IndexError:
218 pass
218 pass
219
219
220 brief = (mode == 'brief')
220 brief = (mode == 'brief')
221 rest = (mode == 'rest')
221 rest = (mode == 'rest')
222 magic_docs = self._magic_docs(brief, rest)
222 magic_docs = self._magic_docs(brief, rest)
223
223
224 if mode == 'latex':
224 if mode == 'latex':
225 print(self.format_latex(magic_docs))
225 print(self.format_latex(magic_docs))
226 return
226 return
227 else:
227 else:
228 magic_docs = format_screen(magic_docs)
228 magic_docs = format_screen(magic_docs)
229
229
230 out = ["""
230 out = ["""
231 IPython's 'magic' functions
231 IPython's 'magic' functions
232 ===========================
232 ===========================
233
233
234 The magic function system provides a series of functions which allow you to
234 The magic function system provides a series of functions which allow you to
235 control the behavior of IPython itself, plus a lot of system-type
235 control the behavior of IPython itself, plus a lot of system-type
236 features. There are two kinds of magics, line-oriented and cell-oriented.
236 features. There are two kinds of magics, line-oriented and cell-oriented.
237
237
238 Line magics are prefixed with the % character and work much like OS
238 Line magics are prefixed with the % character and work much like OS
239 command-line calls: they get as an argument the rest of the line, where
239 command-line calls: they get as an argument the rest of the line, where
240 arguments are passed without parentheses or quotes. For example, this will
240 arguments are passed without parentheses or quotes. For example, this will
241 time the given statement::
241 time the given statement::
242
242
243 %timeit range(1000)
243 %timeit range(1000)
244
244
245 Cell magics are prefixed with a double %%, and they are functions that get as
245 Cell magics are prefixed with a double %%, and they are functions that get as
246 an argument not only the rest of the line, but also the lines below it in a
246 an argument not only the rest of the line, but also the lines below it in a
247 separate argument. These magics are called with two arguments: the rest of the
247 separate argument. These magics are called with two arguments: the rest of the
248 call line and the body of the cell, consisting of the lines below the first.
248 call line and the body of the cell, consisting of the lines below the first.
249 For example::
249 For example::
250
250
251 %%timeit x = numpy.random.randn((100, 100))
251 %%timeit x = numpy.random.randn((100, 100))
252 numpy.linalg.svd(x)
252 numpy.linalg.svd(x)
253
253
254 will time the execution of the numpy svd routine, running the assignment of x
254 will time the execution of the numpy svd routine, running the assignment of x
255 as part of the setup phase, which is not timed.
255 as part of the setup phase, which is not timed.
256
256
257 In a line-oriented client (the terminal or Qt console IPython), starting a new
257 In a line-oriented client (the terminal or Qt console IPython), starting a new
258 input with %% will automatically enter cell mode, and IPython will continue
258 input with %% will automatically enter cell mode, and IPython will continue
259 reading input until a blank line is given. In the notebook, simply type the
259 reading input until a blank line is given. In the notebook, simply type the
260 whole cell as one entity, but keep in mind that the %% escape can only be at
260 whole cell as one entity, but keep in mind that the %% escape can only be at
261 the very start of the cell.
261 the very start of the cell.
262
262
263 NOTE: If you have 'automagic' enabled (via the command line option or with the
263 NOTE: If you have 'automagic' enabled (via the command line option or with the
264 %automagic function), you don't need to type in the % explicitly for line
264 %automagic function), you don't need to type in the % explicitly for line
265 magics; cell magics always require an explicit '%%' escape. By default,
265 magics; cell magics always require an explicit '%%' escape. By default,
266 IPython ships with automagic on, so you should only rarely need the % escape.
266 IPython ships with automagic on, so you should only rarely need the % escape.
267
267
268 Example: typing '%cd mydir' (without the quotes) changes your working directory
268 Example: typing '%cd mydir' (without the quotes) changes your working directory
269 to 'mydir', if it exists.
269 to 'mydir', if it exists.
270
270
271 For a list of the available magic functions, use %lsmagic. For a description
271 For a list of the available magic functions, use %lsmagic. For a description
272 of any of them, type %magic_name?, e.g. '%cd?'.
272 of any of them, type %magic_name?, e.g. '%cd?'.
273
273
274 Currently the magic system has the following functions:""",
274 Currently the magic system has the following functions:""",
275 magic_docs,
275 magic_docs,
276 "Summary of magic functions (from %slsmagic):" % magic_escapes['line'],
276 "Summary of magic functions (from %slsmagic):" % magic_escapes['line'],
277 str(self.lsmagic()),
277 str(self.lsmagic()),
278 ]
278 ]
279 page.page('\n'.join(out))
279 page.page('\n'.join(out))
280
280
281
281
282 @line_magic
282 @line_magic
283 def page(self, parameter_s=''):
283 def page(self, parameter_s=''):
284 """Pretty print the object and display it through a pager.
284 """Pretty print the object and display it through a pager.
285
285
286 %page [options] OBJECT
286 %page [options] OBJECT
287
287
288 If no object is given, use _ (last output).
288 If no object is given, use _ (last output).
289
289
290 Options:
290 Options:
291
291
292 -r: page str(object), don't pretty-print it."""
292 -r: page str(object), don't pretty-print it."""
293
293
294 # After a function contributed by Olivier Aubert, slightly modified.
294 # After a function contributed by Olivier Aubert, slightly modified.
295
295
296 # Process options/args
296 # Process options/args
297 opts, args = self.parse_options(parameter_s, 'r')
297 opts, args = self.parse_options(parameter_s, 'r')
298 raw = 'r' in opts
298 raw = 'r' in opts
299
299
300 oname = args and args or '_'
300 oname = args and args or '_'
301 info = self.shell._ofind(oname)
301 info = self.shell._ofind(oname)
302 if info.found:
302 if info.found:
303 if raw:
303 if raw:
304 txt = str(info.obj)
304 txt = str(info.obj)
305 else:
305 else:
306 txt = pformat(info.obj)
306 txt = pformat(info.obj)
307 page.page(txt)
307 page.page(txt)
308 else:
308 else:
309 print('Object `%s` not found' % oname)
309 print('Object `%s` not found' % oname)
310
310
311 @line_magic
311 @line_magic
312 def pprint(self, parameter_s=''):
312 def pprint(self, parameter_s=''):
313 """Toggle pretty printing on/off."""
313 """Toggle pretty printing on/off."""
314 ptformatter = self.shell.display_formatter.formatters['text/plain']
314 ptformatter = self.shell.display_formatter.formatters['text/plain']
315 ptformatter.pprint = bool(1 - ptformatter.pprint)
315 ptformatter.pprint = bool(1 - ptformatter.pprint)
316 print('Pretty printing has been turned',
316 print('Pretty printing has been turned',
317 ['OFF','ON'][ptformatter.pprint])
317 ['OFF','ON'][ptformatter.pprint])
318
318
319 @line_magic
319 @line_magic
320 def colors(self, parameter_s=''):
320 def colors(self, parameter_s=''):
321 """Switch color scheme for prompts, info system and exception handlers.
321 """Switch color scheme for prompts, info system and exception handlers.
322
322
323 Currently implemented schemes: NoColor, Linux, LightBG.
323 Currently implemented schemes: NoColor, Linux, LightBG.
324
324
325 Color scheme names are not case-sensitive.
325 Color scheme names are not case-sensitive.
326
326
327 Examples
327 Examples
328 --------
328 --------
329 To get a plain black and white terminal::
329 To get a plain black and white terminal::
330
330
331 %colors nocolor
331 %colors nocolor
332 """
332 """
333 def color_switch_err(name):
333 def color_switch_err(name):
334 warn('Error changing %s color schemes.\n%s' %
334 warn('Error changing %s color schemes.\n%s' %
335 (name, sys.exc_info()[1]), stacklevel=2)
335 (name, sys.exc_info()[1]), stacklevel=2)
336
336
337
337
338 new_scheme = parameter_s.strip()
338 new_scheme = parameter_s.strip()
339 if not new_scheme:
339 if not new_scheme:
340 raise UsageError(
340 raise UsageError(
341 "%colors: you must specify a color scheme. See '%colors?'")
341 "%colors: you must specify a color scheme. See '%colors?'")
342 # local shortcut
342 # local shortcut
343 shell = self.shell
343 shell = self.shell
344
344
345 # Set shell colour scheme
345 # Set shell colour scheme
346 try:
346 try:
347 shell.colors = new_scheme
347 shell.colors = new_scheme
348 shell.refresh_style()
348 shell.refresh_style()
349 except:
349 except:
350 color_switch_err('shell')
350 color_switch_err('shell')
351
351
352 # Set exception colors
352 # Set exception colors
353 try:
353 try:
354 shell.InteractiveTB.set_colors(scheme = new_scheme)
354 shell.InteractiveTB.set_colors(scheme = new_scheme)
355 shell.SyntaxTB.set_colors(scheme = new_scheme)
355 shell.SyntaxTB.set_colors(scheme = new_scheme)
356 except:
356 except:
357 color_switch_err('exception')
357 color_switch_err('exception')
358
358
359 # Set info (for 'object?') colors
359 # Set info (for 'object?') colors
360 if shell.color_info:
360 if shell.color_info:
361 try:
361 try:
362 shell.inspector.set_active_scheme(new_scheme)
362 shell.inspector.set_active_scheme(new_scheme)
363 except:
363 except:
364 color_switch_err('object inspector')
364 color_switch_err('object inspector')
365 else:
365 else:
366 shell.inspector.set_active_scheme('NoColor')
366 shell.inspector.set_active_scheme('NoColor')
367
367
368 @line_magic
368 @line_magic
369 def xmode(self, parameter_s=''):
369 def xmode(self, parameter_s=''):
370 """Switch modes for the exception handlers.
370 """Switch modes for the exception handlers.
371
371
372 Valid modes: Plain, Context, Verbose, and Minimal.
372 Valid modes: Plain, Context, Verbose, and Minimal.
373
373
374 If called without arguments, acts as a toggle.
374 If called without arguments, acts as a toggle.
375
375
376 When in verbose mode the value `--show` (and `--hide`)
376 When in verbose mode the value `--show` (and `--hide`)
377 will respectively show (or hide) frames with ``__tracebackhide__ =
377 will respectively show (or hide) frames with ``__tracebackhide__ =
378 True`` value set.
378 True`` value set.
379 """
379 """
380
380
381 def xmode_switch_err(name):
381 def xmode_switch_err(name):
382 warn('Error changing %s exception modes.\n%s' %
382 warn('Error changing %s exception modes.\n%s' %
383 (name,sys.exc_info()[1]))
383 (name,sys.exc_info()[1]))
384
384
385 shell = self.shell
385 shell = self.shell
386 if parameter_s.strip() == "--show":
386 if parameter_s.strip() == "--show":
387 shell.InteractiveTB.skip_hidden = False
387 shell.InteractiveTB.skip_hidden = False
388 return
388 return
389 if parameter_s.strip() == "--hide":
389 if parameter_s.strip() == "--hide":
390 shell.InteractiveTB.skip_hidden = True
390 shell.InteractiveTB.skip_hidden = True
391 return
391 return
392
392
393 new_mode = parameter_s.strip().capitalize()
393 new_mode = parameter_s.strip().capitalize()
394 try:
394 try:
395 shell.InteractiveTB.set_mode(mode=new_mode)
395 shell.InteractiveTB.set_mode(mode=new_mode)
396 print('Exception reporting mode:',shell.InteractiveTB.mode)
396 print('Exception reporting mode:',shell.InteractiveTB.mode)
397 except:
397 except:
398 xmode_switch_err('user')
398 xmode_switch_err('user')
399
399
400 @line_magic
400 @line_magic
401 def quickref(self, arg):
401 def quickref(self, arg):
402 """ Show a quick reference sheet """
402 """ Show a quick reference sheet """
403 from IPython.core.usage import quick_reference
403 from IPython.core.usage import quick_reference
404 qr = quick_reference + self._magic_docs(brief=True)
404 qr = quick_reference + self._magic_docs(brief=True)
405 page.page(qr)
405 page.page(qr)
406
406
407 @line_magic
407 @line_magic
408 def doctest_mode(self, parameter_s=''):
408 def doctest_mode(self, parameter_s=''):
409 """Toggle doctest mode on and off.
409 """Toggle doctest mode on and off.
410
410
411 This mode is intended to make IPython behave as much as possible like a
411 This mode is intended to make IPython behave as much as possible like a
412 plain Python shell, from the perspective of how its prompts, exceptions
412 plain Python shell, from the perspective of how its prompts, exceptions
413 and output look. This makes it easy to copy and paste parts of a
413 and output look. This makes it easy to copy and paste parts of a
414 session into doctests. It does so by:
414 session into doctests. It does so by:
415
415
416 - Changing the prompts to the classic ``>>>`` ones.
416 - Changing the prompts to the classic ``>>>`` ones.
417 - Changing the exception reporting mode to 'Plain'.
417 - Changing the exception reporting mode to 'Plain'.
418 - Disabling pretty-printing of output.
418 - Disabling pretty-printing of output.
419
419
420 Note that IPython also supports the pasting of code snippets that have
420 Note that IPython also supports the pasting of code snippets that have
421 leading '>>>' and '...' prompts in them. This means that you can paste
421 leading '>>>' and '...' prompts in them. This means that you can paste
422 doctests from files or docstrings (even if they have leading
422 doctests from files or docstrings (even if they have leading
423 whitespace), and the code will execute correctly. You can then use
423 whitespace), and the code will execute correctly. You can then use
424 '%history -t' to see the translated history; this will give you the
424 '%history -t' to see the translated history; this will give you the
425 input after removal of all the leading prompts and whitespace, which
425 input after removal of all the leading prompts and whitespace, which
426 can be pasted back into an editor.
426 can be pasted back into an editor.
427
427
428 With these features, you can switch into this mode easily whenever you
428 With these features, you can switch into this mode easily whenever you
429 need to do testing and changes to doctests, without having to leave
429 need to do testing and changes to doctests, without having to leave
430 your existing IPython session.
430 your existing IPython session.
431 """
431 """
432
432
433 # Shorthands
433 # Shorthands
434 shell = self.shell
434 shell = self.shell
435 meta = shell.meta
435 meta = shell.meta
436 disp_formatter = self.shell.display_formatter
436 disp_formatter = self.shell.display_formatter
437 ptformatter = disp_formatter.formatters['text/plain']
437 ptformatter = disp_formatter.formatters['text/plain']
438 # dstore is a data store kept in the instance metadata bag to track any
438 # dstore is a data store kept in the instance metadata bag to track any
439 # changes we make, so we can undo them later.
439 # changes we make, so we can undo them later.
440 dstore = meta.setdefault('doctest_mode',Struct())
440 dstore = meta.setdefault('doctest_mode',Struct())
441 save_dstore = dstore.setdefault
441 save_dstore = dstore.setdefault
442
442
443 # save a few values we'll need to recover later
443 # save a few values we'll need to recover later
444 mode = save_dstore('mode',False)
444 mode = save_dstore('mode',False)
445 save_dstore('rc_pprint',ptformatter.pprint)
445 save_dstore('rc_pprint',ptformatter.pprint)
446 save_dstore('xmode',shell.InteractiveTB.mode)
446 save_dstore('xmode',shell.InteractiveTB.mode)
447 save_dstore('rc_separate_out',shell.separate_out)
447 save_dstore('rc_separate_out',shell.separate_out)
448 save_dstore('rc_separate_out2',shell.separate_out2)
448 save_dstore('rc_separate_out2',shell.separate_out2)
449 save_dstore('rc_separate_in',shell.separate_in)
449 save_dstore('rc_separate_in',shell.separate_in)
450 save_dstore('rc_active_types',disp_formatter.active_types)
450 save_dstore('rc_active_types',disp_formatter.active_types)
451
451
452 if not mode:
452 if not mode:
453 # turn on
453 # turn on
454
454
455 # Prompt separators like plain python
455 # Prompt separators like plain python
456 shell.separate_in = ''
456 shell.separate_in = ''
457 shell.separate_out = ''
457 shell.separate_out = ''
458 shell.separate_out2 = ''
458 shell.separate_out2 = ''
459
459
460
460
461 ptformatter.pprint = False
461 ptformatter.pprint = False
462 disp_formatter.active_types = ['text/plain']
462 disp_formatter.active_types = ['text/plain']
463
463
464 shell.magic('xmode Plain')
464 shell.magic('xmode Plain')
465 else:
465 else:
466 # turn off
466 # turn off
467 shell.separate_in = dstore.rc_separate_in
467 shell.separate_in = dstore.rc_separate_in
468
468
469 shell.separate_out = dstore.rc_separate_out
469 shell.separate_out = dstore.rc_separate_out
470 shell.separate_out2 = dstore.rc_separate_out2
470 shell.separate_out2 = dstore.rc_separate_out2
471
471
472 ptformatter.pprint = dstore.rc_pprint
472 ptformatter.pprint = dstore.rc_pprint
473 disp_formatter.active_types = dstore.rc_active_types
473 disp_formatter.active_types = dstore.rc_active_types
474
474
475 shell.magic('xmode ' + dstore.xmode)
475 shell.run_line_magic("xmode", dstore.xmode)
476
476
477 # mode here is the state before we switch; switch_doctest_mode takes
477 # mode here is the state before we switch; switch_doctest_mode takes
478 # the mode we're switching to.
478 # the mode we're switching to.
479 shell.switch_doctest_mode(not mode)
479 shell.switch_doctest_mode(not mode)
480
480
481 # Store new mode and inform
481 # Store new mode and inform
482 dstore.mode = bool(not mode)
482 dstore.mode = bool(not mode)
483 mode_label = ['OFF','ON'][dstore.mode]
483 mode_label = ['OFF','ON'][dstore.mode]
484 print('Doctest mode is:', mode_label)
484 print('Doctest mode is:', mode_label)
485
485
486 @line_magic
486 @line_magic
487 def gui(self, parameter_s=''):
487 def gui(self, parameter_s=''):
488 """Enable or disable IPython GUI event loop integration.
488 """Enable or disable IPython GUI event loop integration.
489
489
490 %gui [GUINAME]
490 %gui [GUINAME]
491
491
492 This magic replaces IPython's threaded shells that were activated
492 This magic replaces IPython's threaded shells that were activated
493 using the (pylab/wthread/etc.) command line flags. GUI toolkits
493 using the (pylab/wthread/etc.) command line flags. GUI toolkits
494 can now be enabled at runtime and keyboard
494 can now be enabled at runtime and keyboard
495 interrupts should work without any problems. The following toolkits
495 interrupts should work without any problems. The following toolkits
496 are supported: wxPython, PyQt4, PyGTK, Tk and Cocoa (OSX)::
496 are supported: wxPython, PyQt4, PyGTK, Tk and Cocoa (OSX)::
497
497
498 %gui wx # enable wxPython event loop integration
498 %gui wx # enable wxPython event loop integration
499 %gui qt # enable PyQt/PySide event loop integration
499 %gui qt # enable PyQt/PySide event loop integration
500 # with the latest version available.
500 # with the latest version available.
501 %gui qt6 # enable PyQt6/PySide6 event loop integration
501 %gui qt6 # enable PyQt6/PySide6 event loop integration
502 %gui qt5 # enable PyQt5/PySide2 event loop integration
502 %gui qt5 # enable PyQt5/PySide2 event loop integration
503 %gui gtk # enable PyGTK event loop integration
503 %gui gtk # enable PyGTK event loop integration
504 %gui gtk3 # enable Gtk3 event loop integration
504 %gui gtk3 # enable Gtk3 event loop integration
505 %gui gtk4 # enable Gtk4 event loop integration
505 %gui gtk4 # enable Gtk4 event loop integration
506 %gui tk # enable Tk event loop integration
506 %gui tk # enable Tk event loop integration
507 %gui osx # enable Cocoa event loop integration
507 %gui osx # enable Cocoa event loop integration
508 # (requires %matplotlib 1.1)
508 # (requires %matplotlib 1.1)
509 %gui # disable all event loop integration
509 %gui # disable all event loop integration
510
510
511 WARNING: after any of these has been called you can simply create
511 WARNING: after any of these has been called you can simply create
512 an application object, but DO NOT start the event loop yourself, as
512 an application object, but DO NOT start the event loop yourself, as
513 we have already handled that.
513 we have already handled that.
514 """
514 """
515 opts, arg = self.parse_options(parameter_s, '')
515 opts, arg = self.parse_options(parameter_s, '')
516 if arg=='': arg = None
516 if arg=='': arg = None
517 try:
517 try:
518 return self.shell.enable_gui(arg)
518 return self.shell.enable_gui(arg)
519 except Exception as e:
519 except Exception as e:
520 # print simple error message, rather than traceback if we can't
520 # print simple error message, rather than traceback if we can't
521 # hook up the GUI
521 # hook up the GUI
522 error(str(e))
522 error(str(e))
523
523
524 @skip_doctest
524 @skip_doctest
525 @line_magic
525 @line_magic
526 def precision(self, s=''):
526 def precision(self, s=''):
527 """Set floating point precision for pretty printing.
527 """Set floating point precision for pretty printing.
528
528
529 Can set either integer precision or a format string.
529 Can set either integer precision or a format string.
530
530
531 If numpy has been imported and precision is an int,
531 If numpy has been imported and precision is an int,
532 numpy display precision will also be set, via ``numpy.set_printoptions``.
532 numpy display precision will also be set, via ``numpy.set_printoptions``.
533
533
534 If no argument is given, defaults will be restored.
534 If no argument is given, defaults will be restored.
535
535
536 Examples
536 Examples
537 --------
537 --------
538 ::
538 ::
539
539
540 In [1]: from math import pi
540 In [1]: from math import pi
541
541
542 In [2]: %precision 3
542 In [2]: %precision 3
543 Out[2]: '%.3f'
543 Out[2]: '%.3f'
544
544
545 In [3]: pi
545 In [3]: pi
546 Out[3]: 3.142
546 Out[3]: 3.142
547
547
548 In [4]: %precision %i
548 In [4]: %precision %i
549 Out[4]: '%i'
549 Out[4]: '%i'
550
550
551 In [5]: pi
551 In [5]: pi
552 Out[5]: 3
552 Out[5]: 3
553
553
554 In [6]: %precision %e
554 In [6]: %precision %e
555 Out[6]: '%e'
555 Out[6]: '%e'
556
556
557 In [7]: pi**10
557 In [7]: pi**10
558 Out[7]: 9.364805e+04
558 Out[7]: 9.364805e+04
559
559
560 In [8]: %precision
560 In [8]: %precision
561 Out[8]: '%r'
561 Out[8]: '%r'
562
562
563 In [9]: pi**10
563 In [9]: pi**10
564 Out[9]: 93648.047476082982
564 Out[9]: 93648.047476082982
565 """
565 """
566 ptformatter = self.shell.display_formatter.formatters['text/plain']
566 ptformatter = self.shell.display_formatter.formatters['text/plain']
567 ptformatter.float_precision = s
567 ptformatter.float_precision = s
568 return ptformatter.float_format
568 return ptformatter.float_format
569
569
570 @magic_arguments.magic_arguments()
570 @magic_arguments.magic_arguments()
571 @magic_arguments.argument(
571 @magic_arguments.argument(
572 'filename', type=str,
572 'filename', type=str,
573 help='Notebook name or filename'
573 help='Notebook name or filename'
574 )
574 )
575 @line_magic
575 @line_magic
576 def notebook(self, s):
576 def notebook(self, s):
577 """Export and convert IPython notebooks.
577 """Export and convert IPython notebooks.
578
578
579 This function can export the current IPython history to a notebook file.
579 This function can export the current IPython history to a notebook file.
580 For example, to export the history to "foo.ipynb" do "%notebook foo.ipynb".
580 For example, to export the history to "foo.ipynb" do "%notebook foo.ipynb".
581 """
581 """
582 args = magic_arguments.parse_argstring(self.notebook, s)
582 args = magic_arguments.parse_argstring(self.notebook, s)
583 outfname = os.path.expanduser(args.filename)
583 outfname = os.path.expanduser(args.filename)
584
584
585 from nbformat import write, v4
585 from nbformat import write, v4
586
586
587 cells = []
587 cells = []
588 hist = list(self.shell.history_manager.get_range())
588 hist = list(self.shell.history_manager.get_range())
589 if(len(hist)<=1):
589 if(len(hist)<=1):
590 raise ValueError('History is empty, cannot export')
590 raise ValueError('History is empty, cannot export')
591 for session, execution_count, source in hist[:-1]:
591 for session, execution_count, source in hist[:-1]:
592 cells.append(v4.new_code_cell(
592 cells.append(v4.new_code_cell(
593 execution_count=execution_count,
593 execution_count=execution_count,
594 source=source
594 source=source
595 ))
595 ))
596 nb = v4.new_notebook(cells=cells)
596 nb = v4.new_notebook(cells=cells)
597 with io.open(outfname, "w", encoding="utf-8") as f:
597 with io.open(outfname, "w", encoding="utf-8") as f:
598 write(nb, f, version=4)
598 write(nb, f, version=4)
599
599
600 @magics_class
600 @magics_class
601 class AsyncMagics(BasicMagics):
601 class AsyncMagics(BasicMagics):
602
602
603 @line_magic
603 @line_magic
604 def autoawait(self, parameter_s):
604 def autoawait(self, parameter_s):
605 """
605 """
606 Allow to change the status of the autoawait option.
606 Allow to change the status of the autoawait option.
607
607
608 This allow you to set a specific asynchronous code runner.
608 This allow you to set a specific asynchronous code runner.
609
609
610 If no value is passed, print the currently used asynchronous integration
610 If no value is passed, print the currently used asynchronous integration
611 and whether it is activated.
611 and whether it is activated.
612
612
613 It can take a number of value evaluated in the following order:
613 It can take a number of value evaluated in the following order:
614
614
615 - False/false/off deactivate autoawait integration
615 - False/false/off deactivate autoawait integration
616 - True/true/on activate autoawait integration using configured default
616 - True/true/on activate autoawait integration using configured default
617 loop
617 loop
618 - asyncio/curio/trio activate autoawait integration and use integration
618 - asyncio/curio/trio activate autoawait integration and use integration
619 with said library.
619 with said library.
620
620
621 - `sync` turn on the pseudo-sync integration (mostly used for
621 - `sync` turn on the pseudo-sync integration (mostly used for
622 `IPython.embed()` which does not run IPython with a real eventloop and
622 `IPython.embed()` which does not run IPython with a real eventloop and
623 deactivate running asynchronous code. Turning on Asynchronous code with
623 deactivate running asynchronous code. Turning on Asynchronous code with
624 the pseudo sync loop is undefined behavior and may lead IPython to crash.
624 the pseudo sync loop is undefined behavior and may lead IPython to crash.
625
625
626 If the passed parameter does not match any of the above and is a python
626 If the passed parameter does not match any of the above and is a python
627 identifier, get said object from user namespace and set it as the
627 identifier, get said object from user namespace and set it as the
628 runner, and activate autoawait.
628 runner, and activate autoawait.
629
629
630 If the object is a fully qualified object name, attempt to import it and
630 If the object is a fully qualified object name, attempt to import it and
631 set it as the runner, and activate autoawait.
631 set it as the runner, and activate autoawait.
632
632
633 The exact behavior of autoawait is experimental and subject to change
633 The exact behavior of autoawait is experimental and subject to change
634 across version of IPython and Python.
634 across version of IPython and Python.
635 """
635 """
636
636
637 param = parameter_s.strip()
637 param = parameter_s.strip()
638 d = {True: "on", False: "off"}
638 d = {True: "on", False: "off"}
639
639
640 if not param:
640 if not param:
641 print("IPython autoawait is `{}`, and set to use `{}`".format(
641 print("IPython autoawait is `{}`, and set to use `{}`".format(
642 d[self.shell.autoawait],
642 d[self.shell.autoawait],
643 self.shell.loop_runner
643 self.shell.loop_runner
644 ))
644 ))
645 return None
645 return None
646
646
647 if param.lower() in ('false', 'off'):
647 if param.lower() in ('false', 'off'):
648 self.shell.autoawait = False
648 self.shell.autoawait = False
649 return None
649 return None
650 if param.lower() in ('true', 'on'):
650 if param.lower() in ('true', 'on'):
651 self.shell.autoawait = True
651 self.shell.autoawait = True
652 return None
652 return None
653
653
654 if param in self.shell.loop_runner_map:
654 if param in self.shell.loop_runner_map:
655 self.shell.loop_runner, self.shell.autoawait = self.shell.loop_runner_map[param]
655 self.shell.loop_runner, self.shell.autoawait = self.shell.loop_runner_map[param]
656 return None
656 return None
657
657
658 if param in self.shell.user_ns :
658 if param in self.shell.user_ns :
659 self.shell.loop_runner = self.shell.user_ns[param]
659 self.shell.loop_runner = self.shell.user_ns[param]
660 self.shell.autoawait = True
660 self.shell.autoawait = True
661 return None
661 return None
662
662
663 runner = import_item(param)
663 runner = import_item(param)
664
664
665 self.shell.loop_runner = runner
665 self.shell.loop_runner = runner
666 self.shell.autoawait = True
666 self.shell.autoawait = True
@@ -1,27 +1,27
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Test IPython.core.logger"""
2 """Test IPython.core.logger"""
3
3
4 import os.path
4 import os.path
5
5
6 import pytest
6 import pytest
7 from tempfile import TemporaryDirectory
7 from tempfile import TemporaryDirectory
8
8
9
9
10 def test_logstart_inaccessible_file():
10 def test_logstart_inaccessible_file():
11 with pytest.raises(IOError):
11 with pytest.raises(IOError):
12 _ip.logger.logstart(logfname="/") # Opening that filename will fail.
12 _ip.logger.logstart(logfname="/") # Opening that filename will fail.
13
13
14 try:
14 try:
15 _ip.run_cell("a=1") # Check it doesn't try to log this
15 _ip.run_cell("a=1") # Check it doesn't try to log this
16 finally:
16 finally:
17 _ip.logger.log_active = False # If this fails, don't let later tests fail
17 _ip.logger.log_active = False # If this fails, don't let later tests fail
18
18
19 def test_logstart_unicode():
19 def test_logstart_unicode():
20 with TemporaryDirectory() as tdir:
20 with TemporaryDirectory() as tdir:
21 logfname = os.path.join(tdir, "test_unicode.log")
21 logfname = os.path.join(tdir, "test_unicode.log")
22 _ip.run_cell("'abc€'")
22 _ip.run_cell("'abc€'")
23 try:
23 try:
24 _ip.magic("logstart -to %s" % logfname)
24 _ip.run_line_magic("logstart", "-to %s" % logfname)
25 _ip.run_cell("'abc€'")
25 _ip.run_cell("'abc€'")
26 finally:
26 finally:
27 _ip.logger.logstop()
27 _ip.logger.logstop()
@@ -1,1556 +1,1556
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for various magic functions."""
2 """Tests for various magic functions."""
3
3
4 import gc
4 import gc
5 import io
5 import io
6 import os
6 import os
7 import re
7 import re
8 import shlex
8 import shlex
9 import sys
9 import sys
10 import warnings
10 import warnings
11 from importlib import invalidate_caches
11 from importlib import invalidate_caches
12 from io import StringIO
12 from io import StringIO
13 from pathlib import Path
13 from pathlib import Path
14 from textwrap import dedent
14 from textwrap import dedent
15 from unittest import TestCase, mock
15 from unittest import TestCase, mock
16
16
17 import pytest
17 import pytest
18
18
19 from IPython import get_ipython
19 from IPython import get_ipython
20 from IPython.core import magic
20 from IPython.core import magic
21 from IPython.core.error import UsageError
21 from IPython.core.error import UsageError
22 from IPython.core.magic import (
22 from IPython.core.magic import (
23 Magics,
23 Magics,
24 cell_magic,
24 cell_magic,
25 line_magic,
25 line_magic,
26 magics_class,
26 magics_class,
27 register_cell_magic,
27 register_cell_magic,
28 register_line_magic,
28 register_line_magic,
29 )
29 )
30 from IPython.core.magics import code, execution, logging, osm, script
30 from IPython.core.magics import code, execution, logging, osm, script
31 from IPython.testing import decorators as dec
31 from IPython.testing import decorators as dec
32 from IPython.testing import tools as tt
32 from IPython.testing import tools as tt
33 from IPython.utils.io import capture_output
33 from IPython.utils.io import capture_output
34 from IPython.utils.process import find_cmd
34 from IPython.utils.process import find_cmd
35 from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory
35 from IPython.utils.tempdir import TemporaryDirectory, TemporaryWorkingDirectory
36 from IPython.utils.syspathcontext import prepended_to_syspath
36 from IPython.utils.syspathcontext import prepended_to_syspath
37
37
38 from .test_debugger import PdbTestInput
38 from .test_debugger import PdbTestInput
39
39
40 from tempfile import NamedTemporaryFile
40 from tempfile import NamedTemporaryFile
41
41
42 @magic.magics_class
42 @magic.magics_class
43 class DummyMagics(magic.Magics): pass
43 class DummyMagics(magic.Magics): pass
44
44
45 def test_extract_code_ranges():
45 def test_extract_code_ranges():
46 instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
46 instr = "1 3 5-6 7-9 10:15 17: :10 10- -13 :"
47 expected = [
47 expected = [
48 (0, 1),
48 (0, 1),
49 (2, 3),
49 (2, 3),
50 (4, 6),
50 (4, 6),
51 (6, 9),
51 (6, 9),
52 (9, 14),
52 (9, 14),
53 (16, None),
53 (16, None),
54 (None, 9),
54 (None, 9),
55 (9, None),
55 (9, None),
56 (None, 13),
56 (None, 13),
57 (None, None),
57 (None, None),
58 ]
58 ]
59 actual = list(code.extract_code_ranges(instr))
59 actual = list(code.extract_code_ranges(instr))
60 assert actual == expected
60 assert actual == expected
61
61
62 def test_extract_symbols():
62 def test_extract_symbols():
63 source = """import foo\na = 10\ndef b():\n return 42\n\n\nclass A: pass\n\n\n"""
63 source = """import foo\na = 10\ndef b():\n return 42\n\n\nclass A: pass\n\n\n"""
64 symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
64 symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
65 expected = [([], ['a']),
65 expected = [([], ['a']),
66 (["def b():\n return 42\n"], []),
66 (["def b():\n return 42\n"], []),
67 (["class A: pass\n"], []),
67 (["class A: pass\n"], []),
68 (["class A: pass\n", "def b():\n return 42\n"], []),
68 (["class A: pass\n", "def b():\n return 42\n"], []),
69 (["class A: pass\n"], ['a']),
69 (["class A: pass\n"], ['a']),
70 ([], ['z'])]
70 ([], ['z'])]
71 for symbols, exp in zip(symbols_args, expected):
71 for symbols, exp in zip(symbols_args, expected):
72 assert code.extract_symbols(source, symbols) == exp
72 assert code.extract_symbols(source, symbols) == exp
73
73
74
74
75 def test_extract_symbols_raises_exception_with_non_python_code():
75 def test_extract_symbols_raises_exception_with_non_python_code():
76 source = ("=begin A Ruby program :)=end\n"
76 source = ("=begin A Ruby program :)=end\n"
77 "def hello\n"
77 "def hello\n"
78 "puts 'Hello world'\n"
78 "puts 'Hello world'\n"
79 "end")
79 "end")
80 with pytest.raises(SyntaxError):
80 with pytest.raises(SyntaxError):
81 code.extract_symbols(source, "hello")
81 code.extract_symbols(source, "hello")
82
82
83
83
84 def test_magic_not_found():
84 def test_magic_not_found():
85 # magic not found raises UsageError
85 # magic not found raises UsageError
86 with pytest.raises(UsageError):
86 with pytest.raises(UsageError):
87 _ip.run_line_magic("doesntexist", "")
87 _ip.run_line_magic("doesntexist", "")
88
88
89 # ensure result isn't success when a magic isn't found
89 # ensure result isn't success when a magic isn't found
90 result = _ip.run_cell('%doesntexist')
90 result = _ip.run_cell('%doesntexist')
91 assert isinstance(result.error_in_exec, UsageError)
91 assert isinstance(result.error_in_exec, UsageError)
92
92
93
93
94 def test_cell_magic_not_found():
94 def test_cell_magic_not_found():
95 # magic not found raises UsageError
95 # magic not found raises UsageError
96 with pytest.raises(UsageError):
96 with pytest.raises(UsageError):
97 _ip.run_cell_magic('doesntexist', 'line', 'cell')
97 _ip.run_cell_magic('doesntexist', 'line', 'cell')
98
98
99 # ensure result isn't success when a magic isn't found
99 # ensure result isn't success when a magic isn't found
100 result = _ip.run_cell('%%doesntexist')
100 result = _ip.run_cell('%%doesntexist')
101 assert isinstance(result.error_in_exec, UsageError)
101 assert isinstance(result.error_in_exec, UsageError)
102
102
103
103
104 def test_magic_error_status():
104 def test_magic_error_status():
105 def fail(shell):
105 def fail(shell):
106 1/0
106 1/0
107 _ip.register_magic_function(fail)
107 _ip.register_magic_function(fail)
108 result = _ip.run_cell('%fail')
108 result = _ip.run_cell('%fail')
109 assert isinstance(result.error_in_exec, ZeroDivisionError)
109 assert isinstance(result.error_in_exec, ZeroDivisionError)
110
110
111
111
112 def test_config():
112 def test_config():
113 """ test that config magic does not raise
113 """ test that config magic does not raise
114 can happen if Configurable init is moved too early into
114 can happen if Configurable init is moved too early into
115 Magics.__init__ as then a Config object will be registered as a
115 Magics.__init__ as then a Config object will be registered as a
116 magic.
116 magic.
117 """
117 """
118 ## should not raise.
118 ## should not raise.
119 _ip.run_line_magic("config", "")
119 _ip.run_line_magic("config", "")
120
120
121
121
122 def test_config_available_configs():
122 def test_config_available_configs():
123 """ test that config magic prints available configs in unique and
123 """ test that config magic prints available configs in unique and
124 sorted order. """
124 sorted order. """
125 with capture_output() as captured:
125 with capture_output() as captured:
126 _ip.run_line_magic("config", "")
126 _ip.run_line_magic("config", "")
127
127
128 stdout = captured.stdout
128 stdout = captured.stdout
129 config_classes = stdout.strip().split('\n')[1:]
129 config_classes = stdout.strip().split('\n')[1:]
130 assert config_classes == sorted(set(config_classes))
130 assert config_classes == sorted(set(config_classes))
131
131
132 def test_config_print_class():
132 def test_config_print_class():
133 """ test that config with a classname prints the class's options. """
133 """ test that config with a classname prints the class's options. """
134 with capture_output() as captured:
134 with capture_output() as captured:
135 _ip.run_line_magic("config", "TerminalInteractiveShell")
135 _ip.run_line_magic("config", "TerminalInteractiveShell")
136
136
137 stdout = captured.stdout
137 stdout = captured.stdout
138 assert re.match(
138 assert re.match(
139 "TerminalInteractiveShell.* options", stdout.splitlines()[0]
139 "TerminalInteractiveShell.* options", stdout.splitlines()[0]
140 ), f"{stdout}\n\n1st line of stdout not like 'TerminalInteractiveShell.* options'"
140 ), f"{stdout}\n\n1st line of stdout not like 'TerminalInteractiveShell.* options'"
141
141
142
142
143 def test_rehashx():
143 def test_rehashx():
144 # clear up everything
144 # clear up everything
145 _ip.alias_manager.clear_aliases()
145 _ip.alias_manager.clear_aliases()
146 del _ip.db['syscmdlist']
146 del _ip.db['syscmdlist']
147
147
148 _ip.run_line_magic("rehashx", "")
148 _ip.run_line_magic("rehashx", "")
149 # Practically ALL ipython development systems will have more than 10 aliases
149 # Practically ALL ipython development systems will have more than 10 aliases
150
150
151 assert len(_ip.alias_manager.aliases) > 10
151 assert len(_ip.alias_manager.aliases) > 10
152 for name, cmd in _ip.alias_manager.aliases:
152 for name, cmd in _ip.alias_manager.aliases:
153 # we must strip dots from alias names
153 # we must strip dots from alias names
154 assert "." not in name
154 assert "." not in name
155
155
156 # rehashx must fill up syscmdlist
156 # rehashx must fill up syscmdlist
157 scoms = _ip.db['syscmdlist']
157 scoms = _ip.db['syscmdlist']
158 assert len(scoms) > 10
158 assert len(scoms) > 10
159
159
160
160
161 def test_magic_parse_options():
161 def test_magic_parse_options():
162 """Test that we don't mangle paths when parsing magic options."""
162 """Test that we don't mangle paths when parsing magic options."""
163 ip = get_ipython()
163 ip = get_ipython()
164 path = 'c:\\x'
164 path = 'c:\\x'
165 m = DummyMagics(ip)
165 m = DummyMagics(ip)
166 opts = m.parse_options('-f %s' % path,'f:')[0]
166 opts = m.parse_options('-f %s' % path,'f:')[0]
167 # argv splitting is os-dependent
167 # argv splitting is os-dependent
168 if os.name == 'posix':
168 if os.name == 'posix':
169 expected = 'c:x'
169 expected = 'c:x'
170 else:
170 else:
171 expected = path
171 expected = path
172 assert opts["f"] == expected
172 assert opts["f"] == expected
173
173
174
174
175 def test_magic_parse_long_options():
175 def test_magic_parse_long_options():
176 """Magic.parse_options can handle --foo=bar long options"""
176 """Magic.parse_options can handle --foo=bar long options"""
177 ip = get_ipython()
177 ip = get_ipython()
178 m = DummyMagics(ip)
178 m = DummyMagics(ip)
179 opts, _ = m.parse_options("--foo --bar=bubble", "a", "foo", "bar=")
179 opts, _ = m.parse_options("--foo --bar=bubble", "a", "foo", "bar=")
180 assert "foo" in opts
180 assert "foo" in opts
181 assert "bar" in opts
181 assert "bar" in opts
182 assert opts["bar"] == "bubble"
182 assert opts["bar"] == "bubble"
183
183
184
184
185 def doctest_hist_f():
185 def doctest_hist_f():
186 """Test %hist -f with temporary filename.
186 """Test %hist -f with temporary filename.
187
187
188 In [9]: import tempfile
188 In [9]: import tempfile
189
189
190 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
190 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
191
191
192 In [11]: %hist -nl -f $tfile 3
192 In [11]: %hist -nl -f $tfile 3
193
193
194 In [13]: import os; os.unlink(tfile)
194 In [13]: import os; os.unlink(tfile)
195 """
195 """
196
196
197
197
198 def doctest_hist_op():
198 def doctest_hist_op():
199 """Test %hist -op
199 """Test %hist -op
200
200
201 In [1]: class b(float):
201 In [1]: class b(float):
202 ...: pass
202 ...: pass
203 ...:
203 ...:
204
204
205 In [2]: class s(object):
205 In [2]: class s(object):
206 ...: def __str__(self):
206 ...: def __str__(self):
207 ...: return 's'
207 ...: return 's'
208 ...:
208 ...:
209
209
210 In [3]:
210 In [3]:
211
211
212 In [4]: class r(b):
212 In [4]: class r(b):
213 ...: def __repr__(self):
213 ...: def __repr__(self):
214 ...: return 'r'
214 ...: return 'r'
215 ...:
215 ...:
216
216
217 In [5]: class sr(s,r): pass
217 In [5]: class sr(s,r): pass
218 ...:
218 ...:
219
219
220 In [6]:
220 In [6]:
221
221
222 In [7]: bb=b()
222 In [7]: bb=b()
223
223
224 In [8]: ss=s()
224 In [8]: ss=s()
225
225
226 In [9]: rr=r()
226 In [9]: rr=r()
227
227
228 In [10]: ssrr=sr()
228 In [10]: ssrr=sr()
229
229
230 In [11]: 4.5
230 In [11]: 4.5
231 Out[11]: 4.5
231 Out[11]: 4.5
232
232
233 In [12]: str(ss)
233 In [12]: str(ss)
234 Out[12]: 's'
234 Out[12]: 's'
235
235
236 In [13]:
236 In [13]:
237
237
238 In [14]: %hist -op
238 In [14]: %hist -op
239 >>> class b:
239 >>> class b:
240 ... pass
240 ... pass
241 ...
241 ...
242 >>> class s(b):
242 >>> class s(b):
243 ... def __str__(self):
243 ... def __str__(self):
244 ... return 's'
244 ... return 's'
245 ...
245 ...
246 >>>
246 >>>
247 >>> class r(b):
247 >>> class r(b):
248 ... def __repr__(self):
248 ... def __repr__(self):
249 ... return 'r'
249 ... return 'r'
250 ...
250 ...
251 >>> class sr(s,r): pass
251 >>> class sr(s,r): pass
252 >>>
252 >>>
253 >>> bb=b()
253 >>> bb=b()
254 >>> ss=s()
254 >>> ss=s()
255 >>> rr=r()
255 >>> rr=r()
256 >>> ssrr=sr()
256 >>> ssrr=sr()
257 >>> 4.5
257 >>> 4.5
258 4.5
258 4.5
259 >>> str(ss)
259 >>> str(ss)
260 's'
260 's'
261 >>>
261 >>>
262 """
262 """
263
263
264 def test_hist_pof():
264 def test_hist_pof():
265 ip = get_ipython()
265 ip = get_ipython()
266 ip.run_cell("1+2", store_history=True)
266 ip.run_cell("1+2", store_history=True)
267 #raise Exception(ip.history_manager.session_number)
267 #raise Exception(ip.history_manager.session_number)
268 #raise Exception(list(ip.history_manager._get_range_session()))
268 #raise Exception(list(ip.history_manager._get_range_session()))
269 with TemporaryDirectory() as td:
269 with TemporaryDirectory() as td:
270 tf = os.path.join(td, 'hist.py')
270 tf = os.path.join(td, 'hist.py')
271 ip.run_line_magic('history', '-pof %s' % tf)
271 ip.run_line_magic('history', '-pof %s' % tf)
272 assert os.path.isfile(tf)
272 assert os.path.isfile(tf)
273
273
274
274
275 def test_macro():
275 def test_macro():
276 ip = get_ipython()
276 ip = get_ipython()
277 ip.history_manager.reset() # Clear any existing history.
277 ip.history_manager.reset() # Clear any existing history.
278 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
278 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
279 for i, cmd in enumerate(cmds, start=1):
279 for i, cmd in enumerate(cmds, start=1):
280 ip.history_manager.store_inputs(i, cmd)
280 ip.history_manager.store_inputs(i, cmd)
281 ip.run_line_magic("macro", "test 1-3")
281 ip.run_line_magic("macro", "test 1-3")
282 assert ip.user_ns["test"].value == "\n".join(cmds) + "\n"
282 assert ip.user_ns["test"].value == "\n".join(cmds) + "\n"
283
283
284 # List macros
284 # List macros
285 assert "test" in ip.run_line_magic("macro", "")
285 assert "test" in ip.run_line_magic("macro", "")
286
286
287
287
288 def test_macro_run():
288 def test_macro_run():
289 """Test that we can run a multi-line macro successfully."""
289 """Test that we can run a multi-line macro successfully."""
290 ip = get_ipython()
290 ip = get_ipython()
291 ip.history_manager.reset()
291 ip.history_manager.reset()
292 cmds = ["a=10", "a+=1", "print(a)", "%macro test 2-3"]
292 cmds = ["a=10", "a+=1", "print(a)", "%macro test 2-3"]
293 for cmd in cmds:
293 for cmd in cmds:
294 ip.run_cell(cmd, store_history=True)
294 ip.run_cell(cmd, store_history=True)
295 assert ip.user_ns["test"].value == "a+=1\nprint(a)\n"
295 assert ip.user_ns["test"].value == "a+=1\nprint(a)\n"
296 with tt.AssertPrints("12"):
296 with tt.AssertPrints("12"):
297 ip.run_cell("test")
297 ip.run_cell("test")
298 with tt.AssertPrints("13"):
298 with tt.AssertPrints("13"):
299 ip.run_cell("test")
299 ip.run_cell("test")
300
300
301
301
302 def test_magic_magic():
302 def test_magic_magic():
303 """Test %magic"""
303 """Test %magic"""
304 ip = get_ipython()
304 ip = get_ipython()
305 with capture_output() as captured:
305 with capture_output() as captured:
306 ip.run_line_magic("magic", "")
306 ip.run_line_magic("magic", "")
307
307
308 stdout = captured.stdout
308 stdout = captured.stdout
309 assert "%magic" in stdout
309 assert "%magic" in stdout
310 assert "IPython" in stdout
310 assert "IPython" in stdout
311 assert "Available" in stdout
311 assert "Available" in stdout
312
312
313
313
314 @dec.skipif_not_numpy
314 @dec.skipif_not_numpy
315 def test_numpy_reset_array_undec():
315 def test_numpy_reset_array_undec():
316 "Test '%reset array' functionality"
316 "Test '%reset array' functionality"
317 _ip.ex("import numpy as np")
317 _ip.ex("import numpy as np")
318 _ip.ex("a = np.empty(2)")
318 _ip.ex("a = np.empty(2)")
319 assert "a" in _ip.user_ns
319 assert "a" in _ip.user_ns
320 _ip.run_line_magic("reset", "-f array")
320 _ip.run_line_magic("reset", "-f array")
321 assert "a" not in _ip.user_ns
321 assert "a" not in _ip.user_ns
322
322
323
323
324 def test_reset_out():
324 def test_reset_out():
325 "Test '%reset out' magic"
325 "Test '%reset out' magic"
326 _ip.run_cell("parrot = 'dead'", store_history=True)
326 _ip.run_cell("parrot = 'dead'", store_history=True)
327 # test '%reset -f out', make an Out prompt
327 # test '%reset -f out', make an Out prompt
328 _ip.run_cell("parrot", store_history=True)
328 _ip.run_cell("parrot", store_history=True)
329 assert "dead" in [_ip.user_ns[x] for x in ("_", "__", "___")]
329 assert "dead" in [_ip.user_ns[x] for x in ("_", "__", "___")]
330 _ip.run_line_magic("reset", "-f out")
330 _ip.run_line_magic("reset", "-f out")
331 assert "dead" not in [_ip.user_ns[x] for x in ("_", "__", "___")]
331 assert "dead" not in [_ip.user_ns[x] for x in ("_", "__", "___")]
332 assert len(_ip.user_ns["Out"]) == 0
332 assert len(_ip.user_ns["Out"]) == 0
333
333
334
334
335 def test_reset_in():
335 def test_reset_in():
336 "Test '%reset in' magic"
336 "Test '%reset in' magic"
337 # test '%reset -f in'
337 # test '%reset -f in'
338 _ip.run_cell("parrot", store_history=True)
338 _ip.run_cell("parrot", store_history=True)
339 assert "parrot" in [_ip.user_ns[x] for x in ("_i", "_ii", "_iii")]
339 assert "parrot" in [_ip.user_ns[x] for x in ("_i", "_ii", "_iii")]
340 _ip.run_line_magic("reset", "-f in")
340 _ip.run_line_magic("reset", "-f in")
341 assert "parrot" not in [_ip.user_ns[x] for x in ("_i", "_ii", "_iii")]
341 assert "parrot" not in [_ip.user_ns[x] for x in ("_i", "_ii", "_iii")]
342 assert len(set(_ip.user_ns["In"])) == 1
342 assert len(set(_ip.user_ns["In"])) == 1
343
343
344
344
345 def test_reset_dhist():
345 def test_reset_dhist():
346 "Test '%reset dhist' magic"
346 "Test '%reset dhist' magic"
347 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
347 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
348 _ip.run_line_magic("cd", os.path.dirname(pytest.__file__))
348 _ip.run_line_magic("cd", os.path.dirname(pytest.__file__))
349 _ip.run_line_magic("cd", "-")
349 _ip.run_line_magic("cd", "-")
350 assert len(_ip.user_ns["_dh"]) > 0
350 assert len(_ip.user_ns["_dh"]) > 0
351 _ip.run_line_magic("reset", "-f dhist")
351 _ip.run_line_magic("reset", "-f dhist")
352 assert len(_ip.user_ns["_dh"]) == 0
352 assert len(_ip.user_ns["_dh"]) == 0
353 _ip.run_cell("_dh = [d for d in tmp]") # restore
353 _ip.run_cell("_dh = [d for d in tmp]") # restore
354
354
355
355
356 def test_reset_in_length():
356 def test_reset_in_length():
357 "Test that '%reset in' preserves In[] length"
357 "Test that '%reset in' preserves In[] length"
358 _ip.run_cell("print 'foo'")
358 _ip.run_cell("print 'foo'")
359 _ip.run_cell("reset -f in")
359 _ip.run_cell("reset -f in")
360 assert len(_ip.user_ns["In"]) == _ip.displayhook.prompt_count + 1
360 assert len(_ip.user_ns["In"]) == _ip.displayhook.prompt_count + 1
361
361
362
362
363 class TestResetErrors(TestCase):
363 class TestResetErrors(TestCase):
364
364
365 def test_reset_redefine(self):
365 def test_reset_redefine(self):
366
366
367 @magics_class
367 @magics_class
368 class KernelMagics(Magics):
368 class KernelMagics(Magics):
369 @line_magic
369 @line_magic
370 def less(self, shell): pass
370 def less(self, shell): pass
371
371
372 _ip.register_magics(KernelMagics)
372 _ip.register_magics(KernelMagics)
373
373
374 with self.assertLogs() as cm:
374 with self.assertLogs() as cm:
375 # hack, we want to just capture logs, but assertLogs fails if not
375 # hack, we want to just capture logs, but assertLogs fails if not
376 # logs get produce.
376 # logs get produce.
377 # so log one things we ignore.
377 # so log one things we ignore.
378 import logging as log_mod
378 import logging as log_mod
379 log = log_mod.getLogger()
379 log = log_mod.getLogger()
380 log.info('Nothing')
380 log.info('Nothing')
381 # end hack.
381 # end hack.
382 _ip.run_cell("reset -f")
382 _ip.run_cell("reset -f")
383
383
384 assert len(cm.output) == 1
384 assert len(cm.output) == 1
385 for out in cm.output:
385 for out in cm.output:
386 assert "Invalid alias" not in out
386 assert "Invalid alias" not in out
387
387
388 def test_tb_syntaxerror():
388 def test_tb_syntaxerror():
389 """test %tb after a SyntaxError"""
389 """test %tb after a SyntaxError"""
390 ip = get_ipython()
390 ip = get_ipython()
391 ip.run_cell("for")
391 ip.run_cell("for")
392
392
393 # trap and validate stdout
393 # trap and validate stdout
394 save_stdout = sys.stdout
394 save_stdout = sys.stdout
395 try:
395 try:
396 sys.stdout = StringIO()
396 sys.stdout = StringIO()
397 ip.run_cell("%tb")
397 ip.run_cell("%tb")
398 out = sys.stdout.getvalue()
398 out = sys.stdout.getvalue()
399 finally:
399 finally:
400 sys.stdout = save_stdout
400 sys.stdout = save_stdout
401 # trim output, and only check the last line
401 # trim output, and only check the last line
402 last_line = out.rstrip().splitlines()[-1].strip()
402 last_line = out.rstrip().splitlines()[-1].strip()
403 assert last_line == "SyntaxError: invalid syntax"
403 assert last_line == "SyntaxError: invalid syntax"
404
404
405
405
406 def test_time():
406 def test_time():
407 ip = get_ipython()
407 ip = get_ipython()
408
408
409 with tt.AssertPrints("Wall time: "):
409 with tt.AssertPrints("Wall time: "):
410 ip.run_cell("%time None")
410 ip.run_cell("%time None")
411
411
412 ip.run_cell("def f(kmjy):\n"
412 ip.run_cell("def f(kmjy):\n"
413 " %time print (2*kmjy)")
413 " %time print (2*kmjy)")
414
414
415 with tt.AssertPrints("Wall time: "):
415 with tt.AssertPrints("Wall time: "):
416 with tt.AssertPrints("hihi", suppress=False):
416 with tt.AssertPrints("hihi", suppress=False):
417 ip.run_cell("f('hi')")
417 ip.run_cell("f('hi')")
418
418
419
419
420 # ';' at the end of %time prevents instruction value to be printed.
420 # ';' at the end of %time prevents instruction value to be printed.
421 # This tests fix for #13837.
421 # This tests fix for #13837.
422 def test_time_no_output_with_semicolon():
422 def test_time_no_output_with_semicolon():
423 ip = get_ipython()
423 ip = get_ipython()
424
424
425 # Test %time cases
425 # Test %time cases
426 with tt.AssertPrints(" 123456"):
426 with tt.AssertPrints(" 123456"):
427 with tt.AssertPrints("Wall time: ", suppress=False):
427 with tt.AssertPrints("Wall time: ", suppress=False):
428 with tt.AssertPrints("CPU times: ", suppress=False):
428 with tt.AssertPrints("CPU times: ", suppress=False):
429 ip.run_cell("%time 123000+456")
429 ip.run_cell("%time 123000+456")
430
430
431 with tt.AssertNotPrints(" 123456"):
431 with tt.AssertNotPrints(" 123456"):
432 with tt.AssertPrints("Wall time: ", suppress=False):
432 with tt.AssertPrints("Wall time: ", suppress=False):
433 with tt.AssertPrints("CPU times: ", suppress=False):
433 with tt.AssertPrints("CPU times: ", suppress=False):
434 ip.run_cell("%time 123000+456;")
434 ip.run_cell("%time 123000+456;")
435
435
436 with tt.AssertPrints(" 123456"):
436 with tt.AssertPrints(" 123456"):
437 with tt.AssertPrints("Wall time: ", suppress=False):
437 with tt.AssertPrints("Wall time: ", suppress=False):
438 with tt.AssertPrints("CPU times: ", suppress=False):
438 with tt.AssertPrints("CPU times: ", suppress=False):
439 ip.run_cell("%time 123000+456 # Comment")
439 ip.run_cell("%time 123000+456 # Comment")
440
440
441 with tt.AssertNotPrints(" 123456"):
441 with tt.AssertNotPrints(" 123456"):
442 with tt.AssertPrints("Wall time: ", suppress=False):
442 with tt.AssertPrints("Wall time: ", suppress=False):
443 with tt.AssertPrints("CPU times: ", suppress=False):
443 with tt.AssertPrints("CPU times: ", suppress=False):
444 ip.run_cell("%time 123000+456; # Comment")
444 ip.run_cell("%time 123000+456; # Comment")
445
445
446 with tt.AssertPrints(" 123456"):
446 with tt.AssertPrints(" 123456"):
447 with tt.AssertPrints("Wall time: ", suppress=False):
447 with tt.AssertPrints("Wall time: ", suppress=False):
448 with tt.AssertPrints("CPU times: ", suppress=False):
448 with tt.AssertPrints("CPU times: ", suppress=False):
449 ip.run_cell("%time 123000+456 # ;Comment")
449 ip.run_cell("%time 123000+456 # ;Comment")
450
450
451 # Test %%time cases
451 # Test %%time cases
452 with tt.AssertPrints("123456"):
452 with tt.AssertPrints("123456"):
453 with tt.AssertPrints("Wall time: ", suppress=False):
453 with tt.AssertPrints("Wall time: ", suppress=False):
454 with tt.AssertPrints("CPU times: ", suppress=False):
454 with tt.AssertPrints("CPU times: ", suppress=False):
455 ip.run_cell("%%time\n123000+456\n\n\n")
455 ip.run_cell("%%time\n123000+456\n\n\n")
456
456
457 with tt.AssertNotPrints("123456"):
457 with tt.AssertNotPrints("123456"):
458 with tt.AssertPrints("Wall time: ", suppress=False):
458 with tt.AssertPrints("Wall time: ", suppress=False):
459 with tt.AssertPrints("CPU times: ", suppress=False):
459 with tt.AssertPrints("CPU times: ", suppress=False):
460 ip.run_cell("%%time\n123000+456;\n\n\n")
460 ip.run_cell("%%time\n123000+456;\n\n\n")
461
461
462 with tt.AssertPrints("123456"):
462 with tt.AssertPrints("123456"):
463 with tt.AssertPrints("Wall time: ", suppress=False):
463 with tt.AssertPrints("Wall time: ", suppress=False):
464 with tt.AssertPrints("CPU times: ", suppress=False):
464 with tt.AssertPrints("CPU times: ", suppress=False):
465 ip.run_cell("%%time\n123000+456 # Comment\n\n\n")
465 ip.run_cell("%%time\n123000+456 # Comment\n\n\n")
466
466
467 with tt.AssertNotPrints("123456"):
467 with tt.AssertNotPrints("123456"):
468 with tt.AssertPrints("Wall time: ", suppress=False):
468 with tt.AssertPrints("Wall time: ", suppress=False):
469 with tt.AssertPrints("CPU times: ", suppress=False):
469 with tt.AssertPrints("CPU times: ", suppress=False):
470 ip.run_cell("%%time\n123000+456; # Comment\n\n\n")
470 ip.run_cell("%%time\n123000+456; # Comment\n\n\n")
471
471
472 with tt.AssertPrints("123456"):
472 with tt.AssertPrints("123456"):
473 with tt.AssertPrints("Wall time: ", suppress=False):
473 with tt.AssertPrints("Wall time: ", suppress=False):
474 with tt.AssertPrints("CPU times: ", suppress=False):
474 with tt.AssertPrints("CPU times: ", suppress=False):
475 ip.run_cell("%%time\n123000+456 # ;Comment\n\n\n")
475 ip.run_cell("%%time\n123000+456 # ;Comment\n\n\n")
476
476
477
477
478 def test_time_last_not_expression():
478 def test_time_last_not_expression():
479 ip.run_cell("%%time\n"
479 ip.run_cell("%%time\n"
480 "var_1 = 1\n"
480 "var_1 = 1\n"
481 "var_2 = 2\n")
481 "var_2 = 2\n")
482 assert ip.user_ns['var_1'] == 1
482 assert ip.user_ns['var_1'] == 1
483 del ip.user_ns['var_1']
483 del ip.user_ns['var_1']
484 assert ip.user_ns['var_2'] == 2
484 assert ip.user_ns['var_2'] == 2
485 del ip.user_ns['var_2']
485 del ip.user_ns['var_2']
486
486
487
487
488 @dec.skip_win32
488 @dec.skip_win32
489 def test_time2():
489 def test_time2():
490 ip = get_ipython()
490 ip = get_ipython()
491
491
492 with tt.AssertPrints("CPU times: user "):
492 with tt.AssertPrints("CPU times: user "):
493 ip.run_cell("%time None")
493 ip.run_cell("%time None")
494
494
495 def test_time3():
495 def test_time3():
496 """Erroneous magic function calls, issue gh-3334"""
496 """Erroneous magic function calls, issue gh-3334"""
497 ip = get_ipython()
497 ip = get_ipython()
498 ip.user_ns.pop('run', None)
498 ip.user_ns.pop('run', None)
499
499
500 with tt.AssertNotPrints("not found", channel='stderr'):
500 with tt.AssertNotPrints("not found", channel='stderr'):
501 ip.run_cell("%%time\n"
501 ip.run_cell("%%time\n"
502 "run = 0\n"
502 "run = 0\n"
503 "run += 1")
503 "run += 1")
504
504
505 def test_multiline_time():
505 def test_multiline_time():
506 """Make sure last statement from time return a value."""
506 """Make sure last statement from time return a value."""
507 ip = get_ipython()
507 ip = get_ipython()
508 ip.user_ns.pop('run', None)
508 ip.user_ns.pop('run', None)
509
509
510 ip.run_cell(
510 ip.run_cell(
511 dedent(
511 dedent(
512 """\
512 """\
513 %%time
513 %%time
514 a = "ho"
514 a = "ho"
515 b = "hey"
515 b = "hey"
516 a+b
516 a+b
517 """
517 """
518 )
518 )
519 )
519 )
520 assert ip.user_ns_hidden["_"] == "hohey"
520 assert ip.user_ns_hidden["_"] == "hohey"
521
521
522
522
523 def test_time_local_ns():
523 def test_time_local_ns():
524 """
524 """
525 Test that local_ns is actually global_ns when running a cell magic
525 Test that local_ns is actually global_ns when running a cell magic
526 """
526 """
527 ip = get_ipython()
527 ip = get_ipython()
528 ip.run_cell("%%time\n" "myvar = 1")
528 ip.run_cell("%%time\n" "myvar = 1")
529 assert ip.user_ns["myvar"] == 1
529 assert ip.user_ns["myvar"] == 1
530 del ip.user_ns["myvar"]
530 del ip.user_ns["myvar"]
531
531
532
532
533 def test_time_microseconds_display():
533 def test_time_microseconds_display():
534 """Ensure ASCII is used when necessary"""
534 """Ensure ASCII is used when necessary"""
535 with mock.patch("sys.stdout", io.TextIOWrapper(StringIO(), encoding="utf-8")):
535 with mock.patch("sys.stdout", io.TextIOWrapper(StringIO(), encoding="utf-8")):
536 assert execution._format_time(0.000001) == "1 \u03bcs"
536 assert execution._format_time(0.000001) == "1 \u03bcs"
537 with mock.patch("sys.stdout", io.TextIOWrapper(StringIO(), encoding="ascii")):
537 with mock.patch("sys.stdout", io.TextIOWrapper(StringIO(), encoding="ascii")):
538 assert execution._format_time(0.000001) == "1 us"
538 assert execution._format_time(0.000001) == "1 us"
539
539
540
540
541 # Test %%capture magic. Added to test issue #13926
541 # Test %%capture magic. Added to test issue #13926
542 def test_capture():
542 def test_capture():
543 ip = get_ipython()
543 ip = get_ipython()
544
544
545 # Test %%capture nominal case
545 # Test %%capture nominal case
546 ip.run_cell("%%capture abc\n1+2")
546 ip.run_cell("%%capture abc\n1+2")
547 with tt.AssertPrints("True", suppress=False):
547 with tt.AssertPrints("True", suppress=False):
548 ip.run_cell("'abc' in locals()")
548 ip.run_cell("'abc' in locals()")
549 with tt.AssertPrints("True", suppress=False):
549 with tt.AssertPrints("True", suppress=False):
550 ip.run_cell("'outputs' in dir(abc)")
550 ip.run_cell("'outputs' in dir(abc)")
551 with tt.AssertPrints("3", suppress=False):
551 with tt.AssertPrints("3", suppress=False):
552 ip.run_cell("abc.outputs[0]")
552 ip.run_cell("abc.outputs[0]")
553
553
554 # Test %%capture with ';' at end of expression
554 # Test %%capture with ';' at end of expression
555 ip.run_cell("%%capture abc\n7+8;")
555 ip.run_cell("%%capture abc\n7+8;")
556 with tt.AssertPrints("False", suppress=False):
556 with tt.AssertPrints("False", suppress=False):
557 ip.run_cell("'abc' in locals()")
557 ip.run_cell("'abc' in locals()")
558
558
559
559
560 def test_doctest_mode():
560 def test_doctest_mode():
561 "Toggle doctest_mode twice, it should be a no-op and run without error"
561 "Toggle doctest_mode twice, it should be a no-op and run without error"
562 _ip.run_line_magic("doctest_mode", "")
562 _ip.run_line_magic("doctest_mode", "")
563 _ip.run_line_magic("doctest_mode", "")
563 _ip.run_line_magic("doctest_mode", "")
564
564
565
565
566 def test_parse_options():
566 def test_parse_options():
567 """Tests for basic options parsing in magics."""
567 """Tests for basic options parsing in magics."""
568 # These are only the most minimal of tests, more should be added later. At
568 # These are only the most minimal of tests, more should be added later. At
569 # the very least we check that basic text/unicode calls work OK.
569 # the very least we check that basic text/unicode calls work OK.
570 m = DummyMagics(_ip)
570 m = DummyMagics(_ip)
571 assert m.parse_options("foo", "")[1] == "foo"
571 assert m.parse_options("foo", "")[1] == "foo"
572 assert m.parse_options("foo", "")[1] == "foo"
572 assert m.parse_options("foo", "")[1] == "foo"
573
573
574
574
575 def test_parse_options_preserve_non_option_string():
575 def test_parse_options_preserve_non_option_string():
576 """Test to assert preservation of non-option part of magic-block, while parsing magic options."""
576 """Test to assert preservation of non-option part of magic-block, while parsing magic options."""
577 m = DummyMagics(_ip)
577 m = DummyMagics(_ip)
578 opts, stmt = m.parse_options(
578 opts, stmt = m.parse_options(
579 " -n1 -r 13 _ = 314 + foo", "n:r:", preserve_non_opts=True
579 " -n1 -r 13 _ = 314 + foo", "n:r:", preserve_non_opts=True
580 )
580 )
581 assert opts == {"n": "1", "r": "13"}
581 assert opts == {"n": "1", "r": "13"}
582 assert stmt == "_ = 314 + foo"
582 assert stmt == "_ = 314 + foo"
583
583
584
584
585 def test_run_magic_preserve_code_block():
585 def test_run_magic_preserve_code_block():
586 """Test to assert preservation of non-option part of magic-block, while running magic."""
586 """Test to assert preservation of non-option part of magic-block, while running magic."""
587 _ip.user_ns["spaces"] = []
587 _ip.user_ns["spaces"] = []
588 _ip.run_line_magic(
588 _ip.run_line_magic(
589 "timeit", "-n1 -r1 spaces.append([s.count(' ') for s in ['document']])"
589 "timeit", "-n1 -r1 spaces.append([s.count(' ') for s in ['document']])"
590 )
590 )
591 assert _ip.user_ns["spaces"] == [[0]]
591 assert _ip.user_ns["spaces"] == [[0]]
592
592
593
593
594 def test_dirops():
594 def test_dirops():
595 """Test various directory handling operations."""
595 """Test various directory handling operations."""
596 # curpath = lambda :os.path.splitdrive(os.getcwd())[1].replace('\\','/')
596 # curpath = lambda :os.path.splitdrive(os.getcwd())[1].replace('\\','/')
597 curpath = os.getcwd
597 curpath = os.getcwd
598 startdir = os.getcwd()
598 startdir = os.getcwd()
599 ipdir = os.path.realpath(_ip.ipython_dir)
599 ipdir = os.path.realpath(_ip.ipython_dir)
600 try:
600 try:
601 _ip.run_line_magic("cd", '"%s"' % ipdir)
601 _ip.run_line_magic("cd", '"%s"' % ipdir)
602 assert curpath() == ipdir
602 assert curpath() == ipdir
603 _ip.run_line_magic("cd", "-")
603 _ip.run_line_magic("cd", "-")
604 assert curpath() == startdir
604 assert curpath() == startdir
605 _ip.run_line_magic("pushd", '"%s"' % ipdir)
605 _ip.run_line_magic("pushd", '"%s"' % ipdir)
606 assert curpath() == ipdir
606 assert curpath() == ipdir
607 _ip.run_line_magic("popd", "")
607 _ip.run_line_magic("popd", "")
608 assert curpath() == startdir
608 assert curpath() == startdir
609 finally:
609 finally:
610 os.chdir(startdir)
610 os.chdir(startdir)
611
611
612
612
613 def test_cd_force_quiet():
613 def test_cd_force_quiet():
614 """Test OSMagics.cd_force_quiet option"""
614 """Test OSMagics.cd_force_quiet option"""
615 _ip.config.OSMagics.cd_force_quiet = True
615 _ip.config.OSMagics.cd_force_quiet = True
616 osmagics = osm.OSMagics(shell=_ip)
616 osmagics = osm.OSMagics(shell=_ip)
617
617
618 startdir = os.getcwd()
618 startdir = os.getcwd()
619 ipdir = os.path.realpath(_ip.ipython_dir)
619 ipdir = os.path.realpath(_ip.ipython_dir)
620
620
621 try:
621 try:
622 with tt.AssertNotPrints(ipdir):
622 with tt.AssertNotPrints(ipdir):
623 osmagics.cd('"%s"' % ipdir)
623 osmagics.cd('"%s"' % ipdir)
624 with tt.AssertNotPrints(startdir):
624 with tt.AssertNotPrints(startdir):
625 osmagics.cd('-')
625 osmagics.cd('-')
626 finally:
626 finally:
627 os.chdir(startdir)
627 os.chdir(startdir)
628
628
629
629
630 def test_xmode():
630 def test_xmode():
631 # Calling xmode three times should be a no-op
631 # Calling xmode three times should be a no-op
632 xmode = _ip.InteractiveTB.mode
632 xmode = _ip.InteractiveTB.mode
633 for i in range(4):
633 for i in range(4):
634 _ip.run_line_magic("xmode", "")
634 _ip.run_line_magic("xmode", "")
635 assert _ip.InteractiveTB.mode == xmode
635 assert _ip.InteractiveTB.mode == xmode
636
636
637 def test_reset_hard():
637 def test_reset_hard():
638 monitor = []
638 monitor = []
639 class A(object):
639 class A(object):
640 def __del__(self):
640 def __del__(self):
641 monitor.append(1)
641 monitor.append(1)
642 def __repr__(self):
642 def __repr__(self):
643 return "<A instance>"
643 return "<A instance>"
644
644
645 _ip.user_ns["a"] = A()
645 _ip.user_ns["a"] = A()
646 _ip.run_cell("a")
646 _ip.run_cell("a")
647
647
648 assert monitor == []
648 assert monitor == []
649 _ip.run_line_magic("reset", "-f")
649 _ip.run_line_magic("reset", "-f")
650 assert monitor == [1]
650 assert monitor == [1]
651
651
652 class TestXdel(tt.TempFileMixin):
652 class TestXdel(tt.TempFileMixin):
653 def test_xdel(self):
653 def test_xdel(self):
654 """Test that references from %run are cleared by xdel."""
654 """Test that references from %run are cleared by xdel."""
655 src = ("class A(object):\n"
655 src = ("class A(object):\n"
656 " monitor = []\n"
656 " monitor = []\n"
657 " def __del__(self):\n"
657 " def __del__(self):\n"
658 " self.monitor.append(1)\n"
658 " self.monitor.append(1)\n"
659 "a = A()\n")
659 "a = A()\n")
660 self.mktmp(src)
660 self.mktmp(src)
661 # %run creates some hidden references...
661 # %run creates some hidden references...
662 _ip.run_line_magic("run", "%s" % self.fname)
662 _ip.run_line_magic("run", "%s" % self.fname)
663 # ... as does the displayhook.
663 # ... as does the displayhook.
664 _ip.run_cell("a")
664 _ip.run_cell("a")
665
665
666 monitor = _ip.user_ns["A"].monitor
666 monitor = _ip.user_ns["A"].monitor
667 assert monitor == []
667 assert monitor == []
668
668
669 _ip.run_line_magic("xdel", "a")
669 _ip.run_line_magic("xdel", "a")
670
670
671 # Check that a's __del__ method has been called.
671 # Check that a's __del__ method has been called.
672 gc.collect(0)
672 gc.collect(0)
673 assert monitor == [1]
673 assert monitor == [1]
674
674
675 def doctest_who():
675 def doctest_who():
676 """doctest for %who
676 """doctest for %who
677
677
678 In [1]: %reset -sf
678 In [1]: %reset -sf
679
679
680 In [2]: alpha = 123
680 In [2]: alpha = 123
681
681
682 In [3]: beta = 'beta'
682 In [3]: beta = 'beta'
683
683
684 In [4]: %who int
684 In [4]: %who int
685 alpha
685 alpha
686
686
687 In [5]: %who str
687 In [5]: %who str
688 beta
688 beta
689
689
690 In [6]: %whos
690 In [6]: %whos
691 Variable Type Data/Info
691 Variable Type Data/Info
692 ----------------------------
692 ----------------------------
693 alpha int 123
693 alpha int 123
694 beta str beta
694 beta str beta
695
695
696 In [7]: %who_ls
696 In [7]: %who_ls
697 Out[7]: ['alpha', 'beta']
697 Out[7]: ['alpha', 'beta']
698 """
698 """
699
699
700 def test_whos():
700 def test_whos():
701 """Check that whos is protected against objects where repr() fails."""
701 """Check that whos is protected against objects where repr() fails."""
702 class A(object):
702 class A(object):
703 def __repr__(self):
703 def __repr__(self):
704 raise Exception()
704 raise Exception()
705 _ip.user_ns['a'] = A()
705 _ip.user_ns['a'] = A()
706 _ip.run_line_magic("whos", "")
706 _ip.run_line_magic("whos", "")
707
707
708 def doctest_precision():
708 def doctest_precision():
709 """doctest for %precision
709 """doctest for %precision
710
710
711 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
711 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
712
712
713 In [2]: %precision 5
713 In [2]: %precision 5
714 Out[2]: '%.5f'
714 Out[2]: '%.5f'
715
715
716 In [3]: f.float_format
716 In [3]: f.float_format
717 Out[3]: '%.5f'
717 Out[3]: '%.5f'
718
718
719 In [4]: %precision %e
719 In [4]: %precision %e
720 Out[4]: '%e'
720 Out[4]: '%e'
721
721
722 In [5]: f(3.1415927)
722 In [5]: f(3.1415927)
723 Out[5]: '3.141593e+00'
723 Out[5]: '3.141593e+00'
724 """
724 """
725
725
726
726
727 def test_debug_magic():
727 def test_debug_magic():
728 """Test debugging a small code with %debug
728 """Test debugging a small code with %debug
729
729
730 In [1]: with PdbTestInput(['c']):
730 In [1]: with PdbTestInput(['c']):
731 ...: %debug print("a b") #doctest: +ELLIPSIS
731 ...: %debug print("a b") #doctest: +ELLIPSIS
732 ...:
732 ...:
733 ...
733 ...
734 ipdb> c
734 ipdb> c
735 a b
735 a b
736 In [2]:
736 In [2]:
737 """
737 """
738
738
739
739
740 def test_debug_magic_locals():
740 def test_debug_magic_locals():
741 """Test debugging a small code with %debug with locals
741 """Test debugging a small code with %debug with locals
742
742
743 In [1]: with PdbTestInput(['c']):
743 In [1]: with PdbTestInput(['c']):
744 ...: def fun():
744 ...: def fun():
745 ...: res = 1
745 ...: res = 1
746 ...: %debug print(res)
746 ...: %debug print(res)
747 ...: fun()
747 ...: fun()
748 ...:
748 ...:
749 ...
749 ...
750 ipdb> c
750 ipdb> c
751 1
751 1
752 In [2]:
752 In [2]:
753 """
753 """
754
754
755 def test_psearch():
755 def test_psearch():
756 with tt.AssertPrints("dict.fromkeys"):
756 with tt.AssertPrints("dict.fromkeys"):
757 _ip.run_cell("dict.fr*?")
757 _ip.run_cell("dict.fr*?")
758 with tt.AssertPrints("Ο€.is_integer"):
758 with tt.AssertPrints("Ο€.is_integer"):
759 _ip.run_cell("Ο€ = 3.14;\nΟ€.is_integ*?")
759 _ip.run_cell("Ο€ = 3.14;\nΟ€.is_integ*?")
760
760
761 def test_timeit_shlex():
761 def test_timeit_shlex():
762 """test shlex issues with timeit (#1109)"""
762 """test shlex issues with timeit (#1109)"""
763 _ip.ex("def f(*a,**kw): pass")
763 _ip.ex("def f(*a,**kw): pass")
764 _ip.run_line_magic("timeit", '-n1 "this is a bug".count(" ")')
764 _ip.run_line_magic("timeit", '-n1 "this is a bug".count(" ")')
765 _ip.run_line_magic("timeit", '-r1 -n1 f(" ", 1)')
765 _ip.run_line_magic("timeit", '-r1 -n1 f(" ", 1)')
766 _ip.run_line_magic("timeit", '-r1 -n1 f(" ", 1, " ", 2, " ")')
766 _ip.run_line_magic("timeit", '-r1 -n1 f(" ", 1, " ", 2, " ")')
767 _ip.run_line_magic("timeit", '-r1 -n1 ("a " + "b")')
767 _ip.run_line_magic("timeit", '-r1 -n1 ("a " + "b")')
768 _ip.run_line_magic("timeit", '-r1 -n1 f("a " + "b")')
768 _ip.run_line_magic("timeit", '-r1 -n1 f("a " + "b")')
769 _ip.run_line_magic("timeit", '-r1 -n1 f("a " + "b ")')
769 _ip.run_line_magic("timeit", '-r1 -n1 f("a " + "b ")')
770
770
771
771
772 def test_timeit_special_syntax():
772 def test_timeit_special_syntax():
773 "Test %%timeit with IPython special syntax"
773 "Test %%timeit with IPython special syntax"
774 @register_line_magic
774 @register_line_magic
775 def lmagic(line):
775 def lmagic(line):
776 ip = get_ipython()
776 ip = get_ipython()
777 ip.user_ns['lmagic_out'] = line
777 ip.user_ns['lmagic_out'] = line
778
778
779 # line mode test
779 # line mode test
780 _ip.run_line_magic("timeit", "-n1 -r1 %lmagic my line")
780 _ip.run_line_magic("timeit", "-n1 -r1 %lmagic my line")
781 assert _ip.user_ns["lmagic_out"] == "my line"
781 assert _ip.user_ns["lmagic_out"] == "my line"
782 # cell mode test
782 # cell mode test
783 _ip.run_cell_magic("timeit", "-n1 -r1", "%lmagic my line2")
783 _ip.run_cell_magic("timeit", "-n1 -r1", "%lmagic my line2")
784 assert _ip.user_ns["lmagic_out"] == "my line2"
784 assert _ip.user_ns["lmagic_out"] == "my line2"
785
785
786
786
787 def test_timeit_return():
787 def test_timeit_return():
788 """
788 """
789 test whether timeit -o return object
789 test whether timeit -o return object
790 """
790 """
791
791
792 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
792 res = _ip.run_line_magic('timeit','-n10 -r10 -o 1')
793 assert(res is not None)
793 assert(res is not None)
794
794
795 def test_timeit_quiet():
795 def test_timeit_quiet():
796 """
796 """
797 test quiet option of timeit magic
797 test quiet option of timeit magic
798 """
798 """
799 with tt.AssertNotPrints("loops"):
799 with tt.AssertNotPrints("loops"):
800 _ip.run_cell("%timeit -n1 -r1 -q 1")
800 _ip.run_cell("%timeit -n1 -r1 -q 1")
801
801
802 def test_timeit_return_quiet():
802 def test_timeit_return_quiet():
803 with tt.AssertNotPrints("loops"):
803 with tt.AssertNotPrints("loops"):
804 res = _ip.run_line_magic('timeit', '-n1 -r1 -q -o 1')
804 res = _ip.run_line_magic('timeit', '-n1 -r1 -q -o 1')
805 assert (res is not None)
805 assert (res is not None)
806
806
807 def test_timeit_invalid_return():
807 def test_timeit_invalid_return():
808 with pytest.raises(SyntaxError):
808 with pytest.raises(SyntaxError):
809 _ip.run_line_magic('timeit', 'return')
809 _ip.run_line_magic('timeit', 'return')
810
810
811 @dec.skipif(execution.profile is None)
811 @dec.skipif(execution.profile is None)
812 def test_prun_special_syntax():
812 def test_prun_special_syntax():
813 "Test %%prun with IPython special syntax"
813 "Test %%prun with IPython special syntax"
814 @register_line_magic
814 @register_line_magic
815 def lmagic(line):
815 def lmagic(line):
816 ip = get_ipython()
816 ip = get_ipython()
817 ip.user_ns['lmagic_out'] = line
817 ip.user_ns['lmagic_out'] = line
818
818
819 # line mode test
819 # line mode test
820 _ip.run_line_magic("prun", "-q %lmagic my line")
820 _ip.run_line_magic("prun", "-q %lmagic my line")
821 assert _ip.user_ns["lmagic_out"] == "my line"
821 assert _ip.user_ns["lmagic_out"] == "my line"
822 # cell mode test
822 # cell mode test
823 _ip.run_cell_magic("prun", "-q", "%lmagic my line2")
823 _ip.run_cell_magic("prun", "-q", "%lmagic my line2")
824 assert _ip.user_ns["lmagic_out"] == "my line2"
824 assert _ip.user_ns["lmagic_out"] == "my line2"
825
825
826
826
827 @dec.skipif(execution.profile is None)
827 @dec.skipif(execution.profile is None)
828 def test_prun_quotes():
828 def test_prun_quotes():
829 "Test that prun does not clobber string escapes (GH #1302)"
829 "Test that prun does not clobber string escapes (GH #1302)"
830 _ip.magic(r"prun -q x = '\t'")
830 _ip.run_line_magic("prun", r"-q x = '\t'")
831 assert _ip.user_ns["x"] == "\t"
831 assert _ip.user_ns["x"] == "\t"
832
832
833
833
834 def test_extension():
834 def test_extension():
835 # Debugging information for failures of this test
835 # Debugging information for failures of this test
836 print('sys.path:')
836 print('sys.path:')
837 for p in sys.path:
837 for p in sys.path:
838 print(' ', p)
838 print(' ', p)
839 print('CWD', os.getcwd())
839 print('CWD', os.getcwd())
840
840
841 pytest.raises(ImportError, _ip.magic, "load_ext daft_extension")
841 pytest.raises(ImportError, _ip.run_line_magic, "load_ext", "daft_extension")
842 daft_path = os.path.join(os.path.dirname(__file__), "daft_extension")
842 daft_path = os.path.join(os.path.dirname(__file__), "daft_extension")
843 sys.path.insert(0, daft_path)
843 sys.path.insert(0, daft_path)
844 try:
844 try:
845 _ip.user_ns.pop('arq', None)
845 _ip.user_ns.pop('arq', None)
846 invalidate_caches() # Clear import caches
846 invalidate_caches() # Clear import caches
847 _ip.run_line_magic("load_ext", "daft_extension")
847 _ip.run_line_magic("load_ext", "daft_extension")
848 assert _ip.user_ns["arq"] == 185
848 assert _ip.user_ns["arq"] == 185
849 _ip.run_line_magic("unload_ext", "daft_extension")
849 _ip.run_line_magic("unload_ext", "daft_extension")
850 assert 'arq' not in _ip.user_ns
850 assert 'arq' not in _ip.user_ns
851 finally:
851 finally:
852 sys.path.remove(daft_path)
852 sys.path.remove(daft_path)
853
853
854
854
855 def test_notebook_export_json():
855 def test_notebook_export_json():
856 pytest.importorskip("nbformat")
856 pytest.importorskip("nbformat")
857 _ip = get_ipython()
857 _ip = get_ipython()
858 _ip.history_manager.reset() # Clear any existing history.
858 _ip.history_manager.reset() # Clear any existing history.
859 cmds = ["a=1", "def b():\n return a**2", "print('noΓ«l, Γ©tΓ©', b())"]
859 cmds = ["a=1", "def b():\n return a**2", "print('noΓ«l, Γ©tΓ©', b())"]
860 for i, cmd in enumerate(cmds, start=1):
860 for i, cmd in enumerate(cmds, start=1):
861 _ip.history_manager.store_inputs(i, cmd)
861 _ip.history_manager.store_inputs(i, cmd)
862 with TemporaryDirectory() as td:
862 with TemporaryDirectory() as td:
863 outfile = os.path.join(td, "nb.ipynb")
863 outfile = os.path.join(td, "nb.ipynb")
864 _ip.run_line_magic("notebook", "%s" % outfile)
864 _ip.run_line_magic("notebook", "%s" % outfile)
865
865
866
866
867 class TestEnv(TestCase):
867 class TestEnv(TestCase):
868
868
869 def test_env(self):
869 def test_env(self):
870 env = _ip.run_line_magic("env", "")
870 env = _ip.run_line_magic("env", "")
871 self.assertTrue(isinstance(env, dict))
871 self.assertTrue(isinstance(env, dict))
872
872
873 def test_env_secret(self):
873 def test_env_secret(self):
874 env = _ip.run_line_magic("env", "")
874 env = _ip.run_line_magic("env", "")
875 hidden = "<hidden>"
875 hidden = "<hidden>"
876 with mock.patch.dict(
876 with mock.patch.dict(
877 os.environ,
877 os.environ,
878 {
878 {
879 "API_KEY": "abc123",
879 "API_KEY": "abc123",
880 "SECRET_THING": "ssshhh",
880 "SECRET_THING": "ssshhh",
881 "JUPYTER_TOKEN": "",
881 "JUPYTER_TOKEN": "",
882 "VAR": "abc"
882 "VAR": "abc"
883 }
883 }
884 ):
884 ):
885 env = _ip.run_line_magic("env", "")
885 env = _ip.run_line_magic("env", "")
886 assert env["API_KEY"] == hidden
886 assert env["API_KEY"] == hidden
887 assert env["SECRET_THING"] == hidden
887 assert env["SECRET_THING"] == hidden
888 assert env["JUPYTER_TOKEN"] == hidden
888 assert env["JUPYTER_TOKEN"] == hidden
889 assert env["VAR"] == "abc"
889 assert env["VAR"] == "abc"
890
890
891 def test_env_get_set_simple(self):
891 def test_env_get_set_simple(self):
892 env = _ip.run_line_magic("env", "var val1")
892 env = _ip.run_line_magic("env", "var val1")
893 self.assertEqual(env, None)
893 self.assertEqual(env, None)
894 self.assertEqual(os.environ["var"], "val1")
894 self.assertEqual(os.environ["var"], "val1")
895 self.assertEqual(_ip.run_line_magic("env", "var"), "val1")
895 self.assertEqual(_ip.run_line_magic("env", "var"), "val1")
896 env = _ip.run_line_magic("env", "var=val2")
896 env = _ip.run_line_magic("env", "var=val2")
897 self.assertEqual(env, None)
897 self.assertEqual(env, None)
898 self.assertEqual(os.environ['var'], 'val2')
898 self.assertEqual(os.environ['var'], 'val2')
899
899
900 def test_env_get_set_complex(self):
900 def test_env_get_set_complex(self):
901 env = _ip.run_line_magic("env", "var 'val1 '' 'val2")
901 env = _ip.run_line_magic("env", "var 'val1 '' 'val2")
902 self.assertEqual(env, None)
902 self.assertEqual(env, None)
903 self.assertEqual(os.environ['var'], "'val1 '' 'val2")
903 self.assertEqual(os.environ['var'], "'val1 '' 'val2")
904 self.assertEqual(_ip.run_line_magic("env", "var"), "'val1 '' 'val2")
904 self.assertEqual(_ip.run_line_magic("env", "var"), "'val1 '' 'val2")
905 env = _ip.run_line_magic("env", 'var=val2 val3="val4')
905 env = _ip.run_line_magic("env", 'var=val2 val3="val4')
906 self.assertEqual(env, None)
906 self.assertEqual(env, None)
907 self.assertEqual(os.environ['var'], 'val2 val3="val4')
907 self.assertEqual(os.environ['var'], 'val2 val3="val4')
908
908
909 def test_env_set_bad_input(self):
909 def test_env_set_bad_input(self):
910 self.assertRaises(UsageError, lambda: _ip.run_line_magic("set_env", "var"))
910 self.assertRaises(UsageError, lambda: _ip.run_line_magic("set_env", "var"))
911
911
912 def test_env_set_whitespace(self):
912 def test_env_set_whitespace(self):
913 self.assertRaises(UsageError, lambda: _ip.run_line_magic("env", "var A=B"))
913 self.assertRaises(UsageError, lambda: _ip.run_line_magic("env", "var A=B"))
914
914
915
915
916 class CellMagicTestCase(TestCase):
916 class CellMagicTestCase(TestCase):
917
917
918 def check_ident(self, magic):
918 def check_ident(self, magic):
919 # Manually called, we get the result
919 # Manually called, we get the result
920 out = _ip.run_cell_magic(magic, "a", "b")
920 out = _ip.run_cell_magic(magic, "a", "b")
921 assert out == ("a", "b")
921 assert out == ("a", "b")
922 # Via run_cell, it goes into the user's namespace via displayhook
922 # Via run_cell, it goes into the user's namespace via displayhook
923 _ip.run_cell("%%" + magic + " c\nd\n")
923 _ip.run_cell("%%" + magic + " c\nd\n")
924 assert _ip.user_ns["_"] == ("c", "d\n")
924 assert _ip.user_ns["_"] == ("c", "d\n")
925
925
926 def test_cell_magic_func_deco(self):
926 def test_cell_magic_func_deco(self):
927 "Cell magic using simple decorator"
927 "Cell magic using simple decorator"
928 @register_cell_magic
928 @register_cell_magic
929 def cellm(line, cell):
929 def cellm(line, cell):
930 return line, cell
930 return line, cell
931
931
932 self.check_ident('cellm')
932 self.check_ident('cellm')
933
933
934 def test_cell_magic_reg(self):
934 def test_cell_magic_reg(self):
935 "Cell magic manually registered"
935 "Cell magic manually registered"
936 def cellm(line, cell):
936 def cellm(line, cell):
937 return line, cell
937 return line, cell
938
938
939 _ip.register_magic_function(cellm, 'cell', 'cellm2')
939 _ip.register_magic_function(cellm, 'cell', 'cellm2')
940 self.check_ident('cellm2')
940 self.check_ident('cellm2')
941
941
942 def test_cell_magic_class(self):
942 def test_cell_magic_class(self):
943 "Cell magics declared via a class"
943 "Cell magics declared via a class"
944 @magics_class
944 @magics_class
945 class MyMagics(Magics):
945 class MyMagics(Magics):
946
946
947 @cell_magic
947 @cell_magic
948 def cellm3(self, line, cell):
948 def cellm3(self, line, cell):
949 return line, cell
949 return line, cell
950
950
951 _ip.register_magics(MyMagics)
951 _ip.register_magics(MyMagics)
952 self.check_ident('cellm3')
952 self.check_ident('cellm3')
953
953
954 def test_cell_magic_class2(self):
954 def test_cell_magic_class2(self):
955 "Cell magics declared via a class, #2"
955 "Cell magics declared via a class, #2"
956 @magics_class
956 @magics_class
957 class MyMagics2(Magics):
957 class MyMagics2(Magics):
958
958
959 @cell_magic('cellm4')
959 @cell_magic('cellm4')
960 def cellm33(self, line, cell):
960 def cellm33(self, line, cell):
961 return line, cell
961 return line, cell
962
962
963 _ip.register_magics(MyMagics2)
963 _ip.register_magics(MyMagics2)
964 self.check_ident('cellm4')
964 self.check_ident('cellm4')
965 # Check that nothing is registered as 'cellm33'
965 # Check that nothing is registered as 'cellm33'
966 c33 = _ip.find_cell_magic('cellm33')
966 c33 = _ip.find_cell_magic('cellm33')
967 assert c33 == None
967 assert c33 == None
968
968
969 def test_file():
969 def test_file():
970 """Basic %%writefile"""
970 """Basic %%writefile"""
971 ip = get_ipython()
971 ip = get_ipython()
972 with TemporaryDirectory() as td:
972 with TemporaryDirectory() as td:
973 fname = os.path.join(td, "file1")
973 fname = os.path.join(td, "file1")
974 ip.run_cell_magic(
974 ip.run_cell_magic(
975 "writefile",
975 "writefile",
976 fname,
976 fname,
977 "\n".join(
977 "\n".join(
978 [
978 [
979 "line1",
979 "line1",
980 "line2",
980 "line2",
981 ]
981 ]
982 ),
982 ),
983 )
983 )
984 s = Path(fname).read_text(encoding="utf-8")
984 s = Path(fname).read_text(encoding="utf-8")
985 assert "line1\n" in s
985 assert "line1\n" in s
986 assert "line2" in s
986 assert "line2" in s
987
987
988
988
989 @dec.skip_win32
989 @dec.skip_win32
990 def test_file_single_quote():
990 def test_file_single_quote():
991 """Basic %%writefile with embedded single quotes"""
991 """Basic %%writefile with embedded single quotes"""
992 ip = get_ipython()
992 ip = get_ipython()
993 with TemporaryDirectory() as td:
993 with TemporaryDirectory() as td:
994 fname = os.path.join(td, "'file1'")
994 fname = os.path.join(td, "'file1'")
995 ip.run_cell_magic(
995 ip.run_cell_magic(
996 "writefile",
996 "writefile",
997 fname,
997 fname,
998 "\n".join(
998 "\n".join(
999 [
999 [
1000 "line1",
1000 "line1",
1001 "line2",
1001 "line2",
1002 ]
1002 ]
1003 ),
1003 ),
1004 )
1004 )
1005 s = Path(fname).read_text(encoding="utf-8")
1005 s = Path(fname).read_text(encoding="utf-8")
1006 assert "line1\n" in s
1006 assert "line1\n" in s
1007 assert "line2" in s
1007 assert "line2" in s
1008
1008
1009
1009
1010 @dec.skip_win32
1010 @dec.skip_win32
1011 def test_file_double_quote():
1011 def test_file_double_quote():
1012 """Basic %%writefile with embedded double quotes"""
1012 """Basic %%writefile with embedded double quotes"""
1013 ip = get_ipython()
1013 ip = get_ipython()
1014 with TemporaryDirectory() as td:
1014 with TemporaryDirectory() as td:
1015 fname = os.path.join(td, '"file1"')
1015 fname = os.path.join(td, '"file1"')
1016 ip.run_cell_magic(
1016 ip.run_cell_magic(
1017 "writefile",
1017 "writefile",
1018 fname,
1018 fname,
1019 "\n".join(
1019 "\n".join(
1020 [
1020 [
1021 "line1",
1021 "line1",
1022 "line2",
1022 "line2",
1023 ]
1023 ]
1024 ),
1024 ),
1025 )
1025 )
1026 s = Path(fname).read_text(encoding="utf-8")
1026 s = Path(fname).read_text(encoding="utf-8")
1027 assert "line1\n" in s
1027 assert "line1\n" in s
1028 assert "line2" in s
1028 assert "line2" in s
1029
1029
1030
1030
1031 def test_file_var_expand():
1031 def test_file_var_expand():
1032 """%%writefile $filename"""
1032 """%%writefile $filename"""
1033 ip = get_ipython()
1033 ip = get_ipython()
1034 with TemporaryDirectory() as td:
1034 with TemporaryDirectory() as td:
1035 fname = os.path.join(td, "file1")
1035 fname = os.path.join(td, "file1")
1036 ip.user_ns["filename"] = fname
1036 ip.user_ns["filename"] = fname
1037 ip.run_cell_magic(
1037 ip.run_cell_magic(
1038 "writefile",
1038 "writefile",
1039 "$filename",
1039 "$filename",
1040 "\n".join(
1040 "\n".join(
1041 [
1041 [
1042 "line1",
1042 "line1",
1043 "line2",
1043 "line2",
1044 ]
1044 ]
1045 ),
1045 ),
1046 )
1046 )
1047 s = Path(fname).read_text(encoding="utf-8")
1047 s = Path(fname).read_text(encoding="utf-8")
1048 assert "line1\n" in s
1048 assert "line1\n" in s
1049 assert "line2" in s
1049 assert "line2" in s
1050
1050
1051
1051
1052 def test_file_unicode():
1052 def test_file_unicode():
1053 """%%writefile with unicode cell"""
1053 """%%writefile with unicode cell"""
1054 ip = get_ipython()
1054 ip = get_ipython()
1055 with TemporaryDirectory() as td:
1055 with TemporaryDirectory() as td:
1056 fname = os.path.join(td, 'file1')
1056 fname = os.path.join(td, 'file1')
1057 ip.run_cell_magic("writefile", fname, u'\n'.join([
1057 ip.run_cell_magic("writefile", fname, u'\n'.join([
1058 u'linΓ©1',
1058 u'linΓ©1',
1059 u'linΓ©2',
1059 u'linΓ©2',
1060 ]))
1060 ]))
1061 with io.open(fname, encoding='utf-8') as f:
1061 with io.open(fname, encoding='utf-8') as f:
1062 s = f.read()
1062 s = f.read()
1063 assert "linΓ©1\n" in s
1063 assert "linΓ©1\n" in s
1064 assert "linΓ©2" in s
1064 assert "linΓ©2" in s
1065
1065
1066
1066
1067 def test_file_amend():
1067 def test_file_amend():
1068 """%%writefile -a amends files"""
1068 """%%writefile -a amends files"""
1069 ip = get_ipython()
1069 ip = get_ipython()
1070 with TemporaryDirectory() as td:
1070 with TemporaryDirectory() as td:
1071 fname = os.path.join(td, "file2")
1071 fname = os.path.join(td, "file2")
1072 ip.run_cell_magic(
1072 ip.run_cell_magic(
1073 "writefile",
1073 "writefile",
1074 fname,
1074 fname,
1075 "\n".join(
1075 "\n".join(
1076 [
1076 [
1077 "line1",
1077 "line1",
1078 "line2",
1078 "line2",
1079 ]
1079 ]
1080 ),
1080 ),
1081 )
1081 )
1082 ip.run_cell_magic(
1082 ip.run_cell_magic(
1083 "writefile",
1083 "writefile",
1084 "-a %s" % fname,
1084 "-a %s" % fname,
1085 "\n".join(
1085 "\n".join(
1086 [
1086 [
1087 "line3",
1087 "line3",
1088 "line4",
1088 "line4",
1089 ]
1089 ]
1090 ),
1090 ),
1091 )
1091 )
1092 s = Path(fname).read_text(encoding="utf-8")
1092 s = Path(fname).read_text(encoding="utf-8")
1093 assert "line1\n" in s
1093 assert "line1\n" in s
1094 assert "line3\n" in s
1094 assert "line3\n" in s
1095
1095
1096
1096
1097 def test_file_spaces():
1097 def test_file_spaces():
1098 """%%file with spaces in filename"""
1098 """%%file with spaces in filename"""
1099 ip = get_ipython()
1099 ip = get_ipython()
1100 with TemporaryWorkingDirectory() as td:
1100 with TemporaryWorkingDirectory() as td:
1101 fname = "file name"
1101 fname = "file name"
1102 ip.run_cell_magic(
1102 ip.run_cell_magic(
1103 "file",
1103 "file",
1104 '"%s"' % fname,
1104 '"%s"' % fname,
1105 "\n".join(
1105 "\n".join(
1106 [
1106 [
1107 "line1",
1107 "line1",
1108 "line2",
1108 "line2",
1109 ]
1109 ]
1110 ),
1110 ),
1111 )
1111 )
1112 s = Path(fname).read_text(encoding="utf-8")
1112 s = Path(fname).read_text(encoding="utf-8")
1113 assert "line1\n" in s
1113 assert "line1\n" in s
1114 assert "line2" in s
1114 assert "line2" in s
1115
1115
1116
1116
1117 def test_script_config():
1117 def test_script_config():
1118 ip = get_ipython()
1118 ip = get_ipython()
1119 ip.config.ScriptMagics.script_magics = ['whoda']
1119 ip.config.ScriptMagics.script_magics = ['whoda']
1120 sm = script.ScriptMagics(shell=ip)
1120 sm = script.ScriptMagics(shell=ip)
1121 assert "whoda" in sm.magics["cell"]
1121 assert "whoda" in sm.magics["cell"]
1122
1122
1123
1123
1124 def test_script_out():
1124 def test_script_out():
1125 ip = get_ipython()
1125 ip = get_ipython()
1126 ip.run_cell_magic("script", f"--out output {sys.executable}", "print('hi')")
1126 ip.run_cell_magic("script", f"--out output {sys.executable}", "print('hi')")
1127 assert ip.user_ns["output"].strip() == "hi"
1127 assert ip.user_ns["output"].strip() == "hi"
1128
1128
1129
1129
1130 def test_script_err():
1130 def test_script_err():
1131 ip = get_ipython()
1131 ip = get_ipython()
1132 ip.run_cell_magic(
1132 ip.run_cell_magic(
1133 "script",
1133 "script",
1134 f"--err error {sys.executable}",
1134 f"--err error {sys.executable}",
1135 "import sys; print('hello', file=sys.stderr)",
1135 "import sys; print('hello', file=sys.stderr)",
1136 )
1136 )
1137 assert ip.user_ns["error"].strip() == "hello"
1137 assert ip.user_ns["error"].strip() == "hello"
1138
1138
1139
1139
1140 def test_script_out_err():
1140 def test_script_out_err():
1141 ip = get_ipython()
1141 ip = get_ipython()
1142 ip.run_cell_magic(
1142 ip.run_cell_magic(
1143 "script",
1143 "script",
1144 f"--out output --err error {sys.executable}",
1144 f"--out output --err error {sys.executable}",
1145 "\n".join(
1145 "\n".join(
1146 [
1146 [
1147 "import sys",
1147 "import sys",
1148 "print('hi')",
1148 "print('hi')",
1149 "print('hello', file=sys.stderr)",
1149 "print('hello', file=sys.stderr)",
1150 ]
1150 ]
1151 ),
1151 ),
1152 )
1152 )
1153 assert ip.user_ns["output"].strip() == "hi"
1153 assert ip.user_ns["output"].strip() == "hi"
1154 assert ip.user_ns["error"].strip() == "hello"
1154 assert ip.user_ns["error"].strip() == "hello"
1155
1155
1156
1156
1157 async def test_script_bg_out():
1157 async def test_script_bg_out():
1158 ip = get_ipython()
1158 ip = get_ipython()
1159 ip.run_cell_magic("script", f"--bg --out output {sys.executable}", "print('hi')")
1159 ip.run_cell_magic("script", f"--bg --out output {sys.executable}", "print('hi')")
1160 assert (await ip.user_ns["output"].read()).strip() == b"hi"
1160 assert (await ip.user_ns["output"].read()).strip() == b"hi"
1161 assert ip.user_ns["output"].at_eof()
1161 assert ip.user_ns["output"].at_eof()
1162
1162
1163
1163
1164 async def test_script_bg_err():
1164 async def test_script_bg_err():
1165 ip = get_ipython()
1165 ip = get_ipython()
1166 ip.run_cell_magic(
1166 ip.run_cell_magic(
1167 "script",
1167 "script",
1168 f"--bg --err error {sys.executable}",
1168 f"--bg --err error {sys.executable}",
1169 "import sys; print('hello', file=sys.stderr)",
1169 "import sys; print('hello', file=sys.stderr)",
1170 )
1170 )
1171 assert (await ip.user_ns["error"].read()).strip() == b"hello"
1171 assert (await ip.user_ns["error"].read()).strip() == b"hello"
1172 assert ip.user_ns["error"].at_eof()
1172 assert ip.user_ns["error"].at_eof()
1173
1173
1174
1174
1175 async def test_script_bg_out_err():
1175 async def test_script_bg_out_err():
1176 ip = get_ipython()
1176 ip = get_ipython()
1177 ip.run_cell_magic(
1177 ip.run_cell_magic(
1178 "script",
1178 "script",
1179 f"--bg --out output --err error {sys.executable}",
1179 f"--bg --out output --err error {sys.executable}",
1180 "\n".join(
1180 "\n".join(
1181 [
1181 [
1182 "import sys",
1182 "import sys",
1183 "print('hi')",
1183 "print('hi')",
1184 "print('hello', file=sys.stderr)",
1184 "print('hello', file=sys.stderr)",
1185 ]
1185 ]
1186 ),
1186 ),
1187 )
1187 )
1188 assert (await ip.user_ns["output"].read()).strip() == b"hi"
1188 assert (await ip.user_ns["output"].read()).strip() == b"hi"
1189 assert (await ip.user_ns["error"].read()).strip() == b"hello"
1189 assert (await ip.user_ns["error"].read()).strip() == b"hello"
1190 assert ip.user_ns["output"].at_eof()
1190 assert ip.user_ns["output"].at_eof()
1191 assert ip.user_ns["error"].at_eof()
1191 assert ip.user_ns["error"].at_eof()
1192
1192
1193
1193
1194 async def test_script_bg_proc():
1194 async def test_script_bg_proc():
1195 ip = get_ipython()
1195 ip = get_ipython()
1196 ip.run_cell_magic(
1196 ip.run_cell_magic(
1197 "script",
1197 "script",
1198 f"--bg --out output --proc p {sys.executable}",
1198 f"--bg --out output --proc p {sys.executable}",
1199 "\n".join(
1199 "\n".join(
1200 [
1200 [
1201 "import sys",
1201 "import sys",
1202 "print('hi')",
1202 "print('hi')",
1203 "print('hello', file=sys.stderr)",
1203 "print('hello', file=sys.stderr)",
1204 ]
1204 ]
1205 ),
1205 ),
1206 )
1206 )
1207 p = ip.user_ns["p"]
1207 p = ip.user_ns["p"]
1208 await p.wait()
1208 await p.wait()
1209 assert p.returncode == 0
1209 assert p.returncode == 0
1210 assert (await p.stdout.read()).strip() == b"hi"
1210 assert (await p.stdout.read()).strip() == b"hi"
1211 # not captured, so empty
1211 # not captured, so empty
1212 assert (await p.stderr.read()) == b""
1212 assert (await p.stderr.read()) == b""
1213 assert p.stdout.at_eof()
1213 assert p.stdout.at_eof()
1214 assert p.stderr.at_eof()
1214 assert p.stderr.at_eof()
1215
1215
1216
1216
1217 def test_script_defaults():
1217 def test_script_defaults():
1218 ip = get_ipython()
1218 ip = get_ipython()
1219 for cmd in ['sh', 'bash', 'perl', 'ruby']:
1219 for cmd in ['sh', 'bash', 'perl', 'ruby']:
1220 try:
1220 try:
1221 find_cmd(cmd)
1221 find_cmd(cmd)
1222 except Exception:
1222 except Exception:
1223 pass
1223 pass
1224 else:
1224 else:
1225 assert cmd in ip.magics_manager.magics["cell"]
1225 assert cmd in ip.magics_manager.magics["cell"]
1226
1226
1227
1227
1228 @magics_class
1228 @magics_class
1229 class FooFoo(Magics):
1229 class FooFoo(Magics):
1230 """class with both %foo and %%foo magics"""
1230 """class with both %foo and %%foo magics"""
1231 @line_magic('foo')
1231 @line_magic('foo')
1232 def line_foo(self, line):
1232 def line_foo(self, line):
1233 "I am line foo"
1233 "I am line foo"
1234 pass
1234 pass
1235
1235
1236 @cell_magic("foo")
1236 @cell_magic("foo")
1237 def cell_foo(self, line, cell):
1237 def cell_foo(self, line, cell):
1238 "I am cell foo, not line foo"
1238 "I am cell foo, not line foo"
1239 pass
1239 pass
1240
1240
1241 def test_line_cell_info():
1241 def test_line_cell_info():
1242 """%%foo and %foo magics are distinguishable to inspect"""
1242 """%%foo and %foo magics are distinguishable to inspect"""
1243 ip = get_ipython()
1243 ip = get_ipython()
1244 ip.magics_manager.register(FooFoo)
1244 ip.magics_manager.register(FooFoo)
1245 oinfo = ip.object_inspect("foo")
1245 oinfo = ip.object_inspect("foo")
1246 assert oinfo["found"] is True
1246 assert oinfo["found"] is True
1247 assert oinfo["ismagic"] is True
1247 assert oinfo["ismagic"] is True
1248
1248
1249 oinfo = ip.object_inspect("%%foo")
1249 oinfo = ip.object_inspect("%%foo")
1250 assert oinfo["found"] is True
1250 assert oinfo["found"] is True
1251 assert oinfo["ismagic"] is True
1251 assert oinfo["ismagic"] is True
1252 assert oinfo["docstring"] == FooFoo.cell_foo.__doc__
1252 assert oinfo["docstring"] == FooFoo.cell_foo.__doc__
1253
1253
1254 oinfo = ip.object_inspect("%foo")
1254 oinfo = ip.object_inspect("%foo")
1255 assert oinfo["found"] is True
1255 assert oinfo["found"] is True
1256 assert oinfo["ismagic"] is True
1256 assert oinfo["ismagic"] is True
1257 assert oinfo["docstring"] == FooFoo.line_foo.__doc__
1257 assert oinfo["docstring"] == FooFoo.line_foo.__doc__
1258
1258
1259
1259
1260 def test_multiple_magics():
1260 def test_multiple_magics():
1261 ip = get_ipython()
1261 ip = get_ipython()
1262 foo1 = FooFoo(ip)
1262 foo1 = FooFoo(ip)
1263 foo2 = FooFoo(ip)
1263 foo2 = FooFoo(ip)
1264 mm = ip.magics_manager
1264 mm = ip.magics_manager
1265 mm.register(foo1)
1265 mm.register(foo1)
1266 assert mm.magics["line"]["foo"].__self__ is foo1
1266 assert mm.magics["line"]["foo"].__self__ is foo1
1267 mm.register(foo2)
1267 mm.register(foo2)
1268 assert mm.magics["line"]["foo"].__self__ is foo2
1268 assert mm.magics["line"]["foo"].__self__ is foo2
1269
1269
1270
1270
1271 def test_alias_magic():
1271 def test_alias_magic():
1272 """Test %alias_magic."""
1272 """Test %alias_magic."""
1273 ip = get_ipython()
1273 ip = get_ipython()
1274 mm = ip.magics_manager
1274 mm = ip.magics_manager
1275
1275
1276 # Basic operation: both cell and line magics are created, if possible.
1276 # Basic operation: both cell and line magics are created, if possible.
1277 ip.run_line_magic("alias_magic", "timeit_alias timeit")
1277 ip.run_line_magic("alias_magic", "timeit_alias timeit")
1278 assert "timeit_alias" in mm.magics["line"]
1278 assert "timeit_alias" in mm.magics["line"]
1279 assert "timeit_alias" in mm.magics["cell"]
1279 assert "timeit_alias" in mm.magics["cell"]
1280
1280
1281 # --cell is specified, line magic not created.
1281 # --cell is specified, line magic not created.
1282 ip.run_line_magic("alias_magic", "--cell timeit_cell_alias timeit")
1282 ip.run_line_magic("alias_magic", "--cell timeit_cell_alias timeit")
1283 assert "timeit_cell_alias" not in mm.magics["line"]
1283 assert "timeit_cell_alias" not in mm.magics["line"]
1284 assert "timeit_cell_alias" in mm.magics["cell"]
1284 assert "timeit_cell_alias" in mm.magics["cell"]
1285
1285
1286 # Test that line alias is created successfully.
1286 # Test that line alias is created successfully.
1287 ip.run_line_magic("alias_magic", "--line env_alias env")
1287 ip.run_line_magic("alias_magic", "--line env_alias env")
1288 assert ip.run_line_magic("env", "") == ip.run_line_magic("env_alias", "")
1288 assert ip.run_line_magic("env", "") == ip.run_line_magic("env_alias", "")
1289
1289
1290 # Test that line alias with parameters passed in is created successfully.
1290 # Test that line alias with parameters passed in is created successfully.
1291 ip.run_line_magic(
1291 ip.run_line_magic(
1292 "alias_magic", "--line history_alias history --params " + shlex.quote("3")
1292 "alias_magic", "--line history_alias history --params " + shlex.quote("3")
1293 )
1293 )
1294 assert "history_alias" in mm.magics["line"]
1294 assert "history_alias" in mm.magics["line"]
1295
1295
1296
1296
1297 def test_save():
1297 def test_save():
1298 """Test %save."""
1298 """Test %save."""
1299 ip = get_ipython()
1299 ip = get_ipython()
1300 ip.history_manager.reset() # Clear any existing history.
1300 ip.history_manager.reset() # Clear any existing history.
1301 cmds = ["a=1", "def b():\n return a**2", "print(a, b())"]
1301 cmds = ["a=1", "def b():\n return a**2", "print(a, b())"]
1302 for i, cmd in enumerate(cmds, start=1):
1302 for i, cmd in enumerate(cmds, start=1):
1303 ip.history_manager.store_inputs(i, cmd)
1303 ip.history_manager.store_inputs(i, cmd)
1304 with TemporaryDirectory() as tmpdir:
1304 with TemporaryDirectory() as tmpdir:
1305 file = os.path.join(tmpdir, "testsave.py")
1305 file = os.path.join(tmpdir, "testsave.py")
1306 ip.run_line_magic("save", "%s 1-10" % file)
1306 ip.run_line_magic("save", "%s 1-10" % file)
1307 content = Path(file).read_text(encoding="utf-8")
1307 content = Path(file).read_text(encoding="utf-8")
1308 assert content.count(cmds[0]) == 1
1308 assert content.count(cmds[0]) == 1
1309 assert "coding: utf-8" in content
1309 assert "coding: utf-8" in content
1310 ip.run_line_magic("save", "-a %s 1-10" % file)
1310 ip.run_line_magic("save", "-a %s 1-10" % file)
1311 content = Path(file).read_text(encoding="utf-8")
1311 content = Path(file).read_text(encoding="utf-8")
1312 assert content.count(cmds[0]) == 2
1312 assert content.count(cmds[0]) == 2
1313 assert "coding: utf-8" in content
1313 assert "coding: utf-8" in content
1314
1314
1315
1315
1316 def test_save_with_no_args():
1316 def test_save_with_no_args():
1317 ip = get_ipython()
1317 ip = get_ipython()
1318 ip.history_manager.reset() # Clear any existing history.
1318 ip.history_manager.reset() # Clear any existing history.
1319 cmds = ["a=1", "def b():\n return a**2", "print(a, b())", "%save"]
1319 cmds = ["a=1", "def b():\n return a**2", "print(a, b())", "%save"]
1320 for i, cmd in enumerate(cmds, start=1):
1320 for i, cmd in enumerate(cmds, start=1):
1321 ip.history_manager.store_inputs(i, cmd)
1321 ip.history_manager.store_inputs(i, cmd)
1322
1322
1323 with TemporaryDirectory() as tmpdir:
1323 with TemporaryDirectory() as tmpdir:
1324 path = os.path.join(tmpdir, "testsave.py")
1324 path = os.path.join(tmpdir, "testsave.py")
1325 ip.run_line_magic("save", path)
1325 ip.run_line_magic("save", path)
1326 content = Path(path).read_text(encoding="utf-8")
1326 content = Path(path).read_text(encoding="utf-8")
1327 expected_content = dedent(
1327 expected_content = dedent(
1328 """\
1328 """\
1329 # coding: utf-8
1329 # coding: utf-8
1330 a=1
1330 a=1
1331 def b():
1331 def b():
1332 return a**2
1332 return a**2
1333 print(a, b())
1333 print(a, b())
1334 """
1334 """
1335 )
1335 )
1336 assert content == expected_content
1336 assert content == expected_content
1337
1337
1338
1338
1339 def test_store():
1339 def test_store():
1340 """Test %store."""
1340 """Test %store."""
1341 ip = get_ipython()
1341 ip = get_ipython()
1342 ip.run_line_magic('load_ext', 'storemagic')
1342 ip.run_line_magic('load_ext', 'storemagic')
1343
1343
1344 # make sure the storage is empty
1344 # make sure the storage is empty
1345 ip.run_line_magic("store", "-z")
1345 ip.run_line_magic("store", "-z")
1346 ip.user_ns["var"] = 42
1346 ip.user_ns["var"] = 42
1347 ip.run_line_magic("store", "var")
1347 ip.run_line_magic("store", "var")
1348 ip.user_ns["var"] = 39
1348 ip.user_ns["var"] = 39
1349 ip.run_line_magic("store", "-r")
1349 ip.run_line_magic("store", "-r")
1350 assert ip.user_ns["var"] == 42
1350 assert ip.user_ns["var"] == 42
1351
1351
1352 ip.run_line_magic("store", "-d var")
1352 ip.run_line_magic("store", "-d var")
1353 ip.user_ns["var"] = 39
1353 ip.user_ns["var"] = 39
1354 ip.run_line_magic("store", "-r")
1354 ip.run_line_magic("store", "-r")
1355 assert ip.user_ns["var"] == 39
1355 assert ip.user_ns["var"] == 39
1356
1356
1357
1357
1358 def _run_edit_test(arg_s, exp_filename=None,
1358 def _run_edit_test(arg_s, exp_filename=None,
1359 exp_lineno=-1,
1359 exp_lineno=-1,
1360 exp_contents=None,
1360 exp_contents=None,
1361 exp_is_temp=None):
1361 exp_is_temp=None):
1362 ip = get_ipython()
1362 ip = get_ipython()
1363 M = code.CodeMagics(ip)
1363 M = code.CodeMagics(ip)
1364 last_call = ['','']
1364 last_call = ['','']
1365 opts,args = M.parse_options(arg_s,'prxn:')
1365 opts,args = M.parse_options(arg_s,'prxn:')
1366 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
1366 filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call)
1367
1367
1368 if exp_filename is not None:
1368 if exp_filename is not None:
1369 assert exp_filename == filename
1369 assert exp_filename == filename
1370 if exp_contents is not None:
1370 if exp_contents is not None:
1371 with io.open(filename, 'r', encoding='utf-8') as f:
1371 with io.open(filename, 'r', encoding='utf-8') as f:
1372 contents = f.read()
1372 contents = f.read()
1373 assert exp_contents == contents
1373 assert exp_contents == contents
1374 if exp_lineno != -1:
1374 if exp_lineno != -1:
1375 assert exp_lineno == lineno
1375 assert exp_lineno == lineno
1376 if exp_is_temp is not None:
1376 if exp_is_temp is not None:
1377 assert exp_is_temp == is_temp
1377 assert exp_is_temp == is_temp
1378
1378
1379
1379
1380 def test_edit_interactive():
1380 def test_edit_interactive():
1381 """%edit on interactively defined objects"""
1381 """%edit on interactively defined objects"""
1382 ip = get_ipython()
1382 ip = get_ipython()
1383 n = ip.execution_count
1383 n = ip.execution_count
1384 ip.run_cell("def foo(): return 1", store_history=True)
1384 ip.run_cell("def foo(): return 1", store_history=True)
1385
1385
1386 with pytest.raises(code.InteractivelyDefined) as e:
1386 with pytest.raises(code.InteractivelyDefined) as e:
1387 _run_edit_test("foo")
1387 _run_edit_test("foo")
1388 assert e.value.index == n
1388 assert e.value.index == n
1389
1389
1390
1390
1391 def test_edit_cell():
1391 def test_edit_cell():
1392 """%edit [cell id]"""
1392 """%edit [cell id]"""
1393 ip = get_ipython()
1393 ip = get_ipython()
1394
1394
1395 ip.run_cell("def foo(): return 1", store_history=True)
1395 ip.run_cell("def foo(): return 1", store_history=True)
1396
1396
1397 # test
1397 # test
1398 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
1398 _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True)
1399
1399
1400 def test_edit_fname():
1400 def test_edit_fname():
1401 """%edit file"""
1401 """%edit file"""
1402 # test
1402 # test
1403 _run_edit_test("test file.py", exp_filename="test file.py")
1403 _run_edit_test("test file.py", exp_filename="test file.py")
1404
1404
1405 def test_bookmark():
1405 def test_bookmark():
1406 ip = get_ipython()
1406 ip = get_ipython()
1407 ip.run_line_magic('bookmark', 'bmname')
1407 ip.run_line_magic('bookmark', 'bmname')
1408 with tt.AssertPrints('bmname'):
1408 with tt.AssertPrints('bmname'):
1409 ip.run_line_magic('bookmark', '-l')
1409 ip.run_line_magic('bookmark', '-l')
1410 ip.run_line_magic('bookmark', '-d bmname')
1410 ip.run_line_magic('bookmark', '-d bmname')
1411
1411
1412 def test_ls_magic():
1412 def test_ls_magic():
1413 ip = get_ipython()
1413 ip = get_ipython()
1414 json_formatter = ip.display_formatter.formatters['application/json']
1414 json_formatter = ip.display_formatter.formatters['application/json']
1415 json_formatter.enabled = True
1415 json_formatter.enabled = True
1416 lsmagic = ip.run_line_magic("lsmagic", "")
1416 lsmagic = ip.run_line_magic("lsmagic", "")
1417 with warnings.catch_warnings(record=True) as w:
1417 with warnings.catch_warnings(record=True) as w:
1418 j = json_formatter(lsmagic)
1418 j = json_formatter(lsmagic)
1419 assert sorted(j) == ["cell", "line"]
1419 assert sorted(j) == ["cell", "line"]
1420 assert w == [] # no warnings
1420 assert w == [] # no warnings
1421
1421
1422
1422
1423 def test_strip_initial_indent():
1423 def test_strip_initial_indent():
1424 def sii(s):
1424 def sii(s):
1425 lines = s.splitlines()
1425 lines = s.splitlines()
1426 return '\n'.join(code.strip_initial_indent(lines))
1426 return '\n'.join(code.strip_initial_indent(lines))
1427
1427
1428 assert sii(" a = 1\nb = 2") == "a = 1\nb = 2"
1428 assert sii(" a = 1\nb = 2") == "a = 1\nb = 2"
1429 assert sii(" a\n b\nc") == "a\n b\nc"
1429 assert sii(" a\n b\nc") == "a\n b\nc"
1430 assert sii("a\n b") == "a\n b"
1430 assert sii("a\n b") == "a\n b"
1431
1431
1432 def test_logging_magic_quiet_from_arg():
1432 def test_logging_magic_quiet_from_arg():
1433 _ip.config.LoggingMagics.quiet = False
1433 _ip.config.LoggingMagics.quiet = False
1434 lm = logging.LoggingMagics(shell=_ip)
1434 lm = logging.LoggingMagics(shell=_ip)
1435 with TemporaryDirectory() as td:
1435 with TemporaryDirectory() as td:
1436 try:
1436 try:
1437 with tt.AssertNotPrints(re.compile("Activating.*")):
1437 with tt.AssertNotPrints(re.compile("Activating.*")):
1438 lm.logstart('-q {}'.format(
1438 lm.logstart('-q {}'.format(
1439 os.path.join(td, "quiet_from_arg.log")))
1439 os.path.join(td, "quiet_from_arg.log")))
1440 finally:
1440 finally:
1441 _ip.logger.logstop()
1441 _ip.logger.logstop()
1442
1442
1443 def test_logging_magic_quiet_from_config():
1443 def test_logging_magic_quiet_from_config():
1444 _ip.config.LoggingMagics.quiet = True
1444 _ip.config.LoggingMagics.quiet = True
1445 lm = logging.LoggingMagics(shell=_ip)
1445 lm = logging.LoggingMagics(shell=_ip)
1446 with TemporaryDirectory() as td:
1446 with TemporaryDirectory() as td:
1447 try:
1447 try:
1448 with tt.AssertNotPrints(re.compile("Activating.*")):
1448 with tt.AssertNotPrints(re.compile("Activating.*")):
1449 lm.logstart(os.path.join(td, "quiet_from_config.log"))
1449 lm.logstart(os.path.join(td, "quiet_from_config.log"))
1450 finally:
1450 finally:
1451 _ip.logger.logstop()
1451 _ip.logger.logstop()
1452
1452
1453
1453
1454 def test_logging_magic_not_quiet():
1454 def test_logging_magic_not_quiet():
1455 _ip.config.LoggingMagics.quiet = False
1455 _ip.config.LoggingMagics.quiet = False
1456 lm = logging.LoggingMagics(shell=_ip)
1456 lm = logging.LoggingMagics(shell=_ip)
1457 with TemporaryDirectory() as td:
1457 with TemporaryDirectory() as td:
1458 try:
1458 try:
1459 with tt.AssertPrints(re.compile("Activating.*")):
1459 with tt.AssertPrints(re.compile("Activating.*")):
1460 lm.logstart(os.path.join(td, "not_quiet.log"))
1460 lm.logstart(os.path.join(td, "not_quiet.log"))
1461 finally:
1461 finally:
1462 _ip.logger.logstop()
1462 _ip.logger.logstop()
1463
1463
1464
1464
1465 def test_time_no_var_expand():
1465 def test_time_no_var_expand():
1466 _ip.user_ns["a"] = 5
1466 _ip.user_ns["a"] = 5
1467 _ip.user_ns["b"] = []
1467 _ip.user_ns["b"] = []
1468 _ip.run_line_magic("time", 'b.append("{a}")')
1468 _ip.run_line_magic("time", 'b.append("{a}")')
1469 assert _ip.user_ns["b"] == ["{a}"]
1469 assert _ip.user_ns["b"] == ["{a}"]
1470
1470
1471
1471
1472 # this is slow, put at the end for local testing.
1472 # this is slow, put at the end for local testing.
1473 def test_timeit_arguments():
1473 def test_timeit_arguments():
1474 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
1474 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
1475 _ip.run_line_magic("timeit", "-n1 -r1 a=('#')")
1475 _ip.run_line_magic("timeit", "-n1 -r1 a=('#')")
1476
1476
1477
1477
1478 MINIMAL_LAZY_MAGIC = """
1478 MINIMAL_LAZY_MAGIC = """
1479 from IPython.core.magic import (
1479 from IPython.core.magic import (
1480 Magics,
1480 Magics,
1481 magics_class,
1481 magics_class,
1482 line_magic,
1482 line_magic,
1483 cell_magic,
1483 cell_magic,
1484 )
1484 )
1485
1485
1486
1486
1487 @magics_class
1487 @magics_class
1488 class LazyMagics(Magics):
1488 class LazyMagics(Magics):
1489 @line_magic
1489 @line_magic
1490 def lazy_line(self, line):
1490 def lazy_line(self, line):
1491 print("Lazy Line")
1491 print("Lazy Line")
1492
1492
1493 @cell_magic
1493 @cell_magic
1494 def lazy_cell(self, line, cell):
1494 def lazy_cell(self, line, cell):
1495 print("Lazy Cell")
1495 print("Lazy Cell")
1496
1496
1497
1497
1498 def load_ipython_extension(ipython):
1498 def load_ipython_extension(ipython):
1499 ipython.register_magics(LazyMagics)
1499 ipython.register_magics(LazyMagics)
1500 """
1500 """
1501
1501
1502
1502
1503 def test_lazy_magics():
1503 def test_lazy_magics():
1504 with pytest.raises(UsageError):
1504 with pytest.raises(UsageError):
1505 ip.run_line_magic("lazy_line", "")
1505 ip.run_line_magic("lazy_line", "")
1506
1506
1507 startdir = os.getcwd()
1507 startdir = os.getcwd()
1508
1508
1509 with TemporaryDirectory() as tmpdir:
1509 with TemporaryDirectory() as tmpdir:
1510 with prepended_to_syspath(tmpdir):
1510 with prepended_to_syspath(tmpdir):
1511 ptempdir = Path(tmpdir)
1511 ptempdir = Path(tmpdir)
1512 tf = ptempdir / "lazy_magic_module.py"
1512 tf = ptempdir / "lazy_magic_module.py"
1513 tf.write_text(MINIMAL_LAZY_MAGIC)
1513 tf.write_text(MINIMAL_LAZY_MAGIC)
1514 ip.magics_manager.register_lazy("lazy_line", Path(tf.name).name[:-3])
1514 ip.magics_manager.register_lazy("lazy_line", Path(tf.name).name[:-3])
1515 with tt.AssertPrints("Lazy Line"):
1515 with tt.AssertPrints("Lazy Line"):
1516 ip.run_line_magic("lazy_line", "")
1516 ip.run_line_magic("lazy_line", "")
1517
1517
1518
1518
1519 TEST_MODULE = """
1519 TEST_MODULE = """
1520 print('Loaded my_tmp')
1520 print('Loaded my_tmp')
1521 if __name__ == "__main__":
1521 if __name__ == "__main__":
1522 print('I just ran a script')
1522 print('I just ran a script')
1523 """
1523 """
1524
1524
1525 def test_run_module_from_import_hook():
1525 def test_run_module_from_import_hook():
1526 "Test that a module can be loaded via an import hook"
1526 "Test that a module can be loaded via an import hook"
1527 with TemporaryDirectory() as tmpdir:
1527 with TemporaryDirectory() as tmpdir:
1528 fullpath = os.path.join(tmpdir, "my_tmp.py")
1528 fullpath = os.path.join(tmpdir, "my_tmp.py")
1529 Path(fullpath).write_text(TEST_MODULE, encoding="utf-8")
1529 Path(fullpath).write_text(TEST_MODULE, encoding="utf-8")
1530
1530
1531 import importlib.abc
1531 import importlib.abc
1532 import importlib.util
1532 import importlib.util
1533
1533
1534 class MyTempImporter(importlib.abc.MetaPathFinder, importlib.abc.SourceLoader):
1534 class MyTempImporter(importlib.abc.MetaPathFinder, importlib.abc.SourceLoader):
1535 def find_spec(self, fullname, path, target=None):
1535 def find_spec(self, fullname, path, target=None):
1536 if fullname == "my_tmp":
1536 if fullname == "my_tmp":
1537 return importlib.util.spec_from_loader(fullname, self)
1537 return importlib.util.spec_from_loader(fullname, self)
1538
1538
1539 def get_filename(self, fullname):
1539 def get_filename(self, fullname):
1540 assert fullname == "my_tmp"
1540 assert fullname == "my_tmp"
1541 return fullpath
1541 return fullpath
1542
1542
1543 def get_data(self, path):
1543 def get_data(self, path):
1544 assert Path(path).samefile(fullpath)
1544 assert Path(path).samefile(fullpath)
1545 return Path(fullpath).read_text(encoding="utf-8")
1545 return Path(fullpath).read_text(encoding="utf-8")
1546
1546
1547 sys.meta_path.insert(0, MyTempImporter())
1547 sys.meta_path.insert(0, MyTempImporter())
1548
1548
1549 with capture_output() as captured:
1549 with capture_output() as captured:
1550 _ip.run_line_magic("run", "-m my_tmp")
1550 _ip.run_line_magic("run", "-m my_tmp")
1551 _ip.run_cell("import my_tmp")
1551 _ip.run_cell("import my_tmp")
1552
1552
1553 output = "Loaded my_tmp\nI just ran a script\nLoaded my_tmp\n"
1553 output = "Loaded my_tmp\nI just ran a script\nLoaded my_tmp\n"
1554 assert output == captured.stdout
1554 assert output == captured.stdout
1555
1555
1556 sys.meta_path.pop(0)
1556 sys.meta_path.pop(0)
@@ -1,626 +1,626
1 # encoding: utf-8
1 # encoding: utf-8
2 """Tests for code execution (%run and related), which is particularly tricky.
2 """Tests for code execution (%run and related), which is particularly tricky.
3
3
4 Because of how %run manages namespaces, and the fact that we are trying here to
4 Because of how %run manages namespaces, and the fact that we are trying here to
5 verify subtle object deletion and reference counting issues, the %run tests
5 verify subtle object deletion and reference counting issues, the %run tests
6 will be kept in this separate file. This makes it easier to aggregate in one
6 will be kept in this separate file. This makes it easier to aggregate in one
7 place the tricks needed to handle it; most other magics are much easier to test
7 place the tricks needed to handle it; most other magics are much easier to test
8 and we do so in a common test_magic file.
8 and we do so in a common test_magic file.
9
9
10 Note that any test using `run -i` should make sure to do a `reset` afterwards,
10 Note that any test using `run -i` should make sure to do a `reset` afterwards,
11 as otherwise it may influence later tests.
11 as otherwise it may influence later tests.
12 """
12 """
13
13
14 # Copyright (c) IPython Development Team.
14 # Copyright (c) IPython Development Team.
15 # Distributed under the terms of the Modified BSD License.
15 # Distributed under the terms of the Modified BSD License.
16
16
17
17
18
18
19 import functools
19 import functools
20 import os
20 import os
21 import platform
21 import platform
22 import random
22 import random
23 import string
23 import string
24 import sys
24 import sys
25 import textwrap
25 import textwrap
26 import unittest
26 import unittest
27 from os.path import join as pjoin
27 from os.path import join as pjoin
28 from unittest.mock import patch
28 from unittest.mock import patch
29
29
30 import pytest
30 import pytest
31 from tempfile import TemporaryDirectory
31 from tempfile import TemporaryDirectory
32
32
33 from IPython.core import debugger
33 from IPython.core import debugger
34 from IPython.testing import decorators as dec
34 from IPython.testing import decorators as dec
35 from IPython.testing import tools as tt
35 from IPython.testing import tools as tt
36 from IPython.utils.io import capture_output
36 from IPython.utils.io import capture_output
37
37
38
38
39 def doctest_refbug():
39 def doctest_refbug():
40 """Very nasty problem with references held by multiple runs of a script.
40 """Very nasty problem with references held by multiple runs of a script.
41 See: https://github.com/ipython/ipython/issues/141
41 See: https://github.com/ipython/ipython/issues/141
42
42
43 In [1]: _ip.clear_main_mod_cache()
43 In [1]: _ip.clear_main_mod_cache()
44 # random
44 # random
45
45
46 In [2]: %run refbug
46 In [2]: %run refbug
47
47
48 In [3]: call_f()
48 In [3]: call_f()
49 lowercased: hello
49 lowercased: hello
50
50
51 In [4]: %run refbug
51 In [4]: %run refbug
52
52
53 In [5]: call_f()
53 In [5]: call_f()
54 lowercased: hello
54 lowercased: hello
55 lowercased: hello
55 lowercased: hello
56 """
56 """
57
57
58
58
59 def doctest_run_builtins():
59 def doctest_run_builtins():
60 r"""Check that %run doesn't damage __builtins__.
60 r"""Check that %run doesn't damage __builtins__.
61
61
62 In [1]: import tempfile
62 In [1]: import tempfile
63
63
64 In [2]: bid1 = id(__builtins__)
64 In [2]: bid1 = id(__builtins__)
65
65
66 In [3]: fname = tempfile.mkstemp('.py')[1]
66 In [3]: fname = tempfile.mkstemp('.py')[1]
67
67
68 In [3]: f = open(fname, 'w', encoding='utf-8')
68 In [3]: f = open(fname, 'w', encoding='utf-8')
69
69
70 In [4]: dummy= f.write('pass\n')
70 In [4]: dummy= f.write('pass\n')
71
71
72 In [5]: f.flush()
72 In [5]: f.flush()
73
73
74 In [6]: t1 = type(__builtins__)
74 In [6]: t1 = type(__builtins__)
75
75
76 In [7]: %run $fname
76 In [7]: %run $fname
77
77
78 In [7]: f.close()
78 In [7]: f.close()
79
79
80 In [8]: bid2 = id(__builtins__)
80 In [8]: bid2 = id(__builtins__)
81
81
82 In [9]: t2 = type(__builtins__)
82 In [9]: t2 = type(__builtins__)
83
83
84 In [10]: t1 == t2
84 In [10]: t1 == t2
85 Out[10]: True
85 Out[10]: True
86
86
87 In [10]: bid1 == bid2
87 In [10]: bid1 == bid2
88 Out[10]: True
88 Out[10]: True
89
89
90 In [12]: try:
90 In [12]: try:
91 ....: os.unlink(fname)
91 ....: os.unlink(fname)
92 ....: except:
92 ....: except:
93 ....: pass
93 ....: pass
94 ....:
94 ....:
95 """
95 """
96
96
97
97
98 def doctest_run_option_parser():
98 def doctest_run_option_parser():
99 r"""Test option parser in %run.
99 r"""Test option parser in %run.
100
100
101 In [1]: %run print_argv.py
101 In [1]: %run print_argv.py
102 []
102 []
103
103
104 In [2]: %run print_argv.py print*.py
104 In [2]: %run print_argv.py print*.py
105 ['print_argv.py']
105 ['print_argv.py']
106
106
107 In [3]: %run -G print_argv.py print*.py
107 In [3]: %run -G print_argv.py print*.py
108 ['print*.py']
108 ['print*.py']
109
109
110 """
110 """
111
111
112
112
113 @dec.skip_win32
113 @dec.skip_win32
114 def doctest_run_option_parser_for_posix():
114 def doctest_run_option_parser_for_posix():
115 r"""Test option parser in %run (Linux/OSX specific).
115 r"""Test option parser in %run (Linux/OSX specific).
116
116
117 You need double quote to escape glob in POSIX systems:
117 You need double quote to escape glob in POSIX systems:
118
118
119 In [1]: %run print_argv.py print\\*.py
119 In [1]: %run print_argv.py print\\*.py
120 ['print*.py']
120 ['print*.py']
121
121
122 You can't use quote to escape glob in POSIX systems:
122 You can't use quote to escape glob in POSIX systems:
123
123
124 In [2]: %run print_argv.py 'print*.py'
124 In [2]: %run print_argv.py 'print*.py'
125 ['print_argv.py']
125 ['print_argv.py']
126
126
127 """
127 """
128
128
129
129
130 doctest_run_option_parser_for_posix.__skip_doctest__ = sys.platform == "win32"
130 doctest_run_option_parser_for_posix.__skip_doctest__ = sys.platform == "win32"
131
131
132
132
133 @dec.skip_if_not_win32
133 @dec.skip_if_not_win32
134 def doctest_run_option_parser_for_windows():
134 def doctest_run_option_parser_for_windows():
135 r"""Test option parser in %run (Windows specific).
135 r"""Test option parser in %run (Windows specific).
136
136
137 In Windows, you can't escape ``*` `by backslash:
137 In Windows, you can't escape ``*` `by backslash:
138
138
139 In [1]: %run print_argv.py print\\*.py
139 In [1]: %run print_argv.py print\\*.py
140 ['print\\\\*.py']
140 ['print\\\\*.py']
141
141
142 You can use quote to escape glob:
142 You can use quote to escape glob:
143
143
144 In [2]: %run print_argv.py 'print*.py'
144 In [2]: %run print_argv.py 'print*.py'
145 ["'print*.py'"]
145 ["'print*.py'"]
146
146
147 """
147 """
148
148
149
149
150 doctest_run_option_parser_for_windows.__skip_doctest__ = sys.platform != "win32"
150 doctest_run_option_parser_for_windows.__skip_doctest__ = sys.platform != "win32"
151
151
152
152
153 def doctest_reset_del():
153 def doctest_reset_del():
154 """Test that resetting doesn't cause errors in __del__ methods.
154 """Test that resetting doesn't cause errors in __del__ methods.
155
155
156 In [2]: class A(object):
156 In [2]: class A(object):
157 ...: def __del__(self):
157 ...: def __del__(self):
158 ...: print(str("Hi"))
158 ...: print(str("Hi"))
159 ...:
159 ...:
160
160
161 In [3]: a = A()
161 In [3]: a = A()
162
162
163 In [4]: get_ipython().reset(); import gc; x = gc.collect(0)
163 In [4]: get_ipython().reset(); import gc; x = gc.collect(0)
164 Hi
164 Hi
165
165
166 In [5]: 1+1
166 In [5]: 1+1
167 Out[5]: 2
167 Out[5]: 2
168 """
168 """
169
169
170 # For some tests, it will be handy to organize them in a class with a common
170 # For some tests, it will be handy to organize them in a class with a common
171 # setup that makes a temp file
171 # setup that makes a temp file
172
172
173 class TestMagicRunPass(tt.TempFileMixin):
173 class TestMagicRunPass(tt.TempFileMixin):
174
174
175 def setUp(self):
175 def setUp(self):
176 content = "a = [1,2,3]\nb = 1"
176 content = "a = [1,2,3]\nb = 1"
177 self.mktmp(content)
177 self.mktmp(content)
178
178
179 def run_tmpfile(self):
179 def run_tmpfile(self):
180 _ip = get_ipython()
180 _ip = get_ipython()
181 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
181 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
182 # See below and ticket https://bugs.launchpad.net/bugs/366353
182 # See below and ticket https://bugs.launchpad.net/bugs/366353
183 _ip.run_line_magic("run", self.fname)
183 _ip.run_line_magic("run", self.fname)
184
184
185 def run_tmpfile_p(self):
185 def run_tmpfile_p(self):
186 _ip = get_ipython()
186 _ip = get_ipython()
187 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
187 # This fails on Windows if self.tmpfile.name has spaces or "~" in it.
188 # See below and ticket https://bugs.launchpad.net/bugs/366353
188 # See below and ticket https://bugs.launchpad.net/bugs/366353
189 _ip.run_line_magic("run", "-p %s" % self.fname)
189 _ip.run_line_magic("run", "-p %s" % self.fname)
190
190
191 def test_builtins_id(self):
191 def test_builtins_id(self):
192 """Check that %run doesn't damage __builtins__ """
192 """Check that %run doesn't damage __builtins__ """
193 _ip = get_ipython()
193 _ip = get_ipython()
194 # Test that the id of __builtins__ is not modified by %run
194 # Test that the id of __builtins__ is not modified by %run
195 bid1 = id(_ip.user_ns['__builtins__'])
195 bid1 = id(_ip.user_ns['__builtins__'])
196 self.run_tmpfile()
196 self.run_tmpfile()
197 bid2 = id(_ip.user_ns['__builtins__'])
197 bid2 = id(_ip.user_ns['__builtins__'])
198 assert bid1 == bid2
198 assert bid1 == bid2
199
199
200 def test_builtins_type(self):
200 def test_builtins_type(self):
201 """Check that the type of __builtins__ doesn't change with %run.
201 """Check that the type of __builtins__ doesn't change with %run.
202
202
203 However, the above could pass if __builtins__ was already modified to
203 However, the above could pass if __builtins__ was already modified to
204 be a dict (it should be a module) by a previous use of %run. So we
204 be a dict (it should be a module) by a previous use of %run. So we
205 also check explicitly that it really is a module:
205 also check explicitly that it really is a module:
206 """
206 """
207 _ip = get_ipython()
207 _ip = get_ipython()
208 self.run_tmpfile()
208 self.run_tmpfile()
209 assert type(_ip.user_ns["__builtins__"]) == type(sys)
209 assert type(_ip.user_ns["__builtins__"]) == type(sys)
210
210
211 def test_run_profile(self):
211 def test_run_profile(self):
212 """Test that the option -p, which invokes the profiler, do not
212 """Test that the option -p, which invokes the profiler, do not
213 crash by invoking execfile"""
213 crash by invoking execfile"""
214 self.run_tmpfile_p()
214 self.run_tmpfile_p()
215
215
216 def test_run_debug_twice(self):
216 def test_run_debug_twice(self):
217 # https://github.com/ipython/ipython/issues/10028
217 # https://github.com/ipython/ipython/issues/10028
218 _ip = get_ipython()
218 _ip = get_ipython()
219 with tt.fake_input(["c"]):
219 with tt.fake_input(["c"]):
220 _ip.run_line_magic("run", "-d %s" % self.fname)
220 _ip.run_line_magic("run", "-d %s" % self.fname)
221 with tt.fake_input(["c"]):
221 with tt.fake_input(["c"]):
222 _ip.run_line_magic("run", "-d %s" % self.fname)
222 _ip.run_line_magic("run", "-d %s" % self.fname)
223
223
224 def test_run_debug_twice_with_breakpoint(self):
224 def test_run_debug_twice_with_breakpoint(self):
225 """Make a valid python temp file."""
225 """Make a valid python temp file."""
226 _ip = get_ipython()
226 _ip = get_ipython()
227 with tt.fake_input(["b 2", "c", "c"]):
227 with tt.fake_input(["b 2", "c", "c"]):
228 _ip.run_line_magic("run", "-d %s" % self.fname)
228 _ip.run_line_magic("run", "-d %s" % self.fname)
229
229
230 with tt.fake_input(["c"]):
230 with tt.fake_input(["c"]):
231 with tt.AssertNotPrints("KeyError"):
231 with tt.AssertNotPrints("KeyError"):
232 _ip.run_line_magic("run", "-d %s" % self.fname)
232 _ip.run_line_magic("run", "-d %s" % self.fname)
233
233
234
234
235 class TestMagicRunSimple(tt.TempFileMixin):
235 class TestMagicRunSimple(tt.TempFileMixin):
236
236
237 def test_simpledef(self):
237 def test_simpledef(self):
238 """Test that simple class definitions work."""
238 """Test that simple class definitions work."""
239 src = ("class foo: pass\n"
239 src = ("class foo: pass\n"
240 "def f(): return foo()")
240 "def f(): return foo()")
241 self.mktmp(src)
241 self.mktmp(src)
242 _ip.run_line_magic("run", str(self.fname))
242 _ip.run_line_magic("run", str(self.fname))
243 _ip.run_cell("t = isinstance(f(), foo)")
243 _ip.run_cell("t = isinstance(f(), foo)")
244 assert _ip.user_ns["t"] is True
244 assert _ip.user_ns["t"] is True
245
245
246 @pytest.mark.xfail(
246 @pytest.mark.xfail(
247 platform.python_implementation() == "PyPy",
247 platform.python_implementation() == "PyPy",
248 reason="expecting __del__ call on exit is unreliable and doesn't happen on PyPy",
248 reason="expecting __del__ call on exit is unreliable and doesn't happen on PyPy",
249 )
249 )
250 def test_obj_del(self):
250 def test_obj_del(self):
251 """Test that object's __del__ methods are called on exit."""
251 """Test that object's __del__ methods are called on exit."""
252 src = ("class A(object):\n"
252 src = ("class A(object):\n"
253 " def __del__(self):\n"
253 " def __del__(self):\n"
254 " print('object A deleted')\n"
254 " print('object A deleted')\n"
255 "a = A()\n")
255 "a = A()\n")
256 self.mktmp(src)
256 self.mktmp(src)
257 err = None
257 err = None
258 tt.ipexec_validate(self.fname, 'object A deleted', err)
258 tt.ipexec_validate(self.fname, 'object A deleted', err)
259
259
260 def test_aggressive_namespace_cleanup(self):
260 def test_aggressive_namespace_cleanup(self):
261 """Test that namespace cleanup is not too aggressive GH-238
261 """Test that namespace cleanup is not too aggressive GH-238
262
262
263 Returning from another run magic deletes the namespace"""
263 Returning from another run magic deletes the namespace"""
264 # see ticket https://github.com/ipython/ipython/issues/238
264 # see ticket https://github.com/ipython/ipython/issues/238
265
265
266 with tt.TempFileMixin() as empty:
266 with tt.TempFileMixin() as empty:
267 empty.mktmp("")
267 empty.mktmp("")
268 # On Windows, the filename will have \users in it, so we need to use the
268 # On Windows, the filename will have \users in it, so we need to use the
269 # repr so that the \u becomes \\u.
269 # repr so that the \u becomes \\u.
270 src = (
270 src = (
271 "ip = get_ipython()\n"
271 "ip = get_ipython()\n"
272 "for i in range(5):\n"
272 "for i in range(5):\n"
273 " try:\n"
273 " try:\n"
274 " ip.magic(%r)\n"
274 " ip.run_line_magic(%r, %r)\n"
275 " except NameError as e:\n"
275 " except NameError as e:\n"
276 " print(i)\n"
276 " print(i)\n"
277 " break\n" % ("run " + empty.fname)
277 " break\n" % ("run", empty.fname)
278 )
278 )
279 self.mktmp(src)
279 self.mktmp(src)
280 _ip.run_line_magic("run", str(self.fname))
280 _ip.run_line_magic("run", str(self.fname))
281 _ip.run_cell("ip == get_ipython()")
281 _ip.run_cell("ip == get_ipython()")
282 assert _ip.user_ns["i"] == 4
282 assert _ip.user_ns["i"] == 4
283
283
284 def test_run_second(self):
284 def test_run_second(self):
285 """Test that running a second file doesn't clobber the first, gh-3547"""
285 """Test that running a second file doesn't clobber the first, gh-3547"""
286 self.mktmp("avar = 1\n" "def afunc():\n" " return avar\n")
286 self.mktmp("avar = 1\n" "def afunc():\n" " return avar\n")
287
287
288 with tt.TempFileMixin() as empty:
288 with tt.TempFileMixin() as empty:
289 empty.mktmp("")
289 empty.mktmp("")
290
290
291 _ip.run_line_magic("run", self.fname)
291 _ip.run_line_magic("run", self.fname)
292 _ip.run_line_magic("run", empty.fname)
292 _ip.run_line_magic("run", empty.fname)
293 assert _ip.user_ns["afunc"]() == 1
293 assert _ip.user_ns["afunc"]() == 1
294
294
295 def test_tclass(self):
295 def test_tclass(self):
296 mydir = os.path.dirname(__file__)
296 mydir = os.path.dirname(__file__)
297 tc = os.path.join(mydir, "tclass")
297 tc = os.path.join(mydir, "tclass")
298 src = f"""\
298 src = f"""\
299 import gc
299 import gc
300 %run "{tc}" C-first
300 %run "{tc}" C-first
301 gc.collect(0)
301 gc.collect(0)
302 %run "{tc}" C-second
302 %run "{tc}" C-second
303 gc.collect(0)
303 gc.collect(0)
304 %run "{tc}" C-third
304 %run "{tc}" C-third
305 gc.collect(0)
305 gc.collect(0)
306 %reset -f
306 %reset -f
307 """
307 """
308 self.mktmp(src, ".ipy")
308 self.mktmp(src, ".ipy")
309 out = """\
309 out = """\
310 ARGV 1-: ['C-first']
310 ARGV 1-: ['C-first']
311 ARGV 1-: ['C-second']
311 ARGV 1-: ['C-second']
312 tclass.py: deleting object: C-first
312 tclass.py: deleting object: C-first
313 ARGV 1-: ['C-third']
313 ARGV 1-: ['C-third']
314 tclass.py: deleting object: C-second
314 tclass.py: deleting object: C-second
315 tclass.py: deleting object: C-third
315 tclass.py: deleting object: C-third
316 """
316 """
317 err = None
317 err = None
318 tt.ipexec_validate(self.fname, out, err)
318 tt.ipexec_validate(self.fname, out, err)
319
319
320 def test_run_i_after_reset(self):
320 def test_run_i_after_reset(self):
321 """Check that %run -i still works after %reset (gh-693)"""
321 """Check that %run -i still works after %reset (gh-693)"""
322 src = "yy = zz\n"
322 src = "yy = zz\n"
323 self.mktmp(src)
323 self.mktmp(src)
324 _ip.run_cell("zz = 23")
324 _ip.run_cell("zz = 23")
325 try:
325 try:
326 _ip.run_line_magic("run", "-i %s" % self.fname)
326 _ip.run_line_magic("run", "-i %s" % self.fname)
327 assert _ip.user_ns["yy"] == 23
327 assert _ip.user_ns["yy"] == 23
328 finally:
328 finally:
329 _ip.run_line_magic("reset", "-f")
329 _ip.run_line_magic("reset", "-f")
330
330
331 _ip.run_cell("zz = 23")
331 _ip.run_cell("zz = 23")
332 try:
332 try:
333 _ip.run_line_magic("run", "-i %s" % self.fname)
333 _ip.run_line_magic("run", "-i %s" % self.fname)
334 assert _ip.user_ns["yy"] == 23
334 assert _ip.user_ns["yy"] == 23
335 finally:
335 finally:
336 _ip.run_line_magic("reset", "-f")
336 _ip.run_line_magic("reset", "-f")
337
337
338 def test_unicode(self):
338 def test_unicode(self):
339 """Check that files in odd encodings are accepted."""
339 """Check that files in odd encodings are accepted."""
340 mydir = os.path.dirname(__file__)
340 mydir = os.path.dirname(__file__)
341 na = os.path.join(mydir, "nonascii.py")
341 na = os.path.join(mydir, "nonascii.py")
342 _ip.magic('run "%s"' % na)
342 _ip.run_line_magic("run", na)
343 assert _ip.user_ns["u"] == "ΠŽΡ‚β„–Π€"
343 assert _ip.user_ns["u"] == "ΠŽΡ‚β„–Π€"
344
344
345 def test_run_py_file_attribute(self):
345 def test_run_py_file_attribute(self):
346 """Test handling of `__file__` attribute in `%run <file>.py`."""
346 """Test handling of `__file__` attribute in `%run <file>.py`."""
347 src = "t = __file__\n"
347 src = "t = __file__\n"
348 self.mktmp(src)
348 self.mktmp(src)
349 _missing = object()
349 _missing = object()
350 file1 = _ip.user_ns.get("__file__", _missing)
350 file1 = _ip.user_ns.get("__file__", _missing)
351 _ip.run_line_magic("run", self.fname)
351 _ip.run_line_magic("run", self.fname)
352 file2 = _ip.user_ns.get("__file__", _missing)
352 file2 = _ip.user_ns.get("__file__", _missing)
353
353
354 # Check that __file__ was equal to the filename in the script's
354 # Check that __file__ was equal to the filename in the script's
355 # namespace.
355 # namespace.
356 assert _ip.user_ns["t"] == self.fname
356 assert _ip.user_ns["t"] == self.fname
357
357
358 # Check that __file__ was not leaked back into user_ns.
358 # Check that __file__ was not leaked back into user_ns.
359 assert file1 == file2
359 assert file1 == file2
360
360
361 def test_run_ipy_file_attribute(self):
361 def test_run_ipy_file_attribute(self):
362 """Test handling of `__file__` attribute in `%run <file.ipy>`."""
362 """Test handling of `__file__` attribute in `%run <file.ipy>`."""
363 src = "t = __file__\n"
363 src = "t = __file__\n"
364 self.mktmp(src, ext='.ipy')
364 self.mktmp(src, ext='.ipy')
365 _missing = object()
365 _missing = object()
366 file1 = _ip.user_ns.get("__file__", _missing)
366 file1 = _ip.user_ns.get("__file__", _missing)
367 _ip.run_line_magic("run", self.fname)
367 _ip.run_line_magic("run", self.fname)
368 file2 = _ip.user_ns.get("__file__", _missing)
368 file2 = _ip.user_ns.get("__file__", _missing)
369
369
370 # Check that __file__ was equal to the filename in the script's
370 # Check that __file__ was equal to the filename in the script's
371 # namespace.
371 # namespace.
372 assert _ip.user_ns["t"] == self.fname
372 assert _ip.user_ns["t"] == self.fname
373
373
374 # Check that __file__ was not leaked back into user_ns.
374 # Check that __file__ was not leaked back into user_ns.
375 assert file1 == file2
375 assert file1 == file2
376
376
377 def test_run_formatting(self):
377 def test_run_formatting(self):
378 """ Test that %run -t -N<N> does not raise a TypeError for N > 1."""
378 """ Test that %run -t -N<N> does not raise a TypeError for N > 1."""
379 src = "pass"
379 src = "pass"
380 self.mktmp(src)
380 self.mktmp(src)
381 _ip.run_line_magic("run", "-t -N 1 %s" % self.fname)
381 _ip.run_line_magic("run", "-t -N 1 %s" % self.fname)
382 _ip.run_line_magic("run", "-t -N 10 %s" % self.fname)
382 _ip.run_line_magic("run", "-t -N 10 %s" % self.fname)
383
383
384 def test_ignore_sys_exit(self):
384 def test_ignore_sys_exit(self):
385 """Test the -e option to ignore sys.exit()"""
385 """Test the -e option to ignore sys.exit()"""
386 src = "import sys; sys.exit(1)"
386 src = "import sys; sys.exit(1)"
387 self.mktmp(src)
387 self.mktmp(src)
388 with tt.AssertPrints("SystemExit"):
388 with tt.AssertPrints("SystemExit"):
389 _ip.run_line_magic("run", self.fname)
389 _ip.run_line_magic("run", self.fname)
390
390
391 with tt.AssertNotPrints("SystemExit"):
391 with tt.AssertNotPrints("SystemExit"):
392 _ip.run_line_magic("run", "-e %s" % self.fname)
392 _ip.run_line_magic("run", "-e %s" % self.fname)
393
393
394 def test_run_nb(self):
394 def test_run_nb(self):
395 """Test %run notebook.ipynb"""
395 """Test %run notebook.ipynb"""
396 pytest.importorskip("nbformat")
396 pytest.importorskip("nbformat")
397 from nbformat import v4, writes
397 from nbformat import v4, writes
398 nb = v4.new_notebook(
398 nb = v4.new_notebook(
399 cells=[
399 cells=[
400 v4.new_markdown_cell("The Ultimate Question of Everything"),
400 v4.new_markdown_cell("The Ultimate Question of Everything"),
401 v4.new_code_cell("answer=42")
401 v4.new_code_cell("answer=42")
402 ]
402 ]
403 )
403 )
404 src = writes(nb, version=4)
404 src = writes(nb, version=4)
405 self.mktmp(src, ext='.ipynb')
405 self.mktmp(src, ext='.ipynb')
406
406
407 _ip.run_line_magic("run", self.fname)
407 _ip.run_line_magic("run", self.fname)
408
408
409 assert _ip.user_ns["answer"] == 42
409 assert _ip.user_ns["answer"] == 42
410
410
411 def test_run_nb_error(self):
411 def test_run_nb_error(self):
412 """Test %run notebook.ipynb error"""
412 """Test %run notebook.ipynb error"""
413 pytest.importorskip("nbformat")
413 pytest.importorskip("nbformat")
414 from nbformat import v4, writes
414 from nbformat import v4, writes
415
415
416 # %run when a file name isn't provided
416 # %run when a file name isn't provided
417 pytest.raises(Exception, _ip.magic, "run")
417 pytest.raises(Exception, _ip.magic, "run")
418
418
419 # %run when a file doesn't exist
419 # %run when a file doesn't exist
420 pytest.raises(Exception, _ip.magic, "run foobar.ipynb")
420 pytest.raises(Exception, _ip.magic, "run foobar.ipynb")
421
421
422 # %run on a notebook with an error
422 # %run on a notebook with an error
423 nb = v4.new_notebook(
423 nb = v4.new_notebook(
424 cells=[
424 cells=[
425 v4.new_code_cell("0/0")
425 v4.new_code_cell("0/0")
426 ]
426 ]
427 )
427 )
428 src = writes(nb, version=4)
428 src = writes(nb, version=4)
429 self.mktmp(src, ext='.ipynb')
429 self.mktmp(src, ext='.ipynb')
430 pytest.raises(Exception, _ip.magic, "run %s" % self.fname)
430 pytest.raises(Exception, _ip.magic, "run %s" % self.fname)
431
431
432 def test_file_options(self):
432 def test_file_options(self):
433 src = ('import sys\n'
433 src = ('import sys\n'
434 'a = " ".join(sys.argv[1:])\n')
434 'a = " ".join(sys.argv[1:])\n')
435 self.mktmp(src)
435 self.mktmp(src)
436 test_opts = "-x 3 --verbose"
436 test_opts = "-x 3 --verbose"
437 _ip.run_line_magic("run", "{0} {1}".format(self.fname, test_opts))
437 _ip.run_line_magic("run", "{0} {1}".format(self.fname, test_opts))
438 assert _ip.user_ns["a"] == test_opts
438 assert _ip.user_ns["a"] == test_opts
439
439
440
440
441 class TestMagicRunWithPackage(unittest.TestCase):
441 class TestMagicRunWithPackage(unittest.TestCase):
442
442
443 def writefile(self, name, content):
443 def writefile(self, name, content):
444 path = os.path.join(self.tempdir.name, name)
444 path = os.path.join(self.tempdir.name, name)
445 d = os.path.dirname(path)
445 d = os.path.dirname(path)
446 if not os.path.isdir(d):
446 if not os.path.isdir(d):
447 os.makedirs(d)
447 os.makedirs(d)
448 with open(path, "w", encoding="utf-8") as f:
448 with open(path, "w", encoding="utf-8") as f:
449 f.write(textwrap.dedent(content))
449 f.write(textwrap.dedent(content))
450
450
451 def setUp(self):
451 def setUp(self):
452 self.package = package = 'tmp{0}'.format(''.join([random.choice(string.ascii_letters) for i in range(10)]))
452 self.package = package = 'tmp{0}'.format(''.join([random.choice(string.ascii_letters) for i in range(10)]))
453 """Temporary (probably) valid python package name."""
453 """Temporary (probably) valid python package name."""
454
454
455 self.value = int(random.random() * 10000)
455 self.value = int(random.random() * 10000)
456
456
457 self.tempdir = TemporaryDirectory()
457 self.tempdir = TemporaryDirectory()
458 self.__orig_cwd = os.getcwd()
458 self.__orig_cwd = os.getcwd()
459 sys.path.insert(0, self.tempdir.name)
459 sys.path.insert(0, self.tempdir.name)
460
460
461 self.writefile(os.path.join(package, '__init__.py'), '')
461 self.writefile(os.path.join(package, '__init__.py'), '')
462 self.writefile(os.path.join(package, 'sub.py'), """
462 self.writefile(os.path.join(package, 'sub.py'), """
463 x = {0!r}
463 x = {0!r}
464 """.format(self.value))
464 """.format(self.value))
465 self.writefile(os.path.join(package, 'relative.py'), """
465 self.writefile(os.path.join(package, 'relative.py'), """
466 from .sub import x
466 from .sub import x
467 """)
467 """)
468 self.writefile(os.path.join(package, 'absolute.py'), """
468 self.writefile(os.path.join(package, 'absolute.py'), """
469 from {0}.sub import x
469 from {0}.sub import x
470 """.format(package))
470 """.format(package))
471 self.writefile(os.path.join(package, 'args.py'), """
471 self.writefile(os.path.join(package, 'args.py'), """
472 import sys
472 import sys
473 a = " ".join(sys.argv[1:])
473 a = " ".join(sys.argv[1:])
474 """.format(package))
474 """.format(package))
475
475
476 def tearDown(self):
476 def tearDown(self):
477 os.chdir(self.__orig_cwd)
477 os.chdir(self.__orig_cwd)
478 sys.path[:] = [p for p in sys.path if p != self.tempdir.name]
478 sys.path[:] = [p for p in sys.path if p != self.tempdir.name]
479 self.tempdir.cleanup()
479 self.tempdir.cleanup()
480
480
481 def check_run_submodule(self, submodule, opts=""):
481 def check_run_submodule(self, submodule, opts=""):
482 _ip.user_ns.pop("x", None)
482 _ip.user_ns.pop("x", None)
483 _ip.run_line_magic(
483 _ip.run_line_magic(
484 "run", "{2} -m {0}.{1}".format(self.package, submodule, opts)
484 "run", "{2} -m {0}.{1}".format(self.package, submodule, opts)
485 )
485 )
486 self.assertEqual(
486 self.assertEqual(
487 _ip.user_ns["x"],
487 _ip.user_ns["x"],
488 self.value,
488 self.value,
489 "Variable `x` is not loaded from module `{0}`.".format(submodule),
489 "Variable `x` is not loaded from module `{0}`.".format(submodule),
490 )
490 )
491
491
492 def test_run_submodule_with_absolute_import(self):
492 def test_run_submodule_with_absolute_import(self):
493 self.check_run_submodule('absolute')
493 self.check_run_submodule('absolute')
494
494
495 def test_run_submodule_with_relative_import(self):
495 def test_run_submodule_with_relative_import(self):
496 """Run submodule that has a relative import statement (#2727)."""
496 """Run submodule that has a relative import statement (#2727)."""
497 self.check_run_submodule('relative')
497 self.check_run_submodule('relative')
498
498
499 def test_prun_submodule_with_absolute_import(self):
499 def test_prun_submodule_with_absolute_import(self):
500 self.check_run_submodule('absolute', '-p')
500 self.check_run_submodule('absolute', '-p')
501
501
502 def test_prun_submodule_with_relative_import(self):
502 def test_prun_submodule_with_relative_import(self):
503 self.check_run_submodule('relative', '-p')
503 self.check_run_submodule('relative', '-p')
504
504
505 def with_fake_debugger(func):
505 def with_fake_debugger(func):
506 @functools.wraps(func)
506 @functools.wraps(func)
507 def wrapper(*args, **kwds):
507 def wrapper(*args, **kwds):
508 with patch.object(debugger.Pdb, 'run', staticmethod(eval)):
508 with patch.object(debugger.Pdb, 'run', staticmethod(eval)):
509 return func(*args, **kwds)
509 return func(*args, **kwds)
510 return wrapper
510 return wrapper
511
511
512 @with_fake_debugger
512 @with_fake_debugger
513 def test_debug_run_submodule_with_absolute_import(self):
513 def test_debug_run_submodule_with_absolute_import(self):
514 self.check_run_submodule('absolute', '-d')
514 self.check_run_submodule('absolute', '-d')
515
515
516 @with_fake_debugger
516 @with_fake_debugger
517 def test_debug_run_submodule_with_relative_import(self):
517 def test_debug_run_submodule_with_relative_import(self):
518 self.check_run_submodule('relative', '-d')
518 self.check_run_submodule('relative', '-d')
519
519
520 def test_module_options(self):
520 def test_module_options(self):
521 _ip.user_ns.pop("a", None)
521 _ip.user_ns.pop("a", None)
522 test_opts = "-x abc -m test"
522 test_opts = "-x abc -m test"
523 _ip.run_line_magic("run", "-m {0}.args {1}".format(self.package, test_opts))
523 _ip.run_line_magic("run", "-m {0}.args {1}".format(self.package, test_opts))
524 assert _ip.user_ns["a"] == test_opts
524 assert _ip.user_ns["a"] == test_opts
525
525
526 def test_module_options_with_separator(self):
526 def test_module_options_with_separator(self):
527 _ip.user_ns.pop("a", None)
527 _ip.user_ns.pop("a", None)
528 test_opts = "-x abc -m test"
528 test_opts = "-x abc -m test"
529 _ip.run_line_magic("run", "-m {0}.args -- {1}".format(self.package, test_opts))
529 _ip.run_line_magic("run", "-m {0}.args -- {1}".format(self.package, test_opts))
530 assert _ip.user_ns["a"] == test_opts
530 assert _ip.user_ns["a"] == test_opts
531
531
532
532
533 def test_run__name__():
533 def test_run__name__():
534 with TemporaryDirectory() as td:
534 with TemporaryDirectory() as td:
535 path = pjoin(td, "foo.py")
535 path = pjoin(td, "foo.py")
536 with open(path, "w", encoding="utf-8") as f:
536 with open(path, "w", encoding="utf-8") as f:
537 f.write("q = __name__")
537 f.write("q = __name__")
538
538
539 _ip.user_ns.pop("q", None)
539 _ip.user_ns.pop("q", None)
540 _ip.run_line_magic("run", "{}".format(path))
540 _ip.run_line_magic("run", "{}".format(path))
541 assert _ip.user_ns.pop("q") == "__main__"
541 assert _ip.user_ns.pop("q") == "__main__"
542
542
543 _ip.run_line_magic("run", "-n {}".format(path))
543 _ip.run_line_magic("run", "-n {}".format(path))
544 assert _ip.user_ns.pop("q") == "foo"
544 assert _ip.user_ns.pop("q") == "foo"
545
545
546 try:
546 try:
547 _ip.run_line_magic("run", "-i -n {}".format(path))
547 _ip.run_line_magic("run", "-i -n {}".format(path))
548 assert _ip.user_ns.pop("q") == "foo"
548 assert _ip.user_ns.pop("q") == "foo"
549 finally:
549 finally:
550 _ip.run_line_magic("reset", "-f")
550 _ip.run_line_magic("reset", "-f")
551
551
552
552
553 def test_run_tb():
553 def test_run_tb():
554 """Test traceback offset in %run"""
554 """Test traceback offset in %run"""
555 with TemporaryDirectory() as td:
555 with TemporaryDirectory() as td:
556 path = pjoin(td, "foo.py")
556 path = pjoin(td, "foo.py")
557 with open(path, "w", encoding="utf-8") as f:
557 with open(path, "w", encoding="utf-8") as f:
558 f.write(
558 f.write(
559 "\n".join(
559 "\n".join(
560 [
560 [
561 "def foo():",
561 "def foo():",
562 " return bar()",
562 " return bar()",
563 "def bar():",
563 "def bar():",
564 " raise RuntimeError('hello!')",
564 " raise RuntimeError('hello!')",
565 "foo()",
565 "foo()",
566 ]
566 ]
567 )
567 )
568 )
568 )
569 with capture_output() as io:
569 with capture_output() as io:
570 _ip.run_line_magic("run", "{}".format(path))
570 _ip.run_line_magic("run", "{}".format(path))
571 out = io.stdout
571 out = io.stdout
572 assert "execfile" not in out
572 assert "execfile" not in out
573 assert "RuntimeError" in out
573 assert "RuntimeError" in out
574 assert out.count("---->") == 3
574 assert out.count("---->") == 3
575 del ip.user_ns['bar']
575 del ip.user_ns['bar']
576 del ip.user_ns['foo']
576 del ip.user_ns['foo']
577
577
578
578
579 def test_multiprocessing_run():
579 def test_multiprocessing_run():
580 """Set we can run mutiprocesgin without messing up up main namespace
580 """Set we can run mutiprocesgin without messing up up main namespace
581
581
582 Note that import `nose.tools as nt` modify the values
582 Note that import `nose.tools as nt` modify the values
583 sys.module['__mp_main__'] so we need to temporarily set it to None to test
583 sys.module['__mp_main__'] so we need to temporarily set it to None to test
584 the issue.
584 the issue.
585 """
585 """
586 with TemporaryDirectory() as td:
586 with TemporaryDirectory() as td:
587 mpm = sys.modules.get('__mp_main__')
587 mpm = sys.modules.get('__mp_main__')
588 sys.modules['__mp_main__'] = None
588 sys.modules['__mp_main__'] = None
589 try:
589 try:
590 path = pjoin(td, "test.py")
590 path = pjoin(td, "test.py")
591 with open(path, "w", encoding="utf-8") as f:
591 with open(path, "w", encoding="utf-8") as f:
592 f.write("import multiprocessing\nprint('hoy')")
592 f.write("import multiprocessing\nprint('hoy')")
593 with capture_output() as io:
593 with capture_output() as io:
594 _ip.run_line_magic('run', path)
594 _ip.run_line_magic('run', path)
595 _ip.run_cell("i_m_undefined")
595 _ip.run_cell("i_m_undefined")
596 out = io.stdout
596 out = io.stdout
597 assert "hoy" in out
597 assert "hoy" in out
598 assert "AttributeError" not in out
598 assert "AttributeError" not in out
599 assert "NameError" in out
599 assert "NameError" in out
600 assert out.count("---->") == 1
600 assert out.count("---->") == 1
601 except:
601 except:
602 raise
602 raise
603 finally:
603 finally:
604 sys.modules['__mp_main__'] = mpm
604 sys.modules['__mp_main__'] = mpm
605
605
606
606
607 def test_script_tb():
607 def test_script_tb():
608 """Test traceback offset in `ipython script.py`"""
608 """Test traceback offset in `ipython script.py`"""
609 with TemporaryDirectory() as td:
609 with TemporaryDirectory() as td:
610 path = pjoin(td, "foo.py")
610 path = pjoin(td, "foo.py")
611 with open(path, "w", encoding="utf-8") as f:
611 with open(path, "w", encoding="utf-8") as f:
612 f.write(
612 f.write(
613 "\n".join(
613 "\n".join(
614 [
614 [
615 "def foo():",
615 "def foo():",
616 " return bar()",
616 " return bar()",
617 "def bar():",
617 "def bar():",
618 " raise RuntimeError('hello!')",
618 " raise RuntimeError('hello!')",
619 "foo()",
619 "foo()",
620 ]
620 ]
621 )
621 )
622 )
622 )
623 out, err = tt.ipexec(path)
623 out, err = tt.ipexec(path)
624 assert "execfile" not in out
624 assert "execfile" not in out
625 assert "RuntimeError" in out
625 assert "RuntimeError" in out
626 assert out.count("---->") == 3
626 assert out.count("---->") == 3
@@ -1,456 +1,457
1 # encoding: utf-8
1 # encoding: utf-8
2 """Tests for IPython.core.ultratb
2 """Tests for IPython.core.ultratb
3 """
3 """
4 import io
4 import io
5 import os.path
5 import os.path
6 import platform
6 import platform
7 import re
7 import re
8 import sys
8 import sys
9 import traceback
9 import traceback
10 import unittest
10 import unittest
11 from textwrap import dedent
11 from textwrap import dedent
12
12
13 from tempfile import TemporaryDirectory
13 from tempfile import TemporaryDirectory
14
14
15 from IPython.core.ultratb import ColorTB, VerboseTB
15 from IPython.core.ultratb import ColorTB, VerboseTB
16 from IPython.testing import tools as tt
16 from IPython.testing import tools as tt
17 from IPython.testing.decorators import onlyif_unicode_paths, skip_without
17 from IPython.testing.decorators import onlyif_unicode_paths, skip_without
18 from IPython.utils.syspathcontext import prepended_to_syspath
18 from IPython.utils.syspathcontext import prepended_to_syspath
19
19
20 file_1 = """1
20 file_1 = """1
21 2
21 2
22 3
22 3
23 def f():
23 def f():
24 1/0
24 1/0
25 """
25 """
26
26
27 file_2 = """def f():
27 file_2 = """def f():
28 1/0
28 1/0
29 """
29 """
30
30
31
31
32 def recursionlimit(frames):
32 def recursionlimit(frames):
33 """
33 """
34 decorator to set the recursion limit temporarily
34 decorator to set the recursion limit temporarily
35 """
35 """
36
36
37 def inner(test_function):
37 def inner(test_function):
38 def wrapper(*args, **kwargs):
38 def wrapper(*args, **kwargs):
39 rl = sys.getrecursionlimit()
39 rl = sys.getrecursionlimit()
40 sys.setrecursionlimit(frames)
40 sys.setrecursionlimit(frames)
41 try:
41 try:
42 return test_function(*args, **kwargs)
42 return test_function(*args, **kwargs)
43 finally:
43 finally:
44 sys.setrecursionlimit(rl)
44 sys.setrecursionlimit(rl)
45
45
46 return wrapper
46 return wrapper
47
47
48 return inner
48 return inner
49
49
50
50
51 class ChangedPyFileTest(unittest.TestCase):
51 class ChangedPyFileTest(unittest.TestCase):
52 def test_changing_py_file(self):
52 def test_changing_py_file(self):
53 """Traceback produced if the line where the error occurred is missing?
53 """Traceback produced if the line where the error occurred is missing?
54
54
55 https://github.com/ipython/ipython/issues/1456
55 https://github.com/ipython/ipython/issues/1456
56 """
56 """
57 with TemporaryDirectory() as td:
57 with TemporaryDirectory() as td:
58 fname = os.path.join(td, "foo.py")
58 fname = os.path.join(td, "foo.py")
59 with open(fname, "w", encoding="utf-8") as f:
59 with open(fname, "w", encoding="utf-8") as f:
60 f.write(file_1)
60 f.write(file_1)
61
61
62 with prepended_to_syspath(td):
62 with prepended_to_syspath(td):
63 ip.run_cell("import foo")
63 ip.run_cell("import foo")
64
64
65 with tt.AssertPrints("ZeroDivisionError"):
65 with tt.AssertPrints("ZeroDivisionError"):
66 ip.run_cell("foo.f()")
66 ip.run_cell("foo.f()")
67
67
68 # Make the file shorter, so the line of the error is missing.
68 # Make the file shorter, so the line of the error is missing.
69 with open(fname, "w", encoding="utf-8") as f:
69 with open(fname, "w", encoding="utf-8") as f:
70 f.write(file_2)
70 f.write(file_2)
71
71
72 # For some reason, this was failing on the *second* call after
72 # For some reason, this was failing on the *second* call after
73 # changing the file, so we call f() twice.
73 # changing the file, so we call f() twice.
74 with tt.AssertNotPrints("Internal Python error", channel='stderr'):
74 with tt.AssertNotPrints("Internal Python error", channel='stderr'):
75 with tt.AssertPrints("ZeroDivisionError"):
75 with tt.AssertPrints("ZeroDivisionError"):
76 ip.run_cell("foo.f()")
76 ip.run_cell("foo.f()")
77 with tt.AssertPrints("ZeroDivisionError"):
77 with tt.AssertPrints("ZeroDivisionError"):
78 ip.run_cell("foo.f()")
78 ip.run_cell("foo.f()")
79
79
80 iso_8859_5_file = u'''# coding: iso-8859-5
80 iso_8859_5_file = u'''# coding: iso-8859-5
81
81
82 def fail():
82 def fail():
83 """Π΄Π±Π˜Π–"""
83 """Π΄Π±Π˜Π–"""
84 1/0 # Π΄Π±Π˜Π–
84 1/0 # Π΄Π±Π˜Π–
85 '''
85 '''
86
86
87 class NonAsciiTest(unittest.TestCase):
87 class NonAsciiTest(unittest.TestCase):
88 @onlyif_unicode_paths
88 @onlyif_unicode_paths
89 def test_nonascii_path(self):
89 def test_nonascii_path(self):
90 # Non-ascii directory name as well.
90 # Non-ascii directory name as well.
91 with TemporaryDirectory(suffix=u'Γ©') as td:
91 with TemporaryDirectory(suffix=u'Γ©') as td:
92 fname = os.path.join(td, u"fooΓ©.py")
92 fname = os.path.join(td, u"fooΓ©.py")
93 with open(fname, "w", encoding="utf-8") as f:
93 with open(fname, "w", encoding="utf-8") as f:
94 f.write(file_1)
94 f.write(file_1)
95
95
96 with prepended_to_syspath(td):
96 with prepended_to_syspath(td):
97 ip.run_cell("import foo")
97 ip.run_cell("import foo")
98
98
99 with tt.AssertPrints("ZeroDivisionError"):
99 with tt.AssertPrints("ZeroDivisionError"):
100 ip.run_cell("foo.f()")
100 ip.run_cell("foo.f()")
101
101
102 def test_iso8859_5(self):
102 def test_iso8859_5(self):
103 with TemporaryDirectory() as td:
103 with TemporaryDirectory() as td:
104 fname = os.path.join(td, 'dfghjkl.py')
104 fname = os.path.join(td, 'dfghjkl.py')
105
105
106 with io.open(fname, 'w', encoding='iso-8859-5') as f:
106 with io.open(fname, 'w', encoding='iso-8859-5') as f:
107 f.write(iso_8859_5_file)
107 f.write(iso_8859_5_file)
108
108
109 with prepended_to_syspath(td):
109 with prepended_to_syspath(td):
110 ip.run_cell("from dfghjkl import fail")
110 ip.run_cell("from dfghjkl import fail")
111
111
112 with tt.AssertPrints("ZeroDivisionError"):
112 with tt.AssertPrints("ZeroDivisionError"):
113 with tt.AssertPrints(u'Π΄Π±Π˜Π–', suppress=False):
113 with tt.AssertPrints(u'Π΄Π±Π˜Π–', suppress=False):
114 ip.run_cell('fail()')
114 ip.run_cell('fail()')
115
115
116 def test_nonascii_msg(self):
116 def test_nonascii_msg(self):
117 cell = u"raise Exception('Γ©')"
117 cell = u"raise Exception('Γ©')"
118 expected = u"Exception('Γ©')"
118 expected = u"Exception('Γ©')"
119 ip.run_cell("%xmode plain")
119 ip.run_cell("%xmode plain")
120 with tt.AssertPrints(expected):
120 with tt.AssertPrints(expected):
121 ip.run_cell(cell)
121 ip.run_cell(cell)
122
122
123 ip.run_cell("%xmode verbose")
123 ip.run_cell("%xmode verbose")
124 with tt.AssertPrints(expected):
124 with tt.AssertPrints(expected):
125 ip.run_cell(cell)
125 ip.run_cell(cell)
126
126
127 ip.run_cell("%xmode context")
127 ip.run_cell("%xmode context")
128 with tt.AssertPrints(expected):
128 with tt.AssertPrints(expected):
129 ip.run_cell(cell)
129 ip.run_cell(cell)
130
130
131 ip.run_cell("%xmode minimal")
131 ip.run_cell("%xmode minimal")
132 with tt.AssertPrints(u"Exception: Γ©"):
132 with tt.AssertPrints(u"Exception: Γ©"):
133 ip.run_cell(cell)
133 ip.run_cell(cell)
134
134
135 # Put this back into Context mode for later tests.
135 # Put this back into Context mode for later tests.
136 ip.run_cell("%xmode context")
136 ip.run_cell("%xmode context")
137
137
138 class NestedGenExprTestCase(unittest.TestCase):
138 class NestedGenExprTestCase(unittest.TestCase):
139 """
139 """
140 Regression test for the following issues:
140 Regression test for the following issues:
141 https://github.com/ipython/ipython/issues/8293
141 https://github.com/ipython/ipython/issues/8293
142 https://github.com/ipython/ipython/issues/8205
142 https://github.com/ipython/ipython/issues/8205
143 """
143 """
144 def test_nested_genexpr(self):
144 def test_nested_genexpr(self):
145 code = dedent(
145 code = dedent(
146 """\
146 """\
147 class SpecificException(Exception):
147 class SpecificException(Exception):
148 pass
148 pass
149
149
150 def foo(x):
150 def foo(x):
151 raise SpecificException("Success!")
151 raise SpecificException("Success!")
152
152
153 sum(sum(foo(x) for _ in [0]) for x in [0])
153 sum(sum(foo(x) for _ in [0]) for x in [0])
154 """
154 """
155 )
155 )
156 with tt.AssertPrints('SpecificException: Success!', suppress=False):
156 with tt.AssertPrints('SpecificException: Success!', suppress=False):
157 ip.run_cell(code)
157 ip.run_cell(code)
158
158
159
159
160 indentationerror_file = """if True:
160 indentationerror_file = """if True:
161 zoom()
161 zoom()
162 """
162 """
163
163
164 class IndentationErrorTest(unittest.TestCase):
164 class IndentationErrorTest(unittest.TestCase):
165 def test_indentationerror_shows_line(self):
165 def test_indentationerror_shows_line(self):
166 # See issue gh-2398
166 # See issue gh-2398
167 with tt.AssertPrints("IndentationError"):
167 with tt.AssertPrints("IndentationError"):
168 with tt.AssertPrints("zoom()", suppress=False):
168 with tt.AssertPrints("zoom()", suppress=False):
169 ip.run_cell(indentationerror_file)
169 ip.run_cell(indentationerror_file)
170
170
171 with TemporaryDirectory() as td:
171 with TemporaryDirectory() as td:
172 fname = os.path.join(td, "foo.py")
172 fname = os.path.join(td, "foo.py")
173 with open(fname, "w", encoding="utf-8") as f:
173 with open(fname, "w", encoding="utf-8") as f:
174 f.write(indentationerror_file)
174 f.write(indentationerror_file)
175
175
176 with tt.AssertPrints("IndentationError"):
176 with tt.AssertPrints("IndentationError"):
177 with tt.AssertPrints("zoom()", suppress=False):
177 with tt.AssertPrints("zoom()", suppress=False):
178 ip.magic('run %s' % fname)
178 ip.run_line_magic("run", fname)
179
179
180
180 @skip_without("pandas")
181 @skip_without("pandas")
181 def test_dynamic_code():
182 def test_dynamic_code():
182 code = """
183 code = """
183 import pandas
184 import pandas
184 df = pandas.DataFrame([])
185 df = pandas.DataFrame([])
185
186
186 # Important: only fails inside of an "exec" call:
187 # Important: only fails inside of an "exec" call:
187 exec("df.foobarbaz()")
188 exec("df.foobarbaz()")
188 """
189 """
189
190
190 with tt.AssertPrints("Could not get source"):
191 with tt.AssertPrints("Could not get source"):
191 ip.run_cell(code)
192 ip.run_cell(code)
192
193
193
194
194 se_file_1 = """1
195 se_file_1 = """1
195 2
196 2
196 7/
197 7/
197 """
198 """
198
199
199 se_file_2 = """7/
200 se_file_2 = """7/
200 """
201 """
201
202
202 class SyntaxErrorTest(unittest.TestCase):
203 class SyntaxErrorTest(unittest.TestCase):
203
204
204 def test_syntaxerror_no_stacktrace_at_compile_time(self):
205 def test_syntaxerror_no_stacktrace_at_compile_time(self):
205 syntax_error_at_compile_time = """
206 syntax_error_at_compile_time = """
206 def foo():
207 def foo():
207 ..
208 ..
208 """
209 """
209 with tt.AssertPrints("SyntaxError"):
210 with tt.AssertPrints("SyntaxError"):
210 ip.run_cell(syntax_error_at_compile_time)
211 ip.run_cell(syntax_error_at_compile_time)
211
212
212 with tt.AssertNotPrints("foo()"):
213 with tt.AssertNotPrints("foo()"):
213 ip.run_cell(syntax_error_at_compile_time)
214 ip.run_cell(syntax_error_at_compile_time)
214
215
215 def test_syntaxerror_stacktrace_when_running_compiled_code(self):
216 def test_syntaxerror_stacktrace_when_running_compiled_code(self):
216 syntax_error_at_runtime = """
217 syntax_error_at_runtime = """
217 def foo():
218 def foo():
218 eval("..")
219 eval("..")
219
220
220 def bar():
221 def bar():
221 foo()
222 foo()
222
223
223 bar()
224 bar()
224 """
225 """
225 with tt.AssertPrints("SyntaxError"):
226 with tt.AssertPrints("SyntaxError"):
226 ip.run_cell(syntax_error_at_runtime)
227 ip.run_cell(syntax_error_at_runtime)
227 # Assert syntax error during runtime generate stacktrace
228 # Assert syntax error during runtime generate stacktrace
228 with tt.AssertPrints(["foo()", "bar()"]):
229 with tt.AssertPrints(["foo()", "bar()"]):
229 ip.run_cell(syntax_error_at_runtime)
230 ip.run_cell(syntax_error_at_runtime)
230 del ip.user_ns['bar']
231 del ip.user_ns['bar']
231 del ip.user_ns['foo']
232 del ip.user_ns['foo']
232
233
233 def test_changing_py_file(self):
234 def test_changing_py_file(self):
234 with TemporaryDirectory() as td:
235 with TemporaryDirectory() as td:
235 fname = os.path.join(td, "foo.py")
236 fname = os.path.join(td, "foo.py")
236 with open(fname, "w", encoding="utf-8") as f:
237 with open(fname, "w", encoding="utf-8") as f:
237 f.write(se_file_1)
238 f.write(se_file_1)
238
239
239 with tt.AssertPrints(["7/", "SyntaxError"]):
240 with tt.AssertPrints(["7/", "SyntaxError"]):
240 ip.magic("run " + fname)
241 ip.run_line_magic("run", fname)
241
242
242 # Modify the file
243 # Modify the file
243 with open(fname, "w", encoding="utf-8") as f:
244 with open(fname, "w", encoding="utf-8") as f:
244 f.write(se_file_2)
245 f.write(se_file_2)
245
246
246 # The SyntaxError should point to the correct line
247 # The SyntaxError should point to the correct line
247 with tt.AssertPrints(["7/", "SyntaxError"]):
248 with tt.AssertPrints(["7/", "SyntaxError"]):
248 ip.magic("run " + fname)
249 ip.run_line_magic("run", fname)
249
250
250 def test_non_syntaxerror(self):
251 def test_non_syntaxerror(self):
251 # SyntaxTB may be called with an error other than a SyntaxError
252 # SyntaxTB may be called with an error other than a SyntaxError
252 # See e.g. gh-4361
253 # See e.g. gh-4361
253 try:
254 try:
254 raise ValueError('QWERTY')
255 raise ValueError('QWERTY')
255 except ValueError:
256 except ValueError:
256 with tt.AssertPrints('QWERTY'):
257 with tt.AssertPrints('QWERTY'):
257 ip.showsyntaxerror()
258 ip.showsyntaxerror()
258
259
259 import sys
260 import sys
260
261
261 if platform.python_implementation() != "PyPy":
262 if platform.python_implementation() != "PyPy":
262 """
263 """
263 New 3.9 Pgen Parser does not raise Memory error, except on failed malloc.
264 New 3.9 Pgen Parser does not raise Memory error, except on failed malloc.
264 """
265 """
265 class MemoryErrorTest(unittest.TestCase):
266 class MemoryErrorTest(unittest.TestCase):
266 def test_memoryerror(self):
267 def test_memoryerror(self):
267 memoryerror_code = "(" * 200 + ")" * 200
268 memoryerror_code = "(" * 200 + ")" * 200
268 ip.run_cell(memoryerror_code)
269 ip.run_cell(memoryerror_code)
269
270
270
271
271 class Python3ChainedExceptionsTest(unittest.TestCase):
272 class Python3ChainedExceptionsTest(unittest.TestCase):
272 DIRECT_CAUSE_ERROR_CODE = """
273 DIRECT_CAUSE_ERROR_CODE = """
273 try:
274 try:
274 x = 1 + 2
275 x = 1 + 2
275 print(not_defined_here)
276 print(not_defined_here)
276 except Exception as e:
277 except Exception as e:
277 x += 55
278 x += 55
278 x - 1
279 x - 1
279 y = {}
280 y = {}
280 raise KeyError('uh') from e
281 raise KeyError('uh') from e
281 """
282 """
282
283
283 EXCEPTION_DURING_HANDLING_CODE = """
284 EXCEPTION_DURING_HANDLING_CODE = """
284 try:
285 try:
285 x = 1 + 2
286 x = 1 + 2
286 print(not_defined_here)
287 print(not_defined_here)
287 except Exception as e:
288 except Exception as e:
288 x += 55
289 x += 55
289 x - 1
290 x - 1
290 y = {}
291 y = {}
291 raise KeyError('uh')
292 raise KeyError('uh')
292 """
293 """
293
294
294 SUPPRESS_CHAINING_CODE = """
295 SUPPRESS_CHAINING_CODE = """
295 try:
296 try:
296 1/0
297 1/0
297 except Exception:
298 except Exception:
298 raise ValueError("Yikes") from None
299 raise ValueError("Yikes") from None
299 """
300 """
300
301
301 SYS_EXIT_WITH_CONTEXT_CODE = """
302 SYS_EXIT_WITH_CONTEXT_CODE = """
302 try:
303 try:
303 1/0
304 1/0
304 except Exception as e:
305 except Exception as e:
305 raise SystemExit(1)
306 raise SystemExit(1)
306 """
307 """
307
308
308 def test_direct_cause_error(self):
309 def test_direct_cause_error(self):
309 with tt.AssertPrints(["KeyError", "NameError", "direct cause"]):
310 with tt.AssertPrints(["KeyError", "NameError", "direct cause"]):
310 ip.run_cell(self.DIRECT_CAUSE_ERROR_CODE)
311 ip.run_cell(self.DIRECT_CAUSE_ERROR_CODE)
311
312
312 def test_exception_during_handling_error(self):
313 def test_exception_during_handling_error(self):
313 with tt.AssertPrints(["KeyError", "NameError", "During handling"]):
314 with tt.AssertPrints(["KeyError", "NameError", "During handling"]):
314 ip.run_cell(self.EXCEPTION_DURING_HANDLING_CODE)
315 ip.run_cell(self.EXCEPTION_DURING_HANDLING_CODE)
315
316
316 def test_sysexit_while_handling_error(self):
317 def test_sysexit_while_handling_error(self):
317 with tt.AssertPrints(["SystemExit", "to see the full traceback"]):
318 with tt.AssertPrints(["SystemExit", "to see the full traceback"]):
318 with tt.AssertNotPrints(["another exception"], suppress=False):
319 with tt.AssertNotPrints(["another exception"], suppress=False):
319 ip.run_cell(self.SYS_EXIT_WITH_CONTEXT_CODE)
320 ip.run_cell(self.SYS_EXIT_WITH_CONTEXT_CODE)
320
321
321 def test_suppress_exception_chaining(self):
322 def test_suppress_exception_chaining(self):
322 with tt.AssertNotPrints("ZeroDivisionError"), \
323 with tt.AssertNotPrints("ZeroDivisionError"), \
323 tt.AssertPrints("ValueError", suppress=False):
324 tt.AssertPrints("ValueError", suppress=False):
324 ip.run_cell(self.SUPPRESS_CHAINING_CODE)
325 ip.run_cell(self.SUPPRESS_CHAINING_CODE)
325
326
326 def test_plain_direct_cause_error(self):
327 def test_plain_direct_cause_error(self):
327 with tt.AssertPrints(["KeyError", "NameError", "direct cause"]):
328 with tt.AssertPrints(["KeyError", "NameError", "direct cause"]):
328 ip.run_cell("%xmode Plain")
329 ip.run_cell("%xmode Plain")
329 ip.run_cell(self.DIRECT_CAUSE_ERROR_CODE)
330 ip.run_cell(self.DIRECT_CAUSE_ERROR_CODE)
330 ip.run_cell("%xmode Verbose")
331 ip.run_cell("%xmode Verbose")
331
332
332 def test_plain_exception_during_handling_error(self):
333 def test_plain_exception_during_handling_error(self):
333 with tt.AssertPrints(["KeyError", "NameError", "During handling"]):
334 with tt.AssertPrints(["KeyError", "NameError", "During handling"]):
334 ip.run_cell("%xmode Plain")
335 ip.run_cell("%xmode Plain")
335 ip.run_cell(self.EXCEPTION_DURING_HANDLING_CODE)
336 ip.run_cell(self.EXCEPTION_DURING_HANDLING_CODE)
336 ip.run_cell("%xmode Verbose")
337 ip.run_cell("%xmode Verbose")
337
338
338 def test_plain_suppress_exception_chaining(self):
339 def test_plain_suppress_exception_chaining(self):
339 with tt.AssertNotPrints("ZeroDivisionError"), \
340 with tt.AssertNotPrints("ZeroDivisionError"), \
340 tt.AssertPrints("ValueError", suppress=False):
341 tt.AssertPrints("ValueError", suppress=False):
341 ip.run_cell("%xmode Plain")
342 ip.run_cell("%xmode Plain")
342 ip.run_cell(self.SUPPRESS_CHAINING_CODE)
343 ip.run_cell(self.SUPPRESS_CHAINING_CODE)
343 ip.run_cell("%xmode Verbose")
344 ip.run_cell("%xmode Verbose")
344
345
345
346
346 class RecursionTest(unittest.TestCase):
347 class RecursionTest(unittest.TestCase):
347 DEFINITIONS = """
348 DEFINITIONS = """
348 def non_recurs():
349 def non_recurs():
349 1/0
350 1/0
350
351
351 def r1():
352 def r1():
352 r1()
353 r1()
353
354
354 def r3a():
355 def r3a():
355 r3b()
356 r3b()
356
357
357 def r3b():
358 def r3b():
358 r3c()
359 r3c()
359
360
360 def r3c():
361 def r3c():
361 r3a()
362 r3a()
362
363
363 def r3o1():
364 def r3o1():
364 r3a()
365 r3a()
365
366
366 def r3o2():
367 def r3o2():
367 r3o1()
368 r3o1()
368 """
369 """
369 def setUp(self):
370 def setUp(self):
370 ip.run_cell(self.DEFINITIONS)
371 ip.run_cell(self.DEFINITIONS)
371
372
372 def test_no_recursion(self):
373 def test_no_recursion(self):
373 with tt.AssertNotPrints("skipping similar frames"):
374 with tt.AssertNotPrints("skipping similar frames"):
374 ip.run_cell("non_recurs()")
375 ip.run_cell("non_recurs()")
375
376
376 @recursionlimit(200)
377 @recursionlimit(200)
377 def test_recursion_one_frame(self):
378 def test_recursion_one_frame(self):
378 with tt.AssertPrints(re.compile(
379 with tt.AssertPrints(re.compile(
379 r"\[\.\.\. skipping similar frames: r1 at line 5 \(\d{2,3} times\)\]")
380 r"\[\.\.\. skipping similar frames: r1 at line 5 \(\d{2,3} times\)\]")
380 ):
381 ):
381 ip.run_cell("r1()")
382 ip.run_cell("r1()")
382
383
383 @recursionlimit(160)
384 @recursionlimit(160)
384 def test_recursion_three_frames(self):
385 def test_recursion_three_frames(self):
385 with tt.AssertPrints("[... skipping similar frames: "), \
386 with tt.AssertPrints("[... skipping similar frames: "), \
386 tt.AssertPrints(re.compile(r"r3a at line 8 \(\d{2} times\)"), suppress=False), \
387 tt.AssertPrints(re.compile(r"r3a at line 8 \(\d{2} times\)"), suppress=False), \
387 tt.AssertPrints(re.compile(r"r3b at line 11 \(\d{2} times\)"), suppress=False), \
388 tt.AssertPrints(re.compile(r"r3b at line 11 \(\d{2} times\)"), suppress=False), \
388 tt.AssertPrints(re.compile(r"r3c at line 14 \(\d{2} times\)"), suppress=False):
389 tt.AssertPrints(re.compile(r"r3c at line 14 \(\d{2} times\)"), suppress=False):
389 ip.run_cell("r3o2()")
390 ip.run_cell("r3o2()")
390
391
391
392
392 class PEP678NotesReportingTest(unittest.TestCase):
393 class PEP678NotesReportingTest(unittest.TestCase):
393 ERROR_WITH_NOTE = """
394 ERROR_WITH_NOTE = """
394 try:
395 try:
395 raise AssertionError("Message")
396 raise AssertionError("Message")
396 except Exception as e:
397 except Exception as e:
397 try:
398 try:
398 e.add_note("This is a PEP-678 note.")
399 e.add_note("This is a PEP-678 note.")
399 except AttributeError: # Python <= 3.10
400 except AttributeError: # Python <= 3.10
400 e.__notes__ = ("This is a PEP-678 note.",)
401 e.__notes__ = ("This is a PEP-678 note.",)
401 raise
402 raise
402 """
403 """
403
404
404 def test_verbose_reports_notes(self):
405 def test_verbose_reports_notes(self):
405 with tt.AssertPrints(["AssertionError", "Message", "This is a PEP-678 note."]):
406 with tt.AssertPrints(["AssertionError", "Message", "This is a PEP-678 note."]):
406 ip.run_cell(self.ERROR_WITH_NOTE)
407 ip.run_cell(self.ERROR_WITH_NOTE)
407
408
408 def test_plain_reports_notes(self):
409 def test_plain_reports_notes(self):
409 with tt.AssertPrints(["AssertionError", "Message", "This is a PEP-678 note."]):
410 with tt.AssertPrints(["AssertionError", "Message", "This is a PEP-678 note."]):
410 ip.run_cell("%xmode Plain")
411 ip.run_cell("%xmode Plain")
411 ip.run_cell(self.ERROR_WITH_NOTE)
412 ip.run_cell(self.ERROR_WITH_NOTE)
412 ip.run_cell("%xmode Verbose")
413 ip.run_cell("%xmode Verbose")
413
414
414
415
415 #----------------------------------------------------------------------------
416 #----------------------------------------------------------------------------
416
417
417 # module testing (minimal)
418 # module testing (minimal)
418 def test_handlers():
419 def test_handlers():
419 def spam(c, d_e):
420 def spam(c, d_e):
420 (d, e) = d_e
421 (d, e) = d_e
421 x = c + d
422 x = c + d
422 y = c * d
423 y = c * d
423 foo(x, y)
424 foo(x, y)
424
425
425 def foo(a, b, bar=1):
426 def foo(a, b, bar=1):
426 eggs(a, b + bar)
427 eggs(a, b + bar)
427
428
428 def eggs(f, g, z=globals()):
429 def eggs(f, g, z=globals()):
429 h = f + g
430 h = f + g
430 i = f - g
431 i = f - g
431 return h / i
432 return h / i
432
433
433 buff = io.StringIO()
434 buff = io.StringIO()
434
435
435 buff.write('')
436 buff.write('')
436 buff.write('*** Before ***')
437 buff.write('*** Before ***')
437 try:
438 try:
438 buff.write(spam(1, (2, 3)))
439 buff.write(spam(1, (2, 3)))
439 except:
440 except:
440 traceback.print_exc(file=buff)
441 traceback.print_exc(file=buff)
441
442
442 handler = ColorTB(ostream=buff)
443 handler = ColorTB(ostream=buff)
443 buff.write('*** ColorTB ***')
444 buff.write('*** ColorTB ***')
444 try:
445 try:
445 buff.write(spam(1, (2, 3)))
446 buff.write(spam(1, (2, 3)))
446 except:
447 except:
447 handler(*sys.exc_info())
448 handler(*sys.exc_info())
448 buff.write('')
449 buff.write('')
449
450
450 handler = VerboseTB(ostream=buff)
451 handler = VerboseTB(ostream=buff)
451 buff.write('*** VerboseTB ***')
452 buff.write('*** VerboseTB ***')
452 try:
453 try:
453 buff.write(spam(1, (2, 3)))
454 buff.write(spam(1, (2, 3)))
454 except:
455 except:
455 handler(*sys.exc_info())
456 handler(*sys.exc_info())
456 buff.write('')
457 buff.write('')
General Comments 0
You need to be logged in to leave comments. Login now