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