Show More
1 | NO CONTENT: modified file chmod 100644 => 100755 |
|
NO CONTENT: modified file chmod 100644 => 100755 |
@@ -54,8 +54,9 b' class DisplayHook(Configurable):' | |||||
54 | """ |
|
54 | """ | |
55 |
|
55 | |||
56 | shell = Instance('IPython.core.interactiveshell.InteractiveShellABC') |
|
56 | shell = Instance('IPython.core.interactiveshell.InteractiveShellABC') | |
|
57 | ||||
57 | # Each call to the In[] prompt raises it by 1, even the first. |
|
58 | # Each call to the In[] prompt raises it by 1, even the first. | |
58 | prompt_count = Int(0) |
|
59 | #prompt_count = Int(0) | |
59 |
|
60 | |||
60 | def __init__(self, shell=None, cache_size=1000, |
|
61 | def __init__(self, shell=None, cache_size=1000, | |
61 | colors='NoColor', input_sep='\n', |
|
62 | colors='NoColor', input_sep='\n', | |
@@ -114,6 +115,10 b' class DisplayHook(Configurable):' | |||||
114 | to_user_ns = {'_':self._,'__':self.__,'___':self.___} |
|
115 | to_user_ns = {'_':self._,'__':self.__,'___':self.___} | |
115 | self.shell.user_ns.update(to_user_ns) |
|
116 | self.shell.user_ns.update(to_user_ns) | |
116 |
|
117 | |||
|
118 | @property | |||
|
119 | def prompt_count(self): | |||
|
120 | return self.shell.execution_count | |||
|
121 | ||||
117 | def _set_prompt_str(self,p_str,cache_def,no_cache_def): |
|
122 | def _set_prompt_str(self,p_str,cache_def,no_cache_def): | |
118 | if p_str is None: |
|
123 | if p_str is None: | |
119 | if self.do_full_cache: |
|
124 | if self.do_full_cache: |
@@ -1,14 +1,238 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
|||
2 |
|
|
1 | """ History related magics and functionality """ | |
|
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 | # Stdlib imports |
|
15 | # Stdlib imports | |
5 | import fnmatch |
|
16 | import fnmatch | |
6 | import os |
|
17 | import os | |
|
18 | import sys | |||
7 |
|
19 | |||
|
20 | # Our own packages | |||
8 | import IPython.utils.io |
|
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 | from IPython.utils.io import ask_yes_no |
|
26 | from IPython.utils.io import ask_yes_no | |
10 | from IPython.utils.warn import warn |
|
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 | # Public interface | |||
|
37 | ||||
|
38 | # An instance of the IPython shell we are attached to | |||
|
39 | shell = None | |||
|
40 | # An InputList instance to hold processed history | |||
|
41 | input_hist = None | |||
|
42 | # An InputList instance to hold raw history (as typed by user) | |||
|
43 | input_hist_raw = None | |||
|
44 | # A list of directories visited during session | |||
|
45 | dir_hist = None | |||
|
46 | # A dict of output history, keyed with ints from the shell's execution count | |||
|
47 | output_hist = None | |||
|
48 | # String with path to the history file | |||
|
49 | hist_file = None | |||
|
50 | # PickleShareDB instance holding the raw data for the shadow history | |||
|
51 | shadow_db = None | |||
|
52 | # ShadowHist instance with the actual shadow history | |||
|
53 | shadow_hist = None | |||
|
54 | ||||
|
55 | # Private interface | |||
|
56 | # Variables used to store the three last inputs from the user. On each new | |||
|
57 | # history update, we populate the user's namespace with these, shifted as | |||
|
58 | # necessary. | |||
|
59 | _i00, _i, _ii, _iii = '','','','' | |||
|
60 | ||||
|
61 | def __init__(self, shell): | |||
|
62 | """Create a new history manager associated with a shell instance. | |||
|
63 | """ | |||
|
64 | # We need a pointer back to the shell for various tasks. | |||
|
65 | self.shell = shell | |||
|
66 | ||||
|
67 | # List of input with multi-line handling. | |||
|
68 | self.input_hist = InputList() | |||
|
69 | # This one will hold the 'raw' input history, without any | |||
|
70 | # pre-processing. This will allow users to retrieve the input just as | |||
|
71 | # it was exactly typed in by the user, with %hist -r. | |||
|
72 | self.input_hist_raw = InputList() | |||
|
73 | ||||
|
74 | # list of visited directories | |||
|
75 | try: | |||
|
76 | self.dir_hist = [os.getcwd()] | |||
|
77 | except OSError: | |||
|
78 | self.dir_hist = [] | |||
|
79 | ||||
|
80 | # dict of output history | |||
|
81 | self.output_hist = {} | |||
|
82 | ||||
|
83 | # Now the history file | |||
|
84 | if shell.profile: | |||
|
85 | histfname = 'history-%s' % shell.profile | |||
|
86 | else: | |||
|
87 | histfname = 'history' | |||
|
88 | self.hist_file = os.path.join(shell.ipython_dir, histfname) | |||
|
89 | ||||
|
90 | # Objects related to shadow history management | |||
|
91 | self._init_shadow_hist() | |||
|
92 | ||||
|
93 | self._i00, self._i, self._ii, self._iii = '','','','' | |||
|
94 | ||||
|
95 | # Object is fully initialized, we can now call methods on it. | |||
|
96 | ||||
|
97 | # Fill the history zero entry, user counter starts at 1 | |||
|
98 | self.store_inputs('\n', '\n') | |||
|
99 | ||||
|
100 | # For backwards compatibility, we must put these back in the shell | |||
|
101 | # object, until we've removed all direct uses of the history objects in | |||
|
102 | # the shell itself. | |||
|
103 | shell.input_hist = self.input_hist | |||
|
104 | shell.input_hist_raw = self.input_hist_raw | |||
|
105 | shell.output_hist = self.output_hist | |||
|
106 | shell.dir_hist = self.dir_hist | |||
|
107 | shell.histfile = self.hist_file | |||
|
108 | shell.shadowhist = self.shadow_hist | |||
|
109 | shell.db = self.shadow_db | |||
|
110 | ||||
|
111 | def _init_shadow_hist(self): | |||
|
112 | try: | |||
|
113 | self.shadow_db = PickleShareDB(os.path.join( | |||
|
114 | self.shell.ipython_dir, 'db')) | |||
|
115 | except UnicodeDecodeError: | |||
|
116 | print("Your ipython_dir can't be decoded to unicode!") | |||
|
117 | print("Please set HOME environment variable to something that") | |||
|
118 | print(r"only has ASCII characters, e.g. c:\home") | |||
|
119 | print("Now it is", self.ipython_dir) | |||
|
120 | sys.exit() | |||
|
121 | self.shadow_hist = ShadowHist(self.shadow_db) | |||
|
122 | ||||
|
123 | def save_hist(self): | |||
|
124 | """Save input history to a file (via readline library).""" | |||
|
125 | ||||
|
126 | try: | |||
|
127 | self.shell.readline.write_history_file(self.hist_file) | |||
|
128 | except: | |||
|
129 | print('Unable to save IPython command history to file: ' + | |||
|
130 | `self.hist_file`) | |||
|
131 | ||||
|
132 | def reload_hist(self): | |||
|
133 | """Reload the input history from disk file.""" | |||
|
134 | ||||
|
135 | try: | |||
|
136 | self.shell.readline.clear_history() | |||
|
137 | self.shell.readline.read_history_file(self.hist_file) | |||
|
138 | except AttributeError: | |||
|
139 | pass | |||
|
140 | ||||
|
141 | def get_history(self, index=None, raw=False, output=True): | |||
|
142 | """Get the history list. | |||
|
143 | ||||
|
144 | Get the input and output history. | |||
|
145 | ||||
|
146 | Parameters | |||
|
147 | ---------- | |||
|
148 | index : n or (n1, n2) or None | |||
|
149 | If n, then the last entries. If a tuple, then all in | |||
|
150 | range(n1, n2). If None, then all entries. Raises IndexError if | |||
|
151 | the format of index is incorrect. | |||
|
152 | raw : bool | |||
|
153 | If True, return the raw input. | |||
|
154 | output : bool | |||
|
155 | If True, then return the output as well. | |||
|
156 | ||||
|
157 | Returns | |||
|
158 | ------- | |||
|
159 | If output is True, then return a dict of tuples, keyed by the prompt | |||
|
160 | numbers and with values of (input, output). If output is False, then | |||
|
161 | a dict, keyed by the prompt number with the values of input. Raises | |||
|
162 | IndexError if no history is found. | |||
|
163 | """ | |||
|
164 | if raw: | |||
|
165 | input_hist = self.input_hist_raw | |||
|
166 | else: | |||
|
167 | input_hist = self.input_hist | |||
|
168 | if output: | |||
|
169 | output_hist = self.output_hist | |||
|
170 | n = len(input_hist) | |||
|
171 | if index is None: | |||
|
172 | start=0; stop=n | |||
|
173 | elif isinstance(index, int): | |||
|
174 | start=n-index; stop=n | |||
|
175 | elif isinstance(index, tuple) and len(index) == 2: | |||
|
176 | start=index[0]; stop=index[1] | |||
|
177 | else: | |||
|
178 | raise IndexError('Not a valid index for the input history: %r' | |||
|
179 | % index) | |||
|
180 | hist = {} | |||
|
181 | for i in range(start, stop): | |||
|
182 | if output: | |||
|
183 | hist[i] = (input_hist[i], output_hist.get(i)) | |||
|
184 | else: | |||
|
185 | hist[i] = input_hist[i] | |||
|
186 | if not hist: | |||
|
187 | raise IndexError('No history for range of indices: %r' % index) | |||
|
188 | return hist | |||
|
189 | ||||
|
190 | def store_inputs(self, source, source_raw=None): | |||
|
191 | """Store source and raw input in history and create input cache | |||
|
192 | variables _i*. | |||
|
193 | ||||
|
194 | Parameters | |||
|
195 | ---------- | |||
|
196 | source : str | |||
|
197 | Python input. | |||
|
198 | ||||
|
199 | source_raw : str, optional | |||
|
200 | If given, this is the raw input without any IPython transformations | |||
|
201 | applied to it. If not given, ``source`` is used. | |||
|
202 | """ | |||
|
203 | if source_raw is None: | |||
|
204 | source_raw = source | |||
|
205 | self.input_hist.append(source) | |||
|
206 | self.input_hist_raw.append(source_raw) | |||
|
207 | self.shadow_hist.add(source) | |||
|
208 | ||||
|
209 | # update the auto _i variables | |||
|
210 | self._iii = self._ii | |||
|
211 | self._ii = self._i | |||
|
212 | self._i = self._i00 | |||
|
213 | self._i00 = source_raw | |||
|
214 | ||||
|
215 | # hackish access to user namespace to create _i1,_i2... dynamically | |||
|
216 | new_i = '_i%s' % self.shell.execution_count | |||
|
217 | to_main = {'_i': self._i, | |||
|
218 | '_ii': self._ii, | |||
|
219 | '_iii': self._iii, | |||
|
220 | new_i : self._i00 } | |||
|
221 | self.shell.user_ns.update(to_main) | |||
|
222 | ||||
|
223 | def sync_inputs(self): | |||
|
224 | """Ensure raw and translated histories have same length.""" | |||
|
225 | if len(self.input_hist) != len (self.input_hist_raw): | |||
|
226 | self.input_hist_raw = InputList(self.input_hist) | |||
|
227 | ||||
|
228 | def reset(self): | |||
|
229 | """Clear all histories managed by this object.""" | |||
|
230 | self.input_hist[:] = [] | |||
|
231 | self.input_hist_raw[:] = [] | |||
|
232 | self.output_hist.clear() | |||
|
233 | # The directory history can't be completely empty | |||
|
234 | self.dir_hist[:] = [os.getcwd()] | |||
|
235 | ||||
12 |
|
236 | |||
13 | def magic_history(self, parameter_s = ''): |
|
237 | def magic_history(self, parameter_s = ''): | |
14 | """Print input history (_i<n> variables), with most recent last. |
|
238 | """Print input history (_i<n> variables), with most recent last. | |
@@ -55,7 +279,7 b" def magic_history(self, parameter_s = ''):" | |||||
55 | """ |
|
279 | """ | |
56 |
|
280 | |||
57 | if not self.shell.displayhook.do_full_cache: |
|
281 | if not self.shell.displayhook.do_full_cache: | |
58 |
print |
|
282 | print('This feature is only available if numbered prompts are in use.') | |
59 | return |
|
283 | return | |
60 | opts,args = self.parse_options(parameter_s,'gnoptsrf:',mode='list') |
|
284 | opts,args = self.parse_options(parameter_s,'gnoptsrf:',mode='list') | |
61 |
|
285 | |||
@@ -69,7 +293,7 b" def magic_history(self, parameter_s = ''):" | |||||
69 | else: |
|
293 | else: | |
70 | if os.path.exists(outfname): |
|
294 | if os.path.exists(outfname): | |
71 | if not ask_yes_no("File %r exists. Overwrite?" % outfname): |
|
295 | if not ask_yes_no("File %r exists. Overwrite?" % outfname): | |
72 |
print |
|
296 | print('Aborting.') | |
73 | return |
|
297 | return | |
74 |
|
298 | |||
75 | outfile = open(outfname,'w') |
|
299 | outfile = open(outfname,'w') | |
@@ -103,7 +327,7 b" def magic_history(self, parameter_s = ''):" | |||||
103 | init, final = map(int, args) |
|
327 | init, final = map(int, args) | |
104 | else: |
|
328 | else: | |
105 | warn('%hist takes 0, 1 or 2 arguments separated by spaces.') |
|
329 | warn('%hist takes 0, 1 or 2 arguments separated by spaces.') | |
106 | print >> IPython.utils.io.Term.cout, self.magic_hist.__doc__ |
|
330 | print(self.magic_hist.__doc__, file=IPython.utils.io.Term.cout) | |
107 | return |
|
331 | return | |
108 |
|
332 | |||
109 | width = len(str(final)) |
|
333 | width = len(str(final)) | |
@@ -117,14 +341,14 b" def magic_history(self, parameter_s = ''):" | |||||
117 | sh = self.shell.shadowhist.all() |
|
341 | sh = self.shell.shadowhist.all() | |
118 | for idx, s in sh: |
|
342 | for idx, s in sh: | |
119 | if fnmatch.fnmatch(s, pattern): |
|
343 | if fnmatch.fnmatch(s, pattern): | |
120 |
print |
|
344 | print("0%d: %s" %(idx, s.expandtabs(4)), file=outfile) | |
121 | found = True |
|
345 | found = True | |
122 |
|
346 | |||
123 | if found: |
|
347 | if found: | |
124 |
print |
|
348 | print("===", file=outfile) | |
125 | print >> outfile, \ |
|
349 | print("shadow history ends, fetch by %rep <number> (must start with 0)", | |
126 | "shadow history ends, fetch by %rep <number> (must start with 0)" |
|
350 | file=outfile) | |
127 |
print |
|
351 | print("=== start of normal history ===", file=outfile) | |
128 |
|
352 | |||
129 | for in_num in range(init, final): |
|
353 | for in_num in range(init, final): | |
130 | # Print user history with tabs expanded to 4 spaces. The GUI clients |
|
354 | # Print user history with tabs expanded to 4 spaces. The GUI clients | |
@@ -137,22 +361,22 b" def magic_history(self, parameter_s = ''):" | |||||
137 |
|
361 | |||
138 | multiline = int(inline.count('\n') > 1) |
|
362 | multiline = int(inline.count('\n') > 1) | |
139 | if print_nums: |
|
363 | if print_nums: | |
140 | print >> outfile, \ |
|
364 | print('%s:%s' % (str(in_num).ljust(width), line_sep[multiline]), | |
141 | '%s:%s' % (str(in_num).ljust(width), line_sep[multiline]), |
|
365 | file=outfile) | |
142 | if pyprompts: |
|
366 | if pyprompts: | |
143 |
print |
|
367 | print('>>>', file=outfile) | |
144 | if multiline: |
|
368 | if multiline: | |
145 | lines = inline.splitlines() |
|
369 | lines = inline.splitlines() | |
146 |
print |
|
370 | print('\n... '.join(lines), file=outfile) | |
147 |
print |
|
371 | print('... ', file=outfile) | |
148 | else: |
|
372 | else: | |
149 |
print |
|
373 | print(inline, end='', file=outfile) | |
150 | else: |
|
374 | else: | |
151 |
print |
|
375 | print(inline,end='', file=outfile) | |
152 | if print_outputs: |
|
376 | if print_outputs: | |
153 | output = self.shell.output_hist.get(in_num) |
|
377 | output = self.shell.output_hist.get(in_num) | |
154 | if output is not None: |
|
378 | if output is not None: | |
155 |
print |
|
379 | print(repr(output), file=outfile) | |
156 |
|
380 | |||
157 | if close_at_end: |
|
381 | if close_at_end: | |
158 | outfile.close() |
|
382 | outfile.close() | |
@@ -223,10 +447,10 b' def rep_f(self, arg):' | |||||
223 |
|
447 | |||
224 | try: |
|
448 | try: | |
225 | lines = self.extract_input_slices(args, True) |
|
449 | lines = self.extract_input_slices(args, True) | |
226 |
print |
|
450 | print("lines", lines) | |
227 |
self.run |
|
451 | self.run_cell(lines) | |
228 | except ValueError: |
|
452 | except ValueError: | |
229 |
print |
|
453 | print("Not found in recent history:", args) | |
230 |
|
454 | |||
231 |
|
455 | |||
232 | _sentinel = object() |
|
456 | _sentinel = object() | |
@@ -251,11 +475,11 b' class ShadowHist(object):' | |||||
251 | if old is not _sentinel: |
|
475 | if old is not _sentinel: | |
252 | return |
|
476 | return | |
253 | newidx = self.inc_idx() |
|
477 | newidx = self.inc_idx() | |
254 |
#print |
|
478 | #print("new", newidx) # dbg | |
255 | self.db.hset('shadowhist',ent, newidx) |
|
479 | self.db.hset('shadowhist',ent, newidx) | |
256 | except: |
|
480 | except: | |
257 | ipapi.get().showtraceback() |
|
481 | ipapi.get().showtraceback() | |
258 |
print |
|
482 | print("WARNING: disabling shadow history") | |
259 | self.disabled = True |
|
483 | self.disabled = True | |
260 |
|
484 | |||
261 | def all(self): |
|
485 | def all(self): | |
@@ -268,7 +492,6 b' class ShadowHist(object):' | |||||
268 | all = self.all() |
|
492 | all = self.all() | |
269 |
|
493 | |||
270 | for k, v in all: |
|
494 | for k, v in all: | |
271 | #print k,v |
|
|||
272 | if k == idx: |
|
495 | if k == idx: | |
273 | return v |
|
496 | return v | |
274 |
|
497 |
@@ -53,7 +53,7 b' import IPython.utils.io' | |||||
53 | __all__ = ['editor', 'fix_error_editor', 'synchronize_with_editor', |
|
53 | __all__ = ['editor', 'fix_error_editor', 'synchronize_with_editor', | |
54 | 'input_prefilter', 'shutdown_hook', 'late_startup_hook', |
|
54 | 'input_prefilter', 'shutdown_hook', 'late_startup_hook', | |
55 | 'generate_prompt', 'show_in_pager','pre_prompt_hook', |
|
55 | 'generate_prompt', 'show_in_pager','pre_prompt_hook', | |
56 | 'pre_runcode_hook', 'clipboard_get'] |
|
56 | 'pre_run_code_hook', 'clipboard_get'] | |
57 |
|
57 | |||
58 | def editor(self,filename, linenum=None): |
|
58 | def editor(self,filename, linenum=None): | |
59 | """Open the default editor at the given filename and linenumber. |
|
59 | """Open the default editor at the given filename and linenumber. | |
@@ -238,7 +238,7 b' def pre_prompt_hook(self):' | |||||
238 | return None |
|
238 | return None | |
239 |
|
239 | |||
240 |
|
240 | |||
241 | def pre_runcode_hook(self): |
|
241 | def pre_run_code_hook(self): | |
242 | """ Executed before running the (prefiltered) code in IPython """ |
|
242 | """ Executed before running the (prefiltered) code in IPython """ | |
243 | return None |
|
243 | return None | |
244 |
|
244 |
@@ -371,15 +371,6 b' class InputSplitter(object):' | |||||
371 | if self.input_mode == 'cell': |
|
371 | if self.input_mode == 'cell': | |
372 | self.reset() |
|
372 | self.reset() | |
373 |
|
373 | |||
374 | # If the source code has leading blanks, add 'if 1:\n' to it |
|
|||
375 | # this allows execution of indented pasted code. It is tempting |
|
|||
376 | # to add '\n' at the end of source to run commands like ' a=1' |
|
|||
377 | # directly, but this fails for more complicated scenarios |
|
|||
378 |
|
||||
379 | if not self._buffer and lines[:1] in [' ', '\t'] and \ |
|
|||
380 | not comment_line_re.match(lines): |
|
|||
381 | lines = 'if 1:\n%s' % lines |
|
|||
382 |
|
||||
383 | self._store(lines) |
|
374 | self._store(lines) | |
384 | source = self.source |
|
375 | source = self.source | |
385 |
|
376 | |||
@@ -600,20 +591,23 b' class InputSplitter(object):' | |||||
600 | if line and not line.isspace(): |
|
591 | if line and not line.isspace(): | |
601 | self.indent_spaces, self._full_dedent = self._find_indent(line) |
|
592 | self.indent_spaces, self._full_dedent = self._find_indent(line) | |
602 |
|
593 | |||
603 | def _store(self, lines): |
|
594 | def _store(self, lines, buffer=None, store='source'): | |
604 | """Store one or more lines of input. |
|
595 | """Store one or more lines of input. | |
605 |
|
596 | |||
606 | If input lines are not newline-terminated, a newline is automatically |
|
597 | If input lines are not newline-terminated, a newline is automatically | |
607 | appended.""" |
|
598 | appended.""" | |
608 |
|
599 | |||
|
600 | if buffer is None: | |||
|
601 | buffer = self._buffer | |||
|
602 | ||||
609 | if lines.endswith('\n'): |
|
603 | if lines.endswith('\n'): | |
610 |
|
|
604 | buffer.append(lines) | |
611 | else: |
|
605 | else: | |
612 |
|
|
606 | buffer.append(lines+'\n') | |
613 | self._set_source() |
|
607 | setattr(self, store, self._set_source(buffer)) | |
614 |
|
608 | |||
615 | def _set_source(self): |
|
609 | def _set_source(self, buffer): | |
616 |
|
|
610 | return ''.join(buffer).encode(self.encoding) | |
617 |
|
611 | |||
618 |
|
612 | |||
619 | #----------------------------------------------------------------------------- |
|
613 | #----------------------------------------------------------------------------- | |
@@ -932,6 +926,32 b' transform_escaped = EscapedTransformer()' | |||||
932 | class IPythonInputSplitter(InputSplitter): |
|
926 | class IPythonInputSplitter(InputSplitter): | |
933 | """An input splitter that recognizes all of IPython's special syntax.""" |
|
927 | """An input splitter that recognizes all of IPython's special syntax.""" | |
934 |
|
928 | |||
|
929 | # String with raw, untransformed input. | |||
|
930 | source_raw = '' | |||
|
931 | ||||
|
932 | # Private attributes | |||
|
933 | ||||
|
934 | # List with lines of raw input accumulated so far. | |||
|
935 | _buffer_raw = None | |||
|
936 | ||||
|
937 | def __init__(self, input_mode=None): | |||
|
938 | InputSplitter.__init__(self, input_mode) | |||
|
939 | self._buffer_raw = [] | |||
|
940 | ||||
|
941 | def reset(self): | |||
|
942 | """Reset the input buffer and associated state.""" | |||
|
943 | InputSplitter.reset(self) | |||
|
944 | self._buffer_raw[:] = [] | |||
|
945 | self.source_raw = '' | |||
|
946 | ||||
|
947 | def source_raw_reset(self): | |||
|
948 | """Return input and raw source and perform a full reset. | |||
|
949 | """ | |||
|
950 | out = self.source | |||
|
951 | out_r = self.source_raw | |||
|
952 | self.reset() | |||
|
953 | return out, out_r | |||
|
954 | ||||
935 | def push(self, lines): |
|
955 | def push(self, lines): | |
936 | """Push one or more lines of IPython input. |
|
956 | """Push one or more lines of IPython input. | |
937 | """ |
|
957 | """ | |
@@ -964,12 +984,17 b' class IPythonInputSplitter(InputSplitter):' | |||||
964 | # line. |
|
984 | # line. | |
965 | changed_input_mode = False |
|
985 | changed_input_mode = False | |
966 |
|
986 | |||
967 |
if |
|
987 | if self.input_mode == 'cell': | |
968 | self.reset() |
|
988 | self.reset() | |
969 | changed_input_mode = True |
|
989 | changed_input_mode = True | |
970 | saved_input_mode = 'cell' |
|
990 | saved_input_mode = 'cell' | |
971 | self.input_mode = 'line' |
|
991 | self.input_mode = 'line' | |
972 |
|
992 | |||
|
993 | # Store raw source before applying any transformations to it. Note | |||
|
994 | # that this must be done *after* the reset() call that would otherwise | |||
|
995 | # flush the buffer. | |||
|
996 | self._store(lines, self._buffer_raw, 'source_raw') | |||
|
997 | ||||
973 | try: |
|
998 | try: | |
974 | push = super(IPythonInputSplitter, self).push |
|
999 | push = super(IPythonInputSplitter, self).push | |
975 | for line in lines_list: |
|
1000 | for line in lines_list: | |
@@ -982,5 +1007,4 b' class IPythonInputSplitter(InputSplitter):' | |||||
982 | finally: |
|
1007 | finally: | |
983 | if changed_input_mode: |
|
1008 | if changed_input_mode: | |
984 | self.input_mode = saved_input_mode |
|
1009 | self.input_mode = saved_input_mode | |
985 |
|
||||
986 | return out |
|
1010 | return out |
@@ -1,6 +1,4 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | """Logger class for IPython's logging facilities. | |
2 | """ |
|
|||
3 | Logger class for IPython's logging facilities. |
|
|||
4 | """ |
|
2 | """ | |
5 |
|
3 | |||
6 | #***************************************************************************** |
|
4 | #***************************************************************************** | |
@@ -26,13 +24,12 b' import time' | |||||
26 | class Logger(object): |
|
24 | class Logger(object): | |
27 | """A Logfile class with different policies for file creation""" |
|
25 | """A Logfile class with different policies for file creation""" | |
28 |
|
26 | |||
29 |
def __init__(self, |
|
27 | def __init__(self, home_dir, logfname='Logger.log', loghead='', | |
30 |
|
28 | logmode='over'): | ||
31 | self._i00,self._i,self._ii,self._iii = '','','','' |
|
|||
32 |
|
29 | |||
33 | # this is the full ipython instance, we need some attributes from it |
|
30 | # this is the full ipython instance, we need some attributes from it | |
34 | # which won't exist until later. What a mess, clean up later... |
|
31 | # which won't exist until later. What a mess, clean up later... | |
35 |
self. |
|
32 | self.home_dir = home_dir | |
36 |
|
33 | |||
37 | self.logfname = logfname |
|
34 | self.logfname = logfname | |
38 | self.loghead = loghead |
|
35 | self.loghead = loghead | |
@@ -102,7 +99,7 b' class Logger(object):' | |||||
102 | self.logfile = open(self.logfname,'w') |
|
99 | self.logfile = open(self.logfname,'w') | |
103 |
|
100 | |||
104 | elif logmode == 'global': |
|
101 | elif logmode == 'global': | |
105 |
self.logfname = os.path.join(self. |
|
102 | self.logfname = os.path.join(self.home_dir,self.logfname) | |
106 | self.logfile = open(self.logfname, 'a') |
|
103 | self.logfile = open(self.logfname, 'a') | |
107 |
|
104 | |||
108 | elif logmode == 'over': |
|
105 | elif logmode == 'over': | |
@@ -166,63 +163,18 b' which already exists. But you must first start the logging process with' | |||||
166 | print 'Timestamping :',self.timestamp |
|
163 | print 'Timestamping :',self.timestamp | |
167 | print 'State :',state |
|
164 | print 'State :',state | |
168 |
|
165 | |||
169 |
def log(self, |
|
166 | def log(self, line_mod, line_ori): | |
170 | """Write the line to a log and create input cache variables _i*. |
|
167 | """Write the sources to a log. | |
171 |
|
168 | |||
172 | Inputs: |
|
169 | Inputs: | |
173 |
|
170 | |||
174 | - line_ori: unmodified input line from the user. This is not |
|
|||
175 | necessarily valid Python. |
|
|||
176 |
|
||||
177 | - line_mod: possibly modified input, such as the transformations made |
|
171 | - line_mod: possibly modified input, such as the transformations made | |
178 | by input prefilters or input handlers of various kinds. This should |
|
172 | by input prefilters or input handlers of various kinds. This should | |
179 | always be valid Python. |
|
173 | always be valid Python. | |
180 |
|
174 | |||
181 | - continuation: if True, indicates this is part of multi-line input.""" |
|
175 | - line_ori: unmodified input line from the user. This is not | |
182 |
|
176 | necessarily valid Python. | ||
183 | # update the auto _i tables |
|
177 | """ | |
184 | #print '***logging line',line_mod # dbg |
|
|||
185 | #print '***cache_count', self.shell.displayhook.prompt_count # dbg |
|
|||
186 | try: |
|
|||
187 | input_hist = self.shell.user_ns['_ih'] |
|
|||
188 | except: |
|
|||
189 | #print 'userns:',self.shell.user_ns.keys() # dbg |
|
|||
190 | return |
|
|||
191 |
|
||||
192 | out_cache = self.shell.displayhook |
|
|||
193 |
|
||||
194 | # add blank lines if the input cache fell out of sync. |
|
|||
195 | if out_cache.do_full_cache and \ |
|
|||
196 | out_cache.prompt_count +1 > len(input_hist): |
|
|||
197 | input_hist.extend(['\n'] * (out_cache.prompt_count - len(input_hist))) |
|
|||
198 |
|
||||
199 | if not continuation and line_mod: |
|
|||
200 | self._iii = self._ii |
|
|||
201 | self._ii = self._i |
|
|||
202 | self._i = self._i00 |
|
|||
203 | # put back the final \n of every input line |
|
|||
204 | self._i00 = line_mod+'\n' |
|
|||
205 | #print 'Logging input:<%s>' % line_mod # dbg |
|
|||
206 | input_hist.append(self._i00) |
|
|||
207 | #print '---[%s]' % (len(input_hist)-1,) # dbg |
|
|||
208 |
|
||||
209 | # hackish access to top-level namespace to create _i1,_i2... dynamically |
|
|||
210 | to_main = {'_i':self._i,'_ii':self._ii,'_iii':self._iii} |
|
|||
211 | if self.shell.displayhook.do_full_cache: |
|
|||
212 | in_num = self.shell.displayhook.prompt_count |
|
|||
213 |
|
||||
214 | # but if the opposite is true (a macro can produce multiple inputs |
|
|||
215 | # with no output display called), then bring the output counter in |
|
|||
216 | # sync: |
|
|||
217 | last_num = len(input_hist)-1 |
|
|||
218 | if in_num != last_num: |
|
|||
219 | in_num = self.shell.displayhook.prompt_count = last_num |
|
|||
220 | new_i = '_i%s' % in_num |
|
|||
221 | if continuation: |
|
|||
222 | self._i00 = '%s%s\n' % (self.shell.user_ns[new_i],line_mod) |
|
|||
223 | input_hist[in_num] = self._i00 |
|
|||
224 | to_main[new_i] = self._i00 |
|
|||
225 | self.shell.user_ns.update(to_main) |
|
|||
226 |
|
178 | |||
227 | # Write the log line, but decide which one according to the |
|
179 | # Write the log line, but decide which one according to the | |
228 | # log_raw_input flag, set when the log is started. |
|
180 | # log_raw_input flag, set when the log is started. | |
@@ -241,10 +193,10 b' which already exists. But you must first start the logging process with' | |||||
241 | if self.timestamp: |
|
193 | if self.timestamp: | |
242 | write(time.strftime('# %a, %d %b %Y %H:%M:%S\n', |
|
194 | write(time.strftime('# %a, %d %b %Y %H:%M:%S\n', | |
243 | time.localtime())) |
|
195 | time.localtime())) | |
244 |
write( |
|
196 | write(data) | |
245 | elif kind=='output' and self.log_output: |
|
197 | elif kind=='output' and self.log_output: | |
246 | odata = '\n'.join(['#[Out]# %s' % s |
|
198 | odata = '\n'.join(['#[Out]# %s' % s | |
247 |
for s in data.split( |
|
199 | for s in data.splitlines()]) | |
248 | write('%s\n' % odata) |
|
200 | write('%s\n' % odata) | |
249 | self.logfile.flush() |
|
201 | self.logfile.flush() | |
250 |
|
202 |
@@ -20,9 +20,7 b' class Macro(IPyAutocall):' | |||||
20 | """ |
|
20 | """ | |
21 |
|
21 | |||
22 | def __init__(self,data): |
|
22 | def __init__(self,data): | |
23 |
|
23 | # store the macro value, as a single string which can be executed | ||
24 | # store the macro value, as a single string which can be evaluated by |
|
|||
25 | # runlines() |
|
|||
26 | self.value = ''.join(data).rstrip()+'\n' |
|
24 | self.value = ''.join(data).rstrip()+'\n' | |
27 |
|
25 | |||
28 | def __str__(self): |
|
26 | def __str__(self): | |
@@ -34,7 +32,7 b' class Macro(IPyAutocall):' | |||||
34 | def __call__(self,*args): |
|
32 | def __call__(self,*args): | |
35 | IPython.utils.io.Term.cout.flush() |
|
33 | IPython.utils.io.Term.cout.flush() | |
36 | self._ip.user_ns['_margv'] = args |
|
34 | self._ip.user_ns['_margv'] = args | |
37 |
self._ip.run |
|
35 | self._ip.run_cell(self.value) | |
38 |
|
36 | |||
39 | def __getstate__(self): |
|
37 | def __getstate__(self): | |
40 | """ needed for safe pickling via %store """ |
|
38 | """ needed for safe pickling via %store """ |
@@ -41,11 +41,6 b' except ImportError:' | |||||
41 | except ImportError: |
|
41 | except ImportError: | |
42 | profile = pstats = None |
|
42 | profile = pstats = None | |
43 |
|
43 | |||
44 | # print_function was added to __future__ in Python2.6, remove this when we drop |
|
|||
45 | # 2.5 compatibility |
|
|||
46 | if not hasattr(__future__,'CO_FUTURE_PRINT_FUNCTION'): |
|
|||
47 | __future__.CO_FUTURE_PRINT_FUNCTION = 65536 |
|
|||
48 |
|
||||
49 | import IPython |
|
44 | import IPython | |
50 | from IPython.core import debugger, oinspect |
|
45 | from IPython.core import debugger, oinspect | |
51 | from IPython.core.error import TryNext |
|
46 | from IPython.core.error import TryNext | |
@@ -1556,7 +1551,7 b' Currently the magic system has the following functions:\\n"""' | |||||
1556 |
|
1551 | |||
1557 | stats = None |
|
1552 | stats = None | |
1558 | try: |
|
1553 | try: | |
1559 | self.shell.savehist() |
|
1554 | self.shell.save_hist() | |
1560 |
|
1555 | |||
1561 | if opts.has_key('p'): |
|
1556 | if opts.has_key('p'): | |
1562 | stats = self.magic_prun('',0,opts,arg_lst,prog_ns) |
|
1557 | stats = self.magic_prun('',0,opts,arg_lst,prog_ns) | |
@@ -1675,7 +1670,7 b' Currently the magic system has the following functions:\\n"""' | |||||
1675 | # contained therein. |
|
1670 | # contained therein. | |
1676 | del sys.modules[main_mod_name] |
|
1671 | del sys.modules[main_mod_name] | |
1677 |
|
1672 | |||
1678 | self.shell.reloadhist() |
|
1673 | self.shell.reload_hist() | |
1679 |
|
1674 | |||
1680 | return stats |
|
1675 | return stats | |
1681 |
|
1676 | |||
@@ -2331,7 +2326,7 b' Currently the magic system has the following functions:\\n"""' | |||||
2331 | else: |
|
2326 | else: | |
2332 | print 'done. Executing edited code...' |
|
2327 | print 'done. Executing edited code...' | |
2333 | if opts_r: |
|
2328 | if opts_r: | |
2334 |
self.shell.run |
|
2329 | self.shell.run_cell(file_read(filename)) | |
2335 | else: |
|
2330 | else: | |
2336 | self.shell.safe_execfile(filename,self.shell.user_ns, |
|
2331 | self.shell.safe_execfile(filename,self.shell.user_ns, | |
2337 | self.shell.user_ns) |
|
2332 | self.shell.user_ns) | |
@@ -2992,7 +2987,7 b' Defaulting color scheme to \'NoColor\'"""' | |||||
2992 | (input.startswith(start) or input.startswith(start_magic)): |
|
2987 | (input.startswith(start) or input.startswith(start_magic)): | |
2993 | #print 'match',`input` # dbg |
|
2988 | #print 'match',`input` # dbg | |
2994 | print 'Executing:',input, |
|
2989 | print 'Executing:',input, | |
2995 |
self.shell.run |
|
2990 | self.shell.run_cell(input) | |
2996 | return |
|
2991 | return | |
2997 | print 'No previous input matching `%s` found.' % start |
|
2992 | print 'No previous input matching `%s` found.' % start | |
2998 |
|
2993 |
@@ -373,10 +373,6 b' class PrefilterManager(Configurable):' | |||||
373 | # print "prefilter_line: ", line, continue_prompt |
|
373 | # print "prefilter_line: ", line, continue_prompt | |
374 | # All handlers *must* return a value, even if it's blank (''). |
|
374 | # All handlers *must* return a value, even if it's blank (''). | |
375 |
|
375 | |||
376 | # Lines are NOT logged here. Handlers should process the line as |
|
|||
377 | # needed, update the cache AND log it (so that the input cache array |
|
|||
378 | # stays synced). |
|
|||
379 |
|
||||
380 | # save the line away in case we crash, so the post-mortem handler can |
|
376 | # save the line away in case we crash, so the post-mortem handler can | |
381 | # record it |
|
377 | # record it | |
382 | self.shell._last_input_line = line |
|
378 | self.shell._last_input_line = line | |
@@ -792,7 +788,6 b' class PrefilterHandler(Configurable):' | |||||
792 | ): |
|
788 | ): | |
793 | line = '' |
|
789 | line = '' | |
794 |
|
790 | |||
795 | self.shell.log(line, line, continue_prompt) |
|
|||
796 | return line |
|
791 | return line | |
797 |
|
792 | |||
798 | def __str__(self): |
|
793 | def __str__(self): | |
@@ -811,7 +806,6 b' class AliasHandler(PrefilterHandler):' | |||||
811 | line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace, |
|
806 | line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace, | |
812 | make_quoted_expr(transformed)) |
|
807 | make_quoted_expr(transformed)) | |
813 |
|
808 | |||
814 | self.shell.log(line_info.line, line_out, line_info.continue_prompt) |
|
|||
815 | return line_out |
|
809 | return line_out | |
816 |
|
810 | |||
817 |
|
811 | |||
@@ -840,8 +834,6 b' class ShellEscapeHandler(PrefilterHandler):' | |||||
840 | cmd = line.lstrip().lstrip(ESC_SHELL) |
|
834 | cmd = line.lstrip().lstrip(ESC_SHELL) | |
841 | line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace, |
|
835 | line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace, | |
842 | make_quoted_expr(cmd)) |
|
836 | make_quoted_expr(cmd)) | |
843 | # update cache/log and return |
|
|||
844 | self.shell.log(line, line_out, line_info.continue_prompt) |
|
|||
845 | return line_out |
|
837 | return line_out | |
846 |
|
838 | |||
847 |
|
839 | |||
@@ -856,7 +848,6 b' class MagicHandler(PrefilterHandler):' | |||||
856 | the_rest = line_info.the_rest |
|
848 | the_rest = line_info.the_rest | |
857 | cmd = '%sget_ipython().magic(%s)' % (line_info.pre_whitespace, |
|
849 | cmd = '%sget_ipython().magic(%s)' % (line_info.pre_whitespace, | |
858 | make_quoted_expr(ifun + " " + the_rest)) |
|
850 | make_quoted_expr(ifun + " " + the_rest)) | |
859 | self.shell.log(line_info.line, cmd, line_info.continue_prompt) |
|
|||
860 | return cmd |
|
851 | return cmd | |
861 |
|
852 | |||
862 |
|
853 | |||
@@ -877,7 +868,6 b' class AutoHandler(PrefilterHandler):' | |||||
877 |
|
868 | |||
878 | # This should only be active for single-line input! |
|
869 | # This should only be active for single-line input! | |
879 | if continue_prompt: |
|
870 | if continue_prompt: | |
880 | self.shell.log(line,line,continue_prompt) |
|
|||
881 | return line |
|
871 | return line | |
882 |
|
872 | |||
883 | force_auto = isinstance(obj, IPyAutocall) |
|
873 | force_auto = isinstance(obj, IPyAutocall) | |
@@ -918,9 +908,6 b' class AutoHandler(PrefilterHandler):' | |||||
918 | if auto_rewrite: |
|
908 | if auto_rewrite: | |
919 | self.shell.auto_rewrite_input(newcmd) |
|
909 | self.shell.auto_rewrite_input(newcmd) | |
920 |
|
910 | |||
921 | # log what is now valid Python, not the actual user input (without the |
|
|||
922 | # final newline) |
|
|||
923 | self.shell.log(line,newcmd,continue_prompt) |
|
|||
924 | return newcmd |
|
911 | return newcmd | |
925 |
|
912 | |||
926 |
|
913 | |||
@@ -947,7 +934,6 b' class HelpHandler(PrefilterHandler):' | |||||
947 | line = line[1:] |
|
934 | line = line[1:] | |
948 | elif line[-1]==ESC_HELP: |
|
935 | elif line[-1]==ESC_HELP: | |
949 | line = line[:-1] |
|
936 | line = line[:-1] | |
950 | self.shell.log(line, '#?'+line, line_info.continue_prompt) |
|
|||
951 | if line: |
|
937 | if line: | |
952 | #print 'line:<%r>' % line # dbg |
|
938 | #print 'line:<%r>' % line # dbg | |
953 | self.shell.magic_pinfo(line) |
|
939 | self.shell.magic_pinfo(line) |
@@ -372,15 +372,7 b' class Prompt1(BasePrompt):' | |||||
372 | self.col_p_ni = self.col_p.replace('\001','').replace('\002','') |
|
372 | self.col_p_ni = self.col_p.replace('\001','').replace('\002','') | |
373 | self.col_norm_ni = Colors.normal |
|
373 | self.col_norm_ni = Colors.normal | |
374 |
|
374 | |||
375 | def peek_next_prompt(self): |
|
|||
376 | """Get the next prompt, but don't increment the counter.""" |
|
|||
377 | self.cache.prompt_count += 1 |
|
|||
378 | next_prompt = str_safe(self.p_str) |
|
|||
379 | self.cache.prompt_count -= 1 |
|
|||
380 | return next_prompt |
|
|||
381 |
|
||||
382 | def __str__(self): |
|
375 | def __str__(self): | |
383 | self.cache.prompt_count += 1 |
|
|||
384 | self.cache.last_prompt = str_safe(self.p_str_nocolor).split('\n')[-1] |
|
376 | self.cache.last_prompt = str_safe(self.p_str_nocolor).split('\n')[-1] | |
385 | return str_safe(self.p_str) |
|
377 | return str_safe(self.p_str) | |
386 |
|
378 |
@@ -162,6 +162,12 b' class InputSplitterTestCase(unittest.TestCase):' | |||||
162 | self.assertEqual(isp.indent_spaces, 4) |
|
162 | self.assertEqual(isp.indent_spaces, 4) | |
163 | isp.push('y=2\n') |
|
163 | isp.push('y=2\n') | |
164 | self.assertEqual(isp.indent_spaces, 0) |
|
164 | self.assertEqual(isp.indent_spaces, 0) | |
|
165 | ||||
|
166 | def test_indent2(self): | |||
|
167 | # In cell mode, inputs must be fed in whole blocks, so skip this test | |||
|
168 | if self.isp.input_mode == 'cell': return | |||
|
169 | ||||
|
170 | isp = self.isp | |||
165 | isp.push('if 1:') |
|
171 | isp.push('if 1:') | |
166 | self.assertEqual(isp.indent_spaces, 4) |
|
172 | self.assertEqual(isp.indent_spaces, 4) | |
167 | isp.push(' x=1') |
|
173 | isp.push(' x=1') | |
@@ -170,7 +176,10 b' class InputSplitterTestCase(unittest.TestCase):' | |||||
170 | isp.push(' '*2) |
|
176 | isp.push(' '*2) | |
171 | self.assertEqual(isp.indent_spaces, 4) |
|
177 | self.assertEqual(isp.indent_spaces, 4) | |
172 |
|
178 | |||
173 |
def test_indent |
|
179 | def test_indent3(self): | |
|
180 | # In cell mode, inputs must be fed in whole blocks, so skip this test | |||
|
181 | if self.isp.input_mode == 'cell': return | |||
|
182 | ||||
174 | isp = self.isp |
|
183 | isp = self.isp | |
175 | # When a multiline statement contains parens or multiline strings, we |
|
184 | # When a multiline statement contains parens or multiline strings, we | |
176 | # shouldn't get confused. |
|
185 | # shouldn't get confused. | |
@@ -195,13 +204,6 b' class InputSplitterTestCase(unittest.TestCase):' | |||||
195 | for line in [' x=1', '# a comment', ' y=2']: |
|
204 | for line in [' x=1', '# a comment', ' y=2']: | |
196 | self.assertTrue(isp.push(line)) |
|
205 | self.assertTrue(isp.push(line)) | |
197 |
|
206 | |||
198 | def test_push3(self): |
|
|||
199 | """Test input with leading whitespace""" |
|
|||
200 | isp = self.isp |
|
|||
201 | isp.push(' x=1') |
|
|||
202 | isp.push(' y=2') |
|
|||
203 | self.assertEqual(isp.source, 'if 1:\n x=1\n y=2\n') |
|
|||
204 |
|
||||
205 | def test_replace_mode(self): |
|
207 | def test_replace_mode(self): | |
206 | isp = self.isp |
|
208 | isp = self.isp | |
207 | isp.input_mode = 'cell' |
|
209 | isp.input_mode = 'cell' | |
@@ -216,6 +218,9 b' class InputSplitterTestCase(unittest.TestCase):' | |||||
216 | self.assertFalse(isp.push_accepts_more()) |
|
218 | self.assertFalse(isp.push_accepts_more()) | |
217 |
|
219 | |||
218 | def test_push_accepts_more2(self): |
|
220 | def test_push_accepts_more2(self): | |
|
221 | # In cell mode, inputs must be fed in whole blocks, so skip this test | |||
|
222 | if self.isp.input_mode == 'cell': return | |||
|
223 | ||||
219 | isp = self.isp |
|
224 | isp = self.isp | |
220 | isp.push('if 1:') |
|
225 | isp.push('if 1:') | |
221 | self.assertTrue(isp.push_accepts_more()) |
|
226 | self.assertTrue(isp.push_accepts_more()) | |
@@ -230,6 +235,9 b' class InputSplitterTestCase(unittest.TestCase):' | |||||
230 | self.assertFalse(isp.push_accepts_more()) |
|
235 | self.assertFalse(isp.push_accepts_more()) | |
231 |
|
236 | |||
232 | def test_push_accepts_more4(self): |
|
237 | def test_push_accepts_more4(self): | |
|
238 | # In cell mode, inputs must be fed in whole blocks, so skip this test | |||
|
239 | if self.isp.input_mode == 'cell': return | |||
|
240 | ||||
233 | isp = self.isp |
|
241 | isp = self.isp | |
234 | # When a multiline statement contains parens or multiline strings, we |
|
242 | # When a multiline statement contains parens or multiline strings, we | |
235 | # shouldn't get confused. |
|
243 | # shouldn't get confused. | |
@@ -563,6 +571,8 b' class IPythonInputTestCase(InputSplitterTestCase):' | |||||
563 |
|
571 | |||
564 | In addition, this runs the tests over the syntax and syntax_ml dicts that |
|
572 | In addition, this runs the tests over the syntax and syntax_ml dicts that | |
565 | were tested by individual functions, as part of the OO interface. |
|
573 | were tested by individual functions, as part of the OO interface. | |
|
574 | ||||
|
575 | It also makes some checks on the raw buffer storage. | |||
566 | """ |
|
576 | """ | |
567 |
|
577 | |||
568 | def setUp(self): |
|
578 | def setUp(self): | |
@@ -577,21 +587,26 b' class IPythonInputTestCase(InputSplitterTestCase):' | |||||
577 | continue |
|
587 | continue | |
578 |
|
588 | |||
579 | isp.push(raw) |
|
589 | isp.push(raw) | |
580 |
out = isp.source_reset |
|
590 | out, out_raw = isp.source_raw_reset() | |
581 | self.assertEqual(out, out_t) |
|
591 | self.assertEqual(out.rstrip(), out_t) | |
|
592 | self.assertEqual(out_raw.rstrip(), raw.rstrip()) | |||
582 |
|
593 | |||
583 | def test_syntax_multiline(self): |
|
594 | def test_syntax_multiline(self): | |
584 | isp = self.isp |
|
595 | isp = self.isp | |
585 | for example in syntax_ml.itervalues(): |
|
596 | for example in syntax_ml.itervalues(): | |
586 | out_t_parts = [] |
|
597 | out_t_parts = [] | |
|
598 | raw_parts = [] | |||
587 | for line_pairs in example: |
|
599 | for line_pairs in example: | |
588 | for raw, out_t_part in line_pairs: |
|
600 | for lraw, out_t_part in line_pairs: | |
589 | isp.push(raw) |
|
601 | isp.push(lraw) | |
590 | out_t_parts.append(out_t_part) |
|
602 | out_t_parts.append(out_t_part) | |
|
603 | raw_parts.append(lraw) | |||
591 |
|
604 | |||
592 |
out = isp.source_reset |
|
605 | out, out_raw = isp.source_raw_reset() | |
593 | out_t = '\n'.join(out_t_parts).rstrip() |
|
606 | out_t = '\n'.join(out_t_parts).rstrip() | |
594 | self.assertEqual(out, out_t) |
|
607 | raw = '\n'.join(raw_parts).rstrip() | |
|
608 | self.assertEqual(out.rstrip(), out_t) | |||
|
609 | self.assertEqual(out_raw.rstrip(), raw) | |||
595 |
|
610 | |||
596 |
|
611 | |||
597 | class BlockIPythonInputTestCase(IPythonInputTestCase): |
|
612 | class BlockIPythonInputTestCase(IPythonInputTestCase): | |
@@ -616,9 +631,10 b' class BlockIPythonInputTestCase(IPythonInputTestCase):' | |||||
616 | out_t = '\n'.join(out_t_parts) |
|
631 | out_t = '\n'.join(out_t_parts) | |
617 |
|
632 | |||
618 | isp.push(raw) |
|
633 | isp.push(raw) | |
619 | out = isp.source_reset() |
|
634 | out, out_raw = isp.source_raw_reset() | |
620 | # Match ignoring trailing whitespace |
|
635 | # Match ignoring trailing whitespace | |
621 | self.assertEqual(out.rstrip(), out_t.rstrip()) |
|
636 | self.assertEqual(out.rstrip(), out_t.rstrip()) | |
|
637 | self.assertEqual(out_raw.rstrip(), raw.rstrip()) | |||
622 |
|
638 | |||
623 |
|
639 | |||
624 | #----------------------------------------------------------------------------- |
|
640 | #----------------------------------------------------------------------------- | |
@@ -652,7 +668,8 b" if __name__ == '__main__':" | |||||
652 | # Here we just return input so we can use it in a test suite, but a |
|
668 | # Here we just return input so we can use it in a test suite, but a | |
653 | # real interpreter would instead send it for execution somewhere. |
|
669 | # real interpreter would instead send it for execution somewhere. | |
654 | #src = isp.source; raise EOFError # dbg |
|
670 | #src = isp.source; raise EOFError # dbg | |
655 | src = isp.source_reset() |
|
671 | src, raw = isp.source_raw_reset() | |
656 | print 'Input source was:\n', src |
|
672 | print 'Input source was:\n', src | |
|
673 | print 'Raw source was:\n', raw | |||
657 | except EOFError: |
|
674 | except EOFError: | |
658 | print 'Bye' |
|
675 | print 'Bye' |
@@ -137,29 +137,30 b' class ParalleMagic(Plugin):' | |||||
137 | self._enable_autopx() |
|
137 | self._enable_autopx() | |
138 |
|
138 | |||
139 | def _enable_autopx(self): |
|
139 | def _enable_autopx(self): | |
140 | """Enable %autopx mode by saving the original runsource and installing |
|
140 | """Enable %autopx mode by saving the original run_source and installing | |
141 | pxrunsource. |
|
141 | pxrun_source. | |
142 | """ |
|
142 | """ | |
143 | if self.active_multiengine_client is None: |
|
143 | if self.active_multiengine_client is None: | |
144 | print NO_ACTIVE_MULTIENGINE_CLIENT |
|
144 | print NO_ACTIVE_MULTIENGINE_CLIENT | |
145 | return |
|
145 | return | |
146 |
|
146 | |||
147 | self._original_runsource = self.shell.runsource |
|
147 | self._original_run_source = self.shell.run_source | |
148 | self.shell.runsource = new.instancemethod( |
|
148 | self.shell.run_source = new.instancemethod( | |
149 | self.pxrunsource, self.shell, self.shell.__class__ |
|
149 | self.pxrun_source, self.shell, self.shell.__class__ | |
150 | ) |
|
150 | ) | |
151 | self.autopx = True |
|
151 | self.autopx = True | |
152 | print "%autopx enabled" |
|
152 | print "%autopx enabled" | |
153 |
|
153 | |||
154 | def _disable_autopx(self): |
|
154 | def _disable_autopx(self): | |
155 |
"""Disable %autopx by restoring the original InteractiveShell.runsource. |
|
155 | """Disable %autopx by restoring the original InteractiveShell.run_source. | |
|
156 | """ | |||
156 | if self.autopx: |
|
157 | if self.autopx: | |
157 | self.shell.runsource = self._original_runsource |
|
158 | self.shell.run_source = self._original_run_source | |
158 | self.autopx = False |
|
159 | self.autopx = False | |
159 | print "%autopx disabled" |
|
160 | print "%autopx disabled" | |
160 |
|
161 | |||
161 | def pxrunsource(self, ipself, source, filename="<input>", symbol="single"): |
|
162 | def pxrun_source(self, ipself, source, filename="<input>", symbol="single"): | |
162 | """A parallel replacement for InteractiveShell.runsource.""" |
|
163 | """A parallel replacement for InteractiveShell.run_source.""" | |
163 |
|
164 | |||
164 | try: |
|
165 | try: | |
165 | code = ipself.compile(source, filename, symbol) |
|
166 | code = ipself.compile(source, filename, symbol) |
@@ -191,8 +191,7 b' class TerminalInteractiveShell(InteractiveShell):' | |||||
191 |
|
191 | |||
192 | # if you run stuff with -c <cmd>, raw hist is not updated |
|
192 | # if you run stuff with -c <cmd>, raw hist is not updated | |
193 | # ensure that it's in sync |
|
193 | # ensure that it's in sync | |
194 | if len(self.input_hist) != len (self.input_hist_raw): |
|
194 | self.history_manager.sync_inputs() | |
195 | self.input_hist_raw = InputList(self.input_hist) |
|
|||
196 |
|
195 | |||
197 | while 1: |
|
196 | while 1: | |
198 | try: |
|
197 | try: | |
@@ -218,7 +217,7 b' class TerminalInteractiveShell(InteractiveShell):' | |||||
218 | if display_banner: |
|
217 | if display_banner: | |
219 | self.show_banner() |
|
218 | self.show_banner() | |
220 |
|
219 | |||
221 |
more = |
|
220 | more = False | |
222 |
|
221 | |||
223 | # Mark activity in the builtins |
|
222 | # Mark activity in the builtins | |
224 | __builtin__.__dict__['__IPYTHON__active'] += 1 |
|
223 | __builtin__.__dict__['__IPYTHON__active'] += 1 | |
@@ -244,7 +243,7 b' class TerminalInteractiveShell(InteractiveShell):' | |||||
244 | except: |
|
243 | except: | |
245 | self.showtraceback() |
|
244 | self.showtraceback() | |
246 | try: |
|
245 | try: | |
247 |
line = self.raw_input(prompt |
|
246 | line = self.raw_input(prompt) | |
248 | if self.exit_now: |
|
247 | if self.exit_now: | |
249 | # quick exit on sys.std[in|out] close |
|
248 | # quick exit on sys.std[in|out] close | |
250 | break |
|
249 | break | |
@@ -256,12 +255,7 b' class TerminalInteractiveShell(InteractiveShell):' | |||||
256 | try: |
|
255 | try: | |
257 | self.write('\nKeyboardInterrupt\n') |
|
256 | self.write('\nKeyboardInterrupt\n') | |
258 | self.resetbuffer() |
|
257 | self.resetbuffer() | |
259 | # keep cache in sync with the prompt counter: |
|
258 | more = False | |
260 | self.displayhook.prompt_count -= 1 |
|
|||
261 |
|
||||
262 | if self.autoindent: |
|
|||
263 | self.indent_current_nsp = 0 |
|
|||
264 | more = 0 |
|
|||
265 | except KeyboardInterrupt: |
|
259 | except KeyboardInterrupt: | |
266 | pass |
|
260 | pass | |
267 | except EOFError: |
|
261 | except EOFError: | |
@@ -281,10 +275,14 b' class TerminalInteractiveShell(InteractiveShell):' | |||||
281 | # asynchronously by signal handlers, for example. |
|
275 | # asynchronously by signal handlers, for example. | |
282 | self.showtraceback() |
|
276 | self.showtraceback() | |
283 | else: |
|
277 | else: | |
284 |
|
|
278 | self.input_splitter.push(line) | |
|
279 | more = self.input_splitter.push_accepts_more() | |||
285 | if (self.SyntaxTB.last_syntax_error and |
|
280 | if (self.SyntaxTB.last_syntax_error and | |
286 | self.autoedit_syntax): |
|
281 | self.autoedit_syntax): | |
287 | self.edit_syntax_error() |
|
282 | self.edit_syntax_error() | |
|
283 | if not more: | |||
|
284 | source_raw = self.input_splitter.source_raw_reset()[1] | |||
|
285 | self.run_cell(source_raw) | |||
288 |
|
286 | |||
289 | # We are off again... |
|
287 | # We are off again... | |
290 | __builtin__.__dict__['__IPYTHON__active'] -= 1 |
|
288 | __builtin__.__dict__['__IPYTHON__active'] -= 1 | |
@@ -305,8 +303,6 b' class TerminalInteractiveShell(InteractiveShell):' | |||||
305 | - continue_prompt(False): whether this line is the first one or a |
|
303 | - continue_prompt(False): whether this line is the first one or a | |
306 | continuation in a sequence of inputs. |
|
304 | continuation in a sequence of inputs. | |
307 | """ |
|
305 | """ | |
308 | # growl.notify("raw_input: ", "prompt = %r\ncontinue_prompt = %s" % (prompt, continue_prompt)) |
|
|||
309 |
|
||||
310 | # Code run by the user may have modified the readline completer state. |
|
306 | # Code run by the user may have modified the readline completer state. | |
311 | # We must ensure that our completer is back in place. |
|
307 | # We must ensure that our completer is back in place. | |
312 |
|
308 | |||
@@ -324,8 +320,6 b' class TerminalInteractiveShell(InteractiveShell):' | |||||
324 | # Try to be reasonably smart about not re-indenting pasted input more |
|
320 | # Try to be reasonably smart about not re-indenting pasted input more | |
325 | # than necessary. We do this by trimming out the auto-indent initial |
|
321 | # than necessary. We do this by trimming out the auto-indent initial | |
326 | # spaces, if the user's actual input started itself with whitespace. |
|
322 | # spaces, if the user's actual input started itself with whitespace. | |
327 | #debugx('self.buffer[-1]') |
|
|||
328 |
|
||||
329 | if self.autoindent: |
|
323 | if self.autoindent: | |
330 | if num_ini_spaces(line) > self.indent_current_nsp: |
|
324 | if num_ini_spaces(line) > self.indent_current_nsp: | |
331 | line = line[self.indent_current_nsp:] |
|
325 | line = line[self.indent_current_nsp:] | |
@@ -335,22 +329,15 b' class TerminalInteractiveShell(InteractiveShell):' | |||||
335 | # it. |
|
329 | # it. | |
336 | if line.strip(): |
|
330 | if line.strip(): | |
337 | if continue_prompt: |
|
331 | if continue_prompt: | |
338 | self.input_hist_raw[-1] += '%s\n' % line |
|
|||
339 | if self.has_readline and self.readline_use: |
|
332 | if self.has_readline and self.readline_use: | |
340 | try: |
|
|||
341 |
|
|
333 | histlen = self.readline.get_current_history_length() | |
342 |
|
|
334 | if histlen > 1: | |
343 |
|
|
335 | newhist = self.input_hist_raw[-1].rstrip() | |
344 |
|
|
336 | self.readline.remove_history_item(histlen-1) | |
345 |
|
|
337 | self.readline.replace_history_item(histlen-2, | |
346 |
|
|
338 | newhist.encode(self.stdin_encoding)) | |
347 | except AttributeError: |
|
|||
348 | pass # re{move,place}_history_item are new in 2.4. |
|
|||
349 | else: |
|
339 | else: | |
350 | self.input_hist_raw.append('%s\n' % line) |
|
340 | self.input_hist_raw.append('%s\n' % line) | |
351 | # only entries starting at first column go to shadow history |
|
|||
352 | if line.lstrip() == line: |
|
|||
353 | self.shadowhist.add(line.strip()) |
|
|||
354 | elif not continue_prompt: |
|
341 | elif not continue_prompt: | |
355 | self.input_hist_raw.append('\n') |
|
342 | self.input_hist_raw.append('\n') | |
356 | try: |
|
343 | try: | |
@@ -363,67 +350,43 b' class TerminalInteractiveShell(InteractiveShell):' | |||||
363 | else: |
|
350 | else: | |
364 | return lineout |
|
351 | return lineout | |
365 |
|
352 | |||
366 | # TODO: The following three methods are an early attempt to refactor |
|
353 | ||
367 | # the main code execution logic. We don't use them, but they may be |
|
354 | def raw_input(self, prompt=''): | |
368 | # helpful when we refactor the code execution logic further. |
|
355 | """Write a prompt and read a line. | |
369 | # def interact_prompt(self): |
|
356 | ||
370 | # """ Print the prompt (in read-eval-print loop) |
|
357 | The returned line does not include the trailing newline. | |
371 | # |
|
358 | When the user enters the EOF key sequence, EOFError is raised. | |
372 | # Provided for those who want to implement their own read-eval-print loop (e.g. GUIs), not |
|
359 | ||
373 | # used in standard IPython flow. |
|
360 | Optional inputs: | |
374 | # """ |
|
361 | ||
375 | # if self.more: |
|
362 | - prompt(''): a string to be printed to prompt the user. | |
376 | # try: |
|
363 | ||
377 | # prompt = self.hooks.generate_prompt(True) |
|
364 | - continue_prompt(False): whether this line is the first one or a | |
378 | # except: |
|
365 | continuation in a sequence of inputs. | |
379 | # self.showtraceback() |
|
366 | """ | |
380 | # if self.autoindent: |
|
367 | # Code run by the user may have modified the readline completer state. | |
381 | # self.rl_do_indent = True |
|
368 | # We must ensure that our completer is back in place. | |
382 | # |
|
369 | ||
383 | # else: |
|
370 | if self.has_readline: | |
384 | # try: |
|
371 | self.set_readline_completer() | |
385 | # prompt = self.hooks.generate_prompt(False) |
|
372 | ||
386 |
|
|
373 | try: | |
387 | # self.showtraceback() |
|
374 | line = raw_input_original(prompt).decode(self.stdin_encoding) | |
388 | # self.write(prompt) |
|
375 | except ValueError: | |
389 | # |
|
376 | warn("\n********\nYou or a %run:ed script called sys.stdin.close()" | |
390 | # def interact_handle_input(self,line): |
|
377 | " or sys.stdout.close()!\nExiting IPython!") | |
391 | # """ Handle the input line (in read-eval-print loop) |
|
378 | self.ask_exit() | |
392 | # |
|
379 | return "" | |
393 | # Provided for those who want to implement their own read-eval-print loop (e.g. GUIs), not |
|
380 | ||
394 | # used in standard IPython flow. |
|
381 | # Try to be reasonably smart about not re-indenting pasted input more | |
395 | # """ |
|
382 | # than necessary. We do this by trimming out the auto-indent initial | |
396 | # if line.lstrip() == line: |
|
383 | # spaces, if the user's actual input started itself with whitespace. | |
397 | # self.shadowhist.add(line.strip()) |
|
384 | if self.autoindent: | |
398 | # lineout = self.prefilter_manager.prefilter_lines(line,self.more) |
|
385 | if num_ini_spaces(line) > self.indent_current_nsp: | |
399 | # |
|
386 | line = line[self.indent_current_nsp:] | |
400 | # if line.strip(): |
|
387 | self.indent_current_nsp = 0 | |
401 | # if self.more: |
|
388 | ||
402 | # self.input_hist_raw[-1] += '%s\n' % line |
|
389 | return line | |
403 | # else: |
|
|||
404 | # self.input_hist_raw.append('%s\n' % line) |
|
|||
405 | # |
|
|||
406 | # |
|
|||
407 | # self.more = self.push_line(lineout) |
|
|||
408 | # if (self.SyntaxTB.last_syntax_error and |
|
|||
409 | # self.autoedit_syntax): |
|
|||
410 | # self.edit_syntax_error() |
|
|||
411 | # |
|
|||
412 | # def interact_with_readline(self): |
|
|||
413 | # """ Demo of using interact_handle_input, interact_prompt |
|
|||
414 | # |
|
|||
415 | # This is the main read-eval-print loop. If you need to implement your own (e.g. for GUI), |
|
|||
416 | # it should work like this. |
|
|||
417 | # """ |
|
|||
418 | # self.readline_startup_hook(self.pre_readline) |
|
|||
419 | # while not self.exit_now: |
|
|||
420 | # self.interact_prompt() |
|
|||
421 | # if self.more: |
|
|||
422 | # self.rl_do_indent = True |
|
|||
423 | # else: |
|
|||
424 | # self.rl_do_indent = False |
|
|||
425 | # line = raw_input_original().decode(self.stdin_encoding) |
|
|||
426 | # self.interact_handle_input(line) |
|
|||
427 |
|
390 | |||
428 | #------------------------------------------------------------------------- |
|
391 | #------------------------------------------------------------------------- | |
429 | # Methods to support auto-editing of SyntaxErrors. |
|
392 | # Methods to support auto-editing of SyntaxErrors. |
@@ -571,7 +571,7 b' class IPythonApp(Application):' | |||||
571 | try: |
|
571 | try: | |
572 | self.log.info("Running code in user namespace: %s" % |
|
572 | self.log.info("Running code in user namespace: %s" % | |
573 | line) |
|
573 | line) | |
574 |
self.shell.run |
|
574 | self.shell.run_cell(line) | |
575 | except: |
|
575 | except: | |
576 | self.log.warn("Error in executing line in user " |
|
576 | self.log.warn("Error in executing line in user " | |
577 | "namespace: %s" % line) |
|
577 | "namespace: %s" % line) | |
@@ -616,7 +616,7 b' class IPythonApp(Application):' | |||||
616 | try: |
|
616 | try: | |
617 | self.log.info("Running code given at command line (-c): %s" % |
|
617 | self.log.info("Running code given at command line (-c): %s" % | |
618 | line) |
|
618 | line) | |
619 |
self.shell.run |
|
619 | self.shell.run_cell(line) | |
620 | except: |
|
620 | except: | |
621 | self.log.warn("Error in executing line in user namespace: %s" % |
|
621 | self.log.warn("Error in executing line in user namespace: %s" % | |
622 | line) |
|
622 | line) |
@@ -248,7 +248,7 b' class Demo(object):' | |||||
248 | self.ip_ns = ip.user_ns |
|
248 | self.ip_ns = ip.user_ns | |
249 | self.ip_colorize = ip.pycolorize |
|
249 | self.ip_colorize = ip.pycolorize | |
250 | self.ip_showtb = ip.showtraceback |
|
250 | self.ip_showtb = ip.showtraceback | |
251 |
self.ip_run |
|
251 | self.ip_run_cell = ip.run_cell | |
252 | self.shell = ip |
|
252 | self.shell = ip | |
253 |
|
253 | |||
254 | # load user data and initialize data structures |
|
254 | # load user data and initialize data structures | |
@@ -411,7 +411,7 b' class Demo(object):' | |||||
411 | print >>IPython.utils.io.Term.cout, block, |
|
411 | print >>IPython.utils.io.Term.cout, block, | |
412 | sys.stdout.flush() |
|
412 | sys.stdout.flush() | |
413 |
|
413 | |||
414 |
def run |
|
414 | def run_cell(self,source): | |
415 | """Execute a string with one or more lines of code""" |
|
415 | """Execute a string with one or more lines of code""" | |
416 |
|
416 | |||
417 | exec source in self.user_ns |
|
417 | exec source in self.user_ns | |
@@ -449,7 +449,7 b' class Demo(object):' | |||||
449 | try: |
|
449 | try: | |
450 | save_argv = sys.argv |
|
450 | save_argv = sys.argv | |
451 | sys.argv = self.sys_argv |
|
451 | sys.argv = self.sys_argv | |
452 |
self.run |
|
452 | self.run_cell(next_block) | |
453 | self.post_cmd() |
|
453 | self.post_cmd() | |
454 | finally: |
|
454 | finally: | |
455 | sys.argv = save_argv |
|
455 | sys.argv = save_argv | |
@@ -496,10 +496,10 b' class IPythonDemo(Demo):' | |||||
496 | class requires the input to be valid, pure Python code. |
|
496 | class requires the input to be valid, pure Python code. | |
497 | """ |
|
497 | """ | |
498 |
|
498 | |||
499 |
def run |
|
499 | def run_cell(self,source): | |
500 | """Execute a string with one or more lines of code""" |
|
500 | """Execute a string with one or more lines of code""" | |
501 |
|
501 | |||
502 |
self.shell.run |
|
502 | self.shell.run_cell(source) | |
503 |
|
503 | |||
504 | class LineDemo(Demo): |
|
504 | class LineDemo(Demo): | |
505 | """Demo where each line is executed as a separate block. |
|
505 | """Demo where each line is executed as a separate block. |
@@ -209,19 +209,13 b' class Kernel(Configurable):' | |||||
209 | reply_content = {} |
|
209 | reply_content = {} | |
210 | try: |
|
210 | try: | |
211 | if silent: |
|
211 | if silent: | |
212 | # runcode uses 'exec' mode, so no displayhook will fire, and it |
|
212 | # run_code uses 'exec' mode, so no displayhook will fire, and it | |
213 | # doesn't call logging or history manipulations. Print |
|
213 | # doesn't call logging or history manipulations. Print | |
214 | # statements in that code will obviously still execute. |
|
214 | # statements in that code will obviously still execute. | |
215 | shell.runcode(code) |
|
215 | shell.run_code(code) | |
216 | else: |
|
216 | else: | |
217 |
# FIXME: |
|
217 | # FIXME: the shell calls the exception handler itself. | |
218 | shell._reply_content = None |
|
218 | shell._reply_content = None | |
219 |
|
||||
220 | # For now leave this here until we're sure we can stop using it |
|
|||
221 | #shell.runlines(code) |
|
|||
222 |
|
||||
223 | # Experimental: cell mode! Test more before turning into |
|
|||
224 | # default and removing the hacks around runlines. |
|
|||
225 | shell.run_cell(code) |
|
219 | shell.run_cell(code) | |
226 | except: |
|
220 | except: | |
227 | status = u'error' |
|
221 | status = u'error' | |
@@ -238,8 +232,9 b' class Kernel(Configurable):' | |||||
238 | status = u'ok' |
|
232 | status = u'ok' | |
239 |
|
233 | |||
240 | reply_content[u'status'] = status |
|
234 | reply_content[u'status'] = status | |
241 | # Compute the execution counter so clients can display prompts |
|
235 | ||
242 | reply_content['execution_count'] = shell.displayhook.prompt_count |
|
236 | # Return the execution counter so clients can display prompts | |
|
237 | reply_content['execution_count'] = shell.execution_count -1 | |||
243 |
|
238 | |||
244 | # FIXME - fish exception info out of shell, possibly left there by |
|
239 | # FIXME - fish exception info out of shell, possibly left there by | |
245 | # runlines. We'll need to clean up this logic later. |
|
240 | # runlines. We'll need to clean up this logic later. |
General Comments 0
You need to be logged in to leave comments.
Login now