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