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