Show More
@@ -1,4 +1,5 b'' | |||
|
1 | 1 | import abc |
|
2 | import functools | |
|
2 | 3 | import re |
|
3 | 4 | from StringIO import StringIO |
|
4 | 5 | import tokenize |
@@ -54,46 +55,60 b' class InputTransformer(object):' | |||
|
54 | 55 | |
|
55 | 56 | # Set this to True to allow the transformer to act on lines inside strings. |
|
56 | 57 | look_in_string = False |
|
57 | ||
|
58 | def stateless_input_transformer(func): | |
|
59 | class StatelessInputTransformer(InputTransformer): | |
|
60 | """Decorator for a stateless input transformer implemented as a function.""" | |
|
61 | def __init__(self): | |
|
62 | self.func = func | |
|
63 | ||
|
64 | def push(self, line): | |
|
65 | """Send a line of input to the transformer, returning the | |
|
66 | transformed input.""" | |
|
67 | return self.func(line) | |
|
68 | ||
|
69 | def reset(self): | |
|
70 | """No-op - exists for compatibility.""" | |
|
71 | pass | |
|
72 | 58 | |
|
73 | return StatelessInputTransformer | |
|
74 | ||
|
75 | def coroutine_input_transformer(coro): | |
|
76 | class CoroutineInputTransformer(InputTransformer): | |
|
77 | """Wrapper for input transformers based on coroutines.""" | |
|
78 | def __init__(self): | |
|
79 | # Prime it | |
|
80 |
|
|
|
81 | next(self.coro) | |
|
82 | ||
|
83 | def push(self, line): | |
|
84 | """Send a line of input to the transformer, returning the | |
|
85 | transformed input or None if the transformer is waiting for more | |
|
86 | input. | |
|
87 | """ | |
|
88 | return self.coro.send(line) | |
|
59 | @classmethod | |
|
60 | def wrap(cls, func): | |
|
61 | """Can be used by subclasses as a decorator, to return a factory that | |
|
62 | will allow instantiation with the decorated object. | |
|
63 | """ | |
|
64 | @functools.wraps(func) | |
|
65 | def transformer_factory(): | |
|
66 | transformer = cls(func) | |
|
67 | if getattr(transformer_factory, 'look_in_string', False): | |
|
68 | transformer.look_in_string = True | |
|
69 | return transformer | |
|
89 | 70 | |
|
90 | def reset(self): | |
|
91 | """Return, transformed any lines that the transformer has | |
|
92 | accumulated, and reset its internal state. | |
|
93 | """ | |
|
94 | return self.coro.send(None) | |
|
71 | return transformer_factory | |
|
72 | ||
|
73 | class StatelessInputTransformer(InputTransformer): | |
|
74 | """Wrapper for a stateless input transformer implemented as a function.""" | |
|
75 | def __init__(self, func): | |
|
76 | self.func = func | |
|
77 | ||
|
78 | def __repr__(self): | |
|
79 | return "StatelessInputTransformer(func={!r})".format(self.func) | |
|
95 | 80 | |
|
96 | return CoroutineInputTransformer | |
|
81 | def push(self, line): | |
|
82 | """Send a line of input to the transformer, returning the | |
|
83 | transformed input.""" | |
|
84 | return self.func(line) | |
|
85 | ||
|
86 | def reset(self): | |
|
87 | """No-op - exists for compatibility.""" | |
|
88 | pass | |
|
89 | ||
|
90 | class CoroutineInputTransformer(InputTransformer): | |
|
91 | """Wrapper for an input transformer implemented as a coroutine.""" | |
|
92 | def __init__(self, coro): | |
|
93 | # Prime it | |
|
94 | self.coro = coro() | |
|
95 | next(self.coro) | |
|
96 | ||
|
97 | def __repr__(self): | |
|
98 | return "CoroutineInputTransformer(coro={!r})".format(self.coro) | |
|
99 | ||
|
100 | def push(self, line): | |
|
101 | """Send a line of input to the transformer, returning the | |
|
102 | transformed input or None if the transformer is waiting for more | |
|
103 | input. | |
|
104 | """ | |
|
105 | return self.coro.send(line) | |
|
106 | ||
|
107 | def reset(self): | |
|
108 | """Return, transformed any lines that the transformer has | |
|
109 | accumulated, and reset its internal state. | |
|
110 | """ | |
|
111 | return self.coro.send(None) | |
|
97 | 112 | |
|
98 | 113 | |
|
99 | 114 | # Utilities |
@@ -110,7 +125,7 b' def _make_help_call(target, esc, lspace, next_input=None):' | |||
|
110 | 125 | return '%sget_ipython().set_next_input(%r);get_ipython().magic(%r)' % \ |
|
111 | 126 | (lspace, next_input, arg) |
|
112 | 127 | |
|
113 |
@ |
|
|
128 | @CoroutineInputTransformer.wrap | |
|
114 | 129 | def escaped_transformer(): |
|
115 | 130 | """Translate lines beginning with one of IPython's escape characters. |
|
116 | 131 | |
@@ -220,7 +235,7 b' def has_comment(src):' | |||
|
220 | 235 | return(tokenize.COMMENT in toktypes) |
|
221 | 236 | |
|
222 | 237 | |
|
223 |
@ |
|
|
238 | @StatelessInputTransformer.wrap | |
|
224 | 239 | def help_end(line): |
|
225 | 240 | """Translate lines with ?/?? at the end""" |
|
226 | 241 | m = _help_end_re.search(line) |
@@ -236,7 +251,7 b' def help_end(line):' | |||
|
236 | 251 | return _make_help_call(target, esc, lspace, next_input) |
|
237 | 252 | |
|
238 | 253 | |
|
239 |
@ |
|
|
254 | @CoroutineInputTransformer.wrap | |
|
240 | 255 | def cellmagic(): |
|
241 | 256 | """Captures & transforms cell magics. |
|
242 | 257 | |
@@ -289,7 +304,7 b' def _strip_prompts(prompt1_re, prompt2_re):' | |||
|
289 | 304 | while line is not None: |
|
290 | 305 | line = (yield line) |
|
291 | 306 | |
|
292 |
@ |
|
|
307 | @CoroutineInputTransformer.wrap | |
|
293 | 308 | def classic_prompt(): |
|
294 | 309 | """Strip the >>>/... prompts of the Python interactive shell.""" |
|
295 | 310 | prompt1_re = re.compile(r'^(>>> )') |
@@ -298,7 +313,7 b' def classic_prompt():' | |||
|
298 | 313 | |
|
299 | 314 | classic_prompt.look_in_string = True |
|
300 | 315 | |
|
301 |
@ |
|
|
316 | @CoroutineInputTransformer.wrap | |
|
302 | 317 | def ipy_prompt(): |
|
303 | 318 | """Strip IPython's In [1]:/...: prompts.""" |
|
304 | 319 | prompt1_re = re.compile(r'^In \[\d+\]: ') |
@@ -308,7 +323,7 b' def ipy_prompt():' | |||
|
308 | 323 | ipy_prompt.look_in_string = True |
|
309 | 324 | |
|
310 | 325 | |
|
311 |
@ |
|
|
326 | @CoroutineInputTransformer.wrap | |
|
312 | 327 | def leading_indent(): |
|
313 | 328 | """Remove leading indentation. |
|
314 | 329 | |
@@ -365,7 +380,7 b' def _special_assignment(assignment_re, template):' | |||
|
365 | 380 | whole = assignment_re.match(' '.join(parts)) |
|
366 | 381 | line = template % (whole.group('lhs'), whole.group('cmd')) |
|
367 | 382 | |
|
368 |
@ |
|
|
383 | @CoroutineInputTransformer.wrap | |
|
369 | 384 | def assign_from_system(): |
|
370 | 385 | """Transform assignment from system commands (e.g. files = !ls)""" |
|
371 | 386 | assignment_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))' |
@@ -373,7 +388,7 b' def assign_from_system():' | |||
|
373 | 388 | template = '%s = get_ipython().getoutput(%r)' |
|
374 | 389 | return _special_assignment(assignment_re, template) |
|
375 | 390 | |
|
376 |
@ |
|
|
391 | @CoroutineInputTransformer.wrap | |
|
377 | 392 | def assign_from_magic(): |
|
378 | 393 | """Transform assignment from magic commands (e.g. a = %who_ls)""" |
|
379 | 394 | assignment_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))' |
General Comments 0
You need to be logged in to leave comments.
Login now