Show More
@@ -224,6 +224,8 class InputSplitter(object): | |||
|
224 | 224 | _full_dedent = False |
|
225 | 225 | # Boolean indicating whether the current block is complete |
|
226 | 226 | _is_complete = None |
|
227 | # Boolean indicating whether the current block has an unrecoverable syntax error | |
|
228 | _is_invalid = False | |
|
227 | 229 | |
|
228 | 230 | def __init__(self): |
|
229 | 231 | """Create a new InputSplitter instance. |
@@ -239,6 +241,7 class InputSplitter(object): | |||
|
239 | 241 | self.source = '' |
|
240 | 242 | self.code = None |
|
241 | 243 | self._is_complete = False |
|
244 | self._is_invalid = False | |
|
242 | 245 | self._full_dedent = False |
|
243 | 246 | |
|
244 | 247 | def source_reset(self): |
@@ -248,19 +251,39 class InputSplitter(object): | |||
|
248 | 251 | self.reset() |
|
249 | 252 | return out |
|
250 | 253 | |
|
251 |
def |
|
|
254 | def check_complete(self, source): | |
|
252 | 255 | """Return whether a block of code is ready to execute, or should be continued |
|
253 | 256 | |
|
254 | 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 | 273 | self.reset() |
|
257 | 274 | try: |
|
258 | 275 | self.push(source) |
|
259 | return not self.push_accepts_more() | |
|
260 | 276 | except SyntaxError: |
|
261 | 277 | # Transformers in IPythonInputSplitter can raise SyntaxError, |
|
262 | 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 | 287 | finally: |
|
265 | 288 | self.reset() |
|
266 | 289 | |
@@ -293,6 +316,7 class InputSplitter(object): | |||
|
293 | 316 | # exception is raised in compilation, we don't mislead by having |
|
294 | 317 | # inconsistent code/source attributes. |
|
295 | 318 | self.code, self._is_complete = None, None |
|
319 | self._is_invalid = False | |
|
296 | 320 | |
|
297 | 321 | # Honor termination lines properly |
|
298 | 322 | if source.endswith('\\\n'): |
@@ -309,6 +333,7 class InputSplitter(object): | |||
|
309 | 333 | except (SyntaxError, OverflowError, ValueError, TypeError, |
|
310 | 334 | MemoryError): |
|
311 | 335 | self._is_complete = True |
|
336 | self._is_invalid = True | |
|
312 | 337 | else: |
|
313 | 338 | # Compilation didn't produce any exceptions (though it may not have |
|
314 | 339 | # given a complete code object) |
@@ -355,12 +355,12 class InputSplitterTestCase(unittest.TestCase): | |||
|
355 | 355 | isp.push(r"(1 \ ") |
|
356 | 356 | self.assertFalse(isp.push_accepts_more()) |
|
357 | 357 | |
|
358 |
def test_ |
|
|
358 | def test_check_complete(self): | |
|
359 | 359 | isp = self.isp |
|
360 |
assert |
|
|
361 |
assert |
|
|
362 | assert isp.is_complete("raise = 2") # SyntaxError should mean complete | |
|
363 |
assert |
|
|
360 | self.assertEqual(isp.check_complete("a = 1"), ('complete', None)) | |
|
361 | self.assertEqual(isp.check_complete("for a in range(5):"), ('incomplete', 4)) | |
|
362 | self.assertEqual(isp.check_complete("raise = 2"), ('invalid', None)) | |
|
363 | self.assertEqual(isp.check_complete("a = [1,\n2,"), ('incomplete', 0)) | |
|
364 | 364 | |
|
365 | 365 | class InteractiveLoopTestCase(unittest.TestCase): |
|
366 | 366 | """Tests for an interactive loop like a python shell. |
@@ -211,13 +211,14 def test_is_complete(): | |||
|
211 | 211 | # that the kernel exposes the interface correctly. |
|
212 | 212 | kc.is_complete('2+2') |
|
213 | 213 | reply = kc.get_shell_msg(block=True, timeout=TIMEOUT) |
|
214 |
assert reply['content']['complete' |
|
|
214 | assert reply['content']['status'] == 'complete' | |
|
215 | 215 | |
|
216 | 216 | # SyntaxError should mean it's complete |
|
217 | 217 | kc.is_complete('raise = 2') |
|
218 | 218 | reply = kc.get_shell_msg(block=True, timeout=TIMEOUT) |
|
219 |
assert reply['content'][' |
|
|
219 | assert reply['content']['status'] == 'invalid' | |
|
220 | 220 | |
|
221 | 221 | kc.is_complete('a = [1,\n2,') |
|
222 | 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 class KernelInfoReply(Reference): | |||
|
161 | 161 | |
|
162 | 162 | |
|
163 | 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 | 175 | # IOPub messages |
@@ -230,8 +230,11 class IPythonKernel(KernelBase): | |||
|
230 | 230 | return dict(status='ok', restart=restart) |
|
231 | 231 | |
|
232 | 232 | def do_is_complete(self, code): |
|
233 |
|
|
|
234 | return {'complete': complete} | |
|
233 | status, indent_spaces = self.shell.input_transformer_manager.check_complete(code) | |
|
234 | r = {'status': status} | |
|
235 | if status == 'incomplete': | |
|
236 | r['indent'] = ' ' * indent_spaces | |
|
237 | return r | |
|
235 | 238 | |
|
236 | 239 | def do_apply(self, content, bufs, msg_id, reply_metadata): |
|
237 | 240 | shell = self.shell |
@@ -493,7 +493,7 class Kernel(Configurable): | |||
|
493 | 493 | def do_is_complete(self, code): |
|
494 | 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 decide whether to immediately execute the current code, or whether to show a | |||
|
585 | 585 | continuation prompt for further input. For instance, in Python ``a = 5`` would |
|
586 | 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 | 599 | Frontends may have ways to override this, forcing the code to be sent for |
|
589 |
execution or forcing a continuation prompt. |
|
|
590 | the frontend will probably default to sending the code to be executed. | |
|
600 | execution or forcing a continuation prompt. | |
|
591 | 601 | |
|
592 | 602 | Message type: ``is_complete_request``:: |
|
593 | 603 | |
@@ -596,11 +606,17 Message type: ``is_complete_request``:: | |||
|
596 | 606 | 'code' : str, |
|
597 | 607 | } |
|
598 | 608 | |
|
599 | Message type: ``complete_reply``:: | |
|
609 | Message type: ``is_complete_reply``:: | |
|
600 | 610 | |
|
601 | 611 | content = { |
|
602 | # True if the code is ready to execute, False if not | |
|
603 |
' |
|
|
612 | # One of 'complete', 'incomplete', 'invalid', 'unknown' | |
|
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 | 622 | Connect |
General Comments 0
You need to be logged in to leave comments.
Login now