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