##// END OF EJS Templates
Allow history database access without a shell.
Thomas Kluyver -
Show More
@@ -1,853 +1,883 b''
1 """ History related magics and functionality """
1 """ History related magics and functionality """
2 #-----------------------------------------------------------------------------
2 #-----------------------------------------------------------------------------
3 # Copyright (C) 2010 The IPython Development Team.
3 # Copyright (C) 2010 The IPython Development Team.
4 #
4 #
5 # Distributed under the terms of the BSD License.
5 # Distributed under the terms of the BSD License.
6 #
6 #
7 # The full license is in the file COPYING.txt, distributed with this software.
7 # The full license is in the file COPYING.txt, distributed with this software.
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Imports
11 # Imports
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 from __future__ import print_function
13 from __future__ import print_function
14
14
15 # Stdlib imports
15 # Stdlib imports
16 import atexit
16 import atexit
17 import datetime
17 import datetime
18 import os
18 import os
19 import re
19 import re
20 import sqlite3
20 import sqlite3
21 import threading
21 import threading
22
22
23 # Our own packages
23 # Our own packages
24 from IPython.config.configurable import Configurable
24 from IPython.config.configurable import Configurable
25
25
26 from IPython.testing.skipdoctest import skip_doctest
26 from IPython.testing.skipdoctest import skip_doctest
27 from IPython.utils import io
27 from IPython.utils import io
28 from IPython.utils.traitlets import Bool, Dict, Instance, Int, CInt, List, Unicode
28 from IPython.utils.traitlets import Bool, Dict, Instance, Int, CInt, List, Unicode
29 from IPython.utils.warn import warn
29 from IPython.utils.warn import warn
30
30
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32 # Classes and functions
32 # Classes and functions
33 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
34
34
35 class HistoryAccessor(Configurable):
35 class HistoryAccessor(Configurable):
36 """Access the history database without adding to it. For use by standalone
36 """Access the history database without adding to it. For use by standalone
37 history tools."""
37 history tools."""
38 # String holding the path to the history file
38 # String holding the path to the history file
39 hist_file = Unicode(config=True)
39 hist_file = Unicode(config=True)
40
40
41 # The SQLite database
41 # The SQLite database
42 db = Instance(sqlite3.Connection)
42 db = Instance(sqlite3.Connection)
43
43
44 def __init__(self, hist_file=u'', shell=None, config=None, **traits):
44 def __init__(self, hist_file=u'', shell=None, config=None, **traits):
45 """Create a new history accessor.
45 """Create a new history accessor.
46
46
47 hist_file must be given, either as an argument or through config.
47 hist_file must be given, either as an argument or through config.
48 """
48 """
49 # We need a pointer back to the shell for various tasks.
49 # We need a pointer back to the shell for various tasks.
50 super(HistoryAccessor, self).__init__(shell=shell, config=config,
50 super(HistoryAccessor, self).__init__(shell=shell, config=config,
51 hist_file=hist_file, **traits)
51 hist_file=hist_file, **traits)
52
52
53 if self.hist_file == u'':
53 if self.hist_file == u'':
54 # No one has set the hist_file, yet.
54 # No one has set the hist_file, yet.
55 self.hist_file = self._get_hist_file_name(hist_file)
55 self.hist_file = self._get_hist_file_name(hist_file)
56
56
57 try:
57 try:
58 self.init_db()
58 self.init_db()
59 except sqlite3.DatabaseError:
59 except sqlite3.DatabaseError:
60 if os.path.isfile(self.hist_file):
60 if os.path.isfile(self.hist_file):
61 # Try to move the file out of the way.
61 # Try to move the file out of the way.
62 newpath = os.path.join(self.shell.profile_dir.location, "hist-corrupt.sqlite")
62 newpath = os.path.join(self.shell.profile_dir.location, "hist-corrupt.sqlite")
63 os.rename(self.hist_file, newpath)
63 os.rename(self.hist_file, newpath)
64 print("ERROR! History file wasn't a valid SQLite database.",
64 print("ERROR! History file wasn't a valid SQLite database.",
65 "It was moved to %s" % newpath, "and a new file created.")
65 "It was moved to %s" % newpath, "and a new file created.")
66 self.init_db()
66 self.init_db()
67 else:
67 else:
68 # The hist_file is probably :memory: or something else.
68 # The hist_file is probably :memory: or something else.
69 raise
69 raise
70
70
71 def _get_hist_file_name(self, hist_file=None):
71 def _get_hist_file_name(self, hist_file=None):
72 "Override to produce a default history file name."
72 "Override to produce a default history file name."
73 raise NotImplementedError("No default history file")
73 raise NotImplementedError("No default history file")
74
74
75 def init_db(self):
75 def init_db(self):
76 """Connect to the database, and create tables if necessary."""
76 """Connect to the database, and create tables if necessary."""
77 # use detect_types so that timestamps return datetime objects
77 # use detect_types so that timestamps return datetime objects
78 self.db = sqlite3.connect(self.hist_file, detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
78 self.db = sqlite3.connect(self.hist_file, detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
79 self.db.execute("""CREATE TABLE IF NOT EXISTS sessions (session integer
79 self.db.execute("""CREATE TABLE IF NOT EXISTS sessions (session integer
80 primary key autoincrement, start timestamp,
80 primary key autoincrement, start timestamp,
81 end timestamp, num_cmds integer, remark text)""")
81 end timestamp, num_cmds integer, remark text)""")
82 self.db.execute("""CREATE TABLE IF NOT EXISTS history
82 self.db.execute("""CREATE TABLE IF NOT EXISTS history
83 (session integer, line integer, source text, source_raw text,
83 (session integer, line integer, source text, source_raw text,
84 PRIMARY KEY (session, line))""")
84 PRIMARY KEY (session, line))""")
85 # Output history is optional, but ensure the table's there so it can be
85 # Output history is optional, but ensure the table's there so it can be
86 # enabled later.
86 # enabled later.
87 self.db.execute("""CREATE TABLE IF NOT EXISTS output_history
87 self.db.execute("""CREATE TABLE IF NOT EXISTS output_history
88 (session integer, line integer, output text,
88 (session integer, line integer, output text,
89 PRIMARY KEY (session, line))""")
89 PRIMARY KEY (session, line))""")
90 self.db.commit()
90 self.db.commit()
91
91
92 def writeout_cache(self):
93 """Overridden by HistoryManager to dump the cache before certain
94 database lookups."""
95 pass
96
92 ## -------------------------------
97 ## -------------------------------
93 ## Methods for retrieving history:
98 ## Methods for retrieving history:
94 ## -------------------------------
99 ## -------------------------------
95 def _run_sql(self, sql, params, raw=True, output=False):
100 def _run_sql(self, sql, params, raw=True, output=False):
96 """Prepares and runs an SQL query for the history database.
101 """Prepares and runs an SQL query for the history database.
97
102
98 Parameters
103 Parameters
99 ----------
104 ----------
100 sql : str
105 sql : str
101 Any filtering expressions to go after SELECT ... FROM ...
106 Any filtering expressions to go after SELECT ... FROM ...
102 params : tuple
107 params : tuple
103 Parameters passed to the SQL query (to replace "?")
108 Parameters passed to the SQL query (to replace "?")
104 raw, output : bool
109 raw, output : bool
105 See :meth:`get_range`
110 See :meth:`get_range`
106
111
107 Returns
112 Returns
108 -------
113 -------
109 Tuples as :meth:`get_range`
114 Tuples as :meth:`get_range`
110 """
115 """
111 toget = 'source_raw' if raw else 'source'
116 toget = 'source_raw' if raw else 'source'
112 sqlfrom = "history"
117 sqlfrom = "history"
113 if output:
118 if output:
114 sqlfrom = "history LEFT JOIN output_history USING (session, line)"
119 sqlfrom = "history LEFT JOIN output_history USING (session, line)"
115 toget = "history.%s, output_history.output" % toget
120 toget = "history.%s, output_history.output" % toget
116 cur = self.db.execute("SELECT session, line, %s FROM %s " %\
121 cur = self.db.execute("SELECT session, line, %s FROM %s " %\
117 (toget, sqlfrom) + sql, params)
122 (toget, sqlfrom) + sql, params)
118 if output: # Regroup into 3-tuples, and parse JSON
123 if output: # Regroup into 3-tuples, and parse JSON
119 return ((ses, lin, (inp, out)) for ses, lin, inp, out in cur)
124 return ((ses, lin, (inp, out)) for ses, lin, inp, out in cur)
120 return cur
125 return cur
121
126
122
123 def get_session_info(self, session=0):
127 def get_session_info(self, session=0):
124 """get info about a session
128 """get info about a session
125
129
126 Parameters
130 Parameters
127 ----------
131 ----------
128
132
129 session : int
133 session : int
130 Session number to retrieve. The current session is 0, and negative
134 Session number to retrieve. The current session is 0, and negative
131 numbers count back from current session, so -1 is previous session.
135 numbers count back from current session, so -1 is previous session.
132
136
133 Returns
137 Returns
134 -------
138 -------
135
139
136 (session_id [int], start [datetime], end [datetime], num_cmds [int], remark [unicode])
140 (session_id [int], start [datetime], end [datetime], num_cmds [int], remark [unicode])
137
141
138 Sessions that are running or did not exit cleanly will have `end=None`
142 Sessions that are running or did not exit cleanly will have `end=None`
139 and `num_cmds=None`.
143 and `num_cmds=None`.
140
144
141 """
145 """
142
146
143 if session <= 0:
147 if session <= 0:
144 session += self.session_number
148 session += self.session_number
145
149
146 query = "SELECT * from sessions where session == ?"
150 query = "SELECT * from sessions where session == ?"
147 return self.db.execute(query, (session,)).fetchone()
151 return self.db.execute(query, (session,)).fetchone()
148
152
149
150 def get_tail(self, n=10, raw=True, output=False, include_latest=False):
153 def get_tail(self, n=10, raw=True, output=False, include_latest=False):
151 """Get the last n lines from the history database.
154 """Get the last n lines from the history database.
152
155
153 Parameters
156 Parameters
154 ----------
157 ----------
155 n : int
158 n : int
156 The number of lines to get
159 The number of lines to get
157 raw, output : bool
160 raw, output : bool
158 See :meth:`get_range`
161 See :meth:`get_range`
159 include_latest : bool
162 include_latest : bool
160 If False (default), n+1 lines are fetched, and the latest one
163 If False (default), n+1 lines are fetched, and the latest one
161 is discarded. This is intended to be used where the function
164 is discarded. This is intended to be used where the function
162 is called by a user command, which it should not return.
165 is called by a user command, which it should not return.
163
166
164 Returns
167 Returns
165 -------
168 -------
166 Tuples as :meth:`get_range`
169 Tuples as :meth:`get_range`
167 """
170 """
168 self.writeout_cache()
171 self.writeout_cache()
169 if not include_latest:
172 if not include_latest:
170 n += 1
173 n += 1
171 cur = self._run_sql("ORDER BY session DESC, line DESC LIMIT ?",
174 cur = self._run_sql("ORDER BY session DESC, line DESC LIMIT ?",
172 (n,), raw=raw, output=output)
175 (n,), raw=raw, output=output)
173 if not include_latest:
176 if not include_latest:
174 return reversed(list(cur)[1:])
177 return reversed(list(cur)[1:])
175 return reversed(list(cur))
178 return reversed(list(cur))
176
179
177 def search(self, pattern="*", raw=True, search_raw=True,
180 def search(self, pattern="*", raw=True, search_raw=True,
178 output=False):
181 output=False):
179 """Search the database using unix glob-style matching (wildcards
182 """Search the database using unix glob-style matching (wildcards
180 * and ?).
183 * and ?).
181
184
182 Parameters
185 Parameters
183 ----------
186 ----------
184 pattern : str
187 pattern : str
185 The wildcarded pattern to match when searching
188 The wildcarded pattern to match when searching
186 search_raw : bool
189 search_raw : bool
187 If True, search the raw input, otherwise, the parsed input
190 If True, search the raw input, otherwise, the parsed input
188 raw, output : bool
191 raw, output : bool
189 See :meth:`get_range`
192 See :meth:`get_range`
190
193
191 Returns
194 Returns
192 -------
195 -------
193 Tuples as :meth:`get_range`
196 Tuples as :meth:`get_range`
194 """
197 """
195 tosearch = "source_raw" if search_raw else "source"
198 tosearch = "source_raw" if search_raw else "source"
196 if output:
199 if output:
197 tosearch = "history." + tosearch
200 tosearch = "history." + tosearch
198 self.writeout_cache()
201 self.writeout_cache()
199 return self._run_sql("WHERE %s GLOB ?" % tosearch, (pattern,),
202 return self._run_sql("WHERE %s GLOB ?" % tosearch, (pattern,),
200 raw=raw, output=output)
203 raw=raw, output=output)
201
204
202 def get_range(self, session=0, start=1, stop=None, raw=True,output=False):
205 def get_range(self, session, start=1, stop=None, raw=True,output=False):
203 """Retrieve input by session.
206 """Retrieve input by session.
204
207
205 Parameters
208 Parameters
206 ----------
209 ----------
207 session : int
210 session : int
208 Session number to retrieve. The current session is 0, and negative
211 Session number to retrieve.
209 numbers count back from current session, so -1 is previous session.
210 start : int
212 start : int
211 First line to retrieve.
213 First line to retrieve.
212 stop : int
214 stop : int
213 End of line range (excluded from output itself). If None, retrieve
215 End of line range (excluded from output itself). If None, retrieve
214 to the end of the session.
216 to the end of the session.
215 raw : bool
217 raw : bool
216 If True, return untranslated input
218 If True, return untranslated input
217 output : bool
219 output : bool
218 If True, attempt to include output. This will be 'real' Python
220 If True, attempt to include output. This will be 'real' Python
219 objects for the current session, or text reprs from previous
221 objects for the current session, or text reprs from previous
220 sessions if db_log_output was enabled at the time. Where no output
222 sessions if db_log_output was enabled at the time. Where no output
221 is found, None is used.
223 is found, None is used.
222
224
223 Returns
225 Returns
224 -------
226 -------
225 An iterator over the desired lines. Each line is a 3-tuple, either
227 An iterator over the desired lines. Each line is a 3-tuple, either
226 (session, line, input) if output is False, or
228 (session, line, input) if output is False, or
227 (session, line, (input, output)) if output is True.
229 (session, line, (input, output)) if output is True.
228 """
230 """
229 if session == 0 or session==self.session_number: # Current session
230 return self._get_range_session(start, stop, raw, output)
231 if session < 0:
232 session += self.session_number
233
234 if stop:
231 if stop:
235 lineclause = "line >= ? AND line < ?"
232 lineclause = "line >= ? AND line < ?"
236 params = (session, start, stop)
233 params = (session, start, stop)
237 else:
234 else:
238 lineclause = "line>=?"
235 lineclause = "line>=?"
239 params = (session, start)
236 params = (session, start)
240
237
241 return self._run_sql("WHERE session==? AND %s""" % lineclause,
238 return self._run_sql("WHERE session==? AND %s""" % lineclause,
242 params, raw=raw, output=output)
239 params, raw=raw, output=output)
243
240
244 def get_range_by_str(self, rangestr, raw=True, output=False):
241 def get_range_by_str(self, rangestr, raw=True, output=False):
245 """Get lines of history from a string of ranges, as used by magic
242 """Get lines of history from a string of ranges, as used by magic
246 commands %hist, %save, %macro, etc.
243 commands %hist, %save, %macro, etc.
247
244
248 Parameters
245 Parameters
249 ----------
246 ----------
250 rangestr : str
247 rangestr : str
251 A string specifying ranges, e.g. "5 ~2/1-4". See
248 A string specifying ranges, e.g. "5 ~2/1-4". See
252 :func:`magic_history` for full details.
249 :func:`magic_history` for full details.
253 raw, output : bool
250 raw, output : bool
254 As :meth:`get_range`
251 As :meth:`get_range`
255
252
256 Returns
253 Returns
257 -------
254 -------
258 Tuples as :meth:`get_range`
255 Tuples as :meth:`get_range`
259 """
256 """
260 for sess, s, e in extract_hist_ranges(rangestr):
257 for sess, s, e in extract_hist_ranges(rangestr):
261 for line in self.get_range(sess, s, e, raw=raw, output=output):
258 for line in self.get_range(sess, s, e, raw=raw, output=output):
262 yield line
259 yield line
263
260
264
261
265 class HistoryManager(HistoryAccessor):
262 class HistoryManager(HistoryAccessor):
266 """A class to organize all history-related functionality in one place.
263 """A class to organize all history-related functionality in one place.
267 """
264 """
268 # Public interface
265 # Public interface
269
266
270 # An instance of the IPython shell we are attached to
267 # An instance of the IPython shell we are attached to
271 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
268 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
272 # Lists to hold processed and raw history. These start with a blank entry
269 # Lists to hold processed and raw history. These start with a blank entry
273 # so that we can index them starting from 1
270 # so that we can index them starting from 1
274 input_hist_parsed = List([""])
271 input_hist_parsed = List([""])
275 input_hist_raw = List([""])
272 input_hist_raw = List([""])
276 # A list of directories visited during session
273 # A list of directories visited during session
277 dir_hist = List()
274 dir_hist = List()
278 def _dir_hist_default(self):
275 def _dir_hist_default(self):
279 try:
276 try:
280 return [os.getcwdu()]
277 return [os.getcwdu()]
281 except OSError:
278 except OSError:
282 return []
279 return []
283
280
284 # A dict of output history, keyed with ints from the shell's
281 # A dict of output history, keyed with ints from the shell's
285 # execution count.
282 # execution count.
286 output_hist = Dict()
283 output_hist = Dict()
287 # The text/plain repr of outputs.
284 # The text/plain repr of outputs.
288 output_hist_reprs = Dict()
285 output_hist_reprs = Dict()
289
286
290 # The number of the current session in the history database
287 # The number of the current session in the history database
291 session_number = CInt()
288 session_number = CInt()
292 # Should we log output to the database? (default no)
289 # Should we log output to the database? (default no)
293 db_log_output = Bool(False, config=True)
290 db_log_output = Bool(False, config=True)
294 # Write to database every x commands (higher values save disk access & power)
291 # Write to database every x commands (higher values save disk access & power)
295 # Values of 1 or less effectively disable caching.
292 # Values of 1 or less effectively disable caching.
296 db_cache_size = Int(0, config=True)
293 db_cache_size = Int(0, config=True)
297 # The input and output caches
294 # The input and output caches
298 db_input_cache = List()
295 db_input_cache = List()
299 db_output_cache = List()
296 db_output_cache = List()
300
297
301 # History saving in separate thread
298 # History saving in separate thread
302 save_thread = Instance('IPython.core.history.HistorySavingThread')
299 save_thread = Instance('IPython.core.history.HistorySavingThread')
303 try: # Event is a function returning an instance of _Event...
300 try: # Event is a function returning an instance of _Event...
304 save_flag = Instance(threading._Event)
301 save_flag = Instance(threading._Event)
305 except AttributeError: # ...until Python 3.3, when it's a class.
302 except AttributeError: # ...until Python 3.3, when it's a class.
306 save_flag = Instance(threading.Event)
303 save_flag = Instance(threading.Event)
307
304
308 # Private interface
305 # Private interface
309 # Variables used to store the three last inputs from the user. On each new
306 # Variables used to store the three last inputs from the user. On each new
310 # history update, we populate the user's namespace with these, shifted as
307 # history update, we populate the user's namespace with these, shifted as
311 # necessary.
308 # necessary.
312 _i00 = Unicode(u'')
309 _i00 = Unicode(u'')
313 _i = Unicode(u'')
310 _i = Unicode(u'')
314 _ii = Unicode(u'')
311 _ii = Unicode(u'')
315 _iii = Unicode(u'')
312 _iii = Unicode(u'')
316
313
317 # A regex matching all forms of the exit command, so that we don't store
314 # A regex matching all forms of the exit command, so that we don't store
318 # them in the history (it's annoying to rewind the first entry and land on
315 # them in the history (it's annoying to rewind the first entry and land on
319 # an exit call).
316 # an exit call).
320 _exit_re = re.compile(r"(exit|quit)(\s*\(.*\))?$")
317 _exit_re = re.compile(r"(exit|quit)(\s*\(.*\))?$")
321
318
322 def __init__(self, shell=None, config=None, **traits):
319 def __init__(self, shell=None, config=None, **traits):
323 """Create a new history manager associated with a shell instance.
320 """Create a new history manager associated with a shell instance.
324 """
321 """
325 # We need a pointer back to the shell for various tasks.
322 # We need a pointer back to the shell for various tasks.
326 super(HistoryManager, self).__init__(shell=shell, config=config,
323 super(HistoryManager, self).__init__(shell=shell, config=config,
327 **traits)
324 **traits)
328 self.save_flag = threading.Event()
325 self.save_flag = threading.Event()
329 self.db_input_cache_lock = threading.Lock()
326 self.db_input_cache_lock = threading.Lock()
330 self.db_output_cache_lock = threading.Lock()
327 self.db_output_cache_lock = threading.Lock()
331 self.save_thread = HistorySavingThread(self)
328 self.save_thread = HistorySavingThread(self)
332 self.save_thread.start()
329 self.save_thread.start()
333
330
334 self.new_session()
331 self.new_session()
335
332
336 def _get_hist_file_name(self, hist_file=None):
333 def _get_hist_file_name(self, hist_file=None):
337 profile_dir = self.shell.profile_dir.location
334 profile_dir = self.shell.profile_dir.location
338 return os.path.join(profile_dir, 'history.sqlite')
335 return os.path.join(profile_dir, 'history.sqlite')
339
336
340 def new_session(self, conn=None):
337 def new_session(self, conn=None):
341 """Get a new session number."""
338 """Get a new session number."""
342 if conn is None:
339 if conn is None:
343 conn = self.db
340 conn = self.db
344
341
345 with conn:
342 with conn:
346 cur = conn.execute("""INSERT INTO sessions VALUES (NULL, ?, NULL,
343 cur = conn.execute("""INSERT INTO sessions VALUES (NULL, ?, NULL,
347 NULL, "") """, (datetime.datetime.now(),))
344 NULL, "") """, (datetime.datetime.now(),))
348 self.session_number = cur.lastrowid
345 self.session_number = cur.lastrowid
349
346
350 def end_session(self):
347 def end_session(self):
351 """Close the database session, filling in the end time and line count."""
348 """Close the database session, filling in the end time and line count."""
352 self.writeout_cache()
349 self.writeout_cache()
353 with self.db:
350 with self.db:
354 self.db.execute("""UPDATE sessions SET end=?, num_cmds=? WHERE
351 self.db.execute("""UPDATE sessions SET end=?, num_cmds=? WHERE
355 session==?""", (datetime.datetime.now(),
352 session==?""", (datetime.datetime.now(),
356 len(self.input_hist_parsed)-1, self.session_number))
353 len(self.input_hist_parsed)-1, self.session_number))
357 self.session_number = 0
354 self.session_number = 0
358
355
359 def name_session(self, name):
356 def name_session(self, name):
360 """Give the current session a name in the history database."""
357 """Give the current session a name in the history database."""
361 with self.db:
358 with self.db:
362 self.db.execute("UPDATE sessions SET remark=? WHERE session==?",
359 self.db.execute("UPDATE sessions SET remark=? WHERE session==?",
363 (name, self.session_number))
360 (name, self.session_number))
364
361
365 def reset(self, new_session=True):
362 def reset(self, new_session=True):
366 """Clear the session history, releasing all object references, and
363 """Clear the session history, releasing all object references, and
367 optionally open a new session."""
364 optionally open a new session."""
368 self.output_hist.clear()
365 self.output_hist.clear()
369 # The directory history can't be completely empty
366 # The directory history can't be completely empty
370 self.dir_hist[:] = [os.getcwdu()]
367 self.dir_hist[:] = [os.getcwdu()]
371
368
372 if new_session:
369 if new_session:
373 if self.session_number:
370 if self.session_number:
374 self.end_session()
371 self.end_session()
375 self.input_hist_parsed[:] = [""]
372 self.input_hist_parsed[:] = [""]
376 self.input_hist_raw[:] = [""]
373 self.input_hist_raw[:] = [""]
377 self.new_session()
374 self.new_session()
378
375
379 # ------------------------------
376 # ------------------------------
380 # Methods for retrieving history
377 # Methods for retrieving history
381 # ------------------------------
378 # ------------------------------
382 def _get_range_session(self, start=1, stop=None, raw=True, output=False):
379 def _get_range_session(self, start=1, stop=None, raw=True, output=False):
383 """Get input and output history from the current session. Called by
380 """Get input and output history from the current session. Called by
384 get_range, and takes similar parameters."""
381 get_range, and takes similar parameters."""
385 input_hist = self.input_hist_raw if raw else self.input_hist_parsed
382 input_hist = self.input_hist_raw if raw else self.input_hist_parsed
386
383
387 n = len(input_hist)
384 n = len(input_hist)
388 if start < 0:
385 if start < 0:
389 start += n
386 start += n
390 if not stop or (stop > n):
387 if not stop or (stop > n):
391 stop = n
388 stop = n
392 elif stop < 0:
389 elif stop < 0:
393 stop += n
390 stop += n
394
391
395 for i in range(start, stop):
392 for i in range(start, stop):
396 if output:
393 if output:
397 line = (input_hist[i], self.output_hist_reprs.get(i))
394 line = (input_hist[i], self.output_hist_reprs.get(i))
398 else:
395 else:
399 line = input_hist[i]
396 line = input_hist[i]
400 yield (0, i, line)
397 yield (0, i, line)
398
399 def get_range(self, session, start=1, stop=None, raw=True,output=False):
400 """Retrieve input by session.
401
402 Parameters
403 ----------
404 session : int
405 Session number to retrieve. The current session is 0, and negative
406 numbers count back from current session, so -1 is previous session.
407 start : int
408 First line to retrieve.
409 stop : int
410 End of line range (excluded from output itself). If None, retrieve
411 to the end of the session.
412 raw : bool
413 If True, return untranslated input
414 output : bool
415 If True, attempt to include output. This will be 'real' Python
416 objects for the current session, or text reprs from previous
417 sessions if db_log_output was enabled at the time. Where no output
418 is found, None is used.
419
420 Returns
421 -------
422 An iterator over the desired lines. Each line is a 3-tuple, either
423 (session, line, input) if output is False, or
424 (session, line, (input, output)) if output is True.
425 """
426 if session <= 0:
427 session += self.session_number
428 if session==self.session_number: # Current session
429 return self._get_range_session(start, stop, raw, output)
430 return super(HistoryManager, self).get_range(session, start, stop, raw, output)
401
431
402 ## ----------------------------
432 ## ----------------------------
403 ## Methods for storing history:
433 ## Methods for storing history:
404 ## ----------------------------
434 ## ----------------------------
405 def store_inputs(self, line_num, source, source_raw=None):
435 def store_inputs(self, line_num, source, source_raw=None):
406 """Store source and raw input in history and create input cache
436 """Store source and raw input in history and create input cache
407 variables _i*.
437 variables _i*.
408
438
409 Parameters
439 Parameters
410 ----------
440 ----------
411 line_num : int
441 line_num : int
412 The prompt number of this input.
442 The prompt number of this input.
413
443
414 source : str
444 source : str
415 Python input.
445 Python input.
416
446
417 source_raw : str, optional
447 source_raw : str, optional
418 If given, this is the raw input without any IPython transformations
448 If given, this is the raw input without any IPython transformations
419 applied to it. If not given, ``source`` is used.
449 applied to it. If not given, ``source`` is used.
420 """
450 """
421 if source_raw is None:
451 if source_raw is None:
422 source_raw = source
452 source_raw = source
423 source = source.rstrip('\n')
453 source = source.rstrip('\n')
424 source_raw = source_raw.rstrip('\n')
454 source_raw = source_raw.rstrip('\n')
425
455
426 # do not store exit/quit commands
456 # do not store exit/quit commands
427 if self._exit_re.match(source_raw.strip()):
457 if self._exit_re.match(source_raw.strip()):
428 return
458 return
429
459
430 self.input_hist_parsed.append(source)
460 self.input_hist_parsed.append(source)
431 self.input_hist_raw.append(source_raw)
461 self.input_hist_raw.append(source_raw)
432
462
433 with self.db_input_cache_lock:
463 with self.db_input_cache_lock:
434 self.db_input_cache.append((line_num, source, source_raw))
464 self.db_input_cache.append((line_num, source, source_raw))
435 # Trigger to flush cache and write to DB.
465 # Trigger to flush cache and write to DB.
436 if len(self.db_input_cache) >= self.db_cache_size:
466 if len(self.db_input_cache) >= self.db_cache_size:
437 self.save_flag.set()
467 self.save_flag.set()
438
468
439 # update the auto _i variables
469 # update the auto _i variables
440 self._iii = self._ii
470 self._iii = self._ii
441 self._ii = self._i
471 self._ii = self._i
442 self._i = self._i00
472 self._i = self._i00
443 self._i00 = source_raw
473 self._i00 = source_raw
444
474
445 # hackish access to user namespace to create _i1,_i2... dynamically
475 # hackish access to user namespace to create _i1,_i2... dynamically
446 new_i = '_i%s' % line_num
476 new_i = '_i%s' % line_num
447 to_main = {'_i': self._i,
477 to_main = {'_i': self._i,
448 '_ii': self._ii,
478 '_ii': self._ii,
449 '_iii': self._iii,
479 '_iii': self._iii,
450 new_i : self._i00 }
480 new_i : self._i00 }
451 self.shell.user_ns.update(to_main)
481 self.shell.user_ns.update(to_main)
452
482
453 def store_output(self, line_num):
483 def store_output(self, line_num):
454 """If database output logging is enabled, this saves all the
484 """If database output logging is enabled, this saves all the
455 outputs from the indicated prompt number to the database. It's
485 outputs from the indicated prompt number to the database. It's
456 called by run_cell after code has been executed.
486 called by run_cell after code has been executed.
457
487
458 Parameters
488 Parameters
459 ----------
489 ----------
460 line_num : int
490 line_num : int
461 The line number from which to save outputs
491 The line number from which to save outputs
462 """
492 """
463 if (not self.db_log_output) or (line_num not in self.output_hist_reprs):
493 if (not self.db_log_output) or (line_num not in self.output_hist_reprs):
464 return
494 return
465 output = self.output_hist_reprs[line_num]
495 output = self.output_hist_reprs[line_num]
466
496
467 with self.db_output_cache_lock:
497 with self.db_output_cache_lock:
468 self.db_output_cache.append((line_num, output))
498 self.db_output_cache.append((line_num, output))
469 if self.db_cache_size <= 1:
499 if self.db_cache_size <= 1:
470 self.save_flag.set()
500 self.save_flag.set()
471
501
472 def _writeout_input_cache(self, conn):
502 def _writeout_input_cache(self, conn):
473 with conn:
503 with conn:
474 for line in self.db_input_cache:
504 for line in self.db_input_cache:
475 conn.execute("INSERT INTO history VALUES (?, ?, ?, ?)",
505 conn.execute("INSERT INTO history VALUES (?, ?, ?, ?)",
476 (self.session_number,)+line)
506 (self.session_number,)+line)
477
507
478 def _writeout_output_cache(self, conn):
508 def _writeout_output_cache(self, conn):
479 with conn:
509 with conn:
480 for line in self.db_output_cache:
510 for line in self.db_output_cache:
481 conn.execute("INSERT INTO output_history VALUES (?, ?, ?)",
511 conn.execute("INSERT INTO output_history VALUES (?, ?, ?)",
482 (self.session_number,)+line)
512 (self.session_number,)+line)
483
513
484 def writeout_cache(self, conn=None):
514 def writeout_cache(self, conn=None):
485 """Write any entries in the cache to the database."""
515 """Write any entries in the cache to the database."""
486 if conn is None:
516 if conn is None:
487 conn = self.db
517 conn = self.db
488
518
489 with self.db_input_cache_lock:
519 with self.db_input_cache_lock:
490 try:
520 try:
491 self._writeout_input_cache(conn)
521 self._writeout_input_cache(conn)
492 except sqlite3.IntegrityError:
522 except sqlite3.IntegrityError:
493 self.new_session(conn)
523 self.new_session(conn)
494 print("ERROR! Session/line number was not unique in",
524 print("ERROR! Session/line number was not unique in",
495 "database. History logging moved to new session",
525 "database. History logging moved to new session",
496 self.session_number)
526 self.session_number)
497 try: # Try writing to the new session. If this fails, don't recurse
527 try: # Try writing to the new session. If this fails, don't recurse
498 self._writeout_input_cache(conn)
528 self._writeout_input_cache(conn)
499 except sqlite3.IntegrityError:
529 except sqlite3.IntegrityError:
500 pass
530 pass
501 finally:
531 finally:
502 self.db_input_cache = []
532 self.db_input_cache = []
503
533
504 with self.db_output_cache_lock:
534 with self.db_output_cache_lock:
505 try:
535 try:
506 self._writeout_output_cache(conn)
536 self._writeout_output_cache(conn)
507 except sqlite3.IntegrityError:
537 except sqlite3.IntegrityError:
508 print("!! Session/line number for output was not unique",
538 print("!! Session/line number for output was not unique",
509 "in database. Output will not be stored.")
539 "in database. Output will not be stored.")
510 finally:
540 finally:
511 self.db_output_cache = []
541 self.db_output_cache = []
512
542
513
543
514 class HistorySavingThread(threading.Thread):
544 class HistorySavingThread(threading.Thread):
515 """This thread takes care of writing history to the database, so that
545 """This thread takes care of writing history to the database, so that
516 the UI isn't held up while that happens.
546 the UI isn't held up while that happens.
517
547
518 It waits for the HistoryManager's save_flag to be set, then writes out
548 It waits for the HistoryManager's save_flag to be set, then writes out
519 the history cache. The main thread is responsible for setting the flag when
549 the history cache. The main thread is responsible for setting the flag when
520 the cache size reaches a defined threshold."""
550 the cache size reaches a defined threshold."""
521 daemon = True
551 daemon = True
522 stop_now = False
552 stop_now = False
523 def __init__(self, history_manager):
553 def __init__(self, history_manager):
524 super(HistorySavingThread, self).__init__()
554 super(HistorySavingThread, self).__init__()
525 self.history_manager = history_manager
555 self.history_manager = history_manager
526 atexit.register(self.stop)
556 atexit.register(self.stop)
527
557
528 def run(self):
558 def run(self):
529 # We need a separate db connection per thread:
559 # We need a separate db connection per thread:
530 try:
560 try:
531 self.db = sqlite3.connect(self.history_manager.hist_file)
561 self.db = sqlite3.connect(self.history_manager.hist_file)
532 while True:
562 while True:
533 self.history_manager.save_flag.wait()
563 self.history_manager.save_flag.wait()
534 if self.stop_now:
564 if self.stop_now:
535 return
565 return
536 self.history_manager.save_flag.clear()
566 self.history_manager.save_flag.clear()
537 self.history_manager.writeout_cache(self.db)
567 self.history_manager.writeout_cache(self.db)
538 except Exception as e:
568 except Exception as e:
539 print(("The history saving thread hit an unexpected error (%s)."
569 print(("The history saving thread hit an unexpected error (%s)."
540 "History will not be written to the database.") % repr(e))
570 "History will not be written to the database.") % repr(e))
541
571
542 def stop(self):
572 def stop(self):
543 """This can be called from the main thread to safely stop this thread.
573 """This can be called from the main thread to safely stop this thread.
544
574
545 Note that it does not attempt to write out remaining history before
575 Note that it does not attempt to write out remaining history before
546 exiting. That should be done by calling the HistoryManager's
576 exiting. That should be done by calling the HistoryManager's
547 end_session method."""
577 end_session method."""
548 self.stop_now = True
578 self.stop_now = True
549 self.history_manager.save_flag.set()
579 self.history_manager.save_flag.set()
550 self.join()
580 self.join()
551
581
552
582
553 # To match, e.g. ~5/8-~2/3
583 # To match, e.g. ~5/8-~2/3
554 range_re = re.compile(r"""
584 range_re = re.compile(r"""
555 ((?P<startsess>~?\d+)/)?
585 ((?P<startsess>~?\d+)/)?
556 (?P<start>\d+) # Only the start line num is compulsory
586 (?P<start>\d+) # Only the start line num is compulsory
557 ((?P<sep>[\-:])
587 ((?P<sep>[\-:])
558 ((?P<endsess>~?\d+)/)?
588 ((?P<endsess>~?\d+)/)?
559 (?P<end>\d+))?
589 (?P<end>\d+))?
560 $""", re.VERBOSE)
590 $""", re.VERBOSE)
561
591
562 def extract_hist_ranges(ranges_str):
592 def extract_hist_ranges(ranges_str):
563 """Turn a string of history ranges into 3-tuples of (session, start, stop).
593 """Turn a string of history ranges into 3-tuples of (session, start, stop).
564
594
565 Examples
595 Examples
566 --------
596 --------
567 list(extract_input_ranges("~8/5-~7/4 2"))
597 list(extract_input_ranges("~8/5-~7/4 2"))
568 [(-8, 5, None), (-7, 1, 4), (0, 2, 3)]
598 [(-8, 5, None), (-7, 1, 4), (0, 2, 3)]
569 """
599 """
570 for range_str in ranges_str.split():
600 for range_str in ranges_str.split():
571 rmatch = range_re.match(range_str)
601 rmatch = range_re.match(range_str)
572 if not rmatch:
602 if not rmatch:
573 continue
603 continue
574 start = int(rmatch.group("start"))
604 start = int(rmatch.group("start"))
575 end = rmatch.group("end")
605 end = rmatch.group("end")
576 end = int(end) if end else start+1 # If no end specified, get (a, a+1)
606 end = int(end) if end else start+1 # If no end specified, get (a, a+1)
577 if rmatch.group("sep") == "-": # 1-3 == 1:4 --> [1, 2, 3]
607 if rmatch.group("sep") == "-": # 1-3 == 1:4 --> [1, 2, 3]
578 end += 1
608 end += 1
579 startsess = rmatch.group("startsess") or "0"
609 startsess = rmatch.group("startsess") or "0"
580 endsess = rmatch.group("endsess") or startsess
610 endsess = rmatch.group("endsess") or startsess
581 startsess = int(startsess.replace("~","-"))
611 startsess = int(startsess.replace("~","-"))
582 endsess = int(endsess.replace("~","-"))
612 endsess = int(endsess.replace("~","-"))
583 assert endsess >= startsess
613 assert endsess >= startsess
584
614
585 if endsess == startsess:
615 if endsess == startsess:
586 yield (startsess, start, end)
616 yield (startsess, start, end)
587 continue
617 continue
588 # Multiple sessions in one range:
618 # Multiple sessions in one range:
589 yield (startsess, start, None)
619 yield (startsess, start, None)
590 for sess in range(startsess+1, endsess):
620 for sess in range(startsess+1, endsess):
591 yield (sess, 1, None)
621 yield (sess, 1, None)
592 yield (endsess, 1, end)
622 yield (endsess, 1, end)
593
623
594 def _format_lineno(session, line):
624 def _format_lineno(session, line):
595 """Helper function to format line numbers properly."""
625 """Helper function to format line numbers properly."""
596 if session == 0:
626 if session == 0:
597 return str(line)
627 return str(line)
598 return "%s#%s" % (session, line)
628 return "%s#%s" % (session, line)
599
629
600 @skip_doctest
630 @skip_doctest
601 def magic_history(self, parameter_s = ''):
631 def magic_history(self, parameter_s = ''):
602 """Print input history (_i<n> variables), with most recent last.
632 """Print input history (_i<n> variables), with most recent last.
603
633
604 %history -> print at most 40 inputs (some may be multi-line)\\
634 %history -> print at most 40 inputs (some may be multi-line)\\
605 %history n -> print at most n inputs\\
635 %history n -> print at most n inputs\\
606 %history n1 n2 -> print inputs between n1 and n2 (n2 not included)\\
636 %history n1 n2 -> print inputs between n1 and n2 (n2 not included)\\
607
637
608 By default, input history is printed without line numbers so it can be
638 By default, input history is printed without line numbers so it can be
609 directly pasted into an editor. Use -n to show them.
639 directly pasted into an editor. Use -n to show them.
610
640
611 Ranges of history can be indicated using the syntax:
641 Ranges of history can be indicated using the syntax:
612 4 : Line 4, current session
642 4 : Line 4, current session
613 4-6 : Lines 4-6, current session
643 4-6 : Lines 4-6, current session
614 243/1-5: Lines 1-5, session 243
644 243/1-5: Lines 1-5, session 243
615 ~2/7 : Line 7, session 2 before current
645 ~2/7 : Line 7, session 2 before current
616 ~8/1-~6/5 : From the first line of 8 sessions ago, to the fifth line
646 ~8/1-~6/5 : From the first line of 8 sessions ago, to the fifth line
617 of 6 sessions ago.
647 of 6 sessions ago.
618 Multiple ranges can be entered, separated by spaces
648 Multiple ranges can be entered, separated by spaces
619
649
620 The same syntax is used by %macro, %save, %edit, %rerun
650 The same syntax is used by %macro, %save, %edit, %rerun
621
651
622 Options:
652 Options:
623
653
624 -n: print line numbers for each input.
654 -n: print line numbers for each input.
625 This feature is only available if numbered prompts are in use.
655 This feature is only available if numbered prompts are in use.
626
656
627 -o: also print outputs for each input.
657 -o: also print outputs for each input.
628
658
629 -p: print classic '>>>' python prompts before each input. This is useful
659 -p: print classic '>>>' python prompts before each input. This is useful
630 for making documentation, and in conjunction with -o, for producing
660 for making documentation, and in conjunction with -o, for producing
631 doctest-ready output.
661 doctest-ready output.
632
662
633 -r: (default) print the 'raw' history, i.e. the actual commands you typed.
663 -r: (default) print the 'raw' history, i.e. the actual commands you typed.
634
664
635 -t: print the 'translated' history, as IPython understands it. IPython
665 -t: print the 'translated' history, as IPython understands it. IPython
636 filters your input and converts it all into valid Python source before
666 filters your input and converts it all into valid Python source before
637 executing it (things like magics or aliases are turned into function
667 executing it (things like magics or aliases are turned into function
638 calls, for example). With this option, you'll see the native history
668 calls, for example). With this option, you'll see the native history
639 instead of the user-entered version: '%cd /' will be seen as
669 instead of the user-entered version: '%cd /' will be seen as
640 'get_ipython().magic("%cd /")' instead of '%cd /'.
670 'get_ipython().magic("%cd /")' instead of '%cd /'.
641
671
642 -g: treat the arg as a pattern to grep for in (full) history.
672 -g: treat the arg as a pattern to grep for in (full) history.
643 This includes the saved history (almost all commands ever written).
673 This includes the saved history (almost all commands ever written).
644 Use '%hist -g' to show full saved history (may be very long).
674 Use '%hist -g' to show full saved history (may be very long).
645
675
646 -l: get the last n lines from all sessions. Specify n as a single arg, or
676 -l: get the last n lines from all sessions. Specify n as a single arg, or
647 the default is the last 10 lines.
677 the default is the last 10 lines.
648
678
649 -f FILENAME: instead of printing the output to the screen, redirect it to
679 -f FILENAME: instead of printing the output to the screen, redirect it to
650 the given file. The file is always overwritten, though IPython asks for
680 the given file. The file is always overwritten, though IPython asks for
651 confirmation first if it already exists.
681 confirmation first if it already exists.
652
682
653 Examples
683 Examples
654 --------
684 --------
655 ::
685 ::
656
686
657 In [6]: %hist -n 4 6
687 In [6]: %hist -n 4 6
658 4:a = 12
688 4:a = 12
659 5:print a**2
689 5:print a**2
660
690
661 """
691 """
662
692
663 if not self.shell.displayhook.do_full_cache:
693 if not self.shell.displayhook.do_full_cache:
664 print('This feature is only available if numbered prompts are in use.')
694 print('This feature is only available if numbered prompts are in use.')
665 return
695 return
666 opts,args = self.parse_options(parameter_s,'noprtglf:',mode='string')
696 opts,args = self.parse_options(parameter_s,'noprtglf:',mode='string')
667
697
668 # For brevity
698 # For brevity
669 history_manager = self.shell.history_manager
699 history_manager = self.shell.history_manager
670
700
671 def _format_lineno(session, line):
701 def _format_lineno(session, line):
672 """Helper function to format line numbers properly."""
702 """Helper function to format line numbers properly."""
673 if session in (0, history_manager.session_number):
703 if session in (0, history_manager.session_number):
674 return str(line)
704 return str(line)
675 return "%s/%s" % (session, line)
705 return "%s/%s" % (session, line)
676
706
677 # Check if output to specific file was requested.
707 # Check if output to specific file was requested.
678 try:
708 try:
679 outfname = opts['f']
709 outfname = opts['f']
680 except KeyError:
710 except KeyError:
681 outfile = io.stdout # default
711 outfile = io.stdout # default
682 # We don't want to close stdout at the end!
712 # We don't want to close stdout at the end!
683 close_at_end = False
713 close_at_end = False
684 else:
714 else:
685 if os.path.exists(outfname):
715 if os.path.exists(outfname):
686 if not io.ask_yes_no("File %r exists. Overwrite?" % outfname):
716 if not io.ask_yes_no("File %r exists. Overwrite?" % outfname):
687 print('Aborting.')
717 print('Aborting.')
688 return
718 return
689
719
690 outfile = open(outfname,'w')
720 outfile = open(outfname,'w')
691 close_at_end = True
721 close_at_end = True
692
722
693 print_nums = 'n' in opts
723 print_nums = 'n' in opts
694 get_output = 'o' in opts
724 get_output = 'o' in opts
695 pyprompts = 'p' in opts
725 pyprompts = 'p' in opts
696 # Raw history is the default
726 # Raw history is the default
697 raw = not('t' in opts)
727 raw = not('t' in opts)
698
728
699 default_length = 40
729 default_length = 40
700 pattern = None
730 pattern = None
701
731
702 if 'g' in opts: # Glob search
732 if 'g' in opts: # Glob search
703 pattern = "*" + args + "*" if args else "*"
733 pattern = "*" + args + "*" if args else "*"
704 hist = history_manager.search(pattern, raw=raw, output=get_output)
734 hist = history_manager.search(pattern, raw=raw, output=get_output)
705 print_nums = True
735 print_nums = True
706 elif 'l' in opts: # Get 'tail'
736 elif 'l' in opts: # Get 'tail'
707 try:
737 try:
708 n = int(args)
738 n = int(args)
709 except ValueError, IndexError:
739 except ValueError, IndexError:
710 n = 10
740 n = 10
711 hist = history_manager.get_tail(n, raw=raw, output=get_output)
741 hist = history_manager.get_tail(n, raw=raw, output=get_output)
712 else:
742 else:
713 if args: # Get history by ranges
743 if args: # Get history by ranges
714 hist = history_manager.get_range_by_str(args, raw, get_output)
744 hist = history_manager.get_range_by_str(args, raw, get_output)
715 else: # Just get history for the current session
745 else: # Just get history for the current session
716 hist = history_manager.get_range(raw=raw, output=get_output)
746 hist = history_manager.get_range(raw=raw, output=get_output)
717
747
718 # We could be displaying the entire history, so let's not try to pull it
748 # We could be displaying the entire history, so let's not try to pull it
719 # into a list in memory. Anything that needs more space will just misalign.
749 # into a list in memory. Anything that needs more space will just misalign.
720 width = 4
750 width = 4
721
751
722 for session, lineno, inline in hist:
752 for session, lineno, inline in hist:
723 # Print user history with tabs expanded to 4 spaces. The GUI clients
753 # Print user history with tabs expanded to 4 spaces. The GUI clients
724 # use hard tabs for easier usability in auto-indented code, but we want
754 # use hard tabs for easier usability in auto-indented code, but we want
725 # to produce PEP-8 compliant history for safe pasting into an editor.
755 # to produce PEP-8 compliant history for safe pasting into an editor.
726 if get_output:
756 if get_output:
727 inline, output = inline
757 inline, output = inline
728 inline = inline.expandtabs(4).rstrip()
758 inline = inline.expandtabs(4).rstrip()
729
759
730 multiline = "\n" in inline
760 multiline = "\n" in inline
731 line_sep = '\n' if multiline else ' '
761 line_sep = '\n' if multiline else ' '
732 if print_nums:
762 if print_nums:
733 print('%s:%s' % (_format_lineno(session, lineno).rjust(width),
763 print('%s:%s' % (_format_lineno(session, lineno).rjust(width),
734 line_sep), file=outfile, end='')
764 line_sep), file=outfile, end='')
735 if pyprompts:
765 if pyprompts:
736 print(">>> ", end="", file=outfile)
766 print(">>> ", end="", file=outfile)
737 if multiline:
767 if multiline:
738 inline = "\n... ".join(inline.splitlines()) + "\n..."
768 inline = "\n... ".join(inline.splitlines()) + "\n..."
739 print(inline, file=outfile)
769 print(inline, file=outfile)
740 if get_output and output:
770 if get_output and output:
741 print(output, file=outfile)
771 print(output, file=outfile)
742
772
743 if close_at_end:
773 if close_at_end:
744 outfile.close()
774 outfile.close()
745
775
746
776
747 def magic_rep(self, arg):
777 def magic_rep(self, arg):
748 r"""Repeat a command, or get command to input line for editing. %recall and
778 r"""Repeat a command, or get command to input line for editing. %recall and
749 %rep are equivalent.
779 %rep are equivalent.
750
780
751 - %recall (no arguments):
781 - %recall (no arguments):
752
782
753 Place a string version of last computation result (stored in the special '_'
783 Place a string version of last computation result (stored in the special '_'
754 variable) to the next input prompt. Allows you to create elaborate command
784 variable) to the next input prompt. Allows you to create elaborate command
755 lines without using copy-paste::
785 lines without using copy-paste::
756
786
757 In[1]: l = ["hei", "vaan"]
787 In[1]: l = ["hei", "vaan"]
758 In[2]: "".join(l)
788 In[2]: "".join(l)
759 Out[2]: heivaan
789 Out[2]: heivaan
760 In[3]: %rep
790 In[3]: %rep
761 In[4]: heivaan_ <== cursor blinking
791 In[4]: heivaan_ <== cursor blinking
762
792
763 %recall 45
793 %recall 45
764
794
765 Place history line 45 on the next input prompt. Use %hist to find
795 Place history line 45 on the next input prompt. Use %hist to find
766 out the number.
796 out the number.
767
797
768 %recall 1-4
798 %recall 1-4
769
799
770 Combine the specified lines into one cell, and place it on the next
800 Combine the specified lines into one cell, and place it on the next
771 input prompt. See %history for the slice syntax.
801 input prompt. See %history for the slice syntax.
772
802
773 %recall foo+bar
803 %recall foo+bar
774
804
775 If foo+bar can be evaluated in the user namespace, the result is
805 If foo+bar can be evaluated in the user namespace, the result is
776 placed at the next input prompt. Otherwise, the history is searched
806 placed at the next input prompt. Otherwise, the history is searched
777 for lines which contain that substring, and the most recent one is
807 for lines which contain that substring, and the most recent one is
778 placed at the next input prompt.
808 placed at the next input prompt.
779 """
809 """
780 if not arg: # Last output
810 if not arg: # Last output
781 self.set_next_input(str(self.shell.user_ns["_"]))
811 self.set_next_input(str(self.shell.user_ns["_"]))
782 return
812 return
783 # Get history range
813 # Get history range
784 histlines = self.history_manager.get_range_by_str(arg)
814 histlines = self.history_manager.get_range_by_str(arg)
785 cmd = "\n".join(x[2] for x in histlines)
815 cmd = "\n".join(x[2] for x in histlines)
786 if cmd:
816 if cmd:
787 self.set_next_input(cmd.rstrip())
817 self.set_next_input(cmd.rstrip())
788 return
818 return
789
819
790 try: # Variable in user namespace
820 try: # Variable in user namespace
791 cmd = str(eval(arg, self.shell.user_ns))
821 cmd = str(eval(arg, self.shell.user_ns))
792 except Exception: # Search for term in history
822 except Exception: # Search for term in history
793 histlines = self.history_manager.search("*"+arg+"*")
823 histlines = self.history_manager.search("*"+arg+"*")
794 for h in reversed([x[2] for x in histlines]):
824 for h in reversed([x[2] for x in histlines]):
795 if 'rep' in h:
825 if 'rep' in h:
796 continue
826 continue
797 self.set_next_input(h.rstrip())
827 self.set_next_input(h.rstrip())
798 return
828 return
799 else:
829 else:
800 self.set_next_input(cmd.rstrip())
830 self.set_next_input(cmd.rstrip())
801 print("Couldn't evaluate or find in history:", arg)
831 print("Couldn't evaluate or find in history:", arg)
802
832
803 def magic_rerun(self, parameter_s=''):
833 def magic_rerun(self, parameter_s=''):
804 """Re-run previous input
834 """Re-run previous input
805
835
806 By default, you can specify ranges of input history to be repeated
836 By default, you can specify ranges of input history to be repeated
807 (as with %history). With no arguments, it will repeat the last line.
837 (as with %history). With no arguments, it will repeat the last line.
808
838
809 Options:
839 Options:
810
840
811 -l <n> : Repeat the last n lines of input, not including the
841 -l <n> : Repeat the last n lines of input, not including the
812 current command.
842 current command.
813
843
814 -g foo : Repeat the most recent line which contains foo
844 -g foo : Repeat the most recent line which contains foo
815 """
845 """
816 opts, args = self.parse_options(parameter_s, 'l:g:', mode='string')
846 opts, args = self.parse_options(parameter_s, 'l:g:', mode='string')
817 if "l" in opts: # Last n lines
847 if "l" in opts: # Last n lines
818 n = int(opts['l'])
848 n = int(opts['l'])
819 hist = self.history_manager.get_tail(n)
849 hist = self.history_manager.get_tail(n)
820 elif "g" in opts: # Search
850 elif "g" in opts: # Search
821 p = "*"+opts['g']+"*"
851 p = "*"+opts['g']+"*"
822 hist = list(self.history_manager.search(p))
852 hist = list(self.history_manager.search(p))
823 for l in reversed(hist):
853 for l in reversed(hist):
824 if "rerun" not in l[2]:
854 if "rerun" not in l[2]:
825 hist = [l] # The last match which isn't a %rerun
855 hist = [l] # The last match which isn't a %rerun
826 break
856 break
827 else:
857 else:
828 hist = [] # No matches except %rerun
858 hist = [] # No matches except %rerun
829 elif args: # Specify history ranges
859 elif args: # Specify history ranges
830 hist = self.history_manager.get_range_by_str(args)
860 hist = self.history_manager.get_range_by_str(args)
831 else: # Last line
861 else: # Last line
832 hist = self.history_manager.get_tail(1)
862 hist = self.history_manager.get_tail(1)
833 hist = [x[2] for x in hist]
863 hist = [x[2] for x in hist]
834 if not hist:
864 if not hist:
835 print("No lines in history match specification")
865 print("No lines in history match specification")
836 return
866 return
837 histlines = "\n".join(hist)
867 histlines = "\n".join(hist)
838 print("=== Executing: ===")
868 print("=== Executing: ===")
839 print(histlines)
869 print(histlines)
840 print("=== Output: ===")
870 print("=== Output: ===")
841 self.run_cell("\n".join(hist), store_history=False)
871 self.run_cell("\n".join(hist), store_history=False)
842
872
843
873
844 def init_ipython(ip):
874 def init_ipython(ip):
845 ip.define_magic("rep", magic_rep)
875 ip.define_magic("rep", magic_rep)
846 ip.define_magic("recall", magic_rep)
876 ip.define_magic("recall", magic_rep)
847 ip.define_magic("rerun", magic_rerun)
877 ip.define_magic("rerun", magic_rerun)
848 ip.define_magic("hist",magic_history) # Alternative name
878 ip.define_magic("hist",magic_history) # Alternative name
849 ip.define_magic("history",magic_history)
879 ip.define_magic("history",magic_history)
850
880
851 # XXX - ipy_completers are in quarantine, need to be updated to new apis
881 # XXX - ipy_completers are in quarantine, need to be updated to new apis
852 #import ipy_completers
882 #import ipy_completers
853 #ipy_completers.quick_completer('%hist' ,'-g -t -r -n')
883 #ipy_completers.quick_completer('%hist' ,'-g -t -r -n')
General Comments 0
You need to be logged in to leave comments. Login now