Show More
@@ -1,14 +1,163 b'' | |||
|
1 | # -*- coding: utf-8 -*- | |
|
2 | 1 |
|
|
2 | #----------------------------------------------------------------------------- | |
|
3 | # Copyright (C) 2010 The IPython Development Team. | |
|
4 | # | |
|
5 | # Distributed under the terms of the BSD License. | |
|
6 | # | |
|
7 | # The full license is in the file COPYING.txt, distributed with this software. | |
|
8 | #----------------------------------------------------------------------------- | |
|
9 | ||
|
10 | #----------------------------------------------------------------------------- | |
|
11 | # Imports | |
|
12 | #----------------------------------------------------------------------------- | |
|
13 | from __future__ import print_function | |
|
3 | 14 | |
|
4 | 15 | # Stdlib imports |
|
5 | 16 | import fnmatch |
|
6 | 17 | import os |
|
18 | import sys | |
|
7 | 19 | |
|
20 | # Our own packages | |
|
8 | 21 | import IPython.utils.io |
|
22 | ||
|
23 | from IPython.core import ipapi | |
|
24 | from IPython.core.inputlist import InputList | |
|
25 | from IPython.utils.pickleshare import PickleShareDB | |
|
9 | 26 | from IPython.utils.io import ask_yes_no |
|
10 | 27 | from IPython.utils.warn import warn |
|
11 | from IPython.core import ipapi | |
|
28 | ||
|
29 | #----------------------------------------------------------------------------- | |
|
30 | # Classes and functions | |
|
31 | #----------------------------------------------------------------------------- | |
|
32 | ||
|
33 | class HistoryManager(object): | |
|
34 | """A class to organize all history-related functionality in one place. | |
|
35 | """ | |
|
36 | def __init__(self, shell): | |
|
37 | """Create a new history manager associated with a shell instance. | |
|
38 | """ | |
|
39 | self.shell = shell | |
|
40 | ||
|
41 | # List of input with multi-line handling. | |
|
42 | self.input_hist = InputList() | |
|
43 | # This one will hold the 'raw' input history, without any | |
|
44 | # pre-processing. This will allow users to retrieve the input just as | |
|
45 | # it was exactly typed in by the user, with %hist -r. | |
|
46 | self.input_hist_raw = InputList() | |
|
47 | ||
|
48 | # list of visited directories | |
|
49 | try: | |
|
50 | self.dir_hist = [os.getcwd()] | |
|
51 | except OSError: | |
|
52 | self.dir_hist = [] | |
|
53 | ||
|
54 | # dict of output history | |
|
55 | self.output_hist = {} | |
|
56 | ||
|
57 | # Now the history file | |
|
58 | if shell.profile: | |
|
59 | histfname = 'history-%s' % shell.profile | |
|
60 | else: | |
|
61 | histfname = 'history' | |
|
62 | self.hist_file = os.path.join(shell.ipython_dir, histfname) | |
|
63 | ||
|
64 | # Fill the history zero entry, user counter starts at 1 | |
|
65 | self.input_hist.append('\n') | |
|
66 | self.input_hist_raw.append('\n') | |
|
67 | ||
|
68 | # Objects related to shadow history management | |
|
69 | self._init_shadow_hist() | |
|
70 | ||
|
71 | # For backwards compatibility, we must put these back in the shell | |
|
72 | # object, until we've removed all direct uses of the history objects in | |
|
73 | # the shell itself. | |
|
74 | shell.input_hist = self.input_hist | |
|
75 | shell.input_hist_raw = self.input_hist_raw | |
|
76 | shell.output_hist = self.output_hist | |
|
77 | shell.dir_hist = self.dir_hist | |
|
78 | shell.histfile = self.hist_file | |
|
79 | shell.shadowhist = self.shadow_hist | |
|
80 | shell.db = self.shadow_db | |
|
81 | ||
|
82 | def _init_shadow_hist(self): | |
|
83 | try: | |
|
84 | self.shadow_db = PickleShareDB(os.path.join( | |
|
85 | self.shell.ipython_dir, 'db')) | |
|
86 | except UnicodeDecodeError: | |
|
87 | print("Your ipython_dir can't be decoded to unicode!") | |
|
88 | print("Please set HOME environment variable to something that") | |
|
89 | print(r"only has ASCII characters, e.g. c:\home") | |
|
90 | print("Now it is", self.ipython_dir) | |
|
91 | sys.exit() | |
|
92 | self.shadow_hist = ShadowHist(self.shadow_db) | |
|
93 | ||
|
94 | def save_hist(self): | |
|
95 | """Save input history to a file (via readline library).""" | |
|
96 | ||
|
97 | try: | |
|
98 | self.shell.readline.write_history_file(self.hist_file) | |
|
99 | except: | |
|
100 | print('Unable to save IPython command history to file: ' + | |
|
101 | `self.hist_file`) | |
|
102 | ||
|
103 | def reload_hist(self): | |
|
104 | """Reload the input history from disk file.""" | |
|
105 | ||
|
106 | try: | |
|
107 | self.shell.readline.clear_history() | |
|
108 | self.shell.readline.read_history_file(self.hist_file) | |
|
109 | except AttributeError: | |
|
110 | pass | |
|
111 | ||
|
112 | def get_history(self, index=None, raw=False, output=True): | |
|
113 | """Get the history list. | |
|
114 | ||
|
115 | Get the input and output history. | |
|
116 | ||
|
117 | Parameters | |
|
118 | ---------- | |
|
119 | index : n or (n1, n2) or None | |
|
120 | If n, then the last entries. If a tuple, then all in | |
|
121 | range(n1, n2). If None, then all entries. Raises IndexError if | |
|
122 | the format of index is incorrect. | |
|
123 | raw : bool | |
|
124 | If True, return the raw input. | |
|
125 | output : bool | |
|
126 | If True, then return the output as well. | |
|
127 | ||
|
128 | Returns | |
|
129 | ------- | |
|
130 | If output is True, then return a dict of tuples, keyed by the prompt | |
|
131 | numbers and with values of (input, output). If output is False, then | |
|
132 | a dict, keyed by the prompt number with the values of input. Raises | |
|
133 | IndexError if no history is found. | |
|
134 | """ | |
|
135 | if raw: | |
|
136 | input_hist = self.input_hist_raw | |
|
137 | else: | |
|
138 | input_hist = self.input_hist | |
|
139 | if output: | |
|
140 | output_hist = self.output_hist | |
|
141 | n = len(input_hist) | |
|
142 | if index is None: | |
|
143 | start=0; stop=n | |
|
144 | elif isinstance(index, int): | |
|
145 | start=n-index; stop=n | |
|
146 | elif isinstance(index, tuple) and len(index) == 2: | |
|
147 | start=index[0]; stop=index[1] | |
|
148 | else: | |
|
149 | raise IndexError('Not a valid index for the input history: %r' | |
|
150 | % index) | |
|
151 | hist = {} | |
|
152 | for i in range(start, stop): | |
|
153 | if output: | |
|
154 | hist[i] = (input_hist[i], output_hist.get(i)) | |
|
155 | else: | |
|
156 | hist[i] = input_hist[i] | |
|
157 | if len(hist)==0: | |
|
158 | raise IndexError('No history for range of indices: %r' % index) | |
|
159 | return hist | |
|
160 | ||
|
12 | 161 | |
|
13 | 162 | def magic_history(self, parameter_s = ''): |
|
14 | 163 | """Print input history (_i<n> variables), with most recent last. |
@@ -55,7 +204,7 b" def magic_history(self, parameter_s = ''):" | |||
|
55 | 204 | """ |
|
56 | 205 | |
|
57 | 206 | if not self.shell.displayhook.do_full_cache: |
|
58 |
print |
|
|
207 | print('This feature is only available if numbered prompts are in use.') | |
|
59 | 208 | return |
|
60 | 209 | opts,args = self.parse_options(parameter_s,'gnoptsrf:',mode='list') |
|
61 | 210 | |
@@ -69,7 +218,7 b" def magic_history(self, parameter_s = ''):" | |||
|
69 | 218 | else: |
|
70 | 219 | if os.path.exists(outfname): |
|
71 | 220 | if not ask_yes_no("File %r exists. Overwrite?" % outfname): |
|
72 |
print |
|
|
221 | print('Aborting.') | |
|
73 | 222 | return |
|
74 | 223 | |
|
75 | 224 | outfile = open(outfname,'w') |
@@ -103,7 +252,7 b" def magic_history(self, parameter_s = ''):" | |||
|
103 | 252 | init, final = map(int, args) |
|
104 | 253 | else: |
|
105 | 254 | warn('%hist takes 0, 1 or 2 arguments separated by spaces.') |
|
106 | print >> IPython.utils.io.Term.cout, self.magic_hist.__doc__ | |
|
255 | print(self.magic_hist.__doc__, file=IPython.utils.io.Term.cout) | |
|
107 | 256 | return |
|
108 | 257 | |
|
109 | 258 | width = len(str(final)) |
@@ -117,14 +266,14 b" def magic_history(self, parameter_s = ''):" | |||
|
117 | 266 | sh = self.shell.shadowhist.all() |
|
118 | 267 | for idx, s in sh: |
|
119 | 268 | if fnmatch.fnmatch(s, pattern): |
|
120 |
print |
|
|
269 | print("0%d: %s" %(idx, s.expandtabs(4)), file=outfile) | |
|
121 | 270 | found = True |
|
122 | 271 | |
|
123 | 272 | if found: |
|
124 |
print |
|
|
125 | print >> outfile, \ | |
|
126 | "shadow history ends, fetch by %rep <number> (must start with 0)" | |
|
127 |
print |
|
|
273 | print("===", file=outfile) | |
|
274 | print("shadow history ends, fetch by %rep <number> (must start with 0)", | |
|
275 | file=outfile) | |
|
276 | print("=== start of normal history ===", file=outfile) | |
|
128 | 277 | |
|
129 | 278 | for in_num in range(init, final): |
|
130 | 279 | # Print user history with tabs expanded to 4 spaces. The GUI clients |
@@ -137,22 +286,22 b" def magic_history(self, parameter_s = ''):" | |||
|
137 | 286 | |
|
138 | 287 | multiline = int(inline.count('\n') > 1) |
|
139 | 288 | if print_nums: |
|
140 | print >> outfile, \ | |
|
141 | '%s:%s' % (str(in_num).ljust(width), line_sep[multiline]), | |
|
289 | print('%s:%s' % (str(in_num).ljust(width), line_sep[multiline]), | |
|
290 | file=outfile) | |
|
142 | 291 | if pyprompts: |
|
143 |
print |
|
|
292 | print('>>>', file=outfile) | |
|
144 | 293 | if multiline: |
|
145 | 294 | lines = inline.splitlines() |
|
146 |
print |
|
|
147 |
print |
|
|
295 | print('\n... '.join(lines), file=outfile) | |
|
296 | print('... ', file=outfile) | |
|
148 | 297 | else: |
|
149 |
print |
|
|
298 | print(inline, end='', file=outfile) | |
|
150 | 299 | else: |
|
151 |
print |
|
|
300 | print(inline,end='', file=outfile) | |
|
152 | 301 | if print_outputs: |
|
153 | 302 | output = self.shell.output_hist.get(in_num) |
|
154 | 303 | if output is not None: |
|
155 |
print |
|
|
304 | print(repr(output), file=outfile) | |
|
156 | 305 | |
|
157 | 306 | if close_at_end: |
|
158 | 307 | outfile.close() |
@@ -223,10 +372,10 b' def rep_f(self, arg):' | |||
|
223 | 372 | |
|
224 | 373 | try: |
|
225 | 374 | lines = self.extract_input_slices(args, True) |
|
226 |
print |
|
|
375 | print("lines", lines) | |
|
227 | 376 | self.runlines(lines) |
|
228 | 377 | except ValueError: |
|
229 |
print |
|
|
378 | print("Not found in recent history:", args) | |
|
230 | 379 | |
|
231 | 380 | |
|
232 | 381 | _sentinel = object() |
@@ -251,11 +400,11 b' class ShadowHist(object):' | |||
|
251 | 400 | if old is not _sentinel: |
|
252 | 401 | return |
|
253 | 402 | newidx = self.inc_idx() |
|
254 |
#print |
|
|
403 | #print("new", newidx) # dbg | |
|
255 | 404 | self.db.hset('shadowhist',ent, newidx) |
|
256 | 405 | except: |
|
257 | 406 | ipapi.get().showtraceback() |
|
258 |
print |
|
|
407 | print("WARNING: disabling shadow history") | |
|
259 | 408 | self.disabled = True |
|
260 | 409 | |
|
261 | 410 | def all(self): |
@@ -268,7 +417,6 b' class ShadowHist(object):' | |||
|
268 | 417 | all = self.all() |
|
269 | 418 | |
|
270 | 419 | for k, v in all: |
|
271 | #print k,v | |
|
272 | 420 | if k == idx: |
|
273 | 421 | return v |
|
274 | 422 |
@@ -45,6 +45,7 b' from IPython.core.displayhook import DisplayHook' | |||
|
45 | 45 | from IPython.core.error import TryNext, UsageError |
|
46 | 46 | from IPython.core.extensions import ExtensionManager |
|
47 | 47 | from IPython.core.fakemodule import FakeModule, init_fakemod_dict |
|
48 | from IPython.core.history import HistoryManager | |
|
48 | 49 | from IPython.core.inputlist import InputList |
|
49 | 50 | from IPython.core.inputsplitter import IPythonInputSplitter |
|
50 | 51 | from IPython.core.logger import Logger |
@@ -216,7 +217,8 b' class InteractiveShell(Configurable, Magic):' | |||
|
216 | 217 | extension_manager = Instance('IPython.core.extensions.ExtensionManager') |
|
217 | 218 | plugin_manager = Instance('IPython.core.plugin.PluginManager') |
|
218 | 219 | payload_manager = Instance('IPython.core.payload.PayloadManager') |
|
219 | ||
|
220 | history_manager = Instance('IPython.core.history.HistoryManager') | |
|
221 | ||
|
220 | 222 | # Private interface |
|
221 | 223 | _post_execute = set() |
|
222 | 224 | |
@@ -261,7 +263,6 b' class InteractiveShell(Configurable, Magic):' | |||
|
261 | 263 | self.init_builtins() |
|
262 | 264 | |
|
263 | 265 | # pre_config_initialization |
|
264 | self.init_shadow_hist() | |
|
265 | 266 | |
|
266 | 267 | # The next section should contain everything that was in ipmaker. |
|
267 | 268 | self.init_logstart() |
@@ -1211,61 +1212,15 b' class InteractiveShell(Configurable, Magic):' | |||
|
1211 | 1212 | #------------------------------------------------------------------------- |
|
1212 | 1213 | |
|
1213 | 1214 | def init_history(self): |
|
1214 | # List of input with multi-line handling. | |
|
1215 | self.input_hist = InputList() | |
|
1216 | # This one will hold the 'raw' input history, without any | |
|
1217 | # pre-processing. This will allow users to retrieve the input just as | |
|
1218 | # it was exactly typed in by the user, with %hist -r. | |
|
1219 | self.input_hist_raw = InputList() | |
|
1220 | ||
|
1221 | # list of visited directories | |
|
1222 | try: | |
|
1223 | self.dir_hist = [os.getcwd()] | |
|
1224 | except OSError: | |
|
1225 | self.dir_hist = [] | |
|
1226 | ||
|
1227 | # dict of output history | |
|
1228 | self.output_hist = {} | |
|
1229 | ||
|
1230 | # Now the history file | |
|
1231 | if self.profile: | |
|
1232 | histfname = 'history-%s' % self.profile | |
|
1233 | else: | |
|
1234 | histfname = 'history' | |
|
1235 | self.histfile = os.path.join(self.ipython_dir, histfname) | |
|
1236 | ||
|
1237 | # Fill the history zero entry, user counter starts at 1 | |
|
1238 | self.input_hist.append('\n') | |
|
1239 | self.input_hist_raw.append('\n') | |
|
1240 | ||
|
1241 | def init_shadow_hist(self): | |
|
1242 | try: | |
|
1243 | self.db = pickleshare.PickleShareDB(self.ipython_dir + "/db") | |
|
1244 | except exceptions.UnicodeDecodeError: | |
|
1245 | print "Your ipython_dir can't be decoded to unicode!" | |
|
1246 | print "Please set HOME environment variable to something that" | |
|
1247 | print r"only has ASCII characters, e.g. c:\home" | |
|
1248 | print "Now it is", self.ipython_dir | |
|
1249 | sys.exit() | |
|
1250 | self.shadowhist = ipcorehist.ShadowHist(self.db) | |
|
1215 | self.history_manager = HistoryManager(shell=self) | |
|
1251 | 1216 | |
|
1252 | 1217 | def savehist(self): |
|
1253 | 1218 | """Save input history to a file (via readline library).""" |
|
1254 | ||
|
1255 |
|
|
|
1256 | self.readline.write_history_file(self.histfile) | |
|
1257 | except: | |
|
1258 | print 'Unable to save IPython command history to file: ' + \ | |
|
1259 | `self.histfile` | |
|
1260 | ||
|
1219 | self.history_manager.save_hist() | |
|
1220 | ||
|
1261 | 1221 | def reloadhist(self): |
|
1262 | 1222 | """Reload the input history from disk file.""" |
|
1263 | ||
|
1264 | try: | |
|
1265 | self.readline.clear_history() | |
|
1266 | self.readline.read_history_file(self.shell.histfile) | |
|
1267 | except AttributeError: | |
|
1268 | pass | |
|
1223 | self.history_manager.reload_hist() | |
|
1269 | 1224 | |
|
1270 | 1225 | def history_saving_wrapper(self, func): |
|
1271 | 1226 | """ Wrap func for readline history saving |
@@ -1286,55 +1241,6 b' class InteractiveShell(Configurable, Magic):' | |||
|
1286 | 1241 | readline.read_history_file(self.histfile) |
|
1287 | 1242 | return wrapper |
|
1288 | 1243 | |
|
1289 | def get_history(self, index=None, raw=False, output=True): | |
|
1290 | """Get the history list. | |
|
1291 | ||
|
1292 | Get the input and output history. | |
|
1293 | ||
|
1294 | Parameters | |
|
1295 | ---------- | |
|
1296 | index : n or (n1, n2) or None | |
|
1297 | If n, then the last entries. If a tuple, then all in | |
|
1298 | range(n1, n2). If None, then all entries. Raises IndexError if | |
|
1299 | the format of index is incorrect. | |
|
1300 | raw : bool | |
|
1301 | If True, return the raw input. | |
|
1302 | output : bool | |
|
1303 | If True, then return the output as well. | |
|
1304 | ||
|
1305 | Returns | |
|
1306 | ------- | |
|
1307 | If output is True, then return a dict of tuples, keyed by the prompt | |
|
1308 | numbers and with values of (input, output). If output is False, then | |
|
1309 | a dict, keyed by the prompt number with the values of input. Raises | |
|
1310 | IndexError if no history is found. | |
|
1311 | """ | |
|
1312 | if raw: | |
|
1313 | input_hist = self.input_hist_raw | |
|
1314 | else: | |
|
1315 | input_hist = self.input_hist | |
|
1316 | if output: | |
|
1317 | output_hist = self.user_ns['Out'] | |
|
1318 | n = len(input_hist) | |
|
1319 | if index is None: | |
|
1320 | start=0; stop=n | |
|
1321 | elif isinstance(index, int): | |
|
1322 | start=n-index; stop=n | |
|
1323 | elif isinstance(index, tuple) and len(index) == 2: | |
|
1324 | start=index[0]; stop=index[1] | |
|
1325 | else: | |
|
1326 | raise IndexError('Not a valid index for the input history: %r' | |
|
1327 | % index) | |
|
1328 | hist = {} | |
|
1329 | for i in range(start, stop): | |
|
1330 | if output: | |
|
1331 | hist[i] = (input_hist[i], output_hist.get(i)) | |
|
1332 | else: | |
|
1333 | hist[i] = input_hist[i] | |
|
1334 | if len(hist)==0: | |
|
1335 | raise IndexError('No history for range of indices: %r' % index) | |
|
1336 | return hist | |
|
1337 | ||
|
1338 | 1244 | #------------------------------------------------------------------------- |
|
1339 | 1245 | # Things related to exception handling and tracebacks (not debugging) |
|
1340 | 1246 | #------------------------------------------------------------------------- |
@@ -2200,6 +2106,20 b' class InteractiveShell(Configurable, Magic):' | |||
|
2200 | 2106 | self.input_hist_raw.append(cell) |
|
2201 | 2107 | self.input_hist.append(ipy_cell) |
|
2202 | 2108 | |
|
2109 | ||
|
2110 | # dbg code!!! | |
|
2111 | def myapp(self, val): # dbg | |
|
2112 | import traceback as tb | |
|
2113 | stack = ''.join(tb.format_stack()) | |
|
2114 | print 'Value:', val | |
|
2115 | print 'Stack:\n', stack | |
|
2116 | list.append(self, val) | |
|
2117 | ||
|
2118 | import new | |
|
2119 | self.input_hist.append = new.instancemethod(myapp, self.input_hist, | |
|
2120 | list) | |
|
2121 | # End dbg | |
|
2122 | ||
|
2203 | 2123 | # All user code execution must happen with our context managers active |
|
2204 | 2124 | with nested(self.builtin_trap, self.display_trap): |
|
2205 | 2125 | # Single-block input should behave like an interactive prompt |
General Comments 0
You need to be logged in to leave comments.
Login now