##// END OF EJS Templates
Update history magics to new API.
Fernando Perez -
Show More
@@ -26,6 +26,7 b' import threading'
26
26
27 # Our own packages
27 # Our own packages
28 from IPython.core.error import StdinNotImplementedError
28 from IPython.core.error import StdinNotImplementedError
29 from IPython.core.magic import Magics, register_magics, line_magic
29 from IPython.config.configurable import Configurable
30 from IPython.config.configurable import Configurable
30 from IPython.external.decorator import decorator
31 from IPython.external.decorator import decorator
31 from IPython.testing.skipdoctest import skip_doctest
32 from IPython.testing.skipdoctest import skip_doctest
@@ -74,13 +75,13 b' class HistoryAccessor(Configurable):'
74 hist_file = Unicode(config=True,
75 hist_file = Unicode(config=True,
75 help="""Path to file to use for SQLite history database.
76 help="""Path to file to use for SQLite history database.
76
77
77 By default, IPython will put the history database in the IPython profile
78 By default, IPython will put the history database in the IPython
78 directory. If you would rather share one history among profiles,
79 profile directory. If you would rather share one history among
79 you ca set this value in each, so that they are consistent.
80 profiles, you ca set this value in each, so that they are consistent.
80
81
81 Due to an issue with fcntl, SQLite is known to misbehave on some NFS mounts.
82 Due to an issue with fcntl, SQLite is known to misbehave on some NFS
82 If you see IPython hanging, try setting this to something on a local disk,
83 mounts. If you see IPython hanging, try setting this to something on a
83 e.g::
84 local disk, e.g::
84
85
85 ipython --HistoryManager.hist_file=/tmp/ipython_hist.sqlite
86 ipython --HistoryManager.hist_file=/tmp/ipython_hist.sqlite
86
87
@@ -153,7 +154,8 b' class HistoryAccessor(Configurable):'
153 def init_db(self):
154 def init_db(self):
154 """Connect to the database, and create tables if necessary."""
155 """Connect to the database, and create tables if necessary."""
155 # use detect_types so that timestamps return datetime objects
156 # use detect_types so that timestamps return datetime objects
156 self.db = sqlite3.connect(self.hist_file, detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
157 self.db = sqlite3.connect(self.hist_file,
158 detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
157 self.db.execute("""CREATE TABLE IF NOT EXISTS sessions (session integer
159 self.db.execute("""CREATE TABLE IF NOT EXISTS sessions (session integer
158 primary key autoincrement, start timestamp,
160 primary key autoincrement, start timestamp,
159 end timestamp, num_cmds integer, remark text)""")
161 end timestamp, num_cmds integer, remark text)""")
@@ -216,7 +218,8 b' class HistoryAccessor(Configurable):'
216 Returns
218 Returns
217 -------
219 -------
218
220
219 (session_id [int], start [datetime], end [datetime], num_cmds [int], remark [unicode])
221 (session_id [int], start [datetime], end [datetime], num_cmds [int],
222 remark [unicode])
220
223
221 Sessions that are running or did not exit cleanly will have `end=None`
224 Sessions that are running or did not exit cleanly will have `end=None`
222 and `num_cmds=None`.
225 and `num_cmds=None`.
@@ -512,7 +515,8 b' class HistoryManager(HistoryAccessor):'
512 session += self.session_number
515 session += self.session_number
513 if session==self.session_number: # Current session
516 if session==self.session_number: # Current session
514 return self._get_range_session(start, stop, raw, output)
517 return self._get_range_session(start, stop, raw, output)
515 return super(HistoryManager, self).get_range(session, start, stop, raw, output)
518 return super(HistoryManager, self).get_range(session, start, stop, raw,
519 output)
516
520
517 ## ----------------------------
521 ## ----------------------------
518 ## Methods for storing history:
522 ## Methods for storing history:
@@ -611,7 +615,9 b' class HistoryManager(HistoryAccessor):'
611 print("ERROR! Session/line number was not unique in",
615 print("ERROR! Session/line number was not unique in",
612 "database. History logging moved to new session",
616 "database. History logging moved to new session",
613 self.session_number)
617 self.session_number)
614 try: # Try writing to the new session. If this fails, don't recurse
618 try:
619 # Try writing to the new session. If this fails, don't
620 # recurse
615 self._writeout_input_cache(conn)
621 self._writeout_input_cache(conn)
616 except sqlite3.IntegrityError:
622 except sqlite3.IntegrityError:
617 pass
623 pass
@@ -718,264 +724,270 b' def _format_lineno(session, line):'
718 return "%s#%s" % (session, line)
724 return "%s#%s" % (session, line)
719
725
720
726
721 @skip_doctest
727 @register_magics
722 def magic_history(self, parameter_s = ''):
728 class HistoryMagics(Magics):
723 """Print input history (_i<n> variables), with most recent last.
724
729
725 %history [-o -p -t -n] [-f filename] [range | -g pattern | -l number]
730 @skip_doctest
731 @line_magic
732 def history(self, parameter_s = ''):
733 """Print input history (_i<n> variables), with most recent last.
726
734
727 By default, input history is printed without line numbers so it can be
735 %history [-o -p -t -n] [-f filename] [range | -g pattern | -l number]
728 directly pasted into an editor. Use -n to show them.
729
736
730 By default, all input history from the current session is displayed.
737 By default, input history is printed without line numbers so it can be
731 Ranges of history can be indicated using the syntax:
738 directly pasted into an editor. Use -n to show them.
732 4 : Line 4, current session
733 4-6 : Lines 4-6, current session
734 243/1-5: Lines 1-5, session 243
735 ~2/7 : Line 7, session 2 before current
736 ~8/1-~6/5 : From the first line of 8 sessions ago, to the fifth line
737 of 6 sessions ago.
738 Multiple ranges can be entered, separated by spaces
739
739
740 The same syntax is used by %macro, %save, %edit, %rerun
740 By default, all input history from the current session is displayed.
741 Ranges of history can be indicated using the syntax:
742 4 : Line 4, current session
743 4-6 : Lines 4-6, current session
744 243/1-5: Lines 1-5, session 243
745 ~2/7 : Line 7, session 2 before current
746 ~8/1-~6/5 : From the first line of 8 sessions ago, to the fifth line
747 of 6 sessions ago.
748 Multiple ranges can be entered, separated by spaces
741
749
742 Options:
750 The same syntax is used by %macro, %save, %edit, %rerun
743
751
744 -n: print line numbers for each input.
752 Options:
745 This feature is only available if numbered prompts are in use.
746
753
747 -o: also print outputs for each input.
754 -n: print line numbers for each input.
755 This feature is only available if numbered prompts are in use.
748
756
749 -p: print classic '>>>' python prompts before each input. This is useful
757 -o: also print outputs for each input.
750 for making documentation, and in conjunction with -o, for producing
751 doctest-ready output.
752
758
753 -r: (default) print the 'raw' history, i.e. the actual commands you typed.
759 -p: print classic '>>>' python prompts before each input. This is
760 useful for making documentation, and in conjunction with -o, for
761 producing doctest-ready output.
754
762
755 -t: print the 'translated' history, as IPython understands it. IPython
763 -r: (default) print the 'raw' history, i.e. the actual commands you
756 filters your input and converts it all into valid Python source before
764 typed.
757 executing it (things like magics or aliases are turned into function
758 calls, for example). With this option, you'll see the native history
759 instead of the user-entered version: '%cd /' will be seen as
760 'get_ipython().magic("%cd /")' instead of '%cd /'.
761
765
762 -g: treat the arg as a pattern to grep for in (full) history.
766 -t: print the 'translated' history, as IPython understands it.
763 This includes the saved history (almost all commands ever written).
767 IPython filters your input and converts it all into valid Python
764 Use '%hist -g' to show full saved history (may be very long).
768 source before executing it (things like magics or aliases are turned
769 into function calls, for example). With this option, you'll see the
770 native history instead of the user-entered version: '%cd /' will be
771 seen as 'get_ipython().magic("%cd /")' instead of '%cd /'.
765
772
766 -l: get the last n lines from all sessions. Specify n as a single arg, or
773 -g: treat the arg as a pattern to grep for in (full) history.
767 the default is the last 10 lines.
774 This includes the saved history (almost all commands ever written).
775 Use '%hist -g' to show full saved history (may be very long).
768
776
769 -f FILENAME: instead of printing the output to the screen, redirect it to
777 -l: get the last n lines from all sessions. Specify n as a single
770 the given file. The file is always overwritten, though *when it can*,
778 arg, or the default is the last 10 lines.
771 IPython asks for confirmation first. In particular, running the command
772 "history -f FILENAME" from the IPython Notebook interface will replace
773 FILENAME even if it already exists *without* confirmation.
774
779
775 Examples
780 -f FILENAME: instead of printing the output to the screen, redirect
776 --------
781 it to the given file. The file is always overwritten, though *when
777 ::
782 it can*, IPython asks for confirmation first. In particular, running
778
783 the command 'history -f FILENAME' from the IPython Notebook
779 In [6]: %hist -n 4-6
784 interface will replace FILENAME even if it already exists *without*
780 4:a = 12
785 confirmation.
781 5:print a**2
782 6:%hist -n 4-6
783
784 """
785
786 if not self.shell.displayhook.do_full_cache:
787 print('This feature is only available if numbered prompts are in use.')
788 return
789 opts,args = self.parse_options(parameter_s,'noprtglf:',mode='string')
790
791 # For brevity
792 history_manager = self.shell.history_manager
793
794 def _format_lineno(session, line):
795 """Helper function to format line numbers properly."""
796 if session in (0, history_manager.session_number):
797 return str(line)
798 return "%s/%s" % (session, line)
799
800 # Check if output to specific file was requested.
801 try:
802 outfname = opts['f']
803 except KeyError:
804 outfile = io.stdout # default
805 # We don't want to close stdout at the end!
806 close_at_end = False
807 else:
808 if os.path.exists(outfname):
809 try:
810 ans = io.ask_yes_no("File %r exists. Overwrite?" % outfname)
811 except StdinNotImplementedError:
812 ans = True
813 if not ans:
814 print('Aborting.')
815 return
816 print("Overwriting file.")
817 outfile = io_open(outfname, 'w', encoding='utf-8')
818 close_at_end = True
819
820 print_nums = 'n' in opts
821 get_output = 'o' in opts
822 pyprompts = 'p' in opts
823 # Raw history is the default
824 raw = not('t' in opts)
825
826 default_length = 40
827 pattern = None
828
829 if 'g' in opts: # Glob search
830 pattern = "*" + args + "*" if args else "*"
831 hist = history_manager.search(pattern, raw=raw, output=get_output)
832 print_nums = True
833 elif 'l' in opts: # Get 'tail'
834 try:
835 n = int(args)
836 except ValueError, IndexError:
837 n = 10
838 hist = history_manager.get_tail(n, raw=raw, output=get_output)
839 else:
840 if args: # Get history by ranges
841 hist = history_manager.get_range_by_str(args, raw, get_output)
842 else: # Just get history for the current session
843 hist = history_manager.get_range(raw=raw, output=get_output)
844
845 # We could be displaying the entire history, so let's not try to pull it
846 # into a list in memory. Anything that needs more space will just misalign.
847 width = 4
848
849 for session, lineno, inline in hist:
850 # Print user history with tabs expanded to 4 spaces. The GUI clients
851 # use hard tabs for easier usability in auto-indented code, but we want
852 # to produce PEP-8 compliant history for safe pasting into an editor.
853 if get_output:
854 inline, output = inline
855 inline = inline.expandtabs(4).rstrip()
856
857 multiline = "\n" in inline
858 line_sep = '\n' if multiline else ' '
859 if print_nums:
860 print(u'%s:%s' % (_format_lineno(session, lineno).rjust(width),
861 line_sep), file=outfile, end=u'')
862 if pyprompts:
863 print(u">>> ", end=u"", file=outfile)
864 if multiline:
865 inline = "\n... ".join(inline.splitlines()) + "\n..."
866 print(inline, file=outfile)
867 if get_output and output:
868 print(output, file=outfile)
869
870 if close_at_end:
871 outfile.close()
872
873
874 def magic_rep(self, arg):
875 r"""Repeat a command, or get command to input line for editing.
876
877 %recall and %rep are equivalent.
878
786
879 - %recall (no arguments):
787 Examples
788 --------
789 ::
880
790
881 Place a string version of last computation result (stored in the special '_'
791 In [6]: %hist -n 4-6
882 variable) to the next input prompt. Allows you to create elaborate command
792 4:a = 12
883 lines without using copy-paste::
793 5:print a**2
794 6:%hist -n 4-6
884
795
885 In[1]: l = ["hei", "vaan"]
796 """
886 In[2]: "".join(l)
887 Out[2]: heivaan
888 In[3]: %rep
889 In[4]: heivaan_ <== cursor blinking
890
891 %recall 45
892
893 Place history line 45 on the next input prompt. Use %hist to find
894 out the number.
895
797
896 %recall 1-4
798 if not self.shell.displayhook.do_full_cache:
799 print('This feature is only available if numbered prompts '
800 'are in use.')
801 return
802 opts,args = self.parse_options(parameter_s,'noprtglf:',mode='string')
897
803
898 Combine the specified lines into one cell, and place it on the next
804 # For brevity
899 input prompt. See %history for the slice syntax.
805 history_manager = self.shell.history_manager
900
806
901 %recall foo+bar
807 def _format_lineno(session, line):
808 """Helper function to format line numbers properly."""
809 if session in (0, history_manager.session_number):
810 return str(line)
811 return "%s/%s" % (session, line)
902
812
903 If foo+bar can be evaluated in the user namespace, the result is
813 # Check if output to specific file was requested.
904 placed at the next input prompt. Otherwise, the history is searched
814 try:
905 for lines which contain that substring, and the most recent one is
815 outfname = opts['f']
906 placed at the next input prompt.
816 except KeyError:
907 """
817 outfile = io.stdout # default
908 if not arg: # Last output
818 # We don't want to close stdout at the end!
909 self.shell.set_next_input(str(self.shell.user_ns["_"]))
819 close_at_end = False
910 return
820 else:
911 # Get history range
821 if os.path.exists(outfname):
912 histlines = self.shell.history_manager.get_range_by_str(arg)
822 try:
913 cmd = "\n".join(x[2] for x in histlines)
823 ans = io.ask_yes_no("File %r exists. Overwrite?" % outfname)
914 if cmd:
824 except StdinNotImplementedError:
915 self.shell.set_next_input(cmd.rstrip())
825 ans = True
916 return
826 if not ans:
917
827 print('Aborting.')
918 try: # Variable in user namespace
828 return
919 cmd = str(eval(arg, self.shell.user_ns))
829 print("Overwriting file.")
920 except Exception: # Search for term in history
830 outfile = io_open(outfname, 'w', encoding='utf-8')
921 histlines = self.shell.history_manager.search("*"+arg+"*")
831 close_at_end = True
922 for h in reversed([x[2] for x in histlines]):
832
923 if 'rep' in h:
833 print_nums = 'n' in opts
924 continue
834 get_output = 'o' in opts
925 self.shell.set_next_input(h.rstrip())
835 pyprompts = 'p' in opts
836 # Raw history is the default
837 raw = not('t' in opts)
838
839 pattern = None
840
841 if 'g' in opts: # Glob search
842 pattern = "*" + args + "*" if args else "*"
843 hist = history_manager.search(pattern, raw=raw, output=get_output)
844 print_nums = True
845 elif 'l' in opts: # Get 'tail'
846 try:
847 n = int(args)
848 except (ValueError, IndexError):
849 n = 10
850 hist = history_manager.get_tail(n, raw=raw, output=get_output)
851 else:
852 if args: # Get history by ranges
853 hist = history_manager.get_range_by_str(args, raw, get_output)
854 else: # Just get history for the current session
855 hist = history_manager.get_range(raw=raw, output=get_output)
856
857 # We could be displaying the entire history, so let's not try to pull
858 # it into a list in memory. Anything that needs more space will just
859 # misalign.
860 width = 4
861
862 for session, lineno, inline in hist:
863 # Print user history with tabs expanded to 4 spaces. The GUI
864 # clients use hard tabs for easier usability in auto-indented code,
865 # but we want to produce PEP-8 compliant history for safe pasting
866 # into an editor.
867 if get_output:
868 inline, output = inline
869 inline = inline.expandtabs(4).rstrip()
870
871 multiline = "\n" in inline
872 line_sep = '\n' if multiline else ' '
873 if print_nums:
874 print(u'%s:%s' % (_format_lineno(session, lineno).rjust(width),
875 line_sep), file=outfile, end=u'')
876 if pyprompts:
877 print(u">>> ", end=u"", file=outfile)
878 if multiline:
879 inline = "\n... ".join(inline.splitlines()) + "\n..."
880 print(inline, file=outfile)
881 if get_output and output:
882 print(output, file=outfile)
883
884 if close_at_end:
885 outfile.close()
886
887 @line_magic
888 def rep(self, arg):
889 r"""Repeat a command, or get command to input line for editing.
890
891 %recall and %rep are equivalent.
892
893 - %recall (no arguments):
894
895 Place a string version of last computation result (stored in the
896 special '_' variable) to the next input prompt. Allows you to create
897 elaborate command lines without using copy-paste::
898
899 In[1]: l = ["hei", "vaan"]
900 In[2]: "".join(l)
901 Out[2]: heivaan
902 In[3]: %rep
903 In[4]: heivaan_ <== cursor blinking
904
905 %recall 45
906
907 Place history line 45 on the next input prompt. Use %hist to find
908 out the number.
909
910 %recall 1-4
911
912 Combine the specified lines into one cell, and place it on the next
913 input prompt. See %history for the slice syntax.
914
915 %recall foo+bar
916
917 If foo+bar can be evaluated in the user namespace, the result is
918 placed at the next input prompt. Otherwise, the history is searched
919 for lines which contain that substring, and the most recent one is
920 placed at the next input prompt.
921 """
922 if not arg: # Last output
923 self.shell.set_next_input(str(self.shell.user_ns["_"]))
924 return
925 # Get history range
926 histlines = self.shell.history_manager.get_range_by_str(arg)
927 cmd = "\n".join(x[2] for x in histlines)
928 if cmd:
929 self.shell.set_next_input(cmd.rstrip())
926 return
930 return
927 else:
928 self.shell.set_next_input(cmd.rstrip())
929 print("Couldn't evaluate or find in history:", arg)
930
931
932 try: # Variable in user namespace
933 cmd = str(eval(arg, self.shell.user_ns))
934 except Exception: # Search for term in history
935 histlines = self.shell.history_manager.search("*"+arg+"*")
936 for h in reversed([x[2] for x in histlines]):
937 if 'rep' in h:
938 continue
939 self.shell.set_next_input(h.rstrip())
940 return
941 else:
942 self.shell.set_next_input(cmd.rstrip())
943 print("Couldn't evaluate or find in history:", arg)
931
944
932 def magic_rerun(self, parameter_s=''):
945 @line_magic
933 """Re-run previous input
946 def rerun(self, parameter_s=''):
947 """Re-run previous input
934
948
935 By default, you can specify ranges of input history to be repeated
949 By default, you can specify ranges of input history to be repeated
936 (as with %history). With no arguments, it will repeat the last line.
950 (as with %history). With no arguments, it will repeat the last line.
937
951
938 Options:
952 Options:
939
953
940 -l <n> : Repeat the last n lines of input, not including the
954 -l <n> : Repeat the last n lines of input, not including the
941 current command.
955 current command.
942
956
943 -g foo : Repeat the most recent line which contains foo
957 -g foo : Repeat the most recent line which contains foo
944 """
958 """
945 opts, args = self.parse_options(parameter_s, 'l:g:', mode='string')
959 opts, args = self.parse_options(parameter_s, 'l:g:', mode='string')
946 if "l" in opts: # Last n lines
960 if "l" in opts: # Last n lines
947 n = int(opts['l'])
961 n = int(opts['l'])
948 hist = self.shell.history_manager.get_tail(n)
962 hist = self.shell.history_manager.get_tail(n)
949 elif "g" in opts: # Search
963 elif "g" in opts: # Search
950 p = "*"+opts['g']+"*"
964 p = "*"+opts['g']+"*"
951 hist = list(self.shell.history_manager.search(p))
965 hist = list(self.shell.history_manager.search(p))
952 for l in reversed(hist):
966 for l in reversed(hist):
953 if "rerun" not in l[2]:
967 if "rerun" not in l[2]:
954 hist = [l] # The last match which isn't a %rerun
968 hist = [l] # The last match which isn't a %rerun
955 break
969 break
956 else:
970 else:
957 hist = [] # No matches except %rerun
971 hist = [] # No matches except %rerun
958 elif args: # Specify history ranges
972 elif args: # Specify history ranges
959 hist = self.shell.history_manager.get_range_by_str(args)
973 hist = self.shell.history_manager.get_range_by_str(args)
960 else: # Last line
974 else: # Last line
961 hist = self.shell.history_manager.get_tail(1)
975 hist = self.shell.history_manager.get_tail(1)
962 hist = [x[2] for x in hist]
976 hist = [x[2] for x in hist]
963 if not hist:
977 if not hist:
964 print("No lines in history match specification")
978 print("No lines in history match specification")
965 return
979 return
966 histlines = "\n".join(hist)
980 histlines = "\n".join(hist)
967 print("=== Executing: ===")
981 print("=== Executing: ===")
968 print(histlines)
982 print(histlines)
969 print("=== Output: ===")
983 print("=== Output: ===")
970 self.shell.run_cell("\n".join(hist), store_history=False)
984 self.shell.run_cell("\n".join(hist), store_history=False)
971
985
972
986
973 def init_ipython(ip):
987 def init_ipython(ip):
974 ip.define_magic("rep", magic_rep)
988 ip.magics_manager.register(HistoryMagics)
975 ip.define_magic("recall", magic_rep)
989 #ip.define_magic('hist', HistoryMagics.history)
976 ip.define_magic("rerun", magic_rerun)
990 #ip.define_magic('recall', HistoryMagics.rep)
977 ip.define_magic("hist", magic_history) # Alternative name
978 ip.define_magic("history", magic_history)
979
991
980 # XXX - ipy_completers are in quarantine, need to be updated to new apis
992 # XXX - ipy_completers are in quarantine, need to be updated to new apis
981 #import ipy_completers
993 #import ipy_completers
General Comments 0
You need to be logged in to leave comments. Login now