diff --git a/IPython/core/magics/history.py b/IPython/core/magics/history.py index dbfa1c8..23f5a8f 100644 --- a/IPython/core/magics/history.py +++ b/IPython/core/magics/history.py @@ -16,10 +16,13 @@ from __future__ import print_function # Stdlib import os from io import open as io_open +from argparse import Action # Our own packages from IPython.core.error import StdinNotImplementedError from IPython.core.magic import Magics, magics_class, line_magic +from IPython.core.magic_arguments import (argument, magic_arguments, + parse_argstring) from IPython.testing.skipdoctest import skip_doctest from IPython.utils import io @@ -27,16 +30,74 @@ from IPython.utils import io # Magics class implementation #----------------------------------------------------------------------------- + +class HistoryArgLimitAction(Action): + def __call__(self, parser, namespace, values, option_string=None): + namespace.limit_specified = True + namespace.limit = values + + @magics_class class HistoryMagics(Magics): + @magic_arguments() + @argument( + '-n', dest='print_nums', action='store_true', default=False, + help=""" + print line numbers for each input. + This feature is only available if numbered prompts are in use. + """) + @argument( + '-o', dest='get_output', action='store_true', default=False, + help="also print outputs for each input.") + @argument( + '-p', dest='pyprompts', action='store_true', default=False, + help=""" + print classic '>>>' python prompts before each input. + This is useful for making documentation, and in conjunction + with -o, for producing doctest-ready output. + """) + @argument( + '-t', dest='raw', action='store_false', default=True, + help=""" + 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 /'. + """) + @argument( + '-f', dest='filename', + help=""" + 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. + """) + @argument( + '-g', dest='pattern', nargs='*', default=None, + help=""" + 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). + """) + @argument( + '-l', dest='limit', type=int, nargs='?', action=HistoryArgLimitAction, + help=""" + get the last n lines from all sessions. Specify n as a single + arg, or the default is the last 10 lines. + """) + @argument('range', nargs='*') @skip_doctest @line_magic def history(self, parameter_s = ''): """Print input history (_i 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. @@ -52,43 +113,6 @@ class HistoryMagics(Magics): 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 -------- :: @@ -104,7 +128,7 @@ class HistoryMagics(Magics): print('This feature is only available if numbered prompts ' 'are in use.') return - opts,args = self.parse_options(parameter_s,'noprtglf:',mode='string') + args = parse_argstring(self.history, parameter_s) # For brevity history_manager = self.shell.history_manager @@ -116,9 +140,8 @@ class HistoryMagics(Magics): return "%s/%s" % (session, line) # Check if output to specific file was requested. - try: - outfname = opts['f'] - except KeyError: + outfname = args.filename + if not outfname: outfile = io.stdout # default # We don't want to close stdout at the end! close_at_end = False @@ -135,27 +158,27 @@ class HistoryMagics(Magics): 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) + print_nums = args.print_nums + get_output = args.get_output + pyprompts = args.pyprompts + raw = args.raw pattern = None - if 'g' in opts: # Glob search - pattern = "*" + args + "*" if args else "*" + if args.pattern is not None: + if args.pattern: + pattern = "*" + " ".join(args.pattern) + "*" + else: + pattern = "*" 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 + elif getattr(args, 'limit_specified', False): + n = 10 if args.limit is None else args.limit 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) + if args.range: # Get history by ranges + hist = history_manager.get_range_by_str(" ".join(args.range), + raw, get_output) else: # Just get history for the current session hist = history_manager.get_range(raw=raw, output=get_output)