Show More
@@ -159,6 +159,88 b' def get_input_encoding():' | |||
|
159 | 159 | # Classes and functions for normal Python syntax handling |
|
160 | 160 | #----------------------------------------------------------------------------- |
|
161 | 161 | |
|
162 | # HACK! This implementation, written by Robert K a while ago using the | |
|
163 | # compiler module, is more robust than the other one below, but it expects its | |
|
164 | # input to be pure python (no ipython syntax). For now we're using it as a | |
|
165 | # second-pass splitter after the first pass transforms the input to pure | |
|
166 | # python. | |
|
167 | ||
|
168 | def split_blocks(python): | |
|
169 | """ Split multiple lines of code into discrete commands that can be | |
|
170 | executed singly. | |
|
171 | ||
|
172 | Parameters | |
|
173 | ---------- | |
|
174 | python : str | |
|
175 | Pure, exec'able Python code. | |
|
176 | ||
|
177 | Returns | |
|
178 | ------- | |
|
179 | commands : list of str | |
|
180 | Separate commands that can be exec'ed independently. | |
|
181 | """ | |
|
182 | ||
|
183 | import compiler | |
|
184 | ||
|
185 | # compiler.parse treats trailing spaces after a newline as a | |
|
186 | # SyntaxError. This is different than codeop.CommandCompiler, which | |
|
187 | # will compile the trailng spaces just fine. We simply strip any | |
|
188 | # trailing whitespace off. Passing a string with trailing whitespace | |
|
189 | # to exec will fail however. There seems to be some inconsistency in | |
|
190 | # how trailing whitespace is handled, but this seems to work. | |
|
191 | python_ori = python # save original in case we bail on error | |
|
192 | python = python.strip() | |
|
193 | ||
|
194 | # The compiler module does not like unicode. We need to convert | |
|
195 | # it encode it: | |
|
196 | if isinstance(python, unicode): | |
|
197 | # Use the utf-8-sig BOM so the compiler detects this a UTF-8 | |
|
198 | # encode string. | |
|
199 | python = '\xef\xbb\xbf' + python.encode('utf-8') | |
|
200 | ||
|
201 | # The compiler module will parse the code into an abstract syntax tree. | |
|
202 | # This has a bug with str("a\nb"), but not str("""a\nb""")!!! | |
|
203 | try: | |
|
204 | ast = compiler.parse(python) | |
|
205 | except: | |
|
206 | return [python_ori] | |
|
207 | ||
|
208 | # Uncomment to help debug the ast tree | |
|
209 | # for n in ast.node: | |
|
210 | # print n.lineno,'->',n | |
|
211 | ||
|
212 | # Each separate command is available by iterating over ast.node. The | |
|
213 | # lineno attribute is the line number (1-indexed) beginning the commands | |
|
214 | # suite. | |
|
215 | # lines ending with ";" yield a Discard Node that doesn't have a lineno | |
|
216 | # attribute. These nodes can and should be discarded. But there are | |
|
217 | # other situations that cause Discard nodes that shouldn't be discarded. | |
|
218 | # We might eventually discover other cases where lineno is None and have | |
|
219 | # to put in a more sophisticated test. | |
|
220 | linenos = [x.lineno-1 for x in ast.node if x.lineno is not None] | |
|
221 | ||
|
222 | # When we finally get the slices, we will need to slice all the way to | |
|
223 | # the end even though we don't have a line number for it. Fortunately, | |
|
224 | # None does the job nicely. | |
|
225 | linenos.append(None) | |
|
226 | ||
|
227 | # Same problem at the other end: sometimes the ast tree has its | |
|
228 | # first complete statement not starting on line 0. In this case | |
|
229 | # we might miss part of it. This fixes ticket 266993. Thanks Gael! | |
|
230 | linenos[0] = 0 | |
|
231 | ||
|
232 | lines = python.splitlines() | |
|
233 | ||
|
234 | # Create a list of atomic commands. | |
|
235 | cmds = [] | |
|
236 | for i, j in zip(linenos[:-1], linenos[1:]): | |
|
237 | cmd = lines[i:j] | |
|
238 | if cmd: | |
|
239 | cmds.append('\n'.join(cmd)+'\n') | |
|
240 | ||
|
241 | return cmds | |
|
242 | ||
|
243 | ||
|
162 | 244 | class InputSplitter(object): |
|
163 | 245 | """An object that can split Python source input in executable blocks. |
|
164 | 246 | |
@@ -431,7 +513,11 b' class InputSplitter(object):' | |||
|
431 | 513 | # Form the new block with the current source input |
|
432 | 514 | blocks.append(self.source_reset()) |
|
433 | 515 | |
|
434 | return blocks | |
|
516 | #return blocks | |
|
517 | # HACK!!! Now that our input is in blocks but guaranteed to be pure | |
|
518 | # python syntax, feed it back a second time through the AST-based | |
|
519 | # splitter, which is more accurate than ours. | |
|
520 | return split_blocks(''.join(blocks)) | |
|
435 | 521 | |
|
436 | 522 | #------------------------------------------------------------------------ |
|
437 | 523 | # Private interface |
@@ -46,6 +46,7 b' from IPython.core.error import TryNext, UsageError' | |||
|
46 | 46 | from IPython.core.extensions import ExtensionManager |
|
47 | 47 | from IPython.core.fakemodule import FakeModule, init_fakemod_dict |
|
48 | 48 | from IPython.core.inputlist import InputList |
|
49 | from IPython.core.inputsplitter import IPythonInputSplitter | |
|
49 | 50 | from IPython.core.logger import Logger |
|
50 | 51 | from IPython.core.magic import Magic |
|
51 | 52 | from IPython.core.payload import PayloadManager |
@@ -154,6 +155,7 b' class InteractiveShell(Configurable, Magic):' | |||
|
154 | 155 | exit_now = CBool(False) |
|
155 | 156 | filename = Str("<ipython console>") |
|
156 | 157 | ipython_dir= Unicode('', config=True) # Set to get_ipython_dir() in __init__ |
|
158 | input_splitter = Instance('IPython.core.inputsplitter.IPythonInputSplitter') | |
|
157 | 159 | logstart = CBool(False, config=True) |
|
158 | 160 | logfile = Str('', config=True) |
|
159 | 161 | logappend = Str('', config=True) |
@@ -212,7 +214,7 b' class InteractiveShell(Configurable, Magic):' | |||
|
212 | 214 | |
|
213 | 215 | def __init__(self, config=None, ipython_dir=None, |
|
214 | 216 | user_ns=None, user_global_ns=None, |
|
215 | custom_exceptions=((),None)): | |
|
217 | custom_exceptions=((), None)): | |
|
216 | 218 | |
|
217 | 219 | # This is where traits with a config_key argument are updated |
|
218 | 220 | # from the values on config. |
@@ -252,7 +254,7 b' class InteractiveShell(Configurable, Magic):' | |||
|
252 | 254 | # pre_config_initialization |
|
253 | 255 | self.init_shadow_hist() |
|
254 | 256 | |
|
255 |
# The next section should contain |
|
|
257 | # The next section should contain everything that was in ipmaker. | |
|
256 | 258 | self.init_logstart() |
|
257 | 259 | |
|
258 | 260 | # The following was in post_config_initialization |
@@ -386,6 +388,10 b' class InteractiveShell(Configurable, Magic):' | |||
|
386 | 388 | # Indentation management |
|
387 | 389 | self.indent_current_nsp = 0 |
|
388 | 390 | |
|
391 | # Input splitter, to split entire cells of input into either individual | |
|
392 | # interactive statements or whole blocks. | |
|
393 | self.input_splitter = IPythonInputSplitter() | |
|
394 | ||
|
389 | 395 | def init_encoding(self): |
|
390 | 396 | # Get system encoding at startup time. Certain terminals (like Emacs |
|
391 | 397 | # under Win32 have it set to None, and we need to have a known valid |
@@ -2061,6 +2067,46 b' class InteractiveShell(Configurable, Magic):' | |||
|
2061 | 2067 | self.showtraceback() |
|
2062 | 2068 | warn('Unknown failure executing file: <%s>' % fname) |
|
2063 | 2069 | |
|
2070 | def run_cell(self, cell): | |
|
2071 | """Run the contents of an entire multiline 'cell' of code. | |
|
2072 | ||
|
2073 | The cell is split into separate blocks which can be executed | |
|
2074 | individually. Then, based on how many blocks there are, they are | |
|
2075 | executed as follows: | |
|
2076 | ||
|
2077 | - A single block: 'single' mode. | |
|
2078 | ||
|
2079 | If there's more than one block, it depends: | |
|
2080 | ||
|
2081 | - if the last one is a single line long, run all but the last in | |
|
2082 | 'exec' mode and the very last one in 'single' mode. This makes it | |
|
2083 | easy to type simple expressions at the end to see computed values. | |
|
2084 | - otherwise (last one is also multiline), run all in 'exec' mode | |
|
2085 | ||
|
2086 | When code is executed in 'single' mode, :func:`sys.displayhook` fires, | |
|
2087 | results are displayed and output prompts are computed. In 'exec' mode, | |
|
2088 | no results are displayed unless :func:`print` is called explicitly; | |
|
2089 | this mode is more akin to running a script. | |
|
2090 | ||
|
2091 | Parameters | |
|
2092 | ---------- | |
|
2093 | cell : str | |
|
2094 | A single or multiline string. | |
|
2095 | """ | |
|
2096 | blocks = self.input_splitter.split_blocks(cell) | |
|
2097 | if not blocks: | |
|
2098 | return | |
|
2099 | ||
|
2100 | if len(blocks) == 1: | |
|
2101 | self.runlines(blocks[0]) | |
|
2102 | ||
|
2103 | last = blocks[-1] | |
|
2104 | if len(last.splitlines()) < 2: | |
|
2105 | map(self.runcode, blocks[:-1]) | |
|
2106 | self.runlines(last) | |
|
2107 | else: | |
|
2108 | map(self.runcode, blocks) | |
|
2109 | ||
|
2064 | 2110 | def runlines(self, lines, clean=False): |
|
2065 | 2111 | """Run a string of one or more lines of source. |
|
2066 | 2112 | |
@@ -2166,7 +2212,7 b' class InteractiveShell(Configurable, Magic):' | |||
|
2166 | 2212 | else: |
|
2167 | 2213 | return None |
|
2168 | 2214 | |
|
2169 | def runcode(self,code_obj): | |
|
2215 | def runcode(self, code_obj): | |
|
2170 | 2216 | """Execute a code object. |
|
2171 | 2217 | |
|
2172 | 2218 | When an exception occurs, self.showtraceback() is called to display a |
@@ -278,8 +278,8 b' class InputSplitterTestCase(unittest.TestCase):' | |||
|
278 | 278 | [['x=1'], |
|
279 | 279 | ['y=2']], |
|
280 | 280 | |
|
281 |
[['x=1' |
|
|
282 |
|
|
|
281 | [['x=1', | |
|
282 | '# a comment'], | |
|
283 | 283 | ['y=11']], |
|
284 | 284 | |
|
285 | 285 | [['if 1:', |
@@ -322,11 +322,11 b' class InputSplitterTestCase(unittest.TestCase):' | |||
|
322 | 322 | # Block splitting with invalid syntax |
|
323 | 323 | all_blocks = [ [['a syntax error']], |
|
324 | 324 | |
|
325 |
[['x=1' |
|
|
326 |
|
|
|
325 | [['x=1', | |
|
326 | 'another syntax error']], | |
|
327 | 327 | |
|
328 | 328 | [['for i in range(10):' |
|
329 | ' an error']], | |
|
329 | ' yet another error']], | |
|
330 | 330 | |
|
331 | 331 | ] |
|
332 | 332 | for block_lines in all_blocks: |
@@ -179,7 +179,12 b' class Kernel(Configurable):' | |||
|
179 | 179 | else: |
|
180 | 180 | # FIXME: runlines calls the exception handler itself. |
|
181 | 181 | shell._reply_content = None |
|
182 | shell.runlines(code) | |
|
182 | ||
|
183 | # Experimental: cell mode! Test more before turning into | |
|
184 | # default and removing the hacks around runlines. | |
|
185 | shell.run_cell(code) | |
|
186 | # For now leave this here until we're sure we can stop using it | |
|
187 | #shell.runlines(code) | |
|
183 | 188 | except: |
|
184 | 189 | status = u'error' |
|
185 | 190 | # FIXME: this code right now isn't being used yet by default, |
@@ -26,12 +26,12 b' from IPython.core.interactiveshell import (' | |||
|
26 | 26 | ) |
|
27 | 27 | from IPython.core.displayhook import DisplayHook |
|
28 | 28 | from IPython.core.macro import Macro |
|
29 | from IPython.core.payloadpage import install_payload_page | |
|
29 | 30 | from IPython.utils.path import get_py_filename |
|
30 | 31 | from IPython.utils.text import StringTypes |
|
31 | 32 | from IPython.utils.traitlets import Instance, Type, Dict |
|
32 | 33 | from IPython.utils.warn import warn |
|
33 | 34 | from IPython.zmq.session import extract_header |
|
34 | from IPython.core.payloadpage import install_payload_page | |
|
35 | 35 | from session import Session |
|
36 | 36 | |
|
37 | 37 | #----------------------------------------------------------------------------- |
General Comments 0
You need to be logged in to leave comments.
Login now