##// END OF EJS Templates
Remove unused _full_dedent attribute
Thomas Kluyver -
Show More
@@ -1,743 +1,739 b''
1 """Input handling and transformation machinery.
1 """Input handling and transformation machinery.
2
2
3 The first class in this module, :class:`InputSplitter`, is designed to tell when
3 The first class in this module, :class:`InputSplitter`, is designed to tell when
4 input from a line-oriented frontend is complete and should be executed, and when
4 input from a line-oriented frontend is complete and should be executed, and when
5 the user should be prompted for another line of code instead. The name 'input
5 the user should be prompted for another line of code instead. The name 'input
6 splitter' is largely for historical reasons.
6 splitter' is largely for historical reasons.
7
7
8 A companion, :class:`IPythonInputSplitter`, provides the same functionality but
8 A companion, :class:`IPythonInputSplitter`, provides the same functionality but
9 with full support for the extended IPython syntax (magics, system calls, etc).
9 with full support for the extended IPython syntax (magics, system calls, etc).
10 The code to actually do these transformations is in :mod:`IPython.core.inputtransformer`.
10 The code to actually do these transformations is in :mod:`IPython.core.inputtransformer`.
11 :class:`IPythonInputSplitter` feeds the raw code to the transformers in order
11 :class:`IPythonInputSplitter` feeds the raw code to the transformers in order
12 and stores the results.
12 and stores the results.
13
13
14 For more details, see the class docstrings below.
14 For more details, see the class docstrings below.
15 """
15 """
16
16
17 # Copyright (c) IPython Development Team.
17 # Copyright (c) IPython Development Team.
18 # Distributed under the terms of the Modified BSD License.
18 # Distributed under the terms of the Modified BSD License.
19 import ast
19 import ast
20 import codeop
20 import codeop
21 import io
21 import io
22 import re
22 import re
23 import sys
23 import sys
24 import tokenize
24 import tokenize
25 import warnings
25 import warnings
26
26
27 from IPython.utils.py3compat import cast_unicode
27 from IPython.utils.py3compat import cast_unicode
28 from IPython.core.inputtransformer import (leading_indent,
28 from IPython.core.inputtransformer import (leading_indent,
29 classic_prompt,
29 classic_prompt,
30 ipy_prompt,
30 ipy_prompt,
31 cellmagic,
31 cellmagic,
32 assemble_logical_lines,
32 assemble_logical_lines,
33 help_end,
33 help_end,
34 escaped_commands,
34 escaped_commands,
35 assign_from_magic,
35 assign_from_magic,
36 assign_from_system,
36 assign_from_system,
37 assemble_python_lines,
37 assemble_python_lines,
38 )
38 )
39
39
40 # These are available in this module for backwards compatibility.
40 # These are available in this module for backwards compatibility.
41 from IPython.core.inputtransformer import (ESC_SHELL, ESC_SH_CAP, ESC_HELP,
41 from IPython.core.inputtransformer import (ESC_SHELL, ESC_SH_CAP, ESC_HELP,
42 ESC_HELP2, ESC_MAGIC, ESC_MAGIC2,
42 ESC_HELP2, ESC_MAGIC, ESC_MAGIC2,
43 ESC_QUOTE, ESC_QUOTE2, ESC_PAREN, ESC_SEQUENCES)
43 ESC_QUOTE, ESC_QUOTE2, ESC_PAREN, ESC_SEQUENCES)
44
44
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46 # Utilities
46 # Utilities
47 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
48
48
49 # FIXME: These are general-purpose utilities that later can be moved to the
49 # FIXME: These are general-purpose utilities that later can be moved to the
50 # general ward. Kept here for now because we're being very strict about test
50 # general ward. Kept here for now because we're being very strict about test
51 # coverage with this code, and this lets us ensure that we keep 100% coverage
51 # coverage with this code, and this lets us ensure that we keep 100% coverage
52 # while developing.
52 # while developing.
53
53
54 # compiled regexps for autoindent management
54 # compiled regexps for autoindent management
55 dedent_re = re.compile('|'.join([
55 dedent_re = re.compile('|'.join([
56 r'^\s+raise(\s.*)?$', # raise statement (+ space + other stuff, maybe)
56 r'^\s+raise(\s.*)?$', # raise statement (+ space + other stuff, maybe)
57 r'^\s+raise\([^\)]*\).*$', # wacky raise with immediate open paren
57 r'^\s+raise\([^\)]*\).*$', # wacky raise with immediate open paren
58 r'^\s+return(\s.*)?$', # normal return (+ space + other stuff, maybe)
58 r'^\s+return(\s.*)?$', # normal return (+ space + other stuff, maybe)
59 r'^\s+return\([^\)]*\).*$', # wacky return with immediate open paren
59 r'^\s+return\([^\)]*\).*$', # wacky return with immediate open paren
60 r'^\s+pass\s*$', # pass (optionally followed by trailing spaces)
60 r'^\s+pass\s*$', # pass (optionally followed by trailing spaces)
61 r'^\s+break\s*$', # break (optionally followed by trailing spaces)
61 r'^\s+break\s*$', # break (optionally followed by trailing spaces)
62 r'^\s+continue\s*$', # continue (optionally followed by trailing spaces)
62 r'^\s+continue\s*$', # continue (optionally followed by trailing spaces)
63 ]))
63 ]))
64 ini_spaces_re = re.compile(r'^([ \t\r\f\v]+)')
64 ini_spaces_re = re.compile(r'^([ \t\r\f\v]+)')
65
65
66 # regexp to match pure comment lines so we don't accidentally insert 'if 1:'
66 # regexp to match pure comment lines so we don't accidentally insert 'if 1:'
67 # before pure comments
67 # before pure comments
68 comment_line_re = re.compile('^\s*\#')
68 comment_line_re = re.compile('^\s*\#')
69
69
70
70
71 def num_ini_spaces(s):
71 def num_ini_spaces(s):
72 """Return the number of initial spaces in a string.
72 """Return the number of initial spaces in a string.
73
73
74 Note that tabs are counted as a single space. For now, we do *not* support
74 Note that tabs are counted as a single space. For now, we do *not* support
75 mixing of tabs and spaces in the user's input.
75 mixing of tabs and spaces in the user's input.
76
76
77 Parameters
77 Parameters
78 ----------
78 ----------
79 s : string
79 s : string
80
80
81 Returns
81 Returns
82 -------
82 -------
83 n : int
83 n : int
84 """
84 """
85
85
86 ini_spaces = ini_spaces_re.match(s)
86 ini_spaces = ini_spaces_re.match(s)
87 if ini_spaces:
87 if ini_spaces:
88 return ini_spaces.end()
88 return ini_spaces.end()
89 else:
89 else:
90 return 0
90 return 0
91
91
92 # Fake token types for partial_tokenize:
92 # Fake token types for partial_tokenize:
93 INCOMPLETE_STRING = tokenize.N_TOKENS
93 INCOMPLETE_STRING = tokenize.N_TOKENS
94 IN_MULTILINE_STATEMENT = tokenize.N_TOKENS + 1
94 IN_MULTILINE_STATEMENT = tokenize.N_TOKENS + 1
95
95
96 # The 2 classes below have the same API as TokenInfo, but don't try to look up
96 # The 2 classes below have the same API as TokenInfo, but don't try to look up
97 # a token type name that they won't find.
97 # a token type name that they won't find.
98 class IncompleteString:
98 class IncompleteString:
99 type = exact_type = INCOMPLETE_STRING
99 type = exact_type = INCOMPLETE_STRING
100 def __init__(self, s, start, end, line):
100 def __init__(self, s, start, end, line):
101 self.s = s
101 self.s = s
102 self.start = start
102 self.start = start
103 self.end = end
103 self.end = end
104 self.line = line
104 self.line = line
105
105
106 class InMultilineStatement:
106 class InMultilineStatement:
107 type = exact_type = IN_MULTILINE_STATEMENT
107 type = exact_type = IN_MULTILINE_STATEMENT
108 def __init__(self, pos, line):
108 def __init__(self, pos, line):
109 self.s = ''
109 self.s = ''
110 self.start = self.end = pos
110 self.start = self.end = pos
111 self.line = line
111 self.line = line
112
112
113 def partial_tokens(s):
113 def partial_tokens(s):
114 """Iterate over tokens from a possibly-incomplete string of code.
114 """Iterate over tokens from a possibly-incomplete string of code.
115
115
116 This adds two special token types: INCOMPLETE_STRING and
116 This adds two special token types: INCOMPLETE_STRING and
117 IN_MULTILINE_STATEMENT. These can only occur as the last token yielded, and
117 IN_MULTILINE_STATEMENT. These can only occur as the last token yielded, and
118 represent the two main ways for code to be incomplete.
118 represent the two main ways for code to be incomplete.
119 """
119 """
120 readline = io.StringIO(s).readline
120 readline = io.StringIO(s).readline
121 token = tokenize.TokenInfo(tokenize.NEWLINE, '', (1, 0), (1, 0), '')
121 token = tokenize.TokenInfo(tokenize.NEWLINE, '', (1, 0), (1, 0), '')
122 try:
122 try:
123 for token in tokenize.generate_tokens(readline):
123 for token in tokenize.generate_tokens(readline):
124 yield token
124 yield token
125 except tokenize.TokenError as e:
125 except tokenize.TokenError as e:
126 # catch EOF error
126 # catch EOF error
127 lines = s.splitlines(keepends=True)
127 lines = s.splitlines(keepends=True)
128 end = len(lines), len(lines[-1])
128 end = len(lines), len(lines[-1])
129 if 'multi-line string' in e.args[0]:
129 if 'multi-line string' in e.args[0]:
130 l, c = start = token.end
130 l, c = start = token.end
131 s = lines[l-1][c:] + ''.join(lines[l:])
131 s = lines[l-1][c:] + ''.join(lines[l:])
132 yield IncompleteString(s, start, end, lines[-1])
132 yield IncompleteString(s, start, end, lines[-1])
133 elif 'multi-line statement' in e.args[0]:
133 elif 'multi-line statement' in e.args[0]:
134 yield InMultilineStatement(end, lines[-1])
134 yield InMultilineStatement(end, lines[-1])
135 else:
135 else:
136 raise
136 raise
137
137
138 def find_next_indent(code):
138 def find_next_indent(code):
139 """Find the number of spaces for the next line of indentation"""
139 """Find the number of spaces for the next line of indentation"""
140 tokens = list(partial_tokens(code))
140 tokens = list(partial_tokens(code))
141 if tokens[-1].type == tokenize.ENDMARKER:
141 if tokens[-1].type == tokenize.ENDMARKER:
142 tokens.pop()
142 tokens.pop()
143 if not tokens:
143 if not tokens:
144 return 0
144 return 0
145 while (tokens[-1].type in {tokenize.DEDENT, tokenize.NEWLINE, tokenize.COMMENT}):
145 while (tokens[-1].type in {tokenize.DEDENT, tokenize.NEWLINE, tokenize.COMMENT}):
146 tokens.pop()
146 tokens.pop()
147
147
148 if tokens[-1].type == INCOMPLETE_STRING:
148 if tokens[-1].type == INCOMPLETE_STRING:
149 # Inside a multiline string
149 # Inside a multiline string
150 return 0
150 return 0
151
151
152 # Find the indents used before
152 # Find the indents used before
153 prev_indents = [0]
153 prev_indents = [0]
154 def _add_indent(n):
154 def _add_indent(n):
155 if n != prev_indents[-1]:
155 if n != prev_indents[-1]:
156 prev_indents.append(n)
156 prev_indents.append(n)
157
157
158 tokiter = iter(tokens)
158 tokiter = iter(tokens)
159 for tok in tokiter:
159 for tok in tokiter:
160 if tok.type in {tokenize.INDENT, tokenize.DEDENT}:
160 if tok.type in {tokenize.INDENT, tokenize.DEDENT}:
161 _add_indent(tok.end[1])
161 _add_indent(tok.end[1])
162 elif (tok.type == tokenize.NL):
162 elif (tok.type == tokenize.NL):
163 try:
163 try:
164 _add_indent(next(tokiter).start[1])
164 _add_indent(next(tokiter).start[1])
165 except StopIteration:
165 except StopIteration:
166 break
166 break
167
167
168 last_indent = prev_indents.pop()
168 last_indent = prev_indents.pop()
169
169
170 # If we've just opened a multiline statement (e.g. 'a = ['), indent more
170 # If we've just opened a multiline statement (e.g. 'a = ['), indent more
171 if tokens[-1].type == IN_MULTILINE_STATEMENT:
171 if tokens[-1].type == IN_MULTILINE_STATEMENT:
172 if tokens[-2].exact_type in {tokenize.LPAR, tokenize.LSQB, tokenize.LBRACE}:
172 if tokens[-2].exact_type in {tokenize.LPAR, tokenize.LSQB, tokenize.LBRACE}:
173 return last_indent + 4
173 return last_indent + 4
174 return last_indent
174 return last_indent
175
175
176 if tokens[-1].exact_type == tokenize.COLON:
176 if tokens[-1].exact_type == tokenize.COLON:
177 # Line ends with colon - indent
177 # Line ends with colon - indent
178 return last_indent + 4
178 return last_indent + 4
179
179
180 if last_indent:
180 if last_indent:
181 # Examine the last line for dedent cues - statements like return or
181 # Examine the last line for dedent cues - statements like return or
182 # raise which normally end a block of code.
182 # raise which normally end a block of code.
183 last_line_starts = 0
183 last_line_starts = 0
184 for i, tok in enumerate(tokens):
184 for i, tok in enumerate(tokens):
185 if tok.type == tokenize.NEWLINE:
185 if tok.type == tokenize.NEWLINE:
186 last_line_starts = i + 1
186 last_line_starts = i + 1
187
187
188 last_line_tokens = tokens[last_line_starts:]
188 last_line_tokens = tokens[last_line_starts:]
189 names = [t.string for t in last_line_tokens if t.type == tokenize.NAME]
189 names = [t.string for t in last_line_tokens if t.type == tokenize.NAME]
190 if names and names[0] in {'raise', 'return', 'pass', 'break', 'continue'}:
190 if names and names[0] in {'raise', 'return', 'pass', 'break', 'continue'}:
191 # Find the most recent indentation less than the current level
191 # Find the most recent indentation less than the current level
192 for indent in reversed(prev_indents):
192 for indent in reversed(prev_indents):
193 if indent < last_indent:
193 if indent < last_indent:
194 return indent
194 return indent
195
195
196 return last_indent
196 return last_indent
197
197
198
198
199 def last_blank(src):
199 def last_blank(src):
200 """Determine if the input source ends in a blank.
200 """Determine if the input source ends in a blank.
201
201
202 A blank is either a newline or a line consisting of whitespace.
202 A blank is either a newline or a line consisting of whitespace.
203
203
204 Parameters
204 Parameters
205 ----------
205 ----------
206 src : string
206 src : string
207 A single or multiline string.
207 A single or multiline string.
208 """
208 """
209 if not src: return False
209 if not src: return False
210 ll = src.splitlines()[-1]
210 ll = src.splitlines()[-1]
211 return (ll == '') or ll.isspace()
211 return (ll == '') or ll.isspace()
212
212
213
213
214 last_two_blanks_re = re.compile(r'\n\s*\n\s*$', re.MULTILINE)
214 last_two_blanks_re = re.compile(r'\n\s*\n\s*$', re.MULTILINE)
215 last_two_blanks_re2 = re.compile(r'.+\n\s*\n\s+$', re.MULTILINE)
215 last_two_blanks_re2 = re.compile(r'.+\n\s*\n\s+$', re.MULTILINE)
216
216
217 def last_two_blanks(src):
217 def last_two_blanks(src):
218 """Determine if the input source ends in two blanks.
218 """Determine if the input source ends in two blanks.
219
219
220 A blank is either a newline or a line consisting of whitespace.
220 A blank is either a newline or a line consisting of whitespace.
221
221
222 Parameters
222 Parameters
223 ----------
223 ----------
224 src : string
224 src : string
225 A single or multiline string.
225 A single or multiline string.
226 """
226 """
227 if not src: return False
227 if not src: return False
228 # The logic here is tricky: I couldn't get a regexp to work and pass all
228 # The logic here is tricky: I couldn't get a regexp to work and pass all
229 # the tests, so I took a different approach: split the source by lines,
229 # the tests, so I took a different approach: split the source by lines,
230 # grab the last two and prepend '###\n' as a stand-in for whatever was in
230 # grab the last two and prepend '###\n' as a stand-in for whatever was in
231 # the body before the last two lines. Then, with that structure, it's
231 # the body before the last two lines. Then, with that structure, it's
232 # possible to analyze with two regexps. Not the most elegant solution, but
232 # possible to analyze with two regexps. Not the most elegant solution, but
233 # it works. If anyone tries to change this logic, make sure to validate
233 # it works. If anyone tries to change this logic, make sure to validate
234 # the whole test suite first!
234 # the whole test suite first!
235 new_src = '\n'.join(['###\n'] + src.splitlines()[-2:])
235 new_src = '\n'.join(['###\n'] + src.splitlines()[-2:])
236 return (bool(last_two_blanks_re.match(new_src)) or
236 return (bool(last_two_blanks_re.match(new_src)) or
237 bool(last_two_blanks_re2.match(new_src)) )
237 bool(last_two_blanks_re2.match(new_src)) )
238
238
239
239
240 def remove_comments(src):
240 def remove_comments(src):
241 """Remove all comments from input source.
241 """Remove all comments from input source.
242
242
243 Note: comments are NOT recognized inside of strings!
243 Note: comments are NOT recognized inside of strings!
244
244
245 Parameters
245 Parameters
246 ----------
246 ----------
247 src : string
247 src : string
248 A single or multiline input string.
248 A single or multiline input string.
249
249
250 Returns
250 Returns
251 -------
251 -------
252 String with all Python comments removed.
252 String with all Python comments removed.
253 """
253 """
254
254
255 return re.sub('#.*', '', src)
255 return re.sub('#.*', '', src)
256
256
257
257
258 def get_input_encoding():
258 def get_input_encoding():
259 """Return the default standard input encoding.
259 """Return the default standard input encoding.
260
260
261 If sys.stdin has no encoding, 'ascii' is returned."""
261 If sys.stdin has no encoding, 'ascii' is returned."""
262 # There are strange environments for which sys.stdin.encoding is None. We
262 # There are strange environments for which sys.stdin.encoding is None. We
263 # ensure that a valid encoding is returned.
263 # ensure that a valid encoding is returned.
264 encoding = getattr(sys.stdin, 'encoding', None)
264 encoding = getattr(sys.stdin, 'encoding', None)
265 if encoding is None:
265 if encoding is None:
266 encoding = 'ascii'
266 encoding = 'ascii'
267 return encoding
267 return encoding
268
268
269 #-----------------------------------------------------------------------------
269 #-----------------------------------------------------------------------------
270 # Classes and functions for normal Python syntax handling
270 # Classes and functions for normal Python syntax handling
271 #-----------------------------------------------------------------------------
271 #-----------------------------------------------------------------------------
272
272
273 class InputSplitter(object):
273 class InputSplitter(object):
274 r"""An object that can accumulate lines of Python source before execution.
274 r"""An object that can accumulate lines of Python source before execution.
275
275
276 This object is designed to be fed python source line-by-line, using
276 This object is designed to be fed python source line-by-line, using
277 :meth:`push`. It will return on each push whether the currently pushed
277 :meth:`push`. It will return on each push whether the currently pushed
278 code could be executed already. In addition, it provides a method called
278 code could be executed already. In addition, it provides a method called
279 :meth:`push_accepts_more` that can be used to query whether more input
279 :meth:`push_accepts_more` that can be used to query whether more input
280 can be pushed into a single interactive block.
280 can be pushed into a single interactive block.
281
281
282 This is a simple example of how an interactive terminal-based client can use
282 This is a simple example of how an interactive terminal-based client can use
283 this tool::
283 this tool::
284
284
285 isp = InputSplitter()
285 isp = InputSplitter()
286 while isp.push_accepts_more():
286 while isp.push_accepts_more():
287 indent = ' '*isp.indent_spaces
287 indent = ' '*isp.indent_spaces
288 prompt = '>>> ' + indent
288 prompt = '>>> ' + indent
289 line = indent + raw_input(prompt)
289 line = indent + raw_input(prompt)
290 isp.push(line)
290 isp.push(line)
291 print 'Input source was:\n', isp.source_reset(),
291 print 'Input source was:\n', isp.source_reset(),
292 """
292 """
293 # Number of spaces of indentation computed from input that has been pushed
293 # Number of spaces of indentation computed from input that has been pushed
294 # so far. This is the attributes callers should query to get the current
294 # so far. This is the attributes callers should query to get the current
295 # indentation level, in order to provide auto-indent facilities.
295 # indentation level, in order to provide auto-indent facilities.
296 indent_spaces = 0
296 indent_spaces = 0
297 # String, indicating the default input encoding. It is computed by default
297 # String, indicating the default input encoding. It is computed by default
298 # at initialization time via get_input_encoding(), but it can be reset by a
298 # at initialization time via get_input_encoding(), but it can be reset by a
299 # client with specific knowledge of the encoding.
299 # client with specific knowledge of the encoding.
300 encoding = ''
300 encoding = ''
301 # String where the current full source input is stored, properly encoded.
301 # String where the current full source input is stored, properly encoded.
302 # Reading this attribute is the normal way of querying the currently pushed
302 # Reading this attribute is the normal way of querying the currently pushed
303 # source code, that has been properly encoded.
303 # source code, that has been properly encoded.
304 source = ''
304 source = ''
305 # Code object corresponding to the current source. It is automatically
305 # Code object corresponding to the current source. It is automatically
306 # synced to the source, so it can be queried at any time to obtain the code
306 # synced to the source, so it can be queried at any time to obtain the code
307 # object; it will be None if the source doesn't compile to valid Python.
307 # object; it will be None if the source doesn't compile to valid Python.
308 code = None
308 code = None
309
309
310 # Private attributes
310 # Private attributes
311
311
312 # List with lines of input accumulated so far
312 # List with lines of input accumulated so far
313 _buffer = None
313 _buffer = None
314 # Command compiler
314 # Command compiler
315 _compile = None
315 _compile = None
316 # Mark when input has changed indentation all the way back to flush-left
317 _full_dedent = False
318 # Boolean indicating whether the current block is complete
316 # Boolean indicating whether the current block is complete
319 _is_complete = None
317 _is_complete = None
320 # Boolean indicating whether the current block has an unrecoverable syntax error
318 # Boolean indicating whether the current block has an unrecoverable syntax error
321 _is_invalid = False
319 _is_invalid = False
322
320
323 def __init__(self):
321 def __init__(self):
324 """Create a new InputSplitter instance.
322 """Create a new InputSplitter instance.
325 """
323 """
326 self._buffer = []
324 self._buffer = []
327 self._compile = codeop.CommandCompiler()
325 self._compile = codeop.CommandCompiler()
328 self.encoding = get_input_encoding()
326 self.encoding = get_input_encoding()
329
327
330 def reset(self):
328 def reset(self):
331 """Reset the input buffer and associated state."""
329 """Reset the input buffer and associated state."""
332 self.indent_spaces = 0
330 self.indent_spaces = 0
333 self._buffer[:] = []
331 self._buffer[:] = []
334 self.source = ''
332 self.source = ''
335 self.code = None
333 self.code = None
336 self._is_complete = False
334 self._is_complete = False
337 self._is_invalid = False
335 self._is_invalid = False
338 self._full_dedent = False
339
336
340 def source_reset(self):
337 def source_reset(self):
341 """Return the input source and perform a full reset.
338 """Return the input source and perform a full reset.
342 """
339 """
343 out = self.source
340 out = self.source
344 self.reset()
341 self.reset()
345 return out
342 return out
346
343
347 def check_complete(self, source):
344 def check_complete(self, source):
348 """Return whether a block of code is ready to execute, or should be continued
345 """Return whether a block of code is ready to execute, or should be continued
349
346
350 This is a non-stateful API, and will reset the state of this InputSplitter.
347 This is a non-stateful API, and will reset the state of this InputSplitter.
351
348
352 Parameters
349 Parameters
353 ----------
350 ----------
354 source : string
351 source : string
355 Python input code, which can be multiline.
352 Python input code, which can be multiline.
356
353
357 Returns
354 Returns
358 -------
355 -------
359 status : str
356 status : str
360 One of 'complete', 'incomplete', or 'invalid' if source is not a
357 One of 'complete', 'incomplete', or 'invalid' if source is not a
361 prefix of valid code.
358 prefix of valid code.
362 indent_spaces : int or None
359 indent_spaces : int or None
363 The number of spaces by which to indent the next line of code. If
360 The number of spaces by which to indent the next line of code. If
364 status is not 'incomplete', this is None.
361 status is not 'incomplete', this is None.
365 """
362 """
366 self.reset()
363 self.reset()
367 try:
364 try:
368 self.push(source)
365 self.push(source)
369 except SyntaxError:
366 except SyntaxError:
370 # Transformers in IPythonInputSplitter can raise SyntaxError,
367 # Transformers in IPythonInputSplitter can raise SyntaxError,
371 # which push() will not catch.
368 # which push() will not catch.
372 return 'invalid', None
369 return 'invalid', None
373 else:
370 else:
374 if self._is_invalid:
371 if self._is_invalid:
375 return 'invalid', None
372 return 'invalid', None
376 elif self.push_accepts_more():
373 elif self.push_accepts_more():
377 return 'incomplete', self.indent_spaces
374 return 'incomplete', self.indent_spaces
378 else:
375 else:
379 return 'complete', None
376 return 'complete', None
380 finally:
377 finally:
381 self.reset()
378 self.reset()
382
379
383 def push(self, lines):
380 def push(self, lines):
384 """Push one or more lines of input.
381 """Push one or more lines of input.
385
382
386 This stores the given lines and returns a status code indicating
383 This stores the given lines and returns a status code indicating
387 whether the code forms a complete Python block or not.
384 whether the code forms a complete Python block or not.
388
385
389 Any exceptions generated in compilation are swallowed, but if an
386 Any exceptions generated in compilation are swallowed, but if an
390 exception was produced, the method returns True.
387 exception was produced, the method returns True.
391
388
392 Parameters
389 Parameters
393 ----------
390 ----------
394 lines : string
391 lines : string
395 One or more lines of Python input.
392 One or more lines of Python input.
396
393
397 Returns
394 Returns
398 -------
395 -------
399 is_complete : boolean
396 is_complete : boolean
400 True if the current input source (the result of the current input
397 True if the current input source (the result of the current input
401 plus prior inputs) forms a complete Python execution block. Note that
398 plus prior inputs) forms a complete Python execution block. Note that
402 this value is also stored as a private attribute (``_is_complete``), so it
399 this value is also stored as a private attribute (``_is_complete``), so it
403 can be queried at any time.
400 can be queried at any time.
404 """
401 """
405 self._store(lines)
402 self._store(lines)
406 source = self.source
403 source = self.source
407
404
408 # Before calling _compile(), reset the code object to None so that if an
405 # Before calling _compile(), reset the code object to None so that if an
409 # exception is raised in compilation, we don't mislead by having
406 # exception is raised in compilation, we don't mislead by having
410 # inconsistent code/source attributes.
407 # inconsistent code/source attributes.
411 self.code, self._is_complete = None, None
408 self.code, self._is_complete = None, None
412 self._is_invalid = False
409 self._is_invalid = False
413
410
414 # Honor termination lines properly
411 # Honor termination lines properly
415 if source.endswith('\\\n'):
412 if source.endswith('\\\n'):
416 return False
413 return False
417
414
418 self._update_indent()
415 self._update_indent()
419 try:
416 try:
420 with warnings.catch_warnings():
417 with warnings.catch_warnings():
421 warnings.simplefilter('error', SyntaxWarning)
418 warnings.simplefilter('error', SyntaxWarning)
422 self.code = self._compile(source, symbol="exec")
419 self.code = self._compile(source, symbol="exec")
423 # Invalid syntax can produce any of a number of different errors from
420 # Invalid syntax can produce any of a number of different errors from
424 # inside the compiler, so we have to catch them all. Syntax errors
421 # inside the compiler, so we have to catch them all. Syntax errors
425 # immediately produce a 'ready' block, so the invalid Python can be
422 # immediately produce a 'ready' block, so the invalid Python can be
426 # sent to the kernel for evaluation with possible ipython
423 # sent to the kernel for evaluation with possible ipython
427 # special-syntax conversion.
424 # special-syntax conversion.
428 except (SyntaxError, OverflowError, ValueError, TypeError,
425 except (SyntaxError, OverflowError, ValueError, TypeError,
429 MemoryError, SyntaxWarning):
426 MemoryError, SyntaxWarning):
430 self._is_complete = True
427 self._is_complete = True
431 self._is_invalid = True
428 self._is_invalid = True
432 else:
429 else:
433 # Compilation didn't produce any exceptions (though it may not have
430 # Compilation didn't produce any exceptions (though it may not have
434 # given a complete code object)
431 # given a complete code object)
435 self._is_complete = self.code is not None
432 self._is_complete = self.code is not None
436
433
437 return self._is_complete
434 return self._is_complete
438
435
439 def push_accepts_more(self):
436 def push_accepts_more(self):
440 """Return whether a block of interactive input can accept more input.
437 """Return whether a block of interactive input can accept more input.
441
438
442 This method is meant to be used by line-oriented frontends, who need to
439 This method is meant to be used by line-oriented frontends, who need to
443 guess whether a block is complete or not based solely on prior and
440 guess whether a block is complete or not based solely on prior and
444 current input lines. The InputSplitter considers it has a complete
441 current input lines. The InputSplitter considers it has a complete
445 interactive block and will not accept more input when either:
442 interactive block and will not accept more input when either:
446
443
447 * A SyntaxError is raised
444 * A SyntaxError is raised
448
445
449 * The code is complete and consists of a single line or a single
446 * The code is complete and consists of a single line or a single
450 non-compound statement
447 non-compound statement
451
448
452 * The code is complete and has a blank line at the end
449 * The code is complete and has a blank line at the end
453
450
454 If the current input produces a syntax error, this method immediately
451 If the current input produces a syntax error, this method immediately
455 returns False but does *not* raise the syntax error exception, as
452 returns False but does *not* raise the syntax error exception, as
456 typically clients will want to send invalid syntax to an execution
453 typically clients will want to send invalid syntax to an execution
457 backend which might convert the invalid syntax into valid Python via
454 backend which might convert the invalid syntax into valid Python via
458 one of the dynamic IPython mechanisms.
455 one of the dynamic IPython mechanisms.
459 """
456 """
460
457
461 # With incomplete input, unconditionally accept more
458 # With incomplete input, unconditionally accept more
462 # A syntax error also sets _is_complete to True - see push()
459 # A syntax error also sets _is_complete to True - see push()
463 if not self._is_complete:
460 if not self._is_complete:
464 #print("Not complete") # debug
461 #print("Not complete") # debug
465 return True
462 return True
466
463
467 # The user can make any (complete) input execute by leaving a blank line
464 # The user can make any (complete) input execute by leaving a blank line
468 last_line = self.source.splitlines()[-1]
465 last_line = self.source.splitlines()[-1]
469 if (not last_line) or last_line.isspace():
466 if (not last_line) or last_line.isspace():
470 #print("Blank line") # debug
467 #print("Blank line") # debug
471 return False
468 return False
472
469
473 # If there's just a single line or AST node, and we're flush left, as is
470 # If there's just a single line or AST node, and we're flush left, as is
474 # the case after a simple statement such as 'a=1', we want to execute it
471 # the case after a simple statement such as 'a=1', we want to execute it
475 # straight away.
472 # straight away.
476 if self.indent_spaces==0:
473 if self.indent_spaces==0:
477 if len(self.source.splitlines()) <= 1:
474 if len(self.source.splitlines()) <= 1:
478 return False
475 return False
479
476
480 try:
477 try:
481 code_ast = ast.parse(u''.join(self._buffer))
478 code_ast = ast.parse(u''.join(self._buffer))
482 except Exception:
479 except Exception:
483 #print("Can't parse AST") # debug
480 #print("Can't parse AST") # debug
484 return False
481 return False
485 else:
482 else:
486 if len(code_ast.body) == 1 and \
483 if len(code_ast.body) == 1 and \
487 not hasattr(code_ast.body[0], 'body'):
484 not hasattr(code_ast.body[0], 'body'):
488 #print("Simple statement") # debug
485 #print("Simple statement") # debug
489 return False
486 return False
490
487
491 # General fallback - accept more code
488 # General fallback - accept more code
492 return True
489 return True
493
490
494 def _update_indent(self):
491 def _update_indent(self):
495 # self.source always has a trailing newline
492 # self.source always has a trailing newline
496 self.indent_spaces = find_next_indent(self.source[:-1])
493 self.indent_spaces = find_next_indent(self.source[:-1])
497 self._full_dedent = (self.indent_spaces == 0)
498
494
499 def _store(self, lines, buffer=None, store='source'):
495 def _store(self, lines, buffer=None, store='source'):
500 """Store one or more lines of input.
496 """Store one or more lines of input.
501
497
502 If input lines are not newline-terminated, a newline is automatically
498 If input lines are not newline-terminated, a newline is automatically
503 appended."""
499 appended."""
504
500
505 if buffer is None:
501 if buffer is None:
506 buffer = self._buffer
502 buffer = self._buffer
507
503
508 if lines.endswith('\n'):
504 if lines.endswith('\n'):
509 buffer.append(lines)
505 buffer.append(lines)
510 else:
506 else:
511 buffer.append(lines+'\n')
507 buffer.append(lines+'\n')
512 setattr(self, store, self._set_source(buffer))
508 setattr(self, store, self._set_source(buffer))
513
509
514 def _set_source(self, buffer):
510 def _set_source(self, buffer):
515 return u''.join(buffer)
511 return u''.join(buffer)
516
512
517
513
518 class IPythonInputSplitter(InputSplitter):
514 class IPythonInputSplitter(InputSplitter):
519 """An input splitter that recognizes all of IPython's special syntax."""
515 """An input splitter that recognizes all of IPython's special syntax."""
520
516
521 # String with raw, untransformed input.
517 # String with raw, untransformed input.
522 source_raw = ''
518 source_raw = ''
523
519
524 # Flag to track when a transformer has stored input that it hasn't given
520 # Flag to track when a transformer has stored input that it hasn't given
525 # back yet.
521 # back yet.
526 transformer_accumulating = False
522 transformer_accumulating = False
527
523
528 # Flag to track when assemble_python_lines has stored input that it hasn't
524 # Flag to track when assemble_python_lines has stored input that it hasn't
529 # given back yet.
525 # given back yet.
530 within_python_line = False
526 within_python_line = False
531
527
532 # Private attributes
528 # Private attributes
533
529
534 # List with lines of raw input accumulated so far.
530 # List with lines of raw input accumulated so far.
535 _buffer_raw = None
531 _buffer_raw = None
536
532
537 def __init__(self, line_input_checker=True, physical_line_transforms=None,
533 def __init__(self, line_input_checker=True, physical_line_transforms=None,
538 logical_line_transforms=None, python_line_transforms=None):
534 logical_line_transforms=None, python_line_transforms=None):
539 super(IPythonInputSplitter, self).__init__()
535 super(IPythonInputSplitter, self).__init__()
540 self._buffer_raw = []
536 self._buffer_raw = []
541 self._validate = True
537 self._validate = True
542
538
543 if physical_line_transforms is not None:
539 if physical_line_transforms is not None:
544 self.physical_line_transforms = physical_line_transforms
540 self.physical_line_transforms = physical_line_transforms
545 else:
541 else:
546 self.physical_line_transforms = [
542 self.physical_line_transforms = [
547 leading_indent(),
543 leading_indent(),
548 classic_prompt(),
544 classic_prompt(),
549 ipy_prompt(),
545 ipy_prompt(),
550 cellmagic(end_on_blank_line=line_input_checker),
546 cellmagic(end_on_blank_line=line_input_checker),
551 ]
547 ]
552
548
553 self.assemble_logical_lines = assemble_logical_lines()
549 self.assemble_logical_lines = assemble_logical_lines()
554 if logical_line_transforms is not None:
550 if logical_line_transforms is not None:
555 self.logical_line_transforms = logical_line_transforms
551 self.logical_line_transforms = logical_line_transforms
556 else:
552 else:
557 self.logical_line_transforms = [
553 self.logical_line_transforms = [
558 help_end(),
554 help_end(),
559 escaped_commands(),
555 escaped_commands(),
560 assign_from_magic(),
556 assign_from_magic(),
561 assign_from_system(),
557 assign_from_system(),
562 ]
558 ]
563
559
564 self.assemble_python_lines = assemble_python_lines()
560 self.assemble_python_lines = assemble_python_lines()
565 if python_line_transforms is not None:
561 if python_line_transforms is not None:
566 self.python_line_transforms = python_line_transforms
562 self.python_line_transforms = python_line_transforms
567 else:
563 else:
568 # We don't use any of these at present
564 # We don't use any of these at present
569 self.python_line_transforms = []
565 self.python_line_transforms = []
570
566
571 @property
567 @property
572 def transforms(self):
568 def transforms(self):
573 "Quick access to all transformers."
569 "Quick access to all transformers."
574 return self.physical_line_transforms + \
570 return self.physical_line_transforms + \
575 [self.assemble_logical_lines] + self.logical_line_transforms + \
571 [self.assemble_logical_lines] + self.logical_line_transforms + \
576 [self.assemble_python_lines] + self.python_line_transforms
572 [self.assemble_python_lines] + self.python_line_transforms
577
573
578 @property
574 @property
579 def transforms_in_use(self):
575 def transforms_in_use(self):
580 """Transformers, excluding logical line transformers if we're in a
576 """Transformers, excluding logical line transformers if we're in a
581 Python line."""
577 Python line."""
582 t = self.physical_line_transforms[:]
578 t = self.physical_line_transforms[:]
583 if not self.within_python_line:
579 if not self.within_python_line:
584 t += [self.assemble_logical_lines] + self.logical_line_transforms
580 t += [self.assemble_logical_lines] + self.logical_line_transforms
585 return t + [self.assemble_python_lines] + self.python_line_transforms
581 return t + [self.assemble_python_lines] + self.python_line_transforms
586
582
587 def reset(self):
583 def reset(self):
588 """Reset the input buffer and associated state."""
584 """Reset the input buffer and associated state."""
589 super(IPythonInputSplitter, self).reset()
585 super(IPythonInputSplitter, self).reset()
590 self._buffer_raw[:] = []
586 self._buffer_raw[:] = []
591 self.source_raw = ''
587 self.source_raw = ''
592 self.transformer_accumulating = False
588 self.transformer_accumulating = False
593 self.within_python_line = False
589 self.within_python_line = False
594
590
595 for t in self.transforms:
591 for t in self.transforms:
596 try:
592 try:
597 t.reset()
593 t.reset()
598 except SyntaxError:
594 except SyntaxError:
599 # Nothing that calls reset() expects to handle transformer
595 # Nothing that calls reset() expects to handle transformer
600 # errors
596 # errors
601 pass
597 pass
602
598
603 def flush_transformers(self):
599 def flush_transformers(self):
604 def _flush(transform, outs):
600 def _flush(transform, outs):
605 """yield transformed lines
601 """yield transformed lines
606
602
607 always strings, never None
603 always strings, never None
608
604
609 transform: the current transform
605 transform: the current transform
610 outs: an iterable of previously transformed inputs.
606 outs: an iterable of previously transformed inputs.
611 Each may be multiline, which will be passed
607 Each may be multiline, which will be passed
612 one line at a time to transform.
608 one line at a time to transform.
613 """
609 """
614 for out in outs:
610 for out in outs:
615 for line in out.splitlines():
611 for line in out.splitlines():
616 # push one line at a time
612 # push one line at a time
617 tmp = transform.push(line)
613 tmp = transform.push(line)
618 if tmp is not None:
614 if tmp is not None:
619 yield tmp
615 yield tmp
620
616
621 # reset the transform
617 # reset the transform
622 tmp = transform.reset()
618 tmp = transform.reset()
623 if tmp is not None:
619 if tmp is not None:
624 yield tmp
620 yield tmp
625
621
626 out = []
622 out = []
627 for t in self.transforms_in_use:
623 for t in self.transforms_in_use:
628 out = _flush(t, out)
624 out = _flush(t, out)
629
625
630 out = list(out)
626 out = list(out)
631 if out:
627 if out:
632 self._store('\n'.join(out))
628 self._store('\n'.join(out))
633
629
634 def raw_reset(self):
630 def raw_reset(self):
635 """Return raw input only and perform a full reset.
631 """Return raw input only and perform a full reset.
636 """
632 """
637 out = self.source_raw
633 out = self.source_raw
638 self.reset()
634 self.reset()
639 return out
635 return out
640
636
641 def source_reset(self):
637 def source_reset(self):
642 try:
638 try:
643 self.flush_transformers()
639 self.flush_transformers()
644 return self.source
640 return self.source
645 finally:
641 finally:
646 self.reset()
642 self.reset()
647
643
648 def push_accepts_more(self):
644 def push_accepts_more(self):
649 if self.transformer_accumulating:
645 if self.transformer_accumulating:
650 return True
646 return True
651 else:
647 else:
652 return super(IPythonInputSplitter, self).push_accepts_more()
648 return super(IPythonInputSplitter, self).push_accepts_more()
653
649
654 def transform_cell(self, cell):
650 def transform_cell(self, cell):
655 """Process and translate a cell of input.
651 """Process and translate a cell of input.
656 """
652 """
657 self.reset()
653 self.reset()
658 try:
654 try:
659 self.push(cell)
655 self.push(cell)
660 self.flush_transformers()
656 self.flush_transformers()
661 return self.source
657 return self.source
662 finally:
658 finally:
663 self.reset()
659 self.reset()
664
660
665 def push(self, lines):
661 def push(self, lines):
666 """Push one or more lines of IPython input.
662 """Push one or more lines of IPython input.
667
663
668 This stores the given lines and returns a status code indicating
664 This stores the given lines and returns a status code indicating
669 whether the code forms a complete Python block or not, after processing
665 whether the code forms a complete Python block or not, after processing
670 all input lines for special IPython syntax.
666 all input lines for special IPython syntax.
671
667
672 Any exceptions generated in compilation are swallowed, but if an
668 Any exceptions generated in compilation are swallowed, but if an
673 exception was produced, the method returns True.
669 exception was produced, the method returns True.
674
670
675 Parameters
671 Parameters
676 ----------
672 ----------
677 lines : string
673 lines : string
678 One or more lines of Python input.
674 One or more lines of Python input.
679
675
680 Returns
676 Returns
681 -------
677 -------
682 is_complete : boolean
678 is_complete : boolean
683 True if the current input source (the result of the current input
679 True if the current input source (the result of the current input
684 plus prior inputs) forms a complete Python execution block. Note that
680 plus prior inputs) forms a complete Python execution block. Note that
685 this value is also stored as a private attribute (_is_complete), so it
681 this value is also stored as a private attribute (_is_complete), so it
686 can be queried at any time.
682 can be queried at any time.
687 """
683 """
688
684
689 # We must ensure all input is pure unicode
685 # We must ensure all input is pure unicode
690 lines = cast_unicode(lines, self.encoding)
686 lines = cast_unicode(lines, self.encoding)
691 # ''.splitlines() --> [], but we need to push the empty line to transformers
687 # ''.splitlines() --> [], but we need to push the empty line to transformers
692 lines_list = lines.splitlines()
688 lines_list = lines.splitlines()
693 if not lines_list:
689 if not lines_list:
694 lines_list = ['']
690 lines_list = ['']
695
691
696 # Store raw source before applying any transformations to it. Note
692 # Store raw source before applying any transformations to it. Note
697 # that this must be done *after* the reset() call that would otherwise
693 # that this must be done *after* the reset() call that would otherwise
698 # flush the buffer.
694 # flush the buffer.
699 self._store(lines, self._buffer_raw, 'source_raw')
695 self._store(lines, self._buffer_raw, 'source_raw')
700
696
701 for line in lines_list:
697 for line in lines_list:
702 out = self.push_line(line)
698 out = self.push_line(line)
703
699
704 return out
700 return out
705
701
706 def push_line(self, line):
702 def push_line(self, line):
707 buf = self._buffer
703 buf = self._buffer
708
704
709 def _accumulating(dbg):
705 def _accumulating(dbg):
710 #print(dbg)
706 #print(dbg)
711 self.transformer_accumulating = True
707 self.transformer_accumulating = True
712 return False
708 return False
713
709
714 for transformer in self.physical_line_transforms:
710 for transformer in self.physical_line_transforms:
715 line = transformer.push(line)
711 line = transformer.push(line)
716 if line is None:
712 if line is None:
717 return _accumulating(transformer)
713 return _accumulating(transformer)
718
714
719 if not self.within_python_line:
715 if not self.within_python_line:
720 line = self.assemble_logical_lines.push(line)
716 line = self.assemble_logical_lines.push(line)
721 if line is None:
717 if line is None:
722 return _accumulating('acc logical line')
718 return _accumulating('acc logical line')
723
719
724 for transformer in self.logical_line_transforms:
720 for transformer in self.logical_line_transforms:
725 line = transformer.push(line)
721 line = transformer.push(line)
726 if line is None:
722 if line is None:
727 return _accumulating(transformer)
723 return _accumulating(transformer)
728
724
729 line = self.assemble_python_lines.push(line)
725 line = self.assemble_python_lines.push(line)
730 if line is None:
726 if line is None:
731 self.within_python_line = True
727 self.within_python_line = True
732 return _accumulating('acc python line')
728 return _accumulating('acc python line')
733 else:
729 else:
734 self.within_python_line = False
730 self.within_python_line = False
735
731
736 for transformer in self.python_line_transforms:
732 for transformer in self.python_line_transforms:
737 line = transformer.push(line)
733 line = transformer.push(line)
738 if line is None:
734 if line is None:
739 return _accumulating(transformer)
735 return _accumulating(transformer)
740
736
741 #print("transformers clear") #debug
737 #print("transformers clear") #debug
742 self.transformer_accumulating = False
738 self.transformer_accumulating = False
743 return super(IPythonInputSplitter, self).push(line)
739 return super(IPythonInputSplitter, self).push(line)
General Comments 0
You need to be logged in to leave comments. Login now