##// END OF EJS Templates
Merge branch 'sqlite-history' of github.com:takluyver/ipython
Thomas Kluyver -
r3439:d7ca41af merge
parent child Browse files
Show More
@@ -148,3 +148,14 b' c = get_config()'
148 # c.AliasManager.user_aliases = [
148 # c.AliasManager.user_aliases = [
149 # ('foo', 'echo Hi')
149 # ('foo', 'echo Hi')
150 # ]
150 # ]
151
152 #-----------------------------------------------------------------------------
153 # HistoryManager options
154 #-----------------------------------------------------------------------------
155
156 # Enable logging output as well as input to the database.
157 # c.HistoryManager.db_log_output = False
158
159 # Only write to the database every n commands - this can save disk
160 # access (and hence power) over the default of writing on every command.
161 # c.HistoryManager.db_cache_size = 0
@@ -277,10 +277,13 b' class DisplayHook(Configurable):'
277 self.shell.user_ns.update(to_main)
277 self.shell.user_ns.update(to_main)
278 self.shell.user_ns['_oh'][self.prompt_count] = result
278 self.shell.user_ns['_oh'][self.prompt_count] = result
279
279
280 def log_output(self, result):
280 def log_output(self, format_dict):
281 """Log the output."""
281 """Log the output."""
282 if self.shell.logger.log_output:
282 if self.shell.logger.log_output:
283 self.shell.logger.log_write(repr(result), 'output')
283 self.shell.logger.log_write(format_dict['text/plain'], 'output')
284 # This is a defaultdict of lists, so we can always append
285 self.shell.history_manager.output_hist_reprs[self.prompt_count]\
286 .append(format_dict['text/plain'])
284
287
285 def finish_displayhook(self):
288 def finish_displayhook(self):
286 """Finish up all displayhook activities."""
289 """Finish up all displayhook activities."""
@@ -300,7 +303,7 b' class DisplayHook(Configurable):'
300 format_dict = self.compute_format_data(result)
303 format_dict = self.compute_format_data(result)
301 self.write_format_data(format_dict)
304 self.write_format_data(format_dict)
302 self.update_user_ns(result)
305 self.update_user_ns(result)
303 self.log_output(result)
306 self.log_output(format_dict)
304 self.finish_displayhook()
307 self.finish_displayhook()
305
308
306 def flush(self):
309 def flush(self):
This diff has been collapsed as it changes many lines, (863 lines changed) Show them Hide them
@@ -13,47 +13,61 b''
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 datetime
17 import fnmatch
18 import json
17 import json
19 import os
18 import os
20 import sys
19 import re
21 import threading
20 import sqlite3
22 import time
21
22 from collections import defaultdict
23
23
24 # Our own packages
24 # Our own packages
25 from IPython.config.configurable import Configurable
25 import IPython.utils.io
26 import IPython.utils.io
26
27
27 from IPython.testing import decorators as testdec
28 from IPython.testing import decorators as testdec
28 from IPython.utils.pickleshare import PickleShareDB
29 from IPython.utils.io import ask_yes_no
29 from IPython.utils.io import ask_yes_no
30 from IPython.utils.traitlets import Bool, Dict, Instance, Int, List, Unicode
30 from IPython.utils.warn import warn
31 from IPython.utils.warn import warn
31
32
32 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
33 # Classes and functions
34 # Classes and functions
34 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
35
36
36 class HistoryManager(object):
37 class HistoryManager(Configurable):
37 """A class to organize all history-related functionality in one place.
38 """A class to organize all history-related functionality in one place.
38 """
39 """
39 # Public interface
40 # Public interface
40
41
41 # An instance of the IPython shell we are attached to
42 # An instance of the IPython shell we are attached to
42 shell = None
43 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
43 # A list to hold processed history
44 # Lists to hold processed and raw history. These start with a blank entry
44 input_hist_parsed = None
45 # so that we can index them starting from 1
45 # A list to hold raw history (as typed by user)
46 input_hist_parsed = List([""])
46 input_hist_raw = None
47 input_hist_raw = List([""])
47 # A list of directories visited during session
48 # A list of directories visited during session
48 dir_hist = None
49 dir_hist = List()
49 # A dict of output history, keyed with ints from the shell's execution count
50 # A dict of output history, keyed with ints from the shell's
50 output_hist = None
51 # execution count. If there are several outputs from one command,
51 # String with path to the history file
52 # only the last one is stored.
52 hist_file = None
53 output_hist = Dict()
53 # PickleShareDB instance holding the raw data for the shadow history
54 # Contains all outputs, in lists of reprs.
54 shadow_db = None
55 output_hist_reprs = Instance(defaultdict)
55 # ShadowHist instance with the actual shadow history
56
56 shadow_hist = None
57 # String holding the path to the history file
58 hist_file = Unicode()
59 # The SQLite database
60 db = Instance(sqlite3.Connection)
61 # The number of the current session in the history database
62 session_number = Int()
63 # Should we log output to the database? (default no)
64 db_log_output = Bool(False, config=True)
65 # Write to database every x commands (higher values save disk access & power)
66 # Values of 1 or less effectively disable caching.
67 db_cache_size = Int(0, config=True)
68 # The input and output caches
69 db_input_cache = List()
70 db_output_cache = List()
57
71
58 # Private interface
72 # Private interface
59 # Variables used to store the three last inputs from the user. On each new
73 # Variables used to store the three last inputs from the user. On each new
@@ -66,18 +80,11 b' class HistoryManager(object):'
66 # call).
80 # call).
67 _exit_commands = None
81 _exit_commands = None
68
82
69 def __init__(self, shell):
83 def __init__(self, shell, config=None):
70 """Create a new history manager associated with a shell instance.
84 """Create a new history manager associated with a shell instance.
71 """
85 """
72 # We need a pointer back to the shell for various tasks.
86 # We need a pointer back to the shell for various tasks.
73 self.shell = shell
87 super(HistoryManager, self).__init__(shell=shell, config=config)
74
75 # List of input with multi-line handling.
76 self.input_hist_parsed = []
77 # This one will hold the 'raw' input history, without any
78 # pre-processing. This will allow users to retrieve the input just as
79 # it was exactly typed in by the user, with %hist -r.
80 self.input_hist_raw = []
81
88
82 # list of visited directories
89 # list of visited directories
83 try:
90 try:
@@ -85,149 +92,260 b' class HistoryManager(object):'
85 except OSError:
92 except OSError:
86 self.dir_hist = []
93 self.dir_hist = []
87
94
88 # dict of output history
89 self.output_hist = {}
90
91 # Now the history file
95 # Now the history file
92 if shell.profile:
96 if shell.profile:
93 histfname = 'history-%s' % shell.profile
97 histfname = 'history-%s' % shell.profile
94 else:
98 else:
95 histfname = 'history'
99 histfname = 'history'
96 self.hist_file = os.path.join(shell.ipython_dir, histfname + '.json')
100 self.hist_file = os.path.join(shell.ipython_dir, histfname + '.sqlite')
97
101 try:
98 # Objects related to shadow history management
102 self.init_db()
99 self._init_shadow_hist()
103 except sqlite3.DatabaseError:
104 newpath = os.path.join(self.shell.ipython_dir, "hist-corrupt.sqlite")
105 os.rename(self.hist_file, newpath)
106 print("ERROR! History file wasn't a valid SQLite database.",
107 "It was moved to %s" % newpath, "and a new file created.")
108 self.init_db()
109
110 self.new_session()
100
111
101 self._i00, self._i, self._ii, self._iii = '','','',''
112 self._i00, self._i, self._ii, self._iii = '','','',''
113 self.output_hist_reprs = defaultdict(list)
102
114
103 self._exit_commands = set(['Quit', 'quit', 'Exit', 'exit', '%Quit',
115 self._exit_commands = set(['Quit', 'quit', 'Exit', 'exit', '%Quit',
104 '%quit', '%Exit', '%exit'])
116 '%quit', '%Exit', '%exit'])
105
106 # Object is fully initialized, we can now call methods on it.
107
117
108 # Fill the history zero entry, user counter starts at 1
118 def init_db(self):
109 self.store_inputs('\n', '\n')
119 """Connect to the database, and create tables if necessary."""
120 self.db = sqlite3.connect(self.hist_file)
121 self.db.execute("""CREATE TABLE IF NOT EXISTS sessions (session integer
122 primary key autoincrement, start timestamp,
123 end timestamp, num_cmds integer, remark text)""")
124 self.db.execute("""CREATE TABLE IF NOT EXISTS history
125 (session integer, line integer, source text, source_raw text,
126 PRIMARY KEY (session, line))""")
127 # Output history is optional, but ensure the table's there so it can be
128 # enabled later.
129 self.db.execute("""CREATE TABLE IF NOT EXISTS output_history
130 (session integer, line integer, output text,
131 PRIMARY KEY (session, line))""")
132 self.db.commit()
133
134 def new_session(self):
135 """Get a new session number."""
136 with self.db:
137 cur = self.db.execute("""INSERT INTO sessions VALUES (NULL, ?, NULL,
138 NULL, "") """, (datetime.datetime.now(),))
139 self.session_number = cur.lastrowid
140
141 def end_session(self):
142 """Close the database session, filling in the end time and line count."""
143 self.writeout_cache()
144 with self.db:
145 self.db.execute("""UPDATE sessions SET end=?, num_cmds=? WHERE
146 session==?""", (datetime.datetime.now(),
147 len(self.input_hist_parsed)-1, self.session_number))
148 self.session_number = 0
149
150 def name_session(self, name):
151 """Give the current session a name in the history database."""
152 with self.db:
153 self.db.execute("UPDATE sessions SET remark=? WHERE session==?",
154 (name, self.session_number))
155
156 def reset(self, new_session=True):
157 """Clear the session history, releasing all object references, and
158 optionally open a new session."""
159 if self.session_number:
160 self.end_session()
161 self.input_hist_parsed[:] = [""]
162 self.input_hist_raw[:] = [""]
163 self.output_hist.clear()
164 # The directory history can't be completely empty
165 self.dir_hist[:] = [os.getcwd()]
110
166
111 # Create and start the autosaver.
167 if new_session:
112 self.autosave_flag = threading.Event()
168 self.new_session()
113 self.autosave_timer = HistorySaveThread(self.autosave_flag, 60)
169
114 self.autosave_timer.start()
170 ## -------------------------------
115 # Register the autosave handler to be triggered as a post execute
171 ## Methods for retrieving history:
116 # callback.
172 ## -------------------------------
117 self.shell.register_post_execute(self.autosave_if_due)
173 def _run_sql(self, sql, params, raw=True, output=False):
118
174 """Prepares and runs an SQL query for the history database.
119 def _init_shadow_hist(self):
120 try:
121 self.shadow_db = PickleShareDB(os.path.join(
122 self.shell.ipython_dir, 'db'))
123 except UnicodeDecodeError:
124 print("Your ipython_dir can't be decoded to unicode!")
125 print("Please set HOME environment variable to something that")
126 print(r"only has ASCII characters, e.g. c:\home")
127 print("Now it is", self.ipython_dir)
128 sys.exit()
129 self.shadow_hist = ShadowHist(self.shadow_db, self.shell)
130
175
131 def populate_readline_history(self):
176 Parameters
132 """Populate the readline history from the raw history.
177 ----------
133
178 sql : str
134 We only store one copy of the raw history, which is persisted to a json
179 Any filtering expressions to go after SELECT ... FROM ...
135 file on disk. The readline history is repopulated from the contents of
180 params : tuple
136 this file."""
181 Parameters passed to the SQL query (to replace "?")
137
182 raw, output : bool
138 try:
183 See :meth:`get_range`
139 self.shell.readline.clear_history()
140 except AttributeError:
141 pass
142 else:
143 for h in self.input_hist_raw:
144 if not h.isspace():
145 for line in h.splitlines():
146 self.shell.readline.add_history(line)
147
148 def save_history(self):
149 """Save input history to a file (via readline library)."""
150 hist = dict(raw=self.input_hist_raw, #[-self.shell.history_length:],
151 parsed=self.input_hist_parsed) #[-self.shell.history_length:])
152 with open(self.hist_file,'wt') as hfile:
153 json.dump(hist, hfile,
154 sort_keys=True, indent=4)
155
156 def autosave_if_due(self):
157 """Check if the autosave event is set; if so, save history. We do it
158 this way so that the save takes place in the main thread."""
159 if self.autosave_flag.is_set():
160 self.save_history()
161 self.autosave_flag.clear()
162
184
163 def reload_history(self):
185 Returns
164 """Reload the input history from disk file."""
186 -------
165
187 Tuples as :meth:`get_range`
166 with open(self.hist_file,'rt') as hfile:
188 """
167 try:
189 toget = 'source_raw' if raw else 'source'
168 hist = json.load(hfile)
190 sqlfrom = "history"
169 except ValueError: # Ignore it if JSON is corrupt.
191 if output:
170 return
192 sqlfrom = "history LEFT JOIN output_history USING (session, line)"
171 self.input_hist_parsed = hist['parsed']
193 toget = "history.%s, output_history.output" % toget
172 self.input_hist_raw = hist['raw']
194 cur = self.db.execute("SELECT session, line, %s FROM %s " %\
173 if self.shell.has_readline:
195 (toget, sqlfrom) + sql, params)
174 self.populate_readline_history()
196 if output: # Regroup into 3-tuples, and parse JSON
197 loads = lambda out: json.loads(out) if out else None
198 return ((ses, lin, (inp, loads(out))) \
199 for ses, lin, inp, out in cur)
200 return cur
201
202
203 def get_tail(self, n=10, raw=True, output=False, include_latest=False):
204 """Get the last n lines from the history database.
175
205
176 def get_history(self, index=None, raw=False, output=True):
177 """Get the history list.
178
179 Get the input and output history.
180
181 Parameters
206 Parameters
182 ----------
207 ----------
183 index : n or (n1, n2) or None
208 n : int
184 If n, then the last entries. If a tuple, then all in
209 The number of lines to get
185 range(n1, n2). If None, then all entries. Raises IndexError if
210 raw, output : bool
186 the format of index is incorrect.
211 See :meth:`get_range`
187 raw : bool
212 include_latest : bool
188 If True, return the raw input.
213 If False (default), n+1 lines are fetched, and the latest one
189 output : bool
214 is discarded. This is intended to be used where the function
190 If True, then return the output as well.
215 is called by a user command, which it should not return.
191
216
192 Returns
217 Returns
193 -------
218 -------
194 If output is True, then return a dict of tuples, keyed by the prompt
219 Tuples as :meth:`get_range`
195 numbers and with values of (input, output). If output is False, then
196 a dict, keyed by the prompt number with the values of input. Raises
197 IndexError if no history is found.
198 """
220 """
199 if raw:
221 self.writeout_cache()
200 input_hist = self.input_hist_raw
222 if not include_latest:
201 else:
223 n += 1
202 input_hist = self.input_hist_parsed
224 cur = self._run_sql("ORDER BY session DESC, line DESC LIMIT ?",
225 (n,), raw=raw, output=output)
226 if not include_latest:
227 return reversed(list(cur)[1:])
228 return reversed(list(cur))
229
230 def search(self, pattern="*", raw=True, search_raw=True,
231 output=False):
232 """Search the database using unix glob-style matching (wildcards
233 * and ?).
234
235 Parameters
236 ----------
237 pattern : str
238 The wildcarded pattern to match when searching
239 search_raw : bool
240 If True, search the raw input, otherwise, the parsed input
241 raw, output : bool
242 See :meth:`get_range`
243
244 Returns
245 -------
246 Tuples as :meth:`get_range`
247 """
248 tosearch = "source_raw" if search_raw else "source"
203 if output:
249 if output:
204 output_hist = self.output_hist
250 tosearch = "history." + tosearch
251 self.writeout_cache()
252 return self._run_sql("WHERE %s GLOB ?" % tosearch, (pattern,),
253 raw=raw, output=output)
254
255 def _get_range_session(self, start=1, stop=None, raw=True, output=False):
256 """Get input and output history from the current session. Called by
257 get_range, and takes similar parameters."""
258 input_hist = self.input_hist_raw if raw else self.input_hist_parsed
259
205 n = len(input_hist)
260 n = len(input_hist)
206 if index is None:
261 if start < 0:
207 start=0; stop=n
262 start += n
208 elif isinstance(index, int):
263 if not stop:
209 start=n-index; stop=n
264 stop = n
210 elif isinstance(index, tuple) and len(index) == 2:
265 elif stop < 0:
211 start=index[0]; stop=index[1]
266 stop += n
212 else:
267
213 raise IndexError('Not a valid index for the input history: %r'
214 % index)
215 hist = {}
216 for i in range(start, stop):
268 for i in range(start, stop):
217 if output:
269 if output:
218 hist[i] = (input_hist[i], output_hist.get(i))
270 line = (input_hist[i], self.output_hist_reprs.get(i))
219 else:
271 else:
220 hist[i] = input_hist[i]
272 line = input_hist[i]
221 if not hist:
273 yield (0, i, line)
222 raise IndexError('No history for range of indices: %r' % index)
274
223 return hist
275 def get_range(self, session=0, start=1, stop=None, raw=True,output=False):
224
276 """Retrieve input by session.
225 def store_inputs(self, source, source_raw=None):
277
278 Parameters
279 ----------
280 session : int
281 Session number to retrieve. The current session is 0, and negative
282 numbers count back from current session, so -1 is previous session.
283 start : int
284 First line to retrieve.
285 stop : int
286 End of line range (excluded from output itself). If None, retrieve
287 to the end of the session.
288 raw : bool
289 If True, return untranslated input
290 output : bool
291 If True, attempt to include output. This will be 'real' Python
292 objects for the current session, or text reprs from previous
293 sessions if db_log_output was enabled at the time. Where no output
294 is found, None is used.
295
296 Returns
297 -------
298 An iterator over the desired lines. Each line is a 3-tuple, either
299 (session, line, input) if output is False, or
300 (session, line, (input, output)) if output is True.
301 """
302 if session == 0 or session==self.session_number: # Current session
303 return self._get_range_session(start, stop, raw, output)
304 if session < 0:
305 session += self.session_number
306
307 if stop:
308 lineclause = "line >= ? AND line < ?"
309 params = (session, start, stop)
310 else:
311 lineclause = "line>=?"
312 params = (session, start)
313
314 return self._run_sql("WHERE session==? AND %s""" % lineclause,
315 params, raw=raw, output=output)
316
317 def get_range_by_str(self, rangestr, raw=True, output=False):
318 """Get lines of history from a string of ranges, as used by magic
319 commands %hist, %save, %macro, etc.
320
321 Parameters
322 ----------
323 rangestr : str
324 A string specifying ranges, e.g. "5 ~2/1-4". See
325 :func:`magic_history` for full details.
326 raw, output : bool
327 As :meth:`get_range`
328
329 Returns
330 -------
331 Tuples as :meth:`get_range`
332 """
333 for sess, s, e in extract_hist_ranges(rangestr):
334 for line in self.get_range(sess, s, e, raw=raw, output=output):
335 yield line
336
337 ## ----------------------------
338 ## Methods for storing history:
339 ## ----------------------------
340 def store_inputs(self, line_num, source, source_raw=None):
226 """Store source and raw input in history and create input cache
341 """Store source and raw input in history and create input cache
227 variables _i*.
342 variables _i*.
228
343
229 Parameters
344 Parameters
230 ----------
345 ----------
346 line_num : int
347 The prompt number of this input.
348
231 source : str
349 source : str
232 Python input.
350 Python input.
233
351
@@ -237,14 +355,20 b' class HistoryManager(object):'
237 """
355 """
238 if source_raw is None:
356 if source_raw is None:
239 source_raw = source
357 source_raw = source
358 source = source.rstrip('\n')
359 source_raw = source_raw.rstrip('\n')
240
360
241 # do not store exit/quit commands
361 # do not store exit/quit commands
242 if source_raw.strip() in self._exit_commands:
362 if source_raw.strip() in self._exit_commands:
243 return
363 return
244
364
245 self.input_hist_parsed.append(source.rstrip())
365 self.input_hist_parsed.append(source)
246 self.input_hist_raw.append(source_raw.rstrip())
366 self.input_hist_raw.append(source_raw)
247 self.shadow_hist.add(source)
367
368 self.db_input_cache.append((line_num, source, source_raw))
369 # Trigger to flush cache and write to DB.
370 if len(self.db_input_cache) >= self.db_cache_size:
371 self.writeout_cache()
248
372
249 # update the auto _i variables
373 # update the auto _i variables
250 self._iii = self._ii
374 self._iii = self._ii
@@ -253,58 +377,114 b' class HistoryManager(object):'
253 self._i00 = source_raw
377 self._i00 = source_raw
254
378
255 # hackish access to user namespace to create _i1,_i2... dynamically
379 # hackish access to user namespace to create _i1,_i2... dynamically
256 new_i = '_i%s' % self.shell.execution_count
380 new_i = '_i%s' % line_num
257 to_main = {'_i': self._i,
381 to_main = {'_i': self._i,
258 '_ii': self._ii,
382 '_ii': self._ii,
259 '_iii': self._iii,
383 '_iii': self._iii,
260 new_i : self._i00 }
384 new_i : self._i00 }
261 self.shell.user_ns.update(to_main)
385 self.shell.user_ns.update(to_main)
262
386
263 def sync_inputs(self):
387 def store_output(self, line_num):
264 """Ensure raw and translated histories have same length."""
388 """If database output logging is enabled, this saves all the
265 if len(self.input_hist_parsed) != len (self.input_hist_raw):
389 outputs from the indicated prompt number to the database. It's
266 self.input_hist_raw[:] = self.input_hist_parsed
390 called by run_cell after code has been executed.
267
391
268 def reset(self):
392 Parameters
269 """Clear all histories managed by this object."""
393 ----------
270 self.input_hist_parsed[:] = []
394 line_num : int
271 self.input_hist_raw[:] = []
395 The line number from which to save outputs
272 self.output_hist.clear()
396 """
273 # The directory history can't be completely empty
397 if (not self.db_log_output) or not self.output_hist_reprs[line_num]:
274 self.dir_hist[:] = [os.getcwd()]
398 return
275
399 output = json.dumps(self.output_hist_reprs[line_num])
276 class HistorySaveThread(threading.Thread):
400
277 """This thread makes IPython save history periodically.
401 self.db_output_cache.append((line_num, output))
278
402 if self.db_cache_size <= 1:
279 Without this class, IPython would only save the history on a clean exit.
403 self.writeout_cache()
280 This saves the history periodically (the current default is once per
404
281 minute), so that it is not lost in the event of a crash.
405 def _writeout_input_cache(self):
406 for line in self.db_input_cache:
407 with self.db:
408 self.db.execute("INSERT INTO history VALUES (?, ?, ?, ?)",
409 (self.session_number,)+line)
282
410
283 The implementation sets an event to indicate that history should be saved.
411 def _writeout_output_cache(self):
284 The actual save is carried out after executing a user command, to avoid
412 for line in self.db_output_cache:
285 thread issues.
413 with self.db:
286 """
414 self.db.execute("INSERT INTO output_history VALUES (?, ?, ?)",
287 daemon = True
415 (self.session_number,)+line)
288
416
289 def __init__(self, autosave_flag, time_interval=60):
417 def writeout_cache(self):
290 threading.Thread.__init__(self)
418 """Write any entries in the cache to the database."""
291 self.time_interval = time_interval
419 try:
292 self.autosave_flag = autosave_flag
420 self._writeout_input_cache()
293 self.exit_now = threading.Event()
421 except sqlite3.IntegrityError:
294 # Ensure the thread is stopped tidily when exiting normally
422 self.new_session()
295 atexit.register(self.stop)
423 print("ERROR! Session/line number was not unique in",
296
424 "database. History logging moved to new session",
297 def run(self):
425 self.session_number)
298 while True:
426 try: # Try writing to the new session. If this fails, don't recurse
299 self.exit_now.wait(self.time_interval)
427 self.writeout_cache()
300 if self.exit_now.is_set():
428 except sqlite3.IntegrityError:
301 break
429 pass
302 self.autosave_flag.set()
430 finally:
431 self.db_input_cache = []
303
432
304 def stop(self):
433 try:
305 """Safely and quickly stop the autosave timer thread."""
434 self._writeout_output_cache()
306 self.exit_now.set()
435 except sqlite3.IntegrityError:
307 self.join()
436 print("!! Session/line number for output was not unique",
437 "in database. Output will not be stored.")
438 finally:
439 self.db_output_cache = []
440
441
442 # To match, e.g. ~5/8-~2/3
443 range_re = re.compile(r"""
444 ((?P<startsess>~?\d+)/)?
445 (?P<start>\d+) # Only the start line num is compulsory
446 ((?P<sep>[\-:])
447 ((?P<endsess>~?\d+)/)?
448 (?P<end>\d+))?
449 """, re.VERBOSE)
450
451 def extract_hist_ranges(ranges_str):
452 """Turn a string of history ranges into 3-tuples of (session, start, stop).
453
454 Examples
455 --------
456 list(extract_input_ranges("~8/5-~7/4 2"))
457 [(-8, 5, None), (-7, 1, 4), (0, 2, 3)]
458 """
459 for range_str in ranges_str.split():
460 rmatch = range_re.match(range_str)
461 if not rmatch:
462 continue
463 start = int(rmatch.group("start"))
464 end = rmatch.group("end")
465 end = int(end) if end else start+1 # If no end specified, get (a, a+1)
466 if rmatch.group("sep") == "-": # 1-3 == 1:4 --> [1, 2, 3]
467 end += 1
468 startsess = rmatch.group("startsess") or "0"
469 endsess = rmatch.group("endsess") or startsess
470 startsess = int(startsess.replace("~","-"))
471 endsess = int(endsess.replace("~","-"))
472 assert endsess >= startsess
473
474 if endsess == startsess:
475 yield (startsess, start, end)
476 continue
477 # Multiple sessions in one range:
478 yield (startsess, start, None)
479 for sess in range(startsess+1, endsess):
480 yield (sess, 1, None)
481 yield (endsess, 1, end)
482
483 def _format_lineno(session, line):
484 """Helper function to format line numbers properly."""
485 if session == 0:
486 return str(line)
487 return "%s#%s" % (session, line)
308
488
309 @testdec.skip_doctest
489 @testdec.skip_doctest
310 def magic_history(self, parameter_s = ''):
490 def magic_history(self, parameter_s = ''):
@@ -315,11 +495,18 b" def magic_history(self, parameter_s = ''):"
315 %history n1 n2 -> print inputs between n1 and n2 (n2 not included)\\
495 %history n1 n2 -> print inputs between n1 and n2 (n2 not included)\\
316
496
317 By default, input history is printed without line numbers so it can be
497 By default, input history is printed without line numbers so it can be
318 directly pasted into an editor.
498 directly pasted into an editor. Use -n to show them.
319
499
320 With -n, each input's number <n> is shown, and is accessible as the
500 Ranges of history can be indicated using the syntax:
321 automatically generated variable _i<n> as well as In[<n>]. Multi-line
501 4 : Line 4, current session
322 statements are printed starting at a new line for easy copy/paste.
502 4-6 : Lines 4-6, current session
503 243/1-5: Lines 1-5, session 243
504 ~2/7 : Line 7, session 2 before current
505 ~8/1-~6/5 : From the first line of 8 sessions ago, to the fifth line
506 of 6 sessions ago.
507 Multiple ranges can be entered, separated by spaces
508
509 The same syntax is used by %macro, %save, %edit, %rerun
323
510
324 Options:
511 Options:
325
512
@@ -342,9 +529,11 b" def magic_history(self, parameter_s = ''):"
342 'get_ipython().magic("%cd /")' instead of '%cd /'.
529 'get_ipython().magic("%cd /")' instead of '%cd /'.
343
530
344 -g: treat the arg as a pattern to grep for in (full) history.
531 -g: treat the arg as a pattern to grep for in (full) history.
345 This includes the "shadow history" (almost all commands ever written).
532 This includes the saved history (almost all commands ever written).
346 Use '%hist -g' to show full shadow history (may be very long).
533 Use '%hist -g' to show full saved history (may be very long).
347 In shadow history, every index nuwber starts with 0.
534
535 -l: get the last n lines from all sessions. Specify n as a single arg, or
536 the default is the last 10 lines.
348
537
349 -f FILENAME: instead of printing the output to the screen, redirect it to
538 -f FILENAME: instead of printing the output to the screen, redirect it to
350 the given file. The file is always overwritten, though IPython asks for
539 the given file. The file is always overwritten, though IPython asks for
@@ -363,7 +552,16 b" def magic_history(self, parameter_s = ''):"
363 if not self.shell.displayhook.do_full_cache:
552 if not self.shell.displayhook.do_full_cache:
364 print('This feature is only available if numbered prompts are in use.')
553 print('This feature is only available if numbered prompts are in use.')
365 return
554 return
366 opts,args = self.parse_options(parameter_s,'gnoptsrf:',mode='list')
555 opts,args = self.parse_options(parameter_s,'noprtglf:',mode='string')
556
557 # For brevity
558 history_manager = self.shell.history_manager
559
560 def _format_lineno(session, line):
561 """Helper function to format line numbers properly."""
562 if session in (0, history_manager.session_number):
563 return str(line)
564 return "%s/%s" % (session, line)
367
565
368 # Check if output to specific file was requested.
566 # Check if output to specific file was requested.
369 try:
567 try:
@@ -380,96 +578,61 b" def magic_history(self, parameter_s = ''):"
380
578
381 outfile = open(outfname,'w')
579 outfile = open(outfname,'w')
382 close_at_end = True
580 close_at_end = True
383
384 if 't' in opts:
385 input_hist = self.shell.history_manager.input_hist_parsed
386 elif 'r' in opts:
387 input_hist = self.shell.history_manager.input_hist_raw
388 else:
389 # Raw history is the default
390 input_hist = self.shell.history_manager.input_hist_raw
391
392 default_length = 40
393 pattern = None
394 if 'g' in opts:
395 init = 1
396 final = len(input_hist)
397 parts = parameter_s.split(None, 1)
398 if len(parts) == 1:
399 parts += '*'
400 head, pattern = parts
401 pattern = "*" + pattern + "*"
402 elif len(args) == 0:
403 final = len(input_hist)-1
404 init = max(1,final-default_length)
405 elif len(args) == 1:
406 final = len(input_hist)
407 init = max(1, final-int(args[0]))
408 elif len(args) == 2:
409 init, final = map(int, args)
410 else:
411 warn('%hist takes 0, 1 or 2 arguments separated by spaces.')
412 print(self.magic_hist.__doc__, file=IPython.utils.io.Term.cout)
413 return
414
581
415 width = len(str(final))
416 line_sep = ['','\n']
417 print_nums = 'n' in opts
582 print_nums = 'n' in opts
418 print_outputs = 'o' in opts
583 get_output = 'o' in opts
419 pyprompts = 'p' in opts
584 pyprompts = 'p' in opts
585 # Raw history is the default
586 raw = not('t' in opts)
587
588 default_length = 40
589 pattern = None
420
590
421 found = False
591 if 'g' in opts: # Glob search
422 if pattern is not None:
592 pattern = "*" + args + "*" if args else "*"
423 sh = self.shell.history_manager.shadowhist.all()
593 hist = history_manager.search(pattern, raw=raw, output=get_output)
424 for idx, s in sh:
594 elif 'l' in opts: # Get 'tail'
425 if fnmatch.fnmatch(s, pattern):
595 try:
426 print("0%d: %s" %(idx, s.expandtabs(4)), file=outfile)
596 n = int(args)
427 found = True
597 except ValueError, IndexError:
598 n = 10
599 hist = history_manager.get_tail(n, raw=raw, output=get_output)
600 else:
601 if args: # Get history by ranges
602 hist = history_manager.get_range_by_str(args, raw, get_output)
603 else: # Just get history for the current session
604 hist = history_manager.get_range(raw=raw, output=get_output)
428
605
429 if found:
606 # We could be displaying the entire history, so let's not try to pull it
430 print("===", file=outfile)
607 # into a list in memory. Anything that needs more space will just misalign.
431 print("shadow history ends, fetch by %rep <number> (must start with 0)",
608 width = 4
432 file=outfile)
433 print("=== start of normal history ===", file=outfile)
434
609
435 for in_num in range(init, final):
610 for session, lineno, inline in hist:
436 # Print user history with tabs expanded to 4 spaces. The GUI clients
611 # Print user history with tabs expanded to 4 spaces. The GUI clients
437 # use hard tabs for easier usability in auto-indented code, but we want
612 # use hard tabs for easier usability in auto-indented code, but we want
438 # to produce PEP-8 compliant history for safe pasting into an editor.
613 # to produce PEP-8 compliant history for safe pasting into an editor.
439 inline = input_hist[in_num].expandtabs(4).rstrip()+'\n'
614 if get_output:
440
615 inline, output = inline
441 if pattern is not None and not fnmatch.fnmatch(inline, pattern):
616 inline = inline.expandtabs(4).rstrip()
442 continue
443
617
444 multiline = int(inline.count('\n') > 1)
618 multiline = "\n" in inline
619 line_sep = '\n' if multiline else ' '
445 if print_nums:
620 if print_nums:
446 print('%s:%s' % (str(in_num).ljust(width), line_sep[multiline]),
621 print('%s:%s' % (_format_lineno(session, lineno).rjust(width),
447 file=outfile)
622 line_sep), file=outfile, end='')
448 if pyprompts:
623 if pyprompts:
449 print('>>>', file=outfile)
624 print(">>> ", end="", file=outfile)
450 if multiline:
625 if multiline:
451 lines = inline.splitlines()
626 inline = "\n... ".join(inline.splitlines()) + "\n..."
452 print('\n... '.join(lines), file=outfile)
627 print(inline, file=outfile)
453 print('... ', file=outfile)
628 if get_output and output:
454 else:
629 print("\n".join(output), file=outfile)
455 print(inline, end='', file=outfile)
456 else:
457 print(inline, end='', file=outfile)
458 if print_outputs:
459 output = self.shell.history_manager.output_hist.get(in_num)
460 if output is not None:
461 print(repr(output), file=outfile)
462
630
463 if close_at_end:
631 if close_at_end:
464 outfile.close()
632 outfile.close()
465
633
466
634
467 def magic_hist(self, parameter_s=''):
635 def magic_rep(self, arg):
468 """Alternate name for %history."""
469 return self.magic_history(parameter_s)
470
471
472 def rep_f(self, arg):
473 r""" Repeat a command, or get command to input line for editing
636 r""" Repeat a command, or get command to input line for editing
474
637
475 - %rep (no arguments):
638 - %rep (no arguments):
@@ -478,110 +641,98 b' def rep_f(self, arg):'
478 variable) to the next input prompt. Allows you to create elaborate command
641 variable) to the next input prompt. Allows you to create elaborate command
479 lines without using copy-paste::
642 lines without using copy-paste::
480
643
481 $ l = ["hei", "vaan"]
644 In[1]: l = ["hei", "vaan"]
482 $ "".join(l)
645 In[2]: "".join(l)
483 ==> heivaan
646 Out[2]: heivaan
484 $ %rep
647 In[3]: %rep
485 $ heivaan_ <== cursor blinking
648 In[4]: heivaan_ <== cursor blinking
486
649
487 %rep 45
650 %rep 45
488
651
489 Place history line 45 to next input prompt. Use %hist to find out the
652 Place history line 45 on the next input prompt. Use %hist to find
490 number.
653 out the number.
491
654
492 %rep 1-4 6-7 3
655 %rep 1-4
493
656
494 Repeat the specified lines immediately. Input slice syntax is the same as
657 Combine the specified lines into one cell, and place it on the next
495 in %macro and %save.
658 input prompt. See %history for the slice syntax.
496
659
497 %rep foo
660 %rep foo+bar
498
661
499 Place the most recent line that has the substring "foo" to next input.
662 If foo+bar can be evaluated in the user namespace, the result is
500 (e.g. 'svn ci -m foobar').
663 placed at the next input prompt. Otherwise, the history is searched
664 for lines which contain that substring, and the most recent one is
665 placed at the next input prompt.
501 """
666 """
502
667 if not arg: # Last output
503 opts,args = self.parse_options(arg,'',mode='list')
504 if not args:
505 self.set_next_input(str(self.shell.user_ns["_"]))
668 self.set_next_input(str(self.shell.user_ns["_"]))
506 return
669 return
670 # Get history range
671 histlines = self.history_manager.get_range_by_str(arg)
672 cmd = "\n".join(x[2] for x in histlines)
673 if cmd:
674 self.set_next_input(cmd.rstrip())
675 return
507
676
508 if len(args) == 1 and not '-' in args[0]:
677 try: # Variable in user namespace
509 arg = args[0]
678 cmd = str(eval(arg, self.shell.user_ns))
510 if len(arg) > 1 and arg.startswith('0'):
679 except Exception: # Search for term in history
511 # get from shadow hist
680 histlines = self.history_manager.search("*"+arg+"*")
512 num = int(arg[1:])
681 for h in reversed([x[2] for x in histlines]):
513 line = self.shell.shadowhist.get(num)
514 self.set_next_input(str(line))
515 return
516 try:
517 num = int(args[0])
518 self.set_next_input(str(self.shell.input_hist_raw[num]).rstrip())
519 return
520 except ValueError:
521 pass
522
523 for h in reversed(self.shell.input_hist_raw):
524 if 'rep' in h:
682 if 'rep' in h:
525 continue
683 continue
526 if fnmatch.fnmatch(h,'*' + arg + '*'):
684 self.set_next_input(h.rstrip())
527 self.set_next_input(str(h).rstrip())
685 return
528 return
686 else:
529
687 self.set_next_input(cmd.rstrip())
530 try:
688 print("Couldn't evaluate or find in history:", arg)
531 lines = self.extract_input_slices(args, True)
532 print("lines", lines)
533 self.run_cell(lines)
534 except ValueError:
535 print("Not found in recent history:", args)
536
689
537
690 def magic_rerun(self, parameter_s=''):
538 _sentinel = object()
691 """Re-run previous input
539
540 class ShadowHist(object):
541 def __init__(self, db, shell):
542 # cmd => idx mapping
543 self.curidx = 0
544 self.db = db
545 self.disabled = False
546 self.shell = shell
547
692
548 def inc_idx(self):
693 By default, you can specify ranges of input history to be repeated
549 idx = self.db.get('shadowhist_idx', 1)
694 (as with %history). With no arguments, it will repeat the last line.
550 self.db['shadowhist_idx'] = idx + 1
551 return idx
552
553 def add(self, ent):
554 if self.disabled:
555 return
556 try:
557 old = self.db.hget('shadowhist', ent, _sentinel)
558 if old is not _sentinel:
559 return
560 newidx = self.inc_idx()
561 #print("new", newidx) # dbg
562 self.db.hset('shadowhist',ent, newidx)
563 except:
564 self.shell.showtraceback()
565 print("WARNING: disabling shadow history")
566 self.disabled = True
567
695
568 def all(self):
696 Options:
569 d = self.db.hdict('shadowhist')
697
570 items = [(i,s) for (s,i) in d.iteritems()]
698 -l <n> : Repeat the last n lines of input, not including the
571 items.sort()
699 current command.
572 return items
700
573
701 -g foo : Repeat the most recent line which contains foo
574 def get(self, idx):
702 """
575 all = self.all()
703 opts, args = self.parse_options(parameter_s, 'l:g:', mode='string')
576
704 if "l" in opts: # Last n lines
577 for k, v in all:
705 n = int(opts['l'])
578 if k == idx:
706 hist = self.history_manager.get_tail(n)
579 return v
707 elif "g" in opts: # Search
708 p = "*"+opts['g']+"*"
709 hist = list(self.history_manager.search(p))
710 for l in reversed(hist):
711 if "rerun" not in l[2]:
712 hist = [l] # The last match which isn't a %rerun
713 break
714 else:
715 hist = [] # No matches except %rerun
716 elif args: # Specify history ranges
717 hist = self.history_manager.get_range_by_str(args)
718 else: # Last line
719 hist = self.history_manager.get_tail(1)
720 hist = [x[2] for x in hist]
721 if not hist:
722 print("No lines in history match specification")
723 return
724 histlines = "\n".join(hist)
725 print("=== Executing: ===")
726 print(histlines)
727 print("=== Output: ===")
728 self.run_cell("\n".join(hist), store_history=False)
580
729
581
730
582 def init_ipython(ip):
731 def init_ipython(ip):
583 ip.define_magic("rep",rep_f)
732 ip.define_magic("rep", magic_rep)
584 ip.define_magic("hist",magic_hist)
733 ip.define_magic("recall", magic_rep)
734 ip.define_magic("rerun", magic_rerun)
735 ip.define_magic("hist",magic_history) # Alternative name
585 ip.define_magic("history",magic_history)
736 ip.define_magic("history",magic_history)
586
737
587 # XXX - ipy_completers are in quarantine, need to be updated to new apis
738 # XXX - ipy_completers are in quarantine, need to be updated to new apis
@@ -56,11 +56,11 b' from IPython.core.prefilter import PrefilterManager, ESC_MAGIC'
56 from IPython.external.Itpl import ItplNS
56 from IPython.external.Itpl import ItplNS
57 from IPython.utils import PyColorize
57 from IPython.utils import PyColorize
58 from IPython.utils import io
58 from IPython.utils import io
59 from IPython.utils import pickleshare
60 from IPython.utils.doctestreload import doctest_reload
59 from IPython.utils.doctestreload import doctest_reload
61 from IPython.utils.io import ask_yes_no, rprint
60 from IPython.utils.io import ask_yes_no, rprint
62 from IPython.utils.ipstruct import Struct
61 from IPython.utils.ipstruct import Struct
63 from IPython.utils.path import get_home_dir, get_ipython_dir, HomeDirError
62 from IPython.utils.path import get_home_dir, get_ipython_dir, HomeDirError
63 from IPython.utils.pickleshare import PickleShareDB
64 from IPython.utils.process import system, getoutput
64 from IPython.utils.process import system, getoutput
65 from IPython.utils.strdispatch import StrDispatch
65 from IPython.utils.strdispatch import StrDispatch
66 from IPython.utils.syspathcontext import prepended_to_syspath
66 from IPython.utils.syspathcontext import prepended_to_syspath
@@ -251,6 +251,11 b' class InteractiveShell(Configurable, Magic):'
251 # is what we want to do.
251 # is what we want to do.
252 self.save_sys_module_state()
252 self.save_sys_module_state()
253 self.init_sys_modules()
253 self.init_sys_modules()
254
255 # While we're trying to have each part of the code directly access what
256 # it needs without keeping redundant references to objects, we have too
257 # much legacy code that expects ip.db to exist.
258 self.db = PickleShareDB(os.path.join(self.ipython_dir, 'db'))
254
259
255 self.init_history()
260 self.init_history()
256 self.init_encoding()
261 self.init_encoding()
@@ -301,14 +306,6 b' class InteractiveShell(Configurable, Magic):'
301 self.hooks.late_startup_hook()
306 self.hooks.late_startup_hook()
302 atexit.register(self.atexit_operations)
307 atexit.register(self.atexit_operations)
303
308
304 # While we're trying to have each part of the code directly access what it
305 # needs without keeping redundant references to objects, we have too much
306 # legacy code that expects ip.db to exist, so let's make it a property that
307 # retrieves the underlying object from our new history manager.
308 @property
309 def db(self):
310 return self.history_manager.shadow_db
311
312 @classmethod
309 @classmethod
313 def instance(cls, *args, **kwargs):
310 def instance(cls, *args, **kwargs):
314 """Returns a global InteractiveShell instance."""
311 """Returns a global InteractiveShell instance."""
@@ -994,14 +991,16 b' class InteractiveShell(Configurable, Magic):'
994 # Finally, update the real user's namespace
991 # Finally, update the real user's namespace
995 self.user_ns.update(ns)
992 self.user_ns.update(ns)
996
993
997 def reset(self):
994 def reset(self, new_session=True):
998 """Clear all internal namespaces.
995 """Clear all internal namespaces.
999
996
1000 Note that this is much more aggressive than %reset, since it clears
997 Note that this is much more aggressive than %reset, since it clears
1001 fully all namespaces, as well as all input/output lists.
998 fully all namespaces, as well as all input/output lists.
999
1000 If new_session is True, a new history session will be opened.
1002 """
1001 """
1003 # Clear histories
1002 # Clear histories
1004 self.history_manager.reset()
1003 self.history_manager.reset(new_session)
1005
1004
1006 # Reset counter used to index all histories
1005 # Reset counter used to index all histories
1007 self.execution_count = 0
1006 self.execution_count = 0
@@ -1249,15 +1248,7 b' class InteractiveShell(Configurable, Magic):'
1249
1248
1250 def init_history(self):
1249 def init_history(self):
1251 """Sets up the command history, and starts regular autosaves."""
1250 """Sets up the command history, and starts regular autosaves."""
1252 self.history_manager = HistoryManager(shell=self)
1251 self.history_manager = HistoryManager(shell=self, config=self.config)
1253
1254 def save_history(self):
1255 """Save input history to a file (via readline library)."""
1256 self.history_manager.save_history()
1257
1258 def reload_history(self):
1259 """Reload the input history from disk file."""
1260 self.history_manager.reload_history()
1261
1252
1262 def history_saving_wrapper(self, func):
1253 def history_saving_wrapper(self, func):
1263 """ Wrap func for readline history saving
1254 """ Wrap func for readline history saving
@@ -1278,9 +1269,6 b' class InteractiveShell(Configurable, Magic):'
1278 self.reload_history()
1269 self.reload_history()
1279 return wrapper
1270 return wrapper
1280
1271
1281 def get_history(self, index=None, raw=False, output=True):
1282 return self.history_manager.get_history(index, raw, output)
1283
1284
1272
1285 #-------------------------------------------------------------------------
1273 #-------------------------------------------------------------------------
1286 # Things related to exception handling and tracebacks (not debugging)
1274 # Things related to exception handling and tracebacks (not debugging)
@@ -1561,11 +1549,13 b' class InteractiveShell(Configurable, Magic):'
1561 readline.set_completer_delims(delims)
1549 readline.set_completer_delims(delims)
1562 # otherwise we end up with a monster history after a while:
1550 # otherwise we end up with a monster history after a while:
1563 readline.set_history_length(self.history_length)
1551 readline.set_history_length(self.history_length)
1564 try:
1552
1565 #print '*** Reading readline history' # dbg
1553 # Load the last 1000 lines from history
1566 self.reload_history()
1554 for _, _, cell in self.history_manager.get_tail(1000,
1567 except IOError:
1555 include_latest=True):
1568 pass # It doesn't exist yet.
1556 if cell.strip(): # Ignore blank lines
1557 for line in cell.splitlines():
1558 readline.add_history(line)
1569
1559
1570 # Configure auto-indent for all platforms
1560 # Configure auto-indent for all platforms
1571 self.set_autoindent(self.autoindent)
1561 self.set_autoindent(self.autoindent)
@@ -2071,14 +2061,16 b' class InteractiveShell(Configurable, Magic):'
2071 self.showtraceback()
2061 self.showtraceback()
2072 warn('Unknown failure executing file: <%s>' % fname)
2062 warn('Unknown failure executing file: <%s>' % fname)
2073
2063
2074 def run_cell(self, cell):
2064 def run_cell(self, cell, store_history=True):
2075 """Run the contents of an entire multiline 'cell' of code.
2065 """Run the contents of an entire multiline 'cell' of code, and store it
2066 in the history.
2076
2067
2077 The cell is split into separate blocks which can be executed
2068 The cell is split into separate blocks which can be executed
2078 individually. Then, based on how many blocks there are, they are
2069 individually. Then, based on how many blocks there are, they are
2079 executed as follows:
2070 executed as follows:
2080
2071
2081 - A single block: 'single' mode.
2072 - A single block: 'single' mode. If it is also a single line, dynamic
2073 transformations, including automagic and macros, will be applied.
2082
2074
2083 If there's more than one block, it depends:
2075 If there's more than one block, it depends:
2084
2076
@@ -2097,6 +2089,15 b' class InteractiveShell(Configurable, Magic):'
2097 cell : str
2089 cell : str
2098 A single or multiline string.
2090 A single or multiline string.
2099 """
2091 """
2092 # Store the untransformed code
2093 raw_cell = cell
2094
2095 # We only do dynamic transforms on a single line. We need to do this
2096 # first, because a macro can be expanded to several lines, which then
2097 # need to be split into blocks again.
2098 if len(cell.splitlines()) <= 1:
2099 temp = self.input_splitter.split_blocks(cell)
2100 cell = self.prefilter_manager.prefilter_line(temp[0])
2100
2101
2101 # We need to break up the input into executable blocks that can be run
2102 # We need to break up the input into executable blocks that can be run
2102 # in 'single' mode, to provide comfortable user behavior.
2103 # in 'single' mode, to provide comfortable user behavior.
@@ -2108,32 +2109,36 b' class InteractiveShell(Configurable, Magic):'
2108 # Store the 'ipython' version of the cell as well, since that's what
2109 # Store the 'ipython' version of the cell as well, since that's what
2109 # needs to go into the translated history and get executed (the
2110 # needs to go into the translated history and get executed (the
2110 # original cell may contain non-python syntax).
2111 # original cell may contain non-python syntax).
2111 ipy_cell = ''.join(blocks)
2112 cell = ''.join(blocks)
2112
2113
2113 # Store raw and processed history
2114 # Store raw and processed history
2114 self.history_manager.store_inputs(ipy_cell, cell)
2115 if store_history:
2116 self.history_manager.store_inputs(self.execution_count,
2117 cell, raw_cell)
2115
2118
2116 self.logger.log(ipy_cell, cell)
2119 self.logger.log(cell, raw_cell)
2117
2120
2118 # All user code execution must happen with our context managers active
2121 # All user code execution must happen with our context managers active
2119 with nested(self.builtin_trap, self.display_trap):
2122 with nested(self.builtin_trap, self.display_trap):
2120
2123
2121 # Single-block input should behave like an interactive prompt
2124 # Single-block input should behave like an interactive prompt
2122 if len(blocks) == 1:
2125 if len(blocks) == 1:
2123 # since we return here, we need to update the execution count
2126 out = self.run_source(blocks[0])
2124 out = self.run_one_block(blocks[0])
2127 # Write output to the database. Does nothing unless
2125 self.execution_count += 1
2128 # history output logging is enabled.
2129 if store_history:
2130 self.history_manager.store_output(self.execution_count)
2131 # since we return here, we need to update the execution count
2132 self.execution_count += 1
2126 return out
2133 return out
2127
2134
2128 # In multi-block input, if the last block is a simple (one-two
2135 # In multi-block input, if the last block is a simple (one-two
2129 # lines) expression, run it in single mode so it produces output.
2136 # lines) expression, run it in single mode so it produces output.
2130 # Otherwise just feed the whole thing to run_code. This seems like
2137 # Otherwise just run it all in 'exec' mode. This seems like a
2131 # a reasonable usability design.
2138 # reasonable usability design.
2132 last = blocks[-1]
2139 last = blocks[-1]
2133 last_nlines = len(last.splitlines())
2140 last_nlines = len(last.splitlines())
2134
2141
2135 # Note: below, whenever we call run_code, we must sync history
2136 # ourselves, because run_code is NOT meant to manage history at all.
2137 if last_nlines < 2:
2142 if last_nlines < 2:
2138 # Here we consider the cell split between 'body' and 'last',
2143 # Here we consider the cell split between 'body' and 'last',
2139 # store all history and execute 'body', and if successful, then
2144 # store all history and execute 'body', and if successful, then
@@ -2144,55 +2149,19 b' class InteractiveShell(Configurable, Magic):'
2144 retcode = self.run_source(ipy_body, symbol='exec',
2149 retcode = self.run_source(ipy_body, symbol='exec',
2145 post_execute=False)
2150 post_execute=False)
2146 if retcode==0:
2151 if retcode==0:
2147 # And the last expression via runlines so it produces output
2152 # Last expression compiled as 'single' so it produces output
2148 self.run_one_block(last)
2153 self.run_source(last)
2149 else:
2154 else:
2150 # Run the whole cell as one entity, storing both raw and
2155 # Run the whole cell as one entity, storing both raw and
2151 # processed input in history
2156 # processed input in history
2152 self.run_source(ipy_cell, symbol='exec')
2157 self.run_source(ipy_cell, symbol='exec')
2153
2158
2154 # Each cell is a *single* input, regardless of how many lines it has
2159 # Write output to the database. Does nothing unless
2155 self.execution_count += 1
2160 # history output logging is enabled.
2156
2161 if store_history:
2157 def run_one_block(self, block):
2162 self.history_manager.store_output(self.execution_count)
2158 """Run a single interactive block of source code.
2163 # Each cell is a *single* input, regardless of how many lines it has
2159
2164 self.execution_count += 1
2160 If the block is single-line, dynamic transformations are applied to it
2161 (like automagics, autocall and alias recognition).
2162
2163 If the block is multi-line, it must consist of valid Python code only.
2164
2165 Parameters
2166 ----------
2167 block : string
2168 A (possibly multiline) string of code to be executed.
2169
2170 Returns
2171 -------
2172 The output of the underlying execution method used, be it
2173 :meth:`run_source` or :meth:`run_single_line`.
2174 """
2175 if len(block.splitlines()) <= 1:
2176 out = self.run_single_line(block)
2177 else:
2178 # Call run_source, which correctly compiles the input cell.
2179 # run_code must only be called when we know we have a code object,
2180 # as it does a naked exec and the compilation mode may not be what
2181 # we wanted.
2182 out = self.run_source(block)
2183 return out
2184
2185 def run_single_line(self, line):
2186 """Run a single-line interactive statement.
2187
2188 This assumes the input has been transformed to IPython syntax by
2189 applying all static transformations (those with an explicit prefix like
2190 % or !), but it will further try to apply the dynamic ones.
2191
2192 It does not update history.
2193 """
2194 tline = self.prefilter_manager.prefilter_line(line)
2195 return self.run_source(tline)
2196
2165
2197 # PENDING REMOVAL: this method is slated for deletion, once our new
2166 # PENDING REMOVAL: this method is slated for deletion, once our new
2198 # input logic has been 100% moved to frontends and is stable.
2167 # input logic has been 100% moved to frontends and is stable.
@@ -2205,8 +2174,8 b' class InteractiveShell(Configurable, Magic):'
2205 magic calls (%magic), special shell access (!cmd), etc.
2174 magic calls (%magic), special shell access (!cmd), etc.
2206 """
2175 """
2207
2176
2208 if isinstance(lines, (list, tuple)):
2177 if not isinstance(lines, (list, tuple)):
2209 lines = '\n'.join(lines)
2178 lines = lines.splitlines()
2210
2179
2211 if clean:
2180 if clean:
2212 lines = self._cleanup_ipy_script(lines)
2181 lines = self._cleanup_ipy_script(lines)
@@ -2214,7 +2183,6 b' class InteractiveShell(Configurable, Magic):'
2214 # We must start with a clean buffer, in case this is run from an
2183 # We must start with a clean buffer, in case this is run from an
2215 # interactive IPython session (via a magic, for example).
2184 # interactive IPython session (via a magic, for example).
2216 self.reset_buffer()
2185 self.reset_buffer()
2217 lines = lines.splitlines()
2218
2186
2219 # Since we will prefilter all lines, store the user's raw input too
2187 # Since we will prefilter all lines, store the user's raw input too
2220 # before we apply any transformations
2188 # before we apply any transformations
@@ -2401,8 +2369,8 b' class InteractiveShell(Configurable, Magic):'
2401 full_source = '\n'.join(self.buffer)
2369 full_source = '\n'.join(self.buffer)
2402 more = self.run_source(full_source, self.filename)
2370 more = self.run_source(full_source, self.filename)
2403 if not more:
2371 if not more:
2404 self.history_manager.store_inputs('\n'.join(self.buffer_raw),
2372 self.history_manager.store_inputs(self.execution_count,
2405 full_source)
2373 '\n'.join(self.buffer_raw), full_source)
2406 self.reset_buffer()
2374 self.reset_buffer()
2407 self.execution_count += 1
2375 self.execution_count += 1
2408 return more
2376 return more
@@ -2539,11 +2507,12 b' class InteractiveShell(Configurable, Magic):'
2539 os.unlink(tfile)
2507 os.unlink(tfile)
2540 except OSError:
2508 except OSError:
2541 pass
2509 pass
2542
2510
2543 self.save_history()
2511 # Close the history session (this stores the end time and line count)
2544
2512 self.history_manager.end_session()
2513
2545 # Clear all user namespaces to release all references cleanly.
2514 # Clear all user namespaces to release all references cleanly.
2546 self.reset()
2515 self.reset(new_session=False)
2547
2516
2548 # Run user hooks
2517 # Run user hooks
2549 self.hooks.shutdown_hook()
2518 self.hooks.shutdown_hook()
@@ -8,9 +8,8 b''
8 #*****************************************************************************
8 #*****************************************************************************
9
9
10 import IPython.utils.io
10 import IPython.utils.io
11 from IPython.core.autocall import IPyAutocall
12
11
13 class Macro(IPyAutocall):
12 class Macro(object):
14 """Simple class to store the value of macros as strings.
13 """Simple class to store the value of macros as strings.
15
14
16 Macro is just a callable that executes a string of IPython
15 Macro is just a callable that executes a string of IPython
@@ -19,9 +18,9 b' class Macro(IPyAutocall):'
19 Args to macro are available in _margv list if you need them.
18 Args to macro are available in _margv list if you need them.
20 """
19 """
21
20
22 def __init__(self,data):
21 def __init__(self,code):
23 """store the macro value, as a single string which can be executed"""
22 """store the macro value, as a single string which can be executed"""
24 self.value = ''.join(data).rstrip()+'\n'
23 self.value = code.rstrip()+'\n'
25
24
26 def __str__(self):
25 def __str__(self):
27 return self.value
26 return self.value
@@ -29,11 +28,6 b' class Macro(IPyAutocall):'
29 def __repr__(self):
28 def __repr__(self):
30 return 'IPython.macro.Macro(%s)' % repr(self.value)
29 return 'IPython.macro.Macro(%s)' % repr(self.value)
31
30
32 def __call__(self,*args):
33 IPython.utils.io.Term.cout.flush()
34 self._ip.user_ns['_margv'] = args
35 self._ip.run_cell(self.value)
36
37 def __getstate__(self):
31 def __getstate__(self):
38 """ needed for safe pickling via %store """
32 """ needed for safe pickling via %store """
39 return {'value': self.value}
33 return {'value': self.value}
@@ -57,7 +57,7 b' import IPython.utils.io'
57 from IPython.utils.path import get_py_filename
57 from IPython.utils.path import get_py_filename
58 from IPython.utils.process import arg_split, abbrev_cwd
58 from IPython.utils.process import arg_split, abbrev_cwd
59 from IPython.utils.terminal import set_term_title
59 from IPython.utils.terminal import set_term_title
60 from IPython.utils.text import LSString, SList, StringTypes, format_screen
60 from IPython.utils.text import LSString, SList, format_screen
61 from IPython.utils.timing import clock, clock2
61 from IPython.utils.timing import clock, clock2
62 from IPython.utils.warn import warn, error
62 from IPython.utils.warn import warn, error
63 from IPython.utils.ipstruct import Struct
63 from IPython.utils.ipstruct import Struct
@@ -165,14 +165,15 b' python-profiler package from non-free.""")'
165 out.sort()
165 out.sort()
166 return out
166 return out
167
167
168 def extract_input_slices(self,slices,raw=False):
168 def extract_input_lines(self, range_str, raw=False):
169 """Return as a string a set of input history slices.
169 """Return as a string a set of input history slices.
170
170
171 Inputs:
171 Inputs:
172
172
173 - slices: the set of slices is given as a list of strings (like
173 - range_str: the set of slices is given as a string, like
174 ['1','4:8','9'], since this function is for use by magic functions
174 "~5/6-~4/2 4:8 9", since this function is for use by magic functions
175 which get their arguments as strings.
175 which get their arguments as strings. The number before the / is the
176 session number: ~n goes n back from the current session.
176
177
177 Optional inputs:
178 Optional inputs:
178
179
@@ -184,24 +185,9 b' python-profiler package from non-free.""")'
184 N:M -> standard python form, means including items N...(M-1).
185 N:M -> standard python form, means including items N...(M-1).
185
186
186 N-M -> include items N..M (closed endpoint)."""
187 N-M -> include items N..M (closed endpoint)."""
187
188 lines = self.shell.history_manager.\
188 if raw:
189 get_range_by_str(range_str, raw=raw)
189 hist = self.shell.history_manager.input_hist_raw
190 return "\n".join(x for _, _, x in lines)
190 else:
191 hist = self.shell.history_manager.input_hist_parsed
192
193 cmds = []
194 for chunk in slices:
195 if ':' in chunk:
196 ini,fin = map(int,chunk.split(':'))
197 elif '-' in chunk:
198 ini,fin = map(int,chunk.split('-'))
199 fin += 1
200 else:
201 ini = int(chunk)
202 fin = ini+1
203 cmds.append(''.join(hist[ini:fin]))
204 return cmds
205
191
206 def arg_err(self,func):
192 def arg_err(self,func):
207 """Print docstring if incorrect arguments were passed"""
193 """Print docstring if incorrect arguments were passed"""
@@ -1617,7 +1603,7 b' Currently the magic system has the following functions:\\n"""'
1617
1603
1618 stats = None
1604 stats = None
1619 try:
1605 try:
1620 self.shell.save_history()
1606 #self.shell.save_history()
1621
1607
1622 if opts.has_key('p'):
1608 if opts.has_key('p'):
1623 stats = self.magic_prun('',0,opts,arg_lst,prog_ns)
1609 stats = self.magic_prun('',0,opts,arg_lst,prog_ns)
@@ -1736,7 +1722,7 b' Currently the magic system has the following functions:\\n"""'
1736 # contained therein.
1722 # contained therein.
1737 del sys.modules[main_mod_name]
1723 del sys.modules[main_mod_name]
1738
1724
1739 self.shell.reload_history()
1725 #self.shell.reload_history()
1740
1726
1741 return stats
1727 return stats
1742
1728
@@ -1990,9 +1976,7 b' Currently the magic system has the following functions:\\n"""'
1990 you had typed them. You just type 'name' at the prompt and the code
1976 you had typed them. You just type 'name' at the prompt and the code
1991 executes.
1977 executes.
1992
1978
1993 The notation for indicating number ranges is: n1-n2 means 'use line
1979 The syntax for indicating input ranges is described in %history.
1994 numbers n1,...n2' (the endpoint is included). That is, '5-7' means
1995 using the lines numbered 5,6 and 7.
1996
1980
1997 Note: as a 'hidden' feature, you can also use traditional python slice
1981 Note: as a 'hidden' feature, you can also use traditional python slice
1998 notation, where N:M means numbers N through M-1.
1982 notation, where N:M means numbers N through M-1.
@@ -2033,17 +2017,16 b' Currently the magic system has the following functions:\\n"""'
2033 In [60]: exec In[44:48]+In[49]"""
2017 In [60]: exec In[44:48]+In[49]"""
2034
2018
2035 opts,args = self.parse_options(parameter_s,'r',mode='list')
2019 opts,args = self.parse_options(parameter_s,'r',mode='list')
2036 if not args:
2020 if not args: # List existing macros
2037 macs = [k for k,v in self.shell.user_ns.items() if isinstance(v, Macro)]
2021 return sorted(k for k,v in self.shell.user_ns.iteritems() if\
2038 macs.sort()
2022 isinstance(v, Macro))
2039 return macs
2040 if len(args) == 1:
2023 if len(args) == 1:
2041 raise UsageError(
2024 raise UsageError(
2042 "%macro insufficient args; usage '%macro name n1-n2 n3-4...")
2025 "%macro insufficient args; usage '%macro name n1-n2 n3-4...")
2043 name,ranges = args[0], args[1:]
2026 name, ranges = args[0], " ".join(args[1:])
2044
2027
2045 #print 'rng',ranges # dbg
2028 #print 'rng',ranges # dbg
2046 lines = self.extract_input_slices(ranges,opts.has_key('r'))
2029 lines = self.extract_input_lines(ranges,'r' in opts)
2047 macro = Macro(lines)
2030 macro = Macro(lines)
2048 self.shell.define_macro(name, macro)
2031 self.shell.define_macro(name, macro)
2049 print 'Macro `%s` created. To execute, type its name (without quotes).' % name
2032 print 'Macro `%s` created. To execute, type its name (without quotes).' % name
@@ -2063,15 +2046,14 b' Currently the magic system has the following functions:\\n"""'
2063 Python. If this option is given, the raw input as typed as the
2046 Python. If this option is given, the raw input as typed as the
2064 command line is used instead.
2047 command line is used instead.
2065
2048
2066 This function uses the same syntax as %macro for line extraction, but
2049 This function uses the same syntax as %history for input ranges,
2067 instead of creating a macro it saves the resulting string to the
2050 then saves the lines to the filename you specify.
2068 filename you specify.
2069
2051
2070 It adds a '.py' extension to the file if you don't do so yourself, and
2052 It adds a '.py' extension to the file if you don't do so yourself, and
2071 it asks for confirmation before overwriting existing files."""
2053 it asks for confirmation before overwriting existing files."""
2072
2054
2073 opts,args = self.parse_options(parameter_s,'r',mode='list')
2055 opts,args = self.parse_options(parameter_s,'r',mode='list')
2074 fname,ranges = args[0], args[1:]
2056 fname,ranges = args[0], " ".join(args[1:])
2075 if not fname.endswith('.py'):
2057 if not fname.endswith('.py'):
2076 fname += '.py'
2058 fname += '.py'
2077 if os.path.isfile(fname):
2059 if os.path.isfile(fname):
@@ -2079,10 +2061,9 b' Currently the magic system has the following functions:\\n"""'
2079 if ans.lower() not in ['y','yes']:
2061 if ans.lower() not in ['y','yes']:
2080 print 'Operation cancelled.'
2062 print 'Operation cancelled.'
2081 return
2063 return
2082 cmds = ''.join(self.extract_input_slices(ranges,opts.has_key('r')))
2064 cmds = self.extract_input_lines(ranges, 'r' in opts)
2083 f = file(fname,'w')
2065 with open(fname,'w') as f:
2084 f.write(cmds)
2066 f.write(cmds)
2085 f.close()
2086 print 'The following commands were written to file `%s`:' % fname
2067 print 'The following commands were written to file `%s`:' % fname
2087 print cmds
2068 print cmds
2088
2069
@@ -2154,15 +2135,17 b' Currently the magic system has the following functions:\\n"""'
2154 Arguments:
2135 Arguments:
2155
2136
2156 If arguments are given, the following possibilites exist:
2137 If arguments are given, the following possibilites exist:
2138
2139 - If the argument is a filename, IPython will load that into the
2140 editor. It will execute its contents with execfile() when you exit,
2141 loading any code in the file into your interactive namespace.
2157
2142
2158 - The arguments are numbers or pairs of colon-separated numbers (like
2143 - The arguments are ranges of input history, e.g. "7 ~1/4-6".
2159 1 4:8 9). These are interpreted as lines of previous input to be
2144 The syntax is the same as in the %history magic.
2160 loaded into the editor. The syntax is the same of the %macro command.
2161
2145
2162 - If the argument doesn't start with a number, it is evaluated as a
2146 - If the argument is a string variable, its contents are loaded
2163 variable and its contents loaded into the editor. You can thus edit
2147 into the editor. You can thus edit any string which contains
2164 any string which contains python code (including the result of
2148 python code (including the result of previous edits).
2165 previous edits).
2166
2149
2167 - If the argument is the name of an object (other than a string),
2150 - If the argument is the name of an object (other than a string),
2168 IPython will try to locate the file where it was defined and open the
2151 IPython will try to locate the file where it was defined and open the
@@ -2179,11 +2162,6 b' Currently the magic system has the following functions:\\n"""'
2179 '+NUMBER' parameter necessary for this feature. Good editors like
2162 '+NUMBER' parameter necessary for this feature. Good editors like
2180 (X)Emacs, vi, jed, pico and joe all do.
2163 (X)Emacs, vi, jed, pico and joe all do.
2181
2164
2182 - If the argument is not found as a variable, IPython will look for a
2183 file with that name (adding .py if necessary) and load it into the
2184 editor. It will execute its contents with execfile() when you exit,
2185 loading any code in the file into your interactive namespace.
2186
2187 After executing your code, %edit will return as output the code you
2165 After executing your code, %edit will return as output the code you
2188 typed in the editor (except when it was an existing file). This way
2166 typed in the editor (except when it was an existing file). This way
2189 you can reload the code in further invocations of %edit as a variable,
2167 you can reload the code in further invocations of %edit as a variable,
@@ -2266,13 +2244,13 b' Currently the magic system has the following functions:\\n"""'
2266
2244
2267 opts,args = self.parse_options(parameter_s,'prxn:')
2245 opts,args = self.parse_options(parameter_s,'prxn:')
2268 # Set a few locals from the options for convenience:
2246 # Set a few locals from the options for convenience:
2269 opts_p = opts.has_key('p')
2247 opts_prev = 'p' in opts
2270 opts_r = opts.has_key('r')
2248 opts_raw = 'r' in opts
2271
2249
2272 # Default line number value
2250 # Default line number value
2273 lineno = opts.get('n',None)
2251 lineno = opts.get('n',None)
2274
2252
2275 if opts_p:
2253 if opts_prev:
2276 args = '_%s' % last_call[0]
2254 args = '_%s' % last_call[0]
2277 if not self.shell.user_ns.has_key(args):
2255 if not self.shell.user_ns.has_key(args):
2278 args = last_call[1]
2256 args = last_call[1]
@@ -2281,90 +2259,83 b' Currently the magic system has the following functions:\\n"""'
2281 # let it be clobbered by successive '-p' calls.
2259 # let it be clobbered by successive '-p' calls.
2282 try:
2260 try:
2283 last_call[0] = self.shell.displayhook.prompt_count
2261 last_call[0] = self.shell.displayhook.prompt_count
2284 if not opts_p:
2262 if not opts_prev:
2285 last_call[1] = parameter_s
2263 last_call[1] = parameter_s
2286 except:
2264 except:
2287 pass
2265 pass
2288
2266
2289 # by default this is done with temp files, except when the given
2267 # by default this is done with temp files, except when the given
2290 # arg is a filename
2268 # arg is a filename
2291 use_temp = 1
2269 use_temp = True
2292
2270
2293 if re.match(r'\d',args):
2271 data = ''
2294 # Mode where user specifies ranges of lines, like in %macro.
2272 if args.endswith('.py'):
2295 # This means that you can't edit files whose names begin with
2296 # numbers this way. Tough.
2297 ranges = args.split()
2298 data = ''.join(self.extract_input_slices(ranges,opts_r))
2299 elif args.endswith('.py'):
2300 filename = make_filename(args)
2273 filename = make_filename(args)
2301 data = ''
2274 use_temp = False
2302 use_temp = 0
2303 elif args:
2275 elif args:
2304 try:
2276 # Mode where user specifies ranges of lines, like in %macro.
2305 # Load the parameter given as a variable. If not a string,
2277 data = self.extract_input_lines(args, opts_raw)
2306 # process it as an object instead (below)
2278 if not data:
2307
2279 try:
2308 #print '*** args',args,'type',type(args) # dbg
2280 # Load the parameter given as a variable. If not a string,
2309 data = eval(args,self.shell.user_ns)
2281 # process it as an object instead (below)
2310 if not type(data) in StringTypes:
2311 raise DataIsObject
2312
2313 except (NameError,SyntaxError):
2314 # given argument is not a variable, try as a filename
2315 filename = make_filename(args)
2316 if filename is None:
2317 warn("Argument given (%s) can't be found as a variable "
2318 "or as a filename." % args)
2319 return
2320
2282
2321 data = ''
2283 #print '*** args',args,'type',type(args) # dbg
2322 use_temp = 0
2284 data = eval(args, self.shell.user_ns)
2323 except DataIsObject:
2285 if not isinstance(data, basestring):
2286 raise DataIsObject
2324
2287
2325 # macros have a special edit function
2288 except (NameError,SyntaxError):
2326 if isinstance(data,Macro):
2289 # given argument is not a variable, try as a filename
2327 self._edit_macro(args,data)
2328 return
2329
2330 # For objects, try to edit the file where they are defined
2331 try:
2332 filename = inspect.getabsfile(data)
2333 if 'fakemodule' in filename.lower() and inspect.isclass(data):
2334 # class created by %edit? Try to find source
2335 # by looking for method definitions instead, the
2336 # __module__ in those classes is FakeModule.
2337 attrs = [getattr(data, aname) for aname in dir(data)]
2338 for attr in attrs:
2339 if not inspect.ismethod(attr):
2340 continue
2341 filename = inspect.getabsfile(attr)
2342 if filename and 'fakemodule' not in filename.lower():
2343 # change the attribute to be the edit target instead
2344 data = attr
2345 break
2346
2347 datafile = 1
2348 except TypeError:
2349 filename = make_filename(args)
2290 filename = make_filename(args)
2350 datafile = 1
2291 if filename is None:
2351 warn('Could not find file where `%s` is defined.\n'
2292 warn("Argument given (%s) can't be found as a variable "
2352 'Opening a file named `%s`' % (args,filename))
2293 "or as a filename." % args)
2353 # Now, make sure we can actually read the source (if it was in
2294 return
2354 # a temp file it's gone by now).
2295 use_temp = False
2355 if datafile:
2296
2297 except DataIsObject:
2298 # macros have a special edit function
2299 if isinstance(data, Macro):
2300 self._edit_macro(args,data)
2301 return
2302
2303 # For objects, try to edit the file where they are defined
2356 try:
2304 try:
2357 if lineno is None:
2305 filename = inspect.getabsfile(data)
2358 lineno = inspect.getsourcelines(data)[1]
2306 if 'fakemodule' in filename.lower() and inspect.isclass(data):
2359 except IOError:
2307 # class created by %edit? Try to find source
2308 # by looking for method definitions instead, the
2309 # __module__ in those classes is FakeModule.
2310 attrs = [getattr(data, aname) for aname in dir(data)]
2311 for attr in attrs:
2312 if not inspect.ismethod(attr):
2313 continue
2314 filename = inspect.getabsfile(attr)
2315 if filename and 'fakemodule' not in filename.lower():
2316 # change the attribute to be the edit target instead
2317 data = attr
2318 break
2319
2320 datafile = 1
2321 except TypeError:
2360 filename = make_filename(args)
2322 filename = make_filename(args)
2361 if filename is None:
2323 datafile = 1
2362 warn('The file `%s` where `%s` was defined cannot '
2324 warn('Could not find file where `%s` is defined.\n'
2363 'be read.' % (filename,data))
2325 'Opening a file named `%s`' % (args,filename))
2364 return
2326 # Now, make sure we can actually read the source (if it was in
2365 use_temp = 0
2327 # a temp file it's gone by now).
2366 else:
2328 if datafile:
2367 data = ''
2329 try:
2330 if lineno is None:
2331 lineno = inspect.getsourcelines(data)[1]
2332 except IOError:
2333 filename = make_filename(args)
2334 if filename is None:
2335 warn('The file `%s` where `%s` was defined cannot '
2336 'be read.' % (filename,data))
2337 return
2338 use_temp = False
2368
2339
2369 if use_temp:
2340 if use_temp:
2370 filename = self.shell.mktempfile(data)
2341 filename = self.shell.mktempfile(data)
@@ -2387,12 +2358,13 b' Currently the magic system has the following functions:\\n"""'
2387 if args.strip() == 'pasted_block':
2358 if args.strip() == 'pasted_block':
2388 self.shell.user_ns['pasted_block'] = file_read(filename)
2359 self.shell.user_ns['pasted_block'] = file_read(filename)
2389
2360
2390 if opts.has_key('x'): # -x prevents actual execution
2361 if 'x' in opts: # -x prevents actual execution
2391 print
2362 print
2392 else:
2363 else:
2393 print 'done. Executing edited code...'
2364 print 'done. Executing edited code...'
2394 if opts_r:
2365 if opts_raw:
2395 self.shell.run_cell(file_read(filename))
2366 self.shell.run_cell(file_read(filename),
2367 store_history=False)
2396 else:
2368 else:
2397 self.shell.safe_execfile(filename,self.shell.user_ns,
2369 self.shell.safe_execfile(filename,self.shell.user_ns,
2398 self.shell.user_ns)
2370 self.shell.user_ns)
@@ -3050,38 +3022,6 b' Defaulting color scheme to \'NoColor\'"""'
3050 if parameter_s:
3022 if parameter_s:
3051 return self.shell.getoutput(parameter_s)
3023 return self.shell.getoutput(parameter_s)
3052
3024
3053 def magic_r(self, parameter_s=''):
3054 """Repeat previous input.
3055
3056 Note: Consider using the more powerfull %rep instead!
3057
3058 If given an argument, repeats the previous command which starts with
3059 the same string, otherwise it just repeats the previous input.
3060
3061 Shell escaped commands (with ! as first character) are not recognized
3062 by this system, only pure python code and magic commands.
3063 """
3064
3065 start = parameter_s.strip()
3066 esc_magic = ESC_MAGIC
3067 # Identify magic commands even if automagic is on (which means
3068 # the in-memory version is different from that typed by the user).
3069 if self.shell.automagic:
3070 start_magic = esc_magic+start
3071 else:
3072 start_magic = start
3073 # Look through the input history in reverse
3074 for n in range(len(self.shell.history_manager.input_hist_parsed)-2,0,-1):
3075 input = self.shell.history_manager.input_hist_parsed[n]
3076 # skip plain 'r' lines so we don't recurse to infinity
3077 if input != '_ip.magic("r")\n' and \
3078 (input.startswith(start) or input.startswith(start_magic)):
3079 #print 'match',`input` # dbg
3080 print 'Executing:',input,
3081 self.shell.run_cell(input)
3082 return
3083 print 'No previous input matching `%s` found.' % start
3084
3085
3025
3086 def magic_bookmark(self, parameter_s=''):
3026 def magic_bookmark(self, parameter_s=''):
3087 """Manage IPython's bookmark system.
3027 """Manage IPython's bookmark system.
@@ -32,6 +32,7 b' import re'
32 from IPython.core.alias import AliasManager
32 from IPython.core.alias import AliasManager
33 from IPython.core.autocall import IPyAutocall
33 from IPython.core.autocall import IPyAutocall
34 from IPython.config.configurable import Configurable
34 from IPython.config.configurable import Configurable
35 from IPython.core.macro import Macro
35 from IPython.core.splitinput import split_user_input
36 from IPython.core.splitinput import split_user_input
36 from IPython.core import page
37 from IPython.core import page
37
38
@@ -598,6 +599,18 b' class ShellEscapeChecker(PrefilterChecker):'
598 return self.prefilter_manager.get_handler_by_name('shell')
599 return self.prefilter_manager.get_handler_by_name('shell')
599
600
600
601
602 class MacroChecker(PrefilterChecker):
603
604 priority = Int(250, config=True)
605
606 def check(self, line_info):
607 obj = self.shell.user_ns.get(line_info.ifun)
608 if isinstance(obj, Macro):
609 return self.prefilter_manager.get_handler_by_name('macro')
610 else:
611 return None
612
613
601 class IPyAutocallChecker(PrefilterChecker):
614 class IPyAutocallChecker(PrefilterChecker):
602
615
603 priority = Int(300, config=True)
616 priority = Int(300, config=True)
@@ -837,6 +850,16 b' class ShellEscapeHandler(PrefilterHandler):'
837 return line_out
850 return line_out
838
851
839
852
853 class MacroHandler(PrefilterHandler):
854 handler_name = Str("macro")
855
856 def handle(self, line_info):
857 obj = self.shell.user_ns.get(line_info.ifun)
858 pre_space = line_info.pre_whitespace
859 line_sep = "\n" + pre_space
860 return pre_space + line_sep.join(obj.value.splitlines())
861
862
840 class MagicHandler(PrefilterHandler):
863 class MagicHandler(PrefilterHandler):
841
864
842 handler_name = Str('magic')
865 handler_name = Str('magic')
@@ -979,6 +1002,7 b' _default_transformers = ['
979 _default_checkers = [
1002 _default_checkers = [
980 EmacsChecker,
1003 EmacsChecker,
981 ShellEscapeChecker,
1004 ShellEscapeChecker,
1005 MacroChecker,
982 IPyAutocallChecker,
1006 IPyAutocallChecker,
983 MultiLineMagicChecker,
1007 MultiLineMagicChecker,
984 EscCharsChecker,
1008 EscCharsChecker,
@@ -993,6 +1017,7 b' _default_handlers = ['
993 PrefilterHandler,
1017 PrefilterHandler,
994 AliasHandler,
1018 AliasHandler,
995 ShellEscapeHandler,
1019 ShellEscapeHandler,
1020 MacroHandler,
996 MagicHandler,
1021 MagicHandler,
997 AutoHandler,
1022 AutoHandler,
998 HelpHandler,
1023 HelpHandler,
@@ -14,35 +14,101 b' import nose.tools as nt'
14
14
15 # our own packages
15 # our own packages
16 from IPython.utils.tempdir import TemporaryDirectory
16 from IPython.utils.tempdir import TemporaryDirectory
17 from IPython.core.history import HistoryManager
17 from IPython.core.history import HistoryManager, extract_hist_ranges
18
18
19 def test_history():
19 def test_history():
20
20
21 ip = get_ipython()
21 ip = get_ipython()
22 with TemporaryDirectory() as tmpdir:
22 with TemporaryDirectory() as tmpdir:
23 #tmpdir = '/software/temp'
23 #tmpdir = '/software/temp'
24 histfile = os.path.realpath(os.path.join(tmpdir, 'history.json'))
24 histfile = os.path.realpath(os.path.join(tmpdir, 'history.sqlite'))
25 # Ensure that we restore the history management that we mess with in
25 # Ensure that we restore the history management that we mess with in
26 # this test doesn't affect the IPython instance used by the test suite
26 # this test doesn't affect the IPython instance used by the test suite
27 # beyond this test.
27 # beyond this test.
28 hist_manager_ori = ip.history_manager
28 hist_manager_ori = ip.history_manager
29 try:
29 try:
30 ip.history_manager = HistoryManager(ip)
30 ip.history_manager = HistoryManager(shell=ip)
31 ip.history_manager.hist_file = histfile
31 ip.history_manager.hist_file = histfile
32 ip.history_manager.init_db() # Has to be called after changing file
33 ip.history_manager.reset()
32 print 'test',histfile
34 print 'test',histfile
33 hist = ['a=1\n', 'def f():\n test = 1\n return test\n', 'b=2\n']
35 hist = ['a=1', 'def f():\n test = 1\n return test', 'b=2']
34 # test save and load
36 for i, h in enumerate(hist, start=1):
35 ip.history_manager.input_hist_raw[:] = []
37 ip.history_manager.store_inputs(i, h)
36 for h in hist:
38
37 ip.history_manager.input_hist_raw.append(h)
39 ip.history_manager.db_log_output = True
38 ip.save_history()
40 # Doesn't match the input, but we'll just check it's stored.
39 ip.history_manager.input_hist_raw[:] = []
41 ip.history_manager.output_hist_reprs[3].append("spam")
40 ip.reload_history()
42 ip.history_manager.store_output(3)
41 print type(ip.history_manager.input_hist_raw)
43
42 print ip.history_manager.input_hist_raw
44 nt.assert_equal(ip.history_manager.input_hist_raw, [''] + hist)
43 nt.assert_equal(len(ip.history_manager.input_hist_raw), len(hist))
45
44 for i,h in enumerate(hist):
46 # Check lines were written to DB
45 nt.assert_equal(hist[i], ip.history_manager.input_hist_raw[i])
47 c = ip.history_manager.db.execute("SELECT source_raw FROM history")
48 nt.assert_equal([x for x, in c], hist)
49
50 # New session
51 ip.history_manager.reset()
52 newcmds = ["z=5","class X(object):\n pass", "k='p'"]
53 for i, cmd in enumerate(newcmds, start=1):
54 ip.history_manager.store_inputs(i, cmd)
55 gothist = ip.history_manager.get_range(start=1, stop=4)
56 nt.assert_equal(list(gothist), zip([0,0,0],[1,2,3], newcmds))
57 # Previous session:
58 gothist = ip.history_manager.get_range(-1, 1, 4)
59 nt.assert_equal(list(gothist), zip([1,1,1],[1,2,3], hist))
60
61 # Check get_hist_tail
62 gothist = ip.history_manager.get_tail(4, output=True,
63 include_latest=True)
64 expected = [(1, 3, (hist[-1], ["spam"])),
65 (2, 1, (newcmds[0], None)),
66 (2, 2, (newcmds[1], None)),
67 (2, 3, (newcmds[2], None)),]
68 nt.assert_equal(list(gothist), expected)
69
70 gothist = ip.history_manager.get_tail(2)
71 expected = [(2, 1, newcmds[0]),
72 (2, 2, newcmds[1])]
73 nt.assert_equal(list(gothist), expected)
74
75 # Check get_hist_search
76 gothist = ip.history_manager.search("*test*")
77 nt.assert_equal(list(gothist), [(1,2,hist[1])] )
78 gothist = ip.history_manager.search("b*", output=True)
79 nt.assert_equal(list(gothist), [(1,3,(hist[2],["spam"]))] )
80
81 # Cross testing: check that magic %save can get previous session.
82 testfilename = os.path.realpath(os.path.join(tmpdir, "test.py"))
83 ip.magic_save(testfilename + " ~1/1-3")
84 testfile = open(testfilename, "r")
85 nt.assert_equal(testfile.read(), "\n".join(hist))
86
87 # Duplicate line numbers - check that it doesn't crash, and
88 # gets a new session
89 ip.history_manager.store_inputs(1, "rogue")
90 nt.assert_equal(ip.history_manager.session_number, 3)
46 finally:
91 finally:
47 # Restore history manager
92 # Restore history manager
48 ip.history_manager = hist_manager_ori
93 ip.history_manager = hist_manager_ori
94
95 def test_extract_hist_ranges():
96 instr = "1 2/3 ~4/5-6 ~4/7-~4/9 ~9/2-~7/5"
97 expected = [(0, 1, 2), # 0 == current session
98 (2, 3, 4),
99 (-4, 5, 7),
100 (-4, 7, 10),
101 (-9, 2, None), # None == to end
102 (-8, 1, None),
103 (-7, 1, 6)]
104 actual = list(extract_hist_ranges(instr))
105 nt.assert_equal(actual, expected)
106
107 def test_magic_rerun():
108 """Simple test for %rerun (no args -> rerun last line)"""
109 ip = get_ipython()
110 ip.run_cell("a = 10")
111 ip.run_cell("a += 1")
112 nt.assert_equal(ip.user_ns["a"], 11)
113 ip.run_cell("%rerun")
114 nt.assert_equal(ip.user_ns["a"], 12)
@@ -62,7 +62,7 b' def doctest_hist_f():'
62
62
63 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
63 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
64
64
65 In [11]: %hist -n -f $tfile 3
65 In [11]: %hist -nl -f $tfile 3
66
66
67 In [13]: import os; os.unlink(tfile)
67 In [13]: import os; os.unlink(tfile)
68 """
68 """
@@ -80,7 +80,7 b' def doctest_hist_r():'
80
80
81 In [2]: x=1
81 In [2]: x=1
82
82
83 In [3]: %hist -r 2
83 In [3]: %hist -rl 2
84 x=1 # random
84 x=1 # random
85 %hist -r 2
85 %hist -r 2
86 """
86 """
@@ -150,29 +150,38 b' def doctest_hist_op():'
150 <...s instance at ...>
150 <...s instance at ...>
151 >>>
151 >>>
152 """
152 """
153
153
154 def test_shist():
154 def test_macro():
155 # Simple tests of ShadowHist class - test generator.
155 ip = get_ipython()
156 import os, shutil, tempfile
156 ip.history_manager.reset() # Clear any existing history.
157
157 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
158 from IPython.utils import pickleshare
158 for i, cmd in enumerate(cmds, start=1):
159 from IPython.core.history import ShadowHist
159 ip.history_manager.store_inputs(i, cmd)
160
160 ip.magic("macro test 1-3")
161 tfile = tempfile.mktemp('','tmp-ipython-')
161 nt.assert_equal(ip.user_ns["test"].value, "\n".join(cmds)+"\n")
162
163 db = pickleshare.PickleShareDB(tfile)
164 s = ShadowHist(db, get_ipython())
165 s.add('hello')
166 s.add('world')
167 s.add('hello')
168 s.add('hello')
169 s.add('karhu')
170
171 yield nt.assert_equals,s.all(),[(1, 'hello'), (2, 'world'), (3, 'karhu')]
172
173 yield nt.assert_equal,s.get(2),'world'
174
162
175 shutil.rmtree(tfile)
163 # List macros.
164 assert "test" in ip.magic("macro")
165
166 def test_macro_run():
167 """Test that we can run a multi-line macro successfully."""
168 ip = get_ipython()
169 ip.history_manager.reset()
170 cmds = ["a=10", "a+=1", "print a", "%macro test 2-3"]
171 for cmd in cmds:
172 ip.run_cell(cmd)
173 nt.assert_equal(ip.user_ns["test"].value, "a+=1\nprint a\n")
174 original_stdout = sys.stdout
175 new_stdout = StringIO()
176 sys.stdout = new_stdout
177 try:
178 ip.run_cell("test")
179 nt.assert_true("12" in new_stdout.getvalue())
180 ip.run_cell("test")
181 nt.assert_true("13" in new_stdout.getvalue())
182 finally:
183 sys.stdout = original_stdout
184 new_stdout.close()
176
185
177
186
178 # XXX failing for now, until we get clearcmd out of quarantine. But we should
187 # XXX failing for now, until we get clearcmd out of quarantine. But we should
@@ -158,15 +158,12 b' class IPythonWidget(FrontendWidget):'
158 else:
158 else:
159 super(IPythonWidget, self)._handle_execute_reply(msg)
159 super(IPythonWidget, self)._handle_execute_reply(msg)
160
160
161 def _handle_history_reply(self, msg):
161 def _handle_history_tail_reply(self, msg):
162 """ Implemented to handle history replies, which are only supported by
162 """ Implemented to handle history tail replies, which are only supported
163 the IPython kernel.
163 by the IPython kernel.
164 """
164 """
165 history_dict = msg['content']['history']
165 history_items = msg['content']['history']
166 input_history_dict = {}
166 items = [ line.rstrip() for _, _, line in history_items ]
167 for key,val in history_dict.items():
168 input_history_dict[int(key)] = val
169 items = [ val.rstrip() for _, val in sorted(input_history_dict.items()) ]
170 self._set_history(items)
167 self._set_history(items)
171
168
172 def _handle_pyout(self, msg):
169 def _handle_pyout(self, msg):
@@ -213,7 +210,7 b' class IPythonWidget(FrontendWidget):'
213 """ Reimplemented to make a history request.
210 """ Reimplemented to make a history request.
214 """
211 """
215 super(IPythonWidget, self)._started_channels()
212 super(IPythonWidget, self)._started_channels()
216 self.kernel_manager.xreq_channel.history(raw=True, output=False)
213 self.kernel_manager.xreq_channel.history_tail(1000)
217
214
218 #---------------------------------------------------------------------------
215 #---------------------------------------------------------------------------
219 # 'ConsoleWidget' public interface
216 # 'ConsoleWidget' public interface
@@ -185,10 +185,6 b' class TerminalInteractiveShell(InteractiveShell):'
185
185
186 with nested(self.builtin_trap, self.display_trap):
186 with nested(self.builtin_trap, self.display_trap):
187
187
188 # if you run stuff with -c <cmd>, raw hist is not updated
189 # ensure that it's in sync
190 self.history_manager.sync_inputs()
191
192 while 1:
188 while 1:
193 try:
189 try:
194 self.interact(display_banner=display_banner)
190 self.interact(display_banner=display_banner)
@@ -286,67 +282,6 b' class TerminalInteractiveShell(InteractiveShell):'
286 # Turn off the exit flag, so the mainloop can be restarted if desired
282 # Turn off the exit flag, so the mainloop can be restarted if desired
287 self.exit_now = False
283 self.exit_now = False
288
284
289 def raw_input(self, prompt='', continue_prompt=False):
290 """Write a prompt and read a line.
291
292 The returned line does not include the trailing newline.
293 When the user enters the EOF key sequence, EOFError is raised.
294
295 Optional inputs:
296
297 - prompt(''): a string to be printed to prompt the user.
298
299 - continue_prompt(False): whether this line is the first one or a
300 continuation in a sequence of inputs.
301 """
302 # Code run by the user may have modified the readline completer state.
303 # We must ensure that our completer is back in place.
304
305 if self.has_readline:
306 self.set_readline_completer()
307
308 try:
309 line = raw_input_original(prompt).decode(self.stdin_encoding)
310 except ValueError:
311 warn("\n********\nYou or a %run:ed script called sys.stdin.close()"
312 " or sys.stdout.close()!\nExiting IPython!")
313 self.ask_exit()
314 return ""
315
316 # Try to be reasonably smart about not re-indenting pasted input more
317 # than necessary. We do this by trimming out the auto-indent initial
318 # spaces, if the user's actual input started itself with whitespace.
319 if self.autoindent:
320 if num_ini_spaces(line) > self.indent_current_nsp:
321 line = line[self.indent_current_nsp:]
322 self.indent_current_nsp = 0
323
324 # store the unfiltered input before the user has any chance to modify
325 # it.
326 if line.strip():
327 if continue_prompt:
328 if self.has_readline and self.readline_use:
329 histlen = self.readline.get_current_history_length()
330 if histlen > 1:
331 newhist = self.history_manager.input_hist_raw[-1].rstrip()
332 self.readline.remove_history_item(histlen-1)
333 self.readline.replace_history_item(histlen-2,
334 newhist.encode(self.stdin_encoding))
335 else:
336 self.history_manager.input_hist_raw.append('%s\n' % line)
337 elif not continue_prompt:
338 self.history_manager.input_hist_raw.append('\n')
339 try:
340 lineout = self.prefilter_manager.prefilter_lines(line,continue_prompt)
341 except:
342 # blanket except, in case a user-defined prefilter crashes, so it
343 # can't take all of ipython with it.
344 self.showtraceback()
345 return ''
346 else:
347 return lineout
348
349
350 def raw_input(self, prompt=''):
285 def raw_input(self, prompt=''):
351 """Write a prompt and read a line.
286 """Write a prompt and read a line.
352
287
@@ -19,7 +19,6 b' import __main__'
19 import os
19 import os
20 import re
20 import re
21 import shutil
21 import shutil
22 import types
23
22
24 from IPython.external.path import path
23 from IPython.external.path import path
25
24
@@ -30,8 +29,6 b' from IPython.utils.data import flatten'
30 # Code
29 # Code
31 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
32
31
33 StringTypes = types.StringTypes
34
35
32
36 def unquote_ends(istr):
33 def unquote_ends(istr):
37 """Remove a single pair of quotes from the endpoints of a string."""
34 """Remove a single pair of quotes from the endpoints of a string."""
@@ -325,7 +322,7 b' def qw(words,flat=0,sep=None,maxsplit=-1):'
325 ['a', 'b', '1', '2', 'm', 'n', 'p', 'q']
322 ['a', 'b', '1', '2', 'm', 'n', 'p', 'q']
326 """
323 """
327
324
328 if type(words) in StringTypes:
325 if isinstance(words, basestring):
329 return [word.strip() for word in words.split(sep,maxsplit)
326 return [word.strip() for word in words.split(sep,maxsplit)
330 if word and not word.isspace() ]
327 if word and not word.isspace() ]
331 if flat:
328 if flat:
@@ -345,7 +342,7 b' def qw_lol(indata):'
345 We need this to make sure the modules_some keys *always* end up as a
342 We need this to make sure the modules_some keys *always* end up as a
346 list of lists."""
343 list of lists."""
347
344
348 if type(indata) in StringTypes:
345 if isinstance(indata, basestring):
349 return [qw(indata)]
346 return [qw(indata)]
350 else:
347 else:
351 return qw(indata)
348 return qw(indata)
@@ -122,7 +122,7 b' class Kernel(Configurable):'
122
122
123 # Build dict of handlers for message types
123 # Build dict of handlers for message types
124 msg_types = [ 'execute_request', 'complete_request',
124 msg_types = [ 'execute_request', 'complete_request',
125 'object_info_request', 'history_request',
125 'object_info_request', 'history_tail_request',
126 'connect_request', 'shutdown_request']
126 'connect_request', 'shutdown_request']
127 self.handlers = {}
127 self.handlers = {}
128 for msg_type in msg_types:
128 for msg_type in msg_types:
@@ -323,13 +323,15 b' class Kernel(Configurable):'
323 oinfo, parent, ident)
323 oinfo, parent, ident)
324 logger.debug(msg)
324 logger.debug(msg)
325
325
326 def history_request(self, ident, parent):
326 def history_tail_request(self, ident, parent):
327 output = parent['content']['output']
327 # We need to pull these out, as passing **kwargs doesn't work with
328 index = parent['content']['index']
328 # unicode keys before Python 2.6.5.
329 n = parent['content']['n']
329 raw = parent['content']['raw']
330 raw = parent['content']['raw']
330 hist = self.shell.get_history(index=index, raw=raw, output=output)
331 output = parent['content']['output']
331 content = {'history' : hist}
332 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output)
332 msg = self.session.send(self.reply_socket, 'history_reply',
333 content = {'history' : list(hist)}
334 msg = self.session.send(self.reply_socket, 'history_tail_reply',
333 content, parent, ident)
335 content, parent, ident)
334 logger.debug(str(msg))
336 logger.debug(str(msg))
335
337
@@ -282,15 +282,13 b' class XReqSocketChannel(ZmqSocketChannel):'
282 self._queue_request(msg)
282 self._queue_request(msg)
283 return msg['header']['msg_id']
283 return msg['header']['msg_id']
284
284
285 def history(self, index=None, raw=False, output=True):
285 def history_tail(self, n=10, raw=True, output=False):
286 """Get the history list.
286 """Get the history list.
287
287
288 Parameters
288 Parameters
289 ----------
289 ----------
290 index : n or (n1, n2) or None
290 n : int
291 If n, then the last entries. If a tuple, then all in
291 The number of lines of history to get.
292 range(n1, n2). If None, then all entries. Raises IndexError if
293 the format of index is incorrect.
294 raw : bool
292 raw : bool
295 If True, return the raw input.
293 If True, return the raw input.
296 output : bool
294 output : bool
@@ -300,8 +298,8 b' class XReqSocketChannel(ZmqSocketChannel):'
300 -------
298 -------
301 The msg_id of the message sent.
299 The msg_id of the message sent.
302 """
300 """
303 content = dict(index=index, raw=raw, output=output)
301 content = dict(n=n, raw=raw, output=output)
304 msg = self.session.msg('history_request', content)
302 msg = self.session.msg('history_tail_request', content)
305 self._queue_request(msg)
303 self._queue_request(msg)
306 return msg['header']['msg_id']
304 return msg['header']['msg_id']
307
305
@@ -18,7 +18,6 b' from __future__ import print_function'
18 # Stdlib
18 # Stdlib
19 import inspect
19 import inspect
20 import os
20 import os
21 import re
22
21
23 # Our own
22 # Our own
24 from IPython.core.interactiveshell import (
23 from IPython.core.interactiveshell import (
@@ -31,7 +30,6 b' from IPython.core.macro import Macro'
31 from IPython.core.payloadpage import install_payload_page
30 from IPython.core.payloadpage import install_payload_page
32 from IPython.utils import io
31 from IPython.utils import io
33 from IPython.utils.path import get_py_filename
32 from IPython.utils.path import get_py_filename
34 from IPython.utils.text import StringTypes
35 from IPython.utils.traitlets import Instance, Type, Dict
33 from IPython.utils.traitlets import Instance, Type, Dict
36 from IPython.utils.warn import warn
34 from IPython.utils.warn import warn
37 from IPython.zmq.session import extract_header
35 from IPython.zmq.session import extract_header
@@ -433,9 +431,10 b' class ZMQInteractiveShell(InteractiveShell):'
433
431
434 # by default this is done with temp files, except when the given
432 # by default this is done with temp files, except when the given
435 # arg is a filename
433 # arg is a filename
436 use_temp = 1
434 use_temp = True
437
435
438 if re.match(r'\d',args):
436 data = ''
437 if args[0].isdigit():
439 # Mode where user specifies ranges of lines, like in %macro.
438 # Mode where user specifies ranges of lines, like in %macro.
440 # This means that you can't edit files whose names begin with
439 # This means that you can't edit files whose names begin with
441 # numbers this way. Tough.
440 # numbers this way. Tough.
@@ -443,16 +442,15 b' class ZMQInteractiveShell(InteractiveShell):'
443 data = ''.join(self.extract_input_slices(ranges,opts_r))
442 data = ''.join(self.extract_input_slices(ranges,opts_r))
444 elif args.endswith('.py'):
443 elif args.endswith('.py'):
445 filename = make_filename(args)
444 filename = make_filename(args)
446 data = ''
445 use_temp = False
447 use_temp = 0
448 elif args:
446 elif args:
449 try:
447 try:
450 # Load the parameter given as a variable. If not a string,
448 # Load the parameter given as a variable. If not a string,
451 # process it as an object instead (below)
449 # process it as an object instead (below)
452
450
453 #print '*** args',args,'type',type(args) # dbg
451 #print '*** args',args,'type',type(args) # dbg
454 data = eval(args,self.shell.user_ns)
452 data = eval(args, self.shell.user_ns)
455 if not type(data) in StringTypes:
453 if not isinstance(data, basestring):
456 raise DataIsObject
454 raise DataIsObject
457
455
458 except (NameError,SyntaxError):
456 except (NameError,SyntaxError):
@@ -462,13 +460,11 b' class ZMQInteractiveShell(InteractiveShell):'
462 warn("Argument given (%s) can't be found as a variable "
460 warn("Argument given (%s) can't be found as a variable "
463 "or as a filename." % args)
461 "or as a filename." % args)
464 return
462 return
465
463 use_temp = False
466 data = ''
464
467 use_temp = 0
468 except DataIsObject:
465 except DataIsObject:
469
470 # macros have a special edit function
466 # macros have a special edit function
471 if isinstance(data,Macro):
467 if isinstance(data, Macro):
472 self._edit_macro(args,data)
468 self._edit_macro(args,data)
473 return
469 return
474
470
@@ -507,9 +503,7 b' class ZMQInteractiveShell(InteractiveShell):'
507 warn('The file `%s` where `%s` was defined cannot '
503 warn('The file `%s` where `%s` was defined cannot '
508 'be read.' % (filename,data))
504 'be read.' % (filename,data))
509 return
505 return
510 use_temp = 0
506 use_temp = False
511 else:
512 data = ''
513
507
514 if use_temp:
508 if use_temp:
515 filename = self.shell.mktempfile(data)
509 filename = self.shell.mktempfile(data)
General Comments 0
You need to be logged in to leave comments. Login now