##// END OF EJS Templates
Remove unused _find_indent method
Thomas Kluyver -
Show More
@@ -1,787 +1,742 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 if tokens[-1].type in {tokenize.DEDENT, tokenize.NEWLINE, tokenize.COMMENT}:
145 if 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 tokens[-1].type == IN_MULTILINE_STATEMENT:
170 if tokens[-1].type == IN_MULTILINE_STATEMENT:
171 if tokens[-2].exact_type in {tokenize.LPAR, tokenize.LSQB, tokenize.LBRACE}:
171 if tokens[-2].exact_type in {tokenize.LPAR, tokenize.LSQB, tokenize.LBRACE}:
172 return last_indent + 4
172 return last_indent + 4
173 return last_indent
173 return last_indent
174
174
175 if tokens[-1].exact_type == tokenize.COLON:
175 if tokens[-1].exact_type == tokenize.COLON:
176 # Line ends with colon - indent
176 # Line ends with colon - indent
177 return last_indent + 4
177 return last_indent + 4
178
178
179 if last_indent:
179 if last_indent:
180 # Examine the last line for dedent cues - statements like return or
180 # Examine the last line for dedent cues - statements like return or
181 # raise which normally end a block of code.
181 # raise which normally end a block of code.
182 last_line_starts = 0
182 last_line_starts = 0
183 for i, tok in enumerate(tokens):
183 for i, tok in enumerate(tokens):
184 if tok.type == tokenize.NEWLINE:
184 if tok.type == tokenize.NEWLINE:
185 last_line_starts = i + 1
185 last_line_starts = i + 1
186
186
187 last_line_tokens = tokens[last_line_starts:]
187 last_line_tokens = tokens[last_line_starts:]
188 names = [t.string for t in last_line_tokens if t.type == tokenize.NAME]
188 names = [t.string for t in last_line_tokens if t.type == tokenize.NAME]
189 if names and names[0] in {'raise', 'return', 'pass', 'break', 'continue'}:
189 if names and names[0] in {'raise', 'return', 'pass', 'break', 'continue'}:
190 # Find the most recent indentation less than the current level
190 # Find the most recent indentation less than the current level
191 for indent in reversed(prev_indents):
191 for indent in reversed(prev_indents):
192 if indent < last_indent:
192 if indent < last_indent:
193 return indent
193 return indent
194
194
195 return last_indent
195 return last_indent
196
196
197
197
198 def last_blank(src):
198 def last_blank(src):
199 """Determine if the input source ends in a blank.
199 """Determine if the input source ends in a blank.
200
200
201 A blank is either a newline or a line consisting of whitespace.
201 A blank is either a newline or a line consisting of whitespace.
202
202
203 Parameters
203 Parameters
204 ----------
204 ----------
205 src : string
205 src : string
206 A single or multiline string.
206 A single or multiline string.
207 """
207 """
208 if not src: return False
208 if not src: return False
209 ll = src.splitlines()[-1]
209 ll = src.splitlines()[-1]
210 return (ll == '') or ll.isspace()
210 return (ll == '') or ll.isspace()
211
211
212
212
213 last_two_blanks_re = re.compile(r'\n\s*\n\s*$', re.MULTILINE)
213 last_two_blanks_re = re.compile(r'\n\s*\n\s*$', re.MULTILINE)
214 last_two_blanks_re2 = re.compile(r'.+\n\s*\n\s+$', re.MULTILINE)
214 last_two_blanks_re2 = re.compile(r'.+\n\s*\n\s+$', re.MULTILINE)
215
215
216 def last_two_blanks(src):
216 def last_two_blanks(src):
217 """Determine if the input source ends in two blanks.
217 """Determine if the input source ends in two blanks.
218
218
219 A blank is either a newline or a line consisting of whitespace.
219 A blank is either a newline or a line consisting of whitespace.
220
220
221 Parameters
221 Parameters
222 ----------
222 ----------
223 src : string
223 src : string
224 A single or multiline string.
224 A single or multiline string.
225 """
225 """
226 if not src: return False
226 if not src: return False
227 # The logic here is tricky: I couldn't get a regexp to work and pass all
227 # The logic here is tricky: I couldn't get a regexp to work and pass all
228 # the tests, so I took a different approach: split the source by lines,
228 # the tests, so I took a different approach: split the source by lines,
229 # grab the last two and prepend '###\n' as a stand-in for whatever was in
229 # grab the last two and prepend '###\n' as a stand-in for whatever was in
230 # the body before the last two lines. Then, with that structure, it's
230 # the body before the last two lines. Then, with that structure, it's
231 # possible to analyze with two regexps. Not the most elegant solution, but
231 # possible to analyze with two regexps. Not the most elegant solution, but
232 # it works. If anyone tries to change this logic, make sure to validate
232 # it works. If anyone tries to change this logic, make sure to validate
233 # the whole test suite first!
233 # the whole test suite first!
234 new_src = '\n'.join(['###\n'] + src.splitlines()[-2:])
234 new_src = '\n'.join(['###\n'] + src.splitlines()[-2:])
235 return (bool(last_two_blanks_re.match(new_src)) or
235 return (bool(last_two_blanks_re.match(new_src)) or
236 bool(last_two_blanks_re2.match(new_src)) )
236 bool(last_two_blanks_re2.match(new_src)) )
237
237
238
238
239 def remove_comments(src):
239 def remove_comments(src):
240 """Remove all comments from input source.
240 """Remove all comments from input source.
241
241
242 Note: comments are NOT recognized inside of strings!
242 Note: comments are NOT recognized inside of strings!
243
243
244 Parameters
244 Parameters
245 ----------
245 ----------
246 src : string
246 src : string
247 A single or multiline input string.
247 A single or multiline input string.
248
248
249 Returns
249 Returns
250 -------
250 -------
251 String with all Python comments removed.
251 String with all Python comments removed.
252 """
252 """
253
253
254 return re.sub('#.*', '', src)
254 return re.sub('#.*', '', src)
255
255
256
256
257 def get_input_encoding():
257 def get_input_encoding():
258 """Return the default standard input encoding.
258 """Return the default standard input encoding.
259
259
260 If sys.stdin has no encoding, 'ascii' is returned."""
260 If sys.stdin has no encoding, 'ascii' is returned."""
261 # There are strange environments for which sys.stdin.encoding is None. We
261 # There are strange environments for which sys.stdin.encoding is None. We
262 # ensure that a valid encoding is returned.
262 # ensure that a valid encoding is returned.
263 encoding = getattr(sys.stdin, 'encoding', None)
263 encoding = getattr(sys.stdin, 'encoding', None)
264 if encoding is None:
264 if encoding is None:
265 encoding = 'ascii'
265 encoding = 'ascii'
266 return encoding
266 return encoding
267
267
268 #-----------------------------------------------------------------------------
268 #-----------------------------------------------------------------------------
269 # Classes and functions for normal Python syntax handling
269 # Classes and functions for normal Python syntax handling
270 #-----------------------------------------------------------------------------
270 #-----------------------------------------------------------------------------
271
271
272 class InputSplitter(object):
272 class InputSplitter(object):
273 r"""An object that can accumulate lines of Python source before execution.
273 r"""An object that can accumulate lines of Python source before execution.
274
274
275 This object is designed to be fed python source line-by-line, using
275 This object is designed to be fed python source line-by-line, using
276 :meth:`push`. It will return on each push whether the currently pushed
276 :meth:`push`. It will return on each push whether the currently pushed
277 code could be executed already. In addition, it provides a method called
277 code could be executed already. In addition, it provides a method called
278 :meth:`push_accepts_more` that can be used to query whether more input
278 :meth:`push_accepts_more` that can be used to query whether more input
279 can be pushed into a single interactive block.
279 can be pushed into a single interactive block.
280
280
281 This is a simple example of how an interactive terminal-based client can use
281 This is a simple example of how an interactive terminal-based client can use
282 this tool::
282 this tool::
283
283
284 isp = InputSplitter()
284 isp = InputSplitter()
285 while isp.push_accepts_more():
285 while isp.push_accepts_more():
286 indent = ' '*isp.indent_spaces
286 indent = ' '*isp.indent_spaces
287 prompt = '>>> ' + indent
287 prompt = '>>> ' + indent
288 line = indent + raw_input(prompt)
288 line = indent + raw_input(prompt)
289 isp.push(line)
289 isp.push(line)
290 print 'Input source was:\n', isp.source_reset(),
290 print 'Input source was:\n', isp.source_reset(),
291 """
291 """
292 # Number of spaces of indentation computed from input that has been pushed
292 # Number of spaces of indentation computed from input that has been pushed
293 # so far. This is the attributes callers should query to get the current
293 # so far. This is the attributes callers should query to get the current
294 # indentation level, in order to provide auto-indent facilities.
294 # indentation level, in order to provide auto-indent facilities.
295 indent_spaces = 0
295 indent_spaces = 0
296 # String, indicating the default input encoding. It is computed by default
296 # String, indicating the default input encoding. It is computed by default
297 # at initialization time via get_input_encoding(), but it can be reset by a
297 # at initialization time via get_input_encoding(), but it can be reset by a
298 # client with specific knowledge of the encoding.
298 # client with specific knowledge of the encoding.
299 encoding = ''
299 encoding = ''
300 # String where the current full source input is stored, properly encoded.
300 # String where the current full source input is stored, properly encoded.
301 # Reading this attribute is the normal way of querying the currently pushed
301 # Reading this attribute is the normal way of querying the currently pushed
302 # source code, that has been properly encoded.
302 # source code, that has been properly encoded.
303 source = ''
303 source = ''
304 # Code object corresponding to the current source. It is automatically
304 # Code object corresponding to the current source. It is automatically
305 # synced to the source, so it can be queried at any time to obtain the code
305 # synced to the source, so it can be queried at any time to obtain the code
306 # object; it will be None if the source doesn't compile to valid Python.
306 # object; it will be None if the source doesn't compile to valid Python.
307 code = None
307 code = None
308
308
309 # Private attributes
309 # Private attributes
310
310
311 # List with lines of input accumulated so far
311 # List with lines of input accumulated so far
312 _buffer = None
312 _buffer = None
313 # Command compiler
313 # Command compiler
314 _compile = None
314 _compile = None
315 # Mark when input has changed indentation all the way back to flush-left
315 # Mark when input has changed indentation all the way back to flush-left
316 _full_dedent = False
316 _full_dedent = False
317 # Boolean indicating whether the current block is complete
317 # Boolean indicating whether the current block is complete
318 _is_complete = None
318 _is_complete = None
319 # Boolean indicating whether the current block has an unrecoverable syntax error
319 # Boolean indicating whether the current block has an unrecoverable syntax error
320 _is_invalid = False
320 _is_invalid = False
321
321
322 def __init__(self):
322 def __init__(self):
323 """Create a new InputSplitter instance.
323 """Create a new InputSplitter instance.
324 """
324 """
325 self._buffer = []
325 self._buffer = []
326 self._compile = codeop.CommandCompiler()
326 self._compile = codeop.CommandCompiler()
327 self.encoding = get_input_encoding()
327 self.encoding = get_input_encoding()
328
328
329 def reset(self):
329 def reset(self):
330 """Reset the input buffer and associated state."""
330 """Reset the input buffer and associated state."""
331 self.indent_spaces = 0
331 self.indent_spaces = 0
332 self._buffer[:] = []
332 self._buffer[:] = []
333 self.source = ''
333 self.source = ''
334 self.code = None
334 self.code = None
335 self._is_complete = False
335 self._is_complete = False
336 self._is_invalid = False
336 self._is_invalid = False
337 self._full_dedent = False
337 self._full_dedent = False
338
338
339 def source_reset(self):
339 def source_reset(self):
340 """Return the input source and perform a full reset.
340 """Return the input source and perform a full reset.
341 """
341 """
342 out = self.source
342 out = self.source
343 self.reset()
343 self.reset()
344 return out
344 return out
345
345
346 def check_complete(self, source):
346 def check_complete(self, source):
347 """Return whether a block of code is ready to execute, or should be continued
347 """Return whether a block of code is ready to execute, or should be continued
348
348
349 This is a non-stateful API, and will reset the state of this InputSplitter.
349 This is a non-stateful API, and will reset the state of this InputSplitter.
350
350
351 Parameters
351 Parameters
352 ----------
352 ----------
353 source : string
353 source : string
354 Python input code, which can be multiline.
354 Python input code, which can be multiline.
355
355
356 Returns
356 Returns
357 -------
357 -------
358 status : str
358 status : str
359 One of 'complete', 'incomplete', or 'invalid' if source is not a
359 One of 'complete', 'incomplete', or 'invalid' if source is not a
360 prefix of valid code.
360 prefix of valid code.
361 indent_spaces : int or None
361 indent_spaces : int or None
362 The number of spaces by which to indent the next line of code. If
362 The number of spaces by which to indent the next line of code. If
363 status is not 'incomplete', this is None.
363 status is not 'incomplete', this is None.
364 """
364 """
365 self.reset()
365 self.reset()
366 try:
366 try:
367 self.push(source)
367 self.push(source)
368 except SyntaxError:
368 except SyntaxError:
369 # Transformers in IPythonInputSplitter can raise SyntaxError,
369 # Transformers in IPythonInputSplitter can raise SyntaxError,
370 # which push() will not catch.
370 # which push() will not catch.
371 return 'invalid', None
371 return 'invalid', None
372 else:
372 else:
373 if self._is_invalid:
373 if self._is_invalid:
374 return 'invalid', None
374 return 'invalid', None
375 elif self.push_accepts_more():
375 elif self.push_accepts_more():
376 return 'incomplete', self.indent_spaces
376 return 'incomplete', self.indent_spaces
377 else:
377 else:
378 return 'complete', None
378 return 'complete', None
379 finally:
379 finally:
380 self.reset()
380 self.reset()
381
381
382 def push(self, lines):
382 def push(self, lines):
383 """Push one or more lines of input.
383 """Push one or more lines of input.
384
384
385 This stores the given lines and returns a status code indicating
385 This stores the given lines and returns a status code indicating
386 whether the code forms a complete Python block or not.
386 whether the code forms a complete Python block or not.
387
387
388 Any exceptions generated in compilation are swallowed, but if an
388 Any exceptions generated in compilation are swallowed, but if an
389 exception was produced, the method returns True.
389 exception was produced, the method returns True.
390
390
391 Parameters
391 Parameters
392 ----------
392 ----------
393 lines : string
393 lines : string
394 One or more lines of Python input.
394 One or more lines of Python input.
395
395
396 Returns
396 Returns
397 -------
397 -------
398 is_complete : boolean
398 is_complete : boolean
399 True if the current input source (the result of the current input
399 True if the current input source (the result of the current input
400 plus prior inputs) forms a complete Python execution block. Note that
400 plus prior inputs) forms a complete Python execution block. Note that
401 this value is also stored as a private attribute (``_is_complete``), so it
401 this value is also stored as a private attribute (``_is_complete``), so it
402 can be queried at any time.
402 can be queried at any time.
403 """
403 """
404 self._store(lines)
404 self._store(lines)
405 source = self.source
405 source = self.source
406
406
407 # Before calling _compile(), reset the code object to None so that if an
407 # Before calling _compile(), reset the code object to None so that if an
408 # exception is raised in compilation, we don't mislead by having
408 # exception is raised in compilation, we don't mislead by having
409 # inconsistent code/source attributes.
409 # inconsistent code/source attributes.
410 self.code, self._is_complete = None, None
410 self.code, self._is_complete = None, None
411 self._is_invalid = False
411 self._is_invalid = False
412
412
413 # Honor termination lines properly
413 # Honor termination lines properly
414 if source.endswith('\\\n'):
414 if source.endswith('\\\n'):
415 return False
415 return False
416
416
417 self._update_indent()
417 self._update_indent()
418 try:
418 try:
419 with warnings.catch_warnings():
419 with warnings.catch_warnings():
420 warnings.simplefilter('error', SyntaxWarning)
420 warnings.simplefilter('error', SyntaxWarning)
421 self.code = self._compile(source, symbol="exec")
421 self.code = self._compile(source, symbol="exec")
422 # Invalid syntax can produce any of a number of different errors from
422 # Invalid syntax can produce any of a number of different errors from
423 # inside the compiler, so we have to catch them all. Syntax errors
423 # inside the compiler, so we have to catch them all. Syntax errors
424 # immediately produce a 'ready' block, so the invalid Python can be
424 # immediately produce a 'ready' block, so the invalid Python can be
425 # sent to the kernel for evaluation with possible ipython
425 # sent to the kernel for evaluation with possible ipython
426 # special-syntax conversion.
426 # special-syntax conversion.
427 except (SyntaxError, OverflowError, ValueError, TypeError,
427 except (SyntaxError, OverflowError, ValueError, TypeError,
428 MemoryError, SyntaxWarning):
428 MemoryError, SyntaxWarning):
429 self._is_complete = True
429 self._is_complete = True
430 self._is_invalid = True
430 self._is_invalid = True
431 else:
431 else:
432 # Compilation didn't produce any exceptions (though it may not have
432 # Compilation didn't produce any exceptions (though it may not have
433 # given a complete code object)
433 # given a complete code object)
434 self._is_complete = self.code is not None
434 self._is_complete = self.code is not None
435
435
436 return self._is_complete
436 return self._is_complete
437
437
438 def push_accepts_more(self):
438 def push_accepts_more(self):
439 """Return whether a block of interactive input can accept more input.
439 """Return whether a block of interactive input can accept more input.
440
440
441 This method is meant to be used by line-oriented frontends, who need to
441 This method is meant to be used by line-oriented frontends, who need to
442 guess whether a block is complete or not based solely on prior and
442 guess whether a block is complete or not based solely on prior and
443 current input lines. The InputSplitter considers it has a complete
443 current input lines. The InputSplitter considers it has a complete
444 interactive block and will not accept more input when either:
444 interactive block and will not accept more input when either:
445
445
446 * A SyntaxError is raised
446 * A SyntaxError is raised
447
447
448 * The code is complete and consists of a single line or a single
448 * The code is complete and consists of a single line or a single
449 non-compound statement
449 non-compound statement
450
450
451 * The code is complete and has a blank line at the end
451 * The code is complete and has a blank line at the end
452
452
453 If the current input produces a syntax error, this method immediately
453 If the current input produces a syntax error, this method immediately
454 returns False but does *not* raise the syntax error exception, as
454 returns False but does *not* raise the syntax error exception, as
455 typically clients will want to send invalid syntax to an execution
455 typically clients will want to send invalid syntax to an execution
456 backend which might convert the invalid syntax into valid Python via
456 backend which might convert the invalid syntax into valid Python via
457 one of the dynamic IPython mechanisms.
457 one of the dynamic IPython mechanisms.
458 """
458 """
459
459
460 # With incomplete input, unconditionally accept more
460 # With incomplete input, unconditionally accept more
461 # A syntax error also sets _is_complete to True - see push()
461 # A syntax error also sets _is_complete to True - see push()
462 if not self._is_complete:
462 if not self._is_complete:
463 #print("Not complete") # debug
463 #print("Not complete") # debug
464 return True
464 return True
465
465
466 # The user can make any (complete) input execute by leaving a blank line
466 # The user can make any (complete) input execute by leaving a blank line
467 last_line = self.source.splitlines()[-1]
467 last_line = self.source.splitlines()[-1]
468 if (not last_line) or last_line.isspace():
468 if (not last_line) or last_line.isspace():
469 #print("Blank line") # debug
469 #print("Blank line") # debug
470 return False
470 return False
471
471
472 # If there's just a single line or AST node, and we're flush left, as is
472 # If there's just a single line or AST node, and we're flush left, as is
473 # the case after a simple statement such as 'a=1', we want to execute it
473 # the case after a simple statement such as 'a=1', we want to execute it
474 # straight away.
474 # straight away.
475 if self.indent_spaces==0:
475 if self.indent_spaces==0:
476 if len(self.source.splitlines()) <= 1:
476 if len(self.source.splitlines()) <= 1:
477 return False
477 return False
478
478
479 try:
479 try:
480 code_ast = ast.parse(u''.join(self._buffer))
480 code_ast = ast.parse(u''.join(self._buffer))
481 except Exception:
481 except Exception:
482 #print("Can't parse AST") # debug
482 #print("Can't parse AST") # debug
483 return False
483 return False
484 else:
484 else:
485 if len(code_ast.body) == 1 and \
485 if len(code_ast.body) == 1 and \
486 not hasattr(code_ast.body[0], 'body'):
486 not hasattr(code_ast.body[0], 'body'):
487 #print("Simple statement") # debug
487 #print("Simple statement") # debug
488 return False
488 return False
489
489
490 # General fallback - accept more code
490 # General fallback - accept more code
491 return True
491 return True
492
492
493 #------------------------------------------------------------------------
494 # Private interface
495 #------------------------------------------------------------------------
496
497 def _find_indent(self, line):
498 """Compute the new indentation level for a single line.
499
500 Parameters
501 ----------
502 line : str
503 A single new line of non-whitespace, non-comment Python input.
504
505 Returns
506 -------
507 indent_spaces : int
508 New value for the indent level (it may be equal to self.indent_spaces
509 if indentation doesn't change.
510
511 full_dedent : boolean
512 Whether the new line causes a full flush-left dedent.
513 """
514 indent_spaces = self.indent_spaces
515 full_dedent = self._full_dedent
516
517 inisp = num_ini_spaces(line)
518 if inisp < indent_spaces:
519 indent_spaces = inisp
520 if indent_spaces <= 0:
521 #print 'Full dedent in text',self.source # dbg
522 full_dedent = True
523
524 if line.rstrip()[-1] == ':':
525 indent_spaces += 4
526 elif dedent_re.match(line):
527 indent_spaces -= 4
528 if indent_spaces <= 0:
529 full_dedent = True
530
531 # Safety
532 if indent_spaces < 0:
533 indent_spaces = 0
534 #print 'safety' # dbg
535
536 return indent_spaces, full_dedent
537
538 def _update_indent(self):
493 def _update_indent(self):
539 # self.source always has a trailing newline
494 # self.source always has a trailing newline
540 self.indent_spaces = find_next_indent(self.source[:-1])
495 self.indent_spaces = find_next_indent(self.source[:-1])
541 self._full_dedent = (self.indent_spaces == 0)
496 self._full_dedent = (self.indent_spaces == 0)
542
497
543 def _store(self, lines, buffer=None, store='source'):
498 def _store(self, lines, buffer=None, store='source'):
544 """Store one or more lines of input.
499 """Store one or more lines of input.
545
500
546 If input lines are not newline-terminated, a newline is automatically
501 If input lines are not newline-terminated, a newline is automatically
547 appended."""
502 appended."""
548
503
549 if buffer is None:
504 if buffer is None:
550 buffer = self._buffer
505 buffer = self._buffer
551
506
552 if lines.endswith('\n'):
507 if lines.endswith('\n'):
553 buffer.append(lines)
508 buffer.append(lines)
554 else:
509 else:
555 buffer.append(lines+'\n')
510 buffer.append(lines+'\n')
556 setattr(self, store, self._set_source(buffer))
511 setattr(self, store, self._set_source(buffer))
557
512
558 def _set_source(self, buffer):
513 def _set_source(self, buffer):
559 return u''.join(buffer)
514 return u''.join(buffer)
560
515
561
516
562 class IPythonInputSplitter(InputSplitter):
517 class IPythonInputSplitter(InputSplitter):
563 """An input splitter that recognizes all of IPython's special syntax."""
518 """An input splitter that recognizes all of IPython's special syntax."""
564
519
565 # String with raw, untransformed input.
520 # String with raw, untransformed input.
566 source_raw = ''
521 source_raw = ''
567
522
568 # Flag to track when a transformer has stored input that it hasn't given
523 # Flag to track when a transformer has stored input that it hasn't given
569 # back yet.
524 # back yet.
570 transformer_accumulating = False
525 transformer_accumulating = False
571
526
572 # Flag to track when assemble_python_lines has stored input that it hasn't
527 # Flag to track when assemble_python_lines has stored input that it hasn't
573 # given back yet.
528 # given back yet.
574 within_python_line = False
529 within_python_line = False
575
530
576 # Private attributes
531 # Private attributes
577
532
578 # List with lines of raw input accumulated so far.
533 # List with lines of raw input accumulated so far.
579 _buffer_raw = None
534 _buffer_raw = None
580
535
581 def __init__(self, line_input_checker=True, physical_line_transforms=None,
536 def __init__(self, line_input_checker=True, physical_line_transforms=None,
582 logical_line_transforms=None, python_line_transforms=None):
537 logical_line_transforms=None, python_line_transforms=None):
583 super(IPythonInputSplitter, self).__init__()
538 super(IPythonInputSplitter, self).__init__()
584 self._buffer_raw = []
539 self._buffer_raw = []
585 self._validate = True
540 self._validate = True
586
541
587 if physical_line_transforms is not None:
542 if physical_line_transforms is not None:
588 self.physical_line_transforms = physical_line_transforms
543 self.physical_line_transforms = physical_line_transforms
589 else:
544 else:
590 self.physical_line_transforms = [
545 self.physical_line_transforms = [
591 leading_indent(),
546 leading_indent(),
592 classic_prompt(),
547 classic_prompt(),
593 ipy_prompt(),
548 ipy_prompt(),
594 cellmagic(end_on_blank_line=line_input_checker),
549 cellmagic(end_on_blank_line=line_input_checker),
595 ]
550 ]
596
551
597 self.assemble_logical_lines = assemble_logical_lines()
552 self.assemble_logical_lines = assemble_logical_lines()
598 if logical_line_transforms is not None:
553 if logical_line_transforms is not None:
599 self.logical_line_transforms = logical_line_transforms
554 self.logical_line_transforms = logical_line_transforms
600 else:
555 else:
601 self.logical_line_transforms = [
556 self.logical_line_transforms = [
602 help_end(),
557 help_end(),
603 escaped_commands(),
558 escaped_commands(),
604 assign_from_magic(),
559 assign_from_magic(),
605 assign_from_system(),
560 assign_from_system(),
606 ]
561 ]
607
562
608 self.assemble_python_lines = assemble_python_lines()
563 self.assemble_python_lines = assemble_python_lines()
609 if python_line_transforms is not None:
564 if python_line_transforms is not None:
610 self.python_line_transforms = python_line_transforms
565 self.python_line_transforms = python_line_transforms
611 else:
566 else:
612 # We don't use any of these at present
567 # We don't use any of these at present
613 self.python_line_transforms = []
568 self.python_line_transforms = []
614
569
615 @property
570 @property
616 def transforms(self):
571 def transforms(self):
617 "Quick access to all transformers."
572 "Quick access to all transformers."
618 return self.physical_line_transforms + \
573 return self.physical_line_transforms + \
619 [self.assemble_logical_lines] + self.logical_line_transforms + \
574 [self.assemble_logical_lines] + self.logical_line_transforms + \
620 [self.assemble_python_lines] + self.python_line_transforms
575 [self.assemble_python_lines] + self.python_line_transforms
621
576
622 @property
577 @property
623 def transforms_in_use(self):
578 def transforms_in_use(self):
624 """Transformers, excluding logical line transformers if we're in a
579 """Transformers, excluding logical line transformers if we're in a
625 Python line."""
580 Python line."""
626 t = self.physical_line_transforms[:]
581 t = self.physical_line_transforms[:]
627 if not self.within_python_line:
582 if not self.within_python_line:
628 t += [self.assemble_logical_lines] + self.logical_line_transforms
583 t += [self.assemble_logical_lines] + self.logical_line_transforms
629 return t + [self.assemble_python_lines] + self.python_line_transforms
584 return t + [self.assemble_python_lines] + self.python_line_transforms
630
585
631 def reset(self):
586 def reset(self):
632 """Reset the input buffer and associated state."""
587 """Reset the input buffer and associated state."""
633 super(IPythonInputSplitter, self).reset()
588 super(IPythonInputSplitter, self).reset()
634 self._buffer_raw[:] = []
589 self._buffer_raw[:] = []
635 self.source_raw = ''
590 self.source_raw = ''
636 self.transformer_accumulating = False
591 self.transformer_accumulating = False
637 self.within_python_line = False
592 self.within_python_line = False
638
593
639 for t in self.transforms:
594 for t in self.transforms:
640 try:
595 try:
641 t.reset()
596 t.reset()
642 except SyntaxError:
597 except SyntaxError:
643 # Nothing that calls reset() expects to handle transformer
598 # Nothing that calls reset() expects to handle transformer
644 # errors
599 # errors
645 pass
600 pass
646
601
647 def flush_transformers(self):
602 def flush_transformers(self):
648 def _flush(transform, outs):
603 def _flush(transform, outs):
649 """yield transformed lines
604 """yield transformed lines
650
605
651 always strings, never None
606 always strings, never None
652
607
653 transform: the current transform
608 transform: the current transform
654 outs: an iterable of previously transformed inputs.
609 outs: an iterable of previously transformed inputs.
655 Each may be multiline, which will be passed
610 Each may be multiline, which will be passed
656 one line at a time to transform.
611 one line at a time to transform.
657 """
612 """
658 for out in outs:
613 for out in outs:
659 for line in out.splitlines():
614 for line in out.splitlines():
660 # push one line at a time
615 # push one line at a time
661 tmp = transform.push(line)
616 tmp = transform.push(line)
662 if tmp is not None:
617 if tmp is not None:
663 yield tmp
618 yield tmp
664
619
665 # reset the transform
620 # reset the transform
666 tmp = transform.reset()
621 tmp = transform.reset()
667 if tmp is not None:
622 if tmp is not None:
668 yield tmp
623 yield tmp
669
624
670 out = []
625 out = []
671 for t in self.transforms_in_use:
626 for t in self.transforms_in_use:
672 out = _flush(t, out)
627 out = _flush(t, out)
673
628
674 out = list(out)
629 out = list(out)
675 if out:
630 if out:
676 self._store('\n'.join(out))
631 self._store('\n'.join(out))
677
632
678 def raw_reset(self):
633 def raw_reset(self):
679 """Return raw input only and perform a full reset.
634 """Return raw input only and perform a full reset.
680 """
635 """
681 out = self.source_raw
636 out = self.source_raw
682 self.reset()
637 self.reset()
683 return out
638 return out
684
639
685 def source_reset(self):
640 def source_reset(self):
686 try:
641 try:
687 self.flush_transformers()
642 self.flush_transformers()
688 return self.source
643 return self.source
689 finally:
644 finally:
690 self.reset()
645 self.reset()
691
646
692 def push_accepts_more(self):
647 def push_accepts_more(self):
693 if self.transformer_accumulating:
648 if self.transformer_accumulating:
694 return True
649 return True
695 else:
650 else:
696 return super(IPythonInputSplitter, self).push_accepts_more()
651 return super(IPythonInputSplitter, self).push_accepts_more()
697
652
698 def transform_cell(self, cell):
653 def transform_cell(self, cell):
699 """Process and translate a cell of input.
654 """Process and translate a cell of input.
700 """
655 """
701 self.reset()
656 self.reset()
702 try:
657 try:
703 self.push(cell)
658 self.push(cell)
704 self.flush_transformers()
659 self.flush_transformers()
705 return self.source
660 return self.source
706 finally:
661 finally:
707 self.reset()
662 self.reset()
708
663
709 def push(self, lines):
664 def push(self, lines):
710 """Push one or more lines of IPython input.
665 """Push one or more lines of IPython input.
711
666
712 This stores the given lines and returns a status code indicating
667 This stores the given lines and returns a status code indicating
713 whether the code forms a complete Python block or not, after processing
668 whether the code forms a complete Python block or not, after processing
714 all input lines for special IPython syntax.
669 all input lines for special IPython syntax.
715
670
716 Any exceptions generated in compilation are swallowed, but if an
671 Any exceptions generated in compilation are swallowed, but if an
717 exception was produced, the method returns True.
672 exception was produced, the method returns True.
718
673
719 Parameters
674 Parameters
720 ----------
675 ----------
721 lines : string
676 lines : string
722 One or more lines of Python input.
677 One or more lines of Python input.
723
678
724 Returns
679 Returns
725 -------
680 -------
726 is_complete : boolean
681 is_complete : boolean
727 True if the current input source (the result of the current input
682 True if the current input source (the result of the current input
728 plus prior inputs) forms a complete Python execution block. Note that
683 plus prior inputs) forms a complete Python execution block. Note that
729 this value is also stored as a private attribute (_is_complete), so it
684 this value is also stored as a private attribute (_is_complete), so it
730 can be queried at any time.
685 can be queried at any time.
731 """
686 """
732
687
733 # We must ensure all input is pure unicode
688 # We must ensure all input is pure unicode
734 lines = cast_unicode(lines, self.encoding)
689 lines = cast_unicode(lines, self.encoding)
735 # ''.splitlines() --> [], but we need to push the empty line to transformers
690 # ''.splitlines() --> [], but we need to push the empty line to transformers
736 lines_list = lines.splitlines()
691 lines_list = lines.splitlines()
737 if not lines_list:
692 if not lines_list:
738 lines_list = ['']
693 lines_list = ['']
739
694
740 # Store raw source before applying any transformations to it. Note
695 # Store raw source before applying any transformations to it. Note
741 # that this must be done *after* the reset() call that would otherwise
696 # that this must be done *after* the reset() call that would otherwise
742 # flush the buffer.
697 # flush the buffer.
743 self._store(lines, self._buffer_raw, 'source_raw')
698 self._store(lines, self._buffer_raw, 'source_raw')
744
699
745 for line in lines_list:
700 for line in lines_list:
746 out = self.push_line(line)
701 out = self.push_line(line)
747
702
748 return out
703 return out
749
704
750 def push_line(self, line):
705 def push_line(self, line):
751 buf = self._buffer
706 buf = self._buffer
752
707
753 def _accumulating(dbg):
708 def _accumulating(dbg):
754 #print(dbg)
709 #print(dbg)
755 self.transformer_accumulating = True
710 self.transformer_accumulating = True
756 return False
711 return False
757
712
758 for transformer in self.physical_line_transforms:
713 for transformer in self.physical_line_transforms:
759 line = transformer.push(line)
714 line = transformer.push(line)
760 if line is None:
715 if line is None:
761 return _accumulating(transformer)
716 return _accumulating(transformer)
762
717
763 if not self.within_python_line:
718 if not self.within_python_line:
764 line = self.assemble_logical_lines.push(line)
719 line = self.assemble_logical_lines.push(line)
765 if line is None:
720 if line is None:
766 return _accumulating('acc logical line')
721 return _accumulating('acc logical line')
767
722
768 for transformer in self.logical_line_transforms:
723 for transformer in self.logical_line_transforms:
769 line = transformer.push(line)
724 line = transformer.push(line)
770 if line is None:
725 if line is None:
771 return _accumulating(transformer)
726 return _accumulating(transformer)
772
727
773 line = self.assemble_python_lines.push(line)
728 line = self.assemble_python_lines.push(line)
774 if line is None:
729 if line is None:
775 self.within_python_line = True
730 self.within_python_line = True
776 return _accumulating('acc python line')
731 return _accumulating('acc python line')
777 else:
732 else:
778 self.within_python_line = False
733 self.within_python_line = False
779
734
780 for transformer in self.python_line_transforms:
735 for transformer in self.python_line_transforms:
781 line = transformer.push(line)
736 line = transformer.push(line)
782 if line is None:
737 if line is None:
783 return _accumulating(transformer)
738 return _accumulating(transformer)
784
739
785 #print("transformers clear") #debug
740 #print("transformers clear") #debug
786 self.transformer_accumulating = False
741 self.transformer_accumulating = False
787 return super(IPythonInputSplitter, self).push(line)
742 return super(IPythonInputSplitter, self).push(line)
General Comments 0
You need to be logged in to leave comments. Login now