##// END OF EJS Templates
Implement optional logging of output as suggested by Robert Kern.
Thomas Kluyver -
Show More
@@ -1,531 +1,550 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 fnmatch
16 import fnmatch
17 import os
17 import os
18 import sqlite3
18 import sqlite3
19
19
20 # Our own packages
20 # Our own packages
21 import IPython.utils.io
21 import IPython.utils.io
22
22
23 from IPython.testing import decorators as testdec
23 from IPython.testing import decorators as testdec
24 from IPython.utils.io import ask_yes_no
24 from IPython.utils.io import ask_yes_no
25 from IPython.utils.warn import warn
25 from IPython.utils.warn import warn
26
26
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28 # Classes and functions
28 # Classes and functions
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30
30
31 class HistoryManager(object):
31 class HistoryManager(object):
32 """A class to organize all history-related functionality in one place.
32 """A class to organize all history-related functionality in one place.
33 """
33 """
34 # Public interface
34 # Public interface
35
35
36 # An instance of the IPython shell we are attached to
36 # An instance of the IPython shell we are attached to
37 shell = None
37 shell = None
38 # A list to hold processed history
38 # A list to hold processed history
39 input_hist_parsed = None
39 input_hist_parsed = None
40 # A list to hold raw history (as typed by user)
40 # A list to hold raw history (as typed by user)
41 input_hist_raw = None
41 input_hist_raw = None
42 # A list of directories visited during session
42 # A list of directories visited during session
43 dir_hist = None
43 dir_hist = None
44 # A dict of output history, keyed with ints from the shell's execution count
44 # A dict of output history, keyed with ints from the shell's execution count
45 output_hist = None
45 output_hist = None
46 # String with path to the history file
46 # String with path to the history file
47 hist_file = None
47 hist_file = None
48 # The SQLite database
48 # The SQLite database
49 db = None
49 db = None
50 # The number of the current session in the history database
50 # The number of the current session in the history database
51 session_number = None
51 session_number = None
52 # Number of lines to cache before writing to the database (to save power)
52 # Should we log output to the database? (default no)
53 # - if 0, lines will be written instantly.
53 db_log_output = False
54 # Write to database every x commands (higher values save disk access & power)
55 # Values of 1 or less effectively disable caching.
54 db_cache_size = 0
56 db_cache_size = 0
55 # The line cache
57 # The input and output caches
56 db_cache = None
58 db_input_cache = None
59 db_output_cache = None
57
60
58 # Private interface
61 # Private interface
59 # Variables used to store the three last inputs from the user. On each new
62 # Variables used to store the three last inputs from the user. On each new
60 # history update, we populate the user's namespace with these, shifted as
63 # history update, we populate the user's namespace with these, shifted as
61 # necessary.
64 # necessary.
62 _i00, _i, _ii, _iii = '','','',''
65 _i00, _i, _ii, _iii = '','','',''
63
66
64 # A set with all forms of the exit command, so that we don't store them in
67 # A set with all forms of the exit command, so that we don't store them in
65 # the history (it's annoying to rewind the first entry and land on an exit
68 # the history (it's annoying to rewind the first entry and land on an exit
66 # call).
69 # call).
67 _exit_commands = None
70 _exit_commands = None
68
71
69 def __init__(self, shell, load_history=False):
72 def __init__(self, shell, load_history=False):
70 """Create a new history manager associated with a shell instance.
73 """Create a new history manager associated with a shell instance.
71
74
72 Parameters
75 Parameters
73 ----------
76 ----------
74 load_history: bool, optional
77 load_history: bool, optional
75 If True, history will be loaded from file, and the session
78 If True, history will be loaded from file, and the session
76 offset set, so that the next line entered can be retrieved
79 offset set, so that the next line entered can be retrieved
77 as #1.
80 as #1.
78 """
81 """
79 # We need a pointer back to the shell for various tasks.
82 # We need a pointer back to the shell for various tasks.
80 self.shell = shell
83 self.shell = shell
81
84
82 # List of input with multi-line handling. One blank entry so indexing
85 # List of input with multi-line handling. One blank entry so indexing
83 # starts from 1.
86 # starts from 1.
84 self.input_hist_parsed = [""]
87 self.input_hist_parsed = [""]
85 # This one will hold the 'raw' input history, without any
88 # This one will hold the 'raw' input history, without any
86 # pre-processing. This will allow users to retrieve the input just as
89 # pre-processing. This will allow users to retrieve the input just as
87 # it was exactly typed in by the user, with %hist -r.
90 # it was exactly typed in by the user, with %hist -r.
88 self.input_hist_raw = [""]
91 self.input_hist_raw = [""]
89
92
90 # list of visited directories
93 # list of visited directories
91 try:
94 try:
92 self.dir_hist = [os.getcwd()]
95 self.dir_hist = [os.getcwd()]
93 except OSError:
96 except OSError:
94 self.dir_hist = []
97 self.dir_hist = []
95
98
96 # dict of output history
99 # dict of output history
97 self.output_hist = {}
100 self.output_hist = {}
98
101
99 # Now the history file
102 # Now the history file
100 if shell.profile:
103 if shell.profile:
101 histfname = 'history-%s' % shell.profile
104 histfname = 'history-%s' % shell.profile
102 else:
105 else:
103 histfname = 'history'
106 histfname = 'history'
104 self.hist_file = os.path.join(shell.ipython_dir, histfname + '.sqlite')
107 self.hist_file = os.path.join(shell.ipython_dir, histfname + '.sqlite')
105
108
106 self._i00, self._i, self._ii, self._iii = '','','',''
109 self._i00, self._i, self._ii, self._iii = '','','',''
107
110
108 self._exit_commands = set(['Quit', 'quit', 'Exit', 'exit', '%Quit',
111 self._exit_commands = set(['Quit', 'quit', 'Exit', 'exit', '%Quit',
109 '%quit', '%Exit', '%exit'])
112 '%quit', '%Exit', '%exit'])
110
113
111 self.init_db()
114 self.init_db()
112
115
113 def init_db(self):
116 def init_db(self):
114 self.db = sqlite3.connect(self.hist_file)
117 self.db = sqlite3.connect(self.hist_file)
115 self.db.execute("""CREATE TABLE IF NOT EXISTS history (session integer,
118 self.db.execute("""CREATE TABLE IF NOT EXISTS history
116 line integer, source text, source_raw text,
119 (session integer, line integer, source text, source_raw text,
120 PRIMARY KEY (session, line))""")
121 # Output history is optional, but ensure the table's there so it can be
122 # enabled later.
123 self.db.execute("""CREATE TABLE IF NOT EXISTS output_history
124 (session integer, line integer, output text,
117 PRIMARY KEY (session, line))""")
125 PRIMARY KEY (session, line))""")
118 cur = self.db.execute("""SELECT name FROM sqlite_master WHERE
126 cur = self.db.execute("""SELECT name FROM sqlite_master WHERE
119 type='table' AND name='singletons'""")
127 type='table' AND name='singletons'""")
120 if not cur.fetchone():
128 if not cur.fetchone():
121 self.db.execute("""CREATE TABLE singletons
129 self.db.execute("""CREATE TABLE singletons
122 (name text PRIMARY KEY, value)""")
130 (name text PRIMARY KEY, value)""")
123 self.db.execute("""INSERT INTO singletons VALUES
131 self.db.execute("""INSERT INTO singletons VALUES
124 ('session_number', 1)""")
132 ('session_number', 1)""")
125 self.db.commit()
133 self.db.commit()
126 cur = self.db.execute("""SELECT value FROM singletons WHERE
134 cur = self.db.execute("""SELECT value FROM singletons WHERE
127 name='session_number'""")
135 name='session_number'""")
128 self.session_number = cur.fetchone()[0]
136 self.session_number = cur.fetchone()[0]
129
137
130 #Increment by one for next session.
138 #Increment by one for next session.
131 self.db.execute("""UPDATE singletons SET value=? WHERE
139 self.db.execute("""UPDATE singletons SET value=? WHERE
132 name='session_number'""", (self.session_number+1,))
140 name='session_number'""", (self.session_number+1,))
133 self.db.commit()
141 self.db.commit()
134 self.db_cache = []
142 self.db_input_cache = []
143 self.db_output_cache = []
135
144
136 def get_db_history(self, session, start=1, stop=None, raw=True):
145 def get_db_history(self, session, start=1, stop=None, raw=True):
137 """Retrieve input history from the database by session.
146 """Retrieve input history from the database by session.
138
147
139 Parameters
148 Parameters
140 ----------
149 ----------
141 session : int
150 session : int
142 Session number to retrieve. If negative, counts back from current
151 Session number to retrieve. If negative, counts back from current
143 session (so -1 is previous session).
152 session (so -1 is previous session).
144 start : int
153 start : int
145 First line to retrieve.
154 First line to retrieve.
146 stop : int
155 stop : int
147 Last line to retrieve. If None, retrieve to the end of the session.
156 Last line to retrieve. If None, retrieve to the end of the session.
148 raw : bool
157 raw : bool
149 If True, return raw input
158 If True, return raw input
150
159
151 Returns
160 Returns
152 -------
161 -------
153 An iterator over the desired lines.
162 An iterator over the desired lines.
154 """
163 """
155 toget = 'source_raw' if raw else 'source'
164 toget = 'source_raw' if raw else 'source'
156 if session < 0:
165 if session < 0:
157 session += self.session_number
166 session += self.session_number
158
167
159 if stop:
168 if stop:
160 cur = self.db.execute("SELECT " + toget + """ FROM history WHERE
169 cur = self.db.execute("SELECT " + toget + """ FROM history WHERE
161 session==? AND line BETWEEN ? and ?""",
170 session==? AND line BETWEEN ? and ?""",
162 (session, start, stop))
171 (session, start, stop))
163 else:
172 else:
164 cur = self.db.execute("SELECT " + toget + """ FROM history WHERE
173 cur = self.db.execute("SELECT " + toget + """ FROM history WHERE
165 session==? AND line>=?""", (session, start))
174 session==? AND line>=?""", (session, start))
166 return (x[0] for x in cur)
175 return (x[0] for x in cur)
167
176
168 def tail_db_history(self, n=10, raw=True):
177 def tail_db_history(self, n=10, raw=True):
169 """Get the last n lines from the history database."""
178 """Get the last n lines from the history database."""
170 toget = 'source_raw' if raw else 'source'
179 toget = 'source_raw' if raw else 'source'
171 cur = self.db.execute("SELECT " + toget + """ FROM history ORDER BY
180 cur = self.db.execute("SELECT " + toget + """ FROM history ORDER BY
172 session DESC, line DESC LIMIT ?""", (n,))
181 session DESC, line DESC LIMIT ?""", (n,))
173 return (x[0] for x in reversed(cur.fetchall()))
182 return (x[0] for x in reversed(cur.fetchall()))
174
183
175 def globsearch_db(self, pattern="*"):
184 def globsearch_db(self, pattern="*"):
176 """Search the database using unix glob-style matching (wildcards * and
185 """Search the database using unix glob-style matching (wildcards * and
177 ?, escape using \).
186 ?, escape using \).
178
187
179 Returns
188 Returns
180 -------
189 -------
181 An iterator over tuples: (session, line_number, command)
190 An iterator over tuples: (session, line_number, command)
182 """
191 """
183 return self.db.execute("""SELECT session, line, source_raw FROM history
192 return self.db.execute("""SELECT session, line, source_raw FROM history
184 WHERE source_raw GLOB ?""", (pattern,))
193 WHERE source_raw GLOB ?""", (pattern,))
185
194
186 def get_history(self, start=1, stop=None, raw=False, output=True):
195 def get_history(self, start=1, stop=None, raw=False, output=True):
187 """Get the history list.
196 """Get the history list.
188
197
189 Get the input and output history.
198 Get the input and output history.
190
199
191 Parameters
200 Parameters
192 ----------
201 ----------
193 start : int
202 start : int
194 From (prompt number in the current session). Negative numbers count
203 From (prompt number in the current session). Negative numbers count
195 back from the end.
204 back from the end.
196 stop : int
205 stop : int
197 To (prompt number in the current session, exclusive). Negative
206 To (prompt number in the current session, exclusive). Negative
198 numbers count back from the end, and None goes to the end.
207 numbers count back from the end, and None goes to the end.
199 raw : bool
208 raw : bool
200 If True, return the raw input.
209 If True, return the raw input.
201 output : bool
210 output : bool
202 If True, then return the output as well.
211 If True, then return the output as well.
203 this_session : bool
212 this_session : bool
204 If True, indexing is from 1 at the start of this session.
213 If True, indexing is from 1 at the start of this session.
205 If False, indexing is from 1 at the start of the whole history.
214 If False, indexing is from 1 at the start of the whole history.
206
215
207 Returns
216 Returns
208 -------
217 -------
209 If output is True, then return a dict of tuples, keyed by the prompt
218 If output is True, then return a dict of tuples, keyed by the prompt
210 numbers and with values of (input, output). If output is False, then
219 numbers and with values of (input, output). If output is False, then
211 a dict, keyed by the prompt number with the values of input.
220 a dict, keyed by the prompt number with the values of input.
212 """
221 """
213 if raw:
222 if raw:
214 input_hist = self.input_hist_raw
223 input_hist = self.input_hist_raw
215 else:
224 else:
216 input_hist = self.input_hist_parsed
225 input_hist = self.input_hist_parsed
217 if output:
226 if output:
218 output_hist = self.output_hist
227 output_hist = self.output_hist
219
228
220 n = len(input_hist)
229 n = len(input_hist)
221 if start < 0:
230 if start < 0:
222 start += n
231 start += n
223 if not stop:
232 if not stop:
224 stop = n
233 stop = n
225 elif stop < 0:
234 elif stop < 0:
226 stop += n
235 stop += n
227
236
228 hist = {}
237 hist = {}
229 for i in range(start, stop):
238 for i in range(start, stop):
230 if output:
239 if output:
231 hist[i] = (input_hist[i], output_hist.get(i))
240 hist[i] = (input_hist[i], output_hist.get(i))
232 else:
241 else:
233 hist[i] = input_hist[i]
242 hist[i] = input_hist[i]
234 return hist
243 return hist
235
244
236 def store_inputs(self, line_num, source, source_raw=None):
245 def store_inputs(self, line_num, source, source_raw=None):
237 """Store source and raw input in history and create input cache
246 """Store source and raw input in history and create input cache
238 variables _i*.
247 variables _i*.
239
248
240 Parameters
249 Parameters
241 ----------
250 ----------
242 line_num : int
251 line_num : int
243 The prompt number of this input.
252 The prompt number of this input.
244
253
245 source : str
254 source : str
246 Python input.
255 Python input.
247
256
248 source_raw : str, optional
257 source_raw : str, optional
249 If given, this is the raw input without any IPython transformations
258 If given, this is the raw input without any IPython transformations
250 applied to it. If not given, ``source`` is used.
259 applied to it. If not given, ``source`` is used.
251 """
260 """
252 if source_raw is None:
261 if source_raw is None:
253 source_raw = source
262 source_raw = source
254
263
255 # do not store exit/quit commands
264 # do not store exit/quit commands
256 if source_raw.strip() in self._exit_commands:
265 if source_raw.strip() in self._exit_commands:
257 return
266 return
258
267
259 self.input_hist_parsed.append(source.rstrip())
268 self.input_hist_parsed.append(source.rstrip())
260 self.input_hist_raw.append(source_raw.rstrip())
269 self.input_hist_raw.append(source_raw.rstrip())
261
270
262 db_row = (self.session_number, line_num, source, source_raw)
271 self.db_input_cache.append((self.session_number, line_num,
263 if self.db_cache_size: # Cache before writing
272 source, source_raw))
264 self.db_cache.append(db_row)
273 # Trigger to flush cache and write to DB.
265 if len(self.db_cache) > self.db_cache_size:
274 if len(self.db_input_cache) >= self.db_cache_size:
266 self.writeout_cache()
275 self.writeout_cache()
267 else: # Instant write
268 with self.db:
269 self.db.execute("INSERT INTO history VALUES (?, ?, ?, ?)", db_row)
270
276
271 # update the auto _i variables
277 # update the auto _i variables
272 self._iii = self._ii
278 self._iii = self._ii
273 self._ii = self._i
279 self._ii = self._i
274 self._i = self._i00
280 self._i = self._i00
275 self._i00 = source_raw
281 self._i00 = source_raw
276
282
277 # hackish access to user namespace to create _i1,_i2... dynamically
283 # hackish access to user namespace to create _i1,_i2... dynamically
278 new_i = '_i%s' % line_num
284 new_i = '_i%s' % line_num
279 to_main = {'_i': self._i,
285 to_main = {'_i': self._i,
280 '_ii': self._ii,
286 '_ii': self._ii,
281 '_iii': self._iii,
287 '_iii': self._iii,
282 new_i : self._i00 }
288 new_i : self._i00 }
283 self.shell.user_ns.update(to_main)
289 self.shell.user_ns.update(to_main)
284
290
291 def store_output(self, line_num, output):
292 if not self.db_log_output:
293 return
294 db_row = (self.session_number, line_num, output)
295 if self.db_cache_size > 1:
296 self.db_output_cache.append(db_row)
297 else:
298 with self.db:
299 self.db.execute("INSERT INTO output_history VALUES (?,?,?)", db_row)
300
285 def writeout_cache(self):
301 def writeout_cache(self):
286 with self.db:
302 with self.db:
287 self.db.executemany("INSERT INTO history VALUES (?, ?, ?, ?)",
303 self.db.executemany("INSERT INTO history VALUES (?, ?, ?, ?)",
288 self.db_cache)
304 self.db_input_cache)
289 self.db_cache = []
305 self.db.executemany("INSERT INTO output_history VALUES (?, ?, ?)",
306 self.db_output_cache)
307 self.db_input_cache = []
308 self.db_output_cache = []
290
309
291 def sync_inputs(self):
310 def sync_inputs(self):
292 """Ensure raw and translated histories have same length."""
311 """Ensure raw and translated histories have same length."""
293 lr = len(self.input_hist_raw)
312 lr = len(self.input_hist_raw)
294 lp = len(self.input_hist_parsed)
313 lp = len(self.input_hist_parsed)
295 if lp < lr:
314 if lp < lr:
296 self.input_hist_raw[:lr-lp] = []
315 self.input_hist_raw[:lr-lp] = []
297 elif lr < lp:
316 elif lr < lp:
298 self.input_hist_parsed[:lp-lr] = []
317 self.input_hist_parsed[:lp-lr] = []
299
318
300 def reset(self):
319 def reset(self):
301 """Clear all histories managed by this object."""
320 """Clear all histories managed by this object."""
302 self.input_hist_parsed[:] = []
321 self.input_hist_parsed[:] = []
303 self.input_hist_raw[:] = []
322 self.input_hist_raw[:] = []
304 self.output_hist.clear()
323 self.output_hist.clear()
305 # The directory history can't be completely empty
324 # The directory history can't be completely empty
306 self.dir_hist[:] = [os.getcwd()]
325 self.dir_hist[:] = [os.getcwd()]
307
326
308 @testdec.skip_doctest
327 @testdec.skip_doctest
309 def magic_history(self, parameter_s = ''):
328 def magic_history(self, parameter_s = ''):
310 """Print input history (_i<n> variables), with most recent last.
329 """Print input history (_i<n> variables), with most recent last.
311
330
312 %history -> print at most 40 inputs (some may be multi-line)\\
331 %history -> print at most 40 inputs (some may be multi-line)\\
313 %history n -> print at most n inputs\\
332 %history n -> print at most n inputs\\
314 %history n1 n2 -> print inputs between n1 and n2 (n2 not included)\\
333 %history n1 n2 -> print inputs between n1 and n2 (n2 not included)\\
315
334
316 By default, input history is printed without line numbers so it can be
335 By default, input history is printed without line numbers so it can be
317 directly pasted into an editor.
336 directly pasted into an editor.
318
337
319 With -n, each input's number <n> is shown, and is accessible as the
338 With -n, each input's number <n> is shown, and is accessible as the
320 automatically generated variable _i<n> as well as In[<n>]. Multi-line
339 automatically generated variable _i<n> as well as In[<n>]. Multi-line
321 statements are printed starting at a new line for easy copy/paste.
340 statements are printed starting at a new line for easy copy/paste.
322
341
323 Options:
342 Options:
324
343
325 -n: print line numbers for each input.
344 -n: print line numbers for each input.
326 This feature is only available if numbered prompts are in use.
345 This feature is only available if numbered prompts are in use.
327
346
328 -o: also print outputs for each input.
347 -o: also print outputs for each input.
329
348
330 -p: print classic '>>>' python prompts before each input. This is useful
349 -p: print classic '>>>' python prompts before each input. This is useful
331 for making documentation, and in conjunction with -o, for producing
350 for making documentation, and in conjunction with -o, for producing
332 doctest-ready output.
351 doctest-ready output.
333
352
334 -r: (default) print the 'raw' history, i.e. the actual commands you typed.
353 -r: (default) print the 'raw' history, i.e. the actual commands you typed.
335
354
336 -t: print the 'translated' history, as IPython understands it. IPython
355 -t: print the 'translated' history, as IPython understands it. IPython
337 filters your input and converts it all into valid Python source before
356 filters your input and converts it all into valid Python source before
338 executing it (things like magics or aliases are turned into function
357 executing it (things like magics or aliases are turned into function
339 calls, for example). With this option, you'll see the native history
358 calls, for example). With this option, you'll see the native history
340 instead of the user-entered version: '%cd /' will be seen as
359 instead of the user-entered version: '%cd /' will be seen as
341 'get_ipython().magic("%cd /")' instead of '%cd /'.
360 'get_ipython().magic("%cd /")' instead of '%cd /'.
342
361
343 -g: treat the arg as a pattern to grep for in (full) history.
362 -g: treat the arg as a pattern to grep for in (full) history.
344 This includes the saved history (almost all commands ever written).
363 This includes the saved history (almost all commands ever written).
345 Use '%hist -g' to show full saved history (may be very long).
364 Use '%hist -g' to show full saved history (may be very long).
346
365
347 -f FILENAME: instead of printing the output to the screen, redirect it to
366 -f FILENAME: instead of printing the output to the screen, redirect it to
348 the given file. The file is always overwritten, though IPython asks for
367 the given file. The file is always overwritten, though IPython asks for
349 confirmation first if it already exists.
368 confirmation first if it already exists.
350
369
351 Examples
370 Examples
352 --------
371 --------
353 ::
372 ::
354
373
355 In [6]: %hist -n 4 6
374 In [6]: %hist -n 4 6
356 4:a = 12
375 4:a = 12
357 5:print a**2
376 5:print a**2
358
377
359 """
378 """
360
379
361 if not self.shell.displayhook.do_full_cache:
380 if not self.shell.displayhook.do_full_cache:
362 print('This feature is only available if numbered prompts are in use.')
381 print('This feature is only available if numbered prompts are in use.')
363 return
382 return
364 opts,args = self.parse_options(parameter_s,'gnoptsrf:',mode='list')
383 opts,args = self.parse_options(parameter_s,'gnoptsrf:',mode='list')
365
384
366 # For brevity
385 # For brevity
367 history_manager = self.shell.history_manager
386 history_manager = self.shell.history_manager
368
387
369 # Check if output to specific file was requested.
388 # Check if output to specific file was requested.
370 try:
389 try:
371 outfname = opts['f']
390 outfname = opts['f']
372 except KeyError:
391 except KeyError:
373 outfile = IPython.utils.io.Term.cout # default
392 outfile = IPython.utils.io.Term.cout # default
374 # We don't want to close stdout at the end!
393 # We don't want to close stdout at the end!
375 close_at_end = False
394 close_at_end = False
376 else:
395 else:
377 if os.path.exists(outfname):
396 if os.path.exists(outfname):
378 if not ask_yes_no("File %r exists. Overwrite?" % outfname):
397 if not ask_yes_no("File %r exists. Overwrite?" % outfname):
379 print('Aborting.')
398 print('Aborting.')
380 return
399 return
381
400
382 outfile = open(outfname,'w')
401 outfile = open(outfname,'w')
383 close_at_end = True
402 close_at_end = True
384
403
385 print_nums = 'n' in opts
404 print_nums = 'n' in opts
386 print_outputs = 'o' in opts
405 print_outputs = 'o' in opts
387 pyprompts = 'p' in opts
406 pyprompts = 'p' in opts
388 # Raw history is the default
407 # Raw history is the default
389 raw = not('t' in opts)
408 raw = not('t' in opts)
390
409
391 default_length = 40
410 default_length = 40
392 pattern = None
411 pattern = None
393 if 'g' in opts:
412 if 'g' in opts:
394 start = 1; stop = None
413 start = 1; stop = None
395 parts = parameter_s.split(None, 1)
414 parts = parameter_s.split(None, 1)
396 if len(parts) == 1:
415 if len(parts) == 1:
397 parts += '*'
416 parts += '*'
398 head, pattern = parts
417 head, pattern = parts
399 pattern = "*" + pattern + "*"
418 pattern = "*" + pattern + "*"
400 elif len(args) == 0:
419 elif len(args) == 0:
401 start = 1; stop = None
420 start = 1; stop = None
402 elif len(args) == 1:
421 elif len(args) == 1:
403 start = -int(args[0]); stop=None
422 start = -int(args[0]); stop=None
404 elif len(args) == 2:
423 elif len(args) == 2:
405 start = int(args[0]); stop = int(args[1])
424 start = int(args[0]); stop = int(args[1])
406 else:
425 else:
407 warn('%hist takes 0, 1 or 2 arguments separated by spaces.')
426 warn('%hist takes 0, 1 or 2 arguments separated by spaces.')
408 print(self.magic_hist.__doc__, file=IPython.utils.io.Term.cout)
427 print(self.magic_hist.__doc__, file=IPython.utils.io.Term.cout)
409 return
428 return
410
429
411 hist = history_manager.get_history(start, stop, raw, print_outputs)
430 hist = history_manager.get_history(start, stop, raw, print_outputs)
412
431
413 width = len(str(max(hist.iterkeys())))
432 width = len(str(max(hist.iterkeys())))
414 line_sep = ['','\n']
433 line_sep = ['','\n']
415
434
416 found = False
435 found = False
417 if pattern is not None:
436 if pattern is not None:
418 for session, line, s in history_manager.globsearch_db(pattern):
437 for session, line, s in history_manager.globsearch_db(pattern):
419 print("%d#%d: %s" %(session, line, s.expandtabs(4)), file=outfile)
438 print("%d#%d: %s" %(session, line, s.expandtabs(4)), file=outfile)
420 found = True
439 found = True
421
440
422 if found:
441 if found:
423 print("===", file=outfile)
442 print("===", file=outfile)
424 print("shadow history ends, fetch by %rep session#line",
443 print("shadow history ends, fetch by %rep session#line",
425 file=outfile)
444 file=outfile)
426 print("=== start of normal history ===", file=outfile)
445 print("=== start of normal history ===", file=outfile)
427
446
428 for in_num, inline in sorted(hist.iteritems()):
447 for in_num, inline in sorted(hist.iteritems()):
429 # Print user history with tabs expanded to 4 spaces. The GUI clients
448 # Print user history with tabs expanded to 4 spaces. The GUI clients
430 # use hard tabs for easier usability in auto-indented code, but we want
449 # use hard tabs for easier usability in auto-indented code, but we want
431 # to produce PEP-8 compliant history for safe pasting into an editor.
450 # to produce PEP-8 compliant history for safe pasting into an editor.
432 if print_outputs:
451 if print_outputs:
433 inline, output = inline
452 inline, output = inline
434 inline = inline.expandtabs(4).rstrip()
453 inline = inline.expandtabs(4).rstrip()
435
454
436 if pattern is not None and not fnmatch.fnmatch(inline, pattern):
455 if pattern is not None and not fnmatch.fnmatch(inline, pattern):
437 continue
456 continue
438
457
439 multiline = "\n" in inline
458 multiline = "\n" in inline
440 if print_nums:
459 if print_nums:
441 print('%s:%s' % (str(in_num).ljust(width), line_sep[multiline]),
460 print('%s:%s' % (str(in_num).ljust(width), line_sep[multiline]),
442 file=outfile, end='')
461 file=outfile, end='')
443 if pyprompts:
462 if pyprompts:
444 print(">>> ", end="", file=outfile)
463 print(">>> ", end="", file=outfile)
445 if multiline:
464 if multiline:
446 inline = "\n... ".join(inline.splitlines()) + "\n..."
465 inline = "\n... ".join(inline.splitlines()) + "\n..."
447 print(inline, file=outfile)
466 print(inline, file=outfile)
448 if print_outputs and output:
467 if print_outputs and output:
449 print(repr(output), file=outfile)
468 print(repr(output), file=outfile)
450
469
451 if close_at_end:
470 if close_at_end:
452 outfile.close()
471 outfile.close()
453
472
454 # %hist is an alternative name
473 # %hist is an alternative name
455 magic_hist = magic_history
474 magic_hist = magic_history
456
475
457
476
458 def rep_f(self, arg):
477 def rep_f(self, arg):
459 r""" Repeat a command, or get command to input line for editing
478 r""" Repeat a command, or get command to input line for editing
460
479
461 - %rep (no arguments):
480 - %rep (no arguments):
462
481
463 Place a string version of last computation result (stored in the special '_'
482 Place a string version of last computation result (stored in the special '_'
464 variable) to the next input prompt. Allows you to create elaborate command
483 variable) to the next input prompt. Allows you to create elaborate command
465 lines without using copy-paste::
484 lines without using copy-paste::
466
485
467 $ l = ["hei", "vaan"]
486 $ l = ["hei", "vaan"]
468 $ "".join(l)
487 $ "".join(l)
469 ==> heivaan
488 ==> heivaan
470 $ %rep
489 $ %rep
471 $ heivaan_ <== cursor blinking
490 $ heivaan_ <== cursor blinking
472
491
473 %rep 45
492 %rep 45
474
493
475 Place history line 45 to next input prompt. Use %hist to find out the
494 Place history line 45 to next input prompt. Use %hist to find out the
476 number.
495 number.
477
496
478 %rep 1-4 6-7 3
497 %rep 1-4 6-7 3
479
498
480 Repeat the specified lines immediately. Input slice syntax is the same as
499 Repeat the specified lines immediately. Input slice syntax is the same as
481 in %macro and %save.
500 in %macro and %save.
482
501
483 %rep foo
502 %rep foo
484
503
485 Place the most recent line that has the substring "foo" to next input.
504 Place the most recent line that has the substring "foo" to next input.
486 (e.g. 'svn ci -m foobar').
505 (e.g. 'svn ci -m foobar').
487 """
506 """
488
507
489 opts,args = self.parse_options(arg,'',mode='list')
508 opts,args = self.parse_options(arg,'',mode='list')
490 if not args:
509 if not args:
491 self.set_next_input(str(self.shell.user_ns["_"]))
510 self.set_next_input(str(self.shell.user_ns["_"]))
492 return
511 return
493
512
494 if len(args) == 1 and not '-' in args[0]:
513 if len(args) == 1 and not '-' in args[0]:
495 arg = args[0]
514 arg = args[0]
496 if len(arg) > 1 and arg.startswith('0'):
515 if len(arg) > 1 and arg.startswith('0'):
497 # get from shadow hist
516 # get from shadow hist
498 num = int(arg[1:])
517 num = int(arg[1:])
499 line = self.shell.shadowhist.get(num)
518 line = self.shell.shadowhist.get(num)
500 self.set_next_input(str(line))
519 self.set_next_input(str(line))
501 return
520 return
502 try:
521 try:
503 num = int(args[0])
522 num = int(args[0])
504 self.set_next_input(str(self.shell.input_hist_raw[num]).rstrip())
523 self.set_next_input(str(self.shell.input_hist_raw[num]).rstrip())
505 return
524 return
506 except ValueError:
525 except ValueError:
507 pass
526 pass
508
527
509 for h in reversed(self.shell.input_hist_raw):
528 for h in reversed(self.shell.input_hist_raw):
510 if 'rep' in h:
529 if 'rep' in h:
511 continue
530 continue
512 if fnmatch.fnmatch(h,'*' + arg + '*'):
531 if fnmatch.fnmatch(h,'*' + arg + '*'):
513 self.set_next_input(str(h).rstrip())
532 self.set_next_input(str(h).rstrip())
514 return
533 return
515
534
516 try:
535 try:
517 lines = self.extract_input_slices(args, True)
536 lines = self.extract_input_slices(args, True)
518 print("lines", lines)
537 print("lines", lines)
519 self.run_cell(lines)
538 self.run_cell(lines)
520 except ValueError:
539 except ValueError:
521 print("Not found in recent history:", args)
540 print("Not found in recent history:", args)
522
541
523
542
524 def init_ipython(ip):
543 def init_ipython(ip):
525 ip.define_magic("rep",rep_f)
544 ip.define_magic("rep",rep_f)
526 ip.define_magic("hist",magic_hist)
545 ip.define_magic("hist",magic_hist)
527 ip.define_magic("history",magic_history)
546 ip.define_magic("history",magic_history)
528
547
529 # XXX - ipy_completers are in quarantine, need to be updated to new apis
548 # XXX - ipy_completers are in quarantine, need to be updated to new apis
530 #import ipy_completers
549 #import ipy_completers
531 #ipy_completers.quick_completer('%hist' ,'-g -t -r -n')
550 #ipy_completers.quick_completer('%hist' ,'-g -t -r -n')
General Comments 0
You need to be logged in to leave comments. Login now