##// END OF EJS Templates
added tests of passing alternative formatter functions
added tests of passing alternative formatter functions

File last commit:

r8129:b9c024f6
r8632:b24126ce
Show More
history.py
289 lines | 11.0 KiB | text/x-python | PythonLexer
"""Implementation of magic functions related to History.
"""
#-----------------------------------------------------------------------------
# Copyright (c) 2012, IPython Development Team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file COPYING.txt, distributed with this software.
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
from __future__ import print_function
# Stdlib
import os
from io import open as io_open
# Our own packages
from IPython.core.error import StdinNotImplementedError
from IPython.core.magic import Magics, magics_class, line_magic
from IPython.testing.skipdoctest import skip_doctest
from IPython.utils import io
#-----------------------------------------------------------------------------
# Magics class implementation
#-----------------------------------------------------------------------------
@magics_class
class HistoryMagics(Magics):
@skip_doctest
@line_magic
def history(self, parameter_s = ''):
"""Print input history (_i<n> variables), with most recent last.
%history [-o -p -t -n] [-f filename] [range | -g pattern | -l number]
By default, input history is printed without line numbers so it can be
directly pasted into an editor. Use -n to show them.
By default, all input history from the current session is displayed.
Ranges of history can be indicated using the syntax:
4 : Line 4, current session
4-6 : Lines 4-6, current session
243/1-5: Lines 1-5, session 243
~2/7 : Line 7, session 2 before current
~8/1-~6/5 : From the first line of 8 sessions ago, to the fifth line
of 6 sessions ago.
Multiple ranges can be entered, separated by spaces
The same syntax is used by %macro, %save, %edit, %rerun
Options:
-n: print line numbers for each input.
This feature is only available if numbered prompts are in use.
-o: also print outputs for each input.
-p: print classic '>>>' python prompts before each input. This is
useful for making documentation, and in conjunction with -o, for
producing doctest-ready output.
-r: (default) print the 'raw' history, i.e. the actual commands you
typed.
-t: print the 'translated' history, as IPython understands it.
IPython filters your input and converts it all into valid Python
source before executing it (things like magics or aliases are turned
into function calls, for example). With this option, you'll see the
native history instead of the user-entered version: '%cd /' will be
seen as 'get_ipython().magic("%cd /")' instead of '%cd /'.
-g: treat the arg as a pattern to grep for in (full) history.
This includes the saved history (almost all commands ever written).
The pattern may contain '?' to match one unknown character and '*'
to match any number of unknown characters. Use '%hist -g' to show
full saved history (may be very long).
-l: get the last n lines from all sessions. Specify n as a single
arg, or the default is the last 10 lines.
-f FILENAME: instead of printing the output to the screen, redirect
it to the given file. The file is always overwritten, though *when
it can*, IPython asks for confirmation first. In particular, running
the command 'history -f FILENAME' from the IPython Notebook
interface will replace FILENAME even if it already exists *without*
confirmation.
Examples
--------
::
In [6]: %history -n 4-6
4:a = 12
5:print a**2
6:%history -n 4-6
"""
if not self.shell.displayhook.do_full_cache:
print('This feature is only available if numbered prompts '
'are in use.')
return
opts,args = self.parse_options(parameter_s,'noprtglf:',mode='string')
# For brevity
history_manager = self.shell.history_manager
def _format_lineno(session, line):
"""Helper function to format line numbers properly."""
if session in (0, history_manager.session_number):
return str(line)
return "%s/%s" % (session, line)
# Check if output to specific file was requested.
try:
outfname = opts['f']
except KeyError:
outfile = io.stdout # default
# We don't want to close stdout at the end!
close_at_end = False
else:
if os.path.exists(outfname):
try:
ans = io.ask_yes_no("File %r exists. Overwrite?" % outfname)
except StdinNotImplementedError:
ans = True
if not ans:
print('Aborting.')
return
print("Overwriting file.")
outfile = io_open(outfname, 'w', encoding='utf-8')
close_at_end = True
print_nums = 'n' in opts
get_output = 'o' in opts
pyprompts = 'p' in opts
# Raw history is the default
raw = not('t' in opts)
pattern = None
if 'g' in opts: # Glob search
pattern = "*" + args + "*" if args else "*"
hist = history_manager.search(pattern, raw=raw, output=get_output)
print_nums = True
elif 'l' in opts: # Get 'tail'
try:
n = int(args)
except (ValueError, IndexError):
n = 10
hist = history_manager.get_tail(n, raw=raw, output=get_output)
else:
if args: # Get history by ranges
hist = history_manager.get_range_by_str(args, raw, get_output)
else: # Just get history for the current session
hist = history_manager.get_range(raw=raw, output=get_output)
# We could be displaying the entire history, so let's not try to pull
# it into a list in memory. Anything that needs more space will just
# misalign.
width = 4
for session, lineno, inline in hist:
# Print user history with tabs expanded to 4 spaces. The GUI
# clients use hard tabs for easier usability in auto-indented code,
# but we want to produce PEP-8 compliant history for safe pasting
# into an editor.
if get_output:
inline, output = inline
inline = inline.expandtabs(4).rstrip()
multiline = "\n" in inline
line_sep = '\n' if multiline else ' '
if print_nums:
print(u'%s:%s' % (_format_lineno(session, lineno).rjust(width),
line_sep), file=outfile, end=u'')
if pyprompts:
print(u">>> ", end=u"", file=outfile)
if multiline:
inline = "\n... ".join(inline.splitlines()) + "\n..."
print(inline, file=outfile)
if get_output and output:
print(output, file=outfile)
if close_at_end:
outfile.close()
@line_magic
def recall(self, arg):
r"""Repeat a command, or get command to input line for editing.
%recall and %rep are equivalent.
- %recall (no arguments):
Place a string version of last computation result (stored in the
special '_' variable) to the next input prompt. Allows you to create
elaborate command lines without using copy-paste::
In[1]: l = ["hei", "vaan"]
In[2]: "".join(l)
Out[2]: heivaan
In[3]: %recall
In[4]: heivaan_ <== cursor blinking
%recall 45
Place history line 45 on the next input prompt. Use %hist to find
out the number.
%recall 1-4
Combine the specified lines into one cell, and place it on the next
input prompt. See %history for the slice syntax.
%recall foo+bar
If foo+bar can be evaluated in the user namespace, the result is
placed at the next input prompt. Otherwise, the history is searched
for lines which contain that substring, and the most recent one is
placed at the next input prompt.
"""
if not arg: # Last output
self.shell.set_next_input(str(self.shell.user_ns["_"]))
return
# Get history range
histlines = self.shell.history_manager.get_range_by_str(arg)
cmd = "\n".join(x[2] for x in histlines)
if cmd:
self.shell.set_next_input(cmd.rstrip())
return
try: # Variable in user namespace
cmd = str(eval(arg, self.shell.user_ns))
except Exception: # Search for term in history
histlines = self.shell.history_manager.search("*"+arg+"*")
for h in reversed([x[2] for x in histlines]):
if 'recall' in h or 'rep' in h:
continue
self.shell.set_next_input(h.rstrip())
return
else:
self.shell.set_next_input(cmd.rstrip())
print("Couldn't evaluate or find in history:", arg)
@line_magic
def rerun(self, parameter_s=''):
"""Re-run previous input
By default, you can specify ranges of input history to be repeated
(as with %history). With no arguments, it will repeat the last line.
Options:
-l <n> : Repeat the last n lines of input, not including the
current command.
-g foo : Repeat the most recent line which contains foo
"""
opts, args = self.parse_options(parameter_s, 'l:g:', mode='string')
if "l" in opts: # Last n lines
n = int(opts['l'])
hist = self.shell.history_manager.get_tail(n)
elif "g" in opts: # Search
p = "*"+opts['g']+"*"
hist = list(self.shell.history_manager.search(p))
for l in reversed(hist):
if "rerun" not in l[2]:
hist = [l] # The last match which isn't a %rerun
break
else:
hist = [] # No matches except %rerun
elif args: # Specify history ranges
hist = self.shell.history_manager.get_range_by_str(args)
else: # Last line
hist = self.shell.history_manager.get_tail(1)
hist = [x[2] for x in hist]
if not hist:
print("No lines in history match specification")
return
histlines = "\n".join(hist)
print("=== Executing: ===")
print(histlines)
print("=== Output: ===")
self.shell.run_cell("\n".join(hist), store_history=False)