##// END OF EJS Templates
Use non-deprecated run_line_magic function
M Bussonnier -
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.run_line_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.run_line_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,195 +1,195
1 """Implementation of magic functions for IPython's own logging.
1 """Implementation of magic functions for IPython's own logging.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2012 The IPython Development Team.
4 # Copyright (c) 2012 The IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 # Stdlib
15 # Stdlib
16 import os
16 import os
17 import sys
17 import sys
18
18
19 # Our own packages
19 # Our own packages
20 from IPython.core.magic import Magics, magics_class, line_magic
20 from IPython.core.magic import Magics, magics_class, line_magic
21 from warnings import warn
21 from warnings import warn
22 from traitlets import Bool
22 from traitlets import Bool
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Magic implementation classes
25 # Magic implementation classes
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
27
28 @magics_class
28 @magics_class
29 class LoggingMagics(Magics):
29 class LoggingMagics(Magics):
30 """Magics related to all logging machinery."""
30 """Magics related to all logging machinery."""
31
31
32 quiet = Bool(False, help=
32 quiet = Bool(False, help=
33 """
33 """
34 Suppress output of log state when logging is enabled
34 Suppress output of log state when logging is enabled
35 """
35 """
36 ).tag(config=True)
36 ).tag(config=True)
37
37
38 @line_magic
38 @line_magic
39 def logstart(self, parameter_s=''):
39 def logstart(self, parameter_s=''):
40 """Start logging anywhere in a session.
40 """Start logging anywhere in a session.
41
41
42 %logstart [-o|-r|-t|-q] [log_name [log_mode]]
42 %logstart [-o|-r|-t|-q] [log_name [log_mode]]
43
43
44 If no name is given, it defaults to a file named 'ipython_log.py' in your
44 If no name is given, it defaults to a file named 'ipython_log.py' in your
45 current directory, in 'rotate' mode (see below).
45 current directory, in 'rotate' mode (see below).
46
46
47 '%logstart name' saves to file 'name' in 'backup' mode. It saves your
47 '%logstart name' saves to file 'name' in 'backup' mode. It saves your
48 history up to that point and then continues logging.
48 history up to that point and then continues logging.
49
49
50 %logstart takes a second optional parameter: logging mode. This can be one
50 %logstart takes a second optional parameter: logging mode. This can be one
51 of (note that the modes are given unquoted):
51 of (note that the modes are given unquoted):
52
52
53 append
53 append
54 Keep logging at the end of any existing file.
54 Keep logging at the end of any existing file.
55
55
56 backup
56 backup
57 Rename any existing file to name~ and start name.
57 Rename any existing file to name~ and start name.
58
58
59 global
59 global
60 Append to a single logfile in your home directory.
60 Append to a single logfile in your home directory.
61
61
62 over
62 over
63 Overwrite any existing log.
63 Overwrite any existing log.
64
64
65 rotate
65 rotate
66 Create rotating logs: name.1~, name.2~, etc.
66 Create rotating logs: name.1~, name.2~, etc.
67
67
68 Options:
68 Options:
69
69
70 -o
70 -o
71 log also IPython's output. In this mode, all commands which
71 log also IPython's output. In this mode, all commands which
72 generate an Out[NN] prompt are recorded to the logfile, right after
72 generate an Out[NN] prompt are recorded to the logfile, right after
73 their corresponding input line. The output lines are always
73 their corresponding input line. The output lines are always
74 prepended with a '#[Out]# ' marker, so that the log remains valid
74 prepended with a '#[Out]# ' marker, so that the log remains valid
75 Python code.
75 Python code.
76
76
77 Since this marker is always the same, filtering only the output from
77 Since this marker is always the same, filtering only the output from
78 a log is very easy, using for example a simple awk call::
78 a log is very easy, using for example a simple awk call::
79
79
80 awk -F'#\\[Out\\]# ' '{if($2) {print $2}}' ipython_log.py
80 awk -F'#\\[Out\\]# ' '{if($2) {print $2}}' ipython_log.py
81
81
82 -r
82 -r
83 log 'raw' input. Normally, IPython's logs contain the processed
83 log 'raw' input. Normally, IPython's logs contain the processed
84 input, so that user lines are logged in their final form, converted
84 input, so that user lines are logged in their final form, converted
85 into valid Python. For example, %Exit is logged as
85 into valid Python. For example, %Exit is logged as
86 _ip.magic("Exit"). If the -r flag is given, all input is logged
86 _ip.run_line_magic("Exit"). If the -r flag is given, all input is logged
87 exactly as typed, with no transformations applied.
87 exactly as typed, with no transformations applied.
88
88
89 -t
89 -t
90 put timestamps before each input line logged (these are put in
90 put timestamps before each input line logged (these are put in
91 comments).
91 comments).
92
92
93 -q
93 -q
94 suppress output of logstate message when logging is invoked
94 suppress output of logstate message when logging is invoked
95 """
95 """
96
96
97 opts,par = self.parse_options(parameter_s,'ortq')
97 opts,par = self.parse_options(parameter_s,'ortq')
98 log_output = 'o' in opts
98 log_output = 'o' in opts
99 log_raw_input = 'r' in opts
99 log_raw_input = 'r' in opts
100 timestamp = 't' in opts
100 timestamp = 't' in opts
101 quiet = 'q' in opts
101 quiet = 'q' in opts
102
102
103 logger = self.shell.logger
103 logger = self.shell.logger
104
104
105 # if no args are given, the defaults set in the logger constructor by
105 # if no args are given, the defaults set in the logger constructor by
106 # ipython remain valid
106 # ipython remain valid
107 if par:
107 if par:
108 try:
108 try:
109 logfname,logmode = par.split()
109 logfname,logmode = par.split()
110 except:
110 except:
111 logfname = par
111 logfname = par
112 logmode = 'backup'
112 logmode = 'backup'
113 else:
113 else:
114 logfname = logger.logfname
114 logfname = logger.logfname
115 logmode = logger.logmode
115 logmode = logger.logmode
116 # put logfname into rc struct as if it had been called on the command
116 # put logfname into rc struct as if it had been called on the command
117 # line, so it ends up saved in the log header Save it in case we need
117 # line, so it ends up saved in the log header Save it in case we need
118 # to restore it...
118 # to restore it...
119 old_logfile = self.shell.logfile
119 old_logfile = self.shell.logfile
120 if logfname:
120 if logfname:
121 logfname = os.path.expanduser(logfname)
121 logfname = os.path.expanduser(logfname)
122 self.shell.logfile = logfname
122 self.shell.logfile = logfname
123
123
124 loghead = u'# IPython log file\n\n'
124 loghead = u'# IPython log file\n\n'
125 try:
125 try:
126 logger.logstart(logfname, loghead, logmode, log_output, timestamp,
126 logger.logstart(logfname, loghead, logmode, log_output, timestamp,
127 log_raw_input)
127 log_raw_input)
128 except:
128 except:
129 self.shell.logfile = old_logfile
129 self.shell.logfile = old_logfile
130 warn("Couldn't start log: %s" % sys.exc_info()[1])
130 warn("Couldn't start log: %s" % sys.exc_info()[1])
131 else:
131 else:
132 # log input history up to this point, optionally interleaving
132 # log input history up to this point, optionally interleaving
133 # output if requested
133 # output if requested
134
134
135 if timestamp:
135 if timestamp:
136 # disable timestamping for the previous history, since we've
136 # disable timestamping for the previous history, since we've
137 # lost those already (no time machine here).
137 # lost those already (no time machine here).
138 logger.timestamp = False
138 logger.timestamp = False
139
139
140 if log_raw_input:
140 if log_raw_input:
141 input_hist = self.shell.history_manager.input_hist_raw
141 input_hist = self.shell.history_manager.input_hist_raw
142 else:
142 else:
143 input_hist = self.shell.history_manager.input_hist_parsed
143 input_hist = self.shell.history_manager.input_hist_parsed
144
144
145 if log_output:
145 if log_output:
146 log_write = logger.log_write
146 log_write = logger.log_write
147 output_hist = self.shell.history_manager.output_hist
147 output_hist = self.shell.history_manager.output_hist
148 for n in range(1,len(input_hist)-1):
148 for n in range(1,len(input_hist)-1):
149 log_write(input_hist[n].rstrip() + u'\n')
149 log_write(input_hist[n].rstrip() + u'\n')
150 if n in output_hist:
150 if n in output_hist:
151 log_write(repr(output_hist[n]),'output')
151 log_write(repr(output_hist[n]),'output')
152 else:
152 else:
153 logger.log_write(u'\n'.join(input_hist[1:]))
153 logger.log_write(u'\n'.join(input_hist[1:]))
154 logger.log_write(u'\n')
154 logger.log_write(u'\n')
155 if timestamp:
155 if timestamp:
156 # re-enable timestamping
156 # re-enable timestamping
157 logger.timestamp = True
157 logger.timestamp = True
158
158
159 if not (self.quiet or quiet):
159 if not (self.quiet or quiet):
160 print ('Activating auto-logging. '
160 print ('Activating auto-logging. '
161 'Current session state plus future input saved.')
161 'Current session state plus future input saved.')
162 logger.logstate()
162 logger.logstate()
163
163
164 @line_magic
164 @line_magic
165 def logstop(self, parameter_s=''):
165 def logstop(self, parameter_s=''):
166 """Fully stop logging and close log file.
166 """Fully stop logging and close log file.
167
167
168 In order to start logging again, a new %logstart call needs to be made,
168 In order to start logging again, a new %logstart call needs to be made,
169 possibly (though not necessarily) with a new filename, mode and other
169 possibly (though not necessarily) with a new filename, mode and other
170 options."""
170 options."""
171 self.shell.logger.logstop()
171 self.shell.logger.logstop()
172
172
173 @line_magic
173 @line_magic
174 def logoff(self, parameter_s=''):
174 def logoff(self, parameter_s=''):
175 """Temporarily stop logging.
175 """Temporarily stop logging.
176
176
177 You must have previously started logging."""
177 You must have previously started logging."""
178 self.shell.logger.switch_log(0)
178 self.shell.logger.switch_log(0)
179
179
180 @line_magic
180 @line_magic
181 def logon(self, parameter_s=''):
181 def logon(self, parameter_s=''):
182 """Restart logging.
182 """Restart logging.
183
183
184 This function is for restarting logging which you've temporarily
184 This function is for restarting logging which you've temporarily
185 stopped with %logoff. For starting logging for the first time, you
185 stopped with %logoff. For starting logging for the first time, you
186 must use the %logstart function, which allows you to specify an
186 must use the %logstart function, which allows you to specify an
187 optional log filename."""
187 optional log filename."""
188
188
189 self.shell.logger.switch_log(1)
189 self.shell.logger.switch_log(1)
190
190
191 @line_magic
191 @line_magic
192 def logstate(self, parameter_s=''):
192 def logstate(self, parameter_s=''):
193 """Print the status of the logging system."""
193 """Print the status of the logging system."""
194
194
195 self.shell.logger.logstate()
195 self.shell.logger.logstate()
@@ -1,66 +1,71
1 import tempfile, os
1 import tempfile, os
2 from pathlib import Path
2 from pathlib import Path
3
3
4 from traitlets.config.loader import Config
4 from traitlets.config.loader import Config
5
5
6
6
7 def setup_module():
7 def setup_module():
8 ip.magic('load_ext storemagic')
8 ip.run_line_magic("load_ext", "storemagic")
9
9
10
10 def test_store_restore():
11 def test_store_restore():
11 assert 'bar' not in ip.user_ns, "Error: some other test leaked `bar` in user_ns"
12 assert "bar" not in ip.user_ns, "Error: some other test leaked `bar` in user_ns"
12 assert 'foo' not in ip.user_ns, "Error: some other test leaked `foo` in user_ns"
13 assert "foo" not in ip.user_ns, "Error: some other test leaked `foo` in user_ns"
13 assert 'foobar' not in ip.user_ns, "Error: some other test leaked `foobar` in user_ns"
14 assert (
14 assert 'foobaz' not in ip.user_ns, "Error: some other test leaked `foobaz` in user_ns"
15 "foobar" not in ip.user_ns
15 ip.user_ns['foo'] = 78
16 ), "Error: some other test leaked `foobar` in user_ns"
16 ip.magic('alias bar echo "hello"')
17 assert (
17 ip.user_ns['foobar'] = 79
18 "foobaz" not in ip.user_ns
18 ip.user_ns['foobaz'] = '80'
19 ), "Error: some other test leaked `foobaz` in user_ns"
20 ip.user_ns["foo"] = 78
21 ip.run_line_magic("alias", 'bar echo "hello"')
22 ip.user_ns["foobar"] = 79
23 ip.user_ns["foobaz"] = "80"
19 tmpd = tempfile.mkdtemp()
24 tmpd = tempfile.mkdtemp()
20 ip.magic('cd ' + tmpd)
25 ip.run_line_magic("cd", tmpd)
21 ip.magic('store foo')
26 ip.run_line_magic("store", "foo")
22 ip.magic('store bar')
27 ip.run_line_magic("store", "bar")
23 ip.magic('store foobar foobaz')
28 ip.run_line_magic("store", "foobar foobaz")
24
29
25 # Check storing
30 # Check storing
26 assert ip.db["autorestore/foo"] == 78
31 assert ip.db["autorestore/foo"] == 78
27 assert "bar" in ip.db["stored_aliases"]
32 assert "bar" in ip.db["stored_aliases"]
28 assert ip.db["autorestore/foobar"] == 79
33 assert ip.db["autorestore/foobar"] == 79
29 assert ip.db["autorestore/foobaz"] == "80"
34 assert ip.db["autorestore/foobaz"] == "80"
30
35
31 # Remove those items
36 # Remove those items
32 ip.user_ns.pop('foo', None)
37 ip.user_ns.pop("foo", None)
33 ip.user_ns.pop('foobar', None)
38 ip.user_ns.pop("foobar", None)
34 ip.user_ns.pop('foobaz', None)
39 ip.user_ns.pop("foobaz", None)
35 ip.alias_manager.undefine_alias('bar')
40 ip.alias_manager.undefine_alias("bar")
36 ip.magic('cd -')
41 ip.run_line_magic("cd", "-")
37 ip.user_ns['_dh'][:] = []
42 ip.user_ns["_dh"][:] = []
38
43
39 # Check restoring
44 # Check restoring
40 ip.magic("store -r foo bar foobar foobaz")
45 ip.run_line_magic("store", "-r foo bar foobar foobaz")
41 assert ip.user_ns["foo"] == 78
46 assert ip.user_ns["foo"] == 78
42 assert ip.alias_manager.is_alias("bar")
47 assert ip.alias_manager.is_alias("bar")
43 assert ip.user_ns["foobar"] == 79
48 assert ip.user_ns["foobar"] == 79
44 assert ip.user_ns["foobaz"] == "80"
49 assert ip.user_ns["foobaz"] == "80"
45
50
46 ip.magic("store -r") # restores _dh too
51 ip.run_line_magic("store", "-r") # restores _dh too
47 assert any(Path(tmpd).samefile(p) for p in ip.user_ns["_dh"])
52 assert any(Path(tmpd).samefile(p) for p in ip.user_ns["_dh"])
48
53
49 os.rmdir(tmpd)
54 os.rmdir(tmpd)
50
55
51 def test_autorestore():
56 def test_autorestore():
52 ip.user_ns['foo'] = 95
57 ip.user_ns["foo"] = 95
53 ip.magic('store foo')
58 ip.run_line_magic("store", "foo")
54 del ip.user_ns['foo']
59 del ip.user_ns["foo"]
55 c = Config()
60 c = Config()
56 c.StoreMagics.autorestore = False
61 c.StoreMagics.autorestore = False
57 orig_config = ip.config
62 orig_config = ip.config
58 try:
63 try:
59 ip.config = c
64 ip.config = c
60 ip.extension_manager.reload_extension("storemagic")
65 ip.extension_manager.reload_extension("storemagic")
61 assert "foo" not in ip.user_ns
66 assert "foo" not in ip.user_ns
62 c.StoreMagics.autorestore = True
67 c.StoreMagics.autorestore = True
63 ip.extension_manager.reload_extension("storemagic")
68 ip.extension_manager.reload_extension("storemagic")
64 assert ip.user_ns["foo"] == 95
69 assert ip.user_ns["foo"] == 95
65 finally:
70 finally:
66 ip.config = orig_config
71 ip.config = orig_config
General Comments 0
You need to be logged in to leave comments. Login now