##// END OF EJS Templates
More whitespace between top level functions
Thomas Kluyver -
Show More
@@ -1,333 +1,336 b''
1 1 import abc
2 2 import re
3 3 from StringIO import StringIO
4 4 import tokenize
5 5
6 6 from IPython.core.splitinput import split_user_input, LineInfo
7 7
8 8 #-----------------------------------------------------------------------------
9 9 # Globals
10 10 #-----------------------------------------------------------------------------
11 11
12 12 # The escape sequences that define the syntax transformations IPython will
13 13 # apply to user input. These can NOT be just changed here: many regular
14 14 # expressions and other parts of the code may use their hardcoded values, and
15 15 # for all intents and purposes they constitute the 'IPython syntax', so they
16 16 # should be considered fixed.
17 17
18 18 ESC_SHELL = '!' # Send line to underlying system shell
19 19 ESC_SH_CAP = '!!' # Send line to system shell and capture output
20 20 ESC_HELP = '?' # Find information about object
21 21 ESC_HELP2 = '??' # Find extra-detailed information about object
22 22 ESC_MAGIC = '%' # Call magic function
23 23 ESC_MAGIC2 = '%%' # Call cell-magic function
24 24 ESC_QUOTE = ',' # Split args on whitespace, quote each as string and call
25 25 ESC_QUOTE2 = ';' # Quote all args as a single string, call
26 26 ESC_PAREN = '/' # Call first argument with rest of line as arguments
27 27
28 28 ESC_SEQUENCES = [ESC_SHELL, ESC_SH_CAP, ESC_HELP ,\
29 29 ESC_HELP2, ESC_MAGIC, ESC_MAGIC2,\
30 30 ESC_QUOTE, ESC_QUOTE2, ESC_PAREN ]
31 31
32 32
33
34 33 class InputTransformer(object):
35 34 __metaclass__ = abc.ABCMeta
36 35
37 36 @abc.abstractmethod
38 37 def push(self, line):
39 38 pass
40 39
41 40 @abc.abstractmethod
42 41 def reset(self):
43 42 pass
44 43
45 44 look_in_string = False
46 45
47 46 def stateless_input_transformer(func):
48 47 class StatelessInputTransformer(InputTransformer):
49 48 """Decorator for a stateless input transformer implemented as a function."""
50 49 def __init__(self):
51 50 self.func = func
52 51
53 52 def push(self, line):
54 53 return self.func(line)
55 54
56 55 def reset(self):
57 56 pass
58 57
59 58 return StatelessInputTransformer
60 59
61 60 def coroutine_input_transformer(coro):
62 61 class CoroutineInputTransformer(InputTransformer):
63 62 def __init__(self):
64 63 # Prime it
65 64 self.coro = coro()
66 65 next(self.coro)
67 66
68 67 def push(self, line):
69 68 return self.coro.send(line)
70 69
71 70 def reset(self):
72 71 return self.coro.send(None)
73 72
74 73 return CoroutineInputTransformer
75 74
76 75
77 76 # Utilities
78 77 def _make_help_call(target, esc, lspace, next_input=None):
79 78 """Prepares a pinfo(2)/psearch call from a target name and the escape
80 79 (i.e. ? or ??)"""
81 80 method = 'pinfo2' if esc == '??' \
82 81 else 'psearch' if '*' in target \
83 82 else 'pinfo'
84 83 arg = " ".join([method, target])
85 84 if next_input is None:
86 85 return '%sget_ipython().magic(%r)' % (lspace, arg)
87 86 else:
88 87 return '%sget_ipython().set_next_input(%r);get_ipython().magic(%r)' % \
89 88 (lspace, next_input, arg)
90 89
91 90 @coroutine_input_transformer
92 91 def escaped_transformer():
93 92 """Translate lines beginning with one of IPython's escape characters."""
94 93
95 94 # These define the transformations for the different escape characters.
96 95 def _tr_system(line_info):
97 96 "Translate lines escaped with: !"
98 97 cmd = line_info.line.lstrip().lstrip(ESC_SHELL)
99 98 return '%sget_ipython().system(%r)' % (line_info.pre, cmd)
100 99
101 100 def _tr_system2(line_info):
102 101 "Translate lines escaped with: !!"
103 102 cmd = line_info.line.lstrip()[2:]
104 103 return '%sget_ipython().getoutput(%r)' % (line_info.pre, cmd)
105 104
106 105 def _tr_help(line_info):
107 106 "Translate lines escaped with: ?/??"
108 107 # A naked help line should just fire the intro help screen
109 108 if not line_info.line[1:]:
110 109 return 'get_ipython().show_usage()'
111 110
112 111 return _make_help_call(line_info.ifun, line_info.esc, line_info.pre)
113 112
114 113 def _tr_magic(line_info):
115 114 "Translate lines escaped with: %"
116 115 tpl = '%sget_ipython().magic(%r)'
117 116 cmd = ' '.join([line_info.ifun, line_info.the_rest]).strip()
118 117 return tpl % (line_info.pre, cmd)
119 118
120 119 def _tr_quote(line_info):
121 120 "Translate lines escaped with: ,"
122 121 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
123 122 '", "'.join(line_info.the_rest.split()) )
124 123
125 124 def _tr_quote2(line_info):
126 125 "Translate lines escaped with: ;"
127 126 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
128 127 line_info.the_rest)
129 128
130 129 def _tr_paren(line_info):
131 130 "Translate lines escaped with: /"
132 131 return '%s%s(%s)' % (line_info.pre, line_info.ifun,
133 132 ", ".join(line_info.the_rest.split()))
134 133
135 134 tr = { ESC_SHELL : _tr_system,
136 135 ESC_SH_CAP : _tr_system2,
137 136 ESC_HELP : _tr_help,
138 137 ESC_HELP2 : _tr_help,
139 138 ESC_MAGIC : _tr_magic,
140 139 ESC_QUOTE : _tr_quote,
141 140 ESC_QUOTE2 : _tr_quote2,
142 141 ESC_PAREN : _tr_paren }
143 142
144 143 line = ''
145 144 while True:
146 145 line = (yield line)
147 146 if not line or line.isspace():
148 147 continue
149 148 lineinf = LineInfo(line)
150 149 if lineinf.esc not in tr:
151 150 continue
152 151
153 152 parts = []
154 153 while line is not None:
155 154 parts.append(line.rstrip('\\'))
156 155 if not line.endswith('\\'):
157 156 break
158 157 line = (yield None)
159 158
160 159 # Output
161 160 lineinf = LineInfo(' '.join(parts))
162 161 line = tr[lineinf.esc](lineinf)
163 162
164 163 _initial_space_re = re.compile(r'\s*')
165 164
166 165 _help_end_re = re.compile(r"""(%{0,2}
167 166 [a-zA-Z_*][\w*]* # Variable name
168 167 (\.[a-zA-Z_*][\w*]*)* # .etc.etc
169 168 )
170 169 (\?\??)$ # ? or ??""",
171 170 re.VERBOSE)
172 171
173 172 def has_comment(src):
174 173 """Indicate whether an input line has (i.e. ends in, or is) a comment.
175 174
176 175 This uses tokenize, so it can distinguish comments from # inside strings.
177 176
178 177 Parameters
179 178 ----------
180 179 src : string
181 180 A single line input string.
182 181
183 182 Returns
184 183 -------
185 184 Boolean: True if source has a comment.
186 185 """
187 186 readline = StringIO(src).readline
188 187 toktypes = set()
189 188 try:
190 189 for t in tokenize.generate_tokens(readline):
191 190 toktypes.add(t[0])
192 191 except tokenize.TokenError:
193 192 pass
194 193 return(tokenize.COMMENT in toktypes)
195 194
195
196 196 @stateless_input_transformer
197 197 def help_end(line):
198 198 """Translate lines with ?/?? at the end"""
199 199 m = _help_end_re.search(line)
200 200 if m is None or has_comment(line):
201 201 return line
202 202 target = m.group(1)
203 203 esc = m.group(3)
204 204 lspace = _initial_space_re.match(line).group(0)
205 205
206 206 # If we're mid-command, put it back on the next prompt for the user.
207 207 next_input = line.rstrip('?') if line.strip() != m.group(0) else None
208 208
209 209 return _make_help_call(target, esc, lspace, next_input)
210
211
210
211
212 212 @coroutine_input_transformer
213 213 def cellmagic():
214 214 tpl = 'get_ipython().run_cell_magic(%r, %r, %r)'
215 215 cellmagic_help_re = re.compile('%%\w+\?')
216 216 line = ''
217 217 while True:
218 218 line = (yield line)
219 219 if (not line) or (not line.startswith(ESC_MAGIC2)):
220 220 continue
221 221
222 222 if cellmagic_help_re.match(line):
223 223 # This case will be handled by help_end
224 224 continue
225 225
226 226 first = line
227 227 body = []
228 228 line = (yield None)
229 229 while (line is not None) and (line.strip() != ''):
230 230 body.append(line)
231 231 line = (yield None)
232 232
233 233 # Output
234 234 magic_name, _, first = first.partition(' ')
235 235 magic_name = magic_name.lstrip(ESC_MAGIC2)
236 236 line = tpl % (magic_name, first, u'\n'.join(body))
237 237
238
238 239 def _strip_prompts(prompt1_re, prompt2_re):
239 240 """Remove matching input prompts from a block of input."""
240 241 line = ''
241 242 while True:
242 243 line = (yield line)
243 244
244 245 if line is None:
245 246 continue
246 247
247 248 m = prompt1_re.match(line)
248 249 if m:
249 250 while m:
250 251 line = (yield line[len(m.group(0)):])
251 252 if line is None:
252 253 break
253 254 m = prompt2_re.match(line)
254 255 else:
255 256 # Prompts not in input - wait for reset
256 257 while line is not None:
257 258 line = (yield line)
258 259
259 260 @coroutine_input_transformer
260 261 def classic_prompt():
261 262 prompt1_re = re.compile(r'^(>>> )')
262 263 prompt2_re = re.compile(r'^(>>> |^\.\.\. )')
263 264 return _strip_prompts(prompt1_re, prompt2_re)
264 265
265 266 classic_prompt.look_in_string = True
266 267
267 268 @coroutine_input_transformer
268 269 def ipy_prompt():
269 270 prompt1_re = re.compile(r'^In \[\d+\]: ')
270 271 prompt2_re = re.compile(r'^(In \[\d+\]: |^\ \ \ \.\.\.+: )')
271 272 return _strip_prompts(prompt1_re, prompt2_re)
272 273
273 274 ipy_prompt.look_in_string = True
274 275
276
275 277 @coroutine_input_transformer
276 278 def leading_indent():
277 279 space_re = re.compile(r'^[ \t]+')
278 280 line = ''
279 281 while True:
280 282 line = (yield line)
281 283
282 284 if line is None:
283 285 continue
284 286
285 287 m = space_re.match(line)
286 288 if m:
287 289 space = m.group(0)
288 290 while line is not None:
289 291 if line.startswith(space):
290 292 line = line[len(space):]
291 293 line = (yield line)
292 294 else:
293 295 # No leading spaces - wait for reset
294 296 while line is not None:
295 297 line = (yield line)
296 298
297 299 leading_indent.look_in_string = True
298 300
301
299 302 def _special_assignment(assignment_re, template):
300 303 line = ''
301 304 while True:
302 305 line = (yield line)
303 306 if not line or line.isspace():
304 307 continue
305 308
306 309 m = assignment_re.match(line)
307 310 if not m:
308 311 continue
309 312
310 313 parts = []
311 314 while line is not None:
312 315 parts.append(line.rstrip('\\'))
313 316 if not line.endswith('\\'):
314 317 break
315 318 line = (yield None)
316 319
317 320 # Output
318 321 whole = assignment_re.match(' '.join(parts))
319 322 line = template % (whole.group('lhs'), whole.group('cmd'))
320 323
321 324 @coroutine_input_transformer
322 325 def assign_from_system():
323 326 assignment_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
324 327 r'\s*=\s*!\s*(?P<cmd>.*)')
325 328 template = '%s = get_ipython().getoutput(%r)'
326 329 return _special_assignment(assignment_re, template)
327 330
328 331 @coroutine_input_transformer
329 332 def assign_from_magic():
330 333 assignment_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
331 334 r'\s*=\s*%\s*(?P<cmd>.*)')
332 335 template = '%s = get_ipython().magic(%r)'
333 336 return _special_assignment(assignment_re, template)
General Comments 0
You need to be logged in to leave comments. Login now