Show More
@@ -508,14 +508,14 b' class IPythonInputSplitter(InputSplitter):' | |||||
508 | super(IPythonInputSplitter, self).__init__(input_mode) |
|
508 | super(IPythonInputSplitter, self).__init__(input_mode) | |
509 | self._buffer_raw = [] |
|
509 | self._buffer_raw = [] | |
510 | self._validate = True |
|
510 | self._validate = True | |
511 | self.transforms = [leading_indent, |
|
511 | self.transforms = [leading_indent(), | |
512 | classic_prompt, |
|
512 | classic_prompt(), | |
513 | ipy_prompt, |
|
513 | ipy_prompt(), | |
514 | cellmagic, |
|
514 | cellmagic(), | |
515 | help_end, |
|
515 | help_end(), | |
516 | escaped_transformer, |
|
516 | escaped_transformer(), | |
517 | assign_from_magic, |
|
517 | assign_from_magic(), | |
518 | assign_from_system, |
|
518 | assign_from_system(), | |
519 | ] |
|
519 | ] | |
520 |
|
520 | |||
521 | def reset(self): |
|
521 | def reset(self): |
@@ -44,29 +44,34 b' class InputTransformer(object):' | |||||
44 |
|
44 | |||
45 | look_in_string = False |
|
45 | look_in_string = False | |
46 |
|
46 | |||
47 |
|
|
47 | def stateless_input_transformer(func): | |
48 | """Decorator for a stateless input transformer implemented as a function.""" |
|
48 | class StatelessInputTransformer(InputTransformer): | |
49 | def __init__(self, func): |
|
49 | """Decorator for a stateless input transformer implemented as a function.""" | |
50 | self.func = func |
|
50 | def __init__(self): | |
51 |
|
51 | self.func = func | ||
52 | def push(self, line): |
|
52 | ||
53 |
|
|
53 | def push(self, line): | |
54 |
|
54 | return self.func(line) | ||
55 | def reset(self): |
|
55 | ||
56 | pass |
|
56 | def reset(self): | |
57 |
|
57 | pass | ||
58 | class CoroutineInputTransformer(InputTransformer): |
|
|||
59 | """Decorator for an input transformer implemented as a coroutine.""" |
|
|||
60 | def __init__(self, coro): |
|
|||
61 | # Prime it |
|
|||
62 | self.coro = coro() |
|
|||
63 | next(self.coro) |
|
|||
64 |
|
58 | |||
65 | def push(self, line): |
|
59 | return StatelessInputTransformer | |
66 | return self.coro.send(line) |
|
60 | ||
|
61 | def coroutine_input_transformer(coro): | |||
|
62 | class CoroutineInputTransformer(InputTransformer): | |||
|
63 | def __init__(self): | |||
|
64 | # Prime it | |||
|
65 | self.coro = coro() | |||
|
66 | next(self.coro) | |||
|
67 | ||||
|
68 | def push(self, line): | |||
|
69 | return self.coro.send(line) | |||
|
70 | ||||
|
71 | def reset(self): | |||
|
72 | return self.coro.send(None) | |||
67 |
|
73 | |||
68 | def reset(self): |
|
74 | return CoroutineInputTransformer | |
69 | return self.coro.send(None) |
|
|||
70 |
|
75 | |||
71 |
|
76 | |||
72 | # Utilities |
|
77 | # Utilities | |
@@ -83,7 +88,7 b' def _make_help_call(target, esc, lspace, next_input=None):' | |||||
83 | return '%sget_ipython().set_next_input(%r);get_ipython().magic(%r)' % \ |
|
88 | return '%sget_ipython().set_next_input(%r);get_ipython().magic(%r)' % \ | |
84 | (lspace, next_input, arg) |
|
89 | (lspace, next_input, arg) | |
85 |
|
90 | |||
86 |
@ |
|
91 | @coroutine_input_transformer | |
87 | def escaped_transformer(): |
|
92 | def escaped_transformer(): | |
88 | """Translate lines beginning with one of IPython's escape characters.""" |
|
93 | """Translate lines beginning with one of IPython's escape characters.""" | |
89 |
|
94 | |||
@@ -188,7 +193,7 b' def has_comment(src):' | |||||
188 | pass |
|
193 | pass | |
189 | return(tokenize.COMMENT in toktypes) |
|
194 | return(tokenize.COMMENT in toktypes) | |
190 |
|
195 | |||
191 |
@ |
|
196 | @stateless_input_transformer | |
192 | def help_end(line): |
|
197 | def help_end(line): | |
193 | """Translate lines with ?/?? at the end""" |
|
198 | """Translate lines with ?/?? at the end""" | |
194 | m = _help_end_re.search(line) |
|
199 | m = _help_end_re.search(line) | |
@@ -204,15 +209,20 b' def help_end(line):' | |||||
204 | return _make_help_call(target, esc, lspace, next_input) |
|
209 | return _make_help_call(target, esc, lspace, next_input) | |
205 |
|
210 | |||
206 |
|
211 | |||
207 |
@ |
|
212 | @coroutine_input_transformer | |
208 | def cellmagic(): |
|
213 | def cellmagic(): | |
209 | tpl = 'get_ipython().run_cell_magic(%r, %r, %r)' |
|
214 | tpl = 'get_ipython().run_cell_magic(%r, %r, %r)' | |
|
215 | cellmagic_help_re = re.compile('%%\w+\?') | |||
210 | line = '' |
|
216 | line = '' | |
211 | while True: |
|
217 | while True: | |
212 | line = (yield line) |
|
218 | line = (yield line) | |
213 | if (not line) or (not line.startswith(ESC_MAGIC2)): |
|
219 | if (not line) or (not line.startswith(ESC_MAGIC2)): | |
214 | continue |
|
220 | continue | |
215 |
|
221 | |||
|
222 | if cellmagic_help_re.match(line): | |||
|
223 | # This case will be handled by help_end | |||
|
224 | continue | |||
|
225 | ||||
216 | first = line |
|
226 | first = line | |
217 | body = [] |
|
227 | body = [] | |
218 | line = (yield None) |
|
228 | line = (yield None) | |
@@ -223,7 +233,7 b' def cellmagic():' | |||||
223 | # Output |
|
233 | # Output | |
224 | magic_name, _, first = first.partition(' ') |
|
234 | magic_name, _, first = first.partition(' ') | |
225 | magic_name = magic_name.lstrip(ESC_MAGIC2) |
|
235 | magic_name = magic_name.lstrip(ESC_MAGIC2) | |
226 | line = tpl % (magic_name, first, '\n'.join(body)) |
|
236 | line = tpl % (magic_name, first, u'\n'.join(body)) | |
227 |
|
237 | |||
228 | def _strip_prompts(prompt1_re, prompt2_re): |
|
238 | def _strip_prompts(prompt1_re, prompt2_re): | |
229 | """Remove matching input prompts from a block of input.""" |
|
239 | """Remove matching input prompts from a block of input.""" | |
@@ -246,7 +256,7 b' def _strip_prompts(prompt1_re, prompt2_re):' | |||||
246 | while line is not None: |
|
256 | while line is not None: | |
247 | line = (yield line) |
|
257 | line = (yield line) | |
248 |
|
258 | |||
249 |
@ |
|
259 | @coroutine_input_transformer | |
250 | def classic_prompt(): |
|
260 | def classic_prompt(): | |
251 | prompt1_re = re.compile(r'^(>>> )') |
|
261 | prompt1_re = re.compile(r'^(>>> )') | |
252 | prompt2_re = re.compile(r'^(>>> |^\.\.\. )') |
|
262 | prompt2_re = re.compile(r'^(>>> |^\.\.\. )') | |
@@ -254,7 +264,7 b' def classic_prompt():' | |||||
254 |
|
264 | |||
255 | classic_prompt.look_in_string = True |
|
265 | classic_prompt.look_in_string = True | |
256 |
|
266 | |||
257 |
@ |
|
267 | @coroutine_input_transformer | |
258 | def ipy_prompt(): |
|
268 | def ipy_prompt(): | |
259 | prompt1_re = re.compile(r'^In \[\d+\]: ') |
|
269 | prompt1_re = re.compile(r'^In \[\d+\]: ') | |
260 | prompt2_re = re.compile(r'^(In \[\d+\]: |^\ \ \ \.\.\.+: )') |
|
270 | prompt2_re = re.compile(r'^(In \[\d+\]: |^\ \ \ \.\.\.+: )') | |
@@ -262,7 +272,7 b' def ipy_prompt():' | |||||
262 |
|
272 | |||
263 | ipy_prompt.look_in_string = True |
|
273 | ipy_prompt.look_in_string = True | |
264 |
|
274 | |||
265 |
@ |
|
275 | @coroutine_input_transformer | |
266 | def leading_indent(): |
|
276 | def leading_indent(): | |
267 | space_re = re.compile(r'^[ \t]+') |
|
277 | space_re = re.compile(r'^[ \t]+') | |
268 | line = '' |
|
278 | line = '' | |
@@ -308,14 +318,14 b' def _special_assignment(assignment_re, template):' | |||||
308 | whole = assignment_re.match(' '.join(parts)) |
|
318 | whole = assignment_re.match(' '.join(parts)) | |
309 | line = template % (whole.group('lhs'), whole.group('cmd')) |
|
319 | line = template % (whole.group('lhs'), whole.group('cmd')) | |
310 |
|
320 | |||
311 |
@ |
|
321 | @coroutine_input_transformer | |
312 | def assign_from_system(): |
|
322 | def assign_from_system(): | |
313 | assignment_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))' |
|
323 | assignment_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))' | |
314 | r'\s*=\s*!\s*(?P<cmd>.*)') |
|
324 | r'\s*=\s*!\s*(?P<cmd>.*)') | |
315 | template = '%s = get_ipython().getoutput(%r)' |
|
325 | template = '%s = get_ipython().getoutput(%r)' | |
316 | return _special_assignment(assignment_re, template) |
|
326 | return _special_assignment(assignment_re, template) | |
317 |
|
327 | |||
318 |
@ |
|
328 | @coroutine_input_transformer | |
319 | def assign_from_magic(): |
|
329 | def assign_from_magic(): | |
320 | assignment_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))' |
|
330 | assignment_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))' | |
321 | r'\s*=\s*%\s*(?P<cmd>.*)') |
|
331 | r'\s*=\s*%\s*(?P<cmd>.*)') |
@@ -109,18 +109,6 b' def test_remove_comments():' | |||||
109 | ] |
|
109 | ] | |
110 | tt.check_pairs(isp.remove_comments, tests) |
|
110 | tt.check_pairs(isp.remove_comments, tests) | |
111 |
|
111 | |||
112 | def test_has_comment(): |
|
|||
113 | tests = [('text', False), |
|
|||
114 | ('text #comment', True), |
|
|||
115 | ('text #comment\n', True), |
|
|||
116 | ('#comment', True), |
|
|||
117 | ('#comment\n', True), |
|
|||
118 | ('a = "#string"', False), |
|
|||
119 | ('a = "#string" # comment', True), |
|
|||
120 | ('a #comment not "string"', True), |
|
|||
121 | ] |
|
|||
122 | tt.check_pairs(isp.has_comment, tests) |
|
|||
123 |
|
||||
124 |
|
112 | |||
125 | def test_get_input_encoding(): |
|
113 | def test_get_input_encoding(): | |
126 | encoding = isp.get_input_encoding() |
|
114 | encoding = isp.get_input_encoding() | |
@@ -461,13 +449,16 b' class IPythonInputTestCase(InputSplitterTestCase):' | |||||
461 | def test_syntax_multiline(self): |
|
449 | def test_syntax_multiline(self): | |
462 | isp = self.isp |
|
450 | isp = self.isp | |
463 | for example in syntax_ml.itervalues(): |
|
451 | for example in syntax_ml.itervalues(): | |
464 | out_t_parts = [] |
|
|||
465 | raw_parts = [] |
|
|||
466 | for line_pairs in example: |
|
452 | for line_pairs in example: | |
|
453 | out_t_parts = [] | |||
|
454 | raw_parts = [] | |||
467 | for lraw, out_t_part in line_pairs: |
|
455 | for lraw, out_t_part in line_pairs: | |
468 | isp.push(lraw) |
|
456 | if out_t_part is not None: | |
469 | out_t_parts.append(out_t_part) |
|
457 | out_t_parts.append(out_t_part) | |
470 |
|
|
458 | ||
|
459 | if lraw is not None: | |||
|
460 | isp.push(lraw) | |||
|
461 | raw_parts.append(lraw) | |||
471 |
|
462 | |||
472 | out, out_raw = isp.source_raw_reset() |
|
463 | out, out_raw = isp.source_raw_reset() | |
473 | out_t = '\n'.join(out_t_parts).rstrip() |
|
464 | out_t = '\n'.join(out_t_parts).rstrip() | |
@@ -490,12 +481,10 b' class BlockIPythonInputTestCase(IPythonInputTestCase):' | |||||
490 | raw_parts = [] |
|
481 | raw_parts = [] | |
491 | out_t_parts = [] |
|
482 | out_t_parts = [] | |
492 | for line_pairs in example: |
|
483 | for line_pairs in example: | |
493 |
|
|
484 | raw_parts, out_t_parts = zip(*line_pairs) | |
494 | raw_parts.append(raw) |
|
|||
495 | out_t_parts.append(out_t_part) |
|
|||
496 |
|
485 | |||
497 | raw = '\n'.join(raw_parts) |
|
486 | raw = '\n'.join(r for r in raw_parts if r is not None) | |
498 | out_t = '\n'.join(out_t_parts) |
|
487 | out_t = '\n'.join(o for o in out_t_parts if o is not None) | |
499 |
|
488 | |||
500 | isp.push(raw) |
|
489 | isp.push(raw) | |
501 | out, out_raw = isp.source_raw_reset() |
|
490 | out, out_raw = isp.source_raw_reset() | |
@@ -509,8 +498,8 b' class BlockIPythonInputTestCase(IPythonInputTestCase):' | |||||
509 |
|
498 | |||
510 | out_t_parts = [] |
|
499 | out_t_parts = [] | |
511 | for line_pairs in example: |
|
500 | for line_pairs in example: | |
512 | raw = '\n'.join(r for r, _ in line_pairs) |
|
501 | raw = '\n'.join(r for r, _ in line_pairs if r is not None) | |
513 | out_t = '\n'.join(t for _,t in line_pairs) |
|
502 | out_t = '\n'.join(t for _,t in line_pairs if t is not None) | |
514 | out = isp.transform_cell(raw) |
|
503 | out = isp.transform_cell(raw) | |
515 | # Match ignoring trailing whitespace |
|
504 | # Match ignoring trailing whitespace | |
516 | self.assertEqual(out.rstrip(), out_t.rstrip()) |
|
505 | self.assertEqual(out.rstrip(), out_t.rstrip()) | |
@@ -595,9 +584,8 b' class CellMagicsCommon(object):' | |||||
595 | src = "%%cellm line\nbody\n" |
|
584 | src = "%%cellm line\nbody\n" | |
596 | sp = self.sp |
|
585 | sp = self.sp | |
597 | sp.push(src) |
|
586 | sp.push(src) | |
598 | nt.assert_equal(sp.cell_magic_parts, ['body\n']) |
|
587 | out = sp.source_reset() | |
599 | out = sp.source |
|
588 | ref = u"get_ipython().run_cell_magic({u}'cellm', {u}'line', {u}'body')\n" | |
600 | ref = u"get_ipython()._run_cached_cell_magic({u}'cellm', {u}'line')\n" |
|
|||
601 | nt.assert_equal(out, py3compat.u_format(ref)) |
|
589 | nt.assert_equal(out, py3compat.u_format(ref)) | |
602 |
|
590 | |||
603 | def tearDown(self): |
|
591 | def tearDown(self): |
@@ -8,6 +8,7 b' u_fmt = py3compat.u_format' | |||||
8 | from IPython.core import inputtransformer as ipt |
|
8 | from IPython.core import inputtransformer as ipt | |
9 |
|
9 | |||
10 | def transform_and_reset(transformer): |
|
10 | def transform_and_reset(transformer): | |
|
11 | transformer = transformer() | |||
11 | def transform(inp): |
|
12 | def transform(inp): | |
12 | try: |
|
13 | try: | |
13 | return transformer.push(inp) |
|
14 | return transformer.push(inp) | |
@@ -19,6 +20,7 b' def transform_and_reset(transformer):' | |||||
19 | # Transformer tests |
|
20 | # Transformer tests | |
20 | def transform_checker(tests, transformer): |
|
21 | def transform_checker(tests, transformer): | |
21 | """Utility to loop over test inputs""" |
|
22 | """Utility to loop over test inputs""" | |
|
23 | transformer = transformer() | |||
22 | try: |
|
24 | try: | |
23 | for inp, tr in tests: |
|
25 | for inp, tr in tests: | |
24 | nt.assert_equal(transformer.push(inp), tr) |
|
26 | nt.assert_equal(transformer.push(inp), tr) | |
@@ -191,7 +193,8 b' syntax_ml = \\' | |||||
191 |
|
193 | |||
192 | leading_indent = |
|
194 | leading_indent = | |
193 | [ [(' print "hi"','print "hi"'), |
|
195 | [ [(' print "hi"','print "hi"'), | |
194 | (' for a in range(5):','for a in range(5):'), |
|
196 | ], | |
|
197 | [(' for a in range(5):','for a in range(5):'), | |||
195 | (' a*2',' a*2'), |
|
198 | (' a*2',' a*2'), | |
196 | ], |
|
199 | ], | |
197 | [(' a="""','a="""'), |
|
200 | [(' a="""','a="""'), | |
@@ -203,12 +206,12 b' syntax_ml = \\' | |||||
203 | ], |
|
206 | ], | |
204 |
|
207 | |||
205 | cellmagic = |
|
208 | cellmagic = | |
206 | [ [('%%foo a', None), |
|
209 | [ [(u'%%foo a', None), | |
207 | (None, "get_ipython().run_cell_magic('foo', 'a', '')"), |
|
210 | (None, u_fmt("get_ipython().run_cell_magic({u}'foo', {u}'a', {u}'')")), | |
208 | ], |
|
211 | ], | |
209 | [('%%bar 123', None), |
|
212 | [(u'%%bar 123', None), | |
210 | ('hello', None), |
|
213 | (u'hello', None), | |
211 | ('', "get_ipython().run_cell_magic('bar', '123', 'hello')"), |
|
214 | (u'', u_fmt("get_ipython().run_cell_magic({u}'bar', {u}'123', {u}'hello')")), | |
212 | ], |
|
215 | ], | |
213 | ], |
|
216 | ], | |
214 |
|
217 | |||
@@ -223,22 +226,22 b' syntax_ml = \\' | |||||
223 | ], |
|
226 | ], | |
224 |
|
227 | |||
225 | assign_magic = |
|
228 | assign_magic = | |
226 | [ [('a = %bc de \\', None), |
|
229 | [ [(u'a = %bc de \\', None), | |
227 | ('fg', "a = get_ipython().magic('bc de fg')"), |
|
230 | (u'fg', u_fmt("a = get_ipython().magic({u}'bc de fg')")), | |
228 | ], |
|
231 | ], | |
229 | [('a = %bc de \\', None), |
|
232 | [(u'a = %bc de \\', None), | |
230 | ('fg\\', None), |
|
233 | (u'fg\\', None), | |
231 | (None, "a = get_ipython().magic('bc de fg')"), |
|
234 | (None, u_fmt("a = get_ipython().magic({u}'bc de fg')")), | |
232 | ], |
|
235 | ], | |
233 | ], |
|
236 | ], | |
234 |
|
237 | |||
235 | assign_system = |
|
238 | assign_system = | |
236 | [ [('a = !bc de \\', None), |
|
239 | [ [(u'a = !bc de \\', None), | |
237 | ('fg', "a = get_ipython().getoutput('bc de fg')"), |
|
240 | (u'fg', u_fmt("a = get_ipython().getoutput({u}'bc de fg')")), | |
238 | ], |
|
241 | ], | |
239 | [('a = !bc de \\', None), |
|
242 | [(u'a = !bc de \\', None), | |
240 | ('fg\\', None), |
|
243 | (u'fg\\', None), | |
241 | (None, "a = get_ipython().getoutput('bc de fg')"), |
|
244 | (None, u_fmt("a = get_ipython().getoutput({u}'bc de fg')")), | |
242 | ], |
|
245 | ], | |
243 | ], |
|
246 | ], | |
244 | ) |
|
247 | ) | |
@@ -259,6 +262,8 b' def test_classic_prompt():' | |||||
259 | tt.check_pairs(transform_and_reset(ipt.classic_prompt), syntax['classic_prompt']) |
|
262 | tt.check_pairs(transform_and_reset(ipt.classic_prompt), syntax['classic_prompt']) | |
260 | for example in syntax_ml['classic_prompt']: |
|
263 | for example in syntax_ml['classic_prompt']: | |
261 | transform_checker(example, ipt.classic_prompt) |
|
264 | transform_checker(example, ipt.classic_prompt) | |
|
265 | for example in syntax_ml['multiline_datastructure']: | |||
|
266 | transform_checker(example, ipt.classic_prompt) | |||
262 |
|
267 | |||
263 |
|
268 | |||
264 | def test_ipy_prompt(): |
|
269 | def test_ipy_prompt(): | |
@@ -303,3 +308,15 b' def test_escaped_multiline():' | |||||
303 | def test_cellmagic(): |
|
308 | def test_cellmagic(): | |
304 | for example in syntax_ml['cellmagic']: |
|
309 | for example in syntax_ml['cellmagic']: | |
305 | transform_checker(example, ipt.cellmagic) |
|
310 | transform_checker(example, ipt.cellmagic) | |
|
311 | ||||
|
312 | def test_has_comment(): | |||
|
313 | tests = [('text', False), | |||
|
314 | ('text #comment', True), | |||
|
315 | ('text #comment\n', True), | |||
|
316 | ('#comment', True), | |||
|
317 | ('#comment\n', True), | |||
|
318 | ('a = "#string"', False), | |||
|
319 | ('a = "#string" # comment', True), | |||
|
320 | ('a #comment not "string"', True), | |||
|
321 | ] | |||
|
322 | tt.check_pairs(ipt.has_comment, tests) |
General Comments 0
You need to be logged in to leave comments.
Login now