##// END OF EJS Templates
Merge pull request #1019 from takluyver/repr-quotestring...
Fernando Perez -
r5356:268ecbec merge
parent child Browse files
Show More
@@ -1,178 +1,183 b''
1 1 # encoding: utf-8
2 2 """
3 3 Tests for IPython.config.configurable
4 4
5 5 Authors:
6 6
7 7 * Brian Granger
8 8 * Fernando Perez (design help)
9 9 """
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Copyright (C) 2008-2010 The IPython Development Team
13 13 #
14 14 # Distributed under the terms of the BSD License. The full license is in
15 15 # the file COPYING, distributed as part of this software.
16 16 #-----------------------------------------------------------------------------
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Imports
20 20 #-----------------------------------------------------------------------------
21 21
22 22 from unittest import TestCase
23 23
24 24 from IPython.config.configurable import (
25 25 Configurable,
26 26 SingletonConfigurable
27 27 )
28 28
29 29 from IPython.utils.traitlets import (
30 30 Integer, Float, Unicode
31 31 )
32 32
33 33 from IPython.config.loader import Config
34
34 from IPython.utils.py3compat import PY3
35 35
36 36 #-----------------------------------------------------------------------------
37 37 # Test cases
38 38 #-----------------------------------------------------------------------------
39 39
40 40
41 41 class MyConfigurable(Configurable):
42 42 a = Integer(1, config=True, help="The integer a.")
43 43 b = Float(1.0, config=True, help="The integer b.")
44 44 c = Unicode('no config')
45 45
46 46
47 47 mc_help=u"""MyConfigurable options
48 48 ----------------------
49 49 --MyConfigurable.a=<Integer>
50 50 Default: 1
51 51 The integer a.
52 52 --MyConfigurable.b=<Float>
53 53 Default: 1.0
54 54 The integer b."""
55 55
56 56 mc_help_inst=u"""MyConfigurable options
57 57 ----------------------
58 58 --MyConfigurable.a=<Integer>
59 59 Current: 5
60 60 The integer a.
61 61 --MyConfigurable.b=<Float>
62 62 Current: 4.0
63 63 The integer b."""
64 64
65 # On Python 3, the Integer trait is a synonym for Int
66 if PY3:
67 mc_help = mc_help.replace(u"<Integer>", u"<Int>")
68 mc_help_inst = mc_help_inst.replace(u"<Integer>", u"<Int>")
69
65 70 class Foo(Configurable):
66 71 a = Integer(0, config=True, help="The integer a.")
67 72 b = Unicode('nope', config=True)
68 73
69 74
70 75 class Bar(Foo):
71 76 b = Unicode('gotit', config=False, help="The string b.")
72 77 c = Float(config=True, help="The string c.")
73 78
74 79
75 80 class TestConfigurable(TestCase):
76 81
77 82 def test_default(self):
78 83 c1 = Configurable()
79 84 c2 = Configurable(config=c1.config)
80 85 c3 = Configurable(config=c2.config)
81 86 self.assertEquals(c1.config, c2.config)
82 87 self.assertEquals(c2.config, c3.config)
83 88
84 89 def test_custom(self):
85 90 config = Config()
86 91 config.foo = 'foo'
87 92 config.bar = 'bar'
88 93 c1 = Configurable(config=config)
89 94 c2 = Configurable(config=c1.config)
90 95 c3 = Configurable(config=c2.config)
91 96 self.assertEquals(c1.config, config)
92 97 self.assertEquals(c2.config, config)
93 98 self.assertEquals(c3.config, config)
94 99 # Test that copies are not made
95 100 self.assert_(c1.config is config)
96 101 self.assert_(c2.config is config)
97 102 self.assert_(c3.config is config)
98 103 self.assert_(c1.config is c2.config)
99 104 self.assert_(c2.config is c3.config)
100 105
101 106 def test_inheritance(self):
102 107 config = Config()
103 108 config.MyConfigurable.a = 2
104 109 config.MyConfigurable.b = 2.0
105 110 c1 = MyConfigurable(config=config)
106 111 c2 = MyConfigurable(config=c1.config)
107 112 self.assertEquals(c1.a, config.MyConfigurable.a)
108 113 self.assertEquals(c1.b, config.MyConfigurable.b)
109 114 self.assertEquals(c2.a, config.MyConfigurable.a)
110 115 self.assertEquals(c2.b, config.MyConfigurable.b)
111 116
112 117 def test_parent(self):
113 118 config = Config()
114 119 config.Foo.a = 10
115 120 config.Foo.b = "wow"
116 121 config.Bar.b = 'later'
117 122 config.Bar.c = 100.0
118 123 f = Foo(config=config)
119 124 b = Bar(config=f.config)
120 125 self.assertEquals(f.a, 10)
121 126 self.assertEquals(f.b, 'wow')
122 127 self.assertEquals(b.b, 'gotit')
123 128 self.assertEquals(b.c, 100.0)
124 129
125 130 def test_override1(self):
126 131 config = Config()
127 132 config.MyConfigurable.a = 2
128 133 config.MyConfigurable.b = 2.0
129 134 c = MyConfigurable(a=3, config=config)
130 135 self.assertEquals(c.a, 3)
131 136 self.assertEquals(c.b, config.MyConfigurable.b)
132 137 self.assertEquals(c.c, 'no config')
133 138
134 139 def test_override2(self):
135 140 config = Config()
136 141 config.Foo.a = 1
137 142 config.Bar.b = 'or' # Up above b is config=False, so this won't do it.
138 143 config.Bar.c = 10.0
139 144 c = Bar(config=config)
140 145 self.assertEquals(c.a, config.Foo.a)
141 146 self.assertEquals(c.b, 'gotit')
142 147 self.assertEquals(c.c, config.Bar.c)
143 148 c = Bar(a=2, b='and', c=20.0, config=config)
144 149 self.assertEquals(c.a, 2)
145 150 self.assertEquals(c.b, 'and')
146 151 self.assertEquals(c.c, 20.0)
147 152
148 153 def test_help(self):
149 154 self.assertEquals(MyConfigurable.class_get_help(), mc_help)
150 155
151 156 def test_help_inst(self):
152 157 inst = MyConfigurable(a=5, b=4)
153 158 self.assertEquals(MyConfigurable.class_get_help(inst), mc_help_inst)
154 159
155 160
156 161 class TestSingletonConfigurable(TestCase):
157 162
158 163 def test_instance(self):
159 164 from IPython.config.configurable import SingletonConfigurable
160 165 class Foo(SingletonConfigurable): pass
161 166 self.assertEquals(Foo.initialized(), False)
162 167 foo = Foo.instance()
163 168 self.assertEquals(Foo.initialized(), True)
164 169 self.assertEquals(foo, Foo.instance())
165 170 self.assertEquals(SingletonConfigurable._instance, None)
166 171
167 172 def test_inheritance(self):
168 173 class Bar(SingletonConfigurable): pass
169 174 class Bam(Bar): pass
170 175 self.assertEquals(Bar.initialized(), False)
171 176 self.assertEquals(Bam.initialized(), False)
172 177 bam = Bam.instance()
173 178 bam == Bar.instance()
174 179 self.assertEquals(Bar.initialized(), True)
175 180 self.assertEquals(Bam.initialized(), True)
176 181 self.assertEquals(bam, Bam._instance)
177 182 self.assertEquals(bam, Bar._instance)
178 183 self.assertEquals(SingletonConfigurable._instance, None)
@@ -1,773 +1,767 b''
1 1 """Analysis of text input into executable blocks.
2 2
3 3 The main class in this module, :class:`InputSplitter`, is designed to break
4 4 input from either interactive, line-by-line environments or block-based ones,
5 5 into standalone blocks that can be executed by Python as 'single' statements
6 6 (thus triggering sys.displayhook).
7 7
8 8 A companion, :class:`IPythonInputSplitter`, provides the same functionality but
9 9 with full support for the extended IPython syntax (magics, system calls, etc).
10 10
11 11 For more details, see the class docstring below.
12 12
13 13 Syntax Transformations
14 14 ----------------------
15 15
16 16 One of the main jobs of the code in this file is to apply all syntax
17 17 transformations that make up 'the IPython language', i.e. magics, shell
18 18 escapes, etc. All transformations should be implemented as *fully stateless*
19 19 entities, that simply take one line as their input and return a line.
20 20 Internally for implementation purposes they may be a normal function or a
21 21 callable object, but the only input they receive will be a single line and they
22 22 should only return a line, without holding any data-dependent state between
23 23 calls.
24 24
25 25 As an example, the EscapedTransformer is a class so we can more clearly group
26 26 together the functionality of dispatching to individual functions based on the
27 27 starting escape character, but the only method for public use is its call
28 28 method.
29 29
30 30
31 31 ToDo
32 32 ----
33 33
34 34 - Should we make push() actually raise an exception once push_accepts_more()
35 35 returns False?
36 36
37 37 - Naming cleanups. The tr_* names aren't the most elegant, though now they are
38 38 at least just attributes of a class so not really very exposed.
39 39
40 40 - Think about the best way to support dynamic things: automagic, autocall,
41 41 macros, etc.
42 42
43 43 - Think of a better heuristic for the application of the transforms in
44 44 IPythonInputSplitter.push() than looking at the buffer ending in ':'. Idea:
45 45 track indentation change events (indent, dedent, nothing) and apply them only
46 46 if the indentation went up, but not otherwise.
47 47
48 48 - Think of the cleanest way for supporting user-specified transformations (the
49 49 user prefilters we had before).
50 50
51 51 Authors
52 52 -------
53 53
54 54 * Fernando Perez
55 55 * Brian Granger
56 56 """
57 57 #-----------------------------------------------------------------------------
58 58 # Copyright (C) 2010 The IPython Development Team
59 59 #
60 60 # Distributed under the terms of the BSD License. The full license is in
61 61 # the file COPYING, distributed as part of this software.
62 62 #-----------------------------------------------------------------------------
63 63 from __future__ import print_function
64 64
65 65 #-----------------------------------------------------------------------------
66 66 # Imports
67 67 #-----------------------------------------------------------------------------
68 68 # stdlib
69 69 import ast
70 70 import codeop
71 71 import re
72 72 import sys
73 73 import tokenize
74 74 from StringIO import StringIO
75 75
76 76 # IPython modules
77 77 from IPython.core.splitinput import split_user_input, LineInfo
78 from IPython.utils.text import make_quoted_expr
79 78 from IPython.utils.py3compat import cast_unicode
80 79
81 80 #-----------------------------------------------------------------------------
82 81 # Globals
83 82 #-----------------------------------------------------------------------------
84 83
85 84 # The escape sequences that define the syntax transformations IPython will
86 85 # apply to user input. These can NOT be just changed here: many regular
87 86 # expressions and other parts of the code may use their hardcoded values, and
88 87 # for all intents and purposes they constitute the 'IPython syntax', so they
89 88 # should be considered fixed.
90 89
91 90 ESC_SHELL = '!' # Send line to underlying system shell
92 91 ESC_SH_CAP = '!!' # Send line to system shell and capture output
93 92 ESC_HELP = '?' # Find information about object
94 93 ESC_HELP2 = '??' # Find extra-detailed information about object
95 94 ESC_MAGIC = '%' # Call magic function
96 95 ESC_QUOTE = ',' # Split args on whitespace, quote each as string and call
97 96 ESC_QUOTE2 = ';' # Quote all args as a single string, call
98 97 ESC_PAREN = '/' # Call first argument with rest of line as arguments
99 98
100 99 #-----------------------------------------------------------------------------
101 100 # Utilities
102 101 #-----------------------------------------------------------------------------
103 102
104 103 # FIXME: These are general-purpose utilities that later can be moved to the
105 104 # general ward. Kept here for now because we're being very strict about test
106 105 # coverage with this code, and this lets us ensure that we keep 100% coverage
107 106 # while developing.
108 107
109 108 # compiled regexps for autoindent management
110 109 dedent_re = re.compile('|'.join([
111 110 r'^\s+raise(\s.*)?$', # raise statement (+ space + other stuff, maybe)
112 111 r'^\s+raise\([^\)]*\).*$', # wacky raise with immediate open paren
113 112 r'^\s+return(\s.*)?$', # normal return (+ space + other stuff, maybe)
114 113 r'^\s+return\([^\)]*\).*$', # wacky return with immediate open paren
115 114 r'^\s+pass\s*$' # pass (optionally followed by trailing spaces)
116 115 ]))
117 116 ini_spaces_re = re.compile(r'^([ \t\r\f\v]+)')
118 117
119 118 # regexp to match pure comment lines so we don't accidentally insert 'if 1:'
120 119 # before pure comments
121 120 comment_line_re = re.compile('^\s*\#')
122 121
123 122
124 123 def num_ini_spaces(s):
125 124 """Return the number of initial spaces in a string.
126 125
127 126 Note that tabs are counted as a single space. For now, we do *not* support
128 127 mixing of tabs and spaces in the user's input.
129 128
130 129 Parameters
131 130 ----------
132 131 s : string
133 132
134 133 Returns
135 134 -------
136 135 n : int
137 136 """
138 137
139 138 ini_spaces = ini_spaces_re.match(s)
140 139 if ini_spaces:
141 140 return ini_spaces.end()
142 141 else:
143 142 return 0
144 143
145 144
146 145 def remove_comments(src):
147 146 """Remove all comments from input source.
148 147
149 148 Note: comments are NOT recognized inside of strings!
150 149
151 150 Parameters
152 151 ----------
153 152 src : string
154 153 A single or multiline input string.
155 154
156 155 Returns
157 156 -------
158 157 String with all Python comments removed.
159 158 """
160 159
161 160 return re.sub('#.*', '', src)
162 161
163 162 def has_comment(src):
164 163 """Indicate whether an input line has (i.e. ends in, or is) a comment.
165 164
166 165 This uses tokenize, so it can distinguish comments from # inside strings.
167 166
168 167 Parameters
169 168 ----------
170 169 src : string
171 170 A single line input string.
172 171
173 172 Returns
174 173 -------
175 174 Boolean: True if source has a comment.
176 175 """
177 176 readline = StringIO(src).readline
178 177 toktypes = set()
179 178 try:
180 179 for t in tokenize.generate_tokens(readline):
181 180 toktypes.add(t[0])
182 181 except tokenize.TokenError:
183 182 pass
184 183 return(tokenize.COMMENT in toktypes)
185 184
186 185
187 186 def get_input_encoding():
188 187 """Return the default standard input encoding.
189 188
190 189 If sys.stdin has no encoding, 'ascii' is returned."""
191 190 # There are strange environments for which sys.stdin.encoding is None. We
192 191 # ensure that a valid encoding is returned.
193 192 encoding = getattr(sys.stdin, 'encoding', None)
194 193 if encoding is None:
195 194 encoding = 'ascii'
196 195 return encoding
197 196
198 197 #-----------------------------------------------------------------------------
199 198 # Classes and functions for normal Python syntax handling
200 199 #-----------------------------------------------------------------------------
201 200
202 201 class InputSplitter(object):
203 202 """An object that can accumulate lines of Python source before execution.
204 203
205 204 This object is designed to be fed python source line-by-line, using
206 205 :meth:`push`. It will return on each push whether the currently pushed
207 206 code could be executed already. In addition, it provides a method called
208 207 :meth:`push_accepts_more` that can be used to query whether more input
209 208 can be pushed into a single interactive block.
210 209
211 210 This is a simple example of how an interactive terminal-based client can use
212 211 this tool::
213 212
214 213 isp = InputSplitter()
215 214 while isp.push_accepts_more():
216 215 indent = ' '*isp.indent_spaces
217 216 prompt = '>>> ' + indent
218 217 line = indent + raw_input(prompt)
219 218 isp.push(line)
220 219 print 'Input source was:\n', isp.source_reset(),
221 220 """
222 221 # Number of spaces of indentation computed from input that has been pushed
223 222 # so far. This is the attributes callers should query to get the current
224 223 # indentation level, in order to provide auto-indent facilities.
225 224 indent_spaces = 0
226 225 # String, indicating the default input encoding. It is computed by default
227 226 # at initialization time via get_input_encoding(), but it can be reset by a
228 227 # client with specific knowledge of the encoding.
229 228 encoding = ''
230 229 # String where the current full source input is stored, properly encoded.
231 230 # Reading this attribute is the normal way of querying the currently pushed
232 231 # source code, that has been properly encoded.
233 232 source = ''
234 233 # Code object corresponding to the current source. It is automatically
235 234 # synced to the source, so it can be queried at any time to obtain the code
236 235 # object; it will be None if the source doesn't compile to valid Python.
237 236 code = None
238 237 # Input mode
239 238 input_mode = 'line'
240 239
241 240 # Private attributes
242 241
243 242 # List with lines of input accumulated so far
244 243 _buffer = None
245 244 # Command compiler
246 245 _compile = None
247 246 # Mark when input has changed indentation all the way back to flush-left
248 247 _full_dedent = False
249 248 # Boolean indicating whether the current block is complete
250 249 _is_complete = None
251 250
252 251 def __init__(self, input_mode=None):
253 252 """Create a new InputSplitter instance.
254 253
255 254 Parameters
256 255 ----------
257 256 input_mode : str
258 257
259 258 One of ['line', 'cell']; default is 'line'.
260 259
261 260 The input_mode parameter controls how new inputs are used when fed via
262 261 the :meth:`push` method:
263 262
264 263 - 'line': meant for line-oriented clients, inputs are appended one at a
265 264 time to the internal buffer and the whole buffer is compiled.
266 265
267 266 - 'cell': meant for clients that can edit multi-line 'cells' of text at
268 267 a time. A cell can contain one or more blocks that can be compile in
269 268 'single' mode by Python. In this mode, each new input new input
270 269 completely replaces all prior inputs. Cell mode is thus equivalent
271 270 to prepending a full reset() to every push() call.
272 271 """
273 272 self._buffer = []
274 273 self._compile = codeop.CommandCompiler()
275 274 self.encoding = get_input_encoding()
276 275 self.input_mode = InputSplitter.input_mode if input_mode is None \
277 276 else input_mode
278 277
279 278 def reset(self):
280 279 """Reset the input buffer and associated state."""
281 280 self.indent_spaces = 0
282 281 self._buffer[:] = []
283 282 self.source = ''
284 283 self.code = None
285 284 self._is_complete = False
286 285 self._full_dedent = False
287 286
288 287 def source_reset(self):
289 288 """Return the input source and perform a full reset.
290 289 """
291 290 out = self.source
292 291 self.reset()
293 292 return out
294 293
295 294 def push(self, lines):
296 295 """Push one or more lines of input.
297 296
298 297 This stores the given lines and returns a status code indicating
299 298 whether the code forms a complete Python block or not.
300 299
301 300 Any exceptions generated in compilation are swallowed, but if an
302 301 exception was produced, the method returns True.
303 302
304 303 Parameters
305 304 ----------
306 305 lines : string
307 306 One or more lines of Python input.
308 307
309 308 Returns
310 309 -------
311 310 is_complete : boolean
312 311 True if the current input source (the result of the current input
313 312 plus prior inputs) forms a complete Python execution block. Note that
314 313 this value is also stored as a private attribute (_is_complete), so it
315 314 can be queried at any time.
316 315 """
317 316 if self.input_mode == 'cell':
318 317 self.reset()
319 318
320 319 self._store(lines)
321 320 source = self.source
322 321
323 322 # Before calling _compile(), reset the code object to None so that if an
324 323 # exception is raised in compilation, we don't mislead by having
325 324 # inconsistent code/source attributes.
326 325 self.code, self._is_complete = None, None
327 326
328 327 # Honor termination lines properly
329 328 if source.rstrip().endswith('\\'):
330 329 return False
331 330
332 331 self._update_indent(lines)
333 332 try:
334 333 self.code = self._compile(source, symbol="exec")
335 334 # Invalid syntax can produce any of a number of different errors from
336 335 # inside the compiler, so we have to catch them all. Syntax errors
337 336 # immediately produce a 'ready' block, so the invalid Python can be
338 337 # sent to the kernel for evaluation with possible ipython
339 338 # special-syntax conversion.
340 339 except (SyntaxError, OverflowError, ValueError, TypeError,
341 340 MemoryError):
342 341 self._is_complete = True
343 342 else:
344 343 # Compilation didn't produce any exceptions (though it may not have
345 344 # given a complete code object)
346 345 self._is_complete = self.code is not None
347 346
348 347 return self._is_complete
349 348
350 349 def push_accepts_more(self):
351 350 """Return whether a block of interactive input can accept more input.
352 351
353 352 This method is meant to be used by line-oriented frontends, who need to
354 353 guess whether a block is complete or not based solely on prior and
355 354 current input lines. The InputSplitter considers it has a complete
356 355 interactive block and will not accept more input only when either a
357 356 SyntaxError is raised, or *all* of the following are true:
358 357
359 358 1. The input compiles to a complete statement.
360 359
361 360 2. The indentation level is flush-left (because if we are indented,
362 361 like inside a function definition or for loop, we need to keep
363 362 reading new input).
364 363
365 364 3. There is one extra line consisting only of whitespace.
366 365
367 366 Because of condition #3, this method should be used only by
368 367 *line-oriented* frontends, since it means that intermediate blank lines
369 368 are not allowed in function definitions (or any other indented block).
370 369
371 370 If the current input produces a syntax error, this method immediately
372 371 returns False but does *not* raise the syntax error exception, as
373 372 typically clients will want to send invalid syntax to an execution
374 373 backend which might convert the invalid syntax into valid Python via
375 374 one of the dynamic IPython mechanisms.
376 375 """
377 376
378 377 # With incomplete input, unconditionally accept more
379 378 if not self._is_complete:
380 379 return True
381 380
382 381 # If we already have complete input and we're flush left, the answer
383 382 # depends. In line mode, if there hasn't been any indentation,
384 383 # that's it. If we've come back from some indentation, we need
385 384 # the blank final line to finish.
386 385 # In cell mode, we need to check how many blocks the input so far
387 386 # compiles into, because if there's already more than one full
388 387 # independent block of input, then the client has entered full
389 388 # 'cell' mode and is feeding lines that each is complete. In this
390 389 # case we should then keep accepting. The Qt terminal-like console
391 390 # does precisely this, to provide the convenience of terminal-like
392 391 # input of single expressions, but allowing the user (with a
393 392 # separate keystroke) to switch to 'cell' mode and type multiple
394 393 # expressions in one shot.
395 394 if self.indent_spaces==0:
396 395 if self.input_mode=='line':
397 396 if not self._full_dedent:
398 397 return False
399 398 else:
400 399 try:
401 400 code_ast = ast.parse(u''.join(self._buffer))
402 401 except Exception:
403 402 return False
404 403 else:
405 404 if len(code_ast.body) == 1:
406 405 return False
407 406
408 407 # When input is complete, then termination is marked by an extra blank
409 408 # line at the end.
410 409 last_line = self.source.splitlines()[-1]
411 410 return bool(last_line and not last_line.isspace())
412 411
413 412 #------------------------------------------------------------------------
414 413 # Private interface
415 414 #------------------------------------------------------------------------
416 415
417 416 def _find_indent(self, line):
418 417 """Compute the new indentation level for a single line.
419 418
420 419 Parameters
421 420 ----------
422 421 line : str
423 422 A single new line of non-whitespace, non-comment Python input.
424 423
425 424 Returns
426 425 -------
427 426 indent_spaces : int
428 427 New value for the indent level (it may be equal to self.indent_spaces
429 428 if indentation doesn't change.
430 429
431 430 full_dedent : boolean
432 431 Whether the new line causes a full flush-left dedent.
433 432 """
434 433 indent_spaces = self.indent_spaces
435 434 full_dedent = self._full_dedent
436 435
437 436 inisp = num_ini_spaces(line)
438 437 if inisp < indent_spaces:
439 438 indent_spaces = inisp
440 439 if indent_spaces <= 0:
441 440 #print 'Full dedent in text',self.source # dbg
442 441 full_dedent = True
443 442
444 443 if line.rstrip()[-1] == ':':
445 444 indent_spaces += 4
446 445 elif dedent_re.match(line):
447 446 indent_spaces -= 4
448 447 if indent_spaces <= 0:
449 448 full_dedent = True
450 449
451 450 # Safety
452 451 if indent_spaces < 0:
453 452 indent_spaces = 0
454 453 #print 'safety' # dbg
455 454
456 455 return indent_spaces, full_dedent
457 456
458 457 def _update_indent(self, lines):
459 458 for line in remove_comments(lines).splitlines():
460 459 if line and not line.isspace():
461 460 self.indent_spaces, self._full_dedent = self._find_indent(line)
462 461
463 462 def _store(self, lines, buffer=None, store='source'):
464 463 """Store one or more lines of input.
465 464
466 465 If input lines are not newline-terminated, a newline is automatically
467 466 appended."""
468 467
469 468 if buffer is None:
470 469 buffer = self._buffer
471 470
472 471 if lines.endswith('\n'):
473 472 buffer.append(lines)
474 473 else:
475 474 buffer.append(lines+'\n')
476 475 setattr(self, store, self._set_source(buffer))
477 476
478 477 def _set_source(self, buffer):
479 478 return u''.join(buffer)
480 479
481 480
482 481 #-----------------------------------------------------------------------------
483 482 # Functions and classes for IPython-specific syntactic support
484 483 #-----------------------------------------------------------------------------
485 484
486 485 # The escaped translators ALL receive a line where their own escape has been
487 486 # stripped. Only '?' is valid at the end of the line, all others can only be
488 487 # placed at the start.
489 488
490 489 # Transformations of the special syntaxes that don't rely on an explicit escape
491 490 # character but instead on patterns on the input line
492 491
493 492 # The core transformations are implemented as standalone functions that can be
494 493 # tested and validated in isolation. Each of these uses a regexp, we
495 494 # pre-compile these and keep them close to each function definition for clarity
496 495
497 496 _assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
498 497 r'\s*=\s*!\s*(?P<cmd>.*)')
499 498
500 499 def transform_assign_system(line):
501 500 """Handle the `files = !ls` syntax."""
502 501 m = _assign_system_re.match(line)
503 502 if m is not None:
504 503 cmd = m.group('cmd')
505 504 lhs = m.group('lhs')
506 expr = make_quoted_expr(cmd)
507 new_line = '%s = get_ipython().getoutput(%s)' % (lhs, expr)
505 new_line = '%s = get_ipython().getoutput(%r)' % (lhs, cmd)
508 506 return new_line
509 507 return line
510 508
511 509
512 510 _assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
513 511 r'\s*=\s*%\s*(?P<cmd>.*)')
514 512
515 513 def transform_assign_magic(line):
516 514 """Handle the `a = %who` syntax."""
517 515 m = _assign_magic_re.match(line)
518 516 if m is not None:
519 517 cmd = m.group('cmd')
520 518 lhs = m.group('lhs')
521 expr = make_quoted_expr(cmd)
522 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
519 new_line = '%s = get_ipython().magic(%r)' % (lhs, cmd)
523 520 return new_line
524 521 return line
525 522
526 523
527 524 _classic_prompt_re = re.compile(r'^([ \t]*>>> |^[ \t]*\.\.\. )')
528 525
529 526 def transform_classic_prompt(line):
530 527 """Handle inputs that start with '>>> ' syntax."""
531 528
532 529 if not line or line.isspace():
533 530 return line
534 531 m = _classic_prompt_re.match(line)
535 532 if m:
536 533 return line[len(m.group(0)):]
537 534 else:
538 535 return line
539 536
540 537
541 538 _ipy_prompt_re = re.compile(r'^([ \t]*In \[\d+\]: |^[ \t]*\ \ \ \.\.\.+: )')
542 539
543 540 def transform_ipy_prompt(line):
544 541 """Handle inputs that start classic IPython prompt syntax."""
545 542
546 543 if not line or line.isspace():
547 544 return line
548 545 #print 'LINE: %r' % line # dbg
549 546 m = _ipy_prompt_re.match(line)
550 547 if m:
551 548 #print 'MATCH! %r -> %r' % (line, line[len(m.group(0)):]) # dbg
552 549 return line[len(m.group(0)):]
553 550 else:
554 551 return line
555 552
556 553
557 554 def _make_help_call(target, esc, lspace, next_input=None):
558 555 """Prepares a pinfo(2)/psearch call from a target name and the escape
559 556 (i.e. ? or ??)"""
560 557 method = 'pinfo2' if esc == '??' \
561 558 else 'psearch' if '*' in target \
562 559 else 'pinfo'
563 arg = make_quoted_expr(" ".join([method, target]))
560 arg = " ".join([method, target])
564 561
565 562 if next_input:
566 tpl = '%sget_ipython().magic(%s, next_input=%s)'
567 return tpl % (lspace, arg, make_quoted_expr(next_input))
563 tpl = '%sget_ipython().magic(%r, next_input=%r)'
564 return tpl % (lspace, arg, next_input)
568 565 else:
569 return '%sget_ipython().magic(%s)' % (lspace, arg)
566 return '%sget_ipython().magic(%r)' % (lspace, arg)
570 567
571 568 _initial_space_re = re.compile(r'\s*')
572 569 _help_end_re = re.compile(r"""(%?
573 570 [a-zA-Z_*][\w*]* # Variable name
574 571 (\.[a-zA-Z_*][\w*]*)* # .etc.etc
575 572 )
576 573 (\?\??)$ # ? or ??""",
577 574 re.VERBOSE)
578 575 def transform_help_end(line):
579 576 """Translate lines with ?/?? at the end"""
580 577 m = _help_end_re.search(line)
581 578 if m is None or has_comment(line):
582 579 return line
583 580 target = m.group(1)
584 581 esc = m.group(3)
585 582 lspace = _initial_space_re.match(line).group(0)
586 583
587 584 # If we're mid-command, put it back on the next prompt for the user.
588 585 next_input = line.rstrip('?') if line.strip() != m.group(0) else None
589 586
590 587 return _make_help_call(target, esc, lspace, next_input)
591 588
592 589
593 590 class EscapedTransformer(object):
594 591 """Class to transform lines that are explicitly escaped out."""
595 592
596 593 def __init__(self):
597 594 tr = { ESC_SHELL : self._tr_system,
598 595 ESC_SH_CAP : self._tr_system2,
599 596 ESC_HELP : self._tr_help,
600 597 ESC_HELP2 : self._tr_help,
601 598 ESC_MAGIC : self._tr_magic,
602 599 ESC_QUOTE : self._tr_quote,
603 600 ESC_QUOTE2 : self._tr_quote2,
604 601 ESC_PAREN : self._tr_paren }
605 602 self.tr = tr
606 603
607 604 # Support for syntax transformations that use explicit escapes typed by the
608 605 # user at the beginning of a line
609 606 @staticmethod
610 607 def _tr_system(line_info):
611 608 "Translate lines escaped with: !"
612 609 cmd = line_info.line.lstrip().lstrip(ESC_SHELL)
613 return '%sget_ipython().system(%s)' % (line_info.pre,
614 make_quoted_expr(cmd))
610 return '%sget_ipython().system(%r)' % (line_info.pre, cmd)
615 611
616 612 @staticmethod
617 613 def _tr_system2(line_info):
618 614 "Translate lines escaped with: !!"
619 615 cmd = line_info.line.lstrip()[2:]
620 return '%sget_ipython().getoutput(%s)' % (line_info.pre,
621 make_quoted_expr(cmd))
616 return '%sget_ipython().getoutput(%r)' % (line_info.pre, cmd)
622 617
623 618 @staticmethod
624 619 def _tr_help(line_info):
625 620 "Translate lines escaped with: ?/??"
626 621 # A naked help line should just fire the intro help screen
627 622 if not line_info.line[1:]:
628 623 return 'get_ipython().show_usage()'
629 624
630 625 return _make_help_call(line_info.ifun, line_info.esc, line_info.pre)
631 626
632 627 @staticmethod
633 628 def _tr_magic(line_info):
634 629 "Translate lines escaped with: %"
635 tpl = '%sget_ipython().magic(%s)'
636 cmd = make_quoted_expr(' '.join([line_info.ifun,
637 line_info.the_rest]).strip())
630 tpl = '%sget_ipython().magic(%r)'
631 cmd = ' '.join([line_info.ifun, line_info.the_rest]).strip()
638 632 return tpl % (line_info.pre, cmd)
639 633
640 634 @staticmethod
641 635 def _tr_quote(line_info):
642 636 "Translate lines escaped with: ,"
643 637 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
644 638 '", "'.join(line_info.the_rest.split()) )
645 639
646 640 @staticmethod
647 641 def _tr_quote2(line_info):
648 642 "Translate lines escaped with: ;"
649 643 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
650 644 line_info.the_rest)
651 645
652 646 @staticmethod
653 647 def _tr_paren(line_info):
654 648 "Translate lines escaped with: /"
655 649 return '%s%s(%s)' % (line_info.pre, line_info.ifun,
656 650 ", ".join(line_info.the_rest.split()))
657 651
658 652 def __call__(self, line):
659 653 """Class to transform lines that are explicitly escaped out.
660 654
661 655 This calls the above _tr_* static methods for the actual line
662 656 translations."""
663 657
664 658 # Empty lines just get returned unmodified
665 659 if not line or line.isspace():
666 660 return line
667 661
668 662 # Get line endpoints, where the escapes can be
669 663 line_info = LineInfo(line)
670 664
671 665 if not line_info.esc in self.tr:
672 666 # If we don't recognize the escape, don't modify the line
673 667 return line
674 668
675 669 return self.tr[line_info.esc](line_info)
676 670
677 671
678 672 # A function-looking object to be used by the rest of the code. The purpose of
679 673 # the class in this case is to organize related functionality, more than to
680 674 # manage state.
681 675 transform_escaped = EscapedTransformer()
682 676
683 677
684 678 class IPythonInputSplitter(InputSplitter):
685 679 """An input splitter that recognizes all of IPython's special syntax."""
686 680
687 681 # String with raw, untransformed input.
688 682 source_raw = ''
689 683
690 684 # Private attributes
691 685
692 686 # List with lines of raw input accumulated so far.
693 687 _buffer_raw = None
694 688
695 689 def __init__(self, input_mode=None):
696 690 InputSplitter.__init__(self, input_mode)
697 691 self._buffer_raw = []
698 692
699 693 def reset(self):
700 694 """Reset the input buffer and associated state."""
701 695 InputSplitter.reset(self)
702 696 self._buffer_raw[:] = []
703 697 self.source_raw = ''
704 698
705 699 def source_raw_reset(self):
706 700 """Return input and raw source and perform a full reset.
707 701 """
708 702 out = self.source
709 703 out_r = self.source_raw
710 704 self.reset()
711 705 return out, out_r
712 706
713 707 def push(self, lines):
714 708 """Push one or more lines of IPython input.
715 709 """
716 710 if not lines:
717 711 return super(IPythonInputSplitter, self).push(lines)
718 712
719 713 # We must ensure all input is pure unicode
720 714 lines = cast_unicode(lines, self.encoding)
721 715
722 716 lines_list = lines.splitlines()
723 717
724 718 transforms = [transform_ipy_prompt, transform_classic_prompt,
725 719 transform_help_end, transform_escaped,
726 720 transform_assign_system, transform_assign_magic]
727 721
728 722 # Transform logic
729 723 #
730 724 # We only apply the line transformers to the input if we have either no
731 725 # input yet, or complete input, or if the last line of the buffer ends
732 726 # with ':' (opening an indented block). This prevents the accidental
733 727 # transformation of escapes inside multiline expressions like
734 728 # triple-quoted strings or parenthesized expressions.
735 729 #
736 730 # The last heuristic, while ugly, ensures that the first line of an
737 731 # indented block is correctly transformed.
738 732 #
739 733 # FIXME: try to find a cleaner approach for this last bit.
740 734
741 735 # If we were in 'block' mode, since we're going to pump the parent
742 736 # class by hand line by line, we need to temporarily switch out to
743 737 # 'line' mode, do a single manual reset and then feed the lines one
744 738 # by one. Note that this only matters if the input has more than one
745 739 # line.
746 740 changed_input_mode = False
747 741
748 742 if self.input_mode == 'cell':
749 743 self.reset()
750 744 changed_input_mode = True
751 745 saved_input_mode = 'cell'
752 746 self.input_mode = 'line'
753 747
754 748 # Store raw source before applying any transformations to it. Note
755 749 # that this must be done *after* the reset() call that would otherwise
756 750 # flush the buffer.
757 751 self._store(lines, self._buffer_raw, 'source_raw')
758 752
759 753 try:
760 754 push = super(IPythonInputSplitter, self).push
761 755 buf = self._buffer
762 756 for line in lines_list:
763 757 if self._is_complete or not buf or \
764 758 (buf and (buf[-1].rstrip().endswith(':') or
765 759 buf[-1].rstrip().endswith(',')) ):
766 760 for f in transforms:
767 761 line = f(line)
768 762
769 763 out = push(line)
770 764 finally:
771 765 if changed_input_mode:
772 766 self.input_mode = saved_input_mode
773 767 return out
@@ -1,950 +1,946 b''
1 1 # encoding: utf-8
2 2 """
3 3 Prefiltering components.
4 4
5 5 Prefilters transform user input before it is exec'd by Python. These
6 6 transforms are used to implement additional syntax such as !ls and %magic.
7 7
8 8 Authors:
9 9
10 10 * Brian Granger
11 11 * Fernando Perez
12 12 * Dan Milstein
13 13 * Ville Vainio
14 14 """
15 15
16 16 #-----------------------------------------------------------------------------
17 17 # Copyright (C) 2008-2009 The IPython Development Team
18 18 #
19 19 # Distributed under the terms of the BSD License. The full license is in
20 20 # the file COPYING, distributed as part of this software.
21 21 #-----------------------------------------------------------------------------
22 22
23 23 #-----------------------------------------------------------------------------
24 24 # Imports
25 25 #-----------------------------------------------------------------------------
26 26
27 27 import __builtin__
28 28 import codeop
29 29 import re
30 30
31 31 from IPython.core.alias import AliasManager
32 32 from IPython.core.autocall import IPyAutocall
33 33 from IPython.config.configurable import Configurable
34 34 from IPython.core.macro import Macro
35 35 from IPython.core.splitinput import split_user_input, LineInfo
36 36 from IPython.core import page
37 37
38 38 from IPython.utils.traitlets import List, Integer, Any, Unicode, CBool, Bool, Instance
39 from IPython.utils.text import make_quoted_expr
40 39 from IPython.utils.autoattr import auto_attr
41 40
42 41 #-----------------------------------------------------------------------------
43 42 # Global utilities, errors and constants
44 43 #-----------------------------------------------------------------------------
45 44
46 45 # Warning, these cannot be changed unless various regular expressions
47 46 # are updated in a number of places. Not great, but at least we told you.
48 47 ESC_SHELL = '!'
49 48 ESC_SH_CAP = '!!'
50 49 ESC_HELP = '?'
51 50 ESC_MAGIC = '%'
52 51 ESC_QUOTE = ','
53 52 ESC_QUOTE2 = ';'
54 53 ESC_PAREN = '/'
55 54
56 55
57 56 class PrefilterError(Exception):
58 57 pass
59 58
60 59
61 60 # RegExp to identify potential function names
62 61 re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$')
63 62
64 63 # RegExp to exclude strings with this start from autocalling. In
65 64 # particular, all binary operators should be excluded, so that if foo is
66 65 # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
67 66 # characters '!=()' don't need to be checked for, as the checkPythonChars
68 67 # routine explicitely does so, to catch direct calls and rebindings of
69 68 # existing names.
70 69
71 70 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
72 71 # it affects the rest of the group in square brackets.
73 72 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
74 73 r'|^is |^not |^in |^and |^or ')
75 74
76 75 # try to catch also methods for stuff in lists/tuples/dicts: off
77 76 # (experimental). For this to work, the line_split regexp would need
78 77 # to be modified so it wouldn't break things at '['. That line is
79 78 # nasty enough that I shouldn't change it until I can test it _well_.
80 79 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
81 80
82 81
83 82 # Handler Check Utilities
84 83 def is_shadowed(identifier, ip):
85 84 """Is the given identifier defined in one of the namespaces which shadow
86 85 the alias and magic namespaces? Note that an identifier is different
87 86 than ifun, because it can not contain a '.' character."""
88 87 # This is much safer than calling ofind, which can change state
89 88 return (identifier in ip.user_ns \
90 89 or identifier in ip.internal_ns \
91 90 or identifier in ip.ns_table['builtin'])
92 91
93 92
94 93 #-----------------------------------------------------------------------------
95 94 # Main Prefilter manager
96 95 #-----------------------------------------------------------------------------
97 96
98 97
99 98 class PrefilterManager(Configurable):
100 99 """Main prefilter component.
101 100
102 101 The IPython prefilter is run on all user input before it is run. The
103 102 prefilter consumes lines of input and produces transformed lines of
104 103 input.
105 104
106 105 The iplementation consists of two phases:
107 106
108 107 1. Transformers
109 108 2. Checkers and handlers
110 109
111 110 Over time, we plan on deprecating the checkers and handlers and doing
112 111 everything in the transformers.
113 112
114 113 The transformers are instances of :class:`PrefilterTransformer` and have
115 114 a single method :meth:`transform` that takes a line and returns a
116 115 transformed line. The transformation can be accomplished using any
117 116 tool, but our current ones use regular expressions for speed. We also
118 117 ship :mod:`pyparsing` in :mod:`IPython.external` for use in transformers.
119 118
120 119 After all the transformers have been run, the line is fed to the checkers,
121 120 which are instances of :class:`PrefilterChecker`. The line is passed to
122 121 the :meth:`check` method, which either returns `None` or a
123 122 :class:`PrefilterHandler` instance. If `None` is returned, the other
124 123 checkers are tried. If an :class:`PrefilterHandler` instance is returned,
125 124 the line is passed to the :meth:`handle` method of the returned
126 125 handler and no further checkers are tried.
127 126
128 127 Both transformers and checkers have a `priority` attribute, that determines
129 128 the order in which they are called. Smaller priorities are tried first.
130 129
131 130 Both transformers and checkers also have `enabled` attribute, which is
132 131 a boolean that determines if the instance is used.
133 132
134 133 Users or developers can change the priority or enabled attribute of
135 134 transformers or checkers, but they must call the :meth:`sort_checkers`
136 135 or :meth:`sort_transformers` method after changing the priority.
137 136 """
138 137
139 138 multi_line_specials = CBool(True, config=True)
140 139 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
141 140
142 141 def __init__(self, shell=None, config=None):
143 142 super(PrefilterManager, self).__init__(shell=shell, config=config)
144 143 self.shell = shell
145 144 self.init_transformers()
146 145 self.init_handlers()
147 146 self.init_checkers()
148 147
149 148 #-------------------------------------------------------------------------
150 149 # API for managing transformers
151 150 #-------------------------------------------------------------------------
152 151
153 152 def init_transformers(self):
154 153 """Create the default transformers."""
155 154 self._transformers = []
156 155 for transformer_cls in _default_transformers:
157 156 transformer_cls(
158 157 shell=self.shell, prefilter_manager=self, config=self.config
159 158 )
160 159
161 160 def sort_transformers(self):
162 161 """Sort the transformers by priority.
163 162
164 163 This must be called after the priority of a transformer is changed.
165 164 The :meth:`register_transformer` method calls this automatically.
166 165 """
167 166 self._transformers.sort(key=lambda x: x.priority)
168 167
169 168 @property
170 169 def transformers(self):
171 170 """Return a list of checkers, sorted by priority."""
172 171 return self._transformers
173 172
174 173 def register_transformer(self, transformer):
175 174 """Register a transformer instance."""
176 175 if transformer not in self._transformers:
177 176 self._transformers.append(transformer)
178 177 self.sort_transformers()
179 178
180 179 def unregister_transformer(self, transformer):
181 180 """Unregister a transformer instance."""
182 181 if transformer in self._transformers:
183 182 self._transformers.remove(transformer)
184 183
185 184 #-------------------------------------------------------------------------
186 185 # API for managing checkers
187 186 #-------------------------------------------------------------------------
188 187
189 188 def init_checkers(self):
190 189 """Create the default checkers."""
191 190 self._checkers = []
192 191 for checker in _default_checkers:
193 192 checker(
194 193 shell=self.shell, prefilter_manager=self, config=self.config
195 194 )
196 195
197 196 def sort_checkers(self):
198 197 """Sort the checkers by priority.
199 198
200 199 This must be called after the priority of a checker is changed.
201 200 The :meth:`register_checker` method calls this automatically.
202 201 """
203 202 self._checkers.sort(key=lambda x: x.priority)
204 203
205 204 @property
206 205 def checkers(self):
207 206 """Return a list of checkers, sorted by priority."""
208 207 return self._checkers
209 208
210 209 def register_checker(self, checker):
211 210 """Register a checker instance."""
212 211 if checker not in self._checkers:
213 212 self._checkers.append(checker)
214 213 self.sort_checkers()
215 214
216 215 def unregister_checker(self, checker):
217 216 """Unregister a checker instance."""
218 217 if checker in self._checkers:
219 218 self._checkers.remove(checker)
220 219
221 220 #-------------------------------------------------------------------------
222 221 # API for managing checkers
223 222 #-------------------------------------------------------------------------
224 223
225 224 def init_handlers(self):
226 225 """Create the default handlers."""
227 226 self._handlers = {}
228 227 self._esc_handlers = {}
229 228 for handler in _default_handlers:
230 229 handler(
231 230 shell=self.shell, prefilter_manager=self, config=self.config
232 231 )
233 232
234 233 @property
235 234 def handlers(self):
236 235 """Return a dict of all the handlers."""
237 236 return self._handlers
238 237
239 238 def register_handler(self, name, handler, esc_strings):
240 239 """Register a handler instance by name with esc_strings."""
241 240 self._handlers[name] = handler
242 241 for esc_str in esc_strings:
243 242 self._esc_handlers[esc_str] = handler
244 243
245 244 def unregister_handler(self, name, handler, esc_strings):
246 245 """Unregister a handler instance by name with esc_strings."""
247 246 try:
248 247 del self._handlers[name]
249 248 except KeyError:
250 249 pass
251 250 for esc_str in esc_strings:
252 251 h = self._esc_handlers.get(esc_str)
253 252 if h is handler:
254 253 del self._esc_handlers[esc_str]
255 254
256 255 def get_handler_by_name(self, name):
257 256 """Get a handler by its name."""
258 257 return self._handlers.get(name)
259 258
260 259 def get_handler_by_esc(self, esc_str):
261 260 """Get a handler by its escape string."""
262 261 return self._esc_handlers.get(esc_str)
263 262
264 263 #-------------------------------------------------------------------------
265 264 # Main prefiltering API
266 265 #-------------------------------------------------------------------------
267 266
268 267 def prefilter_line_info(self, line_info):
269 268 """Prefilter a line that has been converted to a LineInfo object.
270 269
271 270 This implements the checker/handler part of the prefilter pipe.
272 271 """
273 272 # print "prefilter_line_info: ", line_info
274 273 handler = self.find_handler(line_info)
275 274 return handler.handle(line_info)
276 275
277 276 def find_handler(self, line_info):
278 277 """Find a handler for the line_info by trying checkers."""
279 278 for checker in self.checkers:
280 279 if checker.enabled:
281 280 handler = checker.check(line_info)
282 281 if handler:
283 282 return handler
284 283 return self.get_handler_by_name('normal')
285 284
286 285 def transform_line(self, line, continue_prompt):
287 286 """Calls the enabled transformers in order of increasing priority."""
288 287 for transformer in self.transformers:
289 288 if transformer.enabled:
290 289 line = transformer.transform(line, continue_prompt)
291 290 return line
292 291
293 292 def prefilter_line(self, line, continue_prompt=False):
294 293 """Prefilter a single input line as text.
295 294
296 295 This method prefilters a single line of text by calling the
297 296 transformers and then the checkers/handlers.
298 297 """
299 298
300 299 # print "prefilter_line: ", line, continue_prompt
301 300 # All handlers *must* return a value, even if it's blank ('').
302 301
303 302 # save the line away in case we crash, so the post-mortem handler can
304 303 # record it
305 304 self.shell._last_input_line = line
306 305
307 306 if not line:
308 307 # Return immediately on purely empty lines, so that if the user
309 308 # previously typed some whitespace that started a continuation
310 309 # prompt, he can break out of that loop with just an empty line.
311 310 # This is how the default python prompt works.
312 311 return ''
313 312
314 313 # At this point, we invoke our transformers.
315 314 if not continue_prompt or (continue_prompt and self.multi_line_specials):
316 315 line = self.transform_line(line, continue_prompt)
317 316
318 317 # Now we compute line_info for the checkers and handlers
319 318 line_info = LineInfo(line, continue_prompt)
320 319
321 320 # the input history needs to track even empty lines
322 321 stripped = line.strip()
323 322
324 323 normal_handler = self.get_handler_by_name('normal')
325 324 if not stripped:
326 325 if not continue_prompt:
327 326 self.shell.displayhook.prompt_count -= 1
328 327
329 328 return normal_handler.handle(line_info)
330 329
331 330 # special handlers are only allowed for single line statements
332 331 if continue_prompt and not self.multi_line_specials:
333 332 return normal_handler.handle(line_info)
334 333
335 334 prefiltered = self.prefilter_line_info(line_info)
336 335 # print "prefiltered line: %r" % prefiltered
337 336 return prefiltered
338 337
339 338 def prefilter_lines(self, lines, continue_prompt=False):
340 339 """Prefilter multiple input lines of text.
341 340
342 341 This is the main entry point for prefiltering multiple lines of
343 342 input. This simply calls :meth:`prefilter_line` for each line of
344 343 input.
345 344
346 345 This covers cases where there are multiple lines in the user entry,
347 346 which is the case when the user goes back to a multiline history
348 347 entry and presses enter.
349 348 """
350 349 llines = lines.rstrip('\n').split('\n')
351 350 # We can get multiple lines in one shot, where multiline input 'blends'
352 351 # into one line, in cases like recalling from the readline history
353 352 # buffer. We need to make sure that in such cases, we correctly
354 353 # communicate downstream which line is first and which are continuation
355 354 # ones.
356 355 if len(llines) > 1:
357 356 out = '\n'.join([self.prefilter_line(line, lnum>0)
358 357 for lnum, line in enumerate(llines) ])
359 358 else:
360 359 out = self.prefilter_line(llines[0], continue_prompt)
361 360
362 361 return out
363 362
364 363 #-----------------------------------------------------------------------------
365 364 # Prefilter transformers
366 365 #-----------------------------------------------------------------------------
367 366
368 367
369 368 class PrefilterTransformer(Configurable):
370 369 """Transform a line of user input."""
371 370
372 371 priority = Integer(100, config=True)
373 372 # Transformers don't currently use shell or prefilter_manager, but as we
374 373 # move away from checkers and handlers, they will need them.
375 374 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
376 375 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
377 376 enabled = Bool(True, config=True)
378 377
379 378 def __init__(self, shell=None, prefilter_manager=None, config=None):
380 379 super(PrefilterTransformer, self).__init__(
381 380 shell=shell, prefilter_manager=prefilter_manager, config=config
382 381 )
383 382 self.prefilter_manager.register_transformer(self)
384 383
385 384 def transform(self, line, continue_prompt):
386 385 """Transform a line, returning the new one."""
387 386 return None
388 387
389 388 def __repr__(self):
390 389 return "<%s(priority=%r, enabled=%r)>" % (
391 390 self.__class__.__name__, self.priority, self.enabled)
392 391
393 392
394 393 _assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
395 394 r'\s*=\s*!(?P<cmd>.*)')
396 395
397 396
398 397 class AssignSystemTransformer(PrefilterTransformer):
399 398 """Handle the `files = !ls` syntax."""
400 399
401 400 priority = Integer(100, config=True)
402 401
403 402 def transform(self, line, continue_prompt):
404 403 m = _assign_system_re.match(line)
405 404 if m is not None:
406 405 cmd = m.group('cmd')
407 406 lhs = m.group('lhs')
408 expr = make_quoted_expr("sc =%s" % cmd)
409 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
407 expr = "sc =%s" % cmd
408 new_line = '%s = get_ipython().magic(%r)' % (lhs, expr)
410 409 return new_line
411 410 return line
412 411
413 412
414 413 _assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
415 414 r'\s*=\s*%(?P<cmd>.*)')
416 415
417 416 class AssignMagicTransformer(PrefilterTransformer):
418 417 """Handle the `a = %who` syntax."""
419 418
420 419 priority = Integer(200, config=True)
421 420
422 421 def transform(self, line, continue_prompt):
423 422 m = _assign_magic_re.match(line)
424 423 if m is not None:
425 424 cmd = m.group('cmd')
426 425 lhs = m.group('lhs')
427 expr = make_quoted_expr(cmd)
428 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
426 new_line = '%s = get_ipython().magic(%r)' % (lhs, cmd)
429 427 return new_line
430 428 return line
431 429
432 430
433 431 _classic_prompt_re = re.compile(r'(^[ \t]*>>> |^[ \t]*\.\.\. )')
434 432
435 433 class PyPromptTransformer(PrefilterTransformer):
436 434 """Handle inputs that start with '>>> ' syntax."""
437 435
438 436 priority = Integer(50, config=True)
439 437
440 438 def transform(self, line, continue_prompt):
441 439
442 440 if not line or line.isspace() or line.strip() == '...':
443 441 # This allows us to recognize multiple input prompts separated by
444 442 # blank lines and pasted in a single chunk, very common when
445 443 # pasting doctests or long tutorial passages.
446 444 return ''
447 445 m = _classic_prompt_re.match(line)
448 446 if m:
449 447 return line[len(m.group(0)):]
450 448 else:
451 449 return line
452 450
453 451
454 452 _ipy_prompt_re = re.compile(r'(^[ \t]*In \[\d+\]: |^[ \t]*\ \ \ \.\.\.+: )')
455 453
456 454 class IPyPromptTransformer(PrefilterTransformer):
457 455 """Handle inputs that start classic IPython prompt syntax."""
458 456
459 457 priority = Integer(50, config=True)
460 458
461 459 def transform(self, line, continue_prompt):
462 460
463 461 if not line or line.isspace() or line.strip() == '...':
464 462 # This allows us to recognize multiple input prompts separated by
465 463 # blank lines and pasted in a single chunk, very common when
466 464 # pasting doctests or long tutorial passages.
467 465 return ''
468 466 m = _ipy_prompt_re.match(line)
469 467 if m:
470 468 return line[len(m.group(0)):]
471 469 else:
472 470 return line
473 471
474 472 #-----------------------------------------------------------------------------
475 473 # Prefilter checkers
476 474 #-----------------------------------------------------------------------------
477 475
478 476
479 477 class PrefilterChecker(Configurable):
480 478 """Inspect an input line and return a handler for that line."""
481 479
482 480 priority = Integer(100, config=True)
483 481 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
484 482 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
485 483 enabled = Bool(True, config=True)
486 484
487 485 def __init__(self, shell=None, prefilter_manager=None, config=None):
488 486 super(PrefilterChecker, self).__init__(
489 487 shell=shell, prefilter_manager=prefilter_manager, config=config
490 488 )
491 489 self.prefilter_manager.register_checker(self)
492 490
493 491 def check(self, line_info):
494 492 """Inspect line_info and return a handler instance or None."""
495 493 return None
496 494
497 495 def __repr__(self):
498 496 return "<%s(priority=%r, enabled=%r)>" % (
499 497 self.__class__.__name__, self.priority, self.enabled)
500 498
501 499
502 500 class EmacsChecker(PrefilterChecker):
503 501
504 502 priority = Integer(100, config=True)
505 503 enabled = Bool(False, config=True)
506 504
507 505 def check(self, line_info):
508 506 "Emacs ipython-mode tags certain input lines."
509 507 if line_info.line.endswith('# PYTHON-MODE'):
510 508 return self.prefilter_manager.get_handler_by_name('emacs')
511 509 else:
512 510 return None
513 511
514 512
515 513 class ShellEscapeChecker(PrefilterChecker):
516 514
517 515 priority = Integer(200, config=True)
518 516
519 517 def check(self, line_info):
520 518 if line_info.line.lstrip().startswith(ESC_SHELL):
521 519 return self.prefilter_manager.get_handler_by_name('shell')
522 520
523 521
524 522 class MacroChecker(PrefilterChecker):
525 523
526 524 priority = Integer(250, config=True)
527 525
528 526 def check(self, line_info):
529 527 obj = self.shell.user_ns.get(line_info.ifun)
530 528 if isinstance(obj, Macro):
531 529 return self.prefilter_manager.get_handler_by_name('macro')
532 530 else:
533 531 return None
534 532
535 533
536 534 class IPyAutocallChecker(PrefilterChecker):
537 535
538 536 priority = Integer(300, config=True)
539 537
540 538 def check(self, line_info):
541 539 "Instances of IPyAutocall in user_ns get autocalled immediately"
542 540 obj = self.shell.user_ns.get(line_info.ifun, None)
543 541 if isinstance(obj, IPyAutocall):
544 542 obj.set_ip(self.shell)
545 543 return self.prefilter_manager.get_handler_by_name('auto')
546 544 else:
547 545 return None
548 546
549 547
550 548 class MultiLineMagicChecker(PrefilterChecker):
551 549
552 550 priority = Integer(400, config=True)
553 551
554 552 def check(self, line_info):
555 553 "Allow ! and !! in multi-line statements if multi_line_specials is on"
556 554 # Note that this one of the only places we check the first character of
557 555 # ifun and *not* the pre_char. Also note that the below test matches
558 556 # both ! and !!.
559 557 if line_info.continue_prompt \
560 558 and self.prefilter_manager.multi_line_specials:
561 559 if line_info.esc == ESC_MAGIC:
562 560 return self.prefilter_manager.get_handler_by_name('magic')
563 561 else:
564 562 return None
565 563
566 564
567 565 class EscCharsChecker(PrefilterChecker):
568 566
569 567 priority = Integer(500, config=True)
570 568
571 569 def check(self, line_info):
572 570 """Check for escape character and return either a handler to handle it,
573 571 or None if there is no escape char."""
574 572 if line_info.line[-1] == ESC_HELP \
575 573 and line_info.esc != ESC_SHELL \
576 574 and line_info.esc != ESC_SH_CAP:
577 575 # the ? can be at the end, but *not* for either kind of shell escape,
578 576 # because a ? can be a vaild final char in a shell cmd
579 577 return self.prefilter_manager.get_handler_by_name('help')
580 578 else:
581 579 if line_info.pre:
582 580 return None
583 581 # This returns None like it should if no handler exists
584 582 return self.prefilter_manager.get_handler_by_esc(line_info.esc)
585 583
586 584
587 585 class AssignmentChecker(PrefilterChecker):
588 586
589 587 priority = Integer(600, config=True)
590 588
591 589 def check(self, line_info):
592 590 """Check to see if user is assigning to a var for the first time, in
593 591 which case we want to avoid any sort of automagic / autocall games.
594 592
595 593 This allows users to assign to either alias or magic names true python
596 594 variables (the magic/alias systems always take second seat to true
597 595 python code). E.g. ls='hi', or ls,that=1,2"""
598 596 if line_info.the_rest:
599 597 if line_info.the_rest[0] in '=,':
600 598 return self.prefilter_manager.get_handler_by_name('normal')
601 599 else:
602 600 return None
603 601
604 602
605 603 class AutoMagicChecker(PrefilterChecker):
606 604
607 605 priority = Integer(700, config=True)
608 606
609 607 def check(self, line_info):
610 608 """If the ifun is magic, and automagic is on, run it. Note: normal,
611 609 non-auto magic would already have been triggered via '%' in
612 610 check_esc_chars. This just checks for automagic. Also, before
613 611 triggering the magic handler, make sure that there is nothing in the
614 612 user namespace which could shadow it."""
615 613 if not self.shell.automagic or not hasattr(self.shell,'magic_'+line_info.ifun):
616 614 return None
617 615
618 616 # We have a likely magic method. Make sure we should actually call it.
619 617 if line_info.continue_prompt and not self.prefilter_manager.multi_line_specials:
620 618 return None
621 619
622 620 head = line_info.ifun.split('.',1)[0]
623 621 if is_shadowed(head, self.shell):
624 622 return None
625 623
626 624 return self.prefilter_manager.get_handler_by_name('magic')
627 625
628 626
629 627 class AliasChecker(PrefilterChecker):
630 628
631 629 priority = Integer(800, config=True)
632 630
633 631 def check(self, line_info):
634 632 "Check if the initital identifier on the line is an alias."
635 633 # Note: aliases can not contain '.'
636 634 head = line_info.ifun.split('.',1)[0]
637 635 if line_info.ifun not in self.shell.alias_manager \
638 636 or head not in self.shell.alias_manager \
639 637 or is_shadowed(head, self.shell):
640 638 return None
641 639
642 640 return self.prefilter_manager.get_handler_by_name('alias')
643 641
644 642
645 643 class PythonOpsChecker(PrefilterChecker):
646 644
647 645 priority = Integer(900, config=True)
648 646
649 647 def check(self, line_info):
650 648 """If the 'rest' of the line begins with a function call or pretty much
651 649 any python operator, we should simply execute the line (regardless of
652 650 whether or not there's a possible autocall expansion). This avoids
653 651 spurious (and very confusing) geattr() accesses."""
654 652 if line_info.the_rest and line_info.the_rest[0] in '!=()<>,+*/%^&|':
655 653 return self.prefilter_manager.get_handler_by_name('normal')
656 654 else:
657 655 return None
658 656
659 657
660 658 class AutocallChecker(PrefilterChecker):
661 659
662 660 priority = Integer(1000, config=True)
663 661
664 662 def check(self, line_info):
665 663 "Check if the initial word/function is callable and autocall is on."
666 664 if not self.shell.autocall:
667 665 return None
668 666
669 667 oinfo = line_info.ofind(self.shell) # This can mutate state via getattr
670 668 if not oinfo['found']:
671 669 return None
672 670
673 671 if callable(oinfo['obj']) \
674 672 and (not re_exclude_auto.match(line_info.the_rest)) \
675 673 and re_fun_name.match(line_info.ifun):
676 674 return self.prefilter_manager.get_handler_by_name('auto')
677 675 else:
678 676 return None
679 677
680 678
681 679 #-----------------------------------------------------------------------------
682 680 # Prefilter handlers
683 681 #-----------------------------------------------------------------------------
684 682
685 683
686 684 class PrefilterHandler(Configurable):
687 685
688 686 handler_name = Unicode('normal')
689 687 esc_strings = List([])
690 688 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
691 689 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
692 690
693 691 def __init__(self, shell=None, prefilter_manager=None, config=None):
694 692 super(PrefilterHandler, self).__init__(
695 693 shell=shell, prefilter_manager=prefilter_manager, config=config
696 694 )
697 695 self.prefilter_manager.register_handler(
698 696 self.handler_name,
699 697 self,
700 698 self.esc_strings
701 699 )
702 700
703 701 def handle(self, line_info):
704 702 # print "normal: ", line_info
705 703 """Handle normal input lines. Use as a template for handlers."""
706 704
707 705 # With autoindent on, we need some way to exit the input loop, and I
708 706 # don't want to force the user to have to backspace all the way to
709 707 # clear the line. The rule will be in this case, that either two
710 708 # lines of pure whitespace in a row, or a line of pure whitespace but
711 709 # of a size different to the indent level, will exit the input loop.
712 710 line = line_info.line
713 711 continue_prompt = line_info.continue_prompt
714 712
715 713 if (continue_prompt and
716 714 self.shell.autoindent and
717 715 line.isspace() and
718 716 0 < abs(len(line) - self.shell.indent_current_nsp) <= 2):
719 717 line = ''
720 718
721 719 return line
722 720
723 721 def __str__(self):
724 722 return "<%s(name=%s)>" % (self.__class__.__name__, self.handler_name)
725 723
726 724
727 725 class AliasHandler(PrefilterHandler):
728 726
729 727 handler_name = Unicode('alias')
730 728
731 729 def handle(self, line_info):
732 730 """Handle alias input lines. """
733 731 transformed = self.shell.alias_manager.expand_aliases(line_info.ifun,line_info.the_rest)
734 732 # pre is needed, because it carries the leading whitespace. Otherwise
735 733 # aliases won't work in indented sections.
736 line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace,
737 make_quoted_expr(transformed))
734 line_out = '%sget_ipython().system(%r)' % (line_info.pre_whitespace, transformed)
738 735
739 736 return line_out
740 737
741 738
742 739 class ShellEscapeHandler(PrefilterHandler):
743 740
744 741 handler_name = Unicode('shell')
745 742 esc_strings = List([ESC_SHELL, ESC_SH_CAP])
746 743
747 744 def handle(self, line_info):
748 745 """Execute the line in a shell, empty return value"""
749 746 magic_handler = self.prefilter_manager.get_handler_by_name('magic')
750 747
751 748 line = line_info.line
752 749 if line.lstrip().startswith(ESC_SH_CAP):
753 750 # rewrite LineInfo's line, ifun and the_rest to properly hold the
754 751 # call to %sx and the actual command to be executed, so
755 752 # handle_magic can work correctly. Note that this works even if
756 753 # the line is indented, so it handles multi_line_specials
757 754 # properly.
758 755 new_rest = line.lstrip()[2:]
759 756 line_info.line = '%ssx %s' % (ESC_MAGIC, new_rest)
760 757 line_info.ifun = 'sx'
761 758 line_info.the_rest = new_rest
762 759 return magic_handler.handle(line_info)
763 760 else:
764 761 cmd = line.lstrip().lstrip(ESC_SHELL)
765 line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace,
766 make_quoted_expr(cmd))
762 line_out = '%sget_ipython().system(%r)' % (line_info.pre_whitespace, cmd)
767 763 return line_out
768 764
769 765
770 766 class MacroHandler(PrefilterHandler):
771 767 handler_name = Unicode("macro")
772 768
773 769 def handle(self, line_info):
774 770 obj = self.shell.user_ns.get(line_info.ifun)
775 771 pre_space = line_info.pre_whitespace
776 772 line_sep = "\n" + pre_space
777 773 return pre_space + line_sep.join(obj.value.splitlines())
778 774
779 775
780 776 class MagicHandler(PrefilterHandler):
781 777
782 778 handler_name = Unicode('magic')
783 779 esc_strings = List([ESC_MAGIC])
784 780
785 781 def handle(self, line_info):
786 782 """Execute magic functions."""
787 783 ifun = line_info.ifun
788 784 the_rest = line_info.the_rest
789 cmd = '%sget_ipython().magic(%s)' % (line_info.pre_whitespace,
790 make_quoted_expr(ifun + " " + the_rest))
785 cmd = '%sget_ipython().magic(%r)' % (line_info.pre_whitespace,
786 (ifun + " " + the_rest))
791 787 return cmd
792 788
793 789
794 790 class AutoHandler(PrefilterHandler):
795 791
796 792 handler_name = Unicode('auto')
797 793 esc_strings = List([ESC_PAREN, ESC_QUOTE, ESC_QUOTE2])
798 794
799 795 def handle(self, line_info):
800 796 """Handle lines which can be auto-executed, quoting if requested."""
801 797 line = line_info.line
802 798 ifun = line_info.ifun
803 799 the_rest = line_info.the_rest
804 800 pre = line_info.pre
805 801 esc = line_info.esc
806 802 continue_prompt = line_info.continue_prompt
807 803 obj = line_info.ofind(self)['obj']
808 804 #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun,the_rest) # dbg
809 805
810 806 # This should only be active for single-line input!
811 807 if continue_prompt:
812 808 return line
813 809
814 810 force_auto = isinstance(obj, IPyAutocall)
815 811
816 812 # User objects sometimes raise exceptions on attribute access other
817 813 # than AttributeError (we've seen it in the past), so it's safest to be
818 814 # ultra-conservative here and catch all.
819 815 try:
820 816 auto_rewrite = obj.rewrite
821 817 except Exception:
822 818 auto_rewrite = True
823 819
824 820 if esc == ESC_QUOTE:
825 821 # Auto-quote splitting on whitespace
826 822 newcmd = '%s("%s")' % (ifun,'", "'.join(the_rest.split()) )
827 823 elif esc == ESC_QUOTE2:
828 824 # Auto-quote whole string
829 825 newcmd = '%s("%s")' % (ifun,the_rest)
830 826 elif esc == ESC_PAREN:
831 827 newcmd = '%s(%s)' % (ifun,",".join(the_rest.split()))
832 828 else:
833 829 # Auto-paren.
834 830 # We only apply it to argument-less calls if the autocall
835 831 # parameter is set to 2. We only need to check that autocall is <
836 832 # 2, since this function isn't called unless it's at least 1.
837 833 if not the_rest and (self.shell.autocall < 2) and not force_auto:
838 834 newcmd = '%s %s' % (ifun,the_rest)
839 835 auto_rewrite = False
840 836 else:
841 837 if not force_auto and the_rest.startswith('['):
842 838 if hasattr(obj,'__getitem__'):
843 839 # Don't autocall in this case: item access for an object
844 840 # which is BOTH callable and implements __getitem__.
845 841 newcmd = '%s %s' % (ifun,the_rest)
846 842 auto_rewrite = False
847 843 else:
848 844 # if the object doesn't support [] access, go ahead and
849 845 # autocall
850 846 newcmd = '%s(%s)' % (ifun.rstrip(),the_rest)
851 847 elif the_rest.endswith(';'):
852 848 newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1])
853 849 else:
854 850 newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
855 851
856 852 if auto_rewrite:
857 853 self.shell.auto_rewrite_input(newcmd)
858 854
859 855 return newcmd
860 856
861 857
862 858 class HelpHandler(PrefilterHandler):
863 859
864 860 handler_name = Unicode('help')
865 861 esc_strings = List([ESC_HELP])
866 862
867 863 def handle(self, line_info):
868 864 """Try to get some help for the object.
869 865
870 866 obj? or ?obj -> basic information.
871 867 obj?? or ??obj -> more details.
872 868 """
873 869 normal_handler = self.prefilter_manager.get_handler_by_name('normal')
874 870 line = line_info.line
875 871 # We need to make sure that we don't process lines which would be
876 872 # otherwise valid python, such as "x=1 # what?"
877 873 try:
878 874 codeop.compile_command(line)
879 875 except SyntaxError:
880 876 # We should only handle as help stuff which is NOT valid syntax
881 877 if line[0]==ESC_HELP:
882 878 line = line[1:]
883 879 elif line[-1]==ESC_HELP:
884 880 line = line[:-1]
885 881 if line:
886 882 #print 'line:<%r>' % line # dbg
887 883 self.shell.magic_pinfo(line_info.ifun)
888 884 else:
889 885 self.shell.show_usage()
890 886 return '' # Empty string is needed here!
891 887 except:
892 888 raise
893 889 # Pass any other exceptions through to the normal handler
894 890 return normal_handler.handle(line_info)
895 891 else:
896 892 # If the code compiles ok, we should handle it normally
897 893 return normal_handler.handle(line_info)
898 894
899 895
900 896 class EmacsHandler(PrefilterHandler):
901 897
902 898 handler_name = Unicode('emacs')
903 899 esc_strings = List([])
904 900
905 901 def handle(self, line_info):
906 902 """Handle input lines marked by python-mode."""
907 903
908 904 # Currently, nothing is done. Later more functionality can be added
909 905 # here if needed.
910 906
911 907 # The input cache shouldn't be updated
912 908 return line_info.line
913 909
914 910
915 911 #-----------------------------------------------------------------------------
916 912 # Defaults
917 913 #-----------------------------------------------------------------------------
918 914
919 915
920 916 _default_transformers = [
921 917 AssignSystemTransformer,
922 918 AssignMagicTransformer,
923 919 PyPromptTransformer,
924 920 IPyPromptTransformer,
925 921 ]
926 922
927 923 _default_checkers = [
928 924 EmacsChecker,
929 925 ShellEscapeChecker,
930 926 MacroChecker,
931 927 IPyAutocallChecker,
932 928 MultiLineMagicChecker,
933 929 EscCharsChecker,
934 930 AssignmentChecker,
935 931 AutoMagicChecker,
936 932 AliasChecker,
937 933 PythonOpsChecker,
938 934 AutocallChecker
939 935 ]
940 936
941 937 _default_handlers = [
942 938 PrefilterHandler,
943 939 AliasHandler,
944 940 ShellEscapeHandler,
945 941 MacroHandler,
946 942 MagicHandler,
947 943 AutoHandler,
948 944 HelpHandler,
949 945 EmacsHandler
950 946 ]
@@ -1,168 +1,168 b''
1 1 """Tests for input handlers.
2 2 """
3 3 #-----------------------------------------------------------------------------
4 4 # Module imports
5 5 #-----------------------------------------------------------------------------
6 6
7 7 # third party
8 8 import nose.tools as nt
9 9
10 10 # our own packages
11 11 from IPython.core import autocall
12 12 from IPython.testing import decorators as dec
13 13 from IPython.testing import tools as tt
14 14 from IPython.testing.globalipapp import get_ipython
15 15 from IPython.utils import py3compat
16 16
17 17 #-----------------------------------------------------------------------------
18 18 # Globals
19 19 #-----------------------------------------------------------------------------
20 20
21 21 # Get the public instance of IPython
22 22 ip = get_ipython()
23 23
24 24 failures = []
25 25 num_tests = 0
26 26
27 27 #-----------------------------------------------------------------------------
28 28 # Test functions
29 29 #-----------------------------------------------------------------------------
30 30
31 31 class CallableIndexable(object):
32 32 def __getitem__(self, idx): return True
33 33 def __call__(self, *args, **kws): return True
34 34
35 35
36 36 class Autocallable(autocall.IPyAutocall):
37 37 def __call__(self):
38 38 return "called"
39 39
40 40
41 41 def run(tests):
42 42 """Loop through a list of (pre, post) inputs, where pre is the string
43 43 handed to ipython, and post is how that string looks after it's been
44 44 transformed (i.e. ipython's notion of _i)"""
45 45 tt.check_pairs(ip.prefilter_manager.prefilter_lines, tests)
46 46
47 47
48 48 def test_handlers():
49 49 # alias expansion
50 50
51 51 # We're using 'true' as our syscall of choice because it doesn't
52 52 # write anything to stdout.
53 53
54 54 # Turn off actual execution of aliases, because it's noisy
55 55 old_system_cmd = ip.system
56 56 ip.system = lambda cmd: None
57 57
58 58
59 59 ip.alias_manager.alias_table['an_alias'] = (0, 'true')
60 60 # These are useful for checking a particular recursive alias issue
61 61 ip.alias_manager.alias_table['top'] = (0, 'd:/cygwin/top')
62 62 ip.alias_manager.alias_table['d'] = (0, 'true')
63 63 run([(i,py3compat.u_format(o)) for i,o in \
64 [("an_alias", 'get_ipython().system({u}"true ")'), # alias
64 [("an_alias", "get_ipython().system({u}'true ')"), # alias
65 65 # Below: recursive aliases should expand whitespace-surrounded
66 66 # chars, *not* initial chars which happen to be aliases:
67 ("top", 'get_ipython().system({u}"d:/cygwin/top ")'),
67 ("top", "get_ipython().system({u}'d:/cygwin/top ')"),
68 68 ]])
69 69 ip.system = old_system_cmd
70 70
71 71 call_idx = CallableIndexable()
72 72 ip.user_ns['call_idx'] = call_idx
73 73
74 74 # For many of the below, we're also checking that leading whitespace
75 75 # turns off the esc char, which it should unless there is a continuation
76 76 # line.
77 77 run([(i,py3compat.u_format(o)) for i,o in \
78 78 [('"no change"', '"no change"'), # normal
79 ("!true", 'get_ipython().system({u}"true")'), # shell_escapes
80 ("!! true", 'get_ipython().magic({u}"sx true")'), # shell_escapes + magic
81 ("!!true", 'get_ipython().magic({u}"sx true")'), # shell_escapes + magic
82 ("%lsmagic", 'get_ipython().magic({u}"lsmagic ")'), # magic
83 ("lsmagic", 'get_ipython().magic({u}"lsmagic ")'), # magic
79 (u"!true", "get_ipython().system({u}'true')"), # shell_escapes
80 (u"!! true", "get_ipython().magic({u}'sx true')"), # shell_escapes + magic
81 (u"!!true", "get_ipython().magic({u}'sx true')"), # shell_escapes + magic
82 (u"%lsmagic", "get_ipython().magic({u}'lsmagic ')"), # magic
83 (u"lsmagic", "get_ipython().magic({u}'lsmagic ')"), # magic
84 84 #("a = b # PYTHON-MODE", '_i'), # emacs -- avoids _in cache
85 85
86 86 # post-esc-char whitespace goes inside
87 ("! true", 'get_ipython().system({u}" true")'),
87 (u"! true", "get_ipython().system({u}' true')"),
88 88
89 89 # handle_help
90 90
91 91 # These are weak tests -- just looking at what the help handlers
92 92 # logs, which is not how it really does its work. But it still
93 93 # lets us check the key paths through the handler.
94 94
95 95 ("x=1 # what?", "x=1 # what?"), # no help if valid python
96 96 ]])
97 97
98 98 # multi_line_specials
99 99 ip.prefilter_manager.multi_line_specials = False
100 100 # W/ multi_line_specials off, leading ws kills esc chars/autoexpansion
101 101 run([
102 ('if 1:\n !true', 'if 1:\n !true'),
103 ('if 1:\n lsmagic', 'if 1:\n lsmagic'),
104 ('if 1:\n an_alias', 'if 1:\n an_alias'),
102 (u'if 1:\n !true', u'if 1:\n !true'),
103 (u'if 1:\n lsmagic', u'if 1:\n lsmagic'),
104 (u'if 1:\n an_alias', u'if 1:\n an_alias'),
105 105 ])
106 106
107 107 ip.prefilter_manager.multi_line_specials = True
108 108 # initial indents must be preserved.
109 109 run([(i,py3compat.u_format(o)) for i,o in \
110 [('if 1:\n !true', 'if 1:\n get_ipython().system({u}"true")'),
111 ('if 2:\n lsmagic', 'if 2:\n get_ipython().magic({u}"lsmagic ")'),
112 ('if 1:\n an_alias', 'if 1:\n get_ipython().system({u}"true ")'),
110 [(u'if 1:\n !true', "if 1:\n get_ipython().system({u}'true')"),
111 (u'if 2:\n lsmagic', "if 2:\n get_ipython().magic({u}'lsmagic ')"),
112 (u'if 1:\n an_alias', "if 1:\n get_ipython().system({u}'true ')"),
113 113 # Weird one
114 ('if 1:\n !!true', 'if 1:\n get_ipython().magic({u}"sx true")'),
114 (u'if 1:\n !!true', "if 1:\n get_ipython().magic({u}'sx true')"),
115 115
116 116 # Even with m_l_s on, autocall is off even with special chars
117 117 ('if 1:\n /fun 1 2', 'if 1:\n /fun 1 2'),
118 118 ('if 1:\n ;fun 1 2', 'if 1:\n ;fun 1 2'),
119 119 ('if 1:\n ,fun 1 2', 'if 1:\n ,fun 1 2'),
120 120 ('if 1:\n ?fun 1 2', 'if 1:\n ?fun 1 2'),
121 121 # What about !!
122 122 ]])
123 123
124 124 # Objects which are instances of IPyAutocall are *always* autocalled
125 125 autocallable = Autocallable()
126 126 ip.user_ns['autocallable'] = autocallable
127 127
128 128 # auto
129 129 ip.magic('autocall 0')
130 130 # Only explicit escapes or instances of IPyAutocallable should get
131 131 # expanded
132 132 run([
133 133 ('len "abc"', 'len "abc"'),
134 134 ('autocallable', 'autocallable()'),
135 135 (",list 1 2 3", 'list("1", "2", "3")'),
136 136 (";list 1 2 3", 'list("1 2 3")'),
137 137 ("/len range(1,4)", 'len(range(1,4))'),
138 138 ])
139 139 ip.magic('autocall 1')
140 140 run([
141 141 (",list 1 2 3", 'list("1", "2", "3")'),
142 142 (";list 1 2 3", 'list("1 2 3")'),
143 143 ("/len range(1,4)", 'len(range(1,4))'),
144 144 ('len "abc"', 'len("abc")'),
145 145 ('len "abc";', 'len("abc");'), # ; is special -- moves out of parens
146 146 # Autocall is turned off if first arg is [] and the object
147 147 # is both callable and indexable. Like so:
148 148 ('len [1,2]', 'len([1,2])'), # len doesn't support __getitem__...
149 149 ('call_idx [1]', 'call_idx [1]'), # call_idx *does*..
150 150 ('call_idx 1', 'call_idx(1)'),
151 151 ('len', 'len '), # only at 2 does it auto-call on single args
152 152 ])
153 153 ip.magic('autocall 2')
154 154 run([
155 155 (",list 1 2 3", 'list("1", "2", "3")'),
156 156 (";list 1 2 3", 'list("1 2 3")'),
157 157 ("/len range(1,4)", 'len(range(1,4))'),
158 158 ('len "abc"', 'len("abc")'),
159 159 ('len "abc";', 'len("abc");'),
160 160 ('len [1,2]', 'len([1,2])'),
161 161 ('call_idx [1]', 'call_idx [1]'),
162 162 ('call_idx 1', 'call_idx(1)'),
163 163 # This is what's different:
164 164 ('len', 'len()'), # only at 2 does it auto-call on single args
165 165 ])
166 166 ip.magic('autocall 1')
167 167
168 168 nt.assert_equals(failures, [])
@@ -1,704 +1,706 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Tests for the inputsplitter module.
3 3
4 4 Authors
5 5 -------
6 6 * Fernando Perez
7 7 * Robert Kern
8 8 """
9 9 #-----------------------------------------------------------------------------
10 10 # Copyright (C) 2010 The IPython Development Team
11 11 #
12 12 # Distributed under the terms of the BSD License. The full license is in
13 13 # the file COPYING, distributed as part of this software.
14 14 #-----------------------------------------------------------------------------
15 15
16 16 #-----------------------------------------------------------------------------
17 17 # Imports
18 18 #-----------------------------------------------------------------------------
19 19 # stdlib
20 20 import unittest
21 21 import sys
22 22
23 23 # Third party
24 24 import nose.tools as nt
25 25
26 26 # Our own
27 27 from IPython.core import inputsplitter as isp
28 28 from IPython.testing import tools as tt
29 29 from IPython.utils import py3compat
30 30
31 31 #-----------------------------------------------------------------------------
32 32 # Semi-complete examples (also used as tests)
33 33 #-----------------------------------------------------------------------------
34 34
35 35 # Note: at the bottom, there's a slightly more complete version of this that
36 36 # can be useful during development of code here.
37 37
38 38 def mini_interactive_loop(input_func):
39 39 """Minimal example of the logic of an interactive interpreter loop.
40 40
41 41 This serves as an example, and it is used by the test system with a fake
42 42 raw_input that simulates interactive input."""
43 43
44 44 from IPython.core.inputsplitter import InputSplitter
45 45
46 46 isp = InputSplitter()
47 47 # In practice, this input loop would be wrapped in an outside loop to read
48 48 # input indefinitely, until some exit/quit command was issued. Here we
49 49 # only illustrate the basic inner loop.
50 50 while isp.push_accepts_more():
51 51 indent = ' '*isp.indent_spaces
52 52 prompt = '>>> ' + indent
53 53 line = indent + input_func(prompt)
54 54 isp.push(line)
55 55
56 56 # Here we just return input so we can use it in a test suite, but a real
57 57 # interpreter would instead send it for execution somewhere.
58 58 src = isp.source_reset()
59 59 #print 'Input source was:\n', src # dbg
60 60 return src
61 61
62 62 #-----------------------------------------------------------------------------
63 63 # Test utilities, just for local use
64 64 #-----------------------------------------------------------------------------
65 65
66 66 def assemble(block):
67 67 """Assemble a block into multi-line sub-blocks."""
68 68 return ['\n'.join(sub_block)+'\n' for sub_block in block]
69 69
70 70
71 71 def pseudo_input(lines):
72 72 """Return a function that acts like raw_input but feeds the input list."""
73 73 ilines = iter(lines)
74 74 def raw_in(prompt):
75 75 try:
76 76 return next(ilines)
77 77 except StopIteration:
78 78 return ''
79 79 return raw_in
80 80
81 81 #-----------------------------------------------------------------------------
82 82 # Tests
83 83 #-----------------------------------------------------------------------------
84 84 def test_spaces():
85 85 tests = [('', 0),
86 86 (' ', 1),
87 87 ('\n', 0),
88 88 (' \n', 1),
89 89 ('x', 0),
90 90 (' x', 1),
91 91 (' x',2),
92 92 (' x',4),
93 93 # Note: tabs are counted as a single whitespace!
94 94 ('\tx', 1),
95 95 ('\t x', 2),
96 96 ]
97 97 tt.check_pairs(isp.num_ini_spaces, tests)
98 98
99 99
100 100 def test_remove_comments():
101 101 tests = [('text', 'text'),
102 102 ('text # comment', 'text '),
103 103 ('text # comment\n', 'text \n'),
104 104 ('text # comment \n', 'text \n'),
105 105 ('line # c \nline\n','line \nline\n'),
106 106 ('line # c \nline#c2 \nline\nline #c\n\n',
107 107 'line \nline\nline\nline \n\n'),
108 108 ]
109 109 tt.check_pairs(isp.remove_comments, tests)
110 110
111 111 def test_has_comment():
112 112 tests = [('text', False),
113 113 ('text #comment', True),
114 114 ('text #comment\n', True),
115 115 ('#comment', True),
116 116 ('#comment\n', True),
117 117 ('a = "#string"', False),
118 118 ('a = "#string" # comment', True),
119 119 ('a #comment not "string"', True),
120 120 ]
121 121 tt.check_pairs(isp.has_comment, tests)
122 122
123 123
124 124 def test_get_input_encoding():
125 125 encoding = isp.get_input_encoding()
126 126 nt.assert_true(isinstance(encoding, basestring))
127 127 # simple-minded check that at least encoding a simple string works with the
128 128 # encoding we got.
129 129 nt.assert_equal(u'test'.encode(encoding), b'test')
130 130
131 131
132 132 class NoInputEncodingTestCase(unittest.TestCase):
133 133 def setUp(self):
134 134 self.old_stdin = sys.stdin
135 135 class X: pass
136 136 fake_stdin = X()
137 137 sys.stdin = fake_stdin
138 138
139 139 def test(self):
140 140 # Verify that if sys.stdin has no 'encoding' attribute we do the right
141 141 # thing
142 142 enc = isp.get_input_encoding()
143 143 self.assertEqual(enc, 'ascii')
144 144
145 145 def tearDown(self):
146 146 sys.stdin = self.old_stdin
147 147
148 148
149 149 class InputSplitterTestCase(unittest.TestCase):
150 150 def setUp(self):
151 151 self.isp = isp.InputSplitter()
152 152
153 153 def test_reset(self):
154 154 isp = self.isp
155 155 isp.push('x=1')
156 156 isp.reset()
157 157 self.assertEqual(isp._buffer, [])
158 158 self.assertEqual(isp.indent_spaces, 0)
159 159 self.assertEqual(isp.source, '')
160 160 self.assertEqual(isp.code, None)
161 161 self.assertEqual(isp._is_complete, False)
162 162
163 163 def test_source(self):
164 164 self.isp._store('1')
165 165 self.isp._store('2')
166 166 self.assertEqual(self.isp.source, '1\n2\n')
167 167 self.assertTrue(len(self.isp._buffer)>0)
168 168 self.assertEqual(self.isp.source_reset(), '1\n2\n')
169 169 self.assertEqual(self.isp._buffer, [])
170 170 self.assertEqual(self.isp.source, '')
171 171
172 172 def test_indent(self):
173 173 isp = self.isp # shorthand
174 174 isp.push('x=1')
175 175 self.assertEqual(isp.indent_spaces, 0)
176 176 isp.push('if 1:\n x=1')
177 177 self.assertEqual(isp.indent_spaces, 4)
178 178 isp.push('y=2\n')
179 179 self.assertEqual(isp.indent_spaces, 0)
180 180
181 181 def test_indent2(self):
182 182 # In cell mode, inputs must be fed in whole blocks, so skip this test
183 183 if self.isp.input_mode == 'cell': return
184 184
185 185 isp = self.isp
186 186 isp.push('if 1:')
187 187 self.assertEqual(isp.indent_spaces, 4)
188 188 isp.push(' x=1')
189 189 self.assertEqual(isp.indent_spaces, 4)
190 190 # Blank lines shouldn't change the indent level
191 191 isp.push(' '*2)
192 192 self.assertEqual(isp.indent_spaces, 4)
193 193
194 194 def test_indent3(self):
195 195 # In cell mode, inputs must be fed in whole blocks, so skip this test
196 196 if self.isp.input_mode == 'cell': return
197 197
198 198 isp = self.isp
199 199 # When a multiline statement contains parens or multiline strings, we
200 200 # shouldn't get confused.
201 201 isp.push("if 1:")
202 202 isp.push(" x = (1+\n 2)")
203 203 self.assertEqual(isp.indent_spaces, 4)
204 204
205 205 def test_indent4(self):
206 206 # In cell mode, inputs must be fed in whole blocks, so skip this test
207 207 if self.isp.input_mode == 'cell': return
208 208
209 209 isp = self.isp
210 210 # whitespace after ':' should not screw up indent level
211 211 isp.push('if 1: \n x=1')
212 212 self.assertEqual(isp.indent_spaces, 4)
213 213 isp.push('y=2\n')
214 214 self.assertEqual(isp.indent_spaces, 0)
215 215 isp.push('if 1:\t\n x=1')
216 216 self.assertEqual(isp.indent_spaces, 4)
217 217 isp.push('y=2\n')
218 218 self.assertEqual(isp.indent_spaces, 0)
219 219
220 220 def test_dedent_pass(self):
221 221 isp = self.isp # shorthand
222 222 # should NOT cause dedent
223 223 isp.push('if 1:\n passes = 5')
224 224 self.assertEqual(isp.indent_spaces, 4)
225 225 isp.push('if 1:\n pass')
226 226 self.assertEqual(isp.indent_spaces, 0)
227 227 isp.push('if 1:\n pass ')
228 228 self.assertEqual(isp.indent_spaces, 0)
229 229
230 230 def test_dedent_raise(self):
231 231 isp = self.isp # shorthand
232 232 # should NOT cause dedent
233 233 isp.push('if 1:\n raised = 4')
234 234 self.assertEqual(isp.indent_spaces, 4)
235 235 isp.push('if 1:\n raise TypeError()')
236 236 self.assertEqual(isp.indent_spaces, 0)
237 237 isp.push('if 1:\n raise')
238 238 self.assertEqual(isp.indent_spaces, 0)
239 239 isp.push('if 1:\n raise ')
240 240 self.assertEqual(isp.indent_spaces, 0)
241 241
242 242 def test_dedent_return(self):
243 243 isp = self.isp # shorthand
244 244 # should NOT cause dedent
245 245 isp.push('if 1:\n returning = 4')
246 246 self.assertEqual(isp.indent_spaces, 4)
247 247 isp.push('if 1:\n return 5 + 493')
248 248 self.assertEqual(isp.indent_spaces, 0)
249 249 isp.push('if 1:\n return')
250 250 self.assertEqual(isp.indent_spaces, 0)
251 251 isp.push('if 1:\n return ')
252 252 self.assertEqual(isp.indent_spaces, 0)
253 253 isp.push('if 1:\n return(0)')
254 254 self.assertEqual(isp.indent_spaces, 0)
255 255
256 256 def test_push(self):
257 257 isp = self.isp
258 258 self.assertTrue(isp.push('x=1'))
259 259
260 260 def test_push2(self):
261 261 isp = self.isp
262 262 self.assertFalse(isp.push('if 1:'))
263 263 for line in [' x=1', '# a comment', ' y=2']:
264 264 self.assertTrue(isp.push(line))
265 265
266 266 def test_push3(self):
267 267 isp = self.isp
268 268 isp.push('if True:')
269 269 isp.push(' a = 1')
270 270 self.assertFalse(isp.push('b = [1,'))
271 271
272 272 def test_replace_mode(self):
273 273 isp = self.isp
274 274 isp.input_mode = 'cell'
275 275 isp.push('x=1')
276 276 self.assertEqual(isp.source, 'x=1\n')
277 277 isp.push('x=2')
278 278 self.assertEqual(isp.source, 'x=2\n')
279 279
280 280 def test_push_accepts_more(self):
281 281 isp = self.isp
282 282 isp.push('x=1')
283 283 self.assertFalse(isp.push_accepts_more())
284 284
285 285 def test_push_accepts_more2(self):
286 286 # In cell mode, inputs must be fed in whole blocks, so skip this test
287 287 if self.isp.input_mode == 'cell': return
288 288
289 289 isp = self.isp
290 290 isp.push('if 1:')
291 291 self.assertTrue(isp.push_accepts_more())
292 292 isp.push(' x=1')
293 293 self.assertTrue(isp.push_accepts_more())
294 294 isp.push('')
295 295 self.assertFalse(isp.push_accepts_more())
296 296
297 297 def test_push_accepts_more3(self):
298 298 isp = self.isp
299 299 isp.push("x = (2+\n3)")
300 300 self.assertFalse(isp.push_accepts_more())
301 301
302 302 def test_push_accepts_more4(self):
303 303 # In cell mode, inputs must be fed in whole blocks, so skip this test
304 304 if self.isp.input_mode == 'cell': return
305 305
306 306 isp = self.isp
307 307 # When a multiline statement contains parens or multiline strings, we
308 308 # shouldn't get confused.
309 309 # FIXME: we should be able to better handle de-dents in statements like
310 310 # multiline strings and multiline expressions (continued with \ or
311 311 # parens). Right now we aren't handling the indentation tracking quite
312 312 # correctly with this, though in practice it may not be too much of a
313 313 # problem. We'll need to see.
314 314 isp.push("if 1:")
315 315 isp.push(" x = (2+")
316 316 isp.push(" 3)")
317 317 self.assertTrue(isp.push_accepts_more())
318 318 isp.push(" y = 3")
319 319 self.assertTrue(isp.push_accepts_more())
320 320 isp.push('')
321 321 self.assertFalse(isp.push_accepts_more())
322 322
323 323 def test_push_accepts_more5(self):
324 324 # In cell mode, inputs must be fed in whole blocks, so skip this test
325 325 if self.isp.input_mode == 'cell': return
326 326
327 327 isp = self.isp
328 328 isp.push('try:')
329 329 isp.push(' a = 5')
330 330 isp.push('except:')
331 331 isp.push(' raise')
332 332 self.assertTrue(isp.push_accepts_more())
333 333
334 334 def test_continuation(self):
335 335 isp = self.isp
336 336 isp.push("import os, \\")
337 337 self.assertTrue(isp.push_accepts_more())
338 338 isp.push("sys")
339 339 self.assertFalse(isp.push_accepts_more())
340 340
341 341 def test_syntax_error(self):
342 342 isp = self.isp
343 343 # Syntax errors immediately produce a 'ready' block, so the invalid
344 344 # Python can be sent to the kernel for evaluation with possible ipython
345 345 # special-syntax conversion.
346 346 isp.push('run foo')
347 347 self.assertFalse(isp.push_accepts_more())
348 348
349 349 def test_unicode(self):
350 350 self.isp.push(u"PΓ©rez")
351 351 self.isp.push(u'\xc3\xa9')
352 352 self.isp.push(u"u'\xc3\xa9'")
353 353
354 354 class InteractiveLoopTestCase(unittest.TestCase):
355 355 """Tests for an interactive loop like a python shell.
356 356 """
357 357 def check_ns(self, lines, ns):
358 358 """Validate that the given input lines produce the resulting namespace.
359 359
360 360 Note: the input lines are given exactly as they would be typed in an
361 361 auto-indenting environment, as mini_interactive_loop above already does
362 362 auto-indenting and prepends spaces to the input.
363 363 """
364 364 src = mini_interactive_loop(pseudo_input(lines))
365 365 test_ns = {}
366 366 exec src in test_ns
367 367 # We can't check that the provided ns is identical to the test_ns,
368 368 # because Python fills test_ns with extra keys (copyright, etc). But
369 369 # we can check that the given dict is *contained* in test_ns
370 370 for k,v in ns.iteritems():
371 371 self.assertEqual(test_ns[k], v)
372 372
373 373 def test_simple(self):
374 374 self.check_ns(['x=1'], dict(x=1))
375 375
376 376 def test_simple2(self):
377 377 self.check_ns(['if 1:', 'x=2'], dict(x=2))
378 378
379 379 def test_xy(self):
380 380 self.check_ns(['x=1; y=2'], dict(x=1, y=2))
381 381
382 382 def test_abc(self):
383 383 self.check_ns(['if 1:','a=1','b=2','c=3'], dict(a=1, b=2, c=3))
384 384
385 385 def test_multi(self):
386 386 self.check_ns(['x =(1+','1+','2)'], dict(x=4))
387 387
388 388
389 389 def test_LineInfo():
390 390 """Simple test for LineInfo construction and str()"""
391 391 linfo = isp.LineInfo(' %cd /home')
392 392 nt.assert_equals(str(linfo), 'LineInfo [ |%|cd|/home]')
393 393
394 394 # Transformer tests
395 395 def transform_checker(tests, func):
396 396 """Utility to loop over test inputs"""
397 397 for inp, tr in tests:
398 398 nt.assert_equals(func(inp), tr)
399 399
400 400 # Data for all the syntax tests in the form of lists of pairs of
401 401 # raw/transformed input. We store it here as a global dict so that we can use
402 402 # it both within single-function tests and also to validate the behavior of the
403 403 # larger objects
404 404
405 405 syntax = \
406 406 dict(assign_system =
407 407 [(i,py3compat.u_format(o)) for i,o in \
408 [('a =! ls', 'a = get_ipython().getoutput({u}"ls")'),
409 ('b = !ls', 'b = get_ipython().getoutput({u}"ls")'),
408 [(u'a =! ls', "a = get_ipython().getoutput({u}'ls')"),
409 (u'b = !ls', "b = get_ipython().getoutput({u}'ls')"),
410 410 ('x=1', 'x=1'), # normal input is unmodified
411 411 (' ',' '), # blank lines are kept intact
412 412 ]],
413 413
414 414 assign_magic =
415 415 [(i,py3compat.u_format(o)) for i,o in \
416 [('a =% who', 'a = get_ipython().magic({u}"who")'),
417 ('b = %who', 'b = get_ipython().magic({u}"who")'),
416 [(u'a =% who', "a = get_ipython().magic({u}'who')"),
417 (u'b = %who', "b = get_ipython().magic({u}'who')"),
418 418 ('x=1', 'x=1'), # normal input is unmodified
419 419 (' ',' '), # blank lines are kept intact
420 420 ]],
421 421
422 422 classic_prompt =
423 423 [('>>> x=1', 'x=1'),
424 424 ('x=1', 'x=1'), # normal input is unmodified
425 425 (' ', ' '), # blank lines are kept intact
426 426 ('... ', ''), # continuation prompts
427 427 ],
428 428
429 429 ipy_prompt =
430 430 [('In [1]: x=1', 'x=1'),
431 431 ('x=1', 'x=1'), # normal input is unmodified
432 432 (' ',' '), # blank lines are kept intact
433 433 (' ....: ', ''), # continuation prompts
434 434 ],
435 435
436 436 # Tests for the escape transformer to leave normal code alone
437 437 escaped_noesc =
438 438 [ (' ', ' '),
439 439 ('x=1', 'x=1'),
440 440 ],
441 441
442 442 # System calls
443 443 escaped_shell =
444 444 [(i,py3compat.u_format(o)) for i,o in \
445 [ ('!ls', 'get_ipython().system({u}"ls")'),
445 [ (u'!ls', "get_ipython().system({u}'ls')"),
446 446 # Double-escape shell, this means to capture the output of the
447 447 # subprocess and return it
448 ('!!ls', 'get_ipython().getoutput({u}"ls")'),
448 (u'!!ls', "get_ipython().getoutput({u}'ls')"),
449 449 ]],
450 450
451 451 # Help/object info
452 452 escaped_help =
453 453 [(i,py3compat.u_format(o)) for i,o in \
454 [ ('?', 'get_ipython().show_usage()'),
455 ('?x1', 'get_ipython().magic({u}"pinfo x1")'),
456 ('??x2', 'get_ipython().magic({u}"pinfo2 x2")'),
457 ('?a.*s', 'get_ipython().magic({u}"psearch a.*s")'),
458 ('?%hist', 'get_ipython().magic({u}"pinfo %hist")'),
459 ('?abc = qwe', 'get_ipython().magic({u}"pinfo abc")'),
454 [ (u'?', 'get_ipython().show_usage()'),
455 (u'?x1', "get_ipython().magic({u}'pinfo x1')"),
456 (u'??x2', "get_ipython().magic({u}'pinfo2 x2')"),
457 (u'?a.*s', "get_ipython().magic({u}'psearch a.*s')"),
458 (u'?%hist', "get_ipython().magic({u}'pinfo %hist')"),
459 (u'?abc = qwe', "get_ipython().magic({u}'pinfo abc')"),
460 460 ]],
461 461
462 462 end_help =
463 463 [(i,py3compat.u_format(o)) for i,o in \
464 [ ('x3?', 'get_ipython().magic({u}"pinfo x3")'),
465 ('x4??', 'get_ipython().magic({u}"pinfo2 x4")'),
466 ('%hist?', 'get_ipython().magic({u}"pinfo %hist")'),
467 ('f*?', 'get_ipython().magic({u}"psearch f*")'),
468 ('ax.*aspe*?', 'get_ipython().magic({u}"psearch ax.*aspe*")'),
469 ('a = abc?', 'get_ipython().magic({u}"pinfo abc", next_input={u}"a = abc")'),
470 ('a = abc.qe??', 'get_ipython().magic({u}"pinfo2 abc.qe", next_input={u}"a = abc.qe")'),
471 ('a = *.items?', 'get_ipython().magic({u}"psearch *.items", next_input={u}"a = *.items")'),
472 ('plot(a?', 'get_ipython().magic({u}"pinfo a", next_input={u}"plot(a")'),
473 ('a*2 #comment?', 'a*2 #comment?'),
464 [ (u'x3?', "get_ipython().magic({u}'pinfo x3')"),
465 (u'x4??', "get_ipython().magic({u}'pinfo2 x4')"),
466 (u'%hist?', "get_ipython().magic({u}'pinfo %hist')"),
467 (u'f*?', "get_ipython().magic({u}'psearch f*')"),
468 (u'ax.*aspe*?', "get_ipython().magic({u}'psearch ax.*aspe*')"),
469 (u'a = abc?', "get_ipython().magic({u}'pinfo abc', next_input={u}'a = abc')"),
470 (u'a = abc.qe??', "get_ipython().magic({u}'pinfo2 abc.qe', next_input={u}'a = abc.qe')"),
471 (u'a = *.items?', "get_ipython().magic({u}'psearch *.items', next_input={u}'a = *.items')"),
472 (u'plot(a?', "get_ipython().magic({u}'pinfo a', next_input={u}'plot(a')"),
473 (u'a*2 #comment?', 'a*2 #comment?'),
474 474 ]],
475 475
476 476 # Explicit magic calls
477 477 escaped_magic =
478 478 [(i,py3compat.u_format(o)) for i,o in \
479 [ ('%cd', 'get_ipython().magic({u}"cd")'),
480 ('%cd /home', 'get_ipython().magic({u}"cd /home")'),
481 (' %magic', ' get_ipython().magic({u}"magic")'),
479 [ (u'%cd', "get_ipython().magic({u}'cd')"),
480 (u'%cd /home', "get_ipython().magic({u}'cd /home')"),
481 # Backslashes need to be escaped.
482 (u'%cd C:\\User', "get_ipython().magic({u}'cd C:\\\\User')"),
483 (u' %magic', " get_ipython().magic({u}'magic')"),
482 484 ]],
483 485
484 486 # Quoting with separate arguments
485 487 escaped_quote =
486 488 [ (',f', 'f("")'),
487 489 (',f x', 'f("x")'),
488 490 (' ,f y', ' f("y")'),
489 491 (',f a b', 'f("a", "b")'),
490 492 ],
491 493
492 494 # Quoting with single argument
493 495 escaped_quote2 =
494 496 [ (';f', 'f("")'),
495 497 (';f x', 'f("x")'),
496 498 (' ;f y', ' f("y")'),
497 499 (';f a b', 'f("a b")'),
498 500 ],
499 501
500 502 # Simply apply parens
501 503 escaped_paren =
502 504 [ ('/f', 'f()'),
503 505 ('/f x', 'f(x)'),
504 506 (' /f y', ' f(y)'),
505 507 ('/f a b', 'f(a, b)'),
506 508 ],
507 509
508 510 # Check that we transform prompts before other transforms
509 511 mixed =
510 512 [(i,py3compat.u_format(o)) for i,o in \
511 [ ('In [1]: %lsmagic', 'get_ipython().magic({u}"lsmagic")'),
512 ('>>> %lsmagic', 'get_ipython().magic({u}"lsmagic")'),
513 ('In [2]: !ls', 'get_ipython().system({u}"ls")'),
514 ('In [3]: abs?', 'get_ipython().magic({u}"pinfo abs")'),
515 ('In [4]: b = %who', 'b = get_ipython().magic({u}"who")'),
513 [ (u'In [1]: %lsmagic', "get_ipython().magic({u}'lsmagic')"),
514 (u'>>> %lsmagic', "get_ipython().magic({u}'lsmagic')"),
515 (u'In [2]: !ls', "get_ipython().system({u}'ls')"),
516 (u'In [3]: abs?', "get_ipython().magic({u}'pinfo abs')"),
517 (u'In [4]: b = %who', "b = get_ipython().magic({u}'who')"),
516 518 ]],
517 519 )
518 520
519 521 # multiline syntax examples. Each of these should be a list of lists, with
520 522 # each entry itself having pairs of raw/transformed input. The union (with
521 523 # '\n'.join() of the transformed inputs is what the splitter should produce
522 524 # when fed the raw lines one at a time via push.
523 525 syntax_ml = \
524 526 dict(classic_prompt =
525 527 [ [('>>> for i in range(10):','for i in range(10):'),
526 528 ('... print i',' print i'),
527 529 ('... ', ''),
528 530 ],
529 531 ],
530 532
531 533 ipy_prompt =
532 534 [ [('In [24]: for i in range(10):','for i in range(10):'),
533 535 (' ....: print i',' print i'),
534 536 (' ....: ', ''),
535 537 ],
536 538 ],
537 539
538 540 multiline_datastructure =
539 541 [ [('>>> a = [1,','a = [1,'),
540 542 ('... 2]','2]'),
541 543 ],
542 544 ],
543 545 )
544 546
545 547
546 548 def test_assign_system():
547 549 tt.check_pairs(isp.transform_assign_system, syntax['assign_system'])
548 550
549 551
550 552 def test_assign_magic():
551 553 tt.check_pairs(isp.transform_assign_magic, syntax['assign_magic'])
552 554
553 555
554 556 def test_classic_prompt():
555 557 transform_checker(syntax['classic_prompt'], isp.transform_classic_prompt)
556 558 for example in syntax_ml['classic_prompt']:
557 559 transform_checker(example, isp.transform_classic_prompt)
558 560
559 561
560 562 def test_ipy_prompt():
561 563 transform_checker(syntax['ipy_prompt'], isp.transform_ipy_prompt)
562 564 for example in syntax_ml['ipy_prompt']:
563 565 transform_checker(example, isp.transform_ipy_prompt)
564 566
565 567 def test_end_help():
566 568 tt.check_pairs(isp.transform_help_end, syntax['end_help'])
567 569
568 570 def test_escaped_noesc():
569 571 tt.check_pairs(isp.transform_escaped, syntax['escaped_noesc'])
570 572
571 573
572 574 def test_escaped_shell():
573 575 tt.check_pairs(isp.transform_escaped, syntax['escaped_shell'])
574 576
575 577
576 578 def test_escaped_help():
577 579 tt.check_pairs(isp.transform_escaped, syntax['escaped_help'])
578 580
579 581
580 582 def test_escaped_magic():
581 583 tt.check_pairs(isp.transform_escaped, syntax['escaped_magic'])
582 584
583 585
584 586 def test_escaped_quote():
585 587 tt.check_pairs(isp.transform_escaped, syntax['escaped_quote'])
586 588
587 589
588 590 def test_escaped_quote2():
589 591 tt.check_pairs(isp.transform_escaped, syntax['escaped_quote2'])
590 592
591 593
592 594 def test_escaped_paren():
593 595 tt.check_pairs(isp.transform_escaped, syntax['escaped_paren'])
594 596
595 597
596 598 class IPythonInputTestCase(InputSplitterTestCase):
597 599 """By just creating a new class whose .isp is a different instance, we
598 600 re-run the same test battery on the new input splitter.
599 601
600 602 In addition, this runs the tests over the syntax and syntax_ml dicts that
601 603 were tested by individual functions, as part of the OO interface.
602 604
603 605 It also makes some checks on the raw buffer storage.
604 606 """
605 607
606 608 def setUp(self):
607 609 self.isp = isp.IPythonInputSplitter(input_mode='line')
608 610
609 611 def test_syntax(self):
610 612 """Call all single-line syntax tests from the main object"""
611 613 isp = self.isp
612 614 for example in syntax.itervalues():
613 615 for raw, out_t in example:
614 616 if raw.startswith(' '):
615 617 continue
616 618
617 619 isp.push(raw)
618 620 out, out_raw = isp.source_raw_reset()
619 621 self.assertEqual(out.rstrip(), out_t,
620 622 tt.pair_fail_msg.format("inputsplitter",raw, out_t, out))
621 623 self.assertEqual(out_raw.rstrip(), raw.rstrip())
622 624
623 625 def test_syntax_multiline(self):
624 626 isp = self.isp
625 627 for example in syntax_ml.itervalues():
626 628 out_t_parts = []
627 629 raw_parts = []
628 630 for line_pairs in example:
629 631 for lraw, out_t_part in line_pairs:
630 632 isp.push(lraw)
631 633 out_t_parts.append(out_t_part)
632 634 raw_parts.append(lraw)
633 635
634 636 out, out_raw = isp.source_raw_reset()
635 637 out_t = '\n'.join(out_t_parts).rstrip()
636 638 raw = '\n'.join(raw_parts).rstrip()
637 639 self.assertEqual(out.rstrip(), out_t)
638 640 self.assertEqual(out_raw.rstrip(), raw)
639 641
640 642
641 643 class BlockIPythonInputTestCase(IPythonInputTestCase):
642 644
643 645 # Deactivate tests that don't make sense for the block mode
644 646 test_push3 = test_split = lambda s: None
645 647
646 648 def setUp(self):
647 649 self.isp = isp.IPythonInputSplitter(input_mode='cell')
648 650
649 651 def test_syntax_multiline(self):
650 652 isp = self.isp
651 653 for example in syntax_ml.itervalues():
652 654 raw_parts = []
653 655 out_t_parts = []
654 656 for line_pairs in example:
655 657 for raw, out_t_part in line_pairs:
656 658 raw_parts.append(raw)
657 659 out_t_parts.append(out_t_part)
658 660
659 661 raw = '\n'.join(raw_parts)
660 662 out_t = '\n'.join(out_t_parts)
661 663
662 664 isp.push(raw)
663 665 out, out_raw = isp.source_raw_reset()
664 666 # Match ignoring trailing whitespace
665 667 self.assertEqual(out.rstrip(), out_t.rstrip())
666 668 self.assertEqual(out_raw.rstrip(), raw.rstrip())
667 669
668 670
669 671 #-----------------------------------------------------------------------------
670 672 # Main - use as a script, mostly for developer experiments
671 673 #-----------------------------------------------------------------------------
672 674
673 675 if __name__ == '__main__':
674 676 # A simple demo for interactive experimentation. This code will not get
675 677 # picked up by any test suite.
676 678 from IPython.core.inputsplitter import InputSplitter, IPythonInputSplitter
677 679
678 680 # configure here the syntax to use, prompt and whether to autoindent
679 681 #isp, start_prompt = InputSplitter(), '>>> '
680 682 isp, start_prompt = IPythonInputSplitter(), 'In> '
681 683
682 684 autoindent = True
683 685 #autoindent = False
684 686
685 687 try:
686 688 while True:
687 689 prompt = start_prompt
688 690 while isp.push_accepts_more():
689 691 indent = ' '*isp.indent_spaces
690 692 if autoindent:
691 693 line = indent + raw_input(prompt+indent)
692 694 else:
693 695 line = raw_input(prompt)
694 696 isp.push(line)
695 697 prompt = '... '
696 698
697 699 # Here we just return input so we can use it in a test suite, but a
698 700 # real interpreter would instead send it for execution somewhere.
699 701 #src = isp.source; raise EOFError # dbg
700 702 src, raw = isp.source_raw_reset()
701 703 print 'Input source was:\n', src
702 704 print 'Raw source was:\n', raw
703 705 except EOFError:
704 706 print 'Bye'
@@ -1,739 +1,705 b''
1 1 # encoding: utf-8
2 2 """
3 3 Utilities for working with strings and text.
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 7 # Copyright (C) 2008-2009 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 import __main__
18 18
19 19 import locale
20 20 import os
21 21 import re
22 22 import shutil
23 23 import sys
24 24 import textwrap
25 25 from string import Formatter
26 26
27 27 from IPython.external.path import path
28 28 from IPython.utils import py3compat
29 29 from IPython.utils.io import nlprint
30 30 from IPython.utils.data import flatten
31 31
32 32 #-----------------------------------------------------------------------------
33 33 # Code
34 34 #-----------------------------------------------------------------------------
35 35
36 36 # Less conservative replacement for sys.getdefaultencoding, that will try
37 37 # to match the environment.
38 38 # Defined here as central function, so if we find better choices, we
39 39 # won't need to make changes all over IPython.
40 40 def getdefaultencoding():
41 41 """Return IPython's guess for the default encoding for bytes as text.
42 42
43 43 Asks for stdin.encoding first, to match the calling Terminal, but that
44 44 is often None for subprocesses. Fall back on locale.getpreferredencoding()
45 45 which should be a sensible platform default (that respects LANG environment),
46 46 and finally to sys.getdefaultencoding() which is the most conservative option,
47 47 and usually ASCII.
48 48 """
49 49 enc = sys.stdin.encoding
50 50 if not enc or enc=='ascii':
51 51 try:
52 52 # There are reports of getpreferredencoding raising errors
53 53 # in some cases, which may well be fixed, but let's be conservative here.
54 54 enc = locale.getpreferredencoding()
55 55 except Exception:
56 56 pass
57 57 return enc or sys.getdefaultencoding()
58 58
59 59 def unquote_ends(istr):
60 60 """Remove a single pair of quotes from the endpoints of a string."""
61 61
62 62 if not istr:
63 63 return istr
64 64 if (istr[0]=="'" and istr[-1]=="'") or \
65 65 (istr[0]=='"' and istr[-1]=='"'):
66 66 return istr[1:-1]
67 67 else:
68 68 return istr
69 69
70 70
71 71 class LSString(str):
72 72 """String derivative with a special access attributes.
73 73
74 74 These are normal strings, but with the special attributes:
75 75
76 76 .l (or .list) : value as list (split on newlines).
77 77 .n (or .nlstr): original value (the string itself).
78 78 .s (or .spstr): value as whitespace-separated string.
79 79 .p (or .paths): list of path objects
80 80
81 81 Any values which require transformations are computed only once and
82 82 cached.
83 83
84 84 Such strings are very useful to efficiently interact with the shell, which
85 85 typically only understands whitespace-separated options for commands."""
86 86
87 87 def get_list(self):
88 88 try:
89 89 return self.__list
90 90 except AttributeError:
91 91 self.__list = self.split('\n')
92 92 return self.__list
93 93
94 94 l = list = property(get_list)
95 95
96 96 def get_spstr(self):
97 97 try:
98 98 return self.__spstr
99 99 except AttributeError:
100 100 self.__spstr = self.replace('\n',' ')
101 101 return self.__spstr
102 102
103 103 s = spstr = property(get_spstr)
104 104
105 105 def get_nlstr(self):
106 106 return self
107 107
108 108 n = nlstr = property(get_nlstr)
109 109
110 110 def get_paths(self):
111 111 try:
112 112 return self.__paths
113 113 except AttributeError:
114 114 self.__paths = [path(p) for p in self.split('\n') if os.path.exists(p)]
115 115 return self.__paths
116 116
117 117 p = paths = property(get_paths)
118 118
119 119 # FIXME: We need to reimplement type specific displayhook and then add this
120 120 # back as a custom printer. This should also be moved outside utils into the
121 121 # core.
122 122
123 123 # def print_lsstring(arg):
124 124 # """ Prettier (non-repr-like) and more informative printer for LSString """
125 125 # print "LSString (.p, .n, .l, .s available). Value:"
126 126 # print arg
127 127 #
128 128 #
129 129 # print_lsstring = result_display.when_type(LSString)(print_lsstring)
130 130
131 131
132 132 class SList(list):
133 133 """List derivative with a special access attributes.
134 134
135 135 These are normal lists, but with the special attributes:
136 136
137 137 .l (or .list) : value as list (the list itself).
138 138 .n (or .nlstr): value as a string, joined on newlines.
139 139 .s (or .spstr): value as a string, joined on spaces.
140 140 .p (or .paths): list of path objects
141 141
142 142 Any values which require transformations are computed only once and
143 143 cached."""
144 144
145 145 def get_list(self):
146 146 return self
147 147
148 148 l = list = property(get_list)
149 149
150 150 def get_spstr(self):
151 151 try:
152 152 return self.__spstr
153 153 except AttributeError:
154 154 self.__spstr = ' '.join(self)
155 155 return self.__spstr
156 156
157 157 s = spstr = property(get_spstr)
158 158
159 159 def get_nlstr(self):
160 160 try:
161 161 return self.__nlstr
162 162 except AttributeError:
163 163 self.__nlstr = '\n'.join(self)
164 164 return self.__nlstr
165 165
166 166 n = nlstr = property(get_nlstr)
167 167
168 168 def get_paths(self):
169 169 try:
170 170 return self.__paths
171 171 except AttributeError:
172 172 self.__paths = [path(p) for p in self if os.path.exists(p)]
173 173 return self.__paths
174 174
175 175 p = paths = property(get_paths)
176 176
177 177 def grep(self, pattern, prune = False, field = None):
178 178 """ Return all strings matching 'pattern' (a regex or callable)
179 179
180 180 This is case-insensitive. If prune is true, return all items
181 181 NOT matching the pattern.
182 182
183 183 If field is specified, the match must occur in the specified
184 184 whitespace-separated field.
185 185
186 186 Examples::
187 187
188 188 a.grep( lambda x: x.startswith('C') )
189 189 a.grep('Cha.*log', prune=1)
190 190 a.grep('chm', field=-1)
191 191 """
192 192
193 193 def match_target(s):
194 194 if field is None:
195 195 return s
196 196 parts = s.split()
197 197 try:
198 198 tgt = parts[field]
199 199 return tgt
200 200 except IndexError:
201 201 return ""
202 202
203 203 if isinstance(pattern, basestring):
204 204 pred = lambda x : re.search(pattern, x, re.IGNORECASE)
205 205 else:
206 206 pred = pattern
207 207 if not prune:
208 208 return SList([el for el in self if pred(match_target(el))])
209 209 else:
210 210 return SList([el for el in self if not pred(match_target(el))])
211 211
212 212 def fields(self, *fields):
213 213 """ Collect whitespace-separated fields from string list
214 214
215 215 Allows quick awk-like usage of string lists.
216 216
217 217 Example data (in var a, created by 'a = !ls -l')::
218 218 -rwxrwxrwx 1 ville None 18 Dec 14 2006 ChangeLog
219 219 drwxrwxrwx+ 6 ville None 0 Oct 24 18:05 IPython
220 220
221 221 a.fields(0) is ['-rwxrwxrwx', 'drwxrwxrwx+']
222 222 a.fields(1,0) is ['1 -rwxrwxrwx', '6 drwxrwxrwx+']
223 223 (note the joining by space).
224 224 a.fields(-1) is ['ChangeLog', 'IPython']
225 225
226 226 IndexErrors are ignored.
227 227
228 228 Without args, fields() just split()'s the strings.
229 229 """
230 230 if len(fields) == 0:
231 231 return [el.split() for el in self]
232 232
233 233 res = SList()
234 234 for el in [f.split() for f in self]:
235 235 lineparts = []
236 236
237 237 for fd in fields:
238 238 try:
239 239 lineparts.append(el[fd])
240 240 except IndexError:
241 241 pass
242 242 if lineparts:
243 243 res.append(" ".join(lineparts))
244 244
245 245 return res
246 246
247 247 def sort(self,field= None, nums = False):
248 248 """ sort by specified fields (see fields())
249 249
250 250 Example::
251 251 a.sort(1, nums = True)
252 252
253 253 Sorts a by second field, in numerical order (so that 21 > 3)
254 254
255 255 """
256 256
257 257 #decorate, sort, undecorate
258 258 if field is not None:
259 259 dsu = [[SList([line]).fields(field), line] for line in self]
260 260 else:
261 261 dsu = [[line, line] for line in self]
262 262 if nums:
263 263 for i in range(len(dsu)):
264 264 numstr = "".join([ch for ch in dsu[i][0] if ch.isdigit()])
265 265 try:
266 266 n = int(numstr)
267 267 except ValueError:
268 268 n = 0;
269 269 dsu[i][0] = n
270 270
271 271
272 272 dsu.sort()
273 273 return SList([t[1] for t in dsu])
274 274
275 275
276 276 # FIXME: We need to reimplement type specific displayhook and then add this
277 277 # back as a custom printer. This should also be moved outside utils into the
278 278 # core.
279 279
280 280 # def print_slist(arg):
281 281 # """ Prettier (non-repr-like) and more informative printer for SList """
282 282 # print "SList (.p, .n, .l, .s, .grep(), .fields(), sort() available):"
283 283 # if hasattr(arg, 'hideonce') and arg.hideonce:
284 284 # arg.hideonce = False
285 285 # return
286 286 #
287 287 # nlprint(arg)
288 288 #
289 289 # print_slist = result_display.when_type(SList)(print_slist)
290 290
291 291
292 292 def esc_quotes(strng):
293 293 """Return the input string with single and double quotes escaped out"""
294 294
295 295 return strng.replace('"','\\"').replace("'","\\'")
296 296
297 297
298 def make_quoted_expr(s):
299 """Return string s in appropriate quotes, using raw string if possible.
300
301 XXX - example removed because it caused encoding errors in documentation
302 generation. We need a new example that doesn't contain invalid chars.
303
304 Note the use of raw string and padding at the end to allow trailing
305 backslash.
306 """
307
308 tail = ''
309 tailpadding = ''
310 raw = ''
311 ucode = '' if py3compat.PY3 else 'u'
312 if "\\" in s:
313 raw = 'r'
314 if s.endswith('\\'):
315 tail = '[:-1]'
316 tailpadding = '_'
317 if '"' not in s:
318 quote = '"'
319 elif "'" not in s:
320 quote = "'"
321 elif '"""' not in s and not s.endswith('"'):
322 quote = '"""'
323 elif "'''" not in s and not s.endswith("'"):
324 quote = "'''"
325 else:
326 # give up, backslash-escaped string will do
327 return '"%s"' % esc_quotes(s)
328 res = ucode + raw + quote + s + tailpadding + quote + tail
329 return res
330
331
332 298 def qw(words,flat=0,sep=None,maxsplit=-1):
333 299 """Similar to Perl's qw() operator, but with some more options.
334 300
335 301 qw(words,flat=0,sep=' ',maxsplit=-1) -> words.split(sep,maxsplit)
336 302
337 303 words can also be a list itself, and with flat=1, the output will be
338 304 recursively flattened.
339 305
340 306 Examples:
341 307
342 308 >>> qw('1 2')
343 309 ['1', '2']
344 310
345 311 >>> qw(['a b','1 2',['m n','p q']])
346 312 [['a', 'b'], ['1', '2'], [['m', 'n'], ['p', 'q']]]
347 313
348 314 >>> qw(['a b','1 2',['m n','p q']],flat=1)
349 315 ['a', 'b', '1', '2', 'm', 'n', 'p', 'q']
350 316 """
351 317
352 318 if isinstance(words, basestring):
353 319 return [word.strip() for word in words.split(sep,maxsplit)
354 320 if word and not word.isspace() ]
355 321 if flat:
356 322 return flatten(map(qw,words,[1]*len(words)))
357 323 return map(qw,words)
358 324
359 325
360 326 def qwflat(words,sep=None,maxsplit=-1):
361 327 """Calls qw(words) in flat mode. It's just a convenient shorthand."""
362 328 return qw(words,1,sep,maxsplit)
363 329
364 330
365 331 def qw_lol(indata):
366 332 """qw_lol('a b') -> [['a','b']],
367 333 otherwise it's just a call to qw().
368 334
369 335 We need this to make sure the modules_some keys *always* end up as a
370 336 list of lists."""
371 337
372 338 if isinstance(indata, basestring):
373 339 return [qw(indata)]
374 340 else:
375 341 return qw(indata)
376 342
377 343
378 344 def grep(pat,list,case=1):
379 345 """Simple minded grep-like function.
380 346 grep(pat,list) returns occurrences of pat in list, None on failure.
381 347
382 348 It only does simple string matching, with no support for regexps. Use the
383 349 option case=0 for case-insensitive matching."""
384 350
385 351 # This is pretty crude. At least it should implement copying only references
386 352 # to the original data in case it's big. Now it copies the data for output.
387 353 out=[]
388 354 if case:
389 355 for term in list:
390 356 if term.find(pat)>-1: out.append(term)
391 357 else:
392 358 lpat=pat.lower()
393 359 for term in list:
394 360 if term.lower().find(lpat)>-1: out.append(term)
395 361
396 362 if len(out): return out
397 363 else: return None
398 364
399 365
400 366 def dgrep(pat,*opts):
401 367 """Return grep() on dir()+dir(__builtins__).
402 368
403 369 A very common use of grep() when working interactively."""
404 370
405 371 return grep(pat,dir(__main__)+dir(__main__.__builtins__),*opts)
406 372
407 373
408 374 def idgrep(pat):
409 375 """Case-insensitive dgrep()"""
410 376
411 377 return dgrep(pat,0)
412 378
413 379
414 380 def igrep(pat,list):
415 381 """Synonym for case-insensitive grep."""
416 382
417 383 return grep(pat,list,case=0)
418 384
419 385
420 386 def indent(instr,nspaces=4, ntabs=0, flatten=False):
421 387 """Indent a string a given number of spaces or tabstops.
422 388
423 389 indent(str,nspaces=4,ntabs=0) -> indent str by ntabs+nspaces.
424 390
425 391 Parameters
426 392 ----------
427 393
428 394 instr : basestring
429 395 The string to be indented.
430 396 nspaces : int (default: 4)
431 397 The number of spaces to be indented.
432 398 ntabs : int (default: 0)
433 399 The number of tabs to be indented.
434 400 flatten : bool (default: False)
435 401 Whether to scrub existing indentation. If True, all lines will be
436 402 aligned to the same indentation. If False, existing indentation will
437 403 be strictly increased.
438 404
439 405 Returns
440 406 -------
441 407
442 408 str|unicode : string indented by ntabs and nspaces.
443 409
444 410 """
445 411 if instr is None:
446 412 return
447 413 ind = '\t'*ntabs+' '*nspaces
448 414 if flatten:
449 415 pat = re.compile(r'^\s*', re.MULTILINE)
450 416 else:
451 417 pat = re.compile(r'^', re.MULTILINE)
452 418 outstr = re.sub(pat, ind, instr)
453 419 if outstr.endswith(os.linesep+ind):
454 420 return outstr[:-len(ind)]
455 421 else:
456 422 return outstr
457 423
458 424 def native_line_ends(filename,backup=1):
459 425 """Convert (in-place) a file to line-ends native to the current OS.
460 426
461 427 If the optional backup argument is given as false, no backup of the
462 428 original file is left. """
463 429
464 430 backup_suffixes = {'posix':'~','dos':'.bak','nt':'.bak','mac':'.bak'}
465 431
466 432 bak_filename = filename + backup_suffixes[os.name]
467 433
468 434 original = open(filename).read()
469 435 shutil.copy2(filename,bak_filename)
470 436 try:
471 437 new = open(filename,'wb')
472 438 new.write(os.linesep.join(original.splitlines()))
473 439 new.write(os.linesep) # ALWAYS put an eol at the end of the file
474 440 new.close()
475 441 except:
476 442 os.rename(bak_filename,filename)
477 443 if not backup:
478 444 try:
479 445 os.remove(bak_filename)
480 446 except:
481 447 pass
482 448
483 449
484 450 def list_strings(arg):
485 451 """Always return a list of strings, given a string or list of strings
486 452 as input.
487 453
488 454 :Examples:
489 455
490 456 In [7]: list_strings('A single string')
491 457 Out[7]: ['A single string']
492 458
493 459 In [8]: list_strings(['A single string in a list'])
494 460 Out[8]: ['A single string in a list']
495 461
496 462 In [9]: list_strings(['A','list','of','strings'])
497 463 Out[9]: ['A', 'list', 'of', 'strings']
498 464 """
499 465
500 466 if isinstance(arg,basestring): return [arg]
501 467 else: return arg
502 468
503 469
504 470 def marquee(txt='',width=78,mark='*'):
505 471 """Return the input string centered in a 'marquee'.
506 472
507 473 :Examples:
508 474
509 475 In [16]: marquee('A test',40)
510 476 Out[16]: '**************** A test ****************'
511 477
512 478 In [17]: marquee('A test',40,'-')
513 479 Out[17]: '---------------- A test ----------------'
514 480
515 481 In [18]: marquee('A test',40,' ')
516 482 Out[18]: ' A test '
517 483
518 484 """
519 485 if not txt:
520 486 return (mark*width)[:width]
521 487 nmark = (width-len(txt)-2)//len(mark)//2
522 488 if nmark < 0: nmark =0
523 489 marks = mark*nmark
524 490 return '%s %s %s' % (marks,txt,marks)
525 491
526 492
527 493 ini_spaces_re = re.compile(r'^(\s+)')
528 494
529 495 def num_ini_spaces(strng):
530 496 """Return the number of initial spaces in a string"""
531 497
532 498 ini_spaces = ini_spaces_re.match(strng)
533 499 if ini_spaces:
534 500 return ini_spaces.end()
535 501 else:
536 502 return 0
537 503
538 504
539 505 def format_screen(strng):
540 506 """Format a string for screen printing.
541 507
542 508 This removes some latex-type format codes."""
543 509 # Paragraph continue
544 510 par_re = re.compile(r'\\$',re.MULTILINE)
545 511 strng = par_re.sub('',strng)
546 512 return strng
547 513
548 514 def dedent(text):
549 515 """Equivalent of textwrap.dedent that ignores unindented first line.
550 516
551 517 This means it will still dedent strings like:
552 518 '''foo
553 519 is a bar
554 520 '''
555 521
556 522 For use in wrap_paragraphs.
557 523 """
558 524
559 525 if text.startswith('\n'):
560 526 # text starts with blank line, don't ignore the first line
561 527 return textwrap.dedent(text)
562 528
563 529 # split first line
564 530 splits = text.split('\n',1)
565 531 if len(splits) == 1:
566 532 # only one line
567 533 return textwrap.dedent(text)
568 534
569 535 first, rest = splits
570 536 # dedent everything but the first line
571 537 rest = textwrap.dedent(rest)
572 538 return '\n'.join([first, rest])
573 539
574 540 def wrap_paragraphs(text, ncols=80):
575 541 """Wrap multiple paragraphs to fit a specified width.
576 542
577 543 This is equivalent to textwrap.wrap, but with support for multiple
578 544 paragraphs, as separated by empty lines.
579 545
580 546 Returns
581 547 -------
582 548
583 549 list of complete paragraphs, wrapped to fill `ncols` columns.
584 550 """
585 551 paragraph_re = re.compile(r'\n(\s*\n)+', re.MULTILINE)
586 552 text = dedent(text).strip()
587 553 paragraphs = paragraph_re.split(text)[::2] # every other entry is space
588 554 out_ps = []
589 555 indent_re = re.compile(r'\n\s+', re.MULTILINE)
590 556 for p in paragraphs:
591 557 # presume indentation that survives dedent is meaningful formatting,
592 558 # so don't fill unless text is flush.
593 559 if indent_re.search(p) is None:
594 560 # wrap paragraph
595 561 p = textwrap.fill(p, ncols)
596 562 out_ps.append(p)
597 563 return out_ps
598 564
599 565
600 566
601 567 class EvalFormatter(Formatter):
602 568 """A String Formatter that allows evaluation of simple expressions.
603 569
604 570 Any time a format key is not found in the kwargs,
605 571 it will be tried as an expression in the kwargs namespace.
606 572
607 573 This is to be used in templating cases, such as the parallel batch
608 574 script templates, where simple arithmetic on arguments is useful.
609 575
610 576 Examples
611 577 --------
612 578
613 579 In [1]: f = EvalFormatter()
614 580 In [2]: f.format('{n//4}', n=8)
615 581 Out[2]: '2'
616 582
617 583 In [3]: f.format('{list(range(3))}')
618 584 Out[3]: '[0, 1, 2]'
619 585
620 586 In [4]: f.format('{3*2}')
621 587 Out[4]: '6'
622 588 """
623 589
624 590 # should we allow slicing by disabling the format_spec feature?
625 591 allow_slicing = True
626 592
627 593 # copied from Formatter._vformat with minor changes to allow eval
628 594 # and replace the format_spec code with slicing
629 595 def _vformat(self, format_string, args, kwargs, used_args, recursion_depth):
630 596 if recursion_depth < 0:
631 597 raise ValueError('Max string recursion exceeded')
632 598 result = []
633 599 for literal_text, field_name, format_spec, conversion in \
634 600 self.parse(format_string):
635 601
636 602 # output the literal text
637 603 if literal_text:
638 604 result.append(literal_text)
639 605
640 606 # if there's a field, output it
641 607 if field_name is not None:
642 608 # this is some markup, find the object and do
643 609 # the formatting
644 610
645 611 if self.allow_slicing and format_spec:
646 612 # override format spec, to allow slicing:
647 613 field_name = ':'.join([field_name, format_spec])
648 614 format_spec = ''
649 615
650 616 # eval the contents of the field for the object
651 617 # to be formatted
652 618 obj = eval(field_name, kwargs)
653 619
654 620 # do any conversion on the resulting object
655 621 obj = self.convert_field(obj, conversion)
656 622
657 623 # expand the format spec, if needed
658 624 format_spec = self._vformat(format_spec, args, kwargs,
659 625 used_args, recursion_depth-1)
660 626
661 627 # format the object and append to the result
662 628 result.append(self.format_field(obj, format_spec))
663 629
664 630 return ''.join(result)
665 631
666 632
667 633 def columnize(items, separator=' ', displaywidth=80):
668 634 """ Transform a list of strings into a single string with columns.
669 635
670 636 Parameters
671 637 ----------
672 638 items : sequence of strings
673 639 The strings to process.
674 640
675 641 separator : str, optional [default is two spaces]
676 642 The string that separates columns.
677 643
678 644 displaywidth : int, optional [default is 80]
679 645 Width of the display in number of characters.
680 646
681 647 Returns
682 648 -------
683 649 The formatted string.
684 650 """
685 651 # Note: this code is adapted from columnize 0.3.2.
686 652 # See http://code.google.com/p/pycolumnize/
687 653
688 654 # Some degenerate cases.
689 655 size = len(items)
690 656 if size == 0:
691 657 return '\n'
692 658 elif size == 1:
693 659 return '%s\n' % items[0]
694 660
695 661 # Special case: if any item is longer than the maximum width, there's no
696 662 # point in triggering the logic below...
697 663 item_len = map(len, items) # save these, we can reuse them below
698 664 longest = max(item_len)
699 665 if longest >= displaywidth:
700 666 return '\n'.join(items+[''])
701 667
702 668 # Try every row count from 1 upwards
703 669 array_index = lambda nrows, row, col: nrows*col + row
704 670 for nrows in range(1, size):
705 671 ncols = (size + nrows - 1) // nrows
706 672 colwidths = []
707 673 totwidth = -len(separator)
708 674 for col in range(ncols):
709 675 # Get max column width for this column
710 676 colwidth = 0
711 677 for row in range(nrows):
712 678 i = array_index(nrows, row, col)
713 679 if i >= size: break
714 680 x, len_x = items[i], item_len[i]
715 681 colwidth = max(colwidth, len_x)
716 682 colwidths.append(colwidth)
717 683 totwidth += colwidth + len(separator)
718 684 if totwidth > displaywidth:
719 685 break
720 686 if totwidth <= displaywidth:
721 687 break
722 688
723 689 # The smallest number of rows computed and the max widths for each
724 690 # column has been obtained. Now we just have to format each of the rows.
725 691 string = ''
726 692 for row in range(nrows):
727 693 texts = []
728 694 for col in range(ncols):
729 695 i = row + nrows*col
730 696 if i >= size:
731 697 texts.append('')
732 698 else:
733 699 texts.append(items[i])
734 700 while texts and not texts[-1]:
735 701 del texts[-1]
736 702 for col in range(len(texts)):
737 703 texts[col] = texts[col].ljust(colwidths[col])
738 704 string += '%s\n' % separator.join(texts)
739 705 return string
General Comments 0
You need to be logged in to leave comments. Login now