Show More
@@ -224,6 +224,8 b' class InputSplitter(object):' | |||||
224 | _full_dedent = False |
|
224 | _full_dedent = False | |
225 | # Boolean indicating whether the current block is complete |
|
225 | # Boolean indicating whether the current block is complete | |
226 | _is_complete = None |
|
226 | _is_complete = None | |
|
227 | # Boolean indicating whether the current block has an unrecoverable syntax error | |||
|
228 | _is_invalid = False | |||
227 |
|
229 | |||
228 | def __init__(self): |
|
230 | def __init__(self): | |
229 | """Create a new InputSplitter instance. |
|
231 | """Create a new InputSplitter instance. | |
@@ -239,6 +241,7 b' class InputSplitter(object):' | |||||
239 | self.source = '' |
|
241 | self.source = '' | |
240 | self.code = None |
|
242 | self.code = None | |
241 | self._is_complete = False |
|
243 | self._is_complete = False | |
|
244 | self._is_invalid = False | |||
242 | self._full_dedent = False |
|
245 | self._full_dedent = False | |
243 |
|
246 | |||
244 | def source_reset(self): |
|
247 | def source_reset(self): | |
@@ -248,19 +251,39 b' class InputSplitter(object):' | |||||
248 | self.reset() |
|
251 | self.reset() | |
249 | return out |
|
252 | return out | |
250 |
|
253 | |||
251 |
def |
|
254 | def check_complete(self, source): | |
252 | """Return whether a block of code is ready to execute, or should be continued |
|
255 | """Return whether a block of code is ready to execute, or should be continued | |
253 |
|
256 | |||
254 | This is a non-stateful API, and will reset the state of this InputSplitter. |
|
257 | This is a non-stateful API, and will reset the state of this InputSplitter. | |
|
258 | ||||
|
259 | Parameters | |||
|
260 | ---------- | |||
|
261 | source : string | |||
|
262 | Python input code, which can be multiline. | |||
|
263 | ||||
|
264 | Returns | |||
|
265 | ------- | |||
|
266 | status : str | |||
|
267 | One of 'complete', 'incomplete', or 'invalid' if source is not a | |||
|
268 | prefix of valid code. | |||
|
269 | indent_spaces : int or None | |||
|
270 | The number of spaces by which to indent the next line of code. If | |||
|
271 | status is not 'incomplete', this is None. | |||
255 | """ |
|
272 | """ | |
256 | self.reset() |
|
273 | self.reset() | |
257 | try: |
|
274 | try: | |
258 | self.push(source) |
|
275 | self.push(source) | |
259 | return not self.push_accepts_more() |
|
|||
260 | except SyntaxError: |
|
276 | except SyntaxError: | |
261 | # Transformers in IPythonInputSplitter can raise SyntaxError, |
|
277 | # Transformers in IPythonInputSplitter can raise SyntaxError, | |
262 | # which push() will not catch. |
|
278 | # which push() will not catch. | |
263 |
return |
|
279 | return 'invalid', None | |
|
280 | else: | |||
|
281 | if self._is_invalid: | |||
|
282 | return 'invalid', None | |||
|
283 | elif self.push_accepts_more(): | |||
|
284 | return 'incomplete', self.indent_spaces | |||
|
285 | else: | |||
|
286 | return 'complete', None | |||
264 | finally: |
|
287 | finally: | |
265 | self.reset() |
|
288 | self.reset() | |
266 |
|
289 | |||
@@ -293,6 +316,7 b' class InputSplitter(object):' | |||||
293 | # exception is raised in compilation, we don't mislead by having |
|
316 | # exception is raised in compilation, we don't mislead by having | |
294 | # inconsistent code/source attributes. |
|
317 | # inconsistent code/source attributes. | |
295 | self.code, self._is_complete = None, None |
|
318 | self.code, self._is_complete = None, None | |
|
319 | self._is_invalid = False | |||
296 |
|
320 | |||
297 | # Honor termination lines properly |
|
321 | # Honor termination lines properly | |
298 | if source.endswith('\\\n'): |
|
322 | if source.endswith('\\\n'): | |
@@ -309,6 +333,7 b' class InputSplitter(object):' | |||||
309 | except (SyntaxError, OverflowError, ValueError, TypeError, |
|
333 | except (SyntaxError, OverflowError, ValueError, TypeError, | |
310 | MemoryError): |
|
334 | MemoryError): | |
311 | self._is_complete = True |
|
335 | self._is_complete = True | |
|
336 | self._is_invalid = True | |||
312 | else: |
|
337 | else: | |
313 | # Compilation didn't produce any exceptions (though it may not have |
|
338 | # Compilation didn't produce any exceptions (though it may not have | |
314 | # given a complete code object) |
|
339 | # given a complete code object) |
@@ -355,12 +355,12 b' class InputSplitterTestCase(unittest.TestCase):' | |||||
355 | isp.push(r"(1 \ ") |
|
355 | isp.push(r"(1 \ ") | |
356 | self.assertFalse(isp.push_accepts_more()) |
|
356 | self.assertFalse(isp.push_accepts_more()) | |
357 |
|
357 | |||
358 |
def test_ |
|
358 | def test_check_complete(self): | |
359 | isp = self.isp |
|
359 | isp = self.isp | |
360 |
assert |
|
360 | self.assertEqual(isp.check_complete("a = 1"), ('complete', None)) | |
361 |
assert |
|
361 | self.assertEqual(isp.check_complete("for a in range(5):"), ('incomplete', 4)) | |
362 | assert isp.is_complete("raise = 2") # SyntaxError should mean complete |
|
362 | self.assertEqual(isp.check_complete("raise = 2"), ('invalid', None)) | |
363 |
assert |
|
363 | self.assertEqual(isp.check_complete("a = [1,\n2,"), ('incomplete', 0)) | |
364 |
|
364 | |||
365 | class InteractiveLoopTestCase(unittest.TestCase): |
|
365 | class InteractiveLoopTestCase(unittest.TestCase): | |
366 | """Tests for an interactive loop like a python shell. |
|
366 | """Tests for an interactive loop like a python shell. |
@@ -211,13 +211,14 b' def test_is_complete():' | |||||
211 | # that the kernel exposes the interface correctly. |
|
211 | # that the kernel exposes the interface correctly. | |
212 | kc.is_complete('2+2') |
|
212 | kc.is_complete('2+2') | |
213 | reply = kc.get_shell_msg(block=True, timeout=TIMEOUT) |
|
213 | reply = kc.get_shell_msg(block=True, timeout=TIMEOUT) | |
214 |
assert reply['content']['complete' |
|
214 | assert reply['content']['status'] == 'complete' | |
215 |
|
215 | |||
216 | # SyntaxError should mean it's complete |
|
216 | # SyntaxError should mean it's complete | |
217 | kc.is_complete('raise = 2') |
|
217 | kc.is_complete('raise = 2') | |
218 | reply = kc.get_shell_msg(block=True, timeout=TIMEOUT) |
|
218 | reply = kc.get_shell_msg(block=True, timeout=TIMEOUT) | |
219 |
assert reply['content'][' |
|
219 | assert reply['content']['status'] == 'invalid' | |
220 |
|
220 | |||
221 | kc.is_complete('a = [1,\n2,') |
|
221 | kc.is_complete('a = [1,\n2,') | |
222 | reply = kc.get_shell_msg(block=True, timeout=TIMEOUT) |
|
222 | reply = kc.get_shell_msg(block=True, timeout=TIMEOUT) | |
223 |
assert |
|
223 | assert reply['content']['status'] == 'incomplete' | |
|
224 | assert reply['content']['indent'] == '' No newline at end of file |
@@ -161,7 +161,15 b' class KernelInfoReply(Reference):' | |||||
161 |
|
161 | |||
162 |
|
162 | |||
163 | class IsCompleteReply(Reference): |
|
163 | class IsCompleteReply(Reference): | |
164 | complete = Bool() |
|
164 | status = Enum((u'complete', u'incomplete', u'invalid', u'unknown')) | |
|
165 | ||||
|
166 | def check(self, d): | |||
|
167 | Reference.check(self, d) | |||
|
168 | if d['status'] == 'incomplete': | |||
|
169 | IsCompleteReplyIncomplete().check(d) | |||
|
170 | ||||
|
171 | class IsCompleteReplyIncomplete(Reference): | |||
|
172 | indent = Unicode() | |||
165 |
|
173 | |||
166 |
|
174 | |||
167 | # IOPub messages |
|
175 | # IOPub messages |
@@ -230,8 +230,11 b' class IPythonKernel(KernelBase):' | |||||
230 | return dict(status='ok', restart=restart) |
|
230 | return dict(status='ok', restart=restart) | |
231 |
|
231 | |||
232 | def do_is_complete(self, code): |
|
232 | def do_is_complete(self, code): | |
233 |
|
|
233 | status, indent_spaces = self.shell.input_transformer_manager.check_complete(code) | |
234 | return {'complete': complete} |
|
234 | r = {'status': status} | |
|
235 | if status == 'incomplete': | |||
|
236 | r['indent'] = ' ' * indent_spaces | |||
|
237 | return r | |||
235 |
|
238 | |||
236 | def do_apply(self, content, bufs, msg_id, reply_metadata): |
|
239 | def do_apply(self, content, bufs, msg_id, reply_metadata): | |
237 | shell = self.shell |
|
240 | shell = self.shell |
@@ -493,7 +493,7 b' class Kernel(Configurable):' | |||||
493 | def do_is_complete(self, code): |
|
493 | def do_is_complete(self, code): | |
494 | """Override in subclasses to find completions. |
|
494 | """Override in subclasses to find completions. | |
495 | """ |
|
495 | """ | |
496 |
return {' |
|
496 | return {'status' : 'unknown', | |
497 | } |
|
497 | } | |
498 |
|
498 | |||
499 | #--------------------------------------------------------------------------- |
|
499 | #--------------------------------------------------------------------------- |
@@ -585,9 +585,19 b' decide whether to immediately execute the current code, or whether to show a' | |||||
585 | continuation prompt for further input. For instance, in Python ``a = 5`` would |
|
585 | continuation prompt for further input. For instance, in Python ``a = 5`` would | |
586 | be executed immediately, while ``for i in range(5):`` would expect further input. |
|
586 | be executed immediately, while ``for i in range(5):`` would expect further input. | |
587 |
|
587 | |||
|
588 | There are four possible replies: | |||
|
589 | ||||
|
590 | - *complete* code is ready to be executed | |||
|
591 | - *incomplete* code should prompt for another line | |||
|
592 | - *invalid* code will typically be sent for execution, so that the user sees the | |||
|
593 | error soonest. | |||
|
594 | - *unknown* - if the kernel is not able to determine this. The frontend should | |||
|
595 | also handle the kernel not replying promptly. It may default to sending the | |||
|
596 | code for execution, or it may implement simple fallback heuristics for whether | |||
|
597 | to execute the code (e.g. execute after a blank line). | |||
|
598 | ||||
588 | Frontends may have ways to override this, forcing the code to be sent for |
|
599 | Frontends may have ways to override this, forcing the code to be sent for | |
589 |
execution or forcing a continuation prompt. |
|
600 | execution or forcing a continuation prompt. | |
590 | the frontend will probably default to sending the code to be executed. |
|
|||
591 |
|
601 | |||
592 | Message type: ``is_complete_request``:: |
|
602 | Message type: ``is_complete_request``:: | |
593 |
|
603 | |||
@@ -596,11 +606,17 b' Message type: ``is_complete_request``::' | |||||
596 | 'code' : str, |
|
606 | 'code' : str, | |
597 | } |
|
607 | } | |
598 |
|
608 | |||
599 | Message type: ``complete_reply``:: |
|
609 | Message type: ``is_complete_reply``:: | |
600 |
|
610 | |||
601 | content = { |
|
611 | content = { | |
602 | # True if the code is ready to execute, False if not |
|
612 | # One of 'complete', 'incomplete', 'invalid', 'unknown' | |
603 |
' |
|
613 | 'status' : str, | |
|
614 | ||||
|
615 | # If status is 'incomplete', indent should contain the characters to use | |||
|
616 | # to indent the next line. This is only a hint: frontends may ignore it | |||
|
617 | # and use their own autoindentation rules. For other statuses, this | |||
|
618 | # field does not exist. | |||
|
619 | 'indent': str, | |||
604 | } |
|
620 | } | |
605 |
|
621 | |||
606 | Connect |
|
622 | Connect |
General Comments 0
You need to be logged in to leave comments.
Login now