##// END OF EJS Templates
Merge branch 'execution-refactor' of http://github.com/fperez/ipython into fperez-execution-refactor
MinRK -
r3123:7fa34c21 merge
parent child Browse files
Show More
1 NO CONTENT: modified file chmod 100644 => 100755
@@ -54,8 +54,9 b' class DisplayHook(Configurable):'
54 54 """
55 55
56 56 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
57
57 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 61 def __init__(self, shell=None, cache_size=1000,
61 62 colors='NoColor', input_sep='\n',
@@ -114,6 +115,10 b' class DisplayHook(Configurable):'
114 115 to_user_ns = {'_':self._,'__':self.__,'___':self.___}
115 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 122 def _set_prompt_str(self,p_str,cache_def,no_cache_def):
118 123 if p_str is None:
119 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 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 # 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 237 def magic_history(self, parameter_s = ''):
14 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 281 if not self.shell.displayhook.do_full_cache:
58 print 'This feature is only available if numbered prompts are in use.'
282 print('This feature is only available if numbered prompts are in use.')
59 283 return
60 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 293 else:
70 294 if os.path.exists(outfname):
71 295 if not ask_yes_no("File %r exists. Overwrite?" % outfname):
72 print 'Aborting.'
296 print('Aborting.')
73 297 return
74 298
75 299 outfile = open(outfname,'w')
@@ -103,7 +327,7 b" def magic_history(self, parameter_s = ''):"
103 327 init, final = map(int, args)
104 328 else:
105 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 331 return
108 332
109 333 width = len(str(final))
@@ -117,14 +341,14 b" def magic_history(self, parameter_s = ''):"
117 341 sh = self.shell.shadowhist.all()
118 342 for idx, s in sh:
119 343 if fnmatch.fnmatch(s, pattern):
120 print >> outfile, "0%d: %s" %(idx, s.expandtabs(4))
344 print("0%d: %s" %(idx, s.expandtabs(4)), file=outfile)
121 345 found = True
122 346
123 347 if found:
124 print >> outfile, "==="
125 print >> outfile, \
126 "shadow history ends, fetch by %rep <number> (must start with 0)"
127 print >> outfile, "=== start of normal history ==="
348 print("===", file=outfile)
349 print("shadow history ends, fetch by %rep <number> (must start with 0)",
350 file=outfile)
351 print("=== start of normal history ===", file=outfile)
128 352
129 353 for in_num in range(init, final):
130 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 362 multiline = int(inline.count('\n') > 1)
139 363 if print_nums:
140 print >> outfile, \
141 '%s:%s' % (str(in_num).ljust(width), line_sep[multiline]),
364 print('%s:%s' % (str(in_num).ljust(width), line_sep[multiline]),
365 file=outfile)
142 366 if pyprompts:
143 print >> outfile, '>>>',
367 print('>>>', file=outfile)
144 368 if multiline:
145 369 lines = inline.splitlines()
146 print >> outfile, '\n... '.join(lines)
147 print >> outfile, '... '
370 print('\n... '.join(lines), file=outfile)
371 print('... ', file=outfile)
148 372 else:
149 print >> outfile, inline,
373 print(inline, end='', file=outfile)
150 374 else:
151 print >> outfile, inline,
375 print(inline,end='', file=outfile)
152 376 if print_outputs:
153 377 output = self.shell.output_hist.get(in_num)
154 378 if output is not None:
155 print >> outfile, repr(output)
379 print(repr(output), file=outfile)
156 380
157 381 if close_at_end:
158 382 outfile.close()
@@ -223,10 +447,10 b' def rep_f(self, arg):'
223 447
224 448 try:
225 449 lines = self.extract_input_slices(args, True)
226 print "lines",lines
227 self.runlines(lines)
450 print("lines", lines)
451 self.run_cell(lines)
228 452 except ValueError:
229 print "Not found in recent history:", args
453 print("Not found in recent history:", args)
230 454
231 455
232 456 _sentinel = object()
@@ -251,11 +475,11 b' class ShadowHist(object):'
251 475 if old is not _sentinel:
252 476 return
253 477 newidx = self.inc_idx()
254 #print "new",newidx # dbg
478 #print("new", newidx) # dbg
255 479 self.db.hset('shadowhist',ent, newidx)
256 480 except:
257 481 ipapi.get().showtraceback()
258 print "WARNING: disabling shadow history"
482 print("WARNING: disabling shadow history")
259 483 self.disabled = True
260 484
261 485 def all(self):
@@ -268,7 +492,6 b' class ShadowHist(object):'
268 492 all = self.all()
269 493
270 494 for k, v in all:
271 #print k,v
272 495 if k == idx:
273 496 return v
274 497
@@ -53,7 +53,7 b' import IPython.utils.io'
53 53 __all__ = ['editor', 'fix_error_editor', 'synchronize_with_editor',
54 54 'input_prefilter', 'shutdown_hook', 'late_startup_hook',
55 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 58 def editor(self,filename, linenum=None):
59 59 """Open the default editor at the given filename and linenumber.
@@ -238,7 +238,7 b' def pre_prompt_hook(self):'
238 238 return None
239 239
240 240
241 def pre_runcode_hook(self):
241 def pre_run_code_hook(self):
242 242 """ Executed before running the (prefiltered) code in IPython """
243 243 return None
244 244
@@ -371,15 +371,6 b' class InputSplitter(object):'
371 371 if self.input_mode == 'cell':
372 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 374 self._store(lines)
384 375 source = self.source
385 376
@@ -600,20 +591,23 b' class InputSplitter(object):'
600 591 if line and not line.isspace():
601 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 595 """Store one or more lines of input.
605 596
606 597 If input lines are not newline-terminated, a newline is automatically
607 598 appended."""
608 599
600 if buffer is None:
601 buffer = self._buffer
602
609 603 if lines.endswith('\n'):
610 self._buffer.append(lines)
604 buffer.append(lines)
611 605 else:
612 self._buffer.append(lines+'\n')
613 self._set_source()
606 buffer.append(lines+'\n')
607 setattr(self, store, self._set_source(buffer))
614 608
615 def _set_source(self):
616 self.source = ''.join(self._buffer).encode(self.encoding)
609 def _set_source(self, buffer):
610 return ''.join(buffer).encode(self.encoding)
617 611
618 612
619 613 #-----------------------------------------------------------------------------
@@ -932,6 +926,32 b' transform_escaped = EscapedTransformer()'
932 926 class IPythonInputSplitter(InputSplitter):
933 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 955 def push(self, lines):
936 956 """Push one or more lines of IPython input.
937 957 """
@@ -964,12 +984,17 b' class IPythonInputSplitter(InputSplitter):'
964 984 # line.
965 985 changed_input_mode = False
966 986
967 if len(lines_list)>1 and self.input_mode == 'cell':
987 if self.input_mode == 'cell':
968 988 self.reset()
969 989 changed_input_mode = True
970 990 saved_input_mode = 'cell'
971 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 998 try:
974 999 push = super(IPythonInputSplitter, self).push
975 1000 for line in lines_list:
@@ -982,5 +1007,4 b' class IPythonInputSplitter(InputSplitter):'
982 1007 finally:
983 1008 if changed_input_mode:
984 1009 self.input_mode = saved_input_mode
985
986 1010 return out
@@ -1,6 +1,4 b''
1 # -*- coding: utf-8 -*-
2 """
3 Logger class for IPython's logging facilities.
1 """Logger class for IPython's logging facilities.
4 2 """
5 3
6 4 #*****************************************************************************
@@ -26,13 +24,12 b' import time'
26 24 class Logger(object):
27 25 """A Logfile class with different policies for file creation"""
28 26
29 def __init__(self,shell,logfname='Logger.log',loghead='',logmode='over'):
30
31 self._i00,self._i,self._ii,self._iii = '','','',''
27 def __init__(self, home_dir, logfname='Logger.log', loghead='',
28 logmode='over'):
32 29
33 30 # this is the full ipython instance, we need some attributes from it
34 31 # which won't exist until later. What a mess, clean up later...
35 self.shell = shell
32 self.home_dir = home_dir
36 33
37 34 self.logfname = logfname
38 35 self.loghead = loghead
@@ -102,7 +99,7 b' class Logger(object):'
102 99 self.logfile = open(self.logfname,'w')
103 100
104 101 elif logmode == 'global':
105 self.logfname = os.path.join(self.shell.home_dir,self.logfname)
102 self.logfname = os.path.join(self.home_dir,self.logfname)
106 103 self.logfile = open(self.logfname, 'a')
107 104
108 105 elif logmode == 'over':
@@ -166,63 +163,18 b' which already exists. But you must first start the logging process with'
166 163 print 'Timestamping :',self.timestamp
167 164 print 'State :',state
168 165
169 def log(self,line_ori,line_mod,continuation=None):
170 """Write the line to a log and create input cache variables _i*.
166 def log(self, line_mod, line_ori):
167 """Write the sources to a log.
171 168
172 169 Inputs:
173 170
174 - line_ori: unmodified input line from the user. This is not
175 necessarily valid Python.
176
177 171 - line_mod: possibly modified input, such as the transformations made
178 172 by input prefilters or input handlers of various kinds. This should
179 173 always be valid Python.
180 174
181 - continuation: if True, indicates this is part of multi-line input."""
182
183 # update the auto _i tables
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)
175 - line_ori: unmodified input line from the user. This is not
176 necessarily valid Python.
177 """
226 178
227 179 # Write the log line, but decide which one according to the
228 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 193 if self.timestamp:
242 194 write(time.strftime('# %a, %d %b %Y %H:%M:%S\n',
243 195 time.localtime()))
244 write('%s\n' % data)
196 write(data)
245 197 elif kind=='output' and self.log_output:
246 198 odata = '\n'.join(['#[Out]# %s' % s
247 for s in data.split('\n')])
199 for s in data.splitlines()])
248 200 write('%s\n' % odata)
249 201 self.logfile.flush()
250 202
@@ -20,9 +20,7 b' class Macro(IPyAutocall):'
20 20 """
21 21
22 22 def __init__(self,data):
23
24 # store the macro value, as a single string which can be evaluated by
25 # runlines()
23 # store the macro value, as a single string which can be executed
26 24 self.value = ''.join(data).rstrip()+'\n'
27 25
28 26 def __str__(self):
@@ -34,7 +32,7 b' class Macro(IPyAutocall):'
34 32 def __call__(self,*args):
35 33 IPython.utils.io.Term.cout.flush()
36 34 self._ip.user_ns['_margv'] = args
37 self._ip.runlines(self.value)
35 self._ip.run_cell(self.value)
38 36
39 37 def __getstate__(self):
40 38 """ needed for safe pickling via %store """
@@ -41,11 +41,6 b' except ImportError:'
41 41 except ImportError:
42 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 44 import IPython
50 45 from IPython.core import debugger, oinspect
51 46 from IPython.core.error import TryNext
@@ -1556,7 +1551,7 b' Currently the magic system has the following functions:\\n"""'
1556 1551
1557 1552 stats = None
1558 1553 try:
1559 self.shell.savehist()
1554 self.shell.save_hist()
1560 1555
1561 1556 if opts.has_key('p'):
1562 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 1670 # contained therein.
1676 1671 del sys.modules[main_mod_name]
1677 1672
1678 self.shell.reloadhist()
1673 self.shell.reload_hist()
1679 1674
1680 1675 return stats
1681 1676
@@ -2331,7 +2326,7 b' Currently the magic system has the following functions:\\n"""'
2331 2326 else:
2332 2327 print 'done. Executing edited code...'
2333 2328 if opts_r:
2334 self.shell.runlines(file_read(filename))
2329 self.shell.run_cell(file_read(filename))
2335 2330 else:
2336 2331 self.shell.safe_execfile(filename,self.shell.user_ns,
2337 2332 self.shell.user_ns)
@@ -2992,7 +2987,7 b' Defaulting color scheme to \'NoColor\'"""'
2992 2987 (input.startswith(start) or input.startswith(start_magic)):
2993 2988 #print 'match',`input` # dbg
2994 2989 print 'Executing:',input,
2995 self.shell.runlines(input)
2990 self.shell.run_cell(input)
2996 2991 return
2997 2992 print 'No previous input matching `%s` found.' % start
2998 2993
@@ -373,10 +373,6 b' class PrefilterManager(Configurable):'
373 373 # print "prefilter_line: ", line, continue_prompt
374 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 376 # save the line away in case we crash, so the post-mortem handler can
381 377 # record it
382 378 self.shell._last_input_line = line
@@ -792,7 +788,6 b' class PrefilterHandler(Configurable):'
792 788 ):
793 789 line = ''
794 790
795 self.shell.log(line, line, continue_prompt)
796 791 return line
797 792
798 793 def __str__(self):
@@ -811,7 +806,6 b' class AliasHandler(PrefilterHandler):'
811 806 line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace,
812 807 make_quoted_expr(transformed))
813 808
814 self.shell.log(line_info.line, line_out, line_info.continue_prompt)
815 809 return line_out
816 810
817 811
@@ -840,8 +834,6 b' class ShellEscapeHandler(PrefilterHandler):'
840 834 cmd = line.lstrip().lstrip(ESC_SHELL)
841 835 line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace,
842 836 make_quoted_expr(cmd))
843 # update cache/log and return
844 self.shell.log(line, line_out, line_info.continue_prompt)
845 837 return line_out
846 838
847 839
@@ -856,7 +848,6 b' class MagicHandler(PrefilterHandler):'
856 848 the_rest = line_info.the_rest
857 849 cmd = '%sget_ipython().magic(%s)' % (line_info.pre_whitespace,
858 850 make_quoted_expr(ifun + " " + the_rest))
859 self.shell.log(line_info.line, cmd, line_info.continue_prompt)
860 851 return cmd
861 852
862 853
@@ -877,7 +868,6 b' class AutoHandler(PrefilterHandler):'
877 868
878 869 # This should only be active for single-line input!
879 870 if continue_prompt:
880 self.shell.log(line,line,continue_prompt)
881 871 return line
882 872
883 873 force_auto = isinstance(obj, IPyAutocall)
@@ -918,9 +908,6 b' class AutoHandler(PrefilterHandler):'
918 908 if auto_rewrite:
919 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 911 return newcmd
925 912
926 913
@@ -947,7 +934,6 b' class HelpHandler(PrefilterHandler):'
947 934 line = line[1:]
948 935 elif line[-1]==ESC_HELP:
949 936 line = line[:-1]
950 self.shell.log(line, '#?'+line, line_info.continue_prompt)
951 937 if line:
952 938 #print 'line:<%r>' % line # dbg
953 939 self.shell.magic_pinfo(line)
@@ -372,15 +372,7 b' class Prompt1(BasePrompt):'
372 372 self.col_p_ni = self.col_p.replace('\001','').replace('\002','')
373 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 375 def __str__(self):
383 self.cache.prompt_count += 1
384 376 self.cache.last_prompt = str_safe(self.p_str_nocolor).split('\n')[-1]
385 377 return str_safe(self.p_str)
386 378
@@ -162,6 +162,12 b' class InputSplitterTestCase(unittest.TestCase):'
162 162 self.assertEqual(isp.indent_spaces, 4)
163 163 isp.push('y=2\n')
164 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 171 isp.push('if 1:')
166 172 self.assertEqual(isp.indent_spaces, 4)
167 173 isp.push(' x=1')
@@ -170,7 +176,10 b' class InputSplitterTestCase(unittest.TestCase):'
170 176 isp.push(' '*2)
171 177 self.assertEqual(isp.indent_spaces, 4)
172 178
173 def test_indent2(self):
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 183 isp = self.isp
175 184 # When a multiline statement contains parens or multiline strings, we
176 185 # shouldn't get confused.
@@ -195,13 +204,6 b' class InputSplitterTestCase(unittest.TestCase):'
195 204 for line in [' x=1', '# a comment', ' y=2']:
196 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 207 def test_replace_mode(self):
206 208 isp = self.isp
207 209 isp.input_mode = 'cell'
@@ -216,6 +218,9 b' class InputSplitterTestCase(unittest.TestCase):'
216 218 self.assertFalse(isp.push_accepts_more())
217 219
218 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 224 isp = self.isp
220 225 isp.push('if 1:')
221 226 self.assertTrue(isp.push_accepts_more())
@@ -230,6 +235,9 b' class InputSplitterTestCase(unittest.TestCase):'
230 235 self.assertFalse(isp.push_accepts_more())
231 236
232 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 241 isp = self.isp
234 242 # When a multiline statement contains parens or multiline strings, we
235 243 # shouldn't get confused.
@@ -563,6 +571,8 b' class IPythonInputTestCase(InputSplitterTestCase):'
563 571
564 572 In addition, this runs the tests over the syntax and syntax_ml dicts that
565 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 578 def setUp(self):
@@ -577,21 +587,26 b' class IPythonInputTestCase(InputSplitterTestCase):'
577 587 continue
578 588
579 589 isp.push(raw)
580 out = isp.source_reset().rstrip()
581 self.assertEqual(out, out_t)
590 out, out_raw = isp.source_raw_reset()
591 self.assertEqual(out.rstrip(), out_t)
592 self.assertEqual(out_raw.rstrip(), raw.rstrip())
582 593
583 594 def test_syntax_multiline(self):
584 595 isp = self.isp
585 596 for example in syntax_ml.itervalues():
586 597 out_t_parts = []
598 raw_parts = []
587 599 for line_pairs in example:
588 for raw, out_t_part in line_pairs:
589 isp.push(raw)
600 for lraw, out_t_part in line_pairs:
601 isp.push(lraw)
590 602 out_t_parts.append(out_t_part)
603 raw_parts.append(lraw)
591 604
592 out = isp.source_reset().rstrip()
605 out, out_raw = isp.source_raw_reset()
593 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 612 class BlockIPythonInputTestCase(IPythonInputTestCase):
@@ -616,9 +631,10 b' class BlockIPythonInputTestCase(IPythonInputTestCase):'
616 631 out_t = '\n'.join(out_t_parts)
617 632
618 633 isp.push(raw)
619 out = isp.source_reset()
634 out, out_raw = isp.source_raw_reset()
620 635 # Match ignoring trailing whitespace
621 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 668 # Here we just return input so we can use it in a test suite, but a
653 669 # real interpreter would instead send it for execution somewhere.
654 670 #src = isp.source; raise EOFError # dbg
655 src = isp.source_reset()
671 src, raw = isp.source_raw_reset()
656 672 print 'Input source was:\n', src
673 print 'Raw source was:\n', raw
657 674 except EOFError:
658 675 print 'Bye'
@@ -137,29 +137,30 b' class ParalleMagic(Plugin):'
137 137 self._enable_autopx()
138 138
139 139 def _enable_autopx(self):
140 """Enable %autopx mode by saving the original runsource and installing
141 pxrunsource.
140 """Enable %autopx mode by saving the original run_source and installing
141 pxrun_source.
142 142 """
143 143 if self.active_multiengine_client is None:
144 144 print NO_ACTIVE_MULTIENGINE_CLIENT
145 145 return
146 146
147 self._original_runsource = self.shell.runsource
148 self.shell.runsource = new.instancemethod(
149 self.pxrunsource, self.shell, self.shell.__class__
147 self._original_run_source = self.shell.run_source
148 self.shell.run_source = new.instancemethod(
149 self.pxrun_source, self.shell, self.shell.__class__
150 150 )
151 151 self.autopx = True
152 152 print "%autopx enabled"
153 153
154 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 157 if self.autopx:
157 self.shell.runsource = self._original_runsource
158 self.shell.run_source = self._original_run_source
158 159 self.autopx = False
159 160 print "%autopx disabled"
160 161
161 def pxrunsource(self, ipself, source, filename="<input>", symbol="single"):
162 """A parallel replacement for InteractiveShell.runsource."""
162 def pxrun_source(self, ipself, source, filename="<input>", symbol="single"):
163 """A parallel replacement for InteractiveShell.run_source."""
163 164
164 165 try:
165 166 code = ipself.compile(source, filename, symbol)
@@ -191,8 +191,7 b' class TerminalInteractiveShell(InteractiveShell):'
191 191
192 192 # if you run stuff with -c <cmd>, raw hist is not updated
193 193 # ensure that it's in sync
194 if len(self.input_hist) != len (self.input_hist_raw):
195 self.input_hist_raw = InputList(self.input_hist)
194 self.history_manager.sync_inputs()
196 195
197 196 while 1:
198 197 try:
@@ -218,7 +217,7 b' class TerminalInteractiveShell(InteractiveShell):'
218 217 if display_banner:
219 218 self.show_banner()
220 219
221 more = 0
220 more = False
222 221
223 222 # Mark activity in the builtins
224 223 __builtin__.__dict__['__IPYTHON__active'] += 1
@@ -244,7 +243,7 b' class TerminalInteractiveShell(InteractiveShell):'
244 243 except:
245 244 self.showtraceback()
246 245 try:
247 line = self.raw_input(prompt, more)
246 line = self.raw_input(prompt)
248 247 if self.exit_now:
249 248 # quick exit on sys.std[in|out] close
250 249 break
@@ -256,12 +255,7 b' class TerminalInteractiveShell(InteractiveShell):'
256 255 try:
257 256 self.write('\nKeyboardInterrupt\n')
258 257 self.resetbuffer()
259 # keep cache in sync with the prompt counter:
260 self.displayhook.prompt_count -= 1
261
262 if self.autoindent:
263 self.indent_current_nsp = 0
264 more = 0
258 more = False
265 259 except KeyboardInterrupt:
266 260 pass
267 261 except EOFError:
@@ -281,10 +275,14 b' class TerminalInteractiveShell(InteractiveShell):'
281 275 # asynchronously by signal handlers, for example.
282 276 self.showtraceback()
283 277 else:
284 more = self.push_line(line)
278 self.input_splitter.push(line)
279 more = self.input_splitter.push_accepts_more()
285 280 if (self.SyntaxTB.last_syntax_error and
286 281 self.autoedit_syntax):
287 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 287 # We are off again...
290 288 __builtin__.__dict__['__IPYTHON__active'] -= 1
@@ -305,8 +303,6 b' class TerminalInteractiveShell(InteractiveShell):'
305 303 - continue_prompt(False): whether this line is the first one or a
306 304 continuation in a sequence of inputs.
307 305 """
308 # growl.notify("raw_input: ", "prompt = %r\ncontinue_prompt = %s" % (prompt, continue_prompt))
309
310 306 # Code run by the user may have modified the readline completer state.
311 307 # We must ensure that our completer is back in place.
312 308
@@ -324,8 +320,6 b' class TerminalInteractiveShell(InteractiveShell):'
324 320 # Try to be reasonably smart about not re-indenting pasted input more
325 321 # than necessary. We do this by trimming out the auto-indent initial
326 322 # spaces, if the user's actual input started itself with whitespace.
327 #debugx('self.buffer[-1]')
328
329 323 if self.autoindent:
330 324 if num_ini_spaces(line) > self.indent_current_nsp:
331 325 line = line[self.indent_current_nsp:]
@@ -335,22 +329,15 b' class TerminalInteractiveShell(InteractiveShell):'
335 329 # it.
336 330 if line.strip():
337 331 if continue_prompt:
338 self.input_hist_raw[-1] += '%s\n' % line
339 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 339 else:
350 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 341 elif not continue_prompt:
355 342 self.input_hist_raw.append('\n')
356 343 try:
@@ -363,67 +350,43 b' class TerminalInteractiveShell(InteractiveShell):'
363 350 else:
364 351 return lineout
365 352
366 # TODO: The following three methods are an early attempt to refactor
367 # the main code execution logic. We don't use them, but they may be
368 # helpful when we refactor the code execution logic further.
369 # def interact_prompt(self):
370 # """ Print the prompt (in read-eval-print loop)
371 #
372 # Provided for those who want to implement their own read-eval-print loop (e.g. GUIs), not
373 # used in standard IPython flow.
374 # """
375 # if self.more:
376 # try:
377 # prompt = self.hooks.generate_prompt(True)
378 # except:
379 # self.showtraceback()
380 # if self.autoindent:
381 # self.rl_do_indent = True
382 #
383 # else:
384 # try:
385 # prompt = self.hooks.generate_prompt(False)
386 # except:
387 # self.showtraceback()
388 # self.write(prompt)
389 #
390 # def interact_handle_input(self,line):
391 # """ Handle the input line (in read-eval-print loop)
392 #
393 # Provided for those who want to implement their own read-eval-print loop (e.g. GUIs), not
394 # used in standard IPython flow.
395 # """
396 # if line.lstrip() == line:
397 # self.shadowhist.add(line.strip())
398 # lineout = self.prefilter_manager.prefilter_lines(line,self.more)
399 #
400 # if line.strip():
401 # if self.more:
402 # self.input_hist_raw[-1] += '%s\n' % 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)
353
354 def raw_input(self, prompt=''):
355 """Write a prompt and read a line.
356
357 The returned line does not include the trailing newline.
358 When the user enters the EOF key sequence, EOFError is raised.
359
360 Optional inputs:
361
362 - prompt(''): a string to be printed to prompt the user.
363
364 - continue_prompt(False): whether this line is the first one or a
365 continuation in a sequence of inputs.
366 """
367 # Code run by the user may have modified the readline completer state.
368 # We must ensure that our completer is back in place.
369
370 if self.has_readline:
371 self.set_readline_completer()
372
373 try:
374 line = raw_input_original(prompt).decode(self.stdin_encoding)
375 except ValueError:
376 warn("\n********\nYou or a %run:ed script called sys.stdin.close()"
377 " or sys.stdout.close()!\nExiting IPython!")
378 self.ask_exit()
379 return ""
380
381 # Try to be reasonably smart about not re-indenting pasted input more
382 # than necessary. We do this by trimming out the auto-indent initial
383 # spaces, if the user's actual input started itself with whitespace.
384 if self.autoindent:
385 if num_ini_spaces(line) > self.indent_current_nsp:
386 line = line[self.indent_current_nsp:]
387 self.indent_current_nsp = 0
388
389 return line
427 390
428 391 #-------------------------------------------------------------------------
429 392 # Methods to support auto-editing of SyntaxErrors.
@@ -571,7 +571,7 b' class IPythonApp(Application):'
571 571 try:
572 572 self.log.info("Running code in user namespace: %s" %
573 573 line)
574 self.shell.runlines(line)
574 self.shell.run_cell(line)
575 575 except:
576 576 self.log.warn("Error in executing line in user "
577 577 "namespace: %s" % line)
@@ -616,7 +616,7 b' class IPythonApp(Application):'
616 616 try:
617 617 self.log.info("Running code given at command line (-c): %s" %
618 618 line)
619 self.shell.runlines(line)
619 self.shell.run_cell(line)
620 620 except:
621 621 self.log.warn("Error in executing line in user namespace: %s" %
622 622 line)
@@ -248,7 +248,7 b' class Demo(object):'
248 248 self.ip_ns = ip.user_ns
249 249 self.ip_colorize = ip.pycolorize
250 250 self.ip_showtb = ip.showtraceback
251 self.ip_runlines = ip.runlines
251 self.ip_run_cell = ip.run_cell
252 252 self.shell = ip
253 253
254 254 # load user data and initialize data structures
@@ -411,7 +411,7 b' class Demo(object):'
411 411 print >>IPython.utils.io.Term.cout, block,
412 412 sys.stdout.flush()
413 413
414 def runlines(self,source):
414 def run_cell(self,source):
415 415 """Execute a string with one or more lines of code"""
416 416
417 417 exec source in self.user_ns
@@ -449,7 +449,7 b' class Demo(object):'
449 449 try:
450 450 save_argv = sys.argv
451 451 sys.argv = self.sys_argv
452 self.runlines(next_block)
452 self.run_cell(next_block)
453 453 self.post_cmd()
454 454 finally:
455 455 sys.argv = save_argv
@@ -496,10 +496,10 b' class IPythonDemo(Demo):'
496 496 class requires the input to be valid, pure Python code.
497 497 """
498 498
499 def runlines(self,source):
499 def run_cell(self,source):
500 500 """Execute a string with one or more lines of code"""
501 501
502 self.shell.runlines(source)
502 self.shell.run_cell(source)
503 503
504 504 class LineDemo(Demo):
505 505 """Demo where each line is executed as a separate block.
@@ -209,19 +209,13 b' class Kernel(Configurable):'
209 209 reply_content = {}
210 210 try:
211 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 213 # doesn't call logging or history manipulations. Print
214 214 # statements in that code will obviously still execute.
215 shell.runcode(code)
215 shell.run_code(code)
216 216 else:
217 # FIXME: runlines calls the exception handler itself.
217 # FIXME: the shell calls the exception handler itself.
218 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 219 shell.run_cell(code)
226 220 except:
227 221 status = u'error'
@@ -238,8 +232,9 b' class Kernel(Configurable):'
238 232 status = u'ok'
239 233
240 234 reply_content[u'status'] = status
241 # Compute the execution counter so clients can display prompts
242 reply_content['execution_count'] = shell.displayhook.prompt_count
235
236 # Return the execution counter so clients can display prompts
237 reply_content['execution_count'] = shell.execution_count -1
243 238
244 239 # FIXME - fish exception info out of shell, possibly left there by
245 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