##// END OF EJS Templates
update copyright to 2011/20xx-2011...
Matthias BUSSONNIER -
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -1,14 +1,14 b''
1 # encoding: utf-8
1 # encoding: utf-8
2
2
3 __docformat__ = "restructuredtext en"
3 __docformat__ = "restructuredtext en"
4
4
5 #-------------------------------------------------------------------------------
5 #-------------------------------------------------------------------------------
6 # Copyright (C) 2008 The IPython Development Team
6 # Copyright (C) 2008-2011 The IPython Development Team
7 #
7 #
8 # Distributed under the terms of the BSD License. The full license is in
8 # Distributed under the terms of the BSD License. The full license is in
9 # the file COPYING, distributed as part of this software.
9 # the file COPYING, distributed as part of this software.
10 #-------------------------------------------------------------------------------
10 #-------------------------------------------------------------------------------
11
11
12 #-------------------------------------------------------------------------------
12 #-------------------------------------------------------------------------------
13 # Imports
13 # Imports
14 #------------------------------------------------------------------------------- No newline at end of file
14 #-------------------------------------------------------------------------------
@@ -1,183 +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-2011 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 from IPython.utils.py3compat import PY3
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
65 # On Python 3, the Integer trait is a synonym for Int
66 if PY3:
66 if PY3:
67 mc_help = mc_help.replace(u"<Integer>", u"<Int>")
67 mc_help = mc_help.replace(u"<Integer>", u"<Int>")
68 mc_help_inst = mc_help_inst.replace(u"<Integer>", u"<Int>")
68 mc_help_inst = mc_help_inst.replace(u"<Integer>", u"<Int>")
69
69
70 class Foo(Configurable):
70 class Foo(Configurable):
71 a = Integer(0, config=True, help="The integer a.")
71 a = Integer(0, config=True, help="The integer a.")
72 b = Unicode('nope', config=True)
72 b = Unicode('nope', config=True)
73
73
74
74
75 class Bar(Foo):
75 class Bar(Foo):
76 b = Unicode('gotit', config=False, help="The string b.")
76 b = Unicode('gotit', config=False, help="The string b.")
77 c = Float(config=True, help="The string c.")
77 c = Float(config=True, help="The string c.")
78
78
79
79
80 class TestConfigurable(TestCase):
80 class TestConfigurable(TestCase):
81
81
82 def test_default(self):
82 def test_default(self):
83 c1 = Configurable()
83 c1 = Configurable()
84 c2 = Configurable(config=c1.config)
84 c2 = Configurable(config=c1.config)
85 c3 = Configurable(config=c2.config)
85 c3 = Configurable(config=c2.config)
86 self.assertEquals(c1.config, c2.config)
86 self.assertEquals(c1.config, c2.config)
87 self.assertEquals(c2.config, c3.config)
87 self.assertEquals(c2.config, c3.config)
88
88
89 def test_custom(self):
89 def test_custom(self):
90 config = Config()
90 config = Config()
91 config.foo = 'foo'
91 config.foo = 'foo'
92 config.bar = 'bar'
92 config.bar = 'bar'
93 c1 = Configurable(config=config)
93 c1 = Configurable(config=config)
94 c2 = Configurable(config=c1.config)
94 c2 = Configurable(config=c1.config)
95 c3 = Configurable(config=c2.config)
95 c3 = Configurable(config=c2.config)
96 self.assertEquals(c1.config, config)
96 self.assertEquals(c1.config, config)
97 self.assertEquals(c2.config, config)
97 self.assertEquals(c2.config, config)
98 self.assertEquals(c3.config, config)
98 self.assertEquals(c3.config, config)
99 # Test that copies are not made
99 # Test that copies are not made
100 self.assert_(c1.config is config)
100 self.assert_(c1.config is config)
101 self.assert_(c2.config is config)
101 self.assert_(c2.config is config)
102 self.assert_(c3.config is config)
102 self.assert_(c3.config is config)
103 self.assert_(c1.config is c2.config)
103 self.assert_(c1.config is c2.config)
104 self.assert_(c2.config is c3.config)
104 self.assert_(c2.config is c3.config)
105
105
106 def test_inheritance(self):
106 def test_inheritance(self):
107 config = Config()
107 config = Config()
108 config.MyConfigurable.a = 2
108 config.MyConfigurable.a = 2
109 config.MyConfigurable.b = 2.0
109 config.MyConfigurable.b = 2.0
110 c1 = MyConfigurable(config=config)
110 c1 = MyConfigurable(config=config)
111 c2 = MyConfigurable(config=c1.config)
111 c2 = MyConfigurable(config=c1.config)
112 self.assertEquals(c1.a, config.MyConfigurable.a)
112 self.assertEquals(c1.a, config.MyConfigurable.a)
113 self.assertEquals(c1.b, config.MyConfigurable.b)
113 self.assertEquals(c1.b, config.MyConfigurable.b)
114 self.assertEquals(c2.a, config.MyConfigurable.a)
114 self.assertEquals(c2.a, config.MyConfigurable.a)
115 self.assertEquals(c2.b, config.MyConfigurable.b)
115 self.assertEquals(c2.b, config.MyConfigurable.b)
116
116
117 def test_parent(self):
117 def test_parent(self):
118 config = Config()
118 config = Config()
119 config.Foo.a = 10
119 config.Foo.a = 10
120 config.Foo.b = "wow"
120 config.Foo.b = "wow"
121 config.Bar.b = 'later'
121 config.Bar.b = 'later'
122 config.Bar.c = 100.0
122 config.Bar.c = 100.0
123 f = Foo(config=config)
123 f = Foo(config=config)
124 b = Bar(config=f.config)
124 b = Bar(config=f.config)
125 self.assertEquals(f.a, 10)
125 self.assertEquals(f.a, 10)
126 self.assertEquals(f.b, 'wow')
126 self.assertEquals(f.b, 'wow')
127 self.assertEquals(b.b, 'gotit')
127 self.assertEquals(b.b, 'gotit')
128 self.assertEquals(b.c, 100.0)
128 self.assertEquals(b.c, 100.0)
129
129
130 def test_override1(self):
130 def test_override1(self):
131 config = Config()
131 config = Config()
132 config.MyConfigurable.a = 2
132 config.MyConfigurable.a = 2
133 config.MyConfigurable.b = 2.0
133 config.MyConfigurable.b = 2.0
134 c = MyConfigurable(a=3, config=config)
134 c = MyConfigurable(a=3, config=config)
135 self.assertEquals(c.a, 3)
135 self.assertEquals(c.a, 3)
136 self.assertEquals(c.b, config.MyConfigurable.b)
136 self.assertEquals(c.b, config.MyConfigurable.b)
137 self.assertEquals(c.c, 'no config')
137 self.assertEquals(c.c, 'no config')
138
138
139 def test_override2(self):
139 def test_override2(self):
140 config = Config()
140 config = Config()
141 config.Foo.a = 1
141 config.Foo.a = 1
142 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.
143 config.Bar.c = 10.0
143 config.Bar.c = 10.0
144 c = Bar(config=config)
144 c = Bar(config=config)
145 self.assertEquals(c.a, config.Foo.a)
145 self.assertEquals(c.a, config.Foo.a)
146 self.assertEquals(c.b, 'gotit')
146 self.assertEquals(c.b, 'gotit')
147 self.assertEquals(c.c, config.Bar.c)
147 self.assertEquals(c.c, config.Bar.c)
148 c = Bar(a=2, b='and', c=20.0, config=config)
148 c = Bar(a=2, b='and', c=20.0, config=config)
149 self.assertEquals(c.a, 2)
149 self.assertEquals(c.a, 2)
150 self.assertEquals(c.b, 'and')
150 self.assertEquals(c.b, 'and')
151 self.assertEquals(c.c, 20.0)
151 self.assertEquals(c.c, 20.0)
152
152
153 def test_help(self):
153 def test_help(self):
154 self.assertEquals(MyConfigurable.class_get_help(), mc_help)
154 self.assertEquals(MyConfigurable.class_get_help(), mc_help)
155
155
156 def test_help_inst(self):
156 def test_help_inst(self):
157 inst = MyConfigurable(a=5, b=4)
157 inst = MyConfigurable(a=5, b=4)
158 self.assertEquals(MyConfigurable.class_get_help(inst), mc_help_inst)
158 self.assertEquals(MyConfigurable.class_get_help(inst), mc_help_inst)
159
159
160
160
161 class TestSingletonConfigurable(TestCase):
161 class TestSingletonConfigurable(TestCase):
162
162
163 def test_instance(self):
163 def test_instance(self):
164 from IPython.config.configurable import SingletonConfigurable
164 from IPython.config.configurable import SingletonConfigurable
165 class Foo(SingletonConfigurable): pass
165 class Foo(SingletonConfigurable): pass
166 self.assertEquals(Foo.initialized(), False)
166 self.assertEquals(Foo.initialized(), False)
167 foo = Foo.instance()
167 foo = Foo.instance()
168 self.assertEquals(Foo.initialized(), True)
168 self.assertEquals(Foo.initialized(), True)
169 self.assertEquals(foo, Foo.instance())
169 self.assertEquals(foo, Foo.instance())
170 self.assertEquals(SingletonConfigurable._instance, None)
170 self.assertEquals(SingletonConfigurable._instance, None)
171
171
172 def test_inheritance(self):
172 def test_inheritance(self):
173 class Bar(SingletonConfigurable): pass
173 class Bar(SingletonConfigurable): pass
174 class Bam(Bar): pass
174 class Bam(Bar): pass
175 self.assertEquals(Bar.initialized(), False)
175 self.assertEquals(Bar.initialized(), False)
176 self.assertEquals(Bam.initialized(), False)
176 self.assertEquals(Bam.initialized(), False)
177 bam = Bam.instance()
177 bam = Bam.instance()
178 bam == Bar.instance()
178 bam == Bar.instance()
179 self.assertEquals(Bar.initialized(), True)
179 self.assertEquals(Bar.initialized(), True)
180 self.assertEquals(Bam.initialized(), True)
180 self.assertEquals(Bam.initialized(), True)
181 self.assertEquals(bam, Bam._instance)
181 self.assertEquals(bam, Bam._instance)
182 self.assertEquals(bam, Bar._instance)
182 self.assertEquals(bam, Bar._instance)
183 self.assertEquals(SingletonConfigurable._instance, None)
183 self.assertEquals(SingletonConfigurable._instance, None)
@@ -1,255 +1,255 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Tests for IPython.config.loader
3 Tests for IPython.config.loader
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-2009 The IPython Development Team
12 # Copyright (C) 2008-2011 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 import os
22 import os
23 import sys
23 import sys
24 from tempfile import mkstemp
24 from tempfile import mkstemp
25 from unittest import TestCase
25 from unittest import TestCase
26
26
27 from nose import SkipTest
27 from nose import SkipTest
28
28
29 from IPython.testing.tools import mute_warn
29 from IPython.testing.tools import mute_warn
30
30
31 from IPython.utils.traitlets import Unicode
31 from IPython.utils.traitlets import Unicode
32 from IPython.config.configurable import Configurable
32 from IPython.config.configurable import Configurable
33 from IPython.config.loader import (
33 from IPython.config.loader import (
34 Config,
34 Config,
35 PyFileConfigLoader,
35 PyFileConfigLoader,
36 KeyValueConfigLoader,
36 KeyValueConfigLoader,
37 ArgParseConfigLoader,
37 ArgParseConfigLoader,
38 KVArgParseConfigLoader,
38 KVArgParseConfigLoader,
39 ConfigError
39 ConfigError
40 )
40 )
41
41
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43 # Actual tests
43 # Actual tests
44 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
45
45
46
46
47 pyfile = """
47 pyfile = """
48 c = get_config()
48 c = get_config()
49 c.a=10
49 c.a=10
50 c.b=20
50 c.b=20
51 c.Foo.Bar.value=10
51 c.Foo.Bar.value=10
52 c.Foo.Bam.value=list(range(10)) # list() is just so it's the same on Python 3
52 c.Foo.Bam.value=list(range(10)) # list() is just so it's the same on Python 3
53 c.D.C.value='hi there'
53 c.D.C.value='hi there'
54 """
54 """
55
55
56 class TestPyFileCL(TestCase):
56 class TestPyFileCL(TestCase):
57
57
58 def test_basic(self):
58 def test_basic(self):
59 fd, fname = mkstemp('.py')
59 fd, fname = mkstemp('.py')
60 f = os.fdopen(fd, 'w')
60 f = os.fdopen(fd, 'w')
61 f.write(pyfile)
61 f.write(pyfile)
62 f.close()
62 f.close()
63 # Unlink the file
63 # Unlink the file
64 cl = PyFileConfigLoader(fname)
64 cl = PyFileConfigLoader(fname)
65 config = cl.load_config()
65 config = cl.load_config()
66 self.assertEquals(config.a, 10)
66 self.assertEquals(config.a, 10)
67 self.assertEquals(config.b, 20)
67 self.assertEquals(config.b, 20)
68 self.assertEquals(config.Foo.Bar.value, 10)
68 self.assertEquals(config.Foo.Bar.value, 10)
69 self.assertEquals(config.Foo.Bam.value, range(10))
69 self.assertEquals(config.Foo.Bam.value, range(10))
70 self.assertEquals(config.D.C.value, 'hi there')
70 self.assertEquals(config.D.C.value, 'hi there')
71
71
72 class MyLoader1(ArgParseConfigLoader):
72 class MyLoader1(ArgParseConfigLoader):
73 def _add_arguments(self, aliases=None, flags=None):
73 def _add_arguments(self, aliases=None, flags=None):
74 p = self.parser
74 p = self.parser
75 p.add_argument('-f', '--foo', dest='Global.foo', type=str)
75 p.add_argument('-f', '--foo', dest='Global.foo', type=str)
76 p.add_argument('-b', dest='MyClass.bar', type=int)
76 p.add_argument('-b', dest='MyClass.bar', type=int)
77 p.add_argument('-n', dest='n', action='store_true')
77 p.add_argument('-n', dest='n', action='store_true')
78 p.add_argument('Global.bam', type=str)
78 p.add_argument('Global.bam', type=str)
79
79
80 class MyLoader2(ArgParseConfigLoader):
80 class MyLoader2(ArgParseConfigLoader):
81 def _add_arguments(self, aliases=None, flags=None):
81 def _add_arguments(self, aliases=None, flags=None):
82 subparsers = self.parser.add_subparsers(dest='subparser_name')
82 subparsers = self.parser.add_subparsers(dest='subparser_name')
83 subparser1 = subparsers.add_parser('1')
83 subparser1 = subparsers.add_parser('1')
84 subparser1.add_argument('-x',dest='Global.x')
84 subparser1.add_argument('-x',dest='Global.x')
85 subparser2 = subparsers.add_parser('2')
85 subparser2 = subparsers.add_parser('2')
86 subparser2.add_argument('y')
86 subparser2.add_argument('y')
87
87
88 class TestArgParseCL(TestCase):
88 class TestArgParseCL(TestCase):
89
89
90 def test_basic(self):
90 def test_basic(self):
91 cl = MyLoader1()
91 cl = MyLoader1()
92 config = cl.load_config('-f hi -b 10 -n wow'.split())
92 config = cl.load_config('-f hi -b 10 -n wow'.split())
93 self.assertEquals(config.Global.foo, 'hi')
93 self.assertEquals(config.Global.foo, 'hi')
94 self.assertEquals(config.MyClass.bar, 10)
94 self.assertEquals(config.MyClass.bar, 10)
95 self.assertEquals(config.n, True)
95 self.assertEquals(config.n, True)
96 self.assertEquals(config.Global.bam, 'wow')
96 self.assertEquals(config.Global.bam, 'wow')
97 config = cl.load_config(['wow'])
97 config = cl.load_config(['wow'])
98 self.assertEquals(config.keys(), ['Global'])
98 self.assertEquals(config.keys(), ['Global'])
99 self.assertEquals(config.Global.keys(), ['bam'])
99 self.assertEquals(config.Global.keys(), ['bam'])
100 self.assertEquals(config.Global.bam, 'wow')
100 self.assertEquals(config.Global.bam, 'wow')
101
101
102 def test_add_arguments(self):
102 def test_add_arguments(self):
103 cl = MyLoader2()
103 cl = MyLoader2()
104 config = cl.load_config('2 frobble'.split())
104 config = cl.load_config('2 frobble'.split())
105 self.assertEquals(config.subparser_name, '2')
105 self.assertEquals(config.subparser_name, '2')
106 self.assertEquals(config.y, 'frobble')
106 self.assertEquals(config.y, 'frobble')
107 config = cl.load_config('1 -x frobble'.split())
107 config = cl.load_config('1 -x frobble'.split())
108 self.assertEquals(config.subparser_name, '1')
108 self.assertEquals(config.subparser_name, '1')
109 self.assertEquals(config.Global.x, 'frobble')
109 self.assertEquals(config.Global.x, 'frobble')
110
110
111 def test_argv(self):
111 def test_argv(self):
112 cl = MyLoader1(argv='-f hi -b 10 -n wow'.split())
112 cl = MyLoader1(argv='-f hi -b 10 -n wow'.split())
113 config = cl.load_config()
113 config = cl.load_config()
114 self.assertEquals(config.Global.foo, 'hi')
114 self.assertEquals(config.Global.foo, 'hi')
115 self.assertEquals(config.MyClass.bar, 10)
115 self.assertEquals(config.MyClass.bar, 10)
116 self.assertEquals(config.n, True)
116 self.assertEquals(config.n, True)
117 self.assertEquals(config.Global.bam, 'wow')
117 self.assertEquals(config.Global.bam, 'wow')
118
118
119
119
120 class TestKeyValueCL(TestCase):
120 class TestKeyValueCL(TestCase):
121 klass = KeyValueConfigLoader
121 klass = KeyValueConfigLoader
122
122
123 def test_basic(self):
123 def test_basic(self):
124 cl = self.klass()
124 cl = self.klass()
125 argv = ['--'+s.strip('c.') for s in pyfile.split('\n')[2:-1]]
125 argv = ['--'+s.strip('c.') for s in pyfile.split('\n')[2:-1]]
126 with mute_warn():
126 with mute_warn():
127 config = cl.load_config(argv)
127 config = cl.load_config(argv)
128 self.assertEquals(config.a, 10)
128 self.assertEquals(config.a, 10)
129 self.assertEquals(config.b, 20)
129 self.assertEquals(config.b, 20)
130 self.assertEquals(config.Foo.Bar.value, 10)
130 self.assertEquals(config.Foo.Bar.value, 10)
131 self.assertEquals(config.Foo.Bam.value, range(10))
131 self.assertEquals(config.Foo.Bam.value, range(10))
132 self.assertEquals(config.D.C.value, 'hi there')
132 self.assertEquals(config.D.C.value, 'hi there')
133
133
134 def test_expanduser(self):
134 def test_expanduser(self):
135 cl = self.klass()
135 cl = self.klass()
136 argv = ['--a=~/1/2/3', '--b=~', '--c=~/', '--d="~/"']
136 argv = ['--a=~/1/2/3', '--b=~', '--c=~/', '--d="~/"']
137 with mute_warn():
137 with mute_warn():
138 config = cl.load_config(argv)
138 config = cl.load_config(argv)
139 self.assertEquals(config.a, os.path.expanduser('~/1/2/3'))
139 self.assertEquals(config.a, os.path.expanduser('~/1/2/3'))
140 self.assertEquals(config.b, os.path.expanduser('~'))
140 self.assertEquals(config.b, os.path.expanduser('~'))
141 self.assertEquals(config.c, os.path.expanduser('~/'))
141 self.assertEquals(config.c, os.path.expanduser('~/'))
142 self.assertEquals(config.d, '~/')
142 self.assertEquals(config.d, '~/')
143
143
144 def test_extra_args(self):
144 def test_extra_args(self):
145 cl = self.klass()
145 cl = self.klass()
146 with mute_warn():
146 with mute_warn():
147 config = cl.load_config(['--a=5', 'b', '--c=10', 'd'])
147 config = cl.load_config(['--a=5', 'b', '--c=10', 'd'])
148 self.assertEquals(cl.extra_args, ['b', 'd'])
148 self.assertEquals(cl.extra_args, ['b', 'd'])
149 self.assertEquals(config.a, 5)
149 self.assertEquals(config.a, 5)
150 self.assertEquals(config.c, 10)
150 self.assertEquals(config.c, 10)
151 with mute_warn():
151 with mute_warn():
152 config = cl.load_config(['--', '--a=5', '--c=10'])
152 config = cl.load_config(['--', '--a=5', '--c=10'])
153 self.assertEquals(cl.extra_args, ['--a=5', '--c=10'])
153 self.assertEquals(cl.extra_args, ['--a=5', '--c=10'])
154
154
155 def test_unicode_args(self):
155 def test_unicode_args(self):
156 cl = self.klass()
156 cl = self.klass()
157 argv = [u'--a=épsîlön']
157 argv = [u'--a=épsîlön']
158 with mute_warn():
158 with mute_warn():
159 config = cl.load_config(argv)
159 config = cl.load_config(argv)
160 self.assertEquals(config.a, u'épsîlön')
160 self.assertEquals(config.a, u'épsîlön')
161
161
162 def test_unicode_bytes_args(self):
162 def test_unicode_bytes_args(self):
163 uarg = u'--a=é'
163 uarg = u'--a=é'
164 try:
164 try:
165 barg = uarg.encode(sys.stdin.encoding)
165 barg = uarg.encode(sys.stdin.encoding)
166 except (TypeError, UnicodeEncodeError):
166 except (TypeError, UnicodeEncodeError):
167 raise SkipTest("sys.stdin.encoding can't handle 'é'")
167 raise SkipTest("sys.stdin.encoding can't handle 'é'")
168
168
169 cl = self.klass()
169 cl = self.klass()
170 with mute_warn():
170 with mute_warn():
171 config = cl.load_config([barg])
171 config = cl.load_config([barg])
172 self.assertEquals(config.a, u'é')
172 self.assertEquals(config.a, u'é')
173
173
174 def test_unicode_alias(self):
174 def test_unicode_alias(self):
175 cl = self.klass()
175 cl = self.klass()
176 argv = [u'--a=épsîlön']
176 argv = [u'--a=épsîlön']
177 with mute_warn():
177 with mute_warn():
178 config = cl.load_config(argv, aliases=dict(a='A.a'))
178 config = cl.load_config(argv, aliases=dict(a='A.a'))
179 self.assertEquals(config.A.a, u'épsîlön')
179 self.assertEquals(config.A.a, u'épsîlön')
180
180
181
181
182 class TestArgParseKVCL(TestKeyValueCL):
182 class TestArgParseKVCL(TestKeyValueCL):
183 klass = KVArgParseConfigLoader
183 klass = KVArgParseConfigLoader
184
184
185 def test_expanduser2(self):
185 def test_expanduser2(self):
186 cl = self.klass()
186 cl = self.klass()
187 argv = ['-a', '~/1/2/3', '--b', "'~/1/2/3'"]
187 argv = ['-a', '~/1/2/3', '--b', "'~/1/2/3'"]
188 with mute_warn():
188 with mute_warn():
189 config = cl.load_config(argv, aliases=dict(a='A.a', b='A.b'))
189 config = cl.load_config(argv, aliases=dict(a='A.a', b='A.b'))
190 self.assertEquals(config.A.a, os.path.expanduser('~/1/2/3'))
190 self.assertEquals(config.A.a, os.path.expanduser('~/1/2/3'))
191 self.assertEquals(config.A.b, '~/1/2/3')
191 self.assertEquals(config.A.b, '~/1/2/3')
192
192
193 class TestConfig(TestCase):
193 class TestConfig(TestCase):
194
194
195 def test_setget(self):
195 def test_setget(self):
196 c = Config()
196 c = Config()
197 c.a = 10
197 c.a = 10
198 self.assertEquals(c.a, 10)
198 self.assertEquals(c.a, 10)
199 self.assertEquals(c.has_key('b'), False)
199 self.assertEquals(c.has_key('b'), False)
200
200
201 def test_auto_section(self):
201 def test_auto_section(self):
202 c = Config()
202 c = Config()
203 self.assertEquals(c.has_key('A'), True)
203 self.assertEquals(c.has_key('A'), True)
204 self.assertEquals(c._has_section('A'), False)
204 self.assertEquals(c._has_section('A'), False)
205 A = c.A
205 A = c.A
206 A.foo = 'hi there'
206 A.foo = 'hi there'
207 self.assertEquals(c._has_section('A'), True)
207 self.assertEquals(c._has_section('A'), True)
208 self.assertEquals(c.A.foo, 'hi there')
208 self.assertEquals(c.A.foo, 'hi there')
209 del c.A
209 del c.A
210 self.assertEquals(len(c.A.keys()),0)
210 self.assertEquals(len(c.A.keys()),0)
211
211
212 def test_merge_doesnt_exist(self):
212 def test_merge_doesnt_exist(self):
213 c1 = Config()
213 c1 = Config()
214 c2 = Config()
214 c2 = Config()
215 c2.bar = 10
215 c2.bar = 10
216 c2.Foo.bar = 10
216 c2.Foo.bar = 10
217 c1._merge(c2)
217 c1._merge(c2)
218 self.assertEquals(c1.Foo.bar, 10)
218 self.assertEquals(c1.Foo.bar, 10)
219 self.assertEquals(c1.bar, 10)
219 self.assertEquals(c1.bar, 10)
220 c2.Bar.bar = 10
220 c2.Bar.bar = 10
221 c1._merge(c2)
221 c1._merge(c2)
222 self.assertEquals(c1.Bar.bar, 10)
222 self.assertEquals(c1.Bar.bar, 10)
223
223
224 def test_merge_exists(self):
224 def test_merge_exists(self):
225 c1 = Config()
225 c1 = Config()
226 c2 = Config()
226 c2 = Config()
227 c1.Foo.bar = 10
227 c1.Foo.bar = 10
228 c1.Foo.bam = 30
228 c1.Foo.bam = 30
229 c2.Foo.bar = 20
229 c2.Foo.bar = 20
230 c2.Foo.wow = 40
230 c2.Foo.wow = 40
231 c1._merge(c2)
231 c1._merge(c2)
232 self.assertEquals(c1.Foo.bam, 30)
232 self.assertEquals(c1.Foo.bam, 30)
233 self.assertEquals(c1.Foo.bar, 20)
233 self.assertEquals(c1.Foo.bar, 20)
234 self.assertEquals(c1.Foo.wow, 40)
234 self.assertEquals(c1.Foo.wow, 40)
235 c2.Foo.Bam.bam = 10
235 c2.Foo.Bam.bam = 10
236 c1._merge(c2)
236 c1._merge(c2)
237 self.assertEquals(c1.Foo.Bam.bam, 10)
237 self.assertEquals(c1.Foo.Bam.bam, 10)
238
238
239 def test_deepcopy(self):
239 def test_deepcopy(self):
240 c1 = Config()
240 c1 = Config()
241 c1.Foo.bar = 10
241 c1.Foo.bar = 10
242 c1.Foo.bam = 30
242 c1.Foo.bam = 30
243 c1.a = 'asdf'
243 c1.a = 'asdf'
244 c1.b = range(10)
244 c1.b = range(10)
245 import copy
245 import copy
246 c2 = copy.deepcopy(c1)
246 c2 = copy.deepcopy(c1)
247 self.assertEquals(c1, c2)
247 self.assertEquals(c1, c2)
248 self.assert_(c1 is not c2)
248 self.assert_(c1 is not c2)
249 self.assert_(c1.Foo is not c2.Foo)
249 self.assert_(c1.Foo is not c2.Foo)
250
250
251 def test_builtin(self):
251 def test_builtin(self):
252 c1 = Config()
252 c1 = Config()
253 exec 'foo = True' in c1
253 exec 'foo = True' in c1
254 self.assertEquals(c1.foo, True)
254 self.assertEquals(c1.foo, True)
255 self.assertRaises(ConfigError, setattr, c1, 'ValueError', 10)
255 self.assertRaises(ConfigError, setattr, c1, 'ValueError', 10)
@@ -1,263 +1,263 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 System command aliases.
3 System command aliases.
4
4
5 Authors:
5 Authors:
6
6
7 * Fernando Perez
7 * Fernando Perez
8 * Brian Granger
8 * Brian Granger
9 """
9 """
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Copyright (C) 2008-2010 The IPython Development Team
12 # Copyright (C) 2008-2011 The IPython Development Team
13 #
13 #
14 # Distributed under the terms of the BSD License.
14 # Distributed under the terms of the BSD License.
15 #
15 #
16 # The full license is in the file COPYING.txt, distributed with this software.
16 # The full license is in the file COPYING.txt, distributed with this software.
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Imports
20 # Imports
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22
22
23 import __builtin__
23 import __builtin__
24 import keyword
24 import keyword
25 import os
25 import os
26 import re
26 import re
27 import sys
27 import sys
28
28
29 from IPython.config.configurable import Configurable
29 from IPython.config.configurable import Configurable
30 from IPython.core.splitinput import split_user_input
30 from IPython.core.splitinput import split_user_input
31
31
32 from IPython.utils.traitlets import List, Instance
32 from IPython.utils.traitlets import List, Instance
33 from IPython.utils.autoattr import auto_attr
33 from IPython.utils.autoattr import auto_attr
34 from IPython.utils.warn import warn, error
34 from IPython.utils.warn import warn, error
35
35
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37 # Utilities
37 # Utilities
38 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
39
39
40 # This is used as the pattern for calls to split_user_input.
40 # This is used as the pattern for calls to split_user_input.
41 shell_line_split = re.compile(r'^(\s*)()(\S+)(.*$)')
41 shell_line_split = re.compile(r'^(\s*)()(\S+)(.*$)')
42
42
43 def default_aliases():
43 def default_aliases():
44 """Return list of shell aliases to auto-define.
44 """Return list of shell aliases to auto-define.
45 """
45 """
46 # Note: the aliases defined here should be safe to use on a kernel
46 # Note: the aliases defined here should be safe to use on a kernel
47 # regardless of what frontend it is attached to. Frontends that use a
47 # regardless of what frontend it is attached to. Frontends that use a
48 # kernel in-process can define additional aliases that will only work in
48 # kernel in-process can define additional aliases that will only work in
49 # their case. For example, things like 'less' or 'clear' that manipulate
49 # their case. For example, things like 'less' or 'clear' that manipulate
50 # the terminal should NOT be declared here, as they will only work if the
50 # the terminal should NOT be declared here, as they will only work if the
51 # kernel is running inside a true terminal, and not over the network.
51 # kernel is running inside a true terminal, and not over the network.
52
52
53 if os.name == 'posix':
53 if os.name == 'posix':
54 default_aliases = [('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
54 default_aliases = [('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
55 ('mv', 'mv -i'), ('rm', 'rm -i'), ('cp', 'cp -i'),
55 ('mv', 'mv -i'), ('rm', 'rm -i'), ('cp', 'cp -i'),
56 ('cat', 'cat'),
56 ('cat', 'cat'),
57 ]
57 ]
58 # Useful set of ls aliases. The GNU and BSD options are a little
58 # Useful set of ls aliases. The GNU and BSD options are a little
59 # different, so we make aliases that provide as similar as possible
59 # different, so we make aliases that provide as similar as possible
60 # behavior in ipython, by passing the right flags for each platform
60 # behavior in ipython, by passing the right flags for each platform
61 if sys.platform.startswith('linux'):
61 if sys.platform.startswith('linux'):
62 ls_aliases = [('ls', 'ls -F --color'),
62 ls_aliases = [('ls', 'ls -F --color'),
63 # long ls
63 # long ls
64 ('ll', 'ls -F -o --color'),
64 ('ll', 'ls -F -o --color'),
65 # ls normal files only
65 # ls normal files only
66 ('lf', 'ls -F -o --color %l | grep ^-'),
66 ('lf', 'ls -F -o --color %l | grep ^-'),
67 # ls symbolic links
67 # ls symbolic links
68 ('lk', 'ls -F -o --color %l | grep ^l'),
68 ('lk', 'ls -F -o --color %l | grep ^l'),
69 # directories or links to directories,
69 # directories or links to directories,
70 ('ldir', 'ls -F -o --color %l | grep /$'),
70 ('ldir', 'ls -F -o --color %l | grep /$'),
71 # things which are executable
71 # things which are executable
72 ('lx', 'ls -F -o --color %l | grep ^-..x'),
72 ('lx', 'ls -F -o --color %l | grep ^-..x'),
73 ]
73 ]
74 else:
74 else:
75 # BSD, OSX, etc.
75 # BSD, OSX, etc.
76 ls_aliases = [('ls', 'ls -F'),
76 ls_aliases = [('ls', 'ls -F'),
77 # long ls
77 # long ls
78 ('ll', 'ls -F -l'),
78 ('ll', 'ls -F -l'),
79 # ls normal files only
79 # ls normal files only
80 ('lf', 'ls -F -l %l | grep ^-'),
80 ('lf', 'ls -F -l %l | grep ^-'),
81 # ls symbolic links
81 # ls symbolic links
82 ('lk', 'ls -F -l %l | grep ^l'),
82 ('lk', 'ls -F -l %l | grep ^l'),
83 # directories or links to directories,
83 # directories or links to directories,
84 ('ldir', 'ls -F -l %l | grep /$'),
84 ('ldir', 'ls -F -l %l | grep /$'),
85 # things which are executable
85 # things which are executable
86 ('lx', 'ls -F -l %l | grep ^-..x'),
86 ('lx', 'ls -F -l %l | grep ^-..x'),
87 ]
87 ]
88 default_aliases = default_aliases + ls_aliases
88 default_aliases = default_aliases + ls_aliases
89 elif os.name in ['nt', 'dos']:
89 elif os.name in ['nt', 'dos']:
90 default_aliases = [('ls', 'dir /on'),
90 default_aliases = [('ls', 'dir /on'),
91 ('ddir', 'dir /ad /on'), ('ldir', 'dir /ad /on'),
91 ('ddir', 'dir /ad /on'), ('ldir', 'dir /ad /on'),
92 ('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
92 ('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
93 ('echo', 'echo'), ('ren', 'ren'), ('copy', 'copy'),
93 ('echo', 'echo'), ('ren', 'ren'), ('copy', 'copy'),
94 ]
94 ]
95 else:
95 else:
96 default_aliases = []
96 default_aliases = []
97
97
98 return default_aliases
98 return default_aliases
99
99
100
100
101 class AliasError(Exception):
101 class AliasError(Exception):
102 pass
102 pass
103
103
104
104
105 class InvalidAliasError(AliasError):
105 class InvalidAliasError(AliasError):
106 pass
106 pass
107
107
108 #-----------------------------------------------------------------------------
108 #-----------------------------------------------------------------------------
109 # Main AliasManager class
109 # Main AliasManager class
110 #-----------------------------------------------------------------------------
110 #-----------------------------------------------------------------------------
111
111
112 class AliasManager(Configurable):
112 class AliasManager(Configurable):
113
113
114 default_aliases = List(default_aliases(), config=True)
114 default_aliases = List(default_aliases(), config=True)
115 user_aliases = List(default_value=[], config=True)
115 user_aliases = List(default_value=[], config=True)
116 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
116 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
117
117
118 def __init__(self, shell=None, config=None):
118 def __init__(self, shell=None, config=None):
119 super(AliasManager, self).__init__(shell=shell, config=config)
119 super(AliasManager, self).__init__(shell=shell, config=config)
120 self.alias_table = {}
120 self.alias_table = {}
121 self.exclude_aliases()
121 self.exclude_aliases()
122 self.init_aliases()
122 self.init_aliases()
123
123
124 def __contains__(self, name):
124 def __contains__(self, name):
125 return name in self.alias_table
125 return name in self.alias_table
126
126
127 @property
127 @property
128 def aliases(self):
128 def aliases(self):
129 return [(item[0], item[1][1]) for item in self.alias_table.iteritems()]
129 return [(item[0], item[1][1]) for item in self.alias_table.iteritems()]
130
130
131 def exclude_aliases(self):
131 def exclude_aliases(self):
132 # set of things NOT to alias (keywords, builtins and some magics)
132 # set of things NOT to alias (keywords, builtins and some magics)
133 no_alias = set(['cd','popd','pushd','dhist','alias','unalias'])
133 no_alias = set(['cd','popd','pushd','dhist','alias','unalias'])
134 no_alias.update(set(keyword.kwlist))
134 no_alias.update(set(keyword.kwlist))
135 no_alias.update(set(__builtin__.__dict__.keys()))
135 no_alias.update(set(__builtin__.__dict__.keys()))
136 self.no_alias = no_alias
136 self.no_alias = no_alias
137
137
138 def init_aliases(self):
138 def init_aliases(self):
139 # Load default aliases
139 # Load default aliases
140 for name, cmd in self.default_aliases:
140 for name, cmd in self.default_aliases:
141 self.soft_define_alias(name, cmd)
141 self.soft_define_alias(name, cmd)
142
142
143 # Load user aliases
143 # Load user aliases
144 for name, cmd in self.user_aliases:
144 for name, cmd in self.user_aliases:
145 self.soft_define_alias(name, cmd)
145 self.soft_define_alias(name, cmd)
146
146
147 def clear_aliases(self):
147 def clear_aliases(self):
148 self.alias_table.clear()
148 self.alias_table.clear()
149
149
150 def soft_define_alias(self, name, cmd):
150 def soft_define_alias(self, name, cmd):
151 """Define an alias, but don't raise on an AliasError."""
151 """Define an alias, but don't raise on an AliasError."""
152 try:
152 try:
153 self.define_alias(name, cmd)
153 self.define_alias(name, cmd)
154 except AliasError, e:
154 except AliasError, e:
155 error("Invalid alias: %s" % e)
155 error("Invalid alias: %s" % e)
156
156
157 def define_alias(self, name, cmd):
157 def define_alias(self, name, cmd):
158 """Define a new alias after validating it.
158 """Define a new alias after validating it.
159
159
160 This will raise an :exc:`AliasError` if there are validation
160 This will raise an :exc:`AliasError` if there are validation
161 problems.
161 problems.
162 """
162 """
163 nargs = self.validate_alias(name, cmd)
163 nargs = self.validate_alias(name, cmd)
164 self.alias_table[name] = (nargs, cmd)
164 self.alias_table[name] = (nargs, cmd)
165
165
166 def undefine_alias(self, name):
166 def undefine_alias(self, name):
167 if self.alias_table.has_key(name):
167 if self.alias_table.has_key(name):
168 del self.alias_table[name]
168 del self.alias_table[name]
169
169
170 def validate_alias(self, name, cmd):
170 def validate_alias(self, name, cmd):
171 """Validate an alias and return the its number of arguments."""
171 """Validate an alias and return the its number of arguments."""
172 if name in self.no_alias:
172 if name in self.no_alias:
173 raise InvalidAliasError("The name %s can't be aliased "
173 raise InvalidAliasError("The name %s can't be aliased "
174 "because it is a keyword or builtin." % name)
174 "because it is a keyword or builtin." % name)
175 if not (isinstance(cmd, basestring)):
175 if not (isinstance(cmd, basestring)):
176 raise InvalidAliasError("An alias command must be a string, "
176 raise InvalidAliasError("An alias command must be a string, "
177 "got: %r" % cmd)
177 "got: %r" % cmd)
178 nargs = cmd.count('%s')
178 nargs = cmd.count('%s')
179 if nargs>0 and cmd.find('%l')>=0:
179 if nargs>0 and cmd.find('%l')>=0:
180 raise InvalidAliasError('The %s and %l specifiers are mutually '
180 raise InvalidAliasError('The %s and %l specifiers are mutually '
181 'exclusive in alias definitions.')
181 'exclusive in alias definitions.')
182 return nargs
182 return nargs
183
183
184 def call_alias(self, alias, rest=''):
184 def call_alias(self, alias, rest=''):
185 """Call an alias given its name and the rest of the line."""
185 """Call an alias given its name and the rest of the line."""
186 cmd = self.transform_alias(alias, rest)
186 cmd = self.transform_alias(alias, rest)
187 try:
187 try:
188 self.shell.system(cmd)
188 self.shell.system(cmd)
189 except:
189 except:
190 self.shell.showtraceback()
190 self.shell.showtraceback()
191
191
192 def transform_alias(self, alias,rest=''):
192 def transform_alias(self, alias,rest=''):
193 """Transform alias to system command string."""
193 """Transform alias to system command string."""
194 nargs, cmd = self.alias_table[alias]
194 nargs, cmd = self.alias_table[alias]
195
195
196 if ' ' in cmd and os.path.isfile(cmd):
196 if ' ' in cmd and os.path.isfile(cmd):
197 cmd = '"%s"' % cmd
197 cmd = '"%s"' % cmd
198
198
199 # Expand the %l special to be the user's input line
199 # Expand the %l special to be the user's input line
200 if cmd.find('%l') >= 0:
200 if cmd.find('%l') >= 0:
201 cmd = cmd.replace('%l', rest)
201 cmd = cmd.replace('%l', rest)
202 rest = ''
202 rest = ''
203 if nargs==0:
203 if nargs==0:
204 # Simple, argument-less aliases
204 # Simple, argument-less aliases
205 cmd = '%s %s' % (cmd, rest)
205 cmd = '%s %s' % (cmd, rest)
206 else:
206 else:
207 # Handle aliases with positional arguments
207 # Handle aliases with positional arguments
208 args = rest.split(None, nargs)
208 args = rest.split(None, nargs)
209 if len(args) < nargs:
209 if len(args) < nargs:
210 raise AliasError('Alias <%s> requires %s arguments, %s given.' %
210 raise AliasError('Alias <%s> requires %s arguments, %s given.' %
211 (alias, nargs, len(args)))
211 (alias, nargs, len(args)))
212 cmd = '%s %s' % (cmd % tuple(args[:nargs]),' '.join(args[nargs:]))
212 cmd = '%s %s' % (cmd % tuple(args[:nargs]),' '.join(args[nargs:]))
213 return cmd
213 return cmd
214
214
215 def expand_alias(self, line):
215 def expand_alias(self, line):
216 """ Expand an alias in the command line
216 """ Expand an alias in the command line
217
217
218 Returns the provided command line, possibly with the first word
218 Returns the provided command line, possibly with the first word
219 (command) translated according to alias expansion rules.
219 (command) translated according to alias expansion rules.
220
220
221 [ipython]|16> _ip.expand_aliases("np myfile.txt")
221 [ipython]|16> _ip.expand_aliases("np myfile.txt")
222 <16> 'q:/opt/np/notepad++.exe myfile.txt'
222 <16> 'q:/opt/np/notepad++.exe myfile.txt'
223 """
223 """
224
224
225 pre,_,fn,rest = split_user_input(line)
225 pre,_,fn,rest = split_user_input(line)
226 res = pre + self.expand_aliases(fn, rest)
226 res = pre + self.expand_aliases(fn, rest)
227 return res
227 return res
228
228
229 def expand_aliases(self, fn, rest):
229 def expand_aliases(self, fn, rest):
230 """Expand multiple levels of aliases:
230 """Expand multiple levels of aliases:
231
231
232 if:
232 if:
233
233
234 alias foo bar /tmp
234 alias foo bar /tmp
235 alias baz foo
235 alias baz foo
236
236
237 then:
237 then:
238
238
239 baz huhhahhei -> bar /tmp huhhahhei
239 baz huhhahhei -> bar /tmp huhhahhei
240 """
240 """
241 line = fn + " " + rest
241 line = fn + " " + rest
242
242
243 done = set()
243 done = set()
244 while 1:
244 while 1:
245 pre,_,fn,rest = split_user_input(line, shell_line_split)
245 pre,_,fn,rest = split_user_input(line, shell_line_split)
246 if fn in self.alias_table:
246 if fn in self.alias_table:
247 if fn in done:
247 if fn in done:
248 warn("Cyclic alias definition, repeated '%s'" % fn)
248 warn("Cyclic alias definition, repeated '%s'" % fn)
249 return ""
249 return ""
250 done.add(fn)
250 done.add(fn)
251
251
252 l2 = self.transform_alias(fn, rest)
252 l2 = self.transform_alias(fn, rest)
253 if l2 == line:
253 if l2 == line:
254 break
254 break
255 # ls -> ls -F should not recurse forever
255 # ls -> ls -F should not recurse forever
256 if l2.split(None,1)[0] == line.split(None,1)[0]:
256 if l2.split(None,1)[0] == line.split(None,1)[0]:
257 line = l2
257 line = l2
258 break
258 break
259 line=l2
259 line=l2
260 else:
260 else:
261 break
261 break
262
262
263 return line
263 return line
@@ -1,70 +1,70 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Autocall capabilities for IPython.core.
3 Autocall capabilities for IPython.core.
4
4
5 Authors:
5 Authors:
6
6
7 * Brian Granger
7 * Brian Granger
8 * Fernando Perez
8 * Fernando Perez
9 * Thomas Kluyver
9 * Thomas Kluyver
10
10
11 Notes
11 Notes
12 -----
12 -----
13 """
13 """
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Copyright (C) 2008-2009 The IPython Development Team
16 # Copyright (C) 2008-2011 The IPython Development Team
17 #
17 #
18 # Distributed under the terms of the BSD License. The full license is in
18 # Distributed under the terms of the BSD License. The full license is in
19 # the file COPYING, distributed as part of this software.
19 # the file COPYING, distributed as part of this software.
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 # Imports
23 # Imports
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26
26
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28 # Code
28 # Code
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30
30
31 class IPyAutocall(object):
31 class IPyAutocall(object):
32 """ Instances of this class are always autocalled
32 """ Instances of this class are always autocalled
33
33
34 This happens regardless of 'autocall' variable state. Use this to
34 This happens regardless of 'autocall' variable state. Use this to
35 develop macro-like mechanisms.
35 develop macro-like mechanisms.
36 """
36 """
37 _ip = None
37 _ip = None
38 rewrite = True
38 rewrite = True
39 def __init__(self, ip=None):
39 def __init__(self, ip=None):
40 self._ip = ip
40 self._ip = ip
41
41
42 def set_ip(self, ip):
42 def set_ip(self, ip):
43 """ Will be used to set _ip point to current ipython instance b/f call
43 """ Will be used to set _ip point to current ipython instance b/f call
44
44
45 Override this method if you don't want this to happen.
45 Override this method if you don't want this to happen.
46
46
47 """
47 """
48 self._ip = ip
48 self._ip = ip
49
49
50
50
51 class ExitAutocall(IPyAutocall):
51 class ExitAutocall(IPyAutocall):
52 """An autocallable object which will be added to the user namespace so that
52 """An autocallable object which will be added to the user namespace so that
53 exit, exit(), quit or quit() are all valid ways to close the shell."""
53 exit, exit(), quit or quit() are all valid ways to close the shell."""
54 rewrite = False
54 rewrite = False
55
55
56 def __call__(self):
56 def __call__(self):
57 self._ip.ask_exit()
57 self._ip.ask_exit()
58
58
59 class ZMQExitAutocall(ExitAutocall):
59 class ZMQExitAutocall(ExitAutocall):
60 """Exit IPython. Autocallable, so it needn't be explicitly called.
60 """Exit IPython. Autocallable, so it needn't be explicitly called.
61
61
62 Parameters
62 Parameters
63 ----------
63 ----------
64 keep_kernel : bool
64 keep_kernel : bool
65 If True, leave the kernel alive. Otherwise, tell the kernel to exit too
65 If True, leave the kernel alive. Otherwise, tell the kernel to exit too
66 (default).
66 (default).
67 """
67 """
68 def __call__(self, keep_kernel=False):
68 def __call__(self, keep_kernel=False):
69 self._ip.keepkernel_on_exit = keep_kernel
69 self._ip.keepkernel_on_exit = keep_kernel
70 self._ip.ask_exit()
70 self._ip.ask_exit()
@@ -1,128 +1,128 b''
1 """
1 """
2 A context manager for managing things injected into :mod:`__builtin__`.
2 A context manager for managing things injected into :mod:`__builtin__`.
3
3
4 Authors:
4 Authors:
5
5
6 * Brian Granger
6 * Brian Granger
7 * Fernando Perez
7 * Fernando Perez
8 """
8 """
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2010 The IPython Development Team.
10 # Copyright (C) 2010-2011 The IPython Development Team.
11 #
11 #
12 # Distributed under the terms of the BSD License.
12 # Distributed under the terms of the BSD License.
13 #
13 #
14 # Complete license in the file COPYING.txt, distributed with this software.
14 # Complete license in the file COPYING.txt, distributed with this software.
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Imports
18 # Imports
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20
20
21 import __builtin__
21 import __builtin__
22
22
23 from IPython.config.configurable import Configurable
23 from IPython.config.configurable import Configurable
24
24
25 from IPython.utils.traitlets import Instance
25 from IPython.utils.traitlets import Instance
26
26
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28 # Classes and functions
28 # Classes and functions
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30
30
31 class __BuiltinUndefined(object): pass
31 class __BuiltinUndefined(object): pass
32 BuiltinUndefined = __BuiltinUndefined()
32 BuiltinUndefined = __BuiltinUndefined()
33
33
34 class __HideBuiltin(object): pass
34 class __HideBuiltin(object): pass
35 HideBuiltin = __HideBuiltin()
35 HideBuiltin = __HideBuiltin()
36
36
37
37
38 class BuiltinTrap(Configurable):
38 class BuiltinTrap(Configurable):
39
39
40 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
40 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
41
41
42 def __init__(self, shell=None):
42 def __init__(self, shell=None):
43 super(BuiltinTrap, self).__init__(shell=shell, config=None)
43 super(BuiltinTrap, self).__init__(shell=shell, config=None)
44 self._orig_builtins = {}
44 self._orig_builtins = {}
45 # We define this to track if a single BuiltinTrap is nested.
45 # We define this to track if a single BuiltinTrap is nested.
46 # Only turn off the trap when the outermost call to __exit__ is made.
46 # Only turn off the trap when the outermost call to __exit__ is made.
47 self._nested_level = 0
47 self._nested_level = 0
48 self.shell = shell
48 self.shell = shell
49 # builtins we always add - if set to HideBuiltin, they will just
49 # builtins we always add - if set to HideBuiltin, they will just
50 # be removed instead of being replaced by something else
50 # be removed instead of being replaced by something else
51 self.auto_builtins = {'exit': HideBuiltin,
51 self.auto_builtins = {'exit': HideBuiltin,
52 'quit': HideBuiltin,
52 'quit': HideBuiltin,
53 'get_ipython': self.shell.get_ipython,
53 'get_ipython': self.shell.get_ipython,
54 }
54 }
55 # Recursive reload function
55 # Recursive reload function
56 try:
56 try:
57 from IPython.lib import deepreload
57 from IPython.lib import deepreload
58 if self.shell.deep_reload:
58 if self.shell.deep_reload:
59 self.auto_builtins['reload'] = deepreload.reload
59 self.auto_builtins['reload'] = deepreload.reload
60 else:
60 else:
61 self.auto_builtins['dreload']= deepreload.reload
61 self.auto_builtins['dreload']= deepreload.reload
62 except ImportError:
62 except ImportError:
63 pass
63 pass
64
64
65 def __enter__(self):
65 def __enter__(self):
66 if self._nested_level == 0:
66 if self._nested_level == 0:
67 self.activate()
67 self.activate()
68 self._nested_level += 1
68 self._nested_level += 1
69 # I return self, so callers can use add_builtin in a with clause.
69 # I return self, so callers can use add_builtin in a with clause.
70 return self
70 return self
71
71
72 def __exit__(self, type, value, traceback):
72 def __exit__(self, type, value, traceback):
73 if self._nested_level == 1:
73 if self._nested_level == 1:
74 self.deactivate()
74 self.deactivate()
75 self._nested_level -= 1
75 self._nested_level -= 1
76 # Returning False will cause exceptions to propagate
76 # Returning False will cause exceptions to propagate
77 return False
77 return False
78
78
79 def add_builtin(self, key, value):
79 def add_builtin(self, key, value):
80 """Add a builtin and save the original."""
80 """Add a builtin and save the original."""
81 bdict = __builtin__.__dict__
81 bdict = __builtin__.__dict__
82 orig = bdict.get(key, BuiltinUndefined)
82 orig = bdict.get(key, BuiltinUndefined)
83 if value is HideBuiltin:
83 if value is HideBuiltin:
84 if orig is not BuiltinUndefined: #same as 'key in bdict'
84 if orig is not BuiltinUndefined: #same as 'key in bdict'
85 self._orig_builtins[key] = orig
85 self._orig_builtins[key] = orig
86 del bdict[key]
86 del bdict[key]
87 else:
87 else:
88 self._orig_builtins[key] = orig
88 self._orig_builtins[key] = orig
89 bdict[key] = value
89 bdict[key] = value
90
90
91 def remove_builtin(self, key):
91 def remove_builtin(self, key):
92 """Remove an added builtin and re-set the original."""
92 """Remove an added builtin and re-set the original."""
93 try:
93 try:
94 orig = self._orig_builtins.pop(key)
94 orig = self._orig_builtins.pop(key)
95 except KeyError:
95 except KeyError:
96 pass
96 pass
97 else:
97 else:
98 if orig is BuiltinUndefined:
98 if orig is BuiltinUndefined:
99 del __builtin__.__dict__[key]
99 del __builtin__.__dict__[key]
100 else:
100 else:
101 __builtin__.__dict__[key] = orig
101 __builtin__.__dict__[key] = orig
102
102
103 def activate(self):
103 def activate(self):
104 """Store ipython references in the __builtin__ namespace."""
104 """Store ipython references in the __builtin__ namespace."""
105
105
106 add_builtin = self.add_builtin
106 add_builtin = self.add_builtin
107 for name, func in self.auto_builtins.iteritems():
107 for name, func in self.auto_builtins.iteritems():
108 add_builtin(name, func)
108 add_builtin(name, func)
109
109
110 # Keep in the builtins a flag for when IPython is active. We set it
110 # Keep in the builtins a flag for when IPython is active. We set it
111 # with setdefault so that multiple nested IPythons don't clobber one
111 # with setdefault so that multiple nested IPythons don't clobber one
112 # another.
112 # another.
113 __builtin__.__dict__.setdefault('__IPYTHON__active', 0)
113 __builtin__.__dict__.setdefault('__IPYTHON__active', 0)
114
114
115 def deactivate(self):
115 def deactivate(self):
116 """Remove any builtins which might have been added by add_builtins, or
116 """Remove any builtins which might have been added by add_builtins, or
117 restore overwritten ones to their previous values."""
117 restore overwritten ones to their previous values."""
118 # Note: must iterate over a static keys() list because we'll be
118 # Note: must iterate over a static keys() list because we'll be
119 # mutating the dict itself
119 # mutating the dict itself
120 remove_builtin = self.remove_builtin
120 remove_builtin = self.remove_builtin
121 for key in self._orig_builtins.keys():
121 for key in self._orig_builtins.keys():
122 remove_builtin(key)
122 remove_builtin(key)
123 self._orig_builtins.clear()
123 self._orig_builtins.clear()
124 self._builtins_added = False
124 self._builtins_added = False
125 try:
125 try:
126 del __builtin__.__dict__['__IPYTHON__active']
126 del __builtin__.__dict__['__IPYTHON__active']
127 except KeyError:
127 except KeyError:
128 pass
128 pass
@@ -1,131 +1,131 b''
1 """Compiler tools with improved interactive support.
1 """Compiler tools with improved interactive support.
2
2
3 Provides compilation machinery similar to codeop, but with caching support so
3 Provides compilation machinery similar to codeop, but with caching support so
4 we can provide interactive tracebacks.
4 we can provide interactive tracebacks.
5
5
6 Authors
6 Authors
7 -------
7 -------
8 * Robert Kern
8 * Robert Kern
9 * Fernando Perez
9 * Fernando Perez
10 * Thomas Kluyver
10 * Thomas Kluyver
11 """
11 """
12
12
13 # Note: though it might be more natural to name this module 'compiler', that
13 # Note: though it might be more natural to name this module 'compiler', that
14 # name is in the stdlib and name collisions with the stdlib tend to produce
14 # name is in the stdlib and name collisions with the stdlib tend to produce
15 # weird problems (often with third-party tools).
15 # weird problems (often with third-party tools).
16
16
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Copyright (C) 2010 The IPython Development Team.
18 # Copyright (C) 2010-2011 The IPython Development Team.
19 #
19 #
20 # Distributed under the terms of the BSD License.
20 # Distributed under the terms of the BSD License.
21 #
21 #
22 # The full license is in the file COPYING.txt, distributed with this software.
22 # The full license is in the file COPYING.txt, distributed with this software.
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24
24
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26 # Imports
26 # Imports
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28 from __future__ import print_function
28 from __future__ import print_function
29
29
30 # Stdlib imports
30 # Stdlib imports
31 from ast import PyCF_ONLY_AST
31 from ast import PyCF_ONLY_AST
32 import codeop
32 import codeop
33 import hashlib
33 import hashlib
34 import linecache
34 import linecache
35 import time
35 import time
36
36
37 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
38 # Local utilities
38 # Local utilities
39 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
40
40
41 def code_name(code, number=0):
41 def code_name(code, number=0):
42 """ Compute a (probably) unique name for code for caching.
42 """ Compute a (probably) unique name for code for caching.
43
43
44 This now expects code to be unicode.
44 This now expects code to be unicode.
45 """
45 """
46 hash_digest = hashlib.md5(code.encode("utf-8")).hexdigest()
46 hash_digest = hashlib.md5(code.encode("utf-8")).hexdigest()
47 # Include the number and 12 characters of the hash in the name. It's
47 # Include the number and 12 characters of the hash in the name. It's
48 # pretty much impossible that in a single session we'll have collisions
48 # pretty much impossible that in a single session we'll have collisions
49 # even with truncated hashes, and the full one makes tracebacks too long
49 # even with truncated hashes, and the full one makes tracebacks too long
50 return '<ipython-input-{0}-{1}>'.format(number, hash_digest[:12])
50 return '<ipython-input-{0}-{1}>'.format(number, hash_digest[:12])
51
51
52 #-----------------------------------------------------------------------------
52 #-----------------------------------------------------------------------------
53 # Classes and functions
53 # Classes and functions
54 #-----------------------------------------------------------------------------
54 #-----------------------------------------------------------------------------
55
55
56 class CachingCompiler(codeop.Compile):
56 class CachingCompiler(codeop.Compile):
57 """A compiler that caches code compiled from interactive statements.
57 """A compiler that caches code compiled from interactive statements.
58 """
58 """
59
59
60 def __init__(self):
60 def __init__(self):
61 codeop.Compile.__init__(self)
61 codeop.Compile.__init__(self)
62
62
63 # This is ugly, but it must be done this way to allow multiple
63 # This is ugly, but it must be done this way to allow multiple
64 # simultaneous ipython instances to coexist. Since Python itself
64 # simultaneous ipython instances to coexist. Since Python itself
65 # directly accesses the data structures in the linecache module, and
65 # directly accesses the data structures in the linecache module, and
66 # the cache therein is global, we must work with that data structure.
66 # the cache therein is global, we must work with that data structure.
67 # We must hold a reference to the original checkcache routine and call
67 # We must hold a reference to the original checkcache routine and call
68 # that in our own check_cache() below, but the special IPython cache
68 # that in our own check_cache() below, but the special IPython cache
69 # must also be shared by all IPython instances. If we were to hold
69 # must also be shared by all IPython instances. If we were to hold
70 # separate caches (one in each CachingCompiler instance), any call made
70 # separate caches (one in each CachingCompiler instance), any call made
71 # by Python itself to linecache.checkcache() would obliterate the
71 # by Python itself to linecache.checkcache() would obliterate the
72 # cached data from the other IPython instances.
72 # cached data from the other IPython instances.
73 if not hasattr(linecache, '_ipython_cache'):
73 if not hasattr(linecache, '_ipython_cache'):
74 linecache._ipython_cache = {}
74 linecache._ipython_cache = {}
75 if not hasattr(linecache, '_checkcache_ori'):
75 if not hasattr(linecache, '_checkcache_ori'):
76 linecache._checkcache_ori = linecache.checkcache
76 linecache._checkcache_ori = linecache.checkcache
77 # Now, we must monkeypatch the linecache directly so that parts of the
77 # Now, we must monkeypatch the linecache directly so that parts of the
78 # stdlib that call it outside our control go through our codepath
78 # stdlib that call it outside our control go through our codepath
79 # (otherwise we'd lose our tracebacks).
79 # (otherwise we'd lose our tracebacks).
80 linecache.checkcache = self.check_cache
80 linecache.checkcache = self.check_cache
81
81
82 def ast_parse(self, source, filename='<unknown>', symbol='exec'):
82 def ast_parse(self, source, filename='<unknown>', symbol='exec'):
83 """Parse code to an AST with the current compiler flags active.
83 """Parse code to an AST with the current compiler flags active.
84
84
85 Arguments are exactly the same as ast.parse (in the standard library),
85 Arguments are exactly the same as ast.parse (in the standard library),
86 and are passed to the built-in compile function."""
86 and are passed to the built-in compile function."""
87 return compile(source, filename, symbol, self.flags | PyCF_ONLY_AST, 1)
87 return compile(source, filename, symbol, self.flags | PyCF_ONLY_AST, 1)
88
88
89 def reset_compiler_flags(self):
89 def reset_compiler_flags(self):
90 """Reset compiler flags to default state."""
90 """Reset compiler flags to default state."""
91 # This value is copied from codeop.Compile.__init__, so if that ever
91 # This value is copied from codeop.Compile.__init__, so if that ever
92 # changes, it will need to be updated.
92 # changes, it will need to be updated.
93 self.flags = codeop.PyCF_DONT_IMPLY_DEDENT
93 self.flags = codeop.PyCF_DONT_IMPLY_DEDENT
94
94
95 @property
95 @property
96 def compiler_flags(self):
96 def compiler_flags(self):
97 """Flags currently active in the compilation process.
97 """Flags currently active in the compilation process.
98 """
98 """
99 return self.flags
99 return self.flags
100
100
101 def cache(self, code, number=0):
101 def cache(self, code, number=0):
102 """Make a name for a block of code, and cache the code.
102 """Make a name for a block of code, and cache the code.
103
103
104 Parameters
104 Parameters
105 ----------
105 ----------
106 code : str
106 code : str
107 The Python source code to cache.
107 The Python source code to cache.
108 number : int
108 number : int
109 A number which forms part of the code's name. Used for the execution
109 A number which forms part of the code's name. Used for the execution
110 counter.
110 counter.
111
111
112 Returns
112 Returns
113 -------
113 -------
114 The name of the cached code (as a string). Pass this as the filename
114 The name of the cached code (as a string). Pass this as the filename
115 argument to compilation, so that tracebacks are correctly hooked up.
115 argument to compilation, so that tracebacks are correctly hooked up.
116 """
116 """
117 name = code_name(code, number)
117 name = code_name(code, number)
118 entry = (len(code), time.time(),
118 entry = (len(code), time.time(),
119 [line+'\n' for line in code.splitlines()], name)
119 [line+'\n' for line in code.splitlines()], name)
120 linecache.cache[name] = entry
120 linecache.cache[name] = entry
121 linecache._ipython_cache[name] = entry
121 linecache._ipython_cache[name] = entry
122 return name
122 return name
123
123
124 def check_cache(self, *args):
124 def check_cache(self, *args):
125 """Call linecache.checkcache() safely protecting our cached values.
125 """Call linecache.checkcache() safely protecting our cached values.
126 """
126 """
127 # First call the orignal checkcache as intended
127 # First call the orignal checkcache as intended
128 linecache._checkcache_ori(*args)
128 linecache._checkcache_ori(*args)
129 # Then, update back the cache with our data, so that tracebacks related
129 # Then, update back the cache with our data, so that tracebacks related
130 # to our compiled codes can be produced.
130 # to our compiled codes can be produced.
131 linecache.cache.update(linecache._ipython_cache)
131 linecache.cache.update(linecache._ipython_cache)
@@ -1,925 +1,925 b''
1 """Word completion for IPython.
1 """Word completion for IPython.
2
2
3 This module is a fork of the rlcompleter module in the Python standard
3 This module is a fork of the rlcompleter module in the Python standard
4 library. The original enhancements made to rlcompleter have been sent
4 library. The original enhancements made to rlcompleter have been sent
5 upstream and were accepted as of Python 2.3, but we need a lot more
5 upstream and were accepted as of Python 2.3, but we need a lot more
6 functionality specific to IPython, so this module will continue to live as an
6 functionality specific to IPython, so this module will continue to live as an
7 IPython-specific utility.
7 IPython-specific utility.
8
8
9 Original rlcompleter documentation:
9 Original rlcompleter documentation:
10
10
11 This requires the latest extension to the readline module (the
11 This requires the latest extension to the readline module (the
12 completes keywords, built-ins and globals in __main__; when completing
12 completes keywords, built-ins and globals in __main__; when completing
13 NAME.NAME..., it evaluates (!) the expression up to the last dot and
13 NAME.NAME..., it evaluates (!) the expression up to the last dot and
14 completes its attributes.
14 completes its attributes.
15
15
16 It's very cool to do "import string" type "string.", hit the
16 It's very cool to do "import string" type "string.", hit the
17 completion key (twice), and see the list of names defined by the
17 completion key (twice), and see the list of names defined by the
18 string module!
18 string module!
19
19
20 Tip: to use the tab key as the completion key, call
20 Tip: to use the tab key as the completion key, call
21
21
22 readline.parse_and_bind("tab: complete")
22 readline.parse_and_bind("tab: complete")
23
23
24 Notes:
24 Notes:
25
25
26 - Exceptions raised by the completer function are *ignored* (and
26 - Exceptions raised by the completer function are *ignored* (and
27 generally cause the completion to fail). This is a feature -- since
27 generally cause the completion to fail). This is a feature -- since
28 readline sets the tty device in raw (or cbreak) mode, printing a
28 readline sets the tty device in raw (or cbreak) mode, printing a
29 traceback wouldn't work well without some complicated hoopla to save,
29 traceback wouldn't work well without some complicated hoopla to save,
30 reset and restore the tty state.
30 reset and restore the tty state.
31
31
32 - The evaluation of the NAME.NAME... form may cause arbitrary
32 - The evaluation of the NAME.NAME... form may cause arbitrary
33 application defined code to be executed if an object with a
33 application defined code to be executed if an object with a
34 __getattr__ hook is found. Since it is the responsibility of the
34 __getattr__ hook is found. Since it is the responsibility of the
35 application (or the user) to enable this feature, I consider this an
35 application (or the user) to enable this feature, I consider this an
36 acceptable risk. More complicated expressions (e.g. function calls or
36 acceptable risk. More complicated expressions (e.g. function calls or
37 indexing operations) are *not* evaluated.
37 indexing operations) are *not* evaluated.
38
38
39 - GNU readline is also used by the built-in functions input() and
39 - GNU readline is also used by the built-in functions input() and
40 raw_input(), and thus these also benefit/suffer from the completer
40 raw_input(), and thus these also benefit/suffer from the completer
41 features. Clearly an interactive application can benefit by
41 features. Clearly an interactive application can benefit by
42 specifying its own completer function and using raw_input() for all
42 specifying its own completer function and using raw_input() for all
43 its input.
43 its input.
44
44
45 - When the original stdin is not a tty device, GNU readline is never
45 - When the original stdin is not a tty device, GNU readline is never
46 used, and this module (and the readline module) are silently inactive.
46 used, and this module (and the readline module) are silently inactive.
47 """
47 """
48
48
49 #*****************************************************************************
49 #*****************************************************************************
50 #
50 #
51 # Since this file is essentially a minimally modified copy of the rlcompleter
51 # Since this file is essentially a minimally modified copy of the rlcompleter
52 # module which is part of the standard Python distribution, I assume that the
52 # module which is part of the standard Python distribution, I assume that the
53 # proper procedure is to maintain its copyright as belonging to the Python
53 # proper procedure is to maintain its copyright as belonging to the Python
54 # Software Foundation (in addition to my own, for all new code).
54 # Software Foundation (in addition to my own, for all new code).
55 #
55 #
56 # Copyright (C) 2008-2010 IPython Development Team
56 # Copyright (C) 2008-2011 IPython Development Team
57 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
57 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
58 # Copyright (C) 2001 Python Software Foundation, www.python.org
58 # Copyright (C) 2001 Python Software Foundation, www.python.org
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 #*****************************************************************************
63 #*****************************************************************************
64 from __future__ import print_function
64 from __future__ import print_function
65
65
66 #-----------------------------------------------------------------------------
66 #-----------------------------------------------------------------------------
67 # Imports
67 # Imports
68 #-----------------------------------------------------------------------------
68 #-----------------------------------------------------------------------------
69
69
70 import __builtin__
70 import __builtin__
71 import __main__
71 import __main__
72 import glob
72 import glob
73 import inspect
73 import inspect
74 import itertools
74 import itertools
75 import keyword
75 import keyword
76 import os
76 import os
77 import re
77 import re
78 import shlex
78 import shlex
79 import sys
79 import sys
80
80
81 from IPython.config.configurable import Configurable
81 from IPython.config.configurable import Configurable
82 from IPython.core.error import TryNext
82 from IPython.core.error import TryNext
83 from IPython.core.prefilter import ESC_MAGIC
83 from IPython.core.prefilter import ESC_MAGIC
84 from IPython.utils import generics
84 from IPython.utils import generics
85 from IPython.utils import io
85 from IPython.utils import io
86 from IPython.utils.dir2 import dir2
86 from IPython.utils.dir2 import dir2
87 from IPython.utils.process import arg_split
87 from IPython.utils.process import arg_split
88 from IPython.utils.traitlets import CBool, Enum
88 from IPython.utils.traitlets import CBool, Enum
89
89
90 #-----------------------------------------------------------------------------
90 #-----------------------------------------------------------------------------
91 # Globals
91 # Globals
92 #-----------------------------------------------------------------------------
92 #-----------------------------------------------------------------------------
93
93
94 # Public API
94 # Public API
95 __all__ = ['Completer','IPCompleter']
95 __all__ = ['Completer','IPCompleter']
96
96
97 if sys.platform == 'win32':
97 if sys.platform == 'win32':
98 PROTECTABLES = ' '
98 PROTECTABLES = ' '
99 else:
99 else:
100 PROTECTABLES = ' ()[]{}?=\\|;:\'#*"^&'
100 PROTECTABLES = ' ()[]{}?=\\|;:\'#*"^&'
101
101
102 #-----------------------------------------------------------------------------
102 #-----------------------------------------------------------------------------
103 # Main functions and classes
103 # Main functions and classes
104 #-----------------------------------------------------------------------------
104 #-----------------------------------------------------------------------------
105
105
106 def has_open_quotes(s):
106 def has_open_quotes(s):
107 """Return whether a string has open quotes.
107 """Return whether a string has open quotes.
108
108
109 This simply counts whether the number of quote characters of either type in
109 This simply counts whether the number of quote characters of either type in
110 the string is odd.
110 the string is odd.
111
111
112 Returns
112 Returns
113 -------
113 -------
114 If there is an open quote, the quote character is returned. Else, return
114 If there is an open quote, the quote character is returned. Else, return
115 False.
115 False.
116 """
116 """
117 # We check " first, then ', so complex cases with nested quotes will get
117 # We check " first, then ', so complex cases with nested quotes will get
118 # the " to take precedence.
118 # the " to take precedence.
119 if s.count('"') % 2:
119 if s.count('"') % 2:
120 return '"'
120 return '"'
121 elif s.count("'") % 2:
121 elif s.count("'") % 2:
122 return "'"
122 return "'"
123 else:
123 else:
124 return False
124 return False
125
125
126
126
127 def protect_filename(s):
127 def protect_filename(s):
128 """Escape a string to protect certain characters."""
128 """Escape a string to protect certain characters."""
129
129
130 return "".join([(ch in PROTECTABLES and '\\' + ch or ch)
130 return "".join([(ch in PROTECTABLES and '\\' + ch or ch)
131 for ch in s])
131 for ch in s])
132
132
133
133
134 def mark_dirs(matches):
134 def mark_dirs(matches):
135 """Mark directories in input list by appending '/' to their names."""
135 """Mark directories in input list by appending '/' to their names."""
136 out = []
136 out = []
137 isdir = os.path.isdir
137 isdir = os.path.isdir
138 for x in matches:
138 for x in matches:
139 if isdir(x):
139 if isdir(x):
140 out.append(x+'/')
140 out.append(x+'/')
141 else:
141 else:
142 out.append(x)
142 out.append(x)
143 return out
143 return out
144
144
145
145
146 def expand_user(path):
146 def expand_user(path):
147 """Expand '~'-style usernames in strings.
147 """Expand '~'-style usernames in strings.
148
148
149 This is similar to :func:`os.path.expanduser`, but it computes and returns
149 This is similar to :func:`os.path.expanduser`, but it computes and returns
150 extra information that will be useful if the input was being used in
150 extra information that will be useful if the input was being used in
151 computing completions, and you wish to return the completions with the
151 computing completions, and you wish to return the completions with the
152 original '~' instead of its expanded value.
152 original '~' instead of its expanded value.
153
153
154 Parameters
154 Parameters
155 ----------
155 ----------
156 path : str
156 path : str
157 String to be expanded. If no ~ is present, the output is the same as the
157 String to be expanded. If no ~ is present, the output is the same as the
158 input.
158 input.
159
159
160 Returns
160 Returns
161 -------
161 -------
162 newpath : str
162 newpath : str
163 Result of ~ expansion in the input path.
163 Result of ~ expansion in the input path.
164 tilde_expand : bool
164 tilde_expand : bool
165 Whether any expansion was performed or not.
165 Whether any expansion was performed or not.
166 tilde_val : str
166 tilde_val : str
167 The value that ~ was replaced with.
167 The value that ~ was replaced with.
168 """
168 """
169 # Default values
169 # Default values
170 tilde_expand = False
170 tilde_expand = False
171 tilde_val = ''
171 tilde_val = ''
172 newpath = path
172 newpath = path
173
173
174 if path.startswith('~'):
174 if path.startswith('~'):
175 tilde_expand = True
175 tilde_expand = True
176 rest = len(path)-1
176 rest = len(path)-1
177 newpath = os.path.expanduser(path)
177 newpath = os.path.expanduser(path)
178 if rest:
178 if rest:
179 tilde_val = newpath[:-rest]
179 tilde_val = newpath[:-rest]
180 else:
180 else:
181 tilde_val = newpath
181 tilde_val = newpath
182
182
183 return newpath, tilde_expand, tilde_val
183 return newpath, tilde_expand, tilde_val
184
184
185
185
186 def compress_user(path, tilde_expand, tilde_val):
186 def compress_user(path, tilde_expand, tilde_val):
187 """Does the opposite of expand_user, with its outputs.
187 """Does the opposite of expand_user, with its outputs.
188 """
188 """
189 if tilde_expand:
189 if tilde_expand:
190 return path.replace(tilde_val, '~')
190 return path.replace(tilde_val, '~')
191 else:
191 else:
192 return path
192 return path
193
193
194
194
195 def single_dir_expand(matches):
195 def single_dir_expand(matches):
196 "Recursively expand match lists containing a single dir."
196 "Recursively expand match lists containing a single dir."
197
197
198 if len(matches) == 1 and os.path.isdir(matches[0]):
198 if len(matches) == 1 and os.path.isdir(matches[0]):
199 # Takes care of links to directories also. Use '/'
199 # Takes care of links to directories also. Use '/'
200 # explicitly, even under Windows, so that name completions
200 # explicitly, even under Windows, so that name completions
201 # don't end up escaped.
201 # don't end up escaped.
202 d = matches[0]
202 d = matches[0]
203 if d[-1] in ['/','\\']:
203 if d[-1] in ['/','\\']:
204 d = d[:-1]
204 d = d[:-1]
205
205
206 subdirs = os.listdir(d)
206 subdirs = os.listdir(d)
207 if subdirs:
207 if subdirs:
208 matches = [ (d + '/' + p) for p in subdirs]
208 matches = [ (d + '/' + p) for p in subdirs]
209 return single_dir_expand(matches)
209 return single_dir_expand(matches)
210 else:
210 else:
211 return matches
211 return matches
212 else:
212 else:
213 return matches
213 return matches
214
214
215
215
216 class Bunch(object): pass
216 class Bunch(object): pass
217
217
218 DELIMS = ' \t\n`!@#$^&*()=+[{]}\\|;:\'",<>?'
218 DELIMS = ' \t\n`!@#$^&*()=+[{]}\\|;:\'",<>?'
219 GREEDY_DELIMS = ' \r\n'
219 GREEDY_DELIMS = ' \r\n'
220
220
221 class CompletionSplitter(object):
221 class CompletionSplitter(object):
222 """An object to split an input line in a manner similar to readline.
222 """An object to split an input line in a manner similar to readline.
223
223
224 By having our own implementation, we can expose readline-like completion in
224 By having our own implementation, we can expose readline-like completion in
225 a uniform manner to all frontends. This object only needs to be given the
225 a uniform manner to all frontends. This object only needs to be given the
226 line of text to be split and the cursor position on said line, and it
226 line of text to be split and the cursor position on said line, and it
227 returns the 'word' to be completed on at the cursor after splitting the
227 returns the 'word' to be completed on at the cursor after splitting the
228 entire line.
228 entire line.
229
229
230 What characters are used as splitting delimiters can be controlled by
230 What characters are used as splitting delimiters can be controlled by
231 setting the `delims` attribute (this is a property that internally
231 setting the `delims` attribute (this is a property that internally
232 automatically builds the necessary """
232 automatically builds the necessary """
233
233
234 # Private interface
234 # Private interface
235
235
236 # A string of delimiter characters. The default value makes sense for
236 # A string of delimiter characters. The default value makes sense for
237 # IPython's most typical usage patterns.
237 # IPython's most typical usage patterns.
238 _delims = DELIMS
238 _delims = DELIMS
239
239
240 # The expression (a normal string) to be compiled into a regular expression
240 # The expression (a normal string) to be compiled into a regular expression
241 # for actual splitting. We store it as an attribute mostly for ease of
241 # for actual splitting. We store it as an attribute mostly for ease of
242 # debugging, since this type of code can be so tricky to debug.
242 # debugging, since this type of code can be so tricky to debug.
243 _delim_expr = None
243 _delim_expr = None
244
244
245 # The regular expression that does the actual splitting
245 # The regular expression that does the actual splitting
246 _delim_re = None
246 _delim_re = None
247
247
248 def __init__(self, delims=None):
248 def __init__(self, delims=None):
249 delims = CompletionSplitter._delims if delims is None else delims
249 delims = CompletionSplitter._delims if delims is None else delims
250 self.set_delims(delims)
250 self.set_delims(delims)
251
251
252 def set_delims(self, delims):
252 def set_delims(self, delims):
253 """Set the delimiters for line splitting."""
253 """Set the delimiters for line splitting."""
254 expr = '[' + ''.join('\\'+ c for c in delims) + ']'
254 expr = '[' + ''.join('\\'+ c for c in delims) + ']'
255 self._delim_re = re.compile(expr)
255 self._delim_re = re.compile(expr)
256 self._delims = delims
256 self._delims = delims
257 self._delim_expr = expr
257 self._delim_expr = expr
258
258
259 def get_delims(self):
259 def get_delims(self):
260 """Return the string of delimiter characters."""
260 """Return the string of delimiter characters."""
261 return self._delims
261 return self._delims
262
262
263 def split_line(self, line, cursor_pos=None):
263 def split_line(self, line, cursor_pos=None):
264 """Split a line of text with a cursor at the given position.
264 """Split a line of text with a cursor at the given position.
265 """
265 """
266 l = line if cursor_pos is None else line[:cursor_pos]
266 l = line if cursor_pos is None else line[:cursor_pos]
267 return self._delim_re.split(l)[-1]
267 return self._delim_re.split(l)[-1]
268
268
269
269
270 class Completer(Configurable):
270 class Completer(Configurable):
271
271
272 greedy = CBool(False, config=True,
272 greedy = CBool(False, config=True,
273 help="""Activate greedy completion
273 help="""Activate greedy completion
274
274
275 This will enable completion on elements of lists, results of function calls, etc.,
275 This will enable completion on elements of lists, results of function calls, etc.,
276 but can be unsafe because the code is actually evaluated on TAB.
276 but can be unsafe because the code is actually evaluated on TAB.
277 """
277 """
278 )
278 )
279
279
280
280
281 def __init__(self, namespace=None, global_namespace=None, config=None, **kwargs):
281 def __init__(self, namespace=None, global_namespace=None, config=None, **kwargs):
282 """Create a new completer for the command line.
282 """Create a new completer for the command line.
283
283
284 Completer(namespace=ns,global_namespace=ns2) -> completer instance.
284 Completer(namespace=ns,global_namespace=ns2) -> completer instance.
285
285
286 If unspecified, the default namespace where completions are performed
286 If unspecified, the default namespace where completions are performed
287 is __main__ (technically, __main__.__dict__). Namespaces should be
287 is __main__ (technically, __main__.__dict__). Namespaces should be
288 given as dictionaries.
288 given as dictionaries.
289
289
290 An optional second namespace can be given. This allows the completer
290 An optional second namespace can be given. This allows the completer
291 to handle cases where both the local and global scopes need to be
291 to handle cases where both the local and global scopes need to be
292 distinguished.
292 distinguished.
293
293
294 Completer instances should be used as the completion mechanism of
294 Completer instances should be used as the completion mechanism of
295 readline via the set_completer() call:
295 readline via the set_completer() call:
296
296
297 readline.set_completer(Completer(my_namespace).complete)
297 readline.set_completer(Completer(my_namespace).complete)
298 """
298 """
299
299
300 # Don't bind to namespace quite yet, but flag whether the user wants a
300 # Don't bind to namespace quite yet, but flag whether the user wants a
301 # specific namespace or to use __main__.__dict__. This will allow us
301 # specific namespace or to use __main__.__dict__. This will allow us
302 # to bind to __main__.__dict__ at completion time, not now.
302 # to bind to __main__.__dict__ at completion time, not now.
303 if namespace is None:
303 if namespace is None:
304 self.use_main_ns = 1
304 self.use_main_ns = 1
305 else:
305 else:
306 self.use_main_ns = 0
306 self.use_main_ns = 0
307 self.namespace = namespace
307 self.namespace = namespace
308
308
309 # The global namespace, if given, can be bound directly
309 # The global namespace, if given, can be bound directly
310 if global_namespace is None:
310 if global_namespace is None:
311 self.global_namespace = {}
311 self.global_namespace = {}
312 else:
312 else:
313 self.global_namespace = global_namespace
313 self.global_namespace = global_namespace
314
314
315 super(Completer, self).__init__(config=config, **kwargs)
315 super(Completer, self).__init__(config=config, **kwargs)
316
316
317 def complete(self, text, state):
317 def complete(self, text, state):
318 """Return the next possible completion for 'text'.
318 """Return the next possible completion for 'text'.
319
319
320 This is called successively with state == 0, 1, 2, ... until it
320 This is called successively with state == 0, 1, 2, ... until it
321 returns None. The completion should begin with 'text'.
321 returns None. The completion should begin with 'text'.
322
322
323 """
323 """
324 if self.use_main_ns:
324 if self.use_main_ns:
325 self.namespace = __main__.__dict__
325 self.namespace = __main__.__dict__
326
326
327 if state == 0:
327 if state == 0:
328 if "." in text:
328 if "." in text:
329 self.matches = self.attr_matches(text)
329 self.matches = self.attr_matches(text)
330 else:
330 else:
331 self.matches = self.global_matches(text)
331 self.matches = self.global_matches(text)
332 try:
332 try:
333 return self.matches[state]
333 return self.matches[state]
334 except IndexError:
334 except IndexError:
335 return None
335 return None
336
336
337 def global_matches(self, text):
337 def global_matches(self, text):
338 """Compute matches when text is a simple name.
338 """Compute matches when text is a simple name.
339
339
340 Return a list of all keywords, built-in functions and names currently
340 Return a list of all keywords, built-in functions and names currently
341 defined in self.namespace or self.global_namespace that match.
341 defined in self.namespace or self.global_namespace that match.
342
342
343 """
343 """
344 #print 'Completer->global_matches, txt=%r' % text # dbg
344 #print 'Completer->global_matches, txt=%r' % text # dbg
345 matches = []
345 matches = []
346 match_append = matches.append
346 match_append = matches.append
347 n = len(text)
347 n = len(text)
348 for lst in [keyword.kwlist,
348 for lst in [keyword.kwlist,
349 __builtin__.__dict__.keys(),
349 __builtin__.__dict__.keys(),
350 self.namespace.keys(),
350 self.namespace.keys(),
351 self.global_namespace.keys()]:
351 self.global_namespace.keys()]:
352 for word in lst:
352 for word in lst:
353 if word[:n] == text and word != "__builtins__":
353 if word[:n] == text and word != "__builtins__":
354 match_append(word)
354 match_append(word)
355 return matches
355 return matches
356
356
357 def attr_matches(self, text):
357 def attr_matches(self, text):
358 """Compute matches when text contains a dot.
358 """Compute matches when text contains a dot.
359
359
360 Assuming the text is of the form NAME.NAME....[NAME], and is
360 Assuming the text is of the form NAME.NAME....[NAME], and is
361 evaluatable in self.namespace or self.global_namespace, it will be
361 evaluatable in self.namespace or self.global_namespace, it will be
362 evaluated and its attributes (as revealed by dir()) are used as
362 evaluated and its attributes (as revealed by dir()) are used as
363 possible completions. (For class instances, class members are are
363 possible completions. (For class instances, class members are are
364 also considered.)
364 also considered.)
365
365
366 WARNING: this can still invoke arbitrary C code, if an object
366 WARNING: this can still invoke arbitrary C code, if an object
367 with a __getattr__ hook is evaluated.
367 with a __getattr__ hook is evaluated.
368
368
369 """
369 """
370
370
371 #io.rprint('Completer->attr_matches, txt=%r' % text) # dbg
371 #io.rprint('Completer->attr_matches, txt=%r' % text) # dbg
372 # Another option, seems to work great. Catches things like ''.<tab>
372 # Another option, seems to work great. Catches things like ''.<tab>
373 m = re.match(r"(\S+(\.\w+)*)\.(\w*)$", text)
373 m = re.match(r"(\S+(\.\w+)*)\.(\w*)$", text)
374
374
375 if m:
375 if m:
376 expr, attr = m.group(1, 3)
376 expr, attr = m.group(1, 3)
377 elif self.greedy:
377 elif self.greedy:
378 m2 = re.match(r"(.+)\.(\w*)$", self.line_buffer)
378 m2 = re.match(r"(.+)\.(\w*)$", self.line_buffer)
379 if not m2:
379 if not m2:
380 return []
380 return []
381 expr, attr = m2.group(1,2)
381 expr, attr = m2.group(1,2)
382 else:
382 else:
383 return []
383 return []
384
384
385 try:
385 try:
386 obj = eval(expr, self.namespace)
386 obj = eval(expr, self.namespace)
387 except:
387 except:
388 try:
388 try:
389 obj = eval(expr, self.global_namespace)
389 obj = eval(expr, self.global_namespace)
390 except:
390 except:
391 return []
391 return []
392
392
393 words = dir2(obj)
393 words = dir2(obj)
394
394
395 try:
395 try:
396 words = generics.complete_object(obj, words)
396 words = generics.complete_object(obj, words)
397 except TryNext:
397 except TryNext:
398 pass
398 pass
399 except Exception:
399 except Exception:
400 # Silence errors from completion function
400 # Silence errors from completion function
401 #raise # dbg
401 #raise # dbg
402 pass
402 pass
403 # Build match list to return
403 # Build match list to return
404 n = len(attr)
404 n = len(attr)
405 res = ["%s.%s" % (expr, w) for w in words if w[:n] == attr ]
405 res = ["%s.%s" % (expr, w) for w in words if w[:n] == attr ]
406 return res
406 return res
407
407
408
408
409 class IPCompleter(Completer):
409 class IPCompleter(Completer):
410 """Extension of the completer class with IPython-specific features"""
410 """Extension of the completer class with IPython-specific features"""
411
411
412 def _greedy_changed(self, name, old, new):
412 def _greedy_changed(self, name, old, new):
413 """update the splitter and readline delims when greedy is changed"""
413 """update the splitter and readline delims when greedy is changed"""
414 if new:
414 if new:
415 self.splitter.set_delims(GREEDY_DELIMS)
415 self.splitter.set_delims(GREEDY_DELIMS)
416 else:
416 else:
417 self.splitter.set_delims(DELIMS)
417 self.splitter.set_delims(DELIMS)
418
418
419 if self.readline:
419 if self.readline:
420 self.readline.set_completer_delims(self.splitter.get_delims())
420 self.readline.set_completer_delims(self.splitter.get_delims())
421
421
422 merge_completions = CBool(True, config=True,
422 merge_completions = CBool(True, config=True,
423 help="""Whether to merge completion results into a single list
423 help="""Whether to merge completion results into a single list
424
424
425 If False, only the completion results from the first non-empty
425 If False, only the completion results from the first non-empty
426 completer will be returned.
426 completer will be returned.
427 """
427 """
428 )
428 )
429 omit__names = Enum((0,1,2), default_value=2, config=True,
429 omit__names = Enum((0,1,2), default_value=2, config=True,
430 help="""Instruct the completer to omit private method names
430 help="""Instruct the completer to omit private method names
431
431
432 Specifically, when completing on ``object.<tab>``.
432 Specifically, when completing on ``object.<tab>``.
433
433
434 When 2 [default]: all names that start with '_' will be excluded.
434 When 2 [default]: all names that start with '_' will be excluded.
435
435
436 When 1: all 'magic' names (``__foo__``) will be excluded.
436 When 1: all 'magic' names (``__foo__``) will be excluded.
437
437
438 When 0: nothing will be excluded.
438 When 0: nothing will be excluded.
439 """
439 """
440 )
440 )
441
441
442 def __init__(self, shell=None, namespace=None, global_namespace=None,
442 def __init__(self, shell=None, namespace=None, global_namespace=None,
443 alias_table=None, use_readline=True,
443 alias_table=None, use_readline=True,
444 config=None, **kwargs):
444 config=None, **kwargs):
445 """IPCompleter() -> completer
445 """IPCompleter() -> completer
446
446
447 Return a completer object suitable for use by the readline library
447 Return a completer object suitable for use by the readline library
448 via readline.set_completer().
448 via readline.set_completer().
449
449
450 Inputs:
450 Inputs:
451
451
452 - shell: a pointer to the ipython shell itself. This is needed
452 - shell: a pointer to the ipython shell itself. This is needed
453 because this completer knows about magic functions, and those can
453 because this completer knows about magic functions, and those can
454 only be accessed via the ipython instance.
454 only be accessed via the ipython instance.
455
455
456 - namespace: an optional dict where completions are performed.
456 - namespace: an optional dict where completions are performed.
457
457
458 - global_namespace: secondary optional dict for completions, to
458 - global_namespace: secondary optional dict for completions, to
459 handle cases (such as IPython embedded inside functions) where
459 handle cases (such as IPython embedded inside functions) where
460 both Python scopes are visible.
460 both Python scopes are visible.
461
461
462 - If alias_table is supplied, it should be a dictionary of aliases
462 - If alias_table is supplied, it should be a dictionary of aliases
463 to complete.
463 to complete.
464
464
465 use_readline : bool, optional
465 use_readline : bool, optional
466 If true, use the readline library. This completer can still function
466 If true, use the readline library. This completer can still function
467 without readline, though in that case callers must provide some extra
467 without readline, though in that case callers must provide some extra
468 information on each call about the current line."""
468 information on each call about the current line."""
469
469
470 self.magic_escape = ESC_MAGIC
470 self.magic_escape = ESC_MAGIC
471 self.splitter = CompletionSplitter()
471 self.splitter = CompletionSplitter()
472
472
473 # Readline configuration, only used by the rlcompleter method.
473 # Readline configuration, only used by the rlcompleter method.
474 if use_readline:
474 if use_readline:
475 # We store the right version of readline so that later code
475 # We store the right version of readline so that later code
476 import IPython.utils.rlineimpl as readline
476 import IPython.utils.rlineimpl as readline
477 self.readline = readline
477 self.readline = readline
478 else:
478 else:
479 self.readline = None
479 self.readline = None
480
480
481 # _greedy_changed() depends on splitter and readline being defined:
481 # _greedy_changed() depends on splitter and readline being defined:
482 Completer.__init__(self, namespace=namespace, global_namespace=global_namespace,
482 Completer.__init__(self, namespace=namespace, global_namespace=global_namespace,
483 config=config, **kwargs)
483 config=config, **kwargs)
484
484
485 # List where completion matches will be stored
485 # List where completion matches will be stored
486 self.matches = []
486 self.matches = []
487 self.shell = shell.shell
487 self.shell = shell.shell
488 if alias_table is None:
488 if alias_table is None:
489 alias_table = {}
489 alias_table = {}
490 self.alias_table = alias_table
490 self.alias_table = alias_table
491 # Regexp to split filenames with spaces in them
491 # Regexp to split filenames with spaces in them
492 self.space_name_re = re.compile(r'([^\\] )')
492 self.space_name_re = re.compile(r'([^\\] )')
493 # Hold a local ref. to glob.glob for speed
493 # Hold a local ref. to glob.glob for speed
494 self.glob = glob.glob
494 self.glob = glob.glob
495
495
496 # Determine if we are running on 'dumb' terminals, like (X)Emacs
496 # Determine if we are running on 'dumb' terminals, like (X)Emacs
497 # buffers, to avoid completion problems.
497 # buffers, to avoid completion problems.
498 term = os.environ.get('TERM','xterm')
498 term = os.environ.get('TERM','xterm')
499 self.dumb_terminal = term in ['dumb','emacs']
499 self.dumb_terminal = term in ['dumb','emacs']
500
500
501 # Special handling of backslashes needed in win32 platforms
501 # Special handling of backslashes needed in win32 platforms
502 if sys.platform == "win32":
502 if sys.platform == "win32":
503 self.clean_glob = self._clean_glob_win32
503 self.clean_glob = self._clean_glob_win32
504 else:
504 else:
505 self.clean_glob = self._clean_glob
505 self.clean_glob = self._clean_glob
506
506
507 # All active matcher routines for completion
507 # All active matcher routines for completion
508 self.matchers = [self.python_matches,
508 self.matchers = [self.python_matches,
509 self.file_matches,
509 self.file_matches,
510 self.magic_matches,
510 self.magic_matches,
511 self.alias_matches,
511 self.alias_matches,
512 self.python_func_kw_matches,
512 self.python_func_kw_matches,
513 ]
513 ]
514
514
515 def all_completions(self, text):
515 def all_completions(self, text):
516 """
516 """
517 Wrapper around the complete method for the benefit of emacs
517 Wrapper around the complete method for the benefit of emacs
518 and pydb.
518 and pydb.
519 """
519 """
520 return self.complete(text)[1]
520 return self.complete(text)[1]
521
521
522 def _clean_glob(self,text):
522 def _clean_glob(self,text):
523 return self.glob("%s*" % text)
523 return self.glob("%s*" % text)
524
524
525 def _clean_glob_win32(self,text):
525 def _clean_glob_win32(self,text):
526 return [f.replace("\\","/")
526 return [f.replace("\\","/")
527 for f in self.glob("%s*" % text)]
527 for f in self.glob("%s*" % text)]
528
528
529 def file_matches(self, text):
529 def file_matches(self, text):
530 """Match filenames, expanding ~USER type strings.
530 """Match filenames, expanding ~USER type strings.
531
531
532 Most of the seemingly convoluted logic in this completer is an
532 Most of the seemingly convoluted logic in this completer is an
533 attempt to handle filenames with spaces in them. And yet it's not
533 attempt to handle filenames with spaces in them. And yet it's not
534 quite perfect, because Python's readline doesn't expose all of the
534 quite perfect, because Python's readline doesn't expose all of the
535 GNU readline details needed for this to be done correctly.
535 GNU readline details needed for this to be done correctly.
536
536
537 For a filename with a space in it, the printed completions will be
537 For a filename with a space in it, the printed completions will be
538 only the parts after what's already been typed (instead of the
538 only the parts after what's already been typed (instead of the
539 full completions, as is normally done). I don't think with the
539 full completions, as is normally done). I don't think with the
540 current (as of Python 2.3) Python readline it's possible to do
540 current (as of Python 2.3) Python readline it's possible to do
541 better."""
541 better."""
542
542
543 #io.rprint('Completer->file_matches: <%r>' % text) # dbg
543 #io.rprint('Completer->file_matches: <%r>' % text) # dbg
544
544
545 # chars that require escaping with backslash - i.e. chars
545 # chars that require escaping with backslash - i.e. chars
546 # that readline treats incorrectly as delimiters, but we
546 # that readline treats incorrectly as delimiters, but we
547 # don't want to treat as delimiters in filename matching
547 # don't want to treat as delimiters in filename matching
548 # when escaped with backslash
548 # when escaped with backslash
549 if text.startswith('!'):
549 if text.startswith('!'):
550 text = text[1:]
550 text = text[1:]
551 text_prefix = '!'
551 text_prefix = '!'
552 else:
552 else:
553 text_prefix = ''
553 text_prefix = ''
554
554
555 text_until_cursor = self.text_until_cursor
555 text_until_cursor = self.text_until_cursor
556 # track strings with open quotes
556 # track strings with open quotes
557 open_quotes = has_open_quotes(text_until_cursor)
557 open_quotes = has_open_quotes(text_until_cursor)
558
558
559 if '(' in text_until_cursor or '[' in text_until_cursor:
559 if '(' in text_until_cursor or '[' in text_until_cursor:
560 lsplit = text
560 lsplit = text
561 else:
561 else:
562 try:
562 try:
563 # arg_split ~ shlex.split, but with unicode bugs fixed by us
563 # arg_split ~ shlex.split, but with unicode bugs fixed by us
564 lsplit = arg_split(text_until_cursor)[-1]
564 lsplit = arg_split(text_until_cursor)[-1]
565 except ValueError:
565 except ValueError:
566 # typically an unmatched ", or backslash without escaped char.
566 # typically an unmatched ", or backslash without escaped char.
567 if open_quotes:
567 if open_quotes:
568 lsplit = text_until_cursor.split(open_quotes)[-1]
568 lsplit = text_until_cursor.split(open_quotes)[-1]
569 else:
569 else:
570 return []
570 return []
571 except IndexError:
571 except IndexError:
572 # tab pressed on empty line
572 # tab pressed on empty line
573 lsplit = ""
573 lsplit = ""
574
574
575 if not open_quotes and lsplit != protect_filename(lsplit):
575 if not open_quotes and lsplit != protect_filename(lsplit):
576 # if protectables are found, do matching on the whole escaped name
576 # if protectables are found, do matching on the whole escaped name
577 has_protectables = True
577 has_protectables = True
578 text0,text = text,lsplit
578 text0,text = text,lsplit
579 else:
579 else:
580 has_protectables = False
580 has_protectables = False
581 text = os.path.expanduser(text)
581 text = os.path.expanduser(text)
582
582
583 if text == "":
583 if text == "":
584 return [text_prefix + protect_filename(f) for f in self.glob("*")]
584 return [text_prefix + protect_filename(f) for f in self.glob("*")]
585
585
586 # Compute the matches from the filesystem
586 # Compute the matches from the filesystem
587 m0 = self.clean_glob(text.replace('\\',''))
587 m0 = self.clean_glob(text.replace('\\',''))
588
588
589 if has_protectables:
589 if has_protectables:
590 # If we had protectables, we need to revert our changes to the
590 # If we had protectables, we need to revert our changes to the
591 # beginning of filename so that we don't double-write the part
591 # beginning of filename so that we don't double-write the part
592 # of the filename we have so far
592 # of the filename we have so far
593 len_lsplit = len(lsplit)
593 len_lsplit = len(lsplit)
594 matches = [text_prefix + text0 +
594 matches = [text_prefix + text0 +
595 protect_filename(f[len_lsplit:]) for f in m0]
595 protect_filename(f[len_lsplit:]) for f in m0]
596 else:
596 else:
597 if open_quotes:
597 if open_quotes:
598 # if we have a string with an open quote, we don't need to
598 # if we have a string with an open quote, we don't need to
599 # protect the names at all (and we _shouldn't_, as it
599 # protect the names at all (and we _shouldn't_, as it
600 # would cause bugs when the filesystem call is made).
600 # would cause bugs when the filesystem call is made).
601 matches = m0
601 matches = m0
602 else:
602 else:
603 matches = [text_prefix +
603 matches = [text_prefix +
604 protect_filename(f) for f in m0]
604 protect_filename(f) for f in m0]
605
605
606 #io.rprint('mm', matches) # dbg
606 #io.rprint('mm', matches) # dbg
607 return mark_dirs(matches)
607 return mark_dirs(matches)
608
608
609 def magic_matches(self, text):
609 def magic_matches(self, text):
610 """Match magics"""
610 """Match magics"""
611 #print 'Completer->magic_matches:',text,'lb',self.text_until_cursor # dbg
611 #print 'Completer->magic_matches:',text,'lb',self.text_until_cursor # dbg
612 # Get all shell magics now rather than statically, so magics loaded at
612 # Get all shell magics now rather than statically, so magics loaded at
613 # runtime show up too
613 # runtime show up too
614 magics = self.shell.lsmagic()
614 magics = self.shell.lsmagic()
615 pre = self.magic_escape
615 pre = self.magic_escape
616 baretext = text.lstrip(pre)
616 baretext = text.lstrip(pre)
617 return [ pre+m for m in magics if m.startswith(baretext)]
617 return [ pre+m for m in magics if m.startswith(baretext)]
618
618
619 def alias_matches(self, text):
619 def alias_matches(self, text):
620 """Match internal system aliases"""
620 """Match internal system aliases"""
621 #print 'Completer->alias_matches:',text,'lb',self.text_until_cursor # dbg
621 #print 'Completer->alias_matches:',text,'lb',self.text_until_cursor # dbg
622
622
623 # if we are not in the first 'item', alias matching
623 # if we are not in the first 'item', alias matching
624 # doesn't make sense - unless we are starting with 'sudo' command.
624 # doesn't make sense - unless we are starting with 'sudo' command.
625 main_text = self.text_until_cursor.lstrip()
625 main_text = self.text_until_cursor.lstrip()
626 if ' ' in main_text and not main_text.startswith('sudo'):
626 if ' ' in main_text and not main_text.startswith('sudo'):
627 return []
627 return []
628 text = os.path.expanduser(text)
628 text = os.path.expanduser(text)
629 aliases = self.alias_table.keys()
629 aliases = self.alias_table.keys()
630 if text == '':
630 if text == '':
631 return aliases
631 return aliases
632 else:
632 else:
633 return [a for a in aliases if a.startswith(text)]
633 return [a for a in aliases if a.startswith(text)]
634
634
635 def python_matches(self,text):
635 def python_matches(self,text):
636 """Match attributes or global python names"""
636 """Match attributes or global python names"""
637
637
638 #io.rprint('Completer->python_matches, txt=%r' % text) # dbg
638 #io.rprint('Completer->python_matches, txt=%r' % text) # dbg
639 if "." in text:
639 if "." in text:
640 try:
640 try:
641 matches = self.attr_matches(text)
641 matches = self.attr_matches(text)
642 if text.endswith('.') and self.omit__names:
642 if text.endswith('.') and self.omit__names:
643 if self.omit__names == 1:
643 if self.omit__names == 1:
644 # true if txt is _not_ a __ name, false otherwise:
644 # true if txt is _not_ a __ name, false otherwise:
645 no__name = (lambda txt:
645 no__name = (lambda txt:
646 re.match(r'.*\.__.*?__',txt) is None)
646 re.match(r'.*\.__.*?__',txt) is None)
647 else:
647 else:
648 # true if txt is _not_ a _ name, false otherwise:
648 # true if txt is _not_ a _ name, false otherwise:
649 no__name = (lambda txt:
649 no__name = (lambda txt:
650 re.match(r'.*\._.*?',txt) is None)
650 re.match(r'.*\._.*?',txt) is None)
651 matches = filter(no__name, matches)
651 matches = filter(no__name, matches)
652 except NameError:
652 except NameError:
653 # catches <undefined attributes>.<tab>
653 # catches <undefined attributes>.<tab>
654 matches = []
654 matches = []
655 else:
655 else:
656 matches = self.global_matches(text)
656 matches = self.global_matches(text)
657
657
658 return matches
658 return matches
659
659
660 def _default_arguments(self, obj):
660 def _default_arguments(self, obj):
661 """Return the list of default arguments of obj if it is callable,
661 """Return the list of default arguments of obj if it is callable,
662 or empty list otherwise."""
662 or empty list otherwise."""
663
663
664 if not (inspect.isfunction(obj) or inspect.ismethod(obj)):
664 if not (inspect.isfunction(obj) or inspect.ismethod(obj)):
665 # for classes, check for __init__,__new__
665 # for classes, check for __init__,__new__
666 if inspect.isclass(obj):
666 if inspect.isclass(obj):
667 obj = (getattr(obj,'__init__',None) or
667 obj = (getattr(obj,'__init__',None) or
668 getattr(obj,'__new__',None))
668 getattr(obj,'__new__',None))
669 # for all others, check if they are __call__able
669 # for all others, check if they are __call__able
670 elif hasattr(obj, '__call__'):
670 elif hasattr(obj, '__call__'):
671 obj = obj.__call__
671 obj = obj.__call__
672 # XXX: is there a way to handle the builtins ?
672 # XXX: is there a way to handle the builtins ?
673 try:
673 try:
674 args,_,_1,defaults = inspect.getargspec(obj)
674 args,_,_1,defaults = inspect.getargspec(obj)
675 if defaults:
675 if defaults:
676 return args[-len(defaults):]
676 return args[-len(defaults):]
677 except TypeError: pass
677 except TypeError: pass
678 return []
678 return []
679
679
680 def python_func_kw_matches(self,text):
680 def python_func_kw_matches(self,text):
681 """Match named parameters (kwargs) of the last open function"""
681 """Match named parameters (kwargs) of the last open function"""
682
682
683 if "." in text: # a parameter cannot be dotted
683 if "." in text: # a parameter cannot be dotted
684 return []
684 return []
685 try: regexp = self.__funcParamsRegex
685 try: regexp = self.__funcParamsRegex
686 except AttributeError:
686 except AttributeError:
687 regexp = self.__funcParamsRegex = re.compile(r'''
687 regexp = self.__funcParamsRegex = re.compile(r'''
688 '.*?' | # single quoted strings or
688 '.*?' | # single quoted strings or
689 ".*?" | # double quoted strings or
689 ".*?" | # double quoted strings or
690 \w+ | # identifier
690 \w+ | # identifier
691 \S # other characters
691 \S # other characters
692 ''', re.VERBOSE | re.DOTALL)
692 ''', re.VERBOSE | re.DOTALL)
693 # 1. find the nearest identifier that comes before an unclosed
693 # 1. find the nearest identifier that comes before an unclosed
694 # parenthesis e.g. for "foo (1+bar(x), pa", the candidate is "foo"
694 # parenthesis e.g. for "foo (1+bar(x), pa", the candidate is "foo"
695 tokens = regexp.findall(self.line_buffer)
695 tokens = regexp.findall(self.line_buffer)
696 tokens.reverse()
696 tokens.reverse()
697 iterTokens = iter(tokens); openPar = 0
697 iterTokens = iter(tokens); openPar = 0
698 for token in iterTokens:
698 for token in iterTokens:
699 if token == ')':
699 if token == ')':
700 openPar -= 1
700 openPar -= 1
701 elif token == '(':
701 elif token == '(':
702 openPar += 1
702 openPar += 1
703 if openPar > 0:
703 if openPar > 0:
704 # found the last unclosed parenthesis
704 # found the last unclosed parenthesis
705 break
705 break
706 else:
706 else:
707 return []
707 return []
708 # 2. Concatenate dotted names ("foo.bar" for "foo.bar(x, pa" )
708 # 2. Concatenate dotted names ("foo.bar" for "foo.bar(x, pa" )
709 ids = []
709 ids = []
710 isId = re.compile(r'\w+$').match
710 isId = re.compile(r'\w+$').match
711 while True:
711 while True:
712 try:
712 try:
713 ids.append(iterTokens.next())
713 ids.append(iterTokens.next())
714 if not isId(ids[-1]):
714 if not isId(ids[-1]):
715 ids.pop(); break
715 ids.pop(); break
716 if not iterTokens.next() == '.':
716 if not iterTokens.next() == '.':
717 break
717 break
718 except StopIteration:
718 except StopIteration:
719 break
719 break
720 # lookup the candidate callable matches either using global_matches
720 # lookup the candidate callable matches either using global_matches
721 # or attr_matches for dotted names
721 # or attr_matches for dotted names
722 if len(ids) == 1:
722 if len(ids) == 1:
723 callableMatches = self.global_matches(ids[0])
723 callableMatches = self.global_matches(ids[0])
724 else:
724 else:
725 callableMatches = self.attr_matches('.'.join(ids[::-1]))
725 callableMatches = self.attr_matches('.'.join(ids[::-1]))
726 argMatches = []
726 argMatches = []
727 for callableMatch in callableMatches:
727 for callableMatch in callableMatches:
728 try:
728 try:
729 namedArgs = self._default_arguments(eval(callableMatch,
729 namedArgs = self._default_arguments(eval(callableMatch,
730 self.namespace))
730 self.namespace))
731 except:
731 except:
732 continue
732 continue
733 for namedArg in namedArgs:
733 for namedArg in namedArgs:
734 if namedArg.startswith(text):
734 if namedArg.startswith(text):
735 argMatches.append("%s=" %namedArg)
735 argMatches.append("%s=" %namedArg)
736 return argMatches
736 return argMatches
737
737
738 def dispatch_custom_completer(self, text):
738 def dispatch_custom_completer(self, text):
739 #io.rprint("Custom! '%s' %s" % (text, self.custom_completers)) # dbg
739 #io.rprint("Custom! '%s' %s" % (text, self.custom_completers)) # dbg
740 line = self.line_buffer
740 line = self.line_buffer
741 if not line.strip():
741 if not line.strip():
742 return None
742 return None
743
743
744 # Create a little structure to pass all the relevant information about
744 # Create a little structure to pass all the relevant information about
745 # the current completion to any custom completer.
745 # the current completion to any custom completer.
746 event = Bunch()
746 event = Bunch()
747 event.line = line
747 event.line = line
748 event.symbol = text
748 event.symbol = text
749 cmd = line.split(None,1)[0]
749 cmd = line.split(None,1)[0]
750 event.command = cmd
750 event.command = cmd
751 event.text_until_cursor = self.text_until_cursor
751 event.text_until_cursor = self.text_until_cursor
752
752
753 #print "\ncustom:{%s]\n" % event # dbg
753 #print "\ncustom:{%s]\n" % event # dbg
754
754
755 # for foo etc, try also to find completer for %foo
755 # for foo etc, try also to find completer for %foo
756 if not cmd.startswith(self.magic_escape):
756 if not cmd.startswith(self.magic_escape):
757 try_magic = self.custom_completers.s_matches(
757 try_magic = self.custom_completers.s_matches(
758 self.magic_escape + cmd)
758 self.magic_escape + cmd)
759 else:
759 else:
760 try_magic = []
760 try_magic = []
761
761
762 for c in itertools.chain(self.custom_completers.s_matches(cmd),
762 for c in itertools.chain(self.custom_completers.s_matches(cmd),
763 try_magic,
763 try_magic,
764 self.custom_completers.flat_matches(self.text_until_cursor)):
764 self.custom_completers.flat_matches(self.text_until_cursor)):
765 #print "try",c # dbg
765 #print "try",c # dbg
766 try:
766 try:
767 res = c(event)
767 res = c(event)
768 if res:
768 if res:
769 # first, try case sensitive match
769 # first, try case sensitive match
770 withcase = [r for r in res if r.startswith(text)]
770 withcase = [r for r in res if r.startswith(text)]
771 if withcase:
771 if withcase:
772 return withcase
772 return withcase
773 # if none, then case insensitive ones are ok too
773 # if none, then case insensitive ones are ok too
774 text_low = text.lower()
774 text_low = text.lower()
775 return [r for r in res if r.lower().startswith(text_low)]
775 return [r for r in res if r.lower().startswith(text_low)]
776 except TryNext:
776 except TryNext:
777 pass
777 pass
778
778
779 return None
779 return None
780
780
781 def complete(self, text=None, line_buffer=None, cursor_pos=None):
781 def complete(self, text=None, line_buffer=None, cursor_pos=None):
782 """Find completions for the given text and line context.
782 """Find completions for the given text and line context.
783
783
784 This is called successively with state == 0, 1, 2, ... until it
784 This is called successively with state == 0, 1, 2, ... until it
785 returns None. The completion should begin with 'text'.
785 returns None. The completion should begin with 'text'.
786
786
787 Note that both the text and the line_buffer are optional, but at least
787 Note that both the text and the line_buffer are optional, but at least
788 one of them must be given.
788 one of them must be given.
789
789
790 Parameters
790 Parameters
791 ----------
791 ----------
792 text : string, optional
792 text : string, optional
793 Text to perform the completion on. If not given, the line buffer
793 Text to perform the completion on. If not given, the line buffer
794 is split using the instance's CompletionSplitter object.
794 is split using the instance's CompletionSplitter object.
795
795
796 line_buffer : string, optional
796 line_buffer : string, optional
797 If not given, the completer attempts to obtain the current line
797 If not given, the completer attempts to obtain the current line
798 buffer via readline. This keyword allows clients which are
798 buffer via readline. This keyword allows clients which are
799 requesting for text completions in non-readline contexts to inform
799 requesting for text completions in non-readline contexts to inform
800 the completer of the entire text.
800 the completer of the entire text.
801
801
802 cursor_pos : int, optional
802 cursor_pos : int, optional
803 Index of the cursor in the full line buffer. Should be provided by
803 Index of the cursor in the full line buffer. Should be provided by
804 remote frontends where kernel has no access to frontend state.
804 remote frontends where kernel has no access to frontend state.
805
805
806 Returns
806 Returns
807 -------
807 -------
808 text : str
808 text : str
809 Text that was actually used in the completion.
809 Text that was actually used in the completion.
810
810
811 matches : list
811 matches : list
812 A list of completion matches.
812 A list of completion matches.
813 """
813 """
814 #io.rprint('\nCOMP1 %r %r %r' % (text, line_buffer, cursor_pos)) # dbg
814 #io.rprint('\nCOMP1 %r %r %r' % (text, line_buffer, cursor_pos)) # dbg
815
815
816 # if the cursor position isn't given, the only sane assumption we can
816 # if the cursor position isn't given, the only sane assumption we can
817 # make is that it's at the end of the line (the common case)
817 # make is that it's at the end of the line (the common case)
818 if cursor_pos is None:
818 if cursor_pos is None:
819 cursor_pos = len(line_buffer) if text is None else len(text)
819 cursor_pos = len(line_buffer) if text is None else len(text)
820
820
821 # if text is either None or an empty string, rely on the line buffer
821 # if text is either None or an empty string, rely on the line buffer
822 if not text:
822 if not text:
823 text = self.splitter.split_line(line_buffer, cursor_pos)
823 text = self.splitter.split_line(line_buffer, cursor_pos)
824
824
825 # If no line buffer is given, assume the input text is all there was
825 # If no line buffer is given, assume the input text is all there was
826 if line_buffer is None:
826 if line_buffer is None:
827 line_buffer = text
827 line_buffer = text
828
828
829 self.line_buffer = line_buffer
829 self.line_buffer = line_buffer
830 self.text_until_cursor = self.line_buffer[:cursor_pos]
830 self.text_until_cursor = self.line_buffer[:cursor_pos]
831 #io.rprint('\nCOMP2 %r %r %r' % (text, line_buffer, cursor_pos)) # dbg
831 #io.rprint('\nCOMP2 %r %r %r' % (text, line_buffer, cursor_pos)) # dbg
832
832
833 # Start with a clean slate of completions
833 # Start with a clean slate of completions
834 self.matches[:] = []
834 self.matches[:] = []
835 custom_res = self.dispatch_custom_completer(text)
835 custom_res = self.dispatch_custom_completer(text)
836 if custom_res is not None:
836 if custom_res is not None:
837 # did custom completers produce something?
837 # did custom completers produce something?
838 self.matches = custom_res
838 self.matches = custom_res
839 else:
839 else:
840 # Extend the list of completions with the results of each
840 # Extend the list of completions with the results of each
841 # matcher, so we return results to the user from all
841 # matcher, so we return results to the user from all
842 # namespaces.
842 # namespaces.
843 if self.merge_completions:
843 if self.merge_completions:
844 self.matches = []
844 self.matches = []
845 for matcher in self.matchers:
845 for matcher in self.matchers:
846 try:
846 try:
847 self.matches.extend(matcher(text))
847 self.matches.extend(matcher(text))
848 except:
848 except:
849 # Show the ugly traceback if the matcher causes an
849 # Show the ugly traceback if the matcher causes an
850 # exception, but do NOT crash the kernel!
850 # exception, but do NOT crash the kernel!
851 sys.excepthook(*sys.exc_info())
851 sys.excepthook(*sys.exc_info())
852 else:
852 else:
853 for matcher in self.matchers:
853 for matcher in self.matchers:
854 self.matches = matcher(text)
854 self.matches = matcher(text)
855 if self.matches:
855 if self.matches:
856 break
856 break
857 # FIXME: we should extend our api to return a dict with completions for
857 # FIXME: we should extend our api to return a dict with completions for
858 # different types of objects. The rlcomplete() method could then
858 # different types of objects. The rlcomplete() method could then
859 # simply collapse the dict into a list for readline, but we'd have
859 # simply collapse the dict into a list for readline, but we'd have
860 # richer completion semantics in other evironments.
860 # richer completion semantics in other evironments.
861 self.matches = sorted(set(self.matches))
861 self.matches = sorted(set(self.matches))
862 #io.rprint('COMP TEXT, MATCHES: %r, %r' % (text, self.matches)) # dbg
862 #io.rprint('COMP TEXT, MATCHES: %r, %r' % (text, self.matches)) # dbg
863 return text, self.matches
863 return text, self.matches
864
864
865 def rlcomplete(self, text, state):
865 def rlcomplete(self, text, state):
866 """Return the state-th possible completion for 'text'.
866 """Return the state-th possible completion for 'text'.
867
867
868 This is called successively with state == 0, 1, 2, ... until it
868 This is called successively with state == 0, 1, 2, ... until it
869 returns None. The completion should begin with 'text'.
869 returns None. The completion should begin with 'text'.
870
870
871 Parameters
871 Parameters
872 ----------
872 ----------
873 text : string
873 text : string
874 Text to perform the completion on.
874 Text to perform the completion on.
875
875
876 state : int
876 state : int
877 Counter used by readline.
877 Counter used by readline.
878 """
878 """
879 if state==0:
879 if state==0:
880
880
881 self.line_buffer = line_buffer = self.readline.get_line_buffer()
881 self.line_buffer = line_buffer = self.readline.get_line_buffer()
882 cursor_pos = self.readline.get_endidx()
882 cursor_pos = self.readline.get_endidx()
883
883
884 #io.rprint("\nRLCOMPLETE: %r %r %r" %
884 #io.rprint("\nRLCOMPLETE: %r %r %r" %
885 # (text, line_buffer, cursor_pos) ) # dbg
885 # (text, line_buffer, cursor_pos) ) # dbg
886
886
887 # if there is only a tab on a line with only whitespace, instead of
887 # if there is only a tab on a line with only whitespace, instead of
888 # the mostly useless 'do you want to see all million completions'
888 # the mostly useless 'do you want to see all million completions'
889 # message, just do the right thing and give the user his tab!
889 # message, just do the right thing and give the user his tab!
890 # Incidentally, this enables pasting of tabbed text from an editor
890 # Incidentally, this enables pasting of tabbed text from an editor
891 # (as long as autoindent is off).
891 # (as long as autoindent is off).
892
892
893 # It should be noted that at least pyreadline still shows file
893 # It should be noted that at least pyreadline still shows file
894 # completions - is there a way around it?
894 # completions - is there a way around it?
895
895
896 # don't apply this on 'dumb' terminals, such as emacs buffers, so
896 # don't apply this on 'dumb' terminals, such as emacs buffers, so
897 # we don't interfere with their own tab-completion mechanism.
897 # we don't interfere with their own tab-completion mechanism.
898 if not (self.dumb_terminal or line_buffer.strip()):
898 if not (self.dumb_terminal or line_buffer.strip()):
899 self.readline.insert_text('\t')
899 self.readline.insert_text('\t')
900 sys.stdout.flush()
900 sys.stdout.flush()
901 return None
901 return None
902
902
903 # Note: debugging exceptions that may occur in completion is very
903 # Note: debugging exceptions that may occur in completion is very
904 # tricky, because readline unconditionally silences them. So if
904 # tricky, because readline unconditionally silences them. So if
905 # during development you suspect a bug in the completion code, turn
905 # during development you suspect a bug in the completion code, turn
906 # this flag on temporarily by uncommenting the second form (don't
906 # this flag on temporarily by uncommenting the second form (don't
907 # flip the value in the first line, as the '# dbg' marker can be
907 # flip the value in the first line, as the '# dbg' marker can be
908 # automatically detected and is used elsewhere).
908 # automatically detected and is used elsewhere).
909 DEBUG = False
909 DEBUG = False
910 #DEBUG = True # dbg
910 #DEBUG = True # dbg
911 if DEBUG:
911 if DEBUG:
912 try:
912 try:
913 self.complete(text, line_buffer, cursor_pos)
913 self.complete(text, line_buffer, cursor_pos)
914 except:
914 except:
915 import traceback; traceback.print_exc()
915 import traceback; traceback.print_exc()
916 else:
916 else:
917 # The normal production version is here
917 # The normal production version is here
918
918
919 # This method computes the self.matches array
919 # This method computes the self.matches array
920 self.complete(text, line_buffer, cursor_pos)
920 self.complete(text, line_buffer, cursor_pos)
921
921
922 try:
922 try:
923 return self.matches[state]
923 return self.matches[state]
924 except IndexError:
924 except IndexError:
925 return None
925 return None
@@ -1,347 +1,347 b''
1 """Implementations for various useful completers.
1 """Implementations for various useful completers.
2
2
3 These are all loaded by default by IPython.
3 These are all loaded by default by IPython.
4 """
4 """
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (C) 2010 The IPython Development Team.
6 # Copyright (C) 2010-2011 The IPython Development Team.
7 #
7 #
8 # Distributed under the terms of the BSD License.
8 # Distributed under the terms of the BSD License.
9 #
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 from __future__ import print_function
16 from __future__ import print_function
17
17
18 # Stdlib imports
18 # Stdlib imports
19 import glob
19 import glob
20 import inspect
20 import inspect
21 import os
21 import os
22 import re
22 import re
23 import shlex
23 import shlex
24 import sys
24 import sys
25
25
26 # Third-party imports
26 # Third-party imports
27 from time import time
27 from time import time
28 from zipimport import zipimporter
28 from zipimport import zipimporter
29
29
30 # Our own imports
30 # Our own imports
31 from IPython.core.completer import expand_user, compress_user
31 from IPython.core.completer import expand_user, compress_user
32 from IPython.core.error import TryNext
32 from IPython.core.error import TryNext
33 from IPython.utils import py3compat
33 from IPython.utils import py3compat
34
34
35 # FIXME: this should be pulled in with the right call via the component system
35 # FIXME: this should be pulled in with the right call via the component system
36 from IPython.core.ipapi import get as get_ipython
36 from IPython.core.ipapi import get as get_ipython
37
37
38 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
39 # Globals and constants
39 # Globals and constants
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41
41
42 # Time in seconds after which the rootmodules will be stored permanently in the
42 # Time in seconds after which the rootmodules will be stored permanently in the
43 # ipython ip.db database (kept in the user's .ipython dir).
43 # ipython ip.db database (kept in the user's .ipython dir).
44 TIMEOUT_STORAGE = 2
44 TIMEOUT_STORAGE = 2
45
45
46 # Time in seconds after which we give up
46 # Time in seconds after which we give up
47 TIMEOUT_GIVEUP = 20
47 TIMEOUT_GIVEUP = 20
48
48
49 # Regular expression for the python import statement
49 # Regular expression for the python import statement
50 import_re = re.compile(r'.*(\.so|\.py[cod]?)$')
50 import_re = re.compile(r'.*(\.so|\.py[cod]?)$')
51
51
52 # RE for the ipython %run command (python + ipython scripts)
52 # RE for the ipython %run command (python + ipython scripts)
53 magic_run_re = re.compile(r'.*(\.ipy|\.py[w]?)$')
53 magic_run_re = re.compile(r'.*(\.ipy|\.py[w]?)$')
54
54
55 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
56 # Local utilities
56 # Local utilities
57 #-----------------------------------------------------------------------------
57 #-----------------------------------------------------------------------------
58
58
59 def shlex_split(x):
59 def shlex_split(x):
60 """Helper function to split lines into segments.
60 """Helper function to split lines into segments.
61 """
61 """
62 # shlex.split raises an exception if there is a syntax error in sh syntax
62 # shlex.split raises an exception if there is a syntax error in sh syntax
63 # for example if no closing " is found. This function keeps dropping the
63 # for example if no closing " is found. This function keeps dropping the
64 # last character of the line until shlex.split does not raise
64 # last character of the line until shlex.split does not raise
65 # an exception. It adds end of the line to the result of shlex.split
65 # an exception. It adds end of the line to the result of shlex.split
66 #
66 #
67 # Example:
67 # Example:
68 # %run "c:/python -> ['%run','"c:/python']
68 # %run "c:/python -> ['%run','"c:/python']
69
69
70 # shlex.split has unicode bugs in Python 2, so encode first to str
70 # shlex.split has unicode bugs in Python 2, so encode first to str
71 if not py3compat.PY3:
71 if not py3compat.PY3:
72 x = py3compat.cast_bytes(x)
72 x = py3compat.cast_bytes(x)
73
73
74 endofline = []
74 endofline = []
75 while x != '':
75 while x != '':
76 try:
76 try:
77 comps = shlex.split(x)
77 comps = shlex.split(x)
78 if len(endofline) >= 1:
78 if len(endofline) >= 1:
79 comps.append(''.join(endofline))
79 comps.append(''.join(endofline))
80 return comps
80 return comps
81
81
82 except ValueError:
82 except ValueError:
83 endofline = [x[-1:]]+endofline
83 endofline = [x[-1:]]+endofline
84 x = x[:-1]
84 x = x[:-1]
85
85
86 return [''.join(endofline)]
86 return [''.join(endofline)]
87
87
88 def module_list(path):
88 def module_list(path):
89 """
89 """
90 Return the list containing the names of the modules available in the given
90 Return the list containing the names of the modules available in the given
91 folder.
91 folder.
92 """
92 """
93
93
94 if os.path.isdir(path):
94 if os.path.isdir(path):
95 folder_list = os.listdir(path)
95 folder_list = os.listdir(path)
96 elif path.endswith('.egg'):
96 elif path.endswith('.egg'):
97 try:
97 try:
98 folder_list = [f for f in zipimporter(path)._files]
98 folder_list = [f for f in zipimporter(path)._files]
99 except:
99 except:
100 folder_list = []
100 folder_list = []
101 else:
101 else:
102 folder_list = []
102 folder_list = []
103
103
104 if not folder_list:
104 if not folder_list:
105 return []
105 return []
106
106
107 # A few local constants to be used in loops below
107 # A few local constants to be used in loops below
108 isfile = os.path.isfile
108 isfile = os.path.isfile
109 pjoin = os.path.join
109 pjoin = os.path.join
110 basename = os.path.basename
110 basename = os.path.basename
111
111
112 # Now find actual path matches for packages or modules
112 # Now find actual path matches for packages or modules
113 folder_list = [p for p in folder_list
113 folder_list = [p for p in folder_list
114 if isfile(pjoin(path, p,'__init__.py'))
114 if isfile(pjoin(path, p,'__init__.py'))
115 or import_re.match(p) ]
115 or import_re.match(p) ]
116
116
117 return [basename(p).split('.')[0] for p in folder_list]
117 return [basename(p).split('.')[0] for p in folder_list]
118
118
119 def get_root_modules():
119 def get_root_modules():
120 """
120 """
121 Returns a list containing the names of all the modules available in the
121 Returns a list containing the names of all the modules available in the
122 folders of the pythonpath.
122 folders of the pythonpath.
123 """
123 """
124 ip = get_ipython()
124 ip = get_ipython()
125
125
126 if 'rootmodules' in ip.db:
126 if 'rootmodules' in ip.db:
127 return ip.db['rootmodules']
127 return ip.db['rootmodules']
128
128
129 t = time()
129 t = time()
130 store = False
130 store = False
131 modules = list(sys.builtin_module_names)
131 modules = list(sys.builtin_module_names)
132 for path in sys.path:
132 for path in sys.path:
133 modules += module_list(path)
133 modules += module_list(path)
134 if time() - t >= TIMEOUT_STORAGE and not store:
134 if time() - t >= TIMEOUT_STORAGE and not store:
135 store = True
135 store = True
136 print("\nCaching the list of root modules, please wait!")
136 print("\nCaching the list of root modules, please wait!")
137 print("(This will only be done once - type '%rehashx' to "
137 print("(This will only be done once - type '%rehashx' to "
138 "reset cache!)\n")
138 "reset cache!)\n")
139 sys.stdout.flush()
139 sys.stdout.flush()
140 if time() - t > TIMEOUT_GIVEUP:
140 if time() - t > TIMEOUT_GIVEUP:
141 print("This is taking too long, we give up.\n")
141 print("This is taking too long, we give up.\n")
142 ip.db['rootmodules'] = []
142 ip.db['rootmodules'] = []
143 return []
143 return []
144
144
145 modules = set(modules)
145 modules = set(modules)
146 if '__init__' in modules:
146 if '__init__' in modules:
147 modules.remove('__init__')
147 modules.remove('__init__')
148 modules = list(modules)
148 modules = list(modules)
149 if store:
149 if store:
150 ip.db['rootmodules'] = modules
150 ip.db['rootmodules'] = modules
151 return modules
151 return modules
152
152
153
153
154 def is_importable(module, attr, only_modules):
154 def is_importable(module, attr, only_modules):
155 if only_modules:
155 if only_modules:
156 return inspect.ismodule(getattr(module, attr))
156 return inspect.ismodule(getattr(module, attr))
157 else:
157 else:
158 return not(attr[:2] == '__' and attr[-2:] == '__')
158 return not(attr[:2] == '__' and attr[-2:] == '__')
159
159
160
160
161 def try_import(mod, only_modules=False):
161 def try_import(mod, only_modules=False):
162 try:
162 try:
163 m = __import__(mod)
163 m = __import__(mod)
164 except:
164 except:
165 return []
165 return []
166 mods = mod.split('.')
166 mods = mod.split('.')
167 for module in mods[1:]:
167 for module in mods[1:]:
168 m = getattr(m, module)
168 m = getattr(m, module)
169
169
170 m_is_init = hasattr(m, '__file__') and '__init__' in m.__file__
170 m_is_init = hasattr(m, '__file__') and '__init__' in m.__file__
171
171
172 completions = []
172 completions = []
173 if (not hasattr(m, '__file__')) or (not only_modules) or m_is_init:
173 if (not hasattr(m, '__file__')) or (not only_modules) or m_is_init:
174 completions.extend( [attr for attr in dir(m) if
174 completions.extend( [attr for attr in dir(m) if
175 is_importable(m, attr, only_modules)])
175 is_importable(m, attr, only_modules)])
176
176
177 completions.extend(getattr(m, '__all__', []))
177 completions.extend(getattr(m, '__all__', []))
178 if m_is_init:
178 if m_is_init:
179 completions.extend(module_list(os.path.dirname(m.__file__)))
179 completions.extend(module_list(os.path.dirname(m.__file__)))
180 completions = set(completions)
180 completions = set(completions)
181 if '__init__' in completions:
181 if '__init__' in completions:
182 completions.remove('__init__')
182 completions.remove('__init__')
183 return list(completions)
183 return list(completions)
184
184
185
185
186 #-----------------------------------------------------------------------------
186 #-----------------------------------------------------------------------------
187 # Completion-related functions.
187 # Completion-related functions.
188 #-----------------------------------------------------------------------------
188 #-----------------------------------------------------------------------------
189
189
190 def quick_completer(cmd, completions):
190 def quick_completer(cmd, completions):
191 """ Easily create a trivial completer for a command.
191 """ Easily create a trivial completer for a command.
192
192
193 Takes either a list of completions, or all completions in string (that will
193 Takes either a list of completions, or all completions in string (that will
194 be split on whitespace).
194 be split on whitespace).
195
195
196 Example::
196 Example::
197
197
198 [d:\ipython]|1> import ipy_completers
198 [d:\ipython]|1> import ipy_completers
199 [d:\ipython]|2> ipy_completers.quick_completer('foo', ['bar','baz'])
199 [d:\ipython]|2> ipy_completers.quick_completer('foo', ['bar','baz'])
200 [d:\ipython]|3> foo b<TAB>
200 [d:\ipython]|3> foo b<TAB>
201 bar baz
201 bar baz
202 [d:\ipython]|3> foo ba
202 [d:\ipython]|3> foo ba
203 """
203 """
204
204
205 if isinstance(completions, basestring):
205 if isinstance(completions, basestring):
206 completions = completions.split()
206 completions = completions.split()
207
207
208 def do_complete(self, event):
208 def do_complete(self, event):
209 return completions
209 return completions
210
210
211 get_ipython().set_hook('complete_command',do_complete, str_key = cmd)
211 get_ipython().set_hook('complete_command',do_complete, str_key = cmd)
212
212
213
213
214 def module_completion(line):
214 def module_completion(line):
215 """
215 """
216 Returns a list containing the completion possibilities for an import line.
216 Returns a list containing the completion possibilities for an import line.
217
217
218 The line looks like this :
218 The line looks like this :
219 'import xml.d'
219 'import xml.d'
220 'from xml.dom import'
220 'from xml.dom import'
221 """
221 """
222
222
223 words = line.split(' ')
223 words = line.split(' ')
224 nwords = len(words)
224 nwords = len(words)
225
225
226 # from whatever <tab> -> 'import '
226 # from whatever <tab> -> 'import '
227 if nwords == 3 and words[0] == 'from':
227 if nwords == 3 and words[0] == 'from':
228 return ['import ']
228 return ['import ']
229
229
230 # 'from xy<tab>' or 'import xy<tab>'
230 # 'from xy<tab>' or 'import xy<tab>'
231 if nwords < 3 and (words[0] in ['import','from']) :
231 if nwords < 3 and (words[0] in ['import','from']) :
232 if nwords == 1:
232 if nwords == 1:
233 return get_root_modules()
233 return get_root_modules()
234 mod = words[1].split('.')
234 mod = words[1].split('.')
235 if len(mod) < 2:
235 if len(mod) < 2:
236 return get_root_modules()
236 return get_root_modules()
237 completion_list = try_import('.'.join(mod[:-1]), True)
237 completion_list = try_import('.'.join(mod[:-1]), True)
238 return ['.'.join(mod[:-1] + [el]) for el in completion_list]
238 return ['.'.join(mod[:-1] + [el]) for el in completion_list]
239
239
240 # 'from xyz import abc<tab>'
240 # 'from xyz import abc<tab>'
241 if nwords >= 3 and words[0] == 'from':
241 if nwords >= 3 and words[0] == 'from':
242 mod = words[1]
242 mod = words[1]
243 return try_import(mod)
243 return try_import(mod)
244
244
245 #-----------------------------------------------------------------------------
245 #-----------------------------------------------------------------------------
246 # Completers
246 # Completers
247 #-----------------------------------------------------------------------------
247 #-----------------------------------------------------------------------------
248 # These all have the func(self, event) signature to be used as custom
248 # These all have the func(self, event) signature to be used as custom
249 # completers
249 # completers
250
250
251 def module_completer(self,event):
251 def module_completer(self,event):
252 """Give completions after user has typed 'import ...' or 'from ...'"""
252 """Give completions after user has typed 'import ...' or 'from ...'"""
253
253
254 # This works in all versions of python. While 2.5 has
254 # This works in all versions of python. While 2.5 has
255 # pkgutil.walk_packages(), that particular routine is fairly dangerous,
255 # pkgutil.walk_packages(), that particular routine is fairly dangerous,
256 # since it imports *EVERYTHING* on sys.path. That is: a) very slow b) full
256 # since it imports *EVERYTHING* on sys.path. That is: a) very slow b) full
257 # of possibly problematic side effects.
257 # of possibly problematic side effects.
258 # This search the folders in the sys.path for available modules.
258 # This search the folders in the sys.path for available modules.
259
259
260 return module_completion(event.line)
260 return module_completion(event.line)
261
261
262 # FIXME: there's a lot of logic common to the run, cd and builtin file
262 # FIXME: there's a lot of logic common to the run, cd and builtin file
263 # completers, that is currently reimplemented in each.
263 # completers, that is currently reimplemented in each.
264
264
265 def magic_run_completer(self, event):
265 def magic_run_completer(self, event):
266 """Complete files that end in .py or .ipy for the %run command.
266 """Complete files that end in .py or .ipy for the %run command.
267 """
267 """
268 comps = shlex_split(event.line)
268 comps = shlex_split(event.line)
269 relpath = (len(comps) > 1 and comps[-1] or '').strip("'\"")
269 relpath = (len(comps) > 1 and comps[-1] or '').strip("'\"")
270
270
271 #print("\nev=", event) # dbg
271 #print("\nev=", event) # dbg
272 #print("rp=", relpath) # dbg
272 #print("rp=", relpath) # dbg
273 #print('comps=', comps) # dbg
273 #print('comps=', comps) # dbg
274
274
275 lglob = glob.glob
275 lglob = glob.glob
276 isdir = os.path.isdir
276 isdir = os.path.isdir
277 relpath, tilde_expand, tilde_val = expand_user(relpath)
277 relpath, tilde_expand, tilde_val = expand_user(relpath)
278
278
279 dirs = [f.replace('\\','/') + "/" for f in lglob(relpath+'*') if isdir(f)]
279 dirs = [f.replace('\\','/') + "/" for f in lglob(relpath+'*') if isdir(f)]
280
280
281 # Find if the user has already typed the first filename, after which we
281 # Find if the user has already typed the first filename, after which we
282 # should complete on all files, since after the first one other files may
282 # should complete on all files, since after the first one other files may
283 # be arguments to the input script.
283 # be arguments to the input script.
284
284
285 if filter(magic_run_re.match, comps):
285 if filter(magic_run_re.match, comps):
286 pys = [f.replace('\\','/') for f in lglob('*')]
286 pys = [f.replace('\\','/') for f in lglob('*')]
287 else:
287 else:
288 pys = [f.replace('\\','/')
288 pys = [f.replace('\\','/')
289 for f in lglob(relpath+'*.py') + lglob(relpath+'*.ipy') +
289 for f in lglob(relpath+'*.py') + lglob(relpath+'*.ipy') +
290 lglob(relpath + '*.pyw')]
290 lglob(relpath + '*.pyw')]
291 #print('run comp:', dirs+pys) # dbg
291 #print('run comp:', dirs+pys) # dbg
292 return [compress_user(p, tilde_expand, tilde_val) for p in dirs+pys]
292 return [compress_user(p, tilde_expand, tilde_val) for p in dirs+pys]
293
293
294
294
295 def cd_completer(self, event):
295 def cd_completer(self, event):
296 """Completer function for cd, which only returns directories."""
296 """Completer function for cd, which only returns directories."""
297 ip = get_ipython()
297 ip = get_ipython()
298 relpath = event.symbol
298 relpath = event.symbol
299
299
300 #print(event) # dbg
300 #print(event) # dbg
301 if event.line.endswith('-b') or ' -b ' in event.line:
301 if event.line.endswith('-b') or ' -b ' in event.line:
302 # return only bookmark completions
302 # return only bookmark completions
303 bkms = self.db.get('bookmarks', None)
303 bkms = self.db.get('bookmarks', None)
304 if bkms:
304 if bkms:
305 return bkms.keys()
305 return bkms.keys()
306 else:
306 else:
307 return []
307 return []
308
308
309 if event.symbol == '-':
309 if event.symbol == '-':
310 width_dh = str(len(str(len(ip.user_ns['_dh']) + 1)))
310 width_dh = str(len(str(len(ip.user_ns['_dh']) + 1)))
311 # jump in directory history by number
311 # jump in directory history by number
312 fmt = '-%0' + width_dh +'d [%s]'
312 fmt = '-%0' + width_dh +'d [%s]'
313 ents = [ fmt % (i,s) for i,s in enumerate(ip.user_ns['_dh'])]
313 ents = [ fmt % (i,s) for i,s in enumerate(ip.user_ns['_dh'])]
314 if len(ents) > 1:
314 if len(ents) > 1:
315 return ents
315 return ents
316 return []
316 return []
317
317
318 if event.symbol.startswith('--'):
318 if event.symbol.startswith('--'):
319 return ["--" + os.path.basename(d) for d in ip.user_ns['_dh']]
319 return ["--" + os.path.basename(d) for d in ip.user_ns['_dh']]
320
320
321 # Expand ~ in path and normalize directory separators.
321 # Expand ~ in path and normalize directory separators.
322 relpath, tilde_expand, tilde_val = expand_user(relpath)
322 relpath, tilde_expand, tilde_val = expand_user(relpath)
323 relpath = relpath.replace('\\','/')
323 relpath = relpath.replace('\\','/')
324
324
325 found = []
325 found = []
326 for d in [f.replace('\\','/') + '/' for f in glob.glob(relpath+'*')
326 for d in [f.replace('\\','/') + '/' for f in glob.glob(relpath+'*')
327 if os.path.isdir(f)]:
327 if os.path.isdir(f)]:
328 if ' ' in d:
328 if ' ' in d:
329 # we don't want to deal with any of that, complex code
329 # we don't want to deal with any of that, complex code
330 # for this is elsewhere
330 # for this is elsewhere
331 raise TryNext
331 raise TryNext
332
332
333 found.append(d)
333 found.append(d)
334
334
335 if not found:
335 if not found:
336 if os.path.isdir(relpath):
336 if os.path.isdir(relpath):
337 return [compress_user(relpath, tilde_expand, tilde_val)]
337 return [compress_user(relpath, tilde_expand, tilde_val)]
338
338
339 # if no completions so far, try bookmarks
339 # if no completions so far, try bookmarks
340 bks = self.db.get('bookmarks',{}).iterkeys()
340 bks = self.db.get('bookmarks',{}).iterkeys()
341 bkmatches = [s for s in bks if s.startswith(event.symbol)]
341 bkmatches = [s for s in bks if s.startswith(event.symbol)]
342 if bkmatches:
342 if bkmatches:
343 return bkmatches
343 return bkmatches
344
344
345 raise TryNext
345 raise TryNext
346
346
347 return [compress_user(p, tilde_expand, tilde_val) for p in found]
347 return [compress_user(p, tilde_expand, tilde_val) for p in found]
@@ -1,214 +1,214 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """sys.excepthook for IPython itself, leaves a detailed report on disk.
2 """sys.excepthook for IPython itself, leaves a detailed report on disk.
3
3
4 Authors:
4 Authors:
5
5
6 * Fernando Perez
6 * Fernando Perez
7 * Brian E. Granger
7 * Brian E. Granger
8 """
8 """
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
11 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
12 # Copyright (C) 2008-2010 The IPython Development Team
12 # Copyright (C) 2008-2011 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 import os
22 import os
23 import sys
23 import sys
24 import traceback
24 import traceback
25 from pprint import pformat
25 from pprint import pformat
26
26
27 from IPython.core import ultratb
27 from IPython.core import ultratb
28 from IPython.core.release import author_email
28 from IPython.core.release import author_email
29 from IPython.utils.sysinfo import sys_info
29 from IPython.utils.sysinfo import sys_info
30
30
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32 # Code
32 # Code
33 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
34
34
35 # Template for the user message.
35 # Template for the user message.
36 _default_message_template = """\
36 _default_message_template = """\
37 Oops, {app_name} crashed. We do our best to make it stable, but...
37 Oops, {app_name} crashed. We do our best to make it stable, but...
38
38
39 A crash report was automatically generated with the following information:
39 A crash report was automatically generated with the following information:
40 - A verbatim copy of the crash traceback.
40 - A verbatim copy of the crash traceback.
41 - A copy of your input history during this session.
41 - A copy of your input history during this session.
42 - Data on your current {app_name} configuration.
42 - Data on your current {app_name} configuration.
43
43
44 It was left in the file named:
44 It was left in the file named:
45 \t'{crash_report_fname}'
45 \t'{crash_report_fname}'
46 If you can email this file to the developers, the information in it will help
46 If you can email this file to the developers, the information in it will help
47 them in understanding and correcting the problem.
47 them in understanding and correcting the problem.
48
48
49 You can mail it to: {contact_name} at {contact_email}
49 You can mail it to: {contact_name} at {contact_email}
50 with the subject '{app_name} Crash Report'.
50 with the subject '{app_name} Crash Report'.
51
51
52 If you want to do it now, the following command will work (under Unix):
52 If you want to do it now, the following command will work (under Unix):
53 mail -s '{app_name} Crash Report' {contact_email} < {crash_report_fname}
53 mail -s '{app_name} Crash Report' {contact_email} < {crash_report_fname}
54
54
55 To ensure accurate tracking of this issue, please file a report about it at:
55 To ensure accurate tracking of this issue, please file a report about it at:
56 {bug_tracker}
56 {bug_tracker}
57 """
57 """
58
58
59 _lite_message_template = """
59 _lite_message_template = """
60 If you suspect this is an IPython bug, please report it at:
60 If you suspect this is an IPython bug, please report it at:
61 https://github.com/ipython/ipython/issues
61 https://github.com/ipython/ipython/issues
62 or send an email to the mailing list at {email}
62 or send an email to the mailing list at {email}
63
63
64 You can print a more detailed traceback right now with "%tb", or use "%debug"
64 You can print a more detailed traceback right now with "%tb", or use "%debug"
65 to interactively debug it.
65 to interactively debug it.
66
66
67 Extra-detailed tracebacks for bug-reporting purposes can be enabled via:
67 Extra-detailed tracebacks for bug-reporting purposes can be enabled via:
68 {config}Application.verbose_crash=True
68 {config}Application.verbose_crash=True
69 """
69 """
70
70
71
71
72 class CrashHandler(object):
72 class CrashHandler(object):
73 """Customizable crash handlers for IPython applications.
73 """Customizable crash handlers for IPython applications.
74
74
75 Instances of this class provide a :meth:`__call__` method which can be
75 Instances of this class provide a :meth:`__call__` method which can be
76 used as a ``sys.excepthook``. The :meth:`__call__` signature is::
76 used as a ``sys.excepthook``. The :meth:`__call__` signature is::
77
77
78 def __call__(self, etype, evalue, etb)
78 def __call__(self, etype, evalue, etb)
79 """
79 """
80
80
81 message_template = _default_message_template
81 message_template = _default_message_template
82 section_sep = '\n\n'+'*'*75+'\n\n'
82 section_sep = '\n\n'+'*'*75+'\n\n'
83
83
84 def __init__(self, app, contact_name=None, contact_email=None,
84 def __init__(self, app, contact_name=None, contact_email=None,
85 bug_tracker=None, show_crash_traceback=True, call_pdb=False):
85 bug_tracker=None, show_crash_traceback=True, call_pdb=False):
86 """Create a new crash handler
86 """Create a new crash handler
87
87
88 Parameters
88 Parameters
89 ----------
89 ----------
90 app : Application
90 app : Application
91 A running :class:`Application` instance, which will be queried at
91 A running :class:`Application` instance, which will be queried at
92 crash time for internal information.
92 crash time for internal information.
93
93
94 contact_name : str
94 contact_name : str
95 A string with the name of the person to contact.
95 A string with the name of the person to contact.
96
96
97 contact_email : str
97 contact_email : str
98 A string with the email address of the contact.
98 A string with the email address of the contact.
99
99
100 bug_tracker : str
100 bug_tracker : str
101 A string with the URL for your project's bug tracker.
101 A string with the URL for your project's bug tracker.
102
102
103 show_crash_traceback : bool
103 show_crash_traceback : bool
104 If false, don't print the crash traceback on stderr, only generate
104 If false, don't print the crash traceback on stderr, only generate
105 the on-disk report
105 the on-disk report
106
106
107 Non-argument instance attributes:
107 Non-argument instance attributes:
108
108
109 These instances contain some non-argument attributes which allow for
109 These instances contain some non-argument attributes which allow for
110 further customization of the crash handler's behavior. Please see the
110 further customization of the crash handler's behavior. Please see the
111 source for further details.
111 source for further details.
112 """
112 """
113 self.crash_report_fname = "Crash_report_%s.txt" % app.name
113 self.crash_report_fname = "Crash_report_%s.txt" % app.name
114 self.app = app
114 self.app = app
115 self.call_pdb = call_pdb
115 self.call_pdb = call_pdb
116 #self.call_pdb = True # dbg
116 #self.call_pdb = True # dbg
117 self.show_crash_traceback = show_crash_traceback
117 self.show_crash_traceback = show_crash_traceback
118 self.info = dict(app_name = app.name,
118 self.info = dict(app_name = app.name,
119 contact_name = contact_name,
119 contact_name = contact_name,
120 contact_email = contact_email,
120 contact_email = contact_email,
121 bug_tracker = bug_tracker,
121 bug_tracker = bug_tracker,
122 crash_report_fname = self.crash_report_fname)
122 crash_report_fname = self.crash_report_fname)
123
123
124
124
125 def __call__(self, etype, evalue, etb):
125 def __call__(self, etype, evalue, etb):
126 """Handle an exception, call for compatible with sys.excepthook"""
126 """Handle an exception, call for compatible with sys.excepthook"""
127
127
128 # do not allow the crash handler to be called twice without reinstalling it
128 # do not allow the crash handler to be called twice without reinstalling it
129 # this prevents unlikely errors in the crash handling from entering an
129 # this prevents unlikely errors in the crash handling from entering an
130 # infinite loop.
130 # infinite loop.
131 sys.excepthook = sys.__excepthook__
131 sys.excepthook = sys.__excepthook__
132
132
133 # Report tracebacks shouldn't use color in general (safer for users)
133 # Report tracebacks shouldn't use color in general (safer for users)
134 color_scheme = 'NoColor'
134 color_scheme = 'NoColor'
135
135
136 # Use this ONLY for developer debugging (keep commented out for release)
136 # Use this ONLY for developer debugging (keep commented out for release)
137 #color_scheme = 'Linux' # dbg
137 #color_scheme = 'Linux' # dbg
138 try:
138 try:
139 rptdir = self.app.ipython_dir
139 rptdir = self.app.ipython_dir
140 except:
140 except:
141 rptdir = os.getcwdu()
141 rptdir = os.getcwdu()
142 if rptdir is None or not os.path.isdir(rptdir):
142 if rptdir is None or not os.path.isdir(rptdir):
143 rptdir = os.getcwdu()
143 rptdir = os.getcwdu()
144 report_name = os.path.join(rptdir,self.crash_report_fname)
144 report_name = os.path.join(rptdir,self.crash_report_fname)
145 # write the report filename into the instance dict so it can get
145 # write the report filename into the instance dict so it can get
146 # properly expanded out in the user message template
146 # properly expanded out in the user message template
147 self.crash_report_fname = report_name
147 self.crash_report_fname = report_name
148 self.info['crash_report_fname'] = report_name
148 self.info['crash_report_fname'] = report_name
149 TBhandler = ultratb.VerboseTB(
149 TBhandler = ultratb.VerboseTB(
150 color_scheme=color_scheme,
150 color_scheme=color_scheme,
151 long_header=1,
151 long_header=1,
152 call_pdb=self.call_pdb,
152 call_pdb=self.call_pdb,
153 )
153 )
154 if self.call_pdb:
154 if self.call_pdb:
155 TBhandler(etype,evalue,etb)
155 TBhandler(etype,evalue,etb)
156 return
156 return
157 else:
157 else:
158 traceback = TBhandler.text(etype,evalue,etb,context=31)
158 traceback = TBhandler.text(etype,evalue,etb,context=31)
159
159
160 # print traceback to screen
160 # print traceback to screen
161 if self.show_crash_traceback:
161 if self.show_crash_traceback:
162 print >> sys.stderr, traceback
162 print >> sys.stderr, traceback
163
163
164 # and generate a complete report on disk
164 # and generate a complete report on disk
165 try:
165 try:
166 report = open(report_name,'w')
166 report = open(report_name,'w')
167 except:
167 except:
168 print >> sys.stderr, 'Could not create crash report on disk.'
168 print >> sys.stderr, 'Could not create crash report on disk.'
169 return
169 return
170
170
171 # Inform user on stderr of what happened
171 # Inform user on stderr of what happened
172 print >> sys.stderr, '\n'+'*'*70+'\n'
172 print >> sys.stderr, '\n'+'*'*70+'\n'
173 print >> sys.stderr, self.message_template.format(**self.info)
173 print >> sys.stderr, self.message_template.format(**self.info)
174
174
175 # Construct report on disk
175 # Construct report on disk
176 report.write(self.make_report(traceback))
176 report.write(self.make_report(traceback))
177 report.close()
177 report.close()
178 raw_input("Hit <Enter> to quit (your terminal may close):")
178 raw_input("Hit <Enter> to quit (your terminal may close):")
179
179
180 def make_report(self,traceback):
180 def make_report(self,traceback):
181 """Return a string containing a crash report."""
181 """Return a string containing a crash report."""
182
182
183 sec_sep = self.section_sep
183 sec_sep = self.section_sep
184
184
185 report = ['*'*75+'\n\n'+'IPython post-mortem report\n\n']
185 report = ['*'*75+'\n\n'+'IPython post-mortem report\n\n']
186 rpt_add = report.append
186 rpt_add = report.append
187 rpt_add(sys_info())
187 rpt_add(sys_info())
188
188
189 try:
189 try:
190 config = pformat(self.app.config)
190 config = pformat(self.app.config)
191 rpt_add(sec_sep)
191 rpt_add(sec_sep)
192 rpt_add('Application name: %s\n\n' % self.app_name)
192 rpt_add('Application name: %s\n\n' % self.app_name)
193 rpt_add('Current user configuration structure:\n\n')
193 rpt_add('Current user configuration structure:\n\n')
194 rpt_add(config)
194 rpt_add(config)
195 except:
195 except:
196 pass
196 pass
197 rpt_add(sec_sep+'Crash traceback:\n\n' + traceback)
197 rpt_add(sec_sep+'Crash traceback:\n\n' + traceback)
198
198
199 return ''.join(report)
199 return ''.join(report)
200
200
201
201
202 def crash_handler_lite(etype, evalue, tb):
202 def crash_handler_lite(etype, evalue, tb):
203 """a light excepthook, adding a small message to the usual traceback"""
203 """a light excepthook, adding a small message to the usual traceback"""
204 traceback.print_exception(etype, evalue, tb)
204 traceback.print_exception(etype, evalue, tb)
205
205
206 from IPython.core.interactiveshell import InteractiveShell
206 from IPython.core.interactiveshell import InteractiveShell
207 if InteractiveShell.initialized():
207 if InteractiveShell.initialized():
208 # we are in a Shell environment, give %magic example
208 # we are in a Shell environment, give %magic example
209 config = "%config "
209 config = "%config "
210 else:
210 else:
211 # we are not in a shell, show generic config
211 # we are not in a shell, show generic config
212 config = "c."
212 config = "c."
213 print >> sys.stderr, _lite_message_template.format(email=author_email, config=config)
213 print >> sys.stderr, _lite_message_template.format(email=author_email, config=config)
214
214
@@ -1,407 +1,407 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Top-level display functions for displaying object in different formats.
2 """Top-level display functions for displaying object in different formats.
3
3
4 Authors:
4 Authors:
5
5
6 * Brian Granger
6 * Brian Granger
7 """
7 """
8
8
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2008-2010 The IPython Development Team
10 # Copyright (C) 2008-2011 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
19
20 from .displaypub import (
20 from .displaypub import (
21 publish_pretty, publish_html,
21 publish_pretty, publish_html,
22 publish_latex, publish_svg,
22 publish_latex, publish_svg,
23 publish_png, publish_json,
23 publish_png, publish_json,
24 publish_javascript, publish_jpeg
24 publish_javascript, publish_jpeg
25 )
25 )
26
26
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28 # Main functions
28 # Main functions
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30
30
31 def display(*objs, **kwargs):
31 def display(*objs, **kwargs):
32 """Display a Python object in all frontends.
32 """Display a Python object in all frontends.
33
33
34 By default all representations will be computed and sent to the frontends.
34 By default all representations will be computed and sent to the frontends.
35 Frontends can decide which representation is used and how.
35 Frontends can decide which representation is used and how.
36
36
37 Parameters
37 Parameters
38 ----------
38 ----------
39 objs : tuple of objects
39 objs : tuple of objects
40 The Python objects to display.
40 The Python objects to display.
41 include : list or tuple, optional
41 include : list or tuple, optional
42 A list of format type strings (MIME types) to include in the
42 A list of format type strings (MIME types) to include in the
43 format data dict. If this is set *only* the format types included
43 format data dict. If this is set *only* the format types included
44 in this list will be computed.
44 in this list will be computed.
45 exclude : list or tuple, optional
45 exclude : list or tuple, optional
46 A list of format type string (MIME types) to exclue in the format
46 A list of format type string (MIME types) to exclue in the format
47 data dict. If this is set all format types will be computed,
47 data dict. If this is set all format types will be computed,
48 except for those included in this argument.
48 except for those included in this argument.
49 """
49 """
50 include = kwargs.get('include')
50 include = kwargs.get('include')
51 exclude = kwargs.get('exclude')
51 exclude = kwargs.get('exclude')
52
52
53 from IPython.core.interactiveshell import InteractiveShell
53 from IPython.core.interactiveshell import InteractiveShell
54 inst = InteractiveShell.instance()
54 inst = InteractiveShell.instance()
55 format = inst.display_formatter.format
55 format = inst.display_formatter.format
56 publish = inst.display_pub.publish
56 publish = inst.display_pub.publish
57
57
58 for obj in objs:
58 for obj in objs:
59 format_dict = format(obj, include=include, exclude=exclude)
59 format_dict = format(obj, include=include, exclude=exclude)
60 publish('IPython.core.display.display', format_dict)
60 publish('IPython.core.display.display', format_dict)
61
61
62
62
63 def display_pretty(*objs, **kwargs):
63 def display_pretty(*objs, **kwargs):
64 """Display the pretty (default) representation of an object.
64 """Display the pretty (default) representation of an object.
65
65
66 Parameters
66 Parameters
67 ----------
67 ----------
68 objs : tuple of objects
68 objs : tuple of objects
69 The Python objects to display, or if raw=True raw text data to
69 The Python objects to display, or if raw=True raw text data to
70 display.
70 display.
71 raw : bool
71 raw : bool
72 Are the data objects raw data or Python objects that need to be
72 Are the data objects raw data or Python objects that need to be
73 formatted before display? [default: False]
73 formatted before display? [default: False]
74 """
74 """
75 raw = kwargs.pop('raw',False)
75 raw = kwargs.pop('raw',False)
76 if raw:
76 if raw:
77 for obj in objs:
77 for obj in objs:
78 publish_pretty(obj)
78 publish_pretty(obj)
79 else:
79 else:
80 display(*objs, include=['text/plain'])
80 display(*objs, include=['text/plain'])
81
81
82
82
83 def display_html(*objs, **kwargs):
83 def display_html(*objs, **kwargs):
84 """Display the HTML representation of an object.
84 """Display the HTML representation of an object.
85
85
86 Parameters
86 Parameters
87 ----------
87 ----------
88 objs : tuple of objects
88 objs : tuple of objects
89 The Python objects to display, or if raw=True raw HTML data to
89 The Python objects to display, or if raw=True raw HTML data to
90 display.
90 display.
91 raw : bool
91 raw : bool
92 Are the data objects raw data or Python objects that need to be
92 Are the data objects raw data or Python objects that need to be
93 formatted before display? [default: False]
93 formatted before display? [default: False]
94 """
94 """
95 raw = kwargs.pop('raw',False)
95 raw = kwargs.pop('raw',False)
96 if raw:
96 if raw:
97 for obj in objs:
97 for obj in objs:
98 publish_html(obj)
98 publish_html(obj)
99 else:
99 else:
100 display(*objs, include=['text/plain','text/html'])
100 display(*objs, include=['text/plain','text/html'])
101
101
102
102
103 def display_svg(*objs, **kwargs):
103 def display_svg(*objs, **kwargs):
104 """Display the SVG representation of an object.
104 """Display the SVG representation of an object.
105
105
106 Parameters
106 Parameters
107 ----------
107 ----------
108 objs : tuple of objects
108 objs : tuple of objects
109 The Python objects to display, or if raw=True raw svg data to
109 The Python objects to display, or if raw=True raw svg data to
110 display.
110 display.
111 raw : bool
111 raw : bool
112 Are the data objects raw data or Python objects that need to be
112 Are the data objects raw data or Python objects that need to be
113 formatted before display? [default: False]
113 formatted before display? [default: False]
114 """
114 """
115 raw = kwargs.pop('raw',False)
115 raw = kwargs.pop('raw',False)
116 if raw:
116 if raw:
117 for obj in objs:
117 for obj in objs:
118 publish_svg(obj)
118 publish_svg(obj)
119 else:
119 else:
120 display(*objs, include=['text/plain','image/svg+xml'])
120 display(*objs, include=['text/plain','image/svg+xml'])
121
121
122
122
123 def display_png(*objs, **kwargs):
123 def display_png(*objs, **kwargs):
124 """Display the PNG representation of an object.
124 """Display the PNG representation of an object.
125
125
126 Parameters
126 Parameters
127 ----------
127 ----------
128 objs : tuple of objects
128 objs : tuple of objects
129 The Python objects to display, or if raw=True raw png data to
129 The Python objects to display, or if raw=True raw png data to
130 display.
130 display.
131 raw : bool
131 raw : bool
132 Are the data objects raw data or Python objects that need to be
132 Are the data objects raw data or Python objects that need to be
133 formatted before display? [default: False]
133 formatted before display? [default: False]
134 """
134 """
135 raw = kwargs.pop('raw',False)
135 raw = kwargs.pop('raw',False)
136 if raw:
136 if raw:
137 for obj in objs:
137 for obj in objs:
138 publish_png(obj)
138 publish_png(obj)
139 else:
139 else:
140 display(*objs, include=['text/plain','image/png'])
140 display(*objs, include=['text/plain','image/png'])
141
141
142
142
143 def display_jpeg(*objs, **kwargs):
143 def display_jpeg(*objs, **kwargs):
144 """Display the JPEG representation of an object.
144 """Display the JPEG representation of an object.
145
145
146 Parameters
146 Parameters
147 ----------
147 ----------
148 objs : tuple of objects
148 objs : tuple of objects
149 The Python objects to display, or if raw=True raw JPEG data to
149 The Python objects to display, or if raw=True raw JPEG data to
150 display.
150 display.
151 raw : bool
151 raw : bool
152 Are the data objects raw data or Python objects that need to be
152 Are the data objects raw data or Python objects that need to be
153 formatted before display? [default: False]
153 formatted before display? [default: False]
154 """
154 """
155 raw = kwargs.pop('raw',False)
155 raw = kwargs.pop('raw',False)
156 if raw:
156 if raw:
157 for obj in objs:
157 for obj in objs:
158 publish_jpeg(obj)
158 publish_jpeg(obj)
159 else:
159 else:
160 display(*objs, include=['text/plain','image/jpeg'])
160 display(*objs, include=['text/plain','image/jpeg'])
161
161
162
162
163 def display_latex(*objs, **kwargs):
163 def display_latex(*objs, **kwargs):
164 """Display the LaTeX representation of an object.
164 """Display the LaTeX representation of an object.
165
165
166 Parameters
166 Parameters
167 ----------
167 ----------
168 objs : tuple of objects
168 objs : tuple of objects
169 The Python objects to display, or if raw=True raw latex data to
169 The Python objects to display, or if raw=True raw latex data to
170 display.
170 display.
171 raw : bool
171 raw : bool
172 Are the data objects raw data or Python objects that need to be
172 Are the data objects raw data or Python objects that need to be
173 formatted before display? [default: False]
173 formatted before display? [default: False]
174 """
174 """
175 raw = kwargs.pop('raw',False)
175 raw = kwargs.pop('raw',False)
176 if raw:
176 if raw:
177 for obj in objs:
177 for obj in objs:
178 publish_latex(obj)
178 publish_latex(obj)
179 else:
179 else:
180 display(*objs, include=['text/plain','text/latex'])
180 display(*objs, include=['text/plain','text/latex'])
181
181
182
182
183 def display_json(*objs, **kwargs):
183 def display_json(*objs, **kwargs):
184 """Display the JSON representation of an object.
184 """Display the JSON representation of an object.
185
185
186 Parameters
186 Parameters
187 ----------
187 ----------
188 objs : tuple of objects
188 objs : tuple of objects
189 The Python objects to display, or if raw=True raw json data to
189 The Python objects to display, or if raw=True raw json data to
190 display.
190 display.
191 raw : bool
191 raw : bool
192 Are the data objects raw data or Python objects that need to be
192 Are the data objects raw data or Python objects that need to be
193 formatted before display? [default: False]
193 formatted before display? [default: False]
194 """
194 """
195 raw = kwargs.pop('raw',False)
195 raw = kwargs.pop('raw',False)
196 if raw:
196 if raw:
197 for obj in objs:
197 for obj in objs:
198 publish_json(obj)
198 publish_json(obj)
199 else:
199 else:
200 display(*objs, include=['text/plain','application/json'])
200 display(*objs, include=['text/plain','application/json'])
201
201
202
202
203 def display_javascript(*objs, **kwargs):
203 def display_javascript(*objs, **kwargs):
204 """Display the Javascript representation of an object.
204 """Display the Javascript representation of an object.
205
205
206 Parameters
206 Parameters
207 ----------
207 ----------
208 objs : tuple of objects
208 objs : tuple of objects
209 The Python objects to display, or if raw=True raw javascript data to
209 The Python objects to display, or if raw=True raw javascript data to
210 display.
210 display.
211 raw : bool
211 raw : bool
212 Are the data objects raw data or Python objects that need to be
212 Are the data objects raw data or Python objects that need to be
213 formatted before display? [default: False]
213 formatted before display? [default: False]
214 """
214 """
215 raw = kwargs.pop('raw',False)
215 raw = kwargs.pop('raw',False)
216 if raw:
216 if raw:
217 for obj in objs:
217 for obj in objs:
218 publish_javascript(obj)
218 publish_javascript(obj)
219 else:
219 else:
220 display(*objs, include=['text/plain','application/javascript'])
220 display(*objs, include=['text/plain','application/javascript'])
221
221
222 #-----------------------------------------------------------------------------
222 #-----------------------------------------------------------------------------
223 # Smart classes
223 # Smart classes
224 #-----------------------------------------------------------------------------
224 #-----------------------------------------------------------------------------
225
225
226
226
227 class DisplayObject(object):
227 class DisplayObject(object):
228 """An object that wraps data to be displayed."""
228 """An object that wraps data to be displayed."""
229
229
230 _read_flags = 'r'
230 _read_flags = 'r'
231
231
232 def __init__(self, data=None, url=None, filename=None):
232 def __init__(self, data=None, url=None, filename=None):
233 """Create a display object given raw data.
233 """Create a display object given raw data.
234
234
235 When this object is returned by an expression or passed to the
235 When this object is returned by an expression or passed to the
236 display function, it will result in the data being displayed
236 display function, it will result in the data being displayed
237 in the frontend. The MIME type of the data should match the
237 in the frontend. The MIME type of the data should match the
238 subclasses used, so the Png subclass should be used for 'image/png'
238 subclasses used, so the Png subclass should be used for 'image/png'
239 data. If the data is a URL, the data will first be downloaded
239 data. If the data is a URL, the data will first be downloaded
240 and then displayed. If
240 and then displayed. If
241
241
242 Parameters
242 Parameters
243 ----------
243 ----------
244 data : unicode, str or bytes
244 data : unicode, str or bytes
245 The raw data or a URL to download the data from.
245 The raw data or a URL to download the data from.
246 url : unicode
246 url : unicode
247 A URL to download the data from.
247 A URL to download the data from.
248 filename : unicode
248 filename : unicode
249 Path to a local file to load the data from.
249 Path to a local file to load the data from.
250 """
250 """
251 if data is not None and data.startswith('http'):
251 if data is not None and data.startswith('http'):
252 self.url = data
252 self.url = data
253 self.filename = None
253 self.filename = None
254 self.data = None
254 self.data = None
255 else:
255 else:
256 self.data = data
256 self.data = data
257 self.url = url
257 self.url = url
258 self.filename = None if filename is None else unicode(filename)
258 self.filename = None if filename is None else unicode(filename)
259 self.reload()
259 self.reload()
260
260
261 def reload(self):
261 def reload(self):
262 """Reload the raw data from file or URL."""
262 """Reload the raw data from file or URL."""
263 if self.filename is not None:
263 if self.filename is not None:
264 with open(self.filename, self._read_flags) as f:
264 with open(self.filename, self._read_flags) as f:
265 self.data = f.read()
265 self.data = f.read()
266 elif self.url is not None:
266 elif self.url is not None:
267 try:
267 try:
268 import urllib2
268 import urllib2
269 response = urllib2.urlopen(self.url)
269 response = urllib2.urlopen(self.url)
270 self.data = response.read()
270 self.data = response.read()
271 # extract encoding from header, if there is one:
271 # extract encoding from header, if there is one:
272 encoding = None
272 encoding = None
273 for sub in response.headers['content-type'].split(';'):
273 for sub in response.headers['content-type'].split(';'):
274 sub = sub.strip()
274 sub = sub.strip()
275 if sub.startswith('charset'):
275 if sub.startswith('charset'):
276 encoding = sub.split('=')[-1].strip()
276 encoding = sub.split('=')[-1].strip()
277 break
277 break
278 # decode data, if an encoding was specified
278 # decode data, if an encoding was specified
279 if encoding:
279 if encoding:
280 self.data = self.data.decode(encoding, 'replace')
280 self.data = self.data.decode(encoding, 'replace')
281 except:
281 except:
282 self.data = None
282 self.data = None
283
283
284 class Pretty(DisplayObject):
284 class Pretty(DisplayObject):
285
285
286 def _repr_pretty_(self):
286 def _repr_pretty_(self):
287 return self.data
287 return self.data
288
288
289
289
290 class HTML(DisplayObject):
290 class HTML(DisplayObject):
291
291
292 def _repr_html_(self):
292 def _repr_html_(self):
293 return self.data
293 return self.data
294
294
295
295
296 class Math(DisplayObject):
296 class Math(DisplayObject):
297
297
298 def _repr_latex_(self):
298 def _repr_latex_(self):
299 return self.data
299 return self.data
300
300
301
301
302 class SVG(DisplayObject):
302 class SVG(DisplayObject):
303
303
304 def _repr_svg_(self):
304 def _repr_svg_(self):
305 return self.data
305 return self.data
306
306
307
307
308 class JSON(DisplayObject):
308 class JSON(DisplayObject):
309
309
310 def _repr_json_(self):
310 def _repr_json_(self):
311 return self.data
311 return self.data
312
312
313
313
314 class Javascript(DisplayObject):
314 class Javascript(DisplayObject):
315
315
316 def _repr_javascript_(self):
316 def _repr_javascript_(self):
317 return self.data
317 return self.data
318
318
319
319
320 class Image(DisplayObject):
320 class Image(DisplayObject):
321
321
322 _read_flags = 'rb'
322 _read_flags = 'rb'
323
323
324 def __init__(self, data=None, url=None, filename=None, format=u'png', embed=False):
324 def __init__(self, data=None, url=None, filename=None, format=u'png', embed=False):
325 """Create a display an PNG/JPEG image given raw data.
325 """Create a display an PNG/JPEG image given raw data.
326
326
327 When this object is returned by an expression or passed to the
327 When this object is returned by an expression or passed to the
328 display function, it will result in the image being displayed
328 display function, it will result in the image being displayed
329 in the frontend.
329 in the frontend.
330
330
331 Parameters
331 Parameters
332 ----------
332 ----------
333 data : unicode, str or bytes
333 data : unicode, str or bytes
334 The raw data or a URL to download the data from.
334 The raw data or a URL to download the data from.
335 url : unicode
335 url : unicode
336 A URL to download the data from.
336 A URL to download the data from.
337 filename : unicode
337 filename : unicode
338 Path to a local file to load the data from.
338 Path to a local file to load the data from.
339 format : unicode
339 format : unicode
340 The format of the image data (png/jpeg/jpg). If a filename or URL is given
340 The format of the image data (png/jpeg/jpg). If a filename or URL is given
341 for format will be inferred from the filename extension.
341 for format will be inferred from the filename extension.
342 embed : bool
342 embed : bool
343 Should the image data be embedded in the notebook using a data URI (True)
343 Should the image data be embedded in the notebook using a data URI (True)
344 or be loaded using an <img> tag. Set this to True if you want the image
344 or be loaded using an <img> tag. Set this to True if you want the image
345 to be viewable later with no internet connection. If a filename is given
345 to be viewable later with no internet connection. If a filename is given
346 embed is always set to True.
346 embed is always set to True.
347 """
347 """
348 if filename is not None:
348 if filename is not None:
349 ext = self._find_ext(filename)
349 ext = self._find_ext(filename)
350 elif url is not None:
350 elif url is not None:
351 ext = self._find_ext(url)
351 ext = self._find_ext(url)
352 elif data.startswith('http'):
352 elif data.startswith('http'):
353 ext = self._find_ext(data)
353 ext = self._find_ext(data)
354 else:
354 else:
355 ext = None
355 ext = None
356 if ext is not None:
356 if ext is not None:
357 if ext == u'jpg' or ext == u'jpeg':
357 if ext == u'jpg' or ext == u'jpeg':
358 format = u'jpeg'
358 format = u'jpeg'
359 if ext == u'png':
359 if ext == u'png':
360 format = u'png'
360 format = u'png'
361 self.format = unicode(format).lower()
361 self.format = unicode(format).lower()
362 self.embed = True if filename is not None else embed
362 self.embed = True if filename is not None else embed
363 super(Image, self).__init__(data=data, url=url, filename=filename)
363 super(Image, self).__init__(data=data, url=url, filename=filename)
364
364
365 def reload(self):
365 def reload(self):
366 """Reload the raw data from file or URL."""
366 """Reload the raw data from file or URL."""
367 if self.embed:
367 if self.embed:
368 super(Image,self).reload()
368 super(Image,self).reload()
369
369
370 def _repr_html_(self):
370 def _repr_html_(self):
371 if not self.embed:
371 if not self.embed:
372 return u'<img src="%s" />' % self.url
372 return u'<img src="%s" />' % self.url
373
373
374 def _repr_png_(self):
374 def _repr_png_(self):
375 if self.embed and self.format == u'png':
375 if self.embed and self.format == u'png':
376 return self.data
376 return self.data
377
377
378 def _repr_jpeg_(self):
378 def _repr_jpeg_(self):
379 if self.embed and (self.format == u'jpeg' or self.format == u'jpg'):
379 if self.embed and (self.format == u'jpeg' or self.format == u'jpg'):
380 return self.data
380 return self.data
381
381
382 def _find_ext(self, s):
382 def _find_ext(self, s):
383 return unicode(s.split('.')[-1].lower())
383 return unicode(s.split('.')[-1].lower())
384
384
385
385
386 def clear_output(stdout=True, stderr=True, other=True):
386 def clear_output(stdout=True, stderr=True, other=True):
387 """Clear the output of the current cell receiving output.
387 """Clear the output of the current cell receiving output.
388
388
389 Optionally, each of stdout/stderr or other non-stream data (e.g. anything
389 Optionally, each of stdout/stderr or other non-stream data (e.g. anything
390 produced by display()) can be excluded from the clear event.
390 produced by display()) can be excluded from the clear event.
391
391
392 By default, everything is cleared.
392 By default, everything is cleared.
393
393
394 Parameters
394 Parameters
395 ----------
395 ----------
396 stdout : bool [default: True]
396 stdout : bool [default: True]
397 Whether to clear stdout.
397 Whether to clear stdout.
398 stderr : bool [default: True]
398 stderr : bool [default: True]
399 Whether to clear stderr.
399 Whether to clear stderr.
400 other : bool [default: True]
400 other : bool [default: True]
401 Whether to clear everything else that is not stdout/stderr
401 Whether to clear everything else that is not stdout/stderr
402 (e.g. figures,images,HTML, any result of display()).
402 (e.g. figures,images,HTML, any result of display()).
403 """
403 """
404 from IPython.core.interactiveshell import InteractiveShell
404 from IPython.core.interactiveshell import InteractiveShell
405 InteractiveShell.instance().display_pub.clear_output(
405 InteractiveShell.instance().display_pub.clear_output(
406 stdout=stdout, stderr=stderr, other=other,
406 stdout=stdout, stderr=stderr, other=other,
407 )
407 )
@@ -1,70 +1,70 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 A context manager for handling sys.displayhook.
3 A context manager for handling sys.displayhook.
4
4
5 Authors:
5 Authors:
6
6
7 * Robert Kern
7 * Robert Kern
8 * Brian Granger
8 * Brian Granger
9 """
9 """
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Copyright (C) 2008-2009 The IPython Development Team
12 # Copyright (C) 2008-2011 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 import sys
22 import sys
23
23
24 from IPython.config.configurable import Configurable
24 from IPython.config.configurable import Configurable
25 from IPython.utils.traitlets import Any
25 from IPython.utils.traitlets import Any
26
26
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28 # Classes and functions
28 # Classes and functions
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30
30
31
31
32 class DisplayTrap(Configurable):
32 class DisplayTrap(Configurable):
33 """Object to manage sys.displayhook.
33 """Object to manage sys.displayhook.
34
34
35 This came from IPython.core.kernel.display_hook, but is simplified
35 This came from IPython.core.kernel.display_hook, but is simplified
36 (no callbacks or formatters) until more of the core is refactored.
36 (no callbacks or formatters) until more of the core is refactored.
37 """
37 """
38
38
39 hook = Any
39 hook = Any
40
40
41 def __init__(self, hook=None):
41 def __init__(self, hook=None):
42 super(DisplayTrap, self).__init__(hook=hook, config=None)
42 super(DisplayTrap, self).__init__(hook=hook, config=None)
43 self.old_hook = None
43 self.old_hook = None
44 # We define this to track if a single BuiltinTrap is nested.
44 # We define this to track if a single BuiltinTrap is nested.
45 # Only turn off the trap when the outermost call to __exit__ is made.
45 # Only turn off the trap when the outermost call to __exit__ is made.
46 self._nested_level = 0
46 self._nested_level = 0
47
47
48 def __enter__(self):
48 def __enter__(self):
49 if self._nested_level == 0:
49 if self._nested_level == 0:
50 self.set()
50 self.set()
51 self._nested_level += 1
51 self._nested_level += 1
52 return self
52 return self
53
53
54 def __exit__(self, type, value, traceback):
54 def __exit__(self, type, value, traceback):
55 if self._nested_level == 1:
55 if self._nested_level == 1:
56 self.unset()
56 self.unset()
57 self._nested_level -= 1
57 self._nested_level -= 1
58 # Returning False will cause exceptions to propagate
58 # Returning False will cause exceptions to propagate
59 return False
59 return False
60
60
61 def set(self):
61 def set(self):
62 """Set the hook."""
62 """Set the hook."""
63 if sys.displayhook is not self.hook:
63 if sys.displayhook is not self.hook:
64 self.old_hook = sys.displayhook
64 self.old_hook = sys.displayhook
65 sys.displayhook = self.hook
65 sys.displayhook = self.hook
66
66
67 def unset(self):
67 def unset(self):
68 """Unset the hook."""
68 """Unset the hook."""
69 sys.displayhook = self.old_hook
69 sys.displayhook = self.old_hook
70
70
@@ -1,329 +1,329 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Displayhook for IPython.
2 """Displayhook for IPython.
3
3
4 This defines a callable class that IPython uses for `sys.displayhook`.
4 This defines a callable class that IPython uses for `sys.displayhook`.
5
5
6 Authors:
6 Authors:
7
7
8 * Fernando Perez
8 * Fernando Perez
9 * Brian Granger
9 * Brian Granger
10 * Robert Kern
10 * Robert Kern
11 """
11 """
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Copyright (C) 2008-2010 The IPython Development Team
14 # Copyright (C) 2008-2011 The IPython Development Team
15 # Copyright (C) 2001-2007 Fernando Perez <fperez@colorado.edu>
15 # Copyright (C) 2001-2007 Fernando Perez <fperez@colorado.edu>
16 #
16 #
17 # Distributed under the terms of the BSD License. The full license is in
17 # Distributed under the terms of the BSD License. The full license is in
18 # the file COPYING, distributed as part of this software.
18 # the file COPYING, distributed as part of this software.
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20
20
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 # Imports
22 # Imports
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24
24
25 import __builtin__
25 import __builtin__
26
26
27 from IPython.config.configurable import Configurable
27 from IPython.config.configurable import Configurable
28 from IPython.core import prompts
28 from IPython.core import prompts
29 from IPython.utils import io
29 from IPython.utils import io
30 from IPython.utils.traitlets import Instance, List
30 from IPython.utils.traitlets import Instance, List
31 from IPython.utils.warn import warn
31 from IPython.utils.warn import warn
32
32
33 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
34 # Main displayhook class
34 # Main displayhook class
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36
36
37 # TODO: The DisplayHook class should be split into two classes, one that
37 # TODO: The DisplayHook class should be split into two classes, one that
38 # manages the prompts and their synchronization and another that just does the
38 # manages the prompts and their synchronization and another that just does the
39 # displayhook logic and calls into the prompt manager.
39 # displayhook logic and calls into the prompt manager.
40
40
41 # TODO: Move the various attributes (cache_size, colors, input_sep,
41 # TODO: Move the various attributes (cache_size, colors, input_sep,
42 # output_sep, output_sep2, ps1, ps2, ps_out, pad_left). Some of these are also
42 # output_sep, output_sep2, ps1, ps2, ps_out, pad_left). Some of these are also
43 # attributes of InteractiveShell. They should be on ONE object only and the
43 # attributes of InteractiveShell. They should be on ONE object only and the
44 # other objects should ask that one object for their values.
44 # other objects should ask that one object for their values.
45
45
46 class DisplayHook(Configurable):
46 class DisplayHook(Configurable):
47 """The custom IPython displayhook to replace sys.displayhook.
47 """The custom IPython displayhook to replace sys.displayhook.
48
48
49 This class does many things, but the basic idea is that it is a callable
49 This class does many things, but the basic idea is that it is a callable
50 that gets called anytime user code returns a value.
50 that gets called anytime user code returns a value.
51
51
52 Currently this class does more than just the displayhook logic and that
52 Currently this class does more than just the displayhook logic and that
53 extra logic should eventually be moved out of here.
53 extra logic should eventually be moved out of here.
54 """
54 """
55
55
56 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
56 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
57
57
58 def __init__(self, shell=None, cache_size=1000,
58 def __init__(self, shell=None, cache_size=1000,
59 colors='NoColor', input_sep='\n',
59 colors='NoColor', input_sep='\n',
60 output_sep='\n', output_sep2='',
60 output_sep='\n', output_sep2='',
61 ps1 = None, ps2 = None, ps_out = None, pad_left=True,
61 ps1 = None, ps2 = None, ps_out = None, pad_left=True,
62 config=None):
62 config=None):
63 super(DisplayHook, self).__init__(shell=shell, config=config)
63 super(DisplayHook, self).__init__(shell=shell, config=config)
64
64
65 cache_size_min = 3
65 cache_size_min = 3
66 if cache_size <= 0:
66 if cache_size <= 0:
67 self.do_full_cache = 0
67 self.do_full_cache = 0
68 cache_size = 0
68 cache_size = 0
69 elif cache_size < cache_size_min:
69 elif cache_size < cache_size_min:
70 self.do_full_cache = 0
70 self.do_full_cache = 0
71 cache_size = 0
71 cache_size = 0
72 warn('caching was disabled (min value for cache size is %s).' %
72 warn('caching was disabled (min value for cache size is %s).' %
73 cache_size_min,level=3)
73 cache_size_min,level=3)
74 else:
74 else:
75 self.do_full_cache = 1
75 self.do_full_cache = 1
76
76
77 self.cache_size = cache_size
77 self.cache_size = cache_size
78 self.input_sep = input_sep
78 self.input_sep = input_sep
79
79
80 # we need a reference to the user-level namespace
80 # we need a reference to the user-level namespace
81 self.shell = shell
81 self.shell = shell
82
82
83 # Set input prompt strings and colors
83 # Set input prompt strings and colors
84 if cache_size == 0:
84 if cache_size == 0:
85 if ps1.find('%n') > -1 or ps1.find(r'\#') > -1 \
85 if ps1.find('%n') > -1 or ps1.find(r'\#') > -1 \
86 or ps1.find(r'\N') > -1:
86 or ps1.find(r'\N') > -1:
87 ps1 = '>>> '
87 ps1 = '>>> '
88 if ps2.find('%n') > -1 or ps2.find(r'\#') > -1 \
88 if ps2.find('%n') > -1 or ps2.find(r'\#') > -1 \
89 or ps2.find(r'\N') > -1:
89 or ps2.find(r'\N') > -1:
90 ps2 = '... '
90 ps2 = '... '
91 self.ps1_str = self._set_prompt_str(ps1,'In [\\#]: ','>>> ')
91 self.ps1_str = self._set_prompt_str(ps1,'In [\\#]: ','>>> ')
92 self.ps2_str = self._set_prompt_str(ps2,' .\\D.: ','... ')
92 self.ps2_str = self._set_prompt_str(ps2,' .\\D.: ','... ')
93 self.ps_out_str = self._set_prompt_str(ps_out,'Out[\\#]: ','')
93 self.ps_out_str = self._set_prompt_str(ps_out,'Out[\\#]: ','')
94
94
95 self.color_table = prompts.PromptColors
95 self.color_table = prompts.PromptColors
96 self.prompt1 = prompts.Prompt1(self,sep=input_sep,prompt=self.ps1_str,
96 self.prompt1 = prompts.Prompt1(self,sep=input_sep,prompt=self.ps1_str,
97 pad_left=pad_left)
97 pad_left=pad_left)
98 self.prompt2 = prompts.Prompt2(self,prompt=self.ps2_str,pad_left=pad_left)
98 self.prompt2 = prompts.Prompt2(self,prompt=self.ps2_str,pad_left=pad_left)
99 self.prompt_out = prompts.PromptOut(self,sep='',prompt=self.ps_out_str,
99 self.prompt_out = prompts.PromptOut(self,sep='',prompt=self.ps_out_str,
100 pad_left=pad_left)
100 pad_left=pad_left)
101 self.set_colors(colors)
101 self.set_colors(colors)
102
102
103 # Store the last prompt string each time, we need it for aligning
103 # Store the last prompt string each time, we need it for aligning
104 # continuation and auto-rewrite prompts
104 # continuation and auto-rewrite prompts
105 self.last_prompt = ''
105 self.last_prompt = ''
106 self.output_sep = output_sep
106 self.output_sep = output_sep
107 self.output_sep2 = output_sep2
107 self.output_sep2 = output_sep2
108 self._,self.__,self.___ = '','',''
108 self._,self.__,self.___ = '','',''
109
109
110 # these are deliberately global:
110 # these are deliberately global:
111 to_user_ns = {'_':self._,'__':self.__,'___':self.___}
111 to_user_ns = {'_':self._,'__':self.__,'___':self.___}
112 self.shell.user_ns.update(to_user_ns)
112 self.shell.user_ns.update(to_user_ns)
113
113
114 @property
114 @property
115 def prompt_count(self):
115 def prompt_count(self):
116 return self.shell.execution_count
116 return self.shell.execution_count
117
117
118 def _set_prompt_str(self,p_str,cache_def,no_cache_def):
118 def _set_prompt_str(self,p_str,cache_def,no_cache_def):
119 if p_str is None:
119 if p_str is None:
120 if self.do_full_cache:
120 if self.do_full_cache:
121 return cache_def
121 return cache_def
122 else:
122 else:
123 return no_cache_def
123 return no_cache_def
124 else:
124 else:
125 return p_str
125 return p_str
126
126
127 def set_colors(self, colors):
127 def set_colors(self, colors):
128 """Set the active color scheme and configure colors for the three
128 """Set the active color scheme and configure colors for the three
129 prompt subsystems."""
129 prompt subsystems."""
130
130
131 # FIXME: This modifying of the global prompts.prompt_specials needs
131 # FIXME: This modifying of the global prompts.prompt_specials needs
132 # to be fixed. We need to refactor all of the prompts stuff to use
132 # to be fixed. We need to refactor all of the prompts stuff to use
133 # proper configuration and traits notifications.
133 # proper configuration and traits notifications.
134 if colors.lower()=='nocolor':
134 if colors.lower()=='nocolor':
135 prompts.prompt_specials = prompts.prompt_specials_nocolor
135 prompts.prompt_specials = prompts.prompt_specials_nocolor
136 else:
136 else:
137 prompts.prompt_specials = prompts.prompt_specials_color
137 prompts.prompt_specials = prompts.prompt_specials_color
138
138
139 self.color_table.set_active_scheme(colors)
139 self.color_table.set_active_scheme(colors)
140 self.prompt1.set_colors()
140 self.prompt1.set_colors()
141 self.prompt2.set_colors()
141 self.prompt2.set_colors()
142 self.prompt_out.set_colors()
142 self.prompt_out.set_colors()
143
143
144 #-------------------------------------------------------------------------
144 #-------------------------------------------------------------------------
145 # Methods used in __call__. Override these methods to modify the behavior
145 # Methods used in __call__. Override these methods to modify the behavior
146 # of the displayhook.
146 # of the displayhook.
147 #-------------------------------------------------------------------------
147 #-------------------------------------------------------------------------
148
148
149 def check_for_underscore(self):
149 def check_for_underscore(self):
150 """Check if the user has set the '_' variable by hand."""
150 """Check if the user has set the '_' variable by hand."""
151 # If something injected a '_' variable in __builtin__, delete
151 # If something injected a '_' variable in __builtin__, delete
152 # ipython's automatic one so we don't clobber that. gettext() in
152 # ipython's automatic one so we don't clobber that. gettext() in
153 # particular uses _, so we need to stay away from it.
153 # particular uses _, so we need to stay away from it.
154 if '_' in __builtin__.__dict__:
154 if '_' in __builtin__.__dict__:
155 try:
155 try:
156 del self.shell.user_ns['_']
156 del self.shell.user_ns['_']
157 except KeyError:
157 except KeyError:
158 pass
158 pass
159
159
160 def quiet(self):
160 def quiet(self):
161 """Should we silence the display hook because of ';'?"""
161 """Should we silence the display hook because of ';'?"""
162 # do not print output if input ends in ';'
162 # do not print output if input ends in ';'
163 try:
163 try:
164 cell = self.shell.history_manager.input_hist_parsed[self.prompt_count]
164 cell = self.shell.history_manager.input_hist_parsed[self.prompt_count]
165 if cell.rstrip().endswith(';'):
165 if cell.rstrip().endswith(';'):
166 return True
166 return True
167 except IndexError:
167 except IndexError:
168 # some uses of ipshellembed may fail here
168 # some uses of ipshellembed may fail here
169 pass
169 pass
170 return False
170 return False
171
171
172 def start_displayhook(self):
172 def start_displayhook(self):
173 """Start the displayhook, initializing resources."""
173 """Start the displayhook, initializing resources."""
174 pass
174 pass
175
175
176 def write_output_prompt(self):
176 def write_output_prompt(self):
177 """Write the output prompt.
177 """Write the output prompt.
178
178
179 The default implementation simply writes the prompt to
179 The default implementation simply writes the prompt to
180 ``io.stdout``.
180 ``io.stdout``.
181 """
181 """
182 # Use write, not print which adds an extra space.
182 # Use write, not print which adds an extra space.
183 io.stdout.write(self.output_sep)
183 io.stdout.write(self.output_sep)
184 outprompt = str(self.prompt_out)
184 outprompt = str(self.prompt_out)
185 if self.do_full_cache:
185 if self.do_full_cache:
186 io.stdout.write(outprompt)
186 io.stdout.write(outprompt)
187
187
188 def compute_format_data(self, result):
188 def compute_format_data(self, result):
189 """Compute format data of the object to be displayed.
189 """Compute format data of the object to be displayed.
190
190
191 The format data is a generalization of the :func:`repr` of an object.
191 The format data is a generalization of the :func:`repr` of an object.
192 In the default implementation the format data is a :class:`dict` of
192 In the default implementation the format data is a :class:`dict` of
193 key value pair where the keys are valid MIME types and the values
193 key value pair where the keys are valid MIME types and the values
194 are JSON'able data structure containing the raw data for that MIME
194 are JSON'able data structure containing the raw data for that MIME
195 type. It is up to frontends to determine pick a MIME to to use and
195 type. It is up to frontends to determine pick a MIME to to use and
196 display that data in an appropriate manner.
196 display that data in an appropriate manner.
197
197
198 This method only computes the format data for the object and should
198 This method only computes the format data for the object and should
199 NOT actually print or write that to a stream.
199 NOT actually print or write that to a stream.
200
200
201 Parameters
201 Parameters
202 ----------
202 ----------
203 result : object
203 result : object
204 The Python object passed to the display hook, whose format will be
204 The Python object passed to the display hook, whose format will be
205 computed.
205 computed.
206
206
207 Returns
207 Returns
208 -------
208 -------
209 format_data : dict
209 format_data : dict
210 A :class:`dict` whose keys are valid MIME types and values are
210 A :class:`dict` whose keys are valid MIME types and values are
211 JSON'able raw data for that MIME type. It is recommended that
211 JSON'able raw data for that MIME type. It is recommended that
212 all return values of this should always include the "text/plain"
212 all return values of this should always include the "text/plain"
213 MIME type representation of the object.
213 MIME type representation of the object.
214 """
214 """
215 return self.shell.display_formatter.format(result)
215 return self.shell.display_formatter.format(result)
216
216
217 def write_format_data(self, format_dict):
217 def write_format_data(self, format_dict):
218 """Write the format data dict to the frontend.
218 """Write the format data dict to the frontend.
219
219
220 This default version of this method simply writes the plain text
220 This default version of this method simply writes the plain text
221 representation of the object to ``io.stdout``. Subclasses should
221 representation of the object to ``io.stdout``. Subclasses should
222 override this method to send the entire `format_dict` to the
222 override this method to send the entire `format_dict` to the
223 frontends.
223 frontends.
224
224
225 Parameters
225 Parameters
226 ----------
226 ----------
227 format_dict : dict
227 format_dict : dict
228 The format dict for the object passed to `sys.displayhook`.
228 The format dict for the object passed to `sys.displayhook`.
229 """
229 """
230 # We want to print because we want to always make sure we have a
230 # We want to print because we want to always make sure we have a
231 # newline, even if all the prompt separators are ''. This is the
231 # newline, even if all the prompt separators are ''. This is the
232 # standard IPython behavior.
232 # standard IPython behavior.
233 result_repr = format_dict['text/plain']
233 result_repr = format_dict['text/plain']
234 if '\n' in result_repr:
234 if '\n' in result_repr:
235 # So that multi-line strings line up with the left column of
235 # So that multi-line strings line up with the left column of
236 # the screen, instead of having the output prompt mess up
236 # the screen, instead of having the output prompt mess up
237 # their first line.
237 # their first line.
238 # We use the ps_out_str template instead of the expanded prompt
238 # We use the ps_out_str template instead of the expanded prompt
239 # because the expansion may add ANSI escapes that will interfere
239 # because the expansion may add ANSI escapes that will interfere
240 # with our ability to determine whether or not we should add
240 # with our ability to determine whether or not we should add
241 # a newline.
241 # a newline.
242 if self.ps_out_str and not self.ps_out_str.endswith('\n'):
242 if self.ps_out_str and not self.ps_out_str.endswith('\n'):
243 # But avoid extraneous empty lines.
243 # But avoid extraneous empty lines.
244 result_repr = '\n' + result_repr
244 result_repr = '\n' + result_repr
245
245
246 print >>io.stdout, result_repr
246 print >>io.stdout, result_repr
247
247
248 def update_user_ns(self, result):
248 def update_user_ns(self, result):
249 """Update user_ns with various things like _, __, _1, etc."""
249 """Update user_ns with various things like _, __, _1, etc."""
250
250
251 # Avoid recursive reference when displaying _oh/Out
251 # Avoid recursive reference when displaying _oh/Out
252 if result is not self.shell.user_ns['_oh']:
252 if result is not self.shell.user_ns['_oh']:
253 if len(self.shell.user_ns['_oh']) >= self.cache_size and self.do_full_cache:
253 if len(self.shell.user_ns['_oh']) >= self.cache_size and self.do_full_cache:
254 warn('Output cache limit (currently '+
254 warn('Output cache limit (currently '+
255 `self.cache_size`+' entries) hit.\n'
255 `self.cache_size`+' entries) hit.\n'
256 'Flushing cache and resetting history counter...\n'
256 'Flushing cache and resetting history counter...\n'
257 'The only history variables available will be _,__,___ and _1\n'
257 'The only history variables available will be _,__,___ and _1\n'
258 'with the current result.')
258 'with the current result.')
259
259
260 self.flush()
260 self.flush()
261 # Don't overwrite '_' and friends if '_' is in __builtin__ (otherwise
261 # Don't overwrite '_' and friends if '_' is in __builtin__ (otherwise
262 # we cause buggy behavior for things like gettext).
262 # we cause buggy behavior for things like gettext).
263
263
264 if '_' not in __builtin__.__dict__:
264 if '_' not in __builtin__.__dict__:
265 self.___ = self.__
265 self.___ = self.__
266 self.__ = self._
266 self.__ = self._
267 self._ = result
267 self._ = result
268 self.shell.user_ns.update({'_':self._,
268 self.shell.user_ns.update({'_':self._,
269 '__':self.__,
269 '__':self.__,
270 '___':self.___})
270 '___':self.___})
271
271
272 # hackish access to top-level namespace to create _1,_2... dynamically
272 # hackish access to top-level namespace to create _1,_2... dynamically
273 to_main = {}
273 to_main = {}
274 if self.do_full_cache:
274 if self.do_full_cache:
275 new_result = '_'+`self.prompt_count`
275 new_result = '_'+`self.prompt_count`
276 to_main[new_result] = result
276 to_main[new_result] = result
277 self.shell.user_ns.update(to_main)
277 self.shell.user_ns.update(to_main)
278 self.shell.user_ns['_oh'][self.prompt_count] = result
278 self.shell.user_ns['_oh'][self.prompt_count] = result
279
279
280 def log_output(self, format_dict):
280 def log_output(self, format_dict):
281 """Log the output."""
281 """Log the output."""
282 if self.shell.logger.log_output:
282 if self.shell.logger.log_output:
283 self.shell.logger.log_write(format_dict['text/plain'], 'output')
283 self.shell.logger.log_write(format_dict['text/plain'], 'output')
284 self.shell.history_manager.output_hist_reprs[self.prompt_count] = \
284 self.shell.history_manager.output_hist_reprs[self.prompt_count] = \
285 format_dict['text/plain']
285 format_dict['text/plain']
286
286
287 def finish_displayhook(self):
287 def finish_displayhook(self):
288 """Finish up all displayhook activities."""
288 """Finish up all displayhook activities."""
289 io.stdout.write(self.output_sep2)
289 io.stdout.write(self.output_sep2)
290 io.stdout.flush()
290 io.stdout.flush()
291
291
292 def __call__(self, result=None):
292 def __call__(self, result=None):
293 """Printing with history cache management.
293 """Printing with history cache management.
294
294
295 This is invoked everytime the interpreter needs to print, and is
295 This is invoked everytime the interpreter needs to print, and is
296 activated by setting the variable sys.displayhook to it.
296 activated by setting the variable sys.displayhook to it.
297 """
297 """
298 self.check_for_underscore()
298 self.check_for_underscore()
299 if result is not None and not self.quiet():
299 if result is not None and not self.quiet():
300 self.start_displayhook()
300 self.start_displayhook()
301 self.write_output_prompt()
301 self.write_output_prompt()
302 format_dict = self.compute_format_data(result)
302 format_dict = self.compute_format_data(result)
303 self.write_format_data(format_dict)
303 self.write_format_data(format_dict)
304 self.update_user_ns(result)
304 self.update_user_ns(result)
305 self.log_output(format_dict)
305 self.log_output(format_dict)
306 self.finish_displayhook()
306 self.finish_displayhook()
307
307
308 def flush(self):
308 def flush(self):
309 if not self.do_full_cache:
309 if not self.do_full_cache:
310 raise ValueError,"You shouldn't have reached the cache flush "\
310 raise ValueError,"You shouldn't have reached the cache flush "\
311 "if full caching is not enabled!"
311 "if full caching is not enabled!"
312 # delete auto-generated vars from global namespace
312 # delete auto-generated vars from global namespace
313
313
314 for n in range(1,self.prompt_count + 1):
314 for n in range(1,self.prompt_count + 1):
315 key = '_'+`n`
315 key = '_'+`n`
316 try:
316 try:
317 del self.shell.user_ns[key]
317 del self.shell.user_ns[key]
318 except: pass
318 except: pass
319 self.shell.user_ns['_oh'].clear()
319 self.shell.user_ns['_oh'].clear()
320
320
321 # Release our own references to objects:
321 # Release our own references to objects:
322 self._, self.__, self.___ = '', '', ''
322 self._, self.__, self.___ = '', '', ''
323
323
324 if '_' not in __builtin__.__dict__:
324 if '_' not in __builtin__.__dict__:
325 self.shell.user_ns.update({'_':None,'__':None, '___':None})
325 self.shell.user_ns.update({'_':None,'__':None, '___':None})
326 import gc
326 import gc
327 # TODO: Is this really needed?
327 # TODO: Is this really needed?
328 gc.collect()
328 gc.collect()
329
329
@@ -1,302 +1,302 b''
1 """An interface for publishing rich data to frontends.
1 """An interface for publishing rich data to frontends.
2
2
3 There are two components of the display system:
3 There are two components of the display system:
4
4
5 * Display formatters, which take a Python object and compute the
5 * Display formatters, which take a Python object and compute the
6 representation of the object in various formats (text, HTML, SVg, etc.).
6 representation of the object in various formats (text, HTML, SVg, etc.).
7 * The display publisher that is used to send the representation data to the
7 * The display publisher that is used to send the representation data to the
8 various frontends.
8 various frontends.
9
9
10 This module defines the logic display publishing. The display publisher uses
10 This module defines the logic display publishing. The display publisher uses
11 the ``display_data`` message type that is defined in the IPython messaging
11 the ``display_data`` message type that is defined in the IPython messaging
12 spec.
12 spec.
13
13
14 Authors:
14 Authors:
15
15
16 * Brian Granger
16 * Brian Granger
17 """
17 """
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Copyright (C) 2008-2010 The IPython Development Team
20 # Copyright (C) 2008-2011 The IPython Development Team
21 #
21 #
22 # Distributed under the terms of the BSD License. The full license is in
22 # Distributed under the terms of the BSD License. The full license is in
23 # the file COPYING, distributed as part of this software.
23 # the file COPYING, distributed as part of this software.
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 # Imports
27 # Imports
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29
29
30 from __future__ import print_function
30 from __future__ import print_function
31
31
32 from IPython.config.configurable import Configurable
32 from IPython.config.configurable import Configurable
33
33
34 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
35 # Main payload class
35 # Main payload class
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37
37
38 class DisplayPublisher(Configurable):
38 class DisplayPublisher(Configurable):
39 """A traited class that publishes display data to frontends.
39 """A traited class that publishes display data to frontends.
40
40
41 Instances of this class are created by the main IPython object and should
41 Instances of this class are created by the main IPython object and should
42 be accessed there.
42 be accessed there.
43 """
43 """
44
44
45 def _validate_data(self, source, data, metadata=None):
45 def _validate_data(self, source, data, metadata=None):
46 """Validate the display data.
46 """Validate the display data.
47
47
48 Parameters
48 Parameters
49 ----------
49 ----------
50 source : str
50 source : str
51 The fully dotted name of the callable that created the data, like
51 The fully dotted name of the callable that created the data, like
52 :func:`foo.bar.my_formatter`.
52 :func:`foo.bar.my_formatter`.
53 data : dict
53 data : dict
54 The formata data dictionary.
54 The formata data dictionary.
55 metadata : dict
55 metadata : dict
56 Any metadata for the data.
56 Any metadata for the data.
57 """
57 """
58
58
59 if not isinstance(source, basestring):
59 if not isinstance(source, basestring):
60 raise TypeError('source must be a str, got: %r' % source)
60 raise TypeError('source must be a str, got: %r' % source)
61 if not isinstance(data, dict):
61 if not isinstance(data, dict):
62 raise TypeError('data must be a dict, got: %r' % data)
62 raise TypeError('data must be a dict, got: %r' % data)
63 if metadata is not None:
63 if metadata is not None:
64 if not isinstance(metadata, dict):
64 if not isinstance(metadata, dict):
65 raise TypeError('metadata must be a dict, got: %r' % data)
65 raise TypeError('metadata must be a dict, got: %r' % data)
66
66
67 def publish(self, source, data, metadata=None):
67 def publish(self, source, data, metadata=None):
68 """Publish data and metadata to all frontends.
68 """Publish data and metadata to all frontends.
69
69
70 See the ``display_data`` message in the messaging documentation for
70 See the ``display_data`` message in the messaging documentation for
71 more details about this message type.
71 more details about this message type.
72
72
73 The following MIME types are currently implemented:
73 The following MIME types are currently implemented:
74
74
75 * text/plain
75 * text/plain
76 * text/html
76 * text/html
77 * text/latex
77 * text/latex
78 * application/json
78 * application/json
79 * application/javascript
79 * application/javascript
80 * image/png
80 * image/png
81 * image/jpeg
81 * image/jpeg
82 * image/svg+xml
82 * image/svg+xml
83
83
84 Parameters
84 Parameters
85 ----------
85 ----------
86 source : str
86 source : str
87 A string that give the function or method that created the data,
87 A string that give the function or method that created the data,
88 such as 'IPython.core.page'.
88 such as 'IPython.core.page'.
89 data : dict
89 data : dict
90 A dictionary having keys that are valid MIME types (like
90 A dictionary having keys that are valid MIME types (like
91 'text/plain' or 'image/svg+xml') and values that are the data for
91 'text/plain' or 'image/svg+xml') and values that are the data for
92 that MIME type. The data itself must be a JSON'able data
92 that MIME type. The data itself must be a JSON'able data
93 structure. Minimally all data should have the 'text/plain' data,
93 structure. Minimally all data should have the 'text/plain' data,
94 which can be displayed by all frontends. If more than the plain
94 which can be displayed by all frontends. If more than the plain
95 text is given, it is up to the frontend to decide which
95 text is given, it is up to the frontend to decide which
96 representation to use.
96 representation to use.
97 metadata : dict
97 metadata : dict
98 A dictionary for metadata related to the data. This can contain
98 A dictionary for metadata related to the data. This can contain
99 arbitrary key, value pairs that frontends can use to interpret
99 arbitrary key, value pairs that frontends can use to interpret
100 the data.
100 the data.
101 """
101 """
102 from IPython.utils import io
102 from IPython.utils import io
103 # The default is to simply write the plain text data using io.stdout.
103 # The default is to simply write the plain text data using io.stdout.
104 if data.has_key('text/plain'):
104 if data.has_key('text/plain'):
105 print(data['text/plain'], file=io.stdout)
105 print(data['text/plain'], file=io.stdout)
106
106
107 def clear_output(self, stdout=True, stderr=True, other=True):
107 def clear_output(self, stdout=True, stderr=True, other=True):
108 """Clear the output of the cell receiving output."""
108 """Clear the output of the cell receiving output."""
109 pass
109 pass
110
110
111
111
112 def publish_display_data(source, data, metadata=None):
112 def publish_display_data(source, data, metadata=None):
113 """Publish data and metadata to all frontends.
113 """Publish data and metadata to all frontends.
114
114
115 See the ``display_data`` message in the messaging documentation for
115 See the ``display_data`` message in the messaging documentation for
116 more details about this message type.
116 more details about this message type.
117
117
118 The following MIME types are currently implemented:
118 The following MIME types are currently implemented:
119
119
120 * text/plain
120 * text/plain
121 * text/html
121 * text/html
122 * text/latex
122 * text/latex
123 * application/json
123 * application/json
124 * application/javascript
124 * application/javascript
125 * image/png
125 * image/png
126 * image/jpeg
126 * image/jpeg
127 * image/svg+xml
127 * image/svg+xml
128
128
129 Parameters
129 Parameters
130 ----------
130 ----------
131 source : str
131 source : str
132 A string that give the function or method that created the data,
132 A string that give the function or method that created the data,
133 such as 'IPython.core.page'.
133 such as 'IPython.core.page'.
134 data : dict
134 data : dict
135 A dictionary having keys that are valid MIME types (like
135 A dictionary having keys that are valid MIME types (like
136 'text/plain' or 'image/svg+xml') and values that are the data for
136 'text/plain' or 'image/svg+xml') and values that are the data for
137 that MIME type. The data itself must be a JSON'able data
137 that MIME type. The data itself must be a JSON'able data
138 structure. Minimally all data should have the 'text/plain' data,
138 structure. Minimally all data should have the 'text/plain' data,
139 which can be displayed by all frontends. If more than the plain
139 which can be displayed by all frontends. If more than the plain
140 text is given, it is up to the frontend to decide which
140 text is given, it is up to the frontend to decide which
141 representation to use.
141 representation to use.
142 metadata : dict
142 metadata : dict
143 A dictionary for metadata related to the data. This can contain
143 A dictionary for metadata related to the data. This can contain
144 arbitrary key, value pairs that frontends can use to interpret
144 arbitrary key, value pairs that frontends can use to interpret
145 the data.
145 the data.
146 """
146 """
147 from IPython.core.interactiveshell import InteractiveShell
147 from IPython.core.interactiveshell import InteractiveShell
148 InteractiveShell.instance().display_pub.publish(
148 InteractiveShell.instance().display_pub.publish(
149 source,
149 source,
150 data,
150 data,
151 metadata
151 metadata
152 )
152 )
153
153
154
154
155 def publish_pretty(data, metadata=None):
155 def publish_pretty(data, metadata=None):
156 """Publish raw text data to all frontends.
156 """Publish raw text data to all frontends.
157
157
158 Parameters
158 Parameters
159 ----------
159 ----------
160 data : unicode
160 data : unicode
161 The raw text data to publish.
161 The raw text data to publish.
162 metadata : dict
162 metadata : dict
163 A dictionary for metadata related to the data. This can contain
163 A dictionary for metadata related to the data. This can contain
164 arbitrary key, value pairs that frontends can use to interpret
164 arbitrary key, value pairs that frontends can use to interpret
165 the data.
165 the data.
166 """
166 """
167 publish_display_data(
167 publish_display_data(
168 u'IPython.core.displaypub.publish_pretty',
168 u'IPython.core.displaypub.publish_pretty',
169 {'text/plain':data},
169 {'text/plain':data},
170 metadata=metadata
170 metadata=metadata
171 )
171 )
172
172
173
173
174 def publish_html(data, metadata=None):
174 def publish_html(data, metadata=None):
175 """Publish raw HTML data to all frontends.
175 """Publish raw HTML data to all frontends.
176
176
177 Parameters
177 Parameters
178 ----------
178 ----------
179 data : unicode
179 data : unicode
180 The raw HTML data to publish.
180 The raw HTML data to publish.
181 metadata : dict
181 metadata : dict
182 A dictionary for metadata related to the data. This can contain
182 A dictionary for metadata related to the data. This can contain
183 arbitrary key, value pairs that frontends can use to interpret
183 arbitrary key, value pairs that frontends can use to interpret
184 the data.
184 the data.
185 """
185 """
186 publish_display_data(
186 publish_display_data(
187 u'IPython.core.displaypub.publish_html',
187 u'IPython.core.displaypub.publish_html',
188 {'text/html':data},
188 {'text/html':data},
189 metadata=metadata
189 metadata=metadata
190 )
190 )
191
191
192
192
193 def publish_latex(data, metadata=None):
193 def publish_latex(data, metadata=None):
194 """Publish raw LaTeX data to all frontends.
194 """Publish raw LaTeX data to all frontends.
195
195
196 Parameters
196 Parameters
197 ----------
197 ----------
198 data : unicode
198 data : unicode
199 The raw LaTeX data to publish.
199 The raw LaTeX data to publish.
200 metadata : dict
200 metadata : dict
201 A dictionary for metadata related to the data. This can contain
201 A dictionary for metadata related to the data. This can contain
202 arbitrary key, value pairs that frontends can use to interpret
202 arbitrary key, value pairs that frontends can use to interpret
203 the data.
203 the data.
204 """
204 """
205 publish_display_data(
205 publish_display_data(
206 u'IPython.core.displaypub.publish_latex',
206 u'IPython.core.displaypub.publish_latex',
207 {'text/latex':data},
207 {'text/latex':data},
208 metadata=metadata
208 metadata=metadata
209 )
209 )
210
210
211 def publish_png(data, metadata=None):
211 def publish_png(data, metadata=None):
212 """Publish raw binary PNG data to all frontends.
212 """Publish raw binary PNG data to all frontends.
213
213
214 Parameters
214 Parameters
215 ----------
215 ----------
216 data : str/bytes
216 data : str/bytes
217 The raw binary PNG data to publish.
217 The raw binary PNG data to publish.
218 metadata : dict
218 metadata : dict
219 A dictionary for metadata related to the data. This can contain
219 A dictionary for metadata related to the data. This can contain
220 arbitrary key, value pairs that frontends can use to interpret
220 arbitrary key, value pairs that frontends can use to interpret
221 the data.
221 the data.
222 """
222 """
223 publish_display_data(
223 publish_display_data(
224 u'IPython.core.displaypub.publish_png',
224 u'IPython.core.displaypub.publish_png',
225 {'image/png':data},
225 {'image/png':data},
226 metadata=metadata
226 metadata=metadata
227 )
227 )
228
228
229
229
230 def publish_jpeg(data, metadata=None):
230 def publish_jpeg(data, metadata=None):
231 """Publish raw binary JPEG data to all frontends.
231 """Publish raw binary JPEG data to all frontends.
232
232
233 Parameters
233 Parameters
234 ----------
234 ----------
235 data : str/bytes
235 data : str/bytes
236 The raw binary JPEG data to publish.
236 The raw binary JPEG data to publish.
237 metadata : dict
237 metadata : dict
238 A dictionary for metadata related to the data. This can contain
238 A dictionary for metadata related to the data. This can contain
239 arbitrary key, value pairs that frontends can use to interpret
239 arbitrary key, value pairs that frontends can use to interpret
240 the data.
240 the data.
241 """
241 """
242 publish_display_data(
242 publish_display_data(
243 u'IPython.core.displaypub.publish_jpeg',
243 u'IPython.core.displaypub.publish_jpeg',
244 {'image/jpeg':data},
244 {'image/jpeg':data},
245 metadata=metadata
245 metadata=metadata
246 )
246 )
247
247
248
248
249 def publish_svg(data, metadata=None):
249 def publish_svg(data, metadata=None):
250 """Publish raw SVG data to all frontends.
250 """Publish raw SVG data to all frontends.
251
251
252 Parameters
252 Parameters
253 ----------
253 ----------
254 data : unicode
254 data : unicode
255 The raw SVG data to publish.
255 The raw SVG data to publish.
256 metadata : dict
256 metadata : dict
257 A dictionary for metadata related to the data. This can contain
257 A dictionary for metadata related to the data. This can contain
258 arbitrary key, value pairs that frontends can use to interpret
258 arbitrary key, value pairs that frontends can use to interpret
259 the data.
259 the data.
260 """
260 """
261 publish_display_data(
261 publish_display_data(
262 u'IPython.core.displaypub.publish_svg',
262 u'IPython.core.displaypub.publish_svg',
263 {'image/svg+xml':data},
263 {'image/svg+xml':data},
264 metadata=metadata
264 metadata=metadata
265 )
265 )
266
266
267 def publish_json(data, metadata=None):
267 def publish_json(data, metadata=None):
268 """Publish raw JSON data to all frontends.
268 """Publish raw JSON data to all frontends.
269
269
270 Parameters
270 Parameters
271 ----------
271 ----------
272 data : unicode
272 data : unicode
273 The raw JSON data to publish.
273 The raw JSON data to publish.
274 metadata : dict
274 metadata : dict
275 A dictionary for metadata related to the data. This can contain
275 A dictionary for metadata related to the data. This can contain
276 arbitrary key, value pairs that frontends can use to interpret
276 arbitrary key, value pairs that frontends can use to interpret
277 the data.
277 the data.
278 """
278 """
279 publish_display_data(
279 publish_display_data(
280 u'IPython.core.displaypub.publish_json',
280 u'IPython.core.displaypub.publish_json',
281 {'application/json':data},
281 {'application/json':data},
282 metadata=metadata
282 metadata=metadata
283 )
283 )
284
284
285 def publish_javascript(data, metadata=None):
285 def publish_javascript(data, metadata=None):
286 """Publish raw Javascript data to all frontends.
286 """Publish raw Javascript data to all frontends.
287
287
288 Parameters
288 Parameters
289 ----------
289 ----------
290 data : unicode
290 data : unicode
291 The raw Javascript data to publish.
291 The raw Javascript data to publish.
292 metadata : dict
292 metadata : dict
293 A dictionary for metadata related to the data. This can contain
293 A dictionary for metadata related to the data. This can contain
294 arbitrary key, value pairs that frontends can use to interpret
294 arbitrary key, value pairs that frontends can use to interpret
295 the data.
295 the data.
296 """
296 """
297 publish_display_data(
297 publish_display_data(
298 u'IPython.core.displaypub.publish_javascript',
298 u'IPython.core.displaypub.publish_javascript',
299 {'application/javascript':data},
299 {'application/javascript':data},
300 metadata=metadata
300 metadata=metadata
301 )
301 )
302
302
@@ -1,59 +1,59 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Global exception classes for IPython.core.
3 Global exception classes for IPython.core.
4
4
5 Authors:
5 Authors:
6
6
7 * Brian Granger
7 * Brian Granger
8 * Fernando Perez
8 * Fernando Perez
9 * Min Ragan-Kelley
9 * Min Ragan-Kelley
10
10
11 Notes
11 Notes
12 -----
12 -----
13 """
13 """
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Copyright (C) 2008-2009 The IPython Development Team
16 # Copyright (C) 2008-2011 The IPython Development Team
17 #
17 #
18 # Distributed under the terms of the BSD License. The full license is in
18 # Distributed under the terms of the BSD License. The full license is in
19 # the file COPYING, distributed as part of this software.
19 # the file COPYING, distributed as part of this software.
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 # Imports
23 # Imports
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 # Exception classes
27 # Exception classes
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29
29
30 class IPythonCoreError(Exception):
30 class IPythonCoreError(Exception):
31 pass
31 pass
32
32
33
33
34 class TryNext(IPythonCoreError):
34 class TryNext(IPythonCoreError):
35 """Try next hook exception.
35 """Try next hook exception.
36
36
37 Raise this in your hook function to indicate that the next hook handler
37 Raise this in your hook function to indicate that the next hook handler
38 should be used to handle the operation. If you pass arguments to the
38 should be used to handle the operation. If you pass arguments to the
39 constructor those arguments will be used by the next hook instead of the
39 constructor those arguments will be used by the next hook instead of the
40 original ones.
40 original ones.
41 """
41 """
42
42
43 def __init__(self, *args, **kwargs):
43 def __init__(self, *args, **kwargs):
44 self.args = args
44 self.args = args
45 self.kwargs = kwargs
45 self.kwargs = kwargs
46
46
47 class UsageError(IPythonCoreError):
47 class UsageError(IPythonCoreError):
48 """Error in magic function arguments, etc.
48 """Error in magic function arguments, etc.
49
49
50 Something that probably won't warrant a full traceback, but should
50 Something that probably won't warrant a full traceback, but should
51 nevertheless interrupt a macro / batch file.
51 nevertheless interrupt a macro / batch file.
52 """
52 """
53
53
54 class StdinNotImplementedError(IPythonCoreError, NotImplementedError):
54 class StdinNotImplementedError(IPythonCoreError, NotImplementedError):
55 """raw_input was requested in a context where it is not supported
55 """raw_input was requested in a context where it is not supported
56
56
57 For use in IPython kernels, where only some frontends may support
57 For use in IPython kernels, where only some frontends may support
58 stdin requests.
58 stdin requests.
59 """
59 """
@@ -1,125 +1,125 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """A class for managing IPython extensions.
2 """A class for managing IPython extensions.
3
3
4 Authors:
4 Authors:
5
5
6 * Brian Granger
6 * Brian Granger
7 """
7 """
8
8
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2010 The IPython Development Team
10 # Copyright (C) 2010-2011 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
19
20 import os
20 import os
21 import sys
21 import sys
22
22
23 from IPython.config.configurable import Configurable
23 from IPython.config.configurable import Configurable
24 from IPython.utils.traitlets import Instance
24 from IPython.utils.traitlets import Instance
25
25
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 # Main class
27 # Main class
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29
29
30 class ExtensionManager(Configurable):
30 class ExtensionManager(Configurable):
31 """A class to manage IPython extensions.
31 """A class to manage IPython extensions.
32
32
33 An IPython extension is an importable Python module that has
33 An IPython extension is an importable Python module that has
34 a function with the signature::
34 a function with the signature::
35
35
36 def load_ipython_extension(ipython):
36 def load_ipython_extension(ipython):
37 # Do things with ipython
37 # Do things with ipython
38
38
39 This function is called after your extension is imported and the
39 This function is called after your extension is imported and the
40 currently active :class:`InteractiveShell` instance is passed as
40 currently active :class:`InteractiveShell` instance is passed as
41 the only argument. You can do anything you want with IPython at
41 the only argument. You can do anything you want with IPython at
42 that point, including defining new magic and aliases, adding new
42 that point, including defining new magic and aliases, adding new
43 components, etc.
43 components, etc.
44
44
45 The :func:`load_ipython_extension` will be called again is you
45 The :func:`load_ipython_extension` will be called again is you
46 load or reload the extension again. It is up to the extension
46 load or reload the extension again. It is up to the extension
47 author to add code to manage that.
47 author to add code to manage that.
48
48
49 You can put your extension modules anywhere you want, as long as
49 You can put your extension modules anywhere you want, as long as
50 they can be imported by Python's standard import mechanism. However,
50 they can be imported by Python's standard import mechanism. However,
51 to make it easy to write extensions, you can also put your extensions
51 to make it easy to write extensions, you can also put your extensions
52 in ``os.path.join(self.ipython_dir, 'extensions')``. This directory
52 in ``os.path.join(self.ipython_dir, 'extensions')``. This directory
53 is added to ``sys.path`` automatically.
53 is added to ``sys.path`` automatically.
54 """
54 """
55
55
56 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
56 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
57
57
58 def __init__(self, shell=None, config=None):
58 def __init__(self, shell=None, config=None):
59 super(ExtensionManager, self).__init__(shell=shell, config=config)
59 super(ExtensionManager, self).__init__(shell=shell, config=config)
60 self.shell.on_trait_change(
60 self.shell.on_trait_change(
61 self._on_ipython_dir_changed, 'ipython_dir'
61 self._on_ipython_dir_changed, 'ipython_dir'
62 )
62 )
63
63
64 def __del__(self):
64 def __del__(self):
65 self.shell.on_trait_change(
65 self.shell.on_trait_change(
66 self._on_ipython_dir_changed, 'ipython_dir', remove=True
66 self._on_ipython_dir_changed, 'ipython_dir', remove=True
67 )
67 )
68
68
69 @property
69 @property
70 def ipython_extension_dir(self):
70 def ipython_extension_dir(self):
71 return os.path.join(self.shell.ipython_dir, u'extensions')
71 return os.path.join(self.shell.ipython_dir, u'extensions')
72
72
73 def _on_ipython_dir_changed(self):
73 def _on_ipython_dir_changed(self):
74 if not os.path.isdir(self.ipython_extension_dir):
74 if not os.path.isdir(self.ipython_extension_dir):
75 os.makedirs(self.ipython_extension_dir, mode = 0777)
75 os.makedirs(self.ipython_extension_dir, mode = 0777)
76
76
77 def load_extension(self, module_str):
77 def load_extension(self, module_str):
78 """Load an IPython extension by its module name.
78 """Load an IPython extension by its module name.
79
79
80 If :func:`load_ipython_extension` returns anything, this function
80 If :func:`load_ipython_extension` returns anything, this function
81 will return that object.
81 will return that object.
82 """
82 """
83 from IPython.utils.syspathcontext import prepended_to_syspath
83 from IPython.utils.syspathcontext import prepended_to_syspath
84
84
85 if module_str not in sys.modules:
85 if module_str not in sys.modules:
86 with prepended_to_syspath(self.ipython_extension_dir):
86 with prepended_to_syspath(self.ipython_extension_dir):
87 __import__(module_str)
87 __import__(module_str)
88 mod = sys.modules[module_str]
88 mod = sys.modules[module_str]
89 return self._call_load_ipython_extension(mod)
89 return self._call_load_ipython_extension(mod)
90
90
91 def unload_extension(self, module_str):
91 def unload_extension(self, module_str):
92 """Unload an IPython extension by its module name.
92 """Unload an IPython extension by its module name.
93
93
94 This function looks up the extension's name in ``sys.modules`` and
94 This function looks up the extension's name in ``sys.modules`` and
95 simply calls ``mod.unload_ipython_extension(self)``.
95 simply calls ``mod.unload_ipython_extension(self)``.
96 """
96 """
97 if module_str in sys.modules:
97 if module_str in sys.modules:
98 mod = sys.modules[module_str]
98 mod = sys.modules[module_str]
99 self._call_unload_ipython_extension(mod)
99 self._call_unload_ipython_extension(mod)
100
100
101 def reload_extension(self, module_str):
101 def reload_extension(self, module_str):
102 """Reload an IPython extension by calling reload.
102 """Reload an IPython extension by calling reload.
103
103
104 If the module has not been loaded before,
104 If the module has not been loaded before,
105 :meth:`InteractiveShell.load_extension` is called. Otherwise
105 :meth:`InteractiveShell.load_extension` is called. Otherwise
106 :func:`reload` is called and then the :func:`load_ipython_extension`
106 :func:`reload` is called and then the :func:`load_ipython_extension`
107 function of the module, if it exists is called.
107 function of the module, if it exists is called.
108 """
108 """
109 from IPython.utils.syspathcontext import prepended_to_syspath
109 from IPython.utils.syspathcontext import prepended_to_syspath
110
110
111 with prepended_to_syspath(self.ipython_extension_dir):
111 with prepended_to_syspath(self.ipython_extension_dir):
112 if module_str in sys.modules:
112 if module_str in sys.modules:
113 mod = sys.modules[module_str]
113 mod = sys.modules[module_str]
114 reload(mod)
114 reload(mod)
115 self._call_load_ipython_extension(mod)
115 self._call_load_ipython_extension(mod)
116 else:
116 else:
117 self.load_extension(module_str)
117 self.load_extension(module_str)
118
118
119 def _call_load_ipython_extension(self, mod):
119 def _call_load_ipython_extension(self, mod):
120 if hasattr(mod, 'load_ipython_extension'):
120 if hasattr(mod, 'load_ipython_extension'):
121 return mod.load_ipython_extension(self.shell)
121 return mod.load_ipython_extension(self.shell)
122
122
123 def _call_unload_ipython_extension(self, mod):
123 def _call_unload_ipython_extension(self, mod):
124 if hasattr(mod, 'unload_ipython_extension'):
124 if hasattr(mod, 'unload_ipython_extension'):
125 return mod.unload_ipython_extension(self.shell)
125 return mod.unload_ipython_extension(self.shell)
@@ -1,620 +1,620 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Display formatters.
2 """Display formatters.
3
3
4
4
5 Authors:
5 Authors:
6
6
7 * Robert Kern
7 * Robert Kern
8 * Brian Granger
8 * Brian Granger
9 """
9 """
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Copyright (c) 2010, IPython Development Team.
11 # Copyright (C) 2010-2011, IPython Development Team.
12 #
12 #
13 # Distributed under the terms of the Modified BSD License.
13 # Distributed under the terms of the Modified BSD License.
14 #
14 #
15 # The full license is in the file COPYING.txt, distributed with this software.
15 # The full license is in the file COPYING.txt, distributed with this software.
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Imports
19 # Imports
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 # Stdlib imports
22 # Stdlib imports
23 import abc
23 import abc
24 import sys
24 import sys
25 # We must use StringIO, as cStringIO doesn't handle unicode properly.
25 # We must use StringIO, as cStringIO doesn't handle unicode properly.
26 from StringIO import StringIO
26 from StringIO import StringIO
27
27
28 # Our own imports
28 # Our own imports
29 from IPython.config.configurable import Configurable
29 from IPython.config.configurable import Configurable
30 from IPython.lib import pretty
30 from IPython.lib import pretty
31 from IPython.utils.traitlets import Bool, Dict, Integer, Unicode, CUnicode, ObjectName
31 from IPython.utils.traitlets import Bool, Dict, Integer, Unicode, CUnicode, ObjectName
32 from IPython.utils.py3compat import unicode_to_str
32 from IPython.utils.py3compat import unicode_to_str
33
33
34
34
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36 # The main DisplayFormatter class
36 # The main DisplayFormatter class
37 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
38
38
39
39
40 class DisplayFormatter(Configurable):
40 class DisplayFormatter(Configurable):
41
41
42 # When set to true only the default plain text formatter will be used.
42 # When set to true only the default plain text formatter will be used.
43 plain_text_only = Bool(False, config=True)
43 plain_text_only = Bool(False, config=True)
44
44
45 # A dict of formatter whose keys are format types (MIME types) and whose
45 # A dict of formatter whose keys are format types (MIME types) and whose
46 # values are subclasses of BaseFormatter.
46 # values are subclasses of BaseFormatter.
47 formatters = Dict()
47 formatters = Dict()
48 def _formatters_default(self):
48 def _formatters_default(self):
49 """Activate the default formatters."""
49 """Activate the default formatters."""
50 formatter_classes = [
50 formatter_classes = [
51 PlainTextFormatter,
51 PlainTextFormatter,
52 HTMLFormatter,
52 HTMLFormatter,
53 SVGFormatter,
53 SVGFormatter,
54 PNGFormatter,
54 PNGFormatter,
55 JPEGFormatter,
55 JPEGFormatter,
56 LatexFormatter,
56 LatexFormatter,
57 JSONFormatter,
57 JSONFormatter,
58 JavascriptFormatter
58 JavascriptFormatter
59 ]
59 ]
60 d = {}
60 d = {}
61 for cls in formatter_classes:
61 for cls in formatter_classes:
62 f = cls(config=self.config)
62 f = cls(config=self.config)
63 d[f.format_type] = f
63 d[f.format_type] = f
64 return d
64 return d
65
65
66 def format(self, obj, include=None, exclude=None):
66 def format(self, obj, include=None, exclude=None):
67 """Return a format data dict for an object.
67 """Return a format data dict for an object.
68
68
69 By default all format types will be computed.
69 By default all format types will be computed.
70
70
71 The following MIME types are currently implemented:
71 The following MIME types are currently implemented:
72
72
73 * text/plain
73 * text/plain
74 * text/html
74 * text/html
75 * text/latex
75 * text/latex
76 * application/json
76 * application/json
77 * application/javascript
77 * application/javascript
78 * image/png
78 * image/png
79 * image/jpeg
79 * image/jpeg
80 * image/svg+xml
80 * image/svg+xml
81
81
82 Parameters
82 Parameters
83 ----------
83 ----------
84 obj : object
84 obj : object
85 The Python object whose format data will be computed.
85 The Python object whose format data will be computed.
86 include : list or tuple, optional
86 include : list or tuple, optional
87 A list of format type strings (MIME types) to include in the
87 A list of format type strings (MIME types) to include in the
88 format data dict. If this is set *only* the format types included
88 format data dict. If this is set *only* the format types included
89 in this list will be computed.
89 in this list will be computed.
90 exclude : list or tuple, optional
90 exclude : list or tuple, optional
91 A list of format type string (MIME types) to exclue in the format
91 A list of format type string (MIME types) to exclue in the format
92 data dict. If this is set all format types will be computed,
92 data dict. If this is set all format types will be computed,
93 except for those included in this argument.
93 except for those included in this argument.
94
94
95 Returns
95 Returns
96 -------
96 -------
97 format_dict : dict
97 format_dict : dict
98 A dictionary of key/value pairs, one or each format that was
98 A dictionary of key/value pairs, one or each format that was
99 generated for the object. The keys are the format types, which
99 generated for the object. The keys are the format types, which
100 will usually be MIME type strings and the values and JSON'able
100 will usually be MIME type strings and the values and JSON'able
101 data structure containing the raw data for the representation in
101 data structure containing the raw data for the representation in
102 that format.
102 that format.
103 """
103 """
104 format_dict = {}
104 format_dict = {}
105
105
106 # If plain text only is active
106 # If plain text only is active
107 if self.plain_text_only:
107 if self.plain_text_only:
108 formatter = self.formatters['text/plain']
108 formatter = self.formatters['text/plain']
109 try:
109 try:
110 data = formatter(obj)
110 data = formatter(obj)
111 except:
111 except:
112 # FIXME: log the exception
112 # FIXME: log the exception
113 raise
113 raise
114 if data is not None:
114 if data is not None:
115 format_dict['text/plain'] = data
115 format_dict['text/plain'] = data
116 return format_dict
116 return format_dict
117
117
118 for format_type, formatter in self.formatters.items():
118 for format_type, formatter in self.formatters.items():
119 if include is not None:
119 if include is not None:
120 if format_type not in include:
120 if format_type not in include:
121 continue
121 continue
122 if exclude is not None:
122 if exclude is not None:
123 if format_type in exclude:
123 if format_type in exclude:
124 continue
124 continue
125 try:
125 try:
126 data = formatter(obj)
126 data = formatter(obj)
127 except:
127 except:
128 # FIXME: log the exception
128 # FIXME: log the exception
129 raise
129 raise
130 if data is not None:
130 if data is not None:
131 format_dict[format_type] = data
131 format_dict[format_type] = data
132 return format_dict
132 return format_dict
133
133
134 @property
134 @property
135 def format_types(self):
135 def format_types(self):
136 """Return the format types (MIME types) of the active formatters."""
136 """Return the format types (MIME types) of the active formatters."""
137 return self.formatters.keys()
137 return self.formatters.keys()
138
138
139
139
140 #-----------------------------------------------------------------------------
140 #-----------------------------------------------------------------------------
141 # Formatters for specific format types (text, html, svg, etc.)
141 # Formatters for specific format types (text, html, svg, etc.)
142 #-----------------------------------------------------------------------------
142 #-----------------------------------------------------------------------------
143
143
144
144
145 class FormatterABC(object):
145 class FormatterABC(object):
146 """ Abstract base class for Formatters.
146 """ Abstract base class for Formatters.
147
147
148 A formatter is a callable class that is responsible for computing the
148 A formatter is a callable class that is responsible for computing the
149 raw format data for a particular format type (MIME type). For example,
149 raw format data for a particular format type (MIME type). For example,
150 an HTML formatter would have a format type of `text/html` and would return
150 an HTML formatter would have a format type of `text/html` and would return
151 the HTML representation of the object when called.
151 the HTML representation of the object when called.
152 """
152 """
153 __metaclass__ = abc.ABCMeta
153 __metaclass__ = abc.ABCMeta
154
154
155 # The format type of the data returned, usually a MIME type.
155 # The format type of the data returned, usually a MIME type.
156 format_type = 'text/plain'
156 format_type = 'text/plain'
157
157
158 # Is the formatter enabled...
158 # Is the formatter enabled...
159 enabled = True
159 enabled = True
160
160
161 @abc.abstractmethod
161 @abc.abstractmethod
162 def __call__(self, obj):
162 def __call__(self, obj):
163 """Return a JSON'able representation of the object.
163 """Return a JSON'able representation of the object.
164
164
165 If the object cannot be formatted by this formatter, then return None
165 If the object cannot be formatted by this formatter, then return None
166 """
166 """
167 try:
167 try:
168 return repr(obj)
168 return repr(obj)
169 except TypeError:
169 except TypeError:
170 return None
170 return None
171
171
172
172
173 class BaseFormatter(Configurable):
173 class BaseFormatter(Configurable):
174 """A base formatter class that is configurable.
174 """A base formatter class that is configurable.
175
175
176 This formatter should usually be used as the base class of all formatters.
176 This formatter should usually be used as the base class of all formatters.
177 It is a traited :class:`Configurable` class and includes an extensible
177 It is a traited :class:`Configurable` class and includes an extensible
178 API for users to determine how their objects are formatted. The following
178 API for users to determine how their objects are formatted. The following
179 logic is used to find a function to format an given object.
179 logic is used to find a function to format an given object.
180
180
181 1. The object is introspected to see if it has a method with the name
181 1. The object is introspected to see if it has a method with the name
182 :attr:`print_method`. If is does, that object is passed to that method
182 :attr:`print_method`. If is does, that object is passed to that method
183 for formatting.
183 for formatting.
184 2. If no print method is found, three internal dictionaries are consulted
184 2. If no print method is found, three internal dictionaries are consulted
185 to find print method: :attr:`singleton_printers`, :attr:`type_printers`
185 to find print method: :attr:`singleton_printers`, :attr:`type_printers`
186 and :attr:`deferred_printers`.
186 and :attr:`deferred_printers`.
187
187
188 Users should use these dictionaries to register functions that will be
188 Users should use these dictionaries to register functions that will be
189 used to compute the format data for their objects (if those objects don't
189 used to compute the format data for their objects (if those objects don't
190 have the special print methods). The easiest way of using these
190 have the special print methods). The easiest way of using these
191 dictionaries is through the :meth:`for_type` and :meth:`for_type_by_name`
191 dictionaries is through the :meth:`for_type` and :meth:`for_type_by_name`
192 methods.
192 methods.
193
193
194 If no function/callable is found to compute the format data, ``None`` is
194 If no function/callable is found to compute the format data, ``None`` is
195 returned and this format type is not used.
195 returned and this format type is not used.
196 """
196 """
197
197
198 format_type = Unicode('text/plain')
198 format_type = Unicode('text/plain')
199
199
200 enabled = Bool(True, config=True)
200 enabled = Bool(True, config=True)
201
201
202 print_method = ObjectName('__repr__')
202 print_method = ObjectName('__repr__')
203
203
204 # The singleton printers.
204 # The singleton printers.
205 # Maps the IDs of the builtin singleton objects to the format functions.
205 # Maps the IDs of the builtin singleton objects to the format functions.
206 singleton_printers = Dict(config=True)
206 singleton_printers = Dict(config=True)
207 def _singleton_printers_default(self):
207 def _singleton_printers_default(self):
208 return {}
208 return {}
209
209
210 # The type-specific printers.
210 # The type-specific printers.
211 # Map type objects to the format functions.
211 # Map type objects to the format functions.
212 type_printers = Dict(config=True)
212 type_printers = Dict(config=True)
213 def _type_printers_default(self):
213 def _type_printers_default(self):
214 return {}
214 return {}
215
215
216 # The deferred-import type-specific printers.
216 # The deferred-import type-specific printers.
217 # Map (modulename, classname) pairs to the format functions.
217 # Map (modulename, classname) pairs to the format functions.
218 deferred_printers = Dict(config=True)
218 deferred_printers = Dict(config=True)
219 def _deferred_printers_default(self):
219 def _deferred_printers_default(self):
220 return {}
220 return {}
221
221
222 def __call__(self, obj):
222 def __call__(self, obj):
223 """Compute the format for an object."""
223 """Compute the format for an object."""
224 if self.enabled:
224 if self.enabled:
225 obj_id = id(obj)
225 obj_id = id(obj)
226 try:
226 try:
227 obj_class = getattr(obj, '__class__', None) or type(obj)
227 obj_class = getattr(obj, '__class__', None) or type(obj)
228 # First try to find registered singleton printers for the type.
228 # First try to find registered singleton printers for the type.
229 try:
229 try:
230 printer = self.singleton_printers[obj_id]
230 printer = self.singleton_printers[obj_id]
231 except (TypeError, KeyError):
231 except (TypeError, KeyError):
232 pass
232 pass
233 else:
233 else:
234 return printer(obj)
234 return printer(obj)
235 # Next look for type_printers.
235 # Next look for type_printers.
236 for cls in pretty._get_mro(obj_class):
236 for cls in pretty._get_mro(obj_class):
237 if cls in self.type_printers:
237 if cls in self.type_printers:
238 return self.type_printers[cls](obj)
238 return self.type_printers[cls](obj)
239 else:
239 else:
240 printer = self._in_deferred_types(cls)
240 printer = self._in_deferred_types(cls)
241 if printer is not None:
241 if printer is not None:
242 return printer(obj)
242 return printer(obj)
243 # Finally look for special method names.
243 # Finally look for special method names.
244 if hasattr(obj_class, self.print_method):
244 if hasattr(obj_class, self.print_method):
245 printer = getattr(obj_class, self.print_method)
245 printer = getattr(obj_class, self.print_method)
246 return printer(obj)
246 return printer(obj)
247 return None
247 return None
248 except Exception:
248 except Exception:
249 pass
249 pass
250 else:
250 else:
251 return None
251 return None
252
252
253 def for_type(self, typ, func):
253 def for_type(self, typ, func):
254 """Add a format function for a given type.
254 """Add a format function for a given type.
255
255
256 Parameters
256 Parameters
257 -----------
257 -----------
258 typ : class
258 typ : class
259 The class of the object that will be formatted using `func`.
259 The class of the object that will be formatted using `func`.
260 func : callable
260 func : callable
261 The callable that will be called to compute the format data. The
261 The callable that will be called to compute the format data. The
262 call signature of this function is simple, it must take the
262 call signature of this function is simple, it must take the
263 object to be formatted and return the raw data for the given
263 object to be formatted and return the raw data for the given
264 format. Subclasses may use a different call signature for the
264 format. Subclasses may use a different call signature for the
265 `func` argument.
265 `func` argument.
266 """
266 """
267 oldfunc = self.type_printers.get(typ, None)
267 oldfunc = self.type_printers.get(typ, None)
268 if func is not None:
268 if func is not None:
269 # To support easy restoration of old printers, we need to ignore
269 # To support easy restoration of old printers, we need to ignore
270 # Nones.
270 # Nones.
271 self.type_printers[typ] = func
271 self.type_printers[typ] = func
272 return oldfunc
272 return oldfunc
273
273
274 def for_type_by_name(self, type_module, type_name, func):
274 def for_type_by_name(self, type_module, type_name, func):
275 """Add a format function for a type specified by the full dotted
275 """Add a format function for a type specified by the full dotted
276 module and name of the type, rather than the type of the object.
276 module and name of the type, rather than the type of the object.
277
277
278 Parameters
278 Parameters
279 ----------
279 ----------
280 type_module : str
280 type_module : str
281 The full dotted name of the module the type is defined in, like
281 The full dotted name of the module the type is defined in, like
282 ``numpy``.
282 ``numpy``.
283 type_name : str
283 type_name : str
284 The name of the type (the class name), like ``dtype``
284 The name of the type (the class name), like ``dtype``
285 func : callable
285 func : callable
286 The callable that will be called to compute the format data. The
286 The callable that will be called to compute the format data. The
287 call signature of this function is simple, it must take the
287 call signature of this function is simple, it must take the
288 object to be formatted and return the raw data for the given
288 object to be formatted and return the raw data for the given
289 format. Subclasses may use a different call signature for the
289 format. Subclasses may use a different call signature for the
290 `func` argument.
290 `func` argument.
291 """
291 """
292 key = (type_module, type_name)
292 key = (type_module, type_name)
293 oldfunc = self.deferred_printers.get(key, None)
293 oldfunc = self.deferred_printers.get(key, None)
294 if func is not None:
294 if func is not None:
295 # To support easy restoration of old printers, we need to ignore
295 # To support easy restoration of old printers, we need to ignore
296 # Nones.
296 # Nones.
297 self.deferred_printers[key] = func
297 self.deferred_printers[key] = func
298 return oldfunc
298 return oldfunc
299
299
300 def _in_deferred_types(self, cls):
300 def _in_deferred_types(self, cls):
301 """
301 """
302 Check if the given class is specified in the deferred type registry.
302 Check if the given class is specified in the deferred type registry.
303
303
304 Returns the printer from the registry if it exists, and None if the
304 Returns the printer from the registry if it exists, and None if the
305 class is not in the registry. Successful matches will be moved to the
305 class is not in the registry. Successful matches will be moved to the
306 regular type registry for future use.
306 regular type registry for future use.
307 """
307 """
308 mod = getattr(cls, '__module__', None)
308 mod = getattr(cls, '__module__', None)
309 name = getattr(cls, '__name__', None)
309 name = getattr(cls, '__name__', None)
310 key = (mod, name)
310 key = (mod, name)
311 printer = None
311 printer = None
312 if key in self.deferred_printers:
312 if key in self.deferred_printers:
313 # Move the printer over to the regular registry.
313 # Move the printer over to the regular registry.
314 printer = self.deferred_printers.pop(key)
314 printer = self.deferred_printers.pop(key)
315 self.type_printers[cls] = printer
315 self.type_printers[cls] = printer
316 return printer
316 return printer
317
317
318
318
319 class PlainTextFormatter(BaseFormatter):
319 class PlainTextFormatter(BaseFormatter):
320 """The default pretty-printer.
320 """The default pretty-printer.
321
321
322 This uses :mod:`IPython.external.pretty` to compute the format data of
322 This uses :mod:`IPython.external.pretty` to compute the format data of
323 the object. If the object cannot be pretty printed, :func:`repr` is used.
323 the object. If the object cannot be pretty printed, :func:`repr` is used.
324 See the documentation of :mod:`IPython.external.pretty` for details on
324 See the documentation of :mod:`IPython.external.pretty` for details on
325 how to write pretty printers. Here is a simple example::
325 how to write pretty printers. Here is a simple example::
326
326
327 def dtype_pprinter(obj, p, cycle):
327 def dtype_pprinter(obj, p, cycle):
328 if cycle:
328 if cycle:
329 return p.text('dtype(...)')
329 return p.text('dtype(...)')
330 if hasattr(obj, 'fields'):
330 if hasattr(obj, 'fields'):
331 if obj.fields is None:
331 if obj.fields is None:
332 p.text(repr(obj))
332 p.text(repr(obj))
333 else:
333 else:
334 p.begin_group(7, 'dtype([')
334 p.begin_group(7, 'dtype([')
335 for i, field in enumerate(obj.descr):
335 for i, field in enumerate(obj.descr):
336 if i > 0:
336 if i > 0:
337 p.text(',')
337 p.text(',')
338 p.breakable()
338 p.breakable()
339 p.pretty(field)
339 p.pretty(field)
340 p.end_group(7, '])')
340 p.end_group(7, '])')
341 """
341 """
342
342
343 # The format type of data returned.
343 # The format type of data returned.
344 format_type = Unicode('text/plain')
344 format_type = Unicode('text/plain')
345
345
346 # This subclass ignores this attribute as it always need to return
346 # This subclass ignores this attribute as it always need to return
347 # something.
347 # something.
348 enabled = Bool(True, config=False)
348 enabled = Bool(True, config=False)
349
349
350 # Look for a _repr_pretty_ methods to use for pretty printing.
350 # Look for a _repr_pretty_ methods to use for pretty printing.
351 print_method = ObjectName('_repr_pretty_')
351 print_method = ObjectName('_repr_pretty_')
352
352
353 # Whether to pretty-print or not.
353 # Whether to pretty-print or not.
354 pprint = Bool(True, config=True)
354 pprint = Bool(True, config=True)
355
355
356 # Whether to be verbose or not.
356 # Whether to be verbose or not.
357 verbose = Bool(False, config=True)
357 verbose = Bool(False, config=True)
358
358
359 # The maximum width.
359 # The maximum width.
360 max_width = Integer(79, config=True)
360 max_width = Integer(79, config=True)
361
361
362 # The newline character.
362 # The newline character.
363 newline = Unicode('\n', config=True)
363 newline = Unicode('\n', config=True)
364
364
365 # format-string for pprinting floats
365 # format-string for pprinting floats
366 float_format = Unicode('%r')
366 float_format = Unicode('%r')
367 # setter for float precision, either int or direct format-string
367 # setter for float precision, either int or direct format-string
368 float_precision = CUnicode('', config=True)
368 float_precision = CUnicode('', config=True)
369
369
370 def _float_precision_changed(self, name, old, new):
370 def _float_precision_changed(self, name, old, new):
371 """float_precision changed, set float_format accordingly.
371 """float_precision changed, set float_format accordingly.
372
372
373 float_precision can be set by int or str.
373 float_precision can be set by int or str.
374 This will set float_format, after interpreting input.
374 This will set float_format, after interpreting input.
375 If numpy has been imported, numpy print precision will also be set.
375 If numpy has been imported, numpy print precision will also be set.
376
376
377 integer `n` sets format to '%.nf', otherwise, format set directly.
377 integer `n` sets format to '%.nf', otherwise, format set directly.
378
378
379 An empty string returns to defaults (repr for float, 8 for numpy).
379 An empty string returns to defaults (repr for float, 8 for numpy).
380
380
381 This parameter can be set via the '%precision' magic.
381 This parameter can be set via the '%precision' magic.
382 """
382 """
383
383
384 if '%' in new:
384 if '%' in new:
385 # got explicit format string
385 # got explicit format string
386 fmt = new
386 fmt = new
387 try:
387 try:
388 fmt%3.14159
388 fmt%3.14159
389 except Exception:
389 except Exception:
390 raise ValueError("Precision must be int or format string, not %r"%new)
390 raise ValueError("Precision must be int or format string, not %r"%new)
391 elif new:
391 elif new:
392 # otherwise, should be an int
392 # otherwise, should be an int
393 try:
393 try:
394 i = int(new)
394 i = int(new)
395 assert i >= 0
395 assert i >= 0
396 except ValueError:
396 except ValueError:
397 raise ValueError("Precision must be int or format string, not %r"%new)
397 raise ValueError("Precision must be int or format string, not %r"%new)
398 except AssertionError:
398 except AssertionError:
399 raise ValueError("int precision must be non-negative, not %r"%i)
399 raise ValueError("int precision must be non-negative, not %r"%i)
400
400
401 fmt = '%%.%if'%i
401 fmt = '%%.%if'%i
402 if 'numpy' in sys.modules:
402 if 'numpy' in sys.modules:
403 # set numpy precision if it has been imported
403 # set numpy precision if it has been imported
404 import numpy
404 import numpy
405 numpy.set_printoptions(precision=i)
405 numpy.set_printoptions(precision=i)
406 else:
406 else:
407 # default back to repr
407 # default back to repr
408 fmt = '%r'
408 fmt = '%r'
409 if 'numpy' in sys.modules:
409 if 'numpy' in sys.modules:
410 import numpy
410 import numpy
411 # numpy default is 8
411 # numpy default is 8
412 numpy.set_printoptions(precision=8)
412 numpy.set_printoptions(precision=8)
413 self.float_format = fmt
413 self.float_format = fmt
414
414
415 # Use the default pretty printers from IPython.external.pretty.
415 # Use the default pretty printers from IPython.external.pretty.
416 def _singleton_printers_default(self):
416 def _singleton_printers_default(self):
417 return pretty._singleton_pprinters.copy()
417 return pretty._singleton_pprinters.copy()
418
418
419 def _type_printers_default(self):
419 def _type_printers_default(self):
420 d = pretty._type_pprinters.copy()
420 d = pretty._type_pprinters.copy()
421 d[float] = lambda obj,p,cycle: p.text(self.float_format%obj)
421 d[float] = lambda obj,p,cycle: p.text(self.float_format%obj)
422 return d
422 return d
423
423
424 def _deferred_printers_default(self):
424 def _deferred_printers_default(self):
425 return pretty._deferred_type_pprinters.copy()
425 return pretty._deferred_type_pprinters.copy()
426
426
427 #### FormatterABC interface ####
427 #### FormatterABC interface ####
428
428
429 def __call__(self, obj):
429 def __call__(self, obj):
430 """Compute the pretty representation of the object."""
430 """Compute the pretty representation of the object."""
431 if not self.pprint:
431 if not self.pprint:
432 try:
432 try:
433 return repr(obj)
433 return repr(obj)
434 except TypeError:
434 except TypeError:
435 return ''
435 return ''
436 else:
436 else:
437 # This uses use StringIO, as cStringIO doesn't handle unicode.
437 # This uses use StringIO, as cStringIO doesn't handle unicode.
438 stream = StringIO()
438 stream = StringIO()
439 # self.newline.encode() is a quick fix for issue gh-597. We need to
439 # self.newline.encode() is a quick fix for issue gh-597. We need to
440 # ensure that stream does not get a mix of unicode and bytestrings,
440 # ensure that stream does not get a mix of unicode and bytestrings,
441 # or it will cause trouble.
441 # or it will cause trouble.
442 printer = pretty.RepresentationPrinter(stream, self.verbose,
442 printer = pretty.RepresentationPrinter(stream, self.verbose,
443 self.max_width, unicode_to_str(self.newline),
443 self.max_width, unicode_to_str(self.newline),
444 singleton_pprinters=self.singleton_printers,
444 singleton_pprinters=self.singleton_printers,
445 type_pprinters=self.type_printers,
445 type_pprinters=self.type_printers,
446 deferred_pprinters=self.deferred_printers)
446 deferred_pprinters=self.deferred_printers)
447 printer.pretty(obj)
447 printer.pretty(obj)
448 printer.flush()
448 printer.flush()
449 return stream.getvalue()
449 return stream.getvalue()
450
450
451
451
452 class HTMLFormatter(BaseFormatter):
452 class HTMLFormatter(BaseFormatter):
453 """An HTML formatter.
453 """An HTML formatter.
454
454
455 To define the callables that compute the HTML representation of your
455 To define the callables that compute the HTML representation of your
456 objects, define a :meth:`_repr_html_` method or use the :meth:`for_type`
456 objects, define a :meth:`_repr_html_` method or use the :meth:`for_type`
457 or :meth:`for_type_by_name` methods to register functions that handle
457 or :meth:`for_type_by_name` methods to register functions that handle
458 this.
458 this.
459
459
460 The return value of this formatter should be a valid HTML snippet that
460 The return value of this formatter should be a valid HTML snippet that
461 could be injected into an existing DOM. It should *not* include the
461 could be injected into an existing DOM. It should *not* include the
462 ```<html>`` or ```<body>`` tags.
462 ```<html>`` or ```<body>`` tags.
463 """
463 """
464 format_type = Unicode('text/html')
464 format_type = Unicode('text/html')
465
465
466 print_method = ObjectName('_repr_html_')
466 print_method = ObjectName('_repr_html_')
467
467
468
468
469 class SVGFormatter(BaseFormatter):
469 class SVGFormatter(BaseFormatter):
470 """An SVG formatter.
470 """An SVG formatter.
471
471
472 To define the callables that compute the SVG representation of your
472 To define the callables that compute the SVG representation of your
473 objects, define a :meth:`_repr_svg_` method or use the :meth:`for_type`
473 objects, define a :meth:`_repr_svg_` method or use the :meth:`for_type`
474 or :meth:`for_type_by_name` methods to register functions that handle
474 or :meth:`for_type_by_name` methods to register functions that handle
475 this.
475 this.
476
476
477 The return value of this formatter should be valid SVG enclosed in
477 The return value of this formatter should be valid SVG enclosed in
478 ```<svg>``` tags, that could be injected into an existing DOM. It should
478 ```<svg>``` tags, that could be injected into an existing DOM. It should
479 *not* include the ```<html>`` or ```<body>`` tags.
479 *not* include the ```<html>`` or ```<body>`` tags.
480 """
480 """
481 format_type = Unicode('image/svg+xml')
481 format_type = Unicode('image/svg+xml')
482
482
483 print_method = ObjectName('_repr_svg_')
483 print_method = ObjectName('_repr_svg_')
484
484
485
485
486 class PNGFormatter(BaseFormatter):
486 class PNGFormatter(BaseFormatter):
487 """A PNG formatter.
487 """A PNG formatter.
488
488
489 To define the callables that compute the PNG representation of your
489 To define the callables that compute the PNG representation of your
490 objects, define a :meth:`_repr_png_` method or use the :meth:`for_type`
490 objects, define a :meth:`_repr_png_` method or use the :meth:`for_type`
491 or :meth:`for_type_by_name` methods to register functions that handle
491 or :meth:`for_type_by_name` methods to register functions that handle
492 this.
492 this.
493
493
494 The return value of this formatter should be raw PNG data, *not*
494 The return value of this formatter should be raw PNG data, *not*
495 base64 encoded.
495 base64 encoded.
496 """
496 """
497 format_type = Unicode('image/png')
497 format_type = Unicode('image/png')
498
498
499 print_method = ObjectName('_repr_png_')
499 print_method = ObjectName('_repr_png_')
500
500
501
501
502 class JPEGFormatter(BaseFormatter):
502 class JPEGFormatter(BaseFormatter):
503 """A JPEG formatter.
503 """A JPEG formatter.
504
504
505 To define the callables that compute the JPEG representation of your
505 To define the callables that compute the JPEG representation of your
506 objects, define a :meth:`_repr_jpeg_` method or use the :meth:`for_type`
506 objects, define a :meth:`_repr_jpeg_` method or use the :meth:`for_type`
507 or :meth:`for_type_by_name` methods to register functions that handle
507 or :meth:`for_type_by_name` methods to register functions that handle
508 this.
508 this.
509
509
510 The return value of this formatter should be raw JPEG data, *not*
510 The return value of this formatter should be raw JPEG data, *not*
511 base64 encoded.
511 base64 encoded.
512 """
512 """
513 format_type = Unicode('image/jpeg')
513 format_type = Unicode('image/jpeg')
514
514
515 print_method = ObjectName('_repr_jpeg_')
515 print_method = ObjectName('_repr_jpeg_')
516
516
517
517
518 class LatexFormatter(BaseFormatter):
518 class LatexFormatter(BaseFormatter):
519 """A LaTeX formatter.
519 """A LaTeX formatter.
520
520
521 To define the callables that compute the LaTeX representation of your
521 To define the callables that compute the LaTeX representation of your
522 objects, define a :meth:`_repr_latex_` method or use the :meth:`for_type`
522 objects, define a :meth:`_repr_latex_` method or use the :meth:`for_type`
523 or :meth:`for_type_by_name` methods to register functions that handle
523 or :meth:`for_type_by_name` methods to register functions that handle
524 this.
524 this.
525
525
526 The return value of this formatter should be a valid LaTeX equation,
526 The return value of this formatter should be a valid LaTeX equation,
527 enclosed in either ```$``` or ```$$```.
527 enclosed in either ```$``` or ```$$```.
528 """
528 """
529 format_type = Unicode('text/latex')
529 format_type = Unicode('text/latex')
530
530
531 print_method = ObjectName('_repr_latex_')
531 print_method = ObjectName('_repr_latex_')
532
532
533
533
534 class JSONFormatter(BaseFormatter):
534 class JSONFormatter(BaseFormatter):
535 """A JSON string formatter.
535 """A JSON string formatter.
536
536
537 To define the callables that compute the JSON string representation of
537 To define the callables that compute the JSON string representation of
538 your objects, define a :meth:`_repr_json_` method or use the :meth:`for_type`
538 your objects, define a :meth:`_repr_json_` method or use the :meth:`for_type`
539 or :meth:`for_type_by_name` methods to register functions that handle
539 or :meth:`for_type_by_name` methods to register functions that handle
540 this.
540 this.
541
541
542 The return value of this formatter should be a valid JSON string.
542 The return value of this formatter should be a valid JSON string.
543 """
543 """
544 format_type = Unicode('application/json')
544 format_type = Unicode('application/json')
545
545
546 print_method = ObjectName('_repr_json_')
546 print_method = ObjectName('_repr_json_')
547
547
548
548
549 class JavascriptFormatter(BaseFormatter):
549 class JavascriptFormatter(BaseFormatter):
550 """A Javascript formatter.
550 """A Javascript formatter.
551
551
552 To define the callables that compute the Javascript representation of
552 To define the callables that compute the Javascript representation of
553 your objects, define a :meth:`_repr_javascript_` method or use the
553 your objects, define a :meth:`_repr_javascript_` method or use the
554 :meth:`for_type` or :meth:`for_type_by_name` methods to register functions
554 :meth:`for_type` or :meth:`for_type_by_name` methods to register functions
555 that handle this.
555 that handle this.
556
556
557 The return value of this formatter should be valid Javascript code and
557 The return value of this formatter should be valid Javascript code and
558 should *not* be enclosed in ```<script>``` tags.
558 should *not* be enclosed in ```<script>``` tags.
559 """
559 """
560 format_type = Unicode('application/javascript')
560 format_type = Unicode('application/javascript')
561
561
562 print_method = ObjectName('_repr_javascript_')
562 print_method = ObjectName('_repr_javascript_')
563
563
564 FormatterABC.register(BaseFormatter)
564 FormatterABC.register(BaseFormatter)
565 FormatterABC.register(PlainTextFormatter)
565 FormatterABC.register(PlainTextFormatter)
566 FormatterABC.register(HTMLFormatter)
566 FormatterABC.register(HTMLFormatter)
567 FormatterABC.register(SVGFormatter)
567 FormatterABC.register(SVGFormatter)
568 FormatterABC.register(PNGFormatter)
568 FormatterABC.register(PNGFormatter)
569 FormatterABC.register(JPEGFormatter)
569 FormatterABC.register(JPEGFormatter)
570 FormatterABC.register(LatexFormatter)
570 FormatterABC.register(LatexFormatter)
571 FormatterABC.register(JSONFormatter)
571 FormatterABC.register(JSONFormatter)
572 FormatterABC.register(JavascriptFormatter)
572 FormatterABC.register(JavascriptFormatter)
573
573
574
574
575 def format_display_data(obj, include=None, exclude=None):
575 def format_display_data(obj, include=None, exclude=None):
576 """Return a format data dict for an object.
576 """Return a format data dict for an object.
577
577
578 By default all format types will be computed.
578 By default all format types will be computed.
579
579
580 The following MIME types are currently implemented:
580 The following MIME types are currently implemented:
581
581
582 * text/plain
582 * text/plain
583 * text/html
583 * text/html
584 * text/latex
584 * text/latex
585 * application/json
585 * application/json
586 * application/javascript
586 * application/javascript
587 * image/png
587 * image/png
588 * image/jpeg
588 * image/jpeg
589 * image/svg+xml
589 * image/svg+xml
590
590
591 Parameters
591 Parameters
592 ----------
592 ----------
593 obj : object
593 obj : object
594 The Python object whose format data will be computed.
594 The Python object whose format data will be computed.
595
595
596 Returns
596 Returns
597 -------
597 -------
598 format_dict : dict
598 format_dict : dict
599 A dictionary of key/value pairs, one or each format that was
599 A dictionary of key/value pairs, one or each format that was
600 generated for the object. The keys are the format types, which
600 generated for the object. The keys are the format types, which
601 will usually be MIME type strings and the values and JSON'able
601 will usually be MIME type strings and the values and JSON'able
602 data structure containing the raw data for the representation in
602 data structure containing the raw data for the representation in
603 that format.
603 that format.
604 include : list or tuple, optional
604 include : list or tuple, optional
605 A list of format type strings (MIME types) to include in the
605 A list of format type strings (MIME types) to include in the
606 format data dict. If this is set *only* the format types included
606 format data dict. If this is set *only* the format types included
607 in this list will be computed.
607 in this list will be computed.
608 exclude : list or tuple, optional
608 exclude : list or tuple, optional
609 A list of format type string (MIME types) to exclue in the format
609 A list of format type string (MIME types) to exclue in the format
610 data dict. If this is set all format types will be computed,
610 data dict. If this is set all format types will be computed,
611 except for those included in this argument.
611 except for those included in this argument.
612 """
612 """
613 from IPython.core.interactiveshell import InteractiveShell
613 from IPython.core.interactiveshell import InteractiveShell
614
614
615 InteractiveShell.instance().display_formatter.format(
615 InteractiveShell.instance().display_formatter.format(
616 obj,
616 obj,
617 include,
617 include,
618 exclude
618 exclude
619 )
619 )
620
620
@@ -1,967 +1,967 b''
1 """ History related magics and functionality """
1 """ History related magics and functionality """
2 #-----------------------------------------------------------------------------
2 #-----------------------------------------------------------------------------
3 # Copyright (C) 2010 The IPython Development Team.
3 # Copyright (C) 2010-2011 The IPython Development Team.
4 #
4 #
5 # Distributed under the terms of the BSD License.
5 # Distributed under the terms of the BSD License.
6 #
6 #
7 # The full license is in the file COPYING.txt, distributed with this software.
7 # The full license is in the file COPYING.txt, distributed with this software.
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Imports
11 # Imports
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 from __future__ import print_function
13 from __future__ import print_function
14
14
15 # Stdlib imports
15 # Stdlib imports
16 import atexit
16 import atexit
17 import datetime
17 import datetime
18 import os
18 import os
19 import re
19 import re
20 try:
20 try:
21 import sqlite3
21 import sqlite3
22 except ImportError:
22 except ImportError:
23 sqlite3 = None
23 sqlite3 = None
24 import threading
24 import threading
25
25
26 # Our own packages
26 # Our own packages
27 from IPython.config.configurable import Configurable
27 from IPython.config.configurable import Configurable
28 from IPython.external.decorator import decorator
28 from IPython.external.decorator import decorator
29 from IPython.testing.skipdoctest import skip_doctest
29 from IPython.testing.skipdoctest import skip_doctest
30 from IPython.utils import io
30 from IPython.utils import io
31 from IPython.utils.path import locate_profile
31 from IPython.utils.path import locate_profile
32 from IPython.utils.traitlets import Bool, Dict, Instance, Integer, List, Unicode
32 from IPython.utils.traitlets import Bool, Dict, Instance, Integer, List, Unicode
33 from IPython.utils.warn import warn
33 from IPython.utils.warn import warn
34
34
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36 # Classes and functions
36 # Classes and functions
37 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
38
38
39 class DummyDB(object):
39 class DummyDB(object):
40 """Dummy DB that will act as a black hole for history.
40 """Dummy DB that will act as a black hole for history.
41
41
42 Only used in the absence of sqlite"""
42 Only used in the absence of sqlite"""
43 def execute(*args, **kwargs):
43 def execute(*args, **kwargs):
44 return []
44 return []
45
45
46 def commit(self, *args, **kwargs):
46 def commit(self, *args, **kwargs):
47 pass
47 pass
48
48
49 def __enter__(self, *args, **kwargs):
49 def __enter__(self, *args, **kwargs):
50 pass
50 pass
51
51
52 def __exit__(self, *args, **kwargs):
52 def __exit__(self, *args, **kwargs):
53 pass
53 pass
54
54
55 @decorator
55 @decorator
56 def needs_sqlite(f,*a,**kw):
56 def needs_sqlite(f,*a,**kw):
57 """return an empty list in the absence of sqlite"""
57 """return an empty list in the absence of sqlite"""
58 if sqlite3 is None:
58 if sqlite3 is None:
59 return []
59 return []
60 else:
60 else:
61 return f(*a,**kw)
61 return f(*a,**kw)
62
62
63 class HistoryAccessor(Configurable):
63 class HistoryAccessor(Configurable):
64 """Access the history database without adding to it.
64 """Access the history database without adding to it.
65
65
66 This is intended for use by standalone history tools. IPython shells use
66 This is intended for use by standalone history tools. IPython shells use
67 HistoryManager, below, which is a subclass of this."""
67 HistoryManager, below, which is a subclass of this."""
68
68
69 # String holding the path to the history file
69 # String holding the path to the history file
70 hist_file = Unicode(config=True,
70 hist_file = Unicode(config=True,
71 help="""Path to file to use for SQLite history database.
71 help="""Path to file to use for SQLite history database.
72
72
73 By default, IPython will put the history database in the IPython profile
73 By default, IPython will put the history database in the IPython profile
74 directory. If you would rather share one history among profiles,
74 directory. If you would rather share one history among profiles,
75 you ca set this value in each, so that they are consistent.
75 you ca set this value in each, so that they are consistent.
76
76
77 Due to an issue with fcntl, SQLite is known to misbehave on some NFS mounts.
77 Due to an issue with fcntl, SQLite is known to misbehave on some NFS mounts.
78 If you see IPython hanging, try setting this to something on a local disk,
78 If you see IPython hanging, try setting this to something on a local disk,
79 e.g::
79 e.g::
80
80
81 ipython --HistoryManager.hist_file=/tmp/ipython_hist.sqlite
81 ipython --HistoryManager.hist_file=/tmp/ipython_hist.sqlite
82
82
83 """)
83 """)
84
84
85
85
86 # The SQLite database
86 # The SQLite database
87 if sqlite3:
87 if sqlite3:
88 db = Instance(sqlite3.Connection)
88 db = Instance(sqlite3.Connection)
89 else:
89 else:
90 db = Instance(DummyDB)
90 db = Instance(DummyDB)
91
91
92 def __init__(self, profile='default', hist_file=u'', config=None, **traits):
92 def __init__(self, profile='default', hist_file=u'', config=None, **traits):
93 """Create a new history accessor.
93 """Create a new history accessor.
94
94
95 Parameters
95 Parameters
96 ----------
96 ----------
97 profile : str
97 profile : str
98 The name of the profile from which to open history.
98 The name of the profile from which to open history.
99 hist_file : str
99 hist_file : str
100 Path to an SQLite history database stored by IPython. If specified,
100 Path to an SQLite history database stored by IPython. If specified,
101 hist_file overrides profile.
101 hist_file overrides profile.
102 config :
102 config :
103 Config object. hist_file can also be set through this.
103 Config object. hist_file can also be set through this.
104 """
104 """
105 # We need a pointer back to the shell for various tasks.
105 # We need a pointer back to the shell for various tasks.
106 super(HistoryAccessor, self).__init__(config=config, **traits)
106 super(HistoryAccessor, self).__init__(config=config, **traits)
107 # defer setting hist_file from kwarg until after init,
107 # defer setting hist_file from kwarg until after init,
108 # otherwise the default kwarg value would clobber any value
108 # otherwise the default kwarg value would clobber any value
109 # set by config
109 # set by config
110 if hist_file:
110 if hist_file:
111 self.hist_file = hist_file
111 self.hist_file = hist_file
112
112
113 if self.hist_file == u'':
113 if self.hist_file == u'':
114 # No one has set the hist_file, yet.
114 # No one has set the hist_file, yet.
115 self.hist_file = self._get_hist_file_name(profile)
115 self.hist_file = self._get_hist_file_name(profile)
116
116
117 if sqlite3 is None:
117 if sqlite3 is None:
118 warn("IPython History requires SQLite, your history will not be saved\n")
118 warn("IPython History requires SQLite, your history will not be saved\n")
119 self.db = DummyDB()
119 self.db = DummyDB()
120 return
120 return
121
121
122 try:
122 try:
123 self.init_db()
123 self.init_db()
124 except sqlite3.DatabaseError:
124 except sqlite3.DatabaseError:
125 if os.path.isfile(self.hist_file):
125 if os.path.isfile(self.hist_file):
126 # Try to move the file out of the way
126 # Try to move the file out of the way
127 base,ext = os.path.splitext(self.hist_file)
127 base,ext = os.path.splitext(self.hist_file)
128 newpath = base + '-corrupt' + ext
128 newpath = base + '-corrupt' + ext
129 os.rename(self.hist_file, newpath)
129 os.rename(self.hist_file, newpath)
130 print("ERROR! History file wasn't a valid SQLite database.",
130 print("ERROR! History file wasn't a valid SQLite database.",
131 "It was moved to %s" % newpath, "and a new file created.")
131 "It was moved to %s" % newpath, "and a new file created.")
132 self.init_db()
132 self.init_db()
133 else:
133 else:
134 # The hist_file is probably :memory: or something else.
134 # The hist_file is probably :memory: or something else.
135 raise
135 raise
136
136
137 def _get_hist_file_name(self, profile='default'):
137 def _get_hist_file_name(self, profile='default'):
138 """Find the history file for the given profile name.
138 """Find the history file for the given profile name.
139
139
140 This is overridden by the HistoryManager subclass, to use the shell's
140 This is overridden by the HistoryManager subclass, to use the shell's
141 active profile.
141 active profile.
142
142
143 Parameters
143 Parameters
144 ----------
144 ----------
145 profile : str
145 profile : str
146 The name of a profile which has a history file.
146 The name of a profile which has a history file.
147 """
147 """
148 return os.path.join(locate_profile(profile), 'history.sqlite')
148 return os.path.join(locate_profile(profile), 'history.sqlite')
149
149
150 def init_db(self):
150 def init_db(self):
151 """Connect to the database, and create tables if necessary."""
151 """Connect to the database, and create tables if necessary."""
152 # use detect_types so that timestamps return datetime objects
152 # use detect_types so that timestamps return datetime objects
153 self.db = sqlite3.connect(self.hist_file, detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
153 self.db = sqlite3.connect(self.hist_file, detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
154 self.db.execute("""CREATE TABLE IF NOT EXISTS sessions (session integer
154 self.db.execute("""CREATE TABLE IF NOT EXISTS sessions (session integer
155 primary key autoincrement, start timestamp,
155 primary key autoincrement, start timestamp,
156 end timestamp, num_cmds integer, remark text)""")
156 end timestamp, num_cmds integer, remark text)""")
157 self.db.execute("""CREATE TABLE IF NOT EXISTS history
157 self.db.execute("""CREATE TABLE IF NOT EXISTS history
158 (session integer, line integer, source text, source_raw text,
158 (session integer, line integer, source text, source_raw text,
159 PRIMARY KEY (session, line))""")
159 PRIMARY KEY (session, line))""")
160 # Output history is optional, but ensure the table's there so it can be
160 # Output history is optional, but ensure the table's there so it can be
161 # enabled later.
161 # enabled later.
162 self.db.execute("""CREATE TABLE IF NOT EXISTS output_history
162 self.db.execute("""CREATE TABLE IF NOT EXISTS output_history
163 (session integer, line integer, output text,
163 (session integer, line integer, output text,
164 PRIMARY KEY (session, line))""")
164 PRIMARY KEY (session, line))""")
165 self.db.commit()
165 self.db.commit()
166
166
167 def writeout_cache(self):
167 def writeout_cache(self):
168 """Overridden by HistoryManager to dump the cache before certain
168 """Overridden by HistoryManager to dump the cache before certain
169 database lookups."""
169 database lookups."""
170 pass
170 pass
171
171
172 ## -------------------------------
172 ## -------------------------------
173 ## Methods for retrieving history:
173 ## Methods for retrieving history:
174 ## -------------------------------
174 ## -------------------------------
175 def _run_sql(self, sql, params, raw=True, output=False):
175 def _run_sql(self, sql, params, raw=True, output=False):
176 """Prepares and runs an SQL query for the history database.
176 """Prepares and runs an SQL query for the history database.
177
177
178 Parameters
178 Parameters
179 ----------
179 ----------
180 sql : str
180 sql : str
181 Any filtering expressions to go after SELECT ... FROM ...
181 Any filtering expressions to go after SELECT ... FROM ...
182 params : tuple
182 params : tuple
183 Parameters passed to the SQL query (to replace "?")
183 Parameters passed to the SQL query (to replace "?")
184 raw, output : bool
184 raw, output : bool
185 See :meth:`get_range`
185 See :meth:`get_range`
186
186
187 Returns
187 Returns
188 -------
188 -------
189 Tuples as :meth:`get_range`
189 Tuples as :meth:`get_range`
190 """
190 """
191 toget = 'source_raw' if raw else 'source'
191 toget = 'source_raw' if raw else 'source'
192 sqlfrom = "history"
192 sqlfrom = "history"
193 if output:
193 if output:
194 sqlfrom = "history LEFT JOIN output_history USING (session, line)"
194 sqlfrom = "history LEFT JOIN output_history USING (session, line)"
195 toget = "history.%s, output_history.output" % toget
195 toget = "history.%s, output_history.output" % toget
196 cur = self.db.execute("SELECT session, line, %s FROM %s " %\
196 cur = self.db.execute("SELECT session, line, %s FROM %s " %\
197 (toget, sqlfrom) + sql, params)
197 (toget, sqlfrom) + sql, params)
198 if output: # Regroup into 3-tuples, and parse JSON
198 if output: # Regroup into 3-tuples, and parse JSON
199 return ((ses, lin, (inp, out)) for ses, lin, inp, out in cur)
199 return ((ses, lin, (inp, out)) for ses, lin, inp, out in cur)
200 return cur
200 return cur
201
201
202 @needs_sqlite
202 @needs_sqlite
203 def get_session_info(self, session=0):
203 def get_session_info(self, session=0):
204 """get info about a session
204 """get info about a session
205
205
206 Parameters
206 Parameters
207 ----------
207 ----------
208
208
209 session : int
209 session : int
210 Session number to retrieve. The current session is 0, and negative
210 Session number to retrieve. The current session is 0, and negative
211 numbers count back from current session, so -1 is previous session.
211 numbers count back from current session, so -1 is previous session.
212
212
213 Returns
213 Returns
214 -------
214 -------
215
215
216 (session_id [int], start [datetime], end [datetime], num_cmds [int], remark [unicode])
216 (session_id [int], start [datetime], end [datetime], num_cmds [int], remark [unicode])
217
217
218 Sessions that are running or did not exit cleanly will have `end=None`
218 Sessions that are running or did not exit cleanly will have `end=None`
219 and `num_cmds=None`.
219 and `num_cmds=None`.
220
220
221 """
221 """
222
222
223 if session <= 0:
223 if session <= 0:
224 session += self.session_number
224 session += self.session_number
225
225
226 query = "SELECT * from sessions where session == ?"
226 query = "SELECT * from sessions where session == ?"
227 return self.db.execute(query, (session,)).fetchone()
227 return self.db.execute(query, (session,)).fetchone()
228
228
229 def get_tail(self, n=10, raw=True, output=False, include_latest=False):
229 def get_tail(self, n=10, raw=True, output=False, include_latest=False):
230 """Get the last n lines from the history database.
230 """Get the last n lines from the history database.
231
231
232 Parameters
232 Parameters
233 ----------
233 ----------
234 n : int
234 n : int
235 The number of lines to get
235 The number of lines to get
236 raw, output : bool
236 raw, output : bool
237 See :meth:`get_range`
237 See :meth:`get_range`
238 include_latest : bool
238 include_latest : bool
239 If False (default), n+1 lines are fetched, and the latest one
239 If False (default), n+1 lines are fetched, and the latest one
240 is discarded. This is intended to be used where the function
240 is discarded. This is intended to be used where the function
241 is called by a user command, which it should not return.
241 is called by a user command, which it should not return.
242
242
243 Returns
243 Returns
244 -------
244 -------
245 Tuples as :meth:`get_range`
245 Tuples as :meth:`get_range`
246 """
246 """
247 self.writeout_cache()
247 self.writeout_cache()
248 if not include_latest:
248 if not include_latest:
249 n += 1
249 n += 1
250 cur = self._run_sql("ORDER BY session DESC, line DESC LIMIT ?",
250 cur = self._run_sql("ORDER BY session DESC, line DESC LIMIT ?",
251 (n,), raw=raw, output=output)
251 (n,), raw=raw, output=output)
252 if not include_latest:
252 if not include_latest:
253 return reversed(list(cur)[1:])
253 return reversed(list(cur)[1:])
254 return reversed(list(cur))
254 return reversed(list(cur))
255
255
256 def search(self, pattern="*", raw=True, search_raw=True,
256 def search(self, pattern="*", raw=True, search_raw=True,
257 output=False):
257 output=False):
258 """Search the database using unix glob-style matching (wildcards
258 """Search the database using unix glob-style matching (wildcards
259 * and ?).
259 * and ?).
260
260
261 Parameters
261 Parameters
262 ----------
262 ----------
263 pattern : str
263 pattern : str
264 The wildcarded pattern to match when searching
264 The wildcarded pattern to match when searching
265 search_raw : bool
265 search_raw : bool
266 If True, search the raw input, otherwise, the parsed input
266 If True, search the raw input, otherwise, the parsed input
267 raw, output : bool
267 raw, output : bool
268 See :meth:`get_range`
268 See :meth:`get_range`
269
269
270 Returns
270 Returns
271 -------
271 -------
272 Tuples as :meth:`get_range`
272 Tuples as :meth:`get_range`
273 """
273 """
274 tosearch = "source_raw" if search_raw else "source"
274 tosearch = "source_raw" if search_raw else "source"
275 if output:
275 if output:
276 tosearch = "history." + tosearch
276 tosearch = "history." + tosearch
277 self.writeout_cache()
277 self.writeout_cache()
278 return self._run_sql("WHERE %s GLOB ?" % tosearch, (pattern,),
278 return self._run_sql("WHERE %s GLOB ?" % tosearch, (pattern,),
279 raw=raw, output=output)
279 raw=raw, output=output)
280
280
281 def get_range(self, session, start=1, stop=None, raw=True,output=False):
281 def get_range(self, session, start=1, stop=None, raw=True,output=False):
282 """Retrieve input by session.
282 """Retrieve input by session.
283
283
284 Parameters
284 Parameters
285 ----------
285 ----------
286 session : int
286 session : int
287 Session number to retrieve.
287 Session number to retrieve.
288 start : int
288 start : int
289 First line to retrieve.
289 First line to retrieve.
290 stop : int
290 stop : int
291 End of line range (excluded from output itself). If None, retrieve
291 End of line range (excluded from output itself). If None, retrieve
292 to the end of the session.
292 to the end of the session.
293 raw : bool
293 raw : bool
294 If True, return untranslated input
294 If True, return untranslated input
295 output : bool
295 output : bool
296 If True, attempt to include output. This will be 'real' Python
296 If True, attempt to include output. This will be 'real' Python
297 objects for the current session, or text reprs from previous
297 objects for the current session, or text reprs from previous
298 sessions if db_log_output was enabled at the time. Where no output
298 sessions if db_log_output was enabled at the time. Where no output
299 is found, None is used.
299 is found, None is used.
300
300
301 Returns
301 Returns
302 -------
302 -------
303 An iterator over the desired lines. Each line is a 3-tuple, either
303 An iterator over the desired lines. Each line is a 3-tuple, either
304 (session, line, input) if output is False, or
304 (session, line, input) if output is False, or
305 (session, line, (input, output)) if output is True.
305 (session, line, (input, output)) if output is True.
306 """
306 """
307 if stop:
307 if stop:
308 lineclause = "line >= ? AND line < ?"
308 lineclause = "line >= ? AND line < ?"
309 params = (session, start, stop)
309 params = (session, start, stop)
310 else:
310 else:
311 lineclause = "line>=?"
311 lineclause = "line>=?"
312 params = (session, start)
312 params = (session, start)
313
313
314 return self._run_sql("WHERE session==? AND %s""" % lineclause,
314 return self._run_sql("WHERE session==? AND %s""" % lineclause,
315 params, raw=raw, output=output)
315 params, raw=raw, output=output)
316
316
317 def get_range_by_str(self, rangestr, raw=True, output=False):
317 def get_range_by_str(self, rangestr, raw=True, output=False):
318 """Get lines of history from a string of ranges, as used by magic
318 """Get lines of history from a string of ranges, as used by magic
319 commands %hist, %save, %macro, etc.
319 commands %hist, %save, %macro, etc.
320
320
321 Parameters
321 Parameters
322 ----------
322 ----------
323 rangestr : str
323 rangestr : str
324 A string specifying ranges, e.g. "5 ~2/1-4". See
324 A string specifying ranges, e.g. "5 ~2/1-4". See
325 :func:`magic_history` for full details.
325 :func:`magic_history` for full details.
326 raw, output : bool
326 raw, output : bool
327 As :meth:`get_range`
327 As :meth:`get_range`
328
328
329 Returns
329 Returns
330 -------
330 -------
331 Tuples as :meth:`get_range`
331 Tuples as :meth:`get_range`
332 """
332 """
333 for sess, s, e in extract_hist_ranges(rangestr):
333 for sess, s, e in extract_hist_ranges(rangestr):
334 for line in self.get_range(sess, s, e, raw=raw, output=output):
334 for line in self.get_range(sess, s, e, raw=raw, output=output):
335 yield line
335 yield line
336
336
337
337
338 class HistoryManager(HistoryAccessor):
338 class HistoryManager(HistoryAccessor):
339 """A class to organize all history-related functionality in one place.
339 """A class to organize all history-related functionality in one place.
340 """
340 """
341 # Public interface
341 # Public interface
342
342
343 # An instance of the IPython shell we are attached to
343 # An instance of the IPython shell we are attached to
344 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
344 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
345 # Lists to hold processed and raw history. These start with a blank entry
345 # Lists to hold processed and raw history. These start with a blank entry
346 # so that we can index them starting from 1
346 # so that we can index them starting from 1
347 input_hist_parsed = List([""])
347 input_hist_parsed = List([""])
348 input_hist_raw = List([""])
348 input_hist_raw = List([""])
349 # A list of directories visited during session
349 # A list of directories visited during session
350 dir_hist = List()
350 dir_hist = List()
351 def _dir_hist_default(self):
351 def _dir_hist_default(self):
352 try:
352 try:
353 return [os.getcwdu()]
353 return [os.getcwdu()]
354 except OSError:
354 except OSError:
355 return []
355 return []
356
356
357 # A dict of output history, keyed with ints from the shell's
357 # A dict of output history, keyed with ints from the shell's
358 # execution count.
358 # execution count.
359 output_hist = Dict()
359 output_hist = Dict()
360 # The text/plain repr of outputs.
360 # The text/plain repr of outputs.
361 output_hist_reprs = Dict()
361 output_hist_reprs = Dict()
362
362
363 # The number of the current session in the history database
363 # The number of the current session in the history database
364 session_number = Integer()
364 session_number = Integer()
365 # Should we log output to the database? (default no)
365 # Should we log output to the database? (default no)
366 db_log_output = Bool(False, config=True)
366 db_log_output = Bool(False, config=True)
367 # Write to database every x commands (higher values save disk access & power)
367 # Write to database every x commands (higher values save disk access & power)
368 # Values of 1 or less effectively disable caching.
368 # Values of 1 or less effectively disable caching.
369 db_cache_size = Integer(0, config=True)
369 db_cache_size = Integer(0, config=True)
370 # The input and output caches
370 # The input and output caches
371 db_input_cache = List()
371 db_input_cache = List()
372 db_output_cache = List()
372 db_output_cache = List()
373
373
374 # History saving in separate thread
374 # History saving in separate thread
375 save_thread = Instance('IPython.core.history.HistorySavingThread')
375 save_thread = Instance('IPython.core.history.HistorySavingThread')
376 try: # Event is a function returning an instance of _Event...
376 try: # Event is a function returning an instance of _Event...
377 save_flag = Instance(threading._Event)
377 save_flag = Instance(threading._Event)
378 except AttributeError: # ...until Python 3.3, when it's a class.
378 except AttributeError: # ...until Python 3.3, when it's a class.
379 save_flag = Instance(threading.Event)
379 save_flag = Instance(threading.Event)
380
380
381 # Private interface
381 # Private interface
382 # Variables used to store the three last inputs from the user. On each new
382 # Variables used to store the three last inputs from the user. On each new
383 # history update, we populate the user's namespace with these, shifted as
383 # history update, we populate the user's namespace with these, shifted as
384 # necessary.
384 # necessary.
385 _i00 = Unicode(u'')
385 _i00 = Unicode(u'')
386 _i = Unicode(u'')
386 _i = Unicode(u'')
387 _ii = Unicode(u'')
387 _ii = Unicode(u'')
388 _iii = Unicode(u'')
388 _iii = Unicode(u'')
389
389
390 # A regex matching all forms of the exit command, so that we don't store
390 # A regex matching all forms of the exit command, so that we don't store
391 # them in the history (it's annoying to rewind the first entry and land on
391 # them in the history (it's annoying to rewind the first entry and land on
392 # an exit call).
392 # an exit call).
393 _exit_re = re.compile(r"(exit|quit)(\s*\(.*\))?$")
393 _exit_re = re.compile(r"(exit|quit)(\s*\(.*\))?$")
394
394
395 def __init__(self, shell=None, config=None, **traits):
395 def __init__(self, shell=None, config=None, **traits):
396 """Create a new history manager associated with a shell instance.
396 """Create a new history manager associated with a shell instance.
397 """
397 """
398 # We need a pointer back to the shell for various tasks.
398 # We need a pointer back to the shell for various tasks.
399 super(HistoryManager, self).__init__(shell=shell, config=config,
399 super(HistoryManager, self).__init__(shell=shell, config=config,
400 **traits)
400 **traits)
401 self.save_flag = threading.Event()
401 self.save_flag = threading.Event()
402 self.db_input_cache_lock = threading.Lock()
402 self.db_input_cache_lock = threading.Lock()
403 self.db_output_cache_lock = threading.Lock()
403 self.db_output_cache_lock = threading.Lock()
404 self.save_thread = HistorySavingThread(self)
404 self.save_thread = HistorySavingThread(self)
405 self.save_thread.start()
405 self.save_thread.start()
406
406
407 self.new_session()
407 self.new_session()
408
408
409 def _get_hist_file_name(self, profile=None):
409 def _get_hist_file_name(self, profile=None):
410 """Get default history file name based on the Shell's profile.
410 """Get default history file name based on the Shell's profile.
411
411
412 The profile parameter is ignored, but must exist for compatibility with
412 The profile parameter is ignored, but must exist for compatibility with
413 the parent class."""
413 the parent class."""
414 profile_dir = self.shell.profile_dir.location
414 profile_dir = self.shell.profile_dir.location
415 return os.path.join(profile_dir, 'history.sqlite')
415 return os.path.join(profile_dir, 'history.sqlite')
416
416
417 @needs_sqlite
417 @needs_sqlite
418 def new_session(self, conn=None):
418 def new_session(self, conn=None):
419 """Get a new session number."""
419 """Get a new session number."""
420 if conn is None:
420 if conn is None:
421 conn = self.db
421 conn = self.db
422
422
423 with conn:
423 with conn:
424 cur = conn.execute("""INSERT INTO sessions VALUES (NULL, ?, NULL,
424 cur = conn.execute("""INSERT INTO sessions VALUES (NULL, ?, NULL,
425 NULL, "") """, (datetime.datetime.now(),))
425 NULL, "") """, (datetime.datetime.now(),))
426 self.session_number = cur.lastrowid
426 self.session_number = cur.lastrowid
427
427
428 def end_session(self):
428 def end_session(self):
429 """Close the database session, filling in the end time and line count."""
429 """Close the database session, filling in the end time and line count."""
430 self.writeout_cache()
430 self.writeout_cache()
431 with self.db:
431 with self.db:
432 self.db.execute("""UPDATE sessions SET end=?, num_cmds=? WHERE
432 self.db.execute("""UPDATE sessions SET end=?, num_cmds=? WHERE
433 session==?""", (datetime.datetime.now(),
433 session==?""", (datetime.datetime.now(),
434 len(self.input_hist_parsed)-1, self.session_number))
434 len(self.input_hist_parsed)-1, self.session_number))
435 self.session_number = 0
435 self.session_number = 0
436
436
437 def name_session(self, name):
437 def name_session(self, name):
438 """Give the current session a name in the history database."""
438 """Give the current session a name in the history database."""
439 with self.db:
439 with self.db:
440 self.db.execute("UPDATE sessions SET remark=? WHERE session==?",
440 self.db.execute("UPDATE sessions SET remark=? WHERE session==?",
441 (name, self.session_number))
441 (name, self.session_number))
442
442
443 def reset(self, new_session=True):
443 def reset(self, new_session=True):
444 """Clear the session history, releasing all object references, and
444 """Clear the session history, releasing all object references, and
445 optionally open a new session."""
445 optionally open a new session."""
446 self.output_hist.clear()
446 self.output_hist.clear()
447 # The directory history can't be completely empty
447 # The directory history can't be completely empty
448 self.dir_hist[:] = [os.getcwdu()]
448 self.dir_hist[:] = [os.getcwdu()]
449
449
450 if new_session:
450 if new_session:
451 if self.session_number:
451 if self.session_number:
452 self.end_session()
452 self.end_session()
453 self.input_hist_parsed[:] = [""]
453 self.input_hist_parsed[:] = [""]
454 self.input_hist_raw[:] = [""]
454 self.input_hist_raw[:] = [""]
455 self.new_session()
455 self.new_session()
456
456
457 # ------------------------------
457 # ------------------------------
458 # Methods for retrieving history
458 # Methods for retrieving history
459 # ------------------------------
459 # ------------------------------
460 def _get_range_session(self, start=1, stop=None, raw=True, output=False):
460 def _get_range_session(self, start=1, stop=None, raw=True, output=False):
461 """Get input and output history from the current session. Called by
461 """Get input and output history from the current session. Called by
462 get_range, and takes similar parameters."""
462 get_range, and takes similar parameters."""
463 input_hist = self.input_hist_raw if raw else self.input_hist_parsed
463 input_hist = self.input_hist_raw if raw else self.input_hist_parsed
464
464
465 n = len(input_hist)
465 n = len(input_hist)
466 if start < 0:
466 if start < 0:
467 start += n
467 start += n
468 if not stop or (stop > n):
468 if not stop or (stop > n):
469 stop = n
469 stop = n
470 elif stop < 0:
470 elif stop < 0:
471 stop += n
471 stop += n
472
472
473 for i in range(start, stop):
473 for i in range(start, stop):
474 if output:
474 if output:
475 line = (input_hist[i], self.output_hist_reprs.get(i))
475 line = (input_hist[i], self.output_hist_reprs.get(i))
476 else:
476 else:
477 line = input_hist[i]
477 line = input_hist[i]
478 yield (0, i, line)
478 yield (0, i, line)
479
479
480 def get_range(self, session=0, start=1, stop=None, raw=True,output=False):
480 def get_range(self, session=0, start=1, stop=None, raw=True,output=False):
481 """Retrieve input by session.
481 """Retrieve input by session.
482
482
483 Parameters
483 Parameters
484 ----------
484 ----------
485 session : int
485 session : int
486 Session number to retrieve. The current session is 0, and negative
486 Session number to retrieve. The current session is 0, and negative
487 numbers count back from current session, so -1 is previous session.
487 numbers count back from current session, so -1 is previous session.
488 start : int
488 start : int
489 First line to retrieve.
489 First line to retrieve.
490 stop : int
490 stop : int
491 End of line range (excluded from output itself). If None, retrieve
491 End of line range (excluded from output itself). If None, retrieve
492 to the end of the session.
492 to the end of the session.
493 raw : bool
493 raw : bool
494 If True, return untranslated input
494 If True, return untranslated input
495 output : bool
495 output : bool
496 If True, attempt to include output. This will be 'real' Python
496 If True, attempt to include output. This will be 'real' Python
497 objects for the current session, or text reprs from previous
497 objects for the current session, or text reprs from previous
498 sessions if db_log_output was enabled at the time. Where no output
498 sessions if db_log_output was enabled at the time. Where no output
499 is found, None is used.
499 is found, None is used.
500
500
501 Returns
501 Returns
502 -------
502 -------
503 An iterator over the desired lines. Each line is a 3-tuple, either
503 An iterator over the desired lines. Each line is a 3-tuple, either
504 (session, line, input) if output is False, or
504 (session, line, input) if output is False, or
505 (session, line, (input, output)) if output is True.
505 (session, line, (input, output)) if output is True.
506 """
506 """
507 if session <= 0:
507 if session <= 0:
508 session += self.session_number
508 session += self.session_number
509 if session==self.session_number: # Current session
509 if session==self.session_number: # Current session
510 return self._get_range_session(start, stop, raw, output)
510 return self._get_range_session(start, stop, raw, output)
511 return super(HistoryManager, self).get_range(session, start, stop, raw, output)
511 return super(HistoryManager, self).get_range(session, start, stop, raw, output)
512
512
513 ## ----------------------------
513 ## ----------------------------
514 ## Methods for storing history:
514 ## Methods for storing history:
515 ## ----------------------------
515 ## ----------------------------
516 def store_inputs(self, line_num, source, source_raw=None):
516 def store_inputs(self, line_num, source, source_raw=None):
517 """Store source and raw input in history and create input cache
517 """Store source and raw input in history and create input cache
518 variables _i*.
518 variables _i*.
519
519
520 Parameters
520 Parameters
521 ----------
521 ----------
522 line_num : int
522 line_num : int
523 The prompt number of this input.
523 The prompt number of this input.
524
524
525 source : str
525 source : str
526 Python input.
526 Python input.
527
527
528 source_raw : str, optional
528 source_raw : str, optional
529 If given, this is the raw input without any IPython transformations
529 If given, this is the raw input without any IPython transformations
530 applied to it. If not given, ``source`` is used.
530 applied to it. If not given, ``source`` is used.
531 """
531 """
532 if source_raw is None:
532 if source_raw is None:
533 source_raw = source
533 source_raw = source
534 source = source.rstrip('\n')
534 source = source.rstrip('\n')
535 source_raw = source_raw.rstrip('\n')
535 source_raw = source_raw.rstrip('\n')
536
536
537 # do not store exit/quit commands
537 # do not store exit/quit commands
538 if self._exit_re.match(source_raw.strip()):
538 if self._exit_re.match(source_raw.strip()):
539 return
539 return
540
540
541 self.input_hist_parsed.append(source)
541 self.input_hist_parsed.append(source)
542 self.input_hist_raw.append(source_raw)
542 self.input_hist_raw.append(source_raw)
543
543
544 with self.db_input_cache_lock:
544 with self.db_input_cache_lock:
545 self.db_input_cache.append((line_num, source, source_raw))
545 self.db_input_cache.append((line_num, source, source_raw))
546 # Trigger to flush cache and write to DB.
546 # Trigger to flush cache and write to DB.
547 if len(self.db_input_cache) >= self.db_cache_size:
547 if len(self.db_input_cache) >= self.db_cache_size:
548 self.save_flag.set()
548 self.save_flag.set()
549
549
550 # update the auto _i variables
550 # update the auto _i variables
551 self._iii = self._ii
551 self._iii = self._ii
552 self._ii = self._i
552 self._ii = self._i
553 self._i = self._i00
553 self._i = self._i00
554 self._i00 = source_raw
554 self._i00 = source_raw
555
555
556 # hackish access to user namespace to create _i1,_i2... dynamically
556 # hackish access to user namespace to create _i1,_i2... dynamically
557 new_i = '_i%s' % line_num
557 new_i = '_i%s' % line_num
558 to_main = {'_i': self._i,
558 to_main = {'_i': self._i,
559 '_ii': self._ii,
559 '_ii': self._ii,
560 '_iii': self._iii,
560 '_iii': self._iii,
561 new_i : self._i00 }
561 new_i : self._i00 }
562 self.shell.user_ns.update(to_main)
562 self.shell.user_ns.update(to_main)
563
563
564 def store_output(self, line_num):
564 def store_output(self, line_num):
565 """If database output logging is enabled, this saves all the
565 """If database output logging is enabled, this saves all the
566 outputs from the indicated prompt number to the database. It's
566 outputs from the indicated prompt number to the database. It's
567 called by run_cell after code has been executed.
567 called by run_cell after code has been executed.
568
568
569 Parameters
569 Parameters
570 ----------
570 ----------
571 line_num : int
571 line_num : int
572 The line number from which to save outputs
572 The line number from which to save outputs
573 """
573 """
574 if (not self.db_log_output) or (line_num not in self.output_hist_reprs):
574 if (not self.db_log_output) or (line_num not in self.output_hist_reprs):
575 return
575 return
576 output = self.output_hist_reprs[line_num]
576 output = self.output_hist_reprs[line_num]
577
577
578 with self.db_output_cache_lock:
578 with self.db_output_cache_lock:
579 self.db_output_cache.append((line_num, output))
579 self.db_output_cache.append((line_num, output))
580 if self.db_cache_size <= 1:
580 if self.db_cache_size <= 1:
581 self.save_flag.set()
581 self.save_flag.set()
582
582
583 def _writeout_input_cache(self, conn):
583 def _writeout_input_cache(self, conn):
584 with conn:
584 with conn:
585 for line in self.db_input_cache:
585 for line in self.db_input_cache:
586 conn.execute("INSERT INTO history VALUES (?, ?, ?, ?)",
586 conn.execute("INSERT INTO history VALUES (?, ?, ?, ?)",
587 (self.session_number,)+line)
587 (self.session_number,)+line)
588
588
589 def _writeout_output_cache(self, conn):
589 def _writeout_output_cache(self, conn):
590 with conn:
590 with conn:
591 for line in self.db_output_cache:
591 for line in self.db_output_cache:
592 conn.execute("INSERT INTO output_history VALUES (?, ?, ?)",
592 conn.execute("INSERT INTO output_history VALUES (?, ?, ?)",
593 (self.session_number,)+line)
593 (self.session_number,)+line)
594
594
595 @needs_sqlite
595 @needs_sqlite
596 def writeout_cache(self, conn=None):
596 def writeout_cache(self, conn=None):
597 """Write any entries in the cache to the database."""
597 """Write any entries in the cache to the database."""
598 if conn is None:
598 if conn is None:
599 conn = self.db
599 conn = self.db
600
600
601 with self.db_input_cache_lock:
601 with self.db_input_cache_lock:
602 try:
602 try:
603 self._writeout_input_cache(conn)
603 self._writeout_input_cache(conn)
604 except sqlite3.IntegrityError:
604 except sqlite3.IntegrityError:
605 self.new_session(conn)
605 self.new_session(conn)
606 print("ERROR! Session/line number was not unique in",
606 print("ERROR! Session/line number was not unique in",
607 "database. History logging moved to new session",
607 "database. History logging moved to new session",
608 self.session_number)
608 self.session_number)
609 try: # Try writing to the new session. If this fails, don't recurse
609 try: # Try writing to the new session. If this fails, don't recurse
610 self._writeout_input_cache(conn)
610 self._writeout_input_cache(conn)
611 except sqlite3.IntegrityError:
611 except sqlite3.IntegrityError:
612 pass
612 pass
613 finally:
613 finally:
614 self.db_input_cache = []
614 self.db_input_cache = []
615
615
616 with self.db_output_cache_lock:
616 with self.db_output_cache_lock:
617 try:
617 try:
618 self._writeout_output_cache(conn)
618 self._writeout_output_cache(conn)
619 except sqlite3.IntegrityError:
619 except sqlite3.IntegrityError:
620 print("!! Session/line number for output was not unique",
620 print("!! Session/line number for output was not unique",
621 "in database. Output will not be stored.")
621 "in database. Output will not be stored.")
622 finally:
622 finally:
623 self.db_output_cache = []
623 self.db_output_cache = []
624
624
625
625
626 class HistorySavingThread(threading.Thread):
626 class HistorySavingThread(threading.Thread):
627 """This thread takes care of writing history to the database, so that
627 """This thread takes care of writing history to the database, so that
628 the UI isn't held up while that happens.
628 the UI isn't held up while that happens.
629
629
630 It waits for the HistoryManager's save_flag to be set, then writes out
630 It waits for the HistoryManager's save_flag to be set, then writes out
631 the history cache. The main thread is responsible for setting the flag when
631 the history cache. The main thread is responsible for setting the flag when
632 the cache size reaches a defined threshold."""
632 the cache size reaches a defined threshold."""
633 daemon = True
633 daemon = True
634 stop_now = False
634 stop_now = False
635 def __init__(self, history_manager):
635 def __init__(self, history_manager):
636 super(HistorySavingThread, self).__init__()
636 super(HistorySavingThread, self).__init__()
637 self.history_manager = history_manager
637 self.history_manager = history_manager
638 atexit.register(self.stop)
638 atexit.register(self.stop)
639
639
640 @needs_sqlite
640 @needs_sqlite
641 def run(self):
641 def run(self):
642 # We need a separate db connection per thread:
642 # We need a separate db connection per thread:
643 try:
643 try:
644 self.db = sqlite3.connect(self.history_manager.hist_file)
644 self.db = sqlite3.connect(self.history_manager.hist_file)
645 while True:
645 while True:
646 self.history_manager.save_flag.wait()
646 self.history_manager.save_flag.wait()
647 if self.stop_now:
647 if self.stop_now:
648 return
648 return
649 self.history_manager.save_flag.clear()
649 self.history_manager.save_flag.clear()
650 self.history_manager.writeout_cache(self.db)
650 self.history_manager.writeout_cache(self.db)
651 except Exception as e:
651 except Exception as e:
652 print(("The history saving thread hit an unexpected error (%s)."
652 print(("The history saving thread hit an unexpected error (%s)."
653 "History will not be written to the database.") % repr(e))
653 "History will not be written to the database.") % repr(e))
654
654
655 def stop(self):
655 def stop(self):
656 """This can be called from the main thread to safely stop this thread.
656 """This can be called from the main thread to safely stop this thread.
657
657
658 Note that it does not attempt to write out remaining history before
658 Note that it does not attempt to write out remaining history before
659 exiting. That should be done by calling the HistoryManager's
659 exiting. That should be done by calling the HistoryManager's
660 end_session method."""
660 end_session method."""
661 self.stop_now = True
661 self.stop_now = True
662 self.history_manager.save_flag.set()
662 self.history_manager.save_flag.set()
663 self.join()
663 self.join()
664
664
665
665
666 # To match, e.g. ~5/8-~2/3
666 # To match, e.g. ~5/8-~2/3
667 range_re = re.compile(r"""
667 range_re = re.compile(r"""
668 ((?P<startsess>~?\d+)/)?
668 ((?P<startsess>~?\d+)/)?
669 (?P<start>\d+) # Only the start line num is compulsory
669 (?P<start>\d+) # Only the start line num is compulsory
670 ((?P<sep>[\-:])
670 ((?P<sep>[\-:])
671 ((?P<endsess>~?\d+)/)?
671 ((?P<endsess>~?\d+)/)?
672 (?P<end>\d+))?
672 (?P<end>\d+))?
673 $""", re.VERBOSE)
673 $""", re.VERBOSE)
674
674
675 def extract_hist_ranges(ranges_str):
675 def extract_hist_ranges(ranges_str):
676 """Turn a string of history ranges into 3-tuples of (session, start, stop).
676 """Turn a string of history ranges into 3-tuples of (session, start, stop).
677
677
678 Examples
678 Examples
679 --------
679 --------
680 list(extract_input_ranges("~8/5-~7/4 2"))
680 list(extract_input_ranges("~8/5-~7/4 2"))
681 [(-8, 5, None), (-7, 1, 4), (0, 2, 3)]
681 [(-8, 5, None), (-7, 1, 4), (0, 2, 3)]
682 """
682 """
683 for range_str in ranges_str.split():
683 for range_str in ranges_str.split():
684 rmatch = range_re.match(range_str)
684 rmatch = range_re.match(range_str)
685 if not rmatch:
685 if not rmatch:
686 continue
686 continue
687 start = int(rmatch.group("start"))
687 start = int(rmatch.group("start"))
688 end = rmatch.group("end")
688 end = rmatch.group("end")
689 end = int(end) if end else start+1 # If no end specified, get (a, a+1)
689 end = int(end) if end else start+1 # If no end specified, get (a, a+1)
690 if rmatch.group("sep") == "-": # 1-3 == 1:4 --> [1, 2, 3]
690 if rmatch.group("sep") == "-": # 1-3 == 1:4 --> [1, 2, 3]
691 end += 1
691 end += 1
692 startsess = rmatch.group("startsess") or "0"
692 startsess = rmatch.group("startsess") or "0"
693 endsess = rmatch.group("endsess") or startsess
693 endsess = rmatch.group("endsess") or startsess
694 startsess = int(startsess.replace("~","-"))
694 startsess = int(startsess.replace("~","-"))
695 endsess = int(endsess.replace("~","-"))
695 endsess = int(endsess.replace("~","-"))
696 assert endsess >= startsess
696 assert endsess >= startsess
697
697
698 if endsess == startsess:
698 if endsess == startsess:
699 yield (startsess, start, end)
699 yield (startsess, start, end)
700 continue
700 continue
701 # Multiple sessions in one range:
701 # Multiple sessions in one range:
702 yield (startsess, start, None)
702 yield (startsess, start, None)
703 for sess in range(startsess+1, endsess):
703 for sess in range(startsess+1, endsess):
704 yield (sess, 1, None)
704 yield (sess, 1, None)
705 yield (endsess, 1, end)
705 yield (endsess, 1, end)
706
706
707 def _format_lineno(session, line):
707 def _format_lineno(session, line):
708 """Helper function to format line numbers properly."""
708 """Helper function to format line numbers properly."""
709 if session == 0:
709 if session == 0:
710 return str(line)
710 return str(line)
711 return "%s#%s" % (session, line)
711 return "%s#%s" % (session, line)
712
712
713 @skip_doctest
713 @skip_doctest
714 def magic_history(self, parameter_s = ''):
714 def magic_history(self, parameter_s = ''):
715 """Print input history (_i<n> variables), with most recent last.
715 """Print input history (_i<n> variables), with most recent last.
716
716
717 %history -> print at most 40 inputs (some may be multi-line)\\
717 %history -> print at most 40 inputs (some may be multi-line)\\
718 %history n -> print at most n inputs\\
718 %history n -> print at most n inputs\\
719 %history n1 n2 -> print inputs between n1 and n2 (n2 not included)\\
719 %history n1 n2 -> print inputs between n1 and n2 (n2 not included)\\
720
720
721 By default, input history is printed without line numbers so it can be
721 By default, input history is printed without line numbers so it can be
722 directly pasted into an editor. Use -n to show them.
722 directly pasted into an editor. Use -n to show them.
723
723
724 Ranges of history can be indicated using the syntax:
724 Ranges of history can be indicated using the syntax:
725 4 : Line 4, current session
725 4 : Line 4, current session
726 4-6 : Lines 4-6, current session
726 4-6 : Lines 4-6, current session
727 243/1-5: Lines 1-5, session 243
727 243/1-5: Lines 1-5, session 243
728 ~2/7 : Line 7, session 2 before current
728 ~2/7 : Line 7, session 2 before current
729 ~8/1-~6/5 : From the first line of 8 sessions ago, to the fifth line
729 ~8/1-~6/5 : From the first line of 8 sessions ago, to the fifth line
730 of 6 sessions ago.
730 of 6 sessions ago.
731 Multiple ranges can be entered, separated by spaces
731 Multiple ranges can be entered, separated by spaces
732
732
733 The same syntax is used by %macro, %save, %edit, %rerun
733 The same syntax is used by %macro, %save, %edit, %rerun
734
734
735 Options:
735 Options:
736
736
737 -n: print line numbers for each input.
737 -n: print line numbers for each input.
738 This feature is only available if numbered prompts are in use.
738 This feature is only available if numbered prompts are in use.
739
739
740 -o: also print outputs for each input.
740 -o: also print outputs for each input.
741
741
742 -p: print classic '>>>' python prompts before each input. This is useful
742 -p: print classic '>>>' python prompts before each input. This is useful
743 for making documentation, and in conjunction with -o, for producing
743 for making documentation, and in conjunction with -o, for producing
744 doctest-ready output.
744 doctest-ready output.
745
745
746 -r: (default) print the 'raw' history, i.e. the actual commands you typed.
746 -r: (default) print the 'raw' history, i.e. the actual commands you typed.
747
747
748 -t: print the 'translated' history, as IPython understands it. IPython
748 -t: print the 'translated' history, as IPython understands it. IPython
749 filters your input and converts it all into valid Python source before
749 filters your input and converts it all into valid Python source before
750 executing it (things like magics or aliases are turned into function
750 executing it (things like magics or aliases are turned into function
751 calls, for example). With this option, you'll see the native history
751 calls, for example). With this option, you'll see the native history
752 instead of the user-entered version: '%cd /' will be seen as
752 instead of the user-entered version: '%cd /' will be seen as
753 'get_ipython().magic("%cd /")' instead of '%cd /'.
753 'get_ipython().magic("%cd /")' instead of '%cd /'.
754
754
755 -g: treat the arg as a pattern to grep for in (full) history.
755 -g: treat the arg as a pattern to grep for in (full) history.
756 This includes the saved history (almost all commands ever written).
756 This includes the saved history (almost all commands ever written).
757 Use '%hist -g' to show full saved history (may be very long).
757 Use '%hist -g' to show full saved history (may be very long).
758
758
759 -l: get the last n lines from all sessions. Specify n as a single arg, or
759 -l: get the last n lines from all sessions. Specify n as a single arg, or
760 the default is the last 10 lines.
760 the default is the last 10 lines.
761
761
762 -f FILENAME: instead of printing the output to the screen, redirect it to
762 -f FILENAME: instead of printing the output to the screen, redirect it to
763 the given file. The file is always overwritten, though IPython asks for
763 the given file. The file is always overwritten, though IPython asks for
764 confirmation first if it already exists.
764 confirmation first if it already exists.
765
765
766 Examples
766 Examples
767 --------
767 --------
768 ::
768 ::
769
769
770 In [6]: %hist -n 4 6
770 In [6]: %hist -n 4 6
771 4:a = 12
771 4:a = 12
772 5:print a**2
772 5:print a**2
773
773
774 """
774 """
775
775
776 if not self.shell.displayhook.do_full_cache:
776 if not self.shell.displayhook.do_full_cache:
777 print('This feature is only available if numbered prompts are in use.')
777 print('This feature is only available if numbered prompts are in use.')
778 return
778 return
779 opts,args = self.parse_options(parameter_s,'noprtglf:',mode='string')
779 opts,args = self.parse_options(parameter_s,'noprtglf:',mode='string')
780
780
781 # For brevity
781 # For brevity
782 history_manager = self.shell.history_manager
782 history_manager = self.shell.history_manager
783
783
784 def _format_lineno(session, line):
784 def _format_lineno(session, line):
785 """Helper function to format line numbers properly."""
785 """Helper function to format line numbers properly."""
786 if session in (0, history_manager.session_number):
786 if session in (0, history_manager.session_number):
787 return str(line)
787 return str(line)
788 return "%s/%s" % (session, line)
788 return "%s/%s" % (session, line)
789
789
790 # Check if output to specific file was requested.
790 # Check if output to specific file was requested.
791 try:
791 try:
792 outfname = opts['f']
792 outfname = opts['f']
793 except KeyError:
793 except KeyError:
794 outfile = io.stdout # default
794 outfile = io.stdout # default
795 # We don't want to close stdout at the end!
795 # We don't want to close stdout at the end!
796 close_at_end = False
796 close_at_end = False
797 else:
797 else:
798 if os.path.exists(outfname):
798 if os.path.exists(outfname):
799 if not io.ask_yes_no("File %r exists. Overwrite?" % outfname):
799 if not io.ask_yes_no("File %r exists. Overwrite?" % outfname):
800 print('Aborting.')
800 print('Aborting.')
801 return
801 return
802
802
803 outfile = open(outfname,'w')
803 outfile = open(outfname,'w')
804 close_at_end = True
804 close_at_end = True
805
805
806 print_nums = 'n' in opts
806 print_nums = 'n' in opts
807 get_output = 'o' in opts
807 get_output = 'o' in opts
808 pyprompts = 'p' in opts
808 pyprompts = 'p' in opts
809 # Raw history is the default
809 # Raw history is the default
810 raw = not('t' in opts)
810 raw = not('t' in opts)
811
811
812 default_length = 40
812 default_length = 40
813 pattern = None
813 pattern = None
814
814
815 if 'g' in opts: # Glob search
815 if 'g' in opts: # Glob search
816 pattern = "*" + args + "*" if args else "*"
816 pattern = "*" + args + "*" if args else "*"
817 hist = history_manager.search(pattern, raw=raw, output=get_output)
817 hist = history_manager.search(pattern, raw=raw, output=get_output)
818 print_nums = True
818 print_nums = True
819 elif 'l' in opts: # Get 'tail'
819 elif 'l' in opts: # Get 'tail'
820 try:
820 try:
821 n = int(args)
821 n = int(args)
822 except ValueError, IndexError:
822 except ValueError, IndexError:
823 n = 10
823 n = 10
824 hist = history_manager.get_tail(n, raw=raw, output=get_output)
824 hist = history_manager.get_tail(n, raw=raw, output=get_output)
825 else:
825 else:
826 if args: # Get history by ranges
826 if args: # Get history by ranges
827 hist = history_manager.get_range_by_str(args, raw, get_output)
827 hist = history_manager.get_range_by_str(args, raw, get_output)
828 else: # Just get history for the current session
828 else: # Just get history for the current session
829 hist = history_manager.get_range(raw=raw, output=get_output)
829 hist = history_manager.get_range(raw=raw, output=get_output)
830
830
831 # We could be displaying the entire history, so let's not try to pull it
831 # We could be displaying the entire history, so let's not try to pull it
832 # into a list in memory. Anything that needs more space will just misalign.
832 # into a list in memory. Anything that needs more space will just misalign.
833 width = 4
833 width = 4
834
834
835 for session, lineno, inline in hist:
835 for session, lineno, inline in hist:
836 # Print user history with tabs expanded to 4 spaces. The GUI clients
836 # Print user history with tabs expanded to 4 spaces. The GUI clients
837 # use hard tabs for easier usability in auto-indented code, but we want
837 # use hard tabs for easier usability in auto-indented code, but we want
838 # to produce PEP-8 compliant history for safe pasting into an editor.
838 # to produce PEP-8 compliant history for safe pasting into an editor.
839 if get_output:
839 if get_output:
840 inline, output = inline
840 inline, output = inline
841 inline = inline.expandtabs(4).rstrip()
841 inline = inline.expandtabs(4).rstrip()
842
842
843 multiline = "\n" in inline
843 multiline = "\n" in inline
844 line_sep = '\n' if multiline else ' '
844 line_sep = '\n' if multiline else ' '
845 if print_nums:
845 if print_nums:
846 print('%s:%s' % (_format_lineno(session, lineno).rjust(width),
846 print('%s:%s' % (_format_lineno(session, lineno).rjust(width),
847 line_sep), file=outfile, end='')
847 line_sep), file=outfile, end='')
848 if pyprompts:
848 if pyprompts:
849 print(">>> ", end="", file=outfile)
849 print(">>> ", end="", file=outfile)
850 if multiline:
850 if multiline:
851 inline = "\n... ".join(inline.splitlines()) + "\n..."
851 inline = "\n... ".join(inline.splitlines()) + "\n..."
852 print(inline, file=outfile)
852 print(inline, file=outfile)
853 if get_output and output:
853 if get_output and output:
854 print(output, file=outfile)
854 print(output, file=outfile)
855
855
856 if close_at_end:
856 if close_at_end:
857 outfile.close()
857 outfile.close()
858
858
859
859
860 def magic_rep(self, arg):
860 def magic_rep(self, arg):
861 r"""Repeat a command, or get command to input line for editing.
861 r"""Repeat a command, or get command to input line for editing.
862
862
863 %recall and %rep are equivalent.
863 %recall and %rep are equivalent.
864
864
865 - %recall (no arguments):
865 - %recall (no arguments):
866
866
867 Place a string version of last computation result (stored in the special '_'
867 Place a string version of last computation result (stored in the special '_'
868 variable) to the next input prompt. Allows you to create elaborate command
868 variable) to the next input prompt. Allows you to create elaborate command
869 lines without using copy-paste::
869 lines without using copy-paste::
870
870
871 In[1]: l = ["hei", "vaan"]
871 In[1]: l = ["hei", "vaan"]
872 In[2]: "".join(l)
872 In[2]: "".join(l)
873 Out[2]: heivaan
873 Out[2]: heivaan
874 In[3]: %rep
874 In[3]: %rep
875 In[4]: heivaan_ <== cursor blinking
875 In[4]: heivaan_ <== cursor blinking
876
876
877 %recall 45
877 %recall 45
878
878
879 Place history line 45 on the next input prompt. Use %hist to find
879 Place history line 45 on the next input prompt. Use %hist to find
880 out the number.
880 out the number.
881
881
882 %recall 1-4
882 %recall 1-4
883
883
884 Combine the specified lines into one cell, and place it on the next
884 Combine the specified lines into one cell, and place it on the next
885 input prompt. See %history for the slice syntax.
885 input prompt. See %history for the slice syntax.
886
886
887 %recall foo+bar
887 %recall foo+bar
888
888
889 If foo+bar can be evaluated in the user namespace, the result is
889 If foo+bar can be evaluated in the user namespace, the result is
890 placed at the next input prompt. Otherwise, the history is searched
890 placed at the next input prompt. Otherwise, the history is searched
891 for lines which contain that substring, and the most recent one is
891 for lines which contain that substring, and the most recent one is
892 placed at the next input prompt.
892 placed at the next input prompt.
893 """
893 """
894 if not arg: # Last output
894 if not arg: # Last output
895 self.set_next_input(str(self.shell.user_ns["_"]))
895 self.set_next_input(str(self.shell.user_ns["_"]))
896 return
896 return
897 # Get history range
897 # Get history range
898 histlines = self.history_manager.get_range_by_str(arg)
898 histlines = self.history_manager.get_range_by_str(arg)
899 cmd = "\n".join(x[2] for x in histlines)
899 cmd = "\n".join(x[2] for x in histlines)
900 if cmd:
900 if cmd:
901 self.set_next_input(cmd.rstrip())
901 self.set_next_input(cmd.rstrip())
902 return
902 return
903
903
904 try: # Variable in user namespace
904 try: # Variable in user namespace
905 cmd = str(eval(arg, self.shell.user_ns))
905 cmd = str(eval(arg, self.shell.user_ns))
906 except Exception: # Search for term in history
906 except Exception: # Search for term in history
907 histlines = self.history_manager.search("*"+arg+"*")
907 histlines = self.history_manager.search("*"+arg+"*")
908 for h in reversed([x[2] for x in histlines]):
908 for h in reversed([x[2] for x in histlines]):
909 if 'rep' in h:
909 if 'rep' in h:
910 continue
910 continue
911 self.set_next_input(h.rstrip())
911 self.set_next_input(h.rstrip())
912 return
912 return
913 else:
913 else:
914 self.set_next_input(cmd.rstrip())
914 self.set_next_input(cmd.rstrip())
915 print("Couldn't evaluate or find in history:", arg)
915 print("Couldn't evaluate or find in history:", arg)
916
916
917 def magic_rerun(self, parameter_s=''):
917 def magic_rerun(self, parameter_s=''):
918 """Re-run previous input
918 """Re-run previous input
919
919
920 By default, you can specify ranges of input history to be repeated
920 By default, you can specify ranges of input history to be repeated
921 (as with %history). With no arguments, it will repeat the last line.
921 (as with %history). With no arguments, it will repeat the last line.
922
922
923 Options:
923 Options:
924
924
925 -l <n> : Repeat the last n lines of input, not including the
925 -l <n> : Repeat the last n lines of input, not including the
926 current command.
926 current command.
927
927
928 -g foo : Repeat the most recent line which contains foo
928 -g foo : Repeat the most recent line which contains foo
929 """
929 """
930 opts, args = self.parse_options(parameter_s, 'l:g:', mode='string')
930 opts, args = self.parse_options(parameter_s, 'l:g:', mode='string')
931 if "l" in opts: # Last n lines
931 if "l" in opts: # Last n lines
932 n = int(opts['l'])
932 n = int(opts['l'])
933 hist = self.history_manager.get_tail(n)
933 hist = self.history_manager.get_tail(n)
934 elif "g" in opts: # Search
934 elif "g" in opts: # Search
935 p = "*"+opts['g']+"*"
935 p = "*"+opts['g']+"*"
936 hist = list(self.history_manager.search(p))
936 hist = list(self.history_manager.search(p))
937 for l in reversed(hist):
937 for l in reversed(hist):
938 if "rerun" not in l[2]:
938 if "rerun" not in l[2]:
939 hist = [l] # The last match which isn't a %rerun
939 hist = [l] # The last match which isn't a %rerun
940 break
940 break
941 else:
941 else:
942 hist = [] # No matches except %rerun
942 hist = [] # No matches except %rerun
943 elif args: # Specify history ranges
943 elif args: # Specify history ranges
944 hist = self.history_manager.get_range_by_str(args)
944 hist = self.history_manager.get_range_by_str(args)
945 else: # Last line
945 else: # Last line
946 hist = self.history_manager.get_tail(1)
946 hist = self.history_manager.get_tail(1)
947 hist = [x[2] for x in hist]
947 hist = [x[2] for x in hist]
948 if not hist:
948 if not hist:
949 print("No lines in history match specification")
949 print("No lines in history match specification")
950 return
950 return
951 histlines = "\n".join(hist)
951 histlines = "\n".join(hist)
952 print("=== Executing: ===")
952 print("=== Executing: ===")
953 print(histlines)
953 print(histlines)
954 print("=== Output: ===")
954 print("=== Output: ===")
955 self.run_cell("\n".join(hist), store_history=False)
955 self.run_cell("\n".join(hist), store_history=False)
956
956
957
957
958 def init_ipython(ip):
958 def init_ipython(ip):
959 ip.define_magic("rep", magic_rep)
959 ip.define_magic("rep", magic_rep)
960 ip.define_magic("recall", magic_rep)
960 ip.define_magic("recall", magic_rep)
961 ip.define_magic("rerun", magic_rerun)
961 ip.define_magic("rerun", magic_rerun)
962 ip.define_magic("hist",magic_history) # Alternative name
962 ip.define_magic("hist",magic_history) # Alternative name
963 ip.define_magic("history",magic_history)
963 ip.define_magic("history",magic_history)
964
964
965 # XXX - ipy_completers are in quarantine, need to be updated to new apis
965 # XXX - ipy_completers are in quarantine, need to be updated to new apis
966 #import ipy_completers
966 #import ipy_completers
967 #ipy_completers.quick_completer('%hist' ,'-g -t -r -n')
967 #ipy_completers.quick_completer('%hist' ,'-g -t -r -n')
@@ -1,767 +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-2011 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.py3compat import cast_unicode
78 from IPython.utils.py3compat import cast_unicode
79
79
80 #-----------------------------------------------------------------------------
80 #-----------------------------------------------------------------------------
81 # Globals
81 # Globals
82 #-----------------------------------------------------------------------------
82 #-----------------------------------------------------------------------------
83
83
84 # The escape sequences that define the syntax transformations IPython will
84 # The escape sequences that define the syntax transformations IPython will
85 # 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
86 # 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
87 # 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
88 # should be considered fixed.
88 # should be considered fixed.
89
89
90 ESC_SHELL = '!' # Send line to underlying system shell
90 ESC_SHELL = '!' # Send line to underlying system shell
91 ESC_SH_CAP = '!!' # Send line to system shell and capture output
91 ESC_SH_CAP = '!!' # Send line to system shell and capture output
92 ESC_HELP = '?' # Find information about object
92 ESC_HELP = '?' # Find information about object
93 ESC_HELP2 = '??' # Find extra-detailed information about object
93 ESC_HELP2 = '??' # Find extra-detailed information about object
94 ESC_MAGIC = '%' # Call magic function
94 ESC_MAGIC = '%' # Call magic function
95 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
96 ESC_QUOTE2 = ';' # Quote all args as a single string, call
96 ESC_QUOTE2 = ';' # Quote all args as a single string, call
97 ESC_PAREN = '/' # Call first argument with rest of line as arguments
97 ESC_PAREN = '/' # Call first argument with rest of line as arguments
98
98
99 #-----------------------------------------------------------------------------
99 #-----------------------------------------------------------------------------
100 # Utilities
100 # Utilities
101 #-----------------------------------------------------------------------------
101 #-----------------------------------------------------------------------------
102
102
103 # 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
104 # 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
105 # 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
106 # while developing.
106 # while developing.
107
107
108 # compiled regexps for autoindent management
108 # compiled regexps for autoindent management
109 dedent_re = re.compile('|'.join([
109 dedent_re = re.compile('|'.join([
110 r'^\s+raise(\s.*)?$', # raise statement (+ space + other stuff, maybe)
110 r'^\s+raise(\s.*)?$', # raise statement (+ space + other stuff, maybe)
111 r'^\s+raise\([^\)]*\).*$', # wacky raise with immediate open paren
111 r'^\s+raise\([^\)]*\).*$', # wacky raise with immediate open paren
112 r'^\s+return(\s.*)?$', # normal return (+ space + other stuff, maybe)
112 r'^\s+return(\s.*)?$', # normal return (+ space + other stuff, maybe)
113 r'^\s+return\([^\)]*\).*$', # wacky return with immediate open paren
113 r'^\s+return\([^\)]*\).*$', # wacky return with immediate open paren
114 r'^\s+pass\s*$' # pass (optionally followed by trailing spaces)
114 r'^\s+pass\s*$' # pass (optionally followed by trailing spaces)
115 ]))
115 ]))
116 ini_spaces_re = re.compile(r'^([ \t\r\f\v]+)')
116 ini_spaces_re = re.compile(r'^([ \t\r\f\v]+)')
117
117
118 # 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:'
119 # before pure comments
119 # before pure comments
120 comment_line_re = re.compile('^\s*\#')
120 comment_line_re = re.compile('^\s*\#')
121
121
122
122
123 def num_ini_spaces(s):
123 def num_ini_spaces(s):
124 """Return the number of initial spaces in a string.
124 """Return the number of initial spaces in a string.
125
125
126 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
127 mixing of tabs and spaces in the user's input.
127 mixing of tabs and spaces in the user's input.
128
128
129 Parameters
129 Parameters
130 ----------
130 ----------
131 s : string
131 s : string
132
132
133 Returns
133 Returns
134 -------
134 -------
135 n : int
135 n : int
136 """
136 """
137
137
138 ini_spaces = ini_spaces_re.match(s)
138 ini_spaces = ini_spaces_re.match(s)
139 if ini_spaces:
139 if ini_spaces:
140 return ini_spaces.end()
140 return ini_spaces.end()
141 else:
141 else:
142 return 0
142 return 0
143
143
144
144
145 def remove_comments(src):
145 def remove_comments(src):
146 """Remove all comments from input source.
146 """Remove all comments from input source.
147
147
148 Note: comments are NOT recognized inside of strings!
148 Note: comments are NOT recognized inside of strings!
149
149
150 Parameters
150 Parameters
151 ----------
151 ----------
152 src : string
152 src : string
153 A single or multiline input string.
153 A single or multiline input string.
154
154
155 Returns
155 Returns
156 -------
156 -------
157 String with all Python comments removed.
157 String with all Python comments removed.
158 """
158 """
159
159
160 return re.sub('#.*', '', src)
160 return re.sub('#.*', '', src)
161
161
162 def has_comment(src):
162 def has_comment(src):
163 """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.
164
164
165 This uses tokenize, so it can distinguish comments from # inside strings.
165 This uses tokenize, so it can distinguish comments from # inside strings.
166
166
167 Parameters
167 Parameters
168 ----------
168 ----------
169 src : string
169 src : string
170 A single line input string.
170 A single line input string.
171
171
172 Returns
172 Returns
173 -------
173 -------
174 Boolean: True if source has a comment.
174 Boolean: True if source has a comment.
175 """
175 """
176 readline = StringIO(src).readline
176 readline = StringIO(src).readline
177 toktypes = set()
177 toktypes = set()
178 try:
178 try:
179 for t in tokenize.generate_tokens(readline):
179 for t in tokenize.generate_tokens(readline):
180 toktypes.add(t[0])
180 toktypes.add(t[0])
181 except tokenize.TokenError:
181 except tokenize.TokenError:
182 pass
182 pass
183 return(tokenize.COMMENT in toktypes)
183 return(tokenize.COMMENT in toktypes)
184
184
185
185
186 def get_input_encoding():
186 def get_input_encoding():
187 """Return the default standard input encoding.
187 """Return the default standard input encoding.
188
188
189 If sys.stdin has no encoding, 'ascii' is returned."""
189 If sys.stdin has no encoding, 'ascii' is returned."""
190 # 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
191 # ensure that a valid encoding is returned.
191 # ensure that a valid encoding is returned.
192 encoding = getattr(sys.stdin, 'encoding', None)
192 encoding = getattr(sys.stdin, 'encoding', None)
193 if encoding is None:
193 if encoding is None:
194 encoding = 'ascii'
194 encoding = 'ascii'
195 return encoding
195 return encoding
196
196
197 #-----------------------------------------------------------------------------
197 #-----------------------------------------------------------------------------
198 # Classes and functions for normal Python syntax handling
198 # Classes and functions for normal Python syntax handling
199 #-----------------------------------------------------------------------------
199 #-----------------------------------------------------------------------------
200
200
201 class InputSplitter(object):
201 class InputSplitter(object):
202 """An object that can accumulate lines of Python source before execution.
202 """An object that can accumulate lines of Python source before execution.
203
203
204 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
205 :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
206 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
207 :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
208 can be pushed into a single interactive block.
208 can be pushed into a single interactive block.
209
209
210 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
211 this tool::
211 this tool::
212
212
213 isp = InputSplitter()
213 isp = InputSplitter()
214 while isp.push_accepts_more():
214 while isp.push_accepts_more():
215 indent = ' '*isp.indent_spaces
215 indent = ' '*isp.indent_spaces
216 prompt = '>>> ' + indent
216 prompt = '>>> ' + indent
217 line = indent + raw_input(prompt)
217 line = indent + raw_input(prompt)
218 isp.push(line)
218 isp.push(line)
219 print 'Input source was:\n', isp.source_reset(),
219 print 'Input source was:\n', isp.source_reset(),
220 """
220 """
221 # 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
222 # 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
223 # indentation level, in order to provide auto-indent facilities.
223 # indentation level, in order to provide auto-indent facilities.
224 indent_spaces = 0
224 indent_spaces = 0
225 # String, indicating the default input encoding. It is computed by default
225 # String, indicating the default input encoding. It is computed by default
226 # 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
227 # client with specific knowledge of the encoding.
227 # client with specific knowledge of the encoding.
228 encoding = ''
228 encoding = ''
229 # String where the current full source input is stored, properly encoded.
229 # String where the current full source input is stored, properly encoded.
230 # 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
231 # source code, that has been properly encoded.
231 # source code, that has been properly encoded.
232 source = ''
232 source = ''
233 # Code object corresponding to the current source. It is automatically
233 # Code object corresponding to the current source. It is automatically
234 # 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
235 # 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.
236 code = None
236 code = None
237 # Input mode
237 # Input mode
238 input_mode = 'line'
238 input_mode = 'line'
239
239
240 # Private attributes
240 # Private attributes
241
241
242 # List with lines of input accumulated so far
242 # List with lines of input accumulated so far
243 _buffer = None
243 _buffer = None
244 # Command compiler
244 # Command compiler
245 _compile = None
245 _compile = None
246 # 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
247 _full_dedent = False
247 _full_dedent = False
248 # Boolean indicating whether the current block is complete
248 # Boolean indicating whether the current block is complete
249 _is_complete = None
249 _is_complete = None
250
250
251 def __init__(self, input_mode=None):
251 def __init__(self, input_mode=None):
252 """Create a new InputSplitter instance.
252 """Create a new InputSplitter instance.
253
253
254 Parameters
254 Parameters
255 ----------
255 ----------
256 input_mode : str
256 input_mode : str
257
257
258 One of ['line', 'cell']; default is 'line'.
258 One of ['line', 'cell']; default is 'line'.
259
259
260 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
261 the :meth:`push` method:
261 the :meth:`push` method:
262
262
263 - '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
264 time to the internal buffer and the whole buffer is compiled.
264 time to the internal buffer and the whole buffer is compiled.
265
265
266 - '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
267 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
268 '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
269 completely replaces all prior inputs. Cell mode is thus equivalent
269 completely replaces all prior inputs. Cell mode is thus equivalent
270 to prepending a full reset() to every push() call.
270 to prepending a full reset() to every push() call.
271 """
271 """
272 self._buffer = []
272 self._buffer = []
273 self._compile = codeop.CommandCompiler()
273 self._compile = codeop.CommandCompiler()
274 self.encoding = get_input_encoding()
274 self.encoding = get_input_encoding()
275 self.input_mode = InputSplitter.input_mode if input_mode is None \
275 self.input_mode = InputSplitter.input_mode if input_mode is None \
276 else input_mode
276 else input_mode
277
277
278 def reset(self):
278 def reset(self):
279 """Reset the input buffer and associated state."""
279 """Reset the input buffer and associated state."""
280 self.indent_spaces = 0
280 self.indent_spaces = 0
281 self._buffer[:] = []
281 self._buffer[:] = []
282 self.source = ''
282 self.source = ''
283 self.code = None
283 self.code = None
284 self._is_complete = False
284 self._is_complete = False
285 self._full_dedent = False
285 self._full_dedent = False
286
286
287 def source_reset(self):
287 def source_reset(self):
288 """Return the input source and perform a full reset.
288 """Return the input source and perform a full reset.
289 """
289 """
290 out = self.source
290 out = self.source
291 self.reset()
291 self.reset()
292 return out
292 return out
293
293
294 def push(self, lines):
294 def push(self, lines):
295 """Push one or more lines of input.
295 """Push one or more lines of input.
296
296
297 This stores the given lines and returns a status code indicating
297 This stores the given lines and returns a status code indicating
298 whether the code forms a complete Python block or not.
298 whether the code forms a complete Python block or not.
299
299
300 Any exceptions generated in compilation are swallowed, but if an
300 Any exceptions generated in compilation are swallowed, but if an
301 exception was produced, the method returns True.
301 exception was produced, the method returns True.
302
302
303 Parameters
303 Parameters
304 ----------
304 ----------
305 lines : string
305 lines : string
306 One or more lines of Python input.
306 One or more lines of Python input.
307
307
308 Returns
308 Returns
309 -------
309 -------
310 is_complete : boolean
310 is_complete : boolean
311 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
312 plus prior inputs) forms a complete Python execution block. Note that
312 plus prior inputs) forms a complete Python execution block. Note that
313 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
314 can be queried at any time.
314 can be queried at any time.
315 """
315 """
316 if self.input_mode == 'cell':
316 if self.input_mode == 'cell':
317 self.reset()
317 self.reset()
318
318
319 self._store(lines)
319 self._store(lines)
320 source = self.source
320 source = self.source
321
321
322 # 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
323 # exception is raised in compilation, we don't mislead by having
323 # exception is raised in compilation, we don't mislead by having
324 # inconsistent code/source attributes.
324 # inconsistent code/source attributes.
325 self.code, self._is_complete = None, None
325 self.code, self._is_complete = None, None
326
326
327 # Honor termination lines properly
327 # Honor termination lines properly
328 if source.rstrip().endswith('\\'):
328 if source.rstrip().endswith('\\'):
329 return False
329 return False
330
330
331 self._update_indent(lines)
331 self._update_indent(lines)
332 try:
332 try:
333 self.code = self._compile(source, symbol="exec")
333 self.code = self._compile(source, symbol="exec")
334 # 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
335 # 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
336 # immediately produce a 'ready' block, so the invalid Python can be
336 # immediately produce a 'ready' block, so the invalid Python can be
337 # sent to the kernel for evaluation with possible ipython
337 # sent to the kernel for evaluation with possible ipython
338 # special-syntax conversion.
338 # special-syntax conversion.
339 except (SyntaxError, OverflowError, ValueError, TypeError,
339 except (SyntaxError, OverflowError, ValueError, TypeError,
340 MemoryError):
340 MemoryError):
341 self._is_complete = True
341 self._is_complete = True
342 else:
342 else:
343 # Compilation didn't produce any exceptions (though it may not have
343 # Compilation didn't produce any exceptions (though it may not have
344 # given a complete code object)
344 # given a complete code object)
345 self._is_complete = self.code is not None
345 self._is_complete = self.code is not None
346
346
347 return self._is_complete
347 return self._is_complete
348
348
349 def push_accepts_more(self):
349 def push_accepts_more(self):
350 """Return whether a block of interactive input can accept more input.
350 """Return whether a block of interactive input can accept more input.
351
351
352 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
353 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
354 current input lines. The InputSplitter considers it has a complete
354 current input lines. The InputSplitter considers it has a complete
355 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
356 SyntaxError is raised, or *all* of the following are true:
356 SyntaxError is raised, or *all* of the following are true:
357
357
358 1. The input compiles to a complete statement.
358 1. The input compiles to a complete statement.
359
359
360 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,
361 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
362 reading new input).
362 reading new input).
363
363
364 3. There is one extra line consisting only of whitespace.
364 3. There is one extra line consisting only of whitespace.
365
365
366 Because of condition #3, this method should be used only by
366 Because of condition #3, this method should be used only by
367 *line-oriented* frontends, since it means that intermediate blank lines
367 *line-oriented* frontends, since it means that intermediate blank lines
368 are not allowed in function definitions (or any other indented block).
368 are not allowed in function definitions (or any other indented block).
369
369
370 If the current input produces a syntax error, this method immediately
370 If the current input produces a syntax error, this method immediately
371 returns False but does *not* raise the syntax error exception, as
371 returns False but does *not* raise the syntax error exception, as
372 typically clients will want to send invalid syntax to an execution
372 typically clients will want to send invalid syntax to an execution
373 backend which might convert the invalid syntax into valid Python via
373 backend which might convert the invalid syntax into valid Python via
374 one of the dynamic IPython mechanisms.
374 one of the dynamic IPython mechanisms.
375 """
375 """
376
376
377 # With incomplete input, unconditionally accept more
377 # With incomplete input, unconditionally accept more
378 if not self._is_complete:
378 if not self._is_complete:
379 return True
379 return True
380
380
381 # 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
382 # depends. In line mode, if there hasn't been any indentation,
382 # depends. In line mode, if there hasn't been any indentation,
383 # 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
384 # the blank final line to finish.
384 # the blank final line to finish.
385 # 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
386 # compiles into, because if there's already more than one full
386 # compiles into, because if there's already more than one full
387 # independent block of input, then the client has entered full
387 # independent block of input, then the client has entered full
388 # '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
389 # case we should then keep accepting. The Qt terminal-like console
389 # case we should then keep accepting. The Qt terminal-like console
390 # does precisely this, to provide the convenience of terminal-like
390 # does precisely this, to provide the convenience of terminal-like
391 # input of single expressions, but allowing the user (with a
391 # input of single expressions, but allowing the user (with a
392 # separate keystroke) to switch to 'cell' mode and type multiple
392 # separate keystroke) to switch to 'cell' mode and type multiple
393 # expressions in one shot.
393 # expressions in one shot.
394 if self.indent_spaces==0:
394 if self.indent_spaces==0:
395 if self.input_mode=='line':
395 if self.input_mode=='line':
396 if not self._full_dedent:
396 if not self._full_dedent:
397 return False
397 return False
398 else:
398 else:
399 try:
399 try:
400 code_ast = ast.parse(u''.join(self._buffer))
400 code_ast = ast.parse(u''.join(self._buffer))
401 except Exception:
401 except Exception:
402 return False
402 return False
403 else:
403 else:
404 if len(code_ast.body) == 1:
404 if len(code_ast.body) == 1:
405 return False
405 return False
406
406
407 # 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
408 # line at the end.
408 # line at the end.
409 last_line = self.source.splitlines()[-1]
409 last_line = self.source.splitlines()[-1]
410 return bool(last_line and not last_line.isspace())
410 return bool(last_line and not last_line.isspace())
411
411
412 #------------------------------------------------------------------------
412 #------------------------------------------------------------------------
413 # Private interface
413 # Private interface
414 #------------------------------------------------------------------------
414 #------------------------------------------------------------------------
415
415
416 def _find_indent(self, line):
416 def _find_indent(self, line):
417 """Compute the new indentation level for a single line.
417 """Compute the new indentation level for a single line.
418
418
419 Parameters
419 Parameters
420 ----------
420 ----------
421 line : str
421 line : str
422 A single new line of non-whitespace, non-comment Python input.
422 A single new line of non-whitespace, non-comment Python input.
423
423
424 Returns
424 Returns
425 -------
425 -------
426 indent_spaces : int
426 indent_spaces : int
427 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
428 if indentation doesn't change.
428 if indentation doesn't change.
429
429
430 full_dedent : boolean
430 full_dedent : boolean
431 Whether the new line causes a full flush-left dedent.
431 Whether the new line causes a full flush-left dedent.
432 """
432 """
433 indent_spaces = self.indent_spaces
433 indent_spaces = self.indent_spaces
434 full_dedent = self._full_dedent
434 full_dedent = self._full_dedent
435
435
436 inisp = num_ini_spaces(line)
436 inisp = num_ini_spaces(line)
437 if inisp < indent_spaces:
437 if inisp < indent_spaces:
438 indent_spaces = inisp
438 indent_spaces = inisp
439 if indent_spaces <= 0:
439 if indent_spaces <= 0:
440 #print 'Full dedent in text',self.source # dbg
440 #print 'Full dedent in text',self.source # dbg
441 full_dedent = True
441 full_dedent = True
442
442
443 if line.rstrip()[-1] == ':':
443 if line.rstrip()[-1] == ':':
444 indent_spaces += 4
444 indent_spaces += 4
445 elif dedent_re.match(line):
445 elif dedent_re.match(line):
446 indent_spaces -= 4
446 indent_spaces -= 4
447 if indent_spaces <= 0:
447 if indent_spaces <= 0:
448 full_dedent = True
448 full_dedent = True
449
449
450 # Safety
450 # Safety
451 if indent_spaces < 0:
451 if indent_spaces < 0:
452 indent_spaces = 0
452 indent_spaces = 0
453 #print 'safety' # dbg
453 #print 'safety' # dbg
454
454
455 return indent_spaces, full_dedent
455 return indent_spaces, full_dedent
456
456
457 def _update_indent(self, lines):
457 def _update_indent(self, lines):
458 for line in remove_comments(lines).splitlines():
458 for line in remove_comments(lines).splitlines():
459 if line and not line.isspace():
459 if line and not line.isspace():
460 self.indent_spaces, self._full_dedent = self._find_indent(line)
460 self.indent_spaces, self._full_dedent = self._find_indent(line)
461
461
462 def _store(self, lines, buffer=None, store='source'):
462 def _store(self, lines, buffer=None, store='source'):
463 """Store one or more lines of input.
463 """Store one or more lines of input.
464
464
465 If input lines are not newline-terminated, a newline is automatically
465 If input lines are not newline-terminated, a newline is automatically
466 appended."""
466 appended."""
467
467
468 if buffer is None:
468 if buffer is None:
469 buffer = self._buffer
469 buffer = self._buffer
470
470
471 if lines.endswith('\n'):
471 if lines.endswith('\n'):
472 buffer.append(lines)
472 buffer.append(lines)
473 else:
473 else:
474 buffer.append(lines+'\n')
474 buffer.append(lines+'\n')
475 setattr(self, store, self._set_source(buffer))
475 setattr(self, store, self._set_source(buffer))
476
476
477 def _set_source(self, buffer):
477 def _set_source(self, buffer):
478 return u''.join(buffer)
478 return u''.join(buffer)
479
479
480
480
481 #-----------------------------------------------------------------------------
481 #-----------------------------------------------------------------------------
482 # Functions and classes for IPython-specific syntactic support
482 # Functions and classes for IPython-specific syntactic support
483 #-----------------------------------------------------------------------------
483 #-----------------------------------------------------------------------------
484
484
485 # 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
486 # 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
487 # placed at the start.
487 # placed at the start.
488
488
489 # 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
490 # character but instead on patterns on the input line
490 # character but instead on patterns on the input line
491
491
492 # The core transformations are implemented as standalone functions that can be
492 # The core transformations are implemented as standalone functions that can be
493 # 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
494 # 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
495
495
496 _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\.]+)*))'
497 r'\s*=\s*!\s*(?P<cmd>.*)')
497 r'\s*=\s*!\s*(?P<cmd>.*)')
498
498
499 def transform_assign_system(line):
499 def transform_assign_system(line):
500 """Handle the `files = !ls` syntax."""
500 """Handle the `files = !ls` syntax."""
501 m = _assign_system_re.match(line)
501 m = _assign_system_re.match(line)
502 if m is not None:
502 if m is not None:
503 cmd = m.group('cmd')
503 cmd = m.group('cmd')
504 lhs = m.group('lhs')
504 lhs = m.group('lhs')
505 new_line = '%s = get_ipython().getoutput(%r)' % (lhs, cmd)
505 new_line = '%s = get_ipython().getoutput(%r)' % (lhs, cmd)
506 return new_line
506 return new_line
507 return line
507 return line
508
508
509
509
510 _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\.]+)*))'
511 r'\s*=\s*%\s*(?P<cmd>.*)')
511 r'\s*=\s*%\s*(?P<cmd>.*)')
512
512
513 def transform_assign_magic(line):
513 def transform_assign_magic(line):
514 """Handle the `a = %who` syntax."""
514 """Handle the `a = %who` syntax."""
515 m = _assign_magic_re.match(line)
515 m = _assign_magic_re.match(line)
516 if m is not None:
516 if m is not None:
517 cmd = m.group('cmd')
517 cmd = m.group('cmd')
518 lhs = m.group('lhs')
518 lhs = m.group('lhs')
519 new_line = '%s = get_ipython().magic(%r)' % (lhs, cmd)
519 new_line = '%s = get_ipython().magic(%r)' % (lhs, cmd)
520 return new_line
520 return new_line
521 return line
521 return line
522
522
523
523
524 _classic_prompt_re = re.compile(r'^([ \t]*>>> |^[ \t]*\.\.\. )')
524 _classic_prompt_re = re.compile(r'^([ \t]*>>> |^[ \t]*\.\.\. )')
525
525
526 def transform_classic_prompt(line):
526 def transform_classic_prompt(line):
527 """Handle inputs that start with '>>> ' syntax."""
527 """Handle inputs that start with '>>> ' syntax."""
528
528
529 if not line or line.isspace():
529 if not line or line.isspace():
530 return line
530 return line
531 m = _classic_prompt_re.match(line)
531 m = _classic_prompt_re.match(line)
532 if m:
532 if m:
533 return line[len(m.group(0)):]
533 return line[len(m.group(0)):]
534 else:
534 else:
535 return line
535 return line
536
536
537
537
538 _ipy_prompt_re = re.compile(r'^([ \t]*In \[\d+\]: |^[ \t]*\ \ \ \.\.\.+: )')
538 _ipy_prompt_re = re.compile(r'^([ \t]*In \[\d+\]: |^[ \t]*\ \ \ \.\.\.+: )')
539
539
540 def transform_ipy_prompt(line):
540 def transform_ipy_prompt(line):
541 """Handle inputs that start classic IPython prompt syntax."""
541 """Handle inputs that start classic IPython prompt syntax."""
542
542
543 if not line or line.isspace():
543 if not line or line.isspace():
544 return line
544 return line
545 #print 'LINE: %r' % line # dbg
545 #print 'LINE: %r' % line # dbg
546 m = _ipy_prompt_re.match(line)
546 m = _ipy_prompt_re.match(line)
547 if m:
547 if m:
548 #print 'MATCH! %r -> %r' % (line, line[len(m.group(0)):]) # dbg
548 #print 'MATCH! %r -> %r' % (line, line[len(m.group(0)):]) # dbg
549 return line[len(m.group(0)):]
549 return line[len(m.group(0)):]
550 else:
550 else:
551 return line
551 return line
552
552
553
553
554 def _make_help_call(target, esc, lspace, next_input=None):
554 def _make_help_call(target, esc, lspace, next_input=None):
555 """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
556 (i.e. ? or ??)"""
556 (i.e. ? or ??)"""
557 method = 'pinfo2' if esc == '??' \
557 method = 'pinfo2' if esc == '??' \
558 else 'psearch' if '*' in target \
558 else 'psearch' if '*' in target \
559 else 'pinfo'
559 else 'pinfo'
560 arg = " ".join([method, target])
560 arg = " ".join([method, target])
561
561
562 if next_input:
562 if next_input:
563 tpl = '%sget_ipython().magic(%r, next_input=%r)'
563 tpl = '%sget_ipython().magic(%r, next_input=%r)'
564 return tpl % (lspace, arg, next_input)
564 return tpl % (lspace, arg, next_input)
565 else:
565 else:
566 return '%sget_ipython().magic(%r)' % (lspace, arg)
566 return '%sget_ipython().magic(%r)' % (lspace, arg)
567
567
568 _initial_space_re = re.compile(r'\s*')
568 _initial_space_re = re.compile(r'\s*')
569 _help_end_re = re.compile(r"""(%?
569 _help_end_re = re.compile(r"""(%?
570 [a-zA-Z_*][\w*]* # Variable name
570 [a-zA-Z_*][\w*]* # Variable name
571 (\.[a-zA-Z_*][\w*]*)* # .etc.etc
571 (\.[a-zA-Z_*][\w*]*)* # .etc.etc
572 )
572 )
573 (\?\??)$ # ? or ??""",
573 (\?\??)$ # ? or ??""",
574 re.VERBOSE)
574 re.VERBOSE)
575 def transform_help_end(line):
575 def transform_help_end(line):
576 """Translate lines with ?/?? at the end"""
576 """Translate lines with ?/?? at the end"""
577 m = _help_end_re.search(line)
577 m = _help_end_re.search(line)
578 if m is None or has_comment(line):
578 if m is None or has_comment(line):
579 return line
579 return line
580 target = m.group(1)
580 target = m.group(1)
581 esc = m.group(3)
581 esc = m.group(3)
582 lspace = _initial_space_re.match(line).group(0)
582 lspace = _initial_space_re.match(line).group(0)
583
583
584 # 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.
585 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
586
586
587 return _make_help_call(target, esc, lspace, next_input)
587 return _make_help_call(target, esc, lspace, next_input)
588
588
589
589
590 class EscapedTransformer(object):
590 class EscapedTransformer(object):
591 """Class to transform lines that are explicitly escaped out."""
591 """Class to transform lines that are explicitly escaped out."""
592
592
593 def __init__(self):
593 def __init__(self):
594 tr = { ESC_SHELL : self._tr_system,
594 tr = { ESC_SHELL : self._tr_system,
595 ESC_SH_CAP : self._tr_system2,
595 ESC_SH_CAP : self._tr_system2,
596 ESC_HELP : self._tr_help,
596 ESC_HELP : self._tr_help,
597 ESC_HELP2 : self._tr_help,
597 ESC_HELP2 : self._tr_help,
598 ESC_MAGIC : self._tr_magic,
598 ESC_MAGIC : self._tr_magic,
599 ESC_QUOTE : self._tr_quote,
599 ESC_QUOTE : self._tr_quote,
600 ESC_QUOTE2 : self._tr_quote2,
600 ESC_QUOTE2 : self._tr_quote2,
601 ESC_PAREN : self._tr_paren }
601 ESC_PAREN : self._tr_paren }
602 self.tr = tr
602 self.tr = tr
603
603
604 # Support for syntax transformations that use explicit escapes typed by the
604 # Support for syntax transformations that use explicit escapes typed by the
605 # user at the beginning of a line
605 # user at the beginning of a line
606 @staticmethod
606 @staticmethod
607 def _tr_system(line_info):
607 def _tr_system(line_info):
608 "Translate lines escaped with: !"
608 "Translate lines escaped with: !"
609 cmd = line_info.line.lstrip().lstrip(ESC_SHELL)
609 cmd = line_info.line.lstrip().lstrip(ESC_SHELL)
610 return '%sget_ipython().system(%r)' % (line_info.pre, cmd)
610 return '%sget_ipython().system(%r)' % (line_info.pre, cmd)
611
611
612 @staticmethod
612 @staticmethod
613 def _tr_system2(line_info):
613 def _tr_system2(line_info):
614 "Translate lines escaped with: !!"
614 "Translate lines escaped with: !!"
615 cmd = line_info.line.lstrip()[2:]
615 cmd = line_info.line.lstrip()[2:]
616 return '%sget_ipython().getoutput(%r)' % (line_info.pre, cmd)
616 return '%sget_ipython().getoutput(%r)' % (line_info.pre, cmd)
617
617
618 @staticmethod
618 @staticmethod
619 def _tr_help(line_info):
619 def _tr_help(line_info):
620 "Translate lines escaped with: ?/??"
620 "Translate lines escaped with: ?/??"
621 # A naked help line should just fire the intro help screen
621 # A naked help line should just fire the intro help screen
622 if not line_info.line[1:]:
622 if not line_info.line[1:]:
623 return 'get_ipython().show_usage()'
623 return 'get_ipython().show_usage()'
624
624
625 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)
626
626
627 @staticmethod
627 @staticmethod
628 def _tr_magic(line_info):
628 def _tr_magic(line_info):
629 "Translate lines escaped with: %"
629 "Translate lines escaped with: %"
630 tpl = '%sget_ipython().magic(%r)'
630 tpl = '%sget_ipython().magic(%r)'
631 cmd = ' '.join([line_info.ifun, line_info.the_rest]).strip()
631 cmd = ' '.join([line_info.ifun, line_info.the_rest]).strip()
632 return tpl % (line_info.pre, cmd)
632 return tpl % (line_info.pre, cmd)
633
633
634 @staticmethod
634 @staticmethod
635 def _tr_quote(line_info):
635 def _tr_quote(line_info):
636 "Translate lines escaped with: ,"
636 "Translate lines escaped with: ,"
637 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
637 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
638 '", "'.join(line_info.the_rest.split()) )
638 '", "'.join(line_info.the_rest.split()) )
639
639
640 @staticmethod
640 @staticmethod
641 def _tr_quote2(line_info):
641 def _tr_quote2(line_info):
642 "Translate lines escaped with: ;"
642 "Translate lines escaped with: ;"
643 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
643 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
644 line_info.the_rest)
644 line_info.the_rest)
645
645
646 @staticmethod
646 @staticmethod
647 def _tr_paren(line_info):
647 def _tr_paren(line_info):
648 "Translate lines escaped with: /"
648 "Translate lines escaped with: /"
649 return '%s%s(%s)' % (line_info.pre, line_info.ifun,
649 return '%s%s(%s)' % (line_info.pre, line_info.ifun,
650 ", ".join(line_info.the_rest.split()))
650 ", ".join(line_info.the_rest.split()))
651
651
652 def __call__(self, line):
652 def __call__(self, line):
653 """Class to transform lines that are explicitly escaped out.
653 """Class to transform lines that are explicitly escaped out.
654
654
655 This calls the above _tr_* static methods for the actual line
655 This calls the above _tr_* static methods for the actual line
656 translations."""
656 translations."""
657
657
658 # Empty lines just get returned unmodified
658 # Empty lines just get returned unmodified
659 if not line or line.isspace():
659 if not line or line.isspace():
660 return line
660 return line
661
661
662 # Get line endpoints, where the escapes can be
662 # Get line endpoints, where the escapes can be
663 line_info = LineInfo(line)
663 line_info = LineInfo(line)
664
664
665 if not line_info.esc in self.tr:
665 if not line_info.esc in self.tr:
666 # 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
667 return line
667 return line
668
668
669 return self.tr[line_info.esc](line_info)
669 return self.tr[line_info.esc](line_info)
670
670
671
671
672 # 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
673 # 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
674 # manage state.
674 # manage state.
675 transform_escaped = EscapedTransformer()
675 transform_escaped = EscapedTransformer()
676
676
677
677
678 class IPythonInputSplitter(InputSplitter):
678 class IPythonInputSplitter(InputSplitter):
679 """An input splitter that recognizes all of IPython's special syntax."""
679 """An input splitter that recognizes all of IPython's special syntax."""
680
680
681 # String with raw, untransformed input.
681 # String with raw, untransformed input.
682 source_raw = ''
682 source_raw = ''
683
683
684 # Private attributes
684 # Private attributes
685
685
686 # List with lines of raw input accumulated so far.
686 # List with lines of raw input accumulated so far.
687 _buffer_raw = None
687 _buffer_raw = None
688
688
689 def __init__(self, input_mode=None):
689 def __init__(self, input_mode=None):
690 InputSplitter.__init__(self, input_mode)
690 InputSplitter.__init__(self, input_mode)
691 self._buffer_raw = []
691 self._buffer_raw = []
692
692
693 def reset(self):
693 def reset(self):
694 """Reset the input buffer and associated state."""
694 """Reset the input buffer and associated state."""
695 InputSplitter.reset(self)
695 InputSplitter.reset(self)
696 self._buffer_raw[:] = []
696 self._buffer_raw[:] = []
697 self.source_raw = ''
697 self.source_raw = ''
698
698
699 def source_raw_reset(self):
699 def source_raw_reset(self):
700 """Return input and raw source and perform a full reset.
700 """Return input and raw source and perform a full reset.
701 """
701 """
702 out = self.source
702 out = self.source
703 out_r = self.source_raw
703 out_r = self.source_raw
704 self.reset()
704 self.reset()
705 return out, out_r
705 return out, out_r
706
706
707 def push(self, lines):
707 def push(self, lines):
708 """Push one or more lines of IPython input.
708 """Push one or more lines of IPython input.
709 """
709 """
710 if not lines:
710 if not lines:
711 return super(IPythonInputSplitter, self).push(lines)
711 return super(IPythonInputSplitter, self).push(lines)
712
712
713 # We must ensure all input is pure unicode
713 # We must ensure all input is pure unicode
714 lines = cast_unicode(lines, self.encoding)
714 lines = cast_unicode(lines, self.encoding)
715
715
716 lines_list = lines.splitlines()
716 lines_list = lines.splitlines()
717
717
718 transforms = [transform_ipy_prompt, transform_classic_prompt,
718 transforms = [transform_ipy_prompt, transform_classic_prompt,
719 transform_help_end, transform_escaped,
719 transform_help_end, transform_escaped,
720 transform_assign_system, transform_assign_magic]
720 transform_assign_system, transform_assign_magic]
721
721
722 # Transform logic
722 # Transform logic
723 #
723 #
724 # 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
725 # 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
726 # with ':' (opening an indented block). This prevents the accidental
726 # with ':' (opening an indented block). This prevents the accidental
727 # transformation of escapes inside multiline expressions like
727 # transformation of escapes inside multiline expressions like
728 # triple-quoted strings or parenthesized expressions.
728 # triple-quoted strings or parenthesized expressions.
729 #
729 #
730 # 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
731 # indented block is correctly transformed.
731 # indented block is correctly transformed.
732 #
732 #
733 # FIXME: try to find a cleaner approach for this last bit.
733 # FIXME: try to find a cleaner approach for this last bit.
734
734
735 # 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
736 # 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
737 # '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
738 # 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
739 # line.
739 # line.
740 changed_input_mode = False
740 changed_input_mode = False
741
741
742 if self.input_mode == 'cell':
742 if self.input_mode == 'cell':
743 self.reset()
743 self.reset()
744 changed_input_mode = True
744 changed_input_mode = True
745 saved_input_mode = 'cell'
745 saved_input_mode = 'cell'
746 self.input_mode = 'line'
746 self.input_mode = 'line'
747
747
748 # Store raw source before applying any transformations to it. Note
748 # Store raw source before applying any transformations to it. Note
749 # 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
750 # flush the buffer.
750 # flush the buffer.
751 self._store(lines, self._buffer_raw, 'source_raw')
751 self._store(lines, self._buffer_raw, 'source_raw')
752
752
753 try:
753 try:
754 push = super(IPythonInputSplitter, self).push
754 push = super(IPythonInputSplitter, self).push
755 buf = self._buffer
755 buf = self._buffer
756 for line in lines_list:
756 for line in lines_list:
757 if self._is_complete or not buf or \
757 if self._is_complete or not buf or \
758 (buf and (buf[-1].rstrip().endswith(':') or
758 (buf and (buf[-1].rstrip().endswith(':') or
759 buf[-1].rstrip().endswith(',')) ):
759 buf[-1].rstrip().endswith(',')) ):
760 for f in transforms:
760 for f in transforms:
761 line = f(line)
761 line = f(line)
762
762
763 out = push(line)
763 out = push(line)
764 finally:
764 finally:
765 if changed_input_mode:
765 if changed_input_mode:
766 self.input_mode = saved_input_mode
766 self.input_mode = saved_input_mode
767 return out
767 return out
@@ -1,29 +1,29 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 This module is *completely* deprecated and should no longer be used for
3 This module is *completely* deprecated and should no longer be used for
4 any purpose. Currently, we have a few parts of the core that have
4 any purpose. Currently, we have a few parts of the core that have
5 not been componentized and thus, still rely on this module. When everything
5 not been componentized and thus, still rely on this module. When everything
6 has been made into a component, this module will be sent to deathrow.
6 has been made into a component, this module will be sent to deathrow.
7 """
7 """
8
8
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2008-2009 The IPython Development Team
10 # Copyright (C) 2008-2011 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
19
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 # Classes and functions
21 # Classes and functions
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23
23
24
24
25 def get():
25 def get():
26 """Get the global InteractiveShell instance."""
26 """Get the global InteractiveShell instance."""
27 from IPython.core.interactiveshell import InteractiveShell
27 from IPython.core.interactiveshell import InteractiveShell
28 return InteractiveShell.instance()
28 return InteractiveShell.instance()
29
29
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
@@ -1,217 +1,217 b''
1 ''' A decorator-based method of constructing IPython magics with `argparse`
1 ''' A decorator-based method of constructing IPython magics with `argparse`
2 option handling.
2 option handling.
3
3
4 New magic functions can be defined like so::
4 New magic functions can be defined like so::
5
5
6 from IPython.core.magic_arguments import (argument, magic_arguments,
6 from IPython.core.magic_arguments import (argument, magic_arguments,
7 parse_argstring)
7 parse_argstring)
8
8
9 @magic_arguments()
9 @magic_arguments()
10 @argument('-o', '--option', help='An optional argument.')
10 @argument('-o', '--option', help='An optional argument.')
11 @argument('arg', type=int, help='An integer positional argument.')
11 @argument('arg', type=int, help='An integer positional argument.')
12 def magic_cool(self, arg):
12 def magic_cool(self, arg):
13 """ A really cool magic command.
13 """ A really cool magic command.
14
14
15 """
15 """
16 args = parse_argstring(magic_cool, arg)
16 args = parse_argstring(magic_cool, arg)
17 ...
17 ...
18
18
19 The `@magic_arguments` decorator marks the function as having argparse arguments.
19 The `@magic_arguments` decorator marks the function as having argparse arguments.
20 The `@argument` decorator adds an argument using the same syntax as argparse's
20 The `@argument` decorator adds an argument using the same syntax as argparse's
21 `add_argument()` method. More sophisticated uses may also require the
21 `add_argument()` method. More sophisticated uses may also require the
22 `@argument_group` or `@kwds` decorator to customize the formatting and the
22 `@argument_group` or `@kwds` decorator to customize the formatting and the
23 parsing.
23 parsing.
24
24
25 Help text for the magic is automatically generated from the docstring and the
25 Help text for the magic is automatically generated from the docstring and the
26 arguments::
26 arguments::
27
27
28 In[1]: %cool?
28 In[1]: %cool?
29 %cool [-o OPTION] arg
29 %cool [-o OPTION] arg
30
30
31 A really cool magic command.
31 A really cool magic command.
32
32
33 positional arguments:
33 positional arguments:
34 arg An integer positional argument.
34 arg An integer positional argument.
35
35
36 optional arguments:
36 optional arguments:
37 -o OPTION, --option OPTION
37 -o OPTION, --option OPTION
38 An optional argument.
38 An optional argument.
39
39
40 '''
40 '''
41 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
42 # Copyright (c) 2010, IPython Development Team.
42 # Copyright (C) 2010-2011, IPython Development Team.
43 #
43 #
44 # Distributed under the terms of the Modified BSD License.
44 # Distributed under the terms of the Modified BSD License.
45 #
45 #
46 # The full license is in the file COPYING.txt, distributed with this software.
46 # The full license is in the file COPYING.txt, distributed with this software.
47 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
48
48
49 # Our own imports
49 # Our own imports
50 from IPython.external import argparse
50 from IPython.external import argparse
51 from IPython.core.error import UsageError
51 from IPython.core.error import UsageError
52 from IPython.utils.process import arg_split
52 from IPython.utils.process import arg_split
53
53
54
54
55 class MagicArgumentParser(argparse.ArgumentParser):
55 class MagicArgumentParser(argparse.ArgumentParser):
56 """ An ArgumentParser tweaked for use by IPython magics.
56 """ An ArgumentParser tweaked for use by IPython magics.
57 """
57 """
58 def __init__(self,
58 def __init__(self,
59 prog=None,
59 prog=None,
60 usage=None,
60 usage=None,
61 description=None,
61 description=None,
62 epilog=None,
62 epilog=None,
63 version=None,
63 version=None,
64 parents=None,
64 parents=None,
65 formatter_class=argparse.HelpFormatter,
65 formatter_class=argparse.HelpFormatter,
66 prefix_chars='-',
66 prefix_chars='-',
67 argument_default=None,
67 argument_default=None,
68 conflict_handler='error',
68 conflict_handler='error',
69 add_help=False):
69 add_help=False):
70 if parents is None:
70 if parents is None:
71 parents = []
71 parents = []
72 super(MagicArgumentParser, self).__init__(prog=prog, usage=usage,
72 super(MagicArgumentParser, self).__init__(prog=prog, usage=usage,
73 description=description, epilog=epilog, version=version,
73 description=description, epilog=epilog, version=version,
74 parents=parents, formatter_class=formatter_class,
74 parents=parents, formatter_class=formatter_class,
75 prefix_chars=prefix_chars, argument_default=argument_default,
75 prefix_chars=prefix_chars, argument_default=argument_default,
76 conflict_handler=conflict_handler, add_help=add_help)
76 conflict_handler=conflict_handler, add_help=add_help)
77
77
78 def error(self, message):
78 def error(self, message):
79 """ Raise a catchable error instead of exiting.
79 """ Raise a catchable error instead of exiting.
80 """
80 """
81 raise UsageError(message)
81 raise UsageError(message)
82
82
83 def parse_argstring(self, argstring):
83 def parse_argstring(self, argstring):
84 """ Split a string into an argument list and parse that argument list.
84 """ Split a string into an argument list and parse that argument list.
85 """
85 """
86 argv = arg_split(argstring)
86 argv = arg_split(argstring)
87 return self.parse_args(argv)
87 return self.parse_args(argv)
88
88
89
89
90 def construct_parser(magic_func):
90 def construct_parser(magic_func):
91 """ Construct an argument parser using the function decorations.
91 """ Construct an argument parser using the function decorations.
92 """
92 """
93 kwds = getattr(magic_func, 'argcmd_kwds', {})
93 kwds = getattr(magic_func, 'argcmd_kwds', {})
94 if 'description' not in kwds:
94 if 'description' not in kwds:
95 kwds['description'] = getattr(magic_func, '__doc__', None)
95 kwds['description'] = getattr(magic_func, '__doc__', None)
96 arg_name = real_name(magic_func)
96 arg_name = real_name(magic_func)
97 parser = MagicArgumentParser(arg_name, **kwds)
97 parser = MagicArgumentParser(arg_name, **kwds)
98 # Reverse the list of decorators in order to apply them in the
98 # Reverse the list of decorators in order to apply them in the
99 # order in which they appear in the source.
99 # order in which they appear in the source.
100 group = None
100 group = None
101 for deco in magic_func.decorators[::-1]:
101 for deco in magic_func.decorators[::-1]:
102 result = deco.add_to_parser(parser, group)
102 result = deco.add_to_parser(parser, group)
103 if result is not None:
103 if result is not None:
104 group = result
104 group = result
105
105
106 # Replace the starting 'usage: ' with IPython's %.
106 # Replace the starting 'usage: ' with IPython's %.
107 help_text = parser.format_help()
107 help_text = parser.format_help()
108 if help_text.startswith('usage: '):
108 if help_text.startswith('usage: '):
109 help_text = help_text.replace('usage: ', '%', 1)
109 help_text = help_text.replace('usage: ', '%', 1)
110 else:
110 else:
111 help_text = '%' + help_text
111 help_text = '%' + help_text
112
112
113 # Replace the magic function's docstring with the full help text.
113 # Replace the magic function's docstring with the full help text.
114 magic_func.__doc__ = help_text
114 magic_func.__doc__ = help_text
115
115
116 return parser
116 return parser
117
117
118
118
119 def parse_argstring(magic_func, argstring):
119 def parse_argstring(magic_func, argstring):
120 """ Parse the string of arguments for the given magic function.
120 """ Parse the string of arguments for the given magic function.
121 """
121 """
122 return magic_func.parser.parse_argstring(argstring)
122 return magic_func.parser.parse_argstring(argstring)
123
123
124
124
125 def real_name(magic_func):
125 def real_name(magic_func):
126 """ Find the real name of the magic.
126 """ Find the real name of the magic.
127 """
127 """
128 magic_name = magic_func.__name__
128 magic_name = magic_func.__name__
129 if magic_name.startswith('magic_'):
129 if magic_name.startswith('magic_'):
130 magic_name = magic_name[len('magic_'):]
130 magic_name = magic_name[len('magic_'):]
131 return getattr(magic_func, 'argcmd_name', magic_name)
131 return getattr(magic_func, 'argcmd_name', magic_name)
132
132
133
133
134 class ArgDecorator(object):
134 class ArgDecorator(object):
135 """ Base class for decorators to add ArgumentParser information to a method.
135 """ Base class for decorators to add ArgumentParser information to a method.
136 """
136 """
137
137
138 def __call__(self, func):
138 def __call__(self, func):
139 if not getattr(func, 'has_arguments', False):
139 if not getattr(func, 'has_arguments', False):
140 func.has_arguments = True
140 func.has_arguments = True
141 func.decorators = []
141 func.decorators = []
142 func.decorators.append(self)
142 func.decorators.append(self)
143 return func
143 return func
144
144
145 def add_to_parser(self, parser, group):
145 def add_to_parser(self, parser, group):
146 """ Add this object's information to the parser, if necessary.
146 """ Add this object's information to the parser, if necessary.
147 """
147 """
148 pass
148 pass
149
149
150
150
151 class magic_arguments(ArgDecorator):
151 class magic_arguments(ArgDecorator):
152 """ Mark the magic as having argparse arguments and possibly adjust the
152 """ Mark the magic as having argparse arguments and possibly adjust the
153 name.
153 name.
154 """
154 """
155
155
156 def __init__(self, name=None):
156 def __init__(self, name=None):
157 self.name = name
157 self.name = name
158
158
159 def __call__(self, func):
159 def __call__(self, func):
160 if not getattr(func, 'has_arguments', False):
160 if not getattr(func, 'has_arguments', False):
161 func.has_arguments = True
161 func.has_arguments = True
162 func.decorators = []
162 func.decorators = []
163 if self.name is not None:
163 if self.name is not None:
164 func.argcmd_name = self.name
164 func.argcmd_name = self.name
165 # This should be the first decorator in the list of decorators, thus the
165 # This should be the first decorator in the list of decorators, thus the
166 # last to execute. Build the parser.
166 # last to execute. Build the parser.
167 func.parser = construct_parser(func)
167 func.parser = construct_parser(func)
168 return func
168 return func
169
169
170
170
171 class argument(ArgDecorator):
171 class argument(ArgDecorator):
172 """ Store arguments and keywords to pass to add_argument().
172 """ Store arguments and keywords to pass to add_argument().
173
173
174 Instances also serve to decorate command methods.
174 Instances also serve to decorate command methods.
175 """
175 """
176 def __init__(self, *args, **kwds):
176 def __init__(self, *args, **kwds):
177 self.args = args
177 self.args = args
178 self.kwds = kwds
178 self.kwds = kwds
179
179
180 def add_to_parser(self, parser, group):
180 def add_to_parser(self, parser, group):
181 """ Add this object's information to the parser.
181 """ Add this object's information to the parser.
182 """
182 """
183 if group is not None:
183 if group is not None:
184 parser = group
184 parser = group
185 parser.add_argument(*self.args, **self.kwds)
185 parser.add_argument(*self.args, **self.kwds)
186 return None
186 return None
187
187
188
188
189 class argument_group(ArgDecorator):
189 class argument_group(ArgDecorator):
190 """ Store arguments and keywords to pass to add_argument_group().
190 """ Store arguments and keywords to pass to add_argument_group().
191
191
192 Instances also serve to decorate command methods.
192 Instances also serve to decorate command methods.
193 """
193 """
194 def __init__(self, *args, **kwds):
194 def __init__(self, *args, **kwds):
195 self.args = args
195 self.args = args
196 self.kwds = kwds
196 self.kwds = kwds
197
197
198 def add_to_parser(self, parser, group):
198 def add_to_parser(self, parser, group):
199 """ Add this object's information to the parser.
199 """ Add this object's information to the parser.
200 """
200 """
201 return parser.add_argument_group(*self.args, **self.kwds)
201 return parser.add_argument_group(*self.args, **self.kwds)
202
202
203
203
204 class kwds(ArgDecorator):
204 class kwds(ArgDecorator):
205 """ Provide other keywords to the sub-parser constructor.
205 """ Provide other keywords to the sub-parser constructor.
206 """
206 """
207 def __init__(self, **kwds):
207 def __init__(self, **kwds):
208 self.kwds = kwds
208 self.kwds = kwds
209
209
210 def __call__(self, func):
210 def __call__(self, func):
211 func = super(kwds, self).__call__(func)
211 func = super(kwds, self).__call__(func)
212 func.argcmd_kwds = self.kwds
212 func.argcmd_kwds = self.kwds
213 return func
213 return func
214
214
215
215
216 __all__ = ['magic_arguments', 'argument', 'argument_group', 'kwds',
216 __all__ = ['magic_arguments', 'argument', 'argument_group', 'kwds',
217 'parse_argstring']
217 'parse_argstring']
@@ -1,340 +1,340 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Paging capabilities for IPython.core
3 Paging capabilities for IPython.core
4
4
5 Authors:
5 Authors:
6
6
7 * Brian Granger
7 * Brian Granger
8 * Fernando Perez
8 * Fernando Perez
9
9
10 Notes
10 Notes
11 -----
11 -----
12
12
13 For now this uses ipapi, so it can't be in IPython.utils. If we can get
13 For now this uses ipapi, so it can't be in IPython.utils. If we can get
14 rid of that dependency, we could move it there.
14 rid of that dependency, we could move it there.
15 -----
15 -----
16 """
16 """
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Copyright (C) 2008-2009 The IPython Development Team
19 # Copyright (C) 2008-2011 The IPython Development Team
20 #
20 #
21 # Distributed under the terms of the BSD License. The full license is in
21 # Distributed under the terms of the BSD License. The full license is in
22 # the file COPYING, distributed as part of this software.
22 # the file COPYING, distributed as part of this software.
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24
24
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26 # Imports
26 # Imports
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28
28
29 import os
29 import os
30 import re
30 import re
31 import sys
31 import sys
32 import tempfile
32 import tempfile
33
33
34 from io import UnsupportedOperation
34 from io import UnsupportedOperation
35
35
36 from IPython.core import ipapi
36 from IPython.core import ipapi
37 from IPython.core.error import TryNext
37 from IPython.core.error import TryNext
38 from IPython.utils.cursesimport import use_curses
38 from IPython.utils.cursesimport import use_curses
39 from IPython.utils.data import chop
39 from IPython.utils.data import chop
40 from IPython.utils import io
40 from IPython.utils import io
41 from IPython.utils.process import system
41 from IPython.utils.process import system
42 from IPython.utils.terminal import get_terminal_size
42 from IPython.utils.terminal import get_terminal_size
43
43
44
44
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46 # Classes and functions
46 # Classes and functions
47 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
48
48
49 esc_re = re.compile(r"(\x1b[^m]+m)")
49 esc_re = re.compile(r"(\x1b[^m]+m)")
50
50
51 def page_dumb(strng, start=0, screen_lines=25):
51 def page_dumb(strng, start=0, screen_lines=25):
52 """Very dumb 'pager' in Python, for when nothing else works.
52 """Very dumb 'pager' in Python, for when nothing else works.
53
53
54 Only moves forward, same interface as page(), except for pager_cmd and
54 Only moves forward, same interface as page(), except for pager_cmd and
55 mode."""
55 mode."""
56
56
57 out_ln = strng.splitlines()[start:]
57 out_ln = strng.splitlines()[start:]
58 screens = chop(out_ln,screen_lines-1)
58 screens = chop(out_ln,screen_lines-1)
59 if len(screens) == 1:
59 if len(screens) == 1:
60 print >>io.stdout, os.linesep.join(screens[0])
60 print >>io.stdout, os.linesep.join(screens[0])
61 else:
61 else:
62 last_escape = ""
62 last_escape = ""
63 for scr in screens[0:-1]:
63 for scr in screens[0:-1]:
64 hunk = os.linesep.join(scr)
64 hunk = os.linesep.join(scr)
65 print >>io.stdout, last_escape + hunk
65 print >>io.stdout, last_escape + hunk
66 if not page_more():
66 if not page_more():
67 return
67 return
68 esc_list = esc_re.findall(hunk)
68 esc_list = esc_re.findall(hunk)
69 if len(esc_list) > 0:
69 if len(esc_list) > 0:
70 last_escape = esc_list[-1]
70 last_escape = esc_list[-1]
71 print >>io.stdout, last_escape + os.linesep.join(screens[-1])
71 print >>io.stdout, last_escape + os.linesep.join(screens[-1])
72
72
73 def _detect_screen_size(use_curses, screen_lines_def):
73 def _detect_screen_size(use_curses, screen_lines_def):
74 """Attempt to work out the number of lines on the screen.
74 """Attempt to work out the number of lines on the screen.
75
75
76 This is called by page(). It can raise an error (e.g. when run in the
76 This is called by page(). It can raise an error (e.g. when run in the
77 test suite), so it's separated out so it can easily be called in a try block.
77 test suite), so it's separated out so it can easily be called in a try block.
78 """
78 """
79 TERM = os.environ.get('TERM',None)
79 TERM = os.environ.get('TERM',None)
80 if (TERM=='xterm' or TERM=='xterm-color') and sys.platform != 'sunos5':
80 if (TERM=='xterm' or TERM=='xterm-color') and sys.platform != 'sunos5':
81 local_use_curses = use_curses
81 local_use_curses = use_curses
82 else:
82 else:
83 # curses causes problems on many terminals other than xterm, and
83 # curses causes problems on many terminals other than xterm, and
84 # some termios calls lock up on Sun OS5.
84 # some termios calls lock up on Sun OS5.
85 local_use_curses = False
85 local_use_curses = False
86 if local_use_curses:
86 if local_use_curses:
87 import termios
87 import termios
88 import curses
88 import curses
89 # There is a bug in curses, where *sometimes* it fails to properly
89 # There is a bug in curses, where *sometimes* it fails to properly
90 # initialize, and then after the endwin() call is made, the
90 # initialize, and then after the endwin() call is made, the
91 # terminal is left in an unusable state. Rather than trying to
91 # terminal is left in an unusable state. Rather than trying to
92 # check everytime for this (by requesting and comparing termios
92 # check everytime for this (by requesting and comparing termios
93 # flags each time), we just save the initial terminal state and
93 # flags each time), we just save the initial terminal state and
94 # unconditionally reset it every time. It's cheaper than making
94 # unconditionally reset it every time. It's cheaper than making
95 # the checks.
95 # the checks.
96 term_flags = termios.tcgetattr(sys.stdout)
96 term_flags = termios.tcgetattr(sys.stdout)
97
97
98 # Curses modifies the stdout buffer size by default, which messes
98 # Curses modifies the stdout buffer size by default, which messes
99 # up Python's normal stdout buffering. This would manifest itself
99 # up Python's normal stdout buffering. This would manifest itself
100 # to IPython users as delayed printing on stdout after having used
100 # to IPython users as delayed printing on stdout after having used
101 # the pager.
101 # the pager.
102 #
102 #
103 # We can prevent this by manually setting the NCURSES_NO_SETBUF
103 # We can prevent this by manually setting the NCURSES_NO_SETBUF
104 # environment variable. For more details, see:
104 # environment variable. For more details, see:
105 # http://bugs.python.org/issue10144
105 # http://bugs.python.org/issue10144
106 NCURSES_NO_SETBUF = os.environ.get('NCURSES_NO_SETBUF', None)
106 NCURSES_NO_SETBUF = os.environ.get('NCURSES_NO_SETBUF', None)
107 os.environ['NCURSES_NO_SETBUF'] = ''
107 os.environ['NCURSES_NO_SETBUF'] = ''
108
108
109 # Proceed with curses initialization
109 # Proceed with curses initialization
110 scr = curses.initscr()
110 scr = curses.initscr()
111 screen_lines_real,screen_cols = scr.getmaxyx()
111 screen_lines_real,screen_cols = scr.getmaxyx()
112 curses.endwin()
112 curses.endwin()
113
113
114 # Restore environment
114 # Restore environment
115 if NCURSES_NO_SETBUF is None:
115 if NCURSES_NO_SETBUF is None:
116 del os.environ['NCURSES_NO_SETBUF']
116 del os.environ['NCURSES_NO_SETBUF']
117 else:
117 else:
118 os.environ['NCURSES_NO_SETBUF'] = NCURSES_NO_SETBUF
118 os.environ['NCURSES_NO_SETBUF'] = NCURSES_NO_SETBUF
119
119
120 # Restore terminal state in case endwin() didn't.
120 # Restore terminal state in case endwin() didn't.
121 termios.tcsetattr(sys.stdout,termios.TCSANOW,term_flags)
121 termios.tcsetattr(sys.stdout,termios.TCSANOW,term_flags)
122 # Now we have what we needed: the screen size in rows/columns
122 # Now we have what we needed: the screen size in rows/columns
123 return screen_lines_real
123 return screen_lines_real
124 #print '***Screen size:',screen_lines_real,'lines x',\
124 #print '***Screen size:',screen_lines_real,'lines x',\
125 #screen_cols,'columns.' # dbg
125 #screen_cols,'columns.' # dbg
126 else:
126 else:
127 return screen_lines_def
127 return screen_lines_def
128
128
129 def page(strng, start=0, screen_lines=0, pager_cmd=None):
129 def page(strng, start=0, screen_lines=0, pager_cmd=None):
130 """Print a string, piping through a pager after a certain length.
130 """Print a string, piping through a pager after a certain length.
131
131
132 The screen_lines parameter specifies the number of *usable* lines of your
132 The screen_lines parameter specifies the number of *usable* lines of your
133 terminal screen (total lines minus lines you need to reserve to show other
133 terminal screen (total lines minus lines you need to reserve to show other
134 information).
134 information).
135
135
136 If you set screen_lines to a number <=0, page() will try to auto-determine
136 If you set screen_lines to a number <=0, page() will try to auto-determine
137 your screen size and will only use up to (screen_size+screen_lines) for
137 your screen size and will only use up to (screen_size+screen_lines) for
138 printing, paging after that. That is, if you want auto-detection but need
138 printing, paging after that. That is, if you want auto-detection but need
139 to reserve the bottom 3 lines of the screen, use screen_lines = -3, and for
139 to reserve the bottom 3 lines of the screen, use screen_lines = -3, and for
140 auto-detection without any lines reserved simply use screen_lines = 0.
140 auto-detection without any lines reserved simply use screen_lines = 0.
141
141
142 If a string won't fit in the allowed lines, it is sent through the
142 If a string won't fit in the allowed lines, it is sent through the
143 specified pager command. If none given, look for PAGER in the environment,
143 specified pager command. If none given, look for PAGER in the environment,
144 and ultimately default to less.
144 and ultimately default to less.
145
145
146 If no system pager works, the string is sent through a 'dumb pager'
146 If no system pager works, the string is sent through a 'dumb pager'
147 written in python, very simplistic.
147 written in python, very simplistic.
148 """
148 """
149
149
150 # Some routines may auto-compute start offsets incorrectly and pass a
150 # Some routines may auto-compute start offsets incorrectly and pass a
151 # negative value. Offset to 0 for robustness.
151 # negative value. Offset to 0 for robustness.
152 start = max(0, start)
152 start = max(0, start)
153
153
154 # first, try the hook
154 # first, try the hook
155 ip = ipapi.get()
155 ip = ipapi.get()
156 if ip:
156 if ip:
157 try:
157 try:
158 ip.hooks.show_in_pager(strng)
158 ip.hooks.show_in_pager(strng)
159 return
159 return
160 except TryNext:
160 except TryNext:
161 pass
161 pass
162
162
163 # Ugly kludge, but calling curses.initscr() flat out crashes in emacs
163 # Ugly kludge, but calling curses.initscr() flat out crashes in emacs
164 TERM = os.environ.get('TERM','dumb')
164 TERM = os.environ.get('TERM','dumb')
165 if TERM in ['dumb','emacs'] and os.name != 'nt':
165 if TERM in ['dumb','emacs'] and os.name != 'nt':
166 print strng
166 print strng
167 return
167 return
168 # chop off the topmost part of the string we don't want to see
168 # chop off the topmost part of the string we don't want to see
169 str_lines = strng.splitlines()[start:]
169 str_lines = strng.splitlines()[start:]
170 str_toprint = os.linesep.join(str_lines)
170 str_toprint = os.linesep.join(str_lines)
171 num_newlines = len(str_lines)
171 num_newlines = len(str_lines)
172 len_str = len(str_toprint)
172 len_str = len(str_toprint)
173
173
174 # Dumb heuristics to guesstimate number of on-screen lines the string
174 # Dumb heuristics to guesstimate number of on-screen lines the string
175 # takes. Very basic, but good enough for docstrings in reasonable
175 # takes. Very basic, but good enough for docstrings in reasonable
176 # terminals. If someone later feels like refining it, it's not hard.
176 # terminals. If someone later feels like refining it, it's not hard.
177 numlines = max(num_newlines,int(len_str/80)+1)
177 numlines = max(num_newlines,int(len_str/80)+1)
178
178
179 screen_lines_def = get_terminal_size()[1]
179 screen_lines_def = get_terminal_size()[1]
180
180
181 # auto-determine screen size
181 # auto-determine screen size
182 if screen_lines <= 0:
182 if screen_lines <= 0:
183 try:
183 try:
184 screen_lines += _detect_screen_size(use_curses, screen_lines_def)
184 screen_lines += _detect_screen_size(use_curses, screen_lines_def)
185 except (TypeError, UnsupportedOperation):
185 except (TypeError, UnsupportedOperation):
186 print >>io.stdout, str_toprint
186 print >>io.stdout, str_toprint
187 return
187 return
188
188
189 #print 'numlines',numlines,'screenlines',screen_lines # dbg
189 #print 'numlines',numlines,'screenlines',screen_lines # dbg
190 if numlines <= screen_lines :
190 if numlines <= screen_lines :
191 #print '*** normal print' # dbg
191 #print '*** normal print' # dbg
192 print >>io.stdout, str_toprint
192 print >>io.stdout, str_toprint
193 else:
193 else:
194 # Try to open pager and default to internal one if that fails.
194 # Try to open pager and default to internal one if that fails.
195 # All failure modes are tagged as 'retval=1', to match the return
195 # All failure modes are tagged as 'retval=1', to match the return
196 # value of a failed system command. If any intermediate attempt
196 # value of a failed system command. If any intermediate attempt
197 # sets retval to 1, at the end we resort to our own page_dumb() pager.
197 # sets retval to 1, at the end we resort to our own page_dumb() pager.
198 pager_cmd = get_pager_cmd(pager_cmd)
198 pager_cmd = get_pager_cmd(pager_cmd)
199 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
199 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
200 if os.name == 'nt':
200 if os.name == 'nt':
201 if pager_cmd.startswith('type'):
201 if pager_cmd.startswith('type'):
202 # The default WinXP 'type' command is failing on complex strings.
202 # The default WinXP 'type' command is failing on complex strings.
203 retval = 1
203 retval = 1
204 else:
204 else:
205 tmpname = tempfile.mktemp('.txt')
205 tmpname = tempfile.mktemp('.txt')
206 tmpfile = file(tmpname,'wt')
206 tmpfile = file(tmpname,'wt')
207 tmpfile.write(strng)
207 tmpfile.write(strng)
208 tmpfile.close()
208 tmpfile.close()
209 cmd = "%s < %s" % (pager_cmd,tmpname)
209 cmd = "%s < %s" % (pager_cmd,tmpname)
210 if os.system(cmd):
210 if os.system(cmd):
211 retval = 1
211 retval = 1
212 else:
212 else:
213 retval = None
213 retval = None
214 os.remove(tmpname)
214 os.remove(tmpname)
215 else:
215 else:
216 try:
216 try:
217 retval = None
217 retval = None
218 # if I use popen4, things hang. No idea why.
218 # if I use popen4, things hang. No idea why.
219 #pager,shell_out = os.popen4(pager_cmd)
219 #pager,shell_out = os.popen4(pager_cmd)
220 pager = os.popen(pager_cmd,'w')
220 pager = os.popen(pager_cmd,'w')
221 pager.write(strng)
221 pager.write(strng)
222 pager.close()
222 pager.close()
223 retval = pager.close() # success returns None
223 retval = pager.close() # success returns None
224 except IOError,msg: # broken pipe when user quits
224 except IOError,msg: # broken pipe when user quits
225 if msg.args == (32,'Broken pipe'):
225 if msg.args == (32,'Broken pipe'):
226 retval = None
226 retval = None
227 else:
227 else:
228 retval = 1
228 retval = 1
229 except OSError:
229 except OSError:
230 # Other strange problems, sometimes seen in Win2k/cygwin
230 # Other strange problems, sometimes seen in Win2k/cygwin
231 retval = 1
231 retval = 1
232 if retval is not None:
232 if retval is not None:
233 page_dumb(strng,screen_lines=screen_lines)
233 page_dumb(strng,screen_lines=screen_lines)
234
234
235
235
236 def page_file(fname, start=0, pager_cmd=None):
236 def page_file(fname, start=0, pager_cmd=None):
237 """Page a file, using an optional pager command and starting line.
237 """Page a file, using an optional pager command and starting line.
238 """
238 """
239
239
240 pager_cmd = get_pager_cmd(pager_cmd)
240 pager_cmd = get_pager_cmd(pager_cmd)
241 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
241 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
242
242
243 try:
243 try:
244 if os.environ['TERM'] in ['emacs','dumb']:
244 if os.environ['TERM'] in ['emacs','dumb']:
245 raise EnvironmentError
245 raise EnvironmentError
246 system(pager_cmd + ' ' + fname)
246 system(pager_cmd + ' ' + fname)
247 except:
247 except:
248 try:
248 try:
249 if start > 0:
249 if start > 0:
250 start -= 1
250 start -= 1
251 page(open(fname).read(),start)
251 page(open(fname).read(),start)
252 except:
252 except:
253 print 'Unable to show file',`fname`
253 print 'Unable to show file',`fname`
254
254
255
255
256 def get_pager_cmd(pager_cmd=None):
256 def get_pager_cmd(pager_cmd=None):
257 """Return a pager command.
257 """Return a pager command.
258
258
259 Makes some attempts at finding an OS-correct one.
259 Makes some attempts at finding an OS-correct one.
260 """
260 """
261 if os.name == 'posix':
261 if os.name == 'posix':
262 default_pager_cmd = 'less -r' # -r for color control sequences
262 default_pager_cmd = 'less -r' # -r for color control sequences
263 elif os.name in ['nt','dos']:
263 elif os.name in ['nt','dos']:
264 default_pager_cmd = 'type'
264 default_pager_cmd = 'type'
265
265
266 if pager_cmd is None:
266 if pager_cmd is None:
267 try:
267 try:
268 pager_cmd = os.environ['PAGER']
268 pager_cmd = os.environ['PAGER']
269 except:
269 except:
270 pager_cmd = default_pager_cmd
270 pager_cmd = default_pager_cmd
271 return pager_cmd
271 return pager_cmd
272
272
273
273
274 def get_pager_start(pager, start):
274 def get_pager_start(pager, start):
275 """Return the string for paging files with an offset.
275 """Return the string for paging files with an offset.
276
276
277 This is the '+N' argument which less and more (under Unix) accept.
277 This is the '+N' argument which less and more (under Unix) accept.
278 """
278 """
279
279
280 if pager in ['less','more']:
280 if pager in ['less','more']:
281 if start:
281 if start:
282 start_string = '+' + str(start)
282 start_string = '+' + str(start)
283 else:
283 else:
284 start_string = ''
284 start_string = ''
285 else:
285 else:
286 start_string = ''
286 start_string = ''
287 return start_string
287 return start_string
288
288
289
289
290 # (X)emacs on win32 doesn't like to be bypassed with msvcrt.getch()
290 # (X)emacs on win32 doesn't like to be bypassed with msvcrt.getch()
291 if os.name == 'nt' and os.environ.get('TERM','dumb') != 'emacs':
291 if os.name == 'nt' and os.environ.get('TERM','dumb') != 'emacs':
292 import msvcrt
292 import msvcrt
293 def page_more():
293 def page_more():
294 """ Smart pausing between pages
294 """ Smart pausing between pages
295
295
296 @return: True if need print more lines, False if quit
296 @return: True if need print more lines, False if quit
297 """
297 """
298 io.stdout.write('---Return to continue, q to quit--- ')
298 io.stdout.write('---Return to continue, q to quit--- ')
299 ans = msvcrt.getch()
299 ans = msvcrt.getch()
300 if ans in ("q", "Q"):
300 if ans in ("q", "Q"):
301 result = False
301 result = False
302 else:
302 else:
303 result = True
303 result = True
304 io.stdout.write("\b"*37 + " "*37 + "\b"*37)
304 io.stdout.write("\b"*37 + " "*37 + "\b"*37)
305 return result
305 return result
306 else:
306 else:
307 def page_more():
307 def page_more():
308 ans = raw_input('---Return to continue, q to quit--- ')
308 ans = raw_input('---Return to continue, q to quit--- ')
309 if ans.lower().startswith('q'):
309 if ans.lower().startswith('q'):
310 return False
310 return False
311 else:
311 else:
312 return True
312 return True
313
313
314
314
315 def snip_print(str,width = 75,print_full = 0,header = ''):
315 def snip_print(str,width = 75,print_full = 0,header = ''):
316 """Print a string snipping the midsection to fit in width.
316 """Print a string snipping the midsection to fit in width.
317
317
318 print_full: mode control:
318 print_full: mode control:
319 - 0: only snip long strings
319 - 0: only snip long strings
320 - 1: send to page() directly.
320 - 1: send to page() directly.
321 - 2: snip long strings and ask for full length viewing with page()
321 - 2: snip long strings and ask for full length viewing with page()
322 Return 1 if snipping was necessary, 0 otherwise."""
322 Return 1 if snipping was necessary, 0 otherwise."""
323
323
324 if print_full == 1:
324 if print_full == 1:
325 page(header+str)
325 page(header+str)
326 return 0
326 return 0
327
327
328 print header,
328 print header,
329 if len(str) < width:
329 if len(str) < width:
330 print str
330 print str
331 snip = 0
331 snip = 0
332 else:
332 else:
333 whalf = int((width -5)/2)
333 whalf = int((width -5)/2)
334 print str[:whalf] + ' <...> ' + str[-whalf:]
334 print str[:whalf] + ' <...> ' + str[-whalf:]
335 snip = 1
335 snip = 1
336 if snip and print_full == 2:
336 if snip and print_full == 2:
337 if raw_input(header+' Snipped. View (y/n)? [N]').lower() == 'y':
337 if raw_input(header+' Snipped. View (y/n)? [N]').lower() == 'y':
338 page(str)
338 page(str)
339 return snip
339 return snip
340
340
@@ -1,41 +1,41 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Payload system for IPython.
2 """Payload system for IPython.
3
3
4 Authors:
4 Authors:
5
5
6 * Fernando Perez
6 * Fernando Perez
7 * Brian Granger
7 * Brian Granger
8 """
8 """
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Copyright (C) 2008-2010 The IPython Development Team
11 # Copyright (C) 2008-2011 The IPython Development Team
12 #
12 #
13 # Distributed under the terms of the BSD License. The full license is in
13 # Distributed under the terms of the BSD License. The full license is in
14 # the file COPYING, distributed as part of this software.
14 # the file COPYING, distributed as part of this software.
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Imports
18 # Imports
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20
20
21 from IPython.config.configurable import Configurable
21 from IPython.config.configurable import Configurable
22 from IPython.utils.traitlets import List
22 from IPython.utils.traitlets import List
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Main payload class
25 # Main payload class
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
27
28 class PayloadManager(Configurable):
28 class PayloadManager(Configurable):
29
29
30 _payload = List([])
30 _payload = List([])
31
31
32 def write_payload(self, data):
32 def write_payload(self, data):
33 if not isinstance(data, dict):
33 if not isinstance(data, dict):
34 raise TypeError('Each payload write must be a dict, got: %r' % data)
34 raise TypeError('Each payload write must be a dict, got: %r' % data)
35 self._payload.append(data)
35 self._payload.append(data)
36
36
37 def read_payload(self):
37 def read_payload(self):
38 return self._payload
38 return self._payload
39
39
40 def clear_payload(self):
40 def clear_payload(self):
41 self._payload = []
41 self._payload = []
@@ -1,96 +1,96 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 A payload based version of page.
3 A payload based version of page.
4
4
5 Authors:
5 Authors:
6
6
7 * Brian Granger
7 * Brian Granger
8 * Fernando Perez
8 * Fernando Perez
9 """
9 """
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Copyright (C) 2008-2010 The IPython Development Team
12 # Copyright (C) 2008-2011 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 # Third-party
22 # Third-party
23 try:
23 try:
24 from docutils.core import publish_string
24 from docutils.core import publish_string
25 except ImportError:
25 except ImportError:
26 # html paging won't be available, but we don't raise any errors. It's a
26 # html paging won't be available, but we don't raise any errors. It's a
27 # purely optional feature.
27 # purely optional feature.
28 pass
28 pass
29
29
30 # Our own
30 # Our own
31 from IPython.core.interactiveshell import InteractiveShell
31 from IPython.core.interactiveshell import InteractiveShell
32
32
33 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
34 # Classes and functions
34 # Classes and functions
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36
36
37 def page(strng, start=0, screen_lines=0, pager_cmd=None,
37 def page(strng, start=0, screen_lines=0, pager_cmd=None,
38 html=None, auto_html=False):
38 html=None, auto_html=False):
39 """Print a string, piping through a pager.
39 """Print a string, piping through a pager.
40
40
41 This version ignores the screen_lines and pager_cmd arguments and uses
41 This version ignores the screen_lines and pager_cmd arguments and uses
42 IPython's payload system instead.
42 IPython's payload system instead.
43
43
44 Parameters
44 Parameters
45 ----------
45 ----------
46 strng : str
46 strng : str
47 Text to page.
47 Text to page.
48
48
49 start : int
49 start : int
50 Starting line at which to place the display.
50 Starting line at which to place the display.
51
51
52 html : str, optional
52 html : str, optional
53 If given, an html string to send as well.
53 If given, an html string to send as well.
54
54
55 auto_html : bool, optional
55 auto_html : bool, optional
56 If true, the input string is assumed to be valid reStructuredText and is
56 If true, the input string is assumed to be valid reStructuredText and is
57 converted to HTML with docutils. Note that if docutils is not found,
57 converted to HTML with docutils. Note that if docutils is not found,
58 this option is silently ignored.
58 this option is silently ignored.
59
59
60 Note
60 Note
61 ----
61 ----
62
62
63 Only one of the ``html`` and ``auto_html`` options can be given, not
63 Only one of the ``html`` and ``auto_html`` options can be given, not
64 both.
64 both.
65 """
65 """
66
66
67 # Some routines may auto-compute start offsets incorrectly and pass a
67 # Some routines may auto-compute start offsets incorrectly and pass a
68 # negative value. Offset to 0 for robustness.
68 # negative value. Offset to 0 for robustness.
69 start = max(0, start)
69 start = max(0, start)
70 shell = InteractiveShell.instance()
70 shell = InteractiveShell.instance()
71
71
72 if auto_html:
72 if auto_html:
73 try:
73 try:
74 # These defaults ensure user configuration variables for docutils
74 # These defaults ensure user configuration variables for docutils
75 # are not loaded, only our config is used here.
75 # are not loaded, only our config is used here.
76 defaults = {'file_insertion_enabled': 0,
76 defaults = {'file_insertion_enabled': 0,
77 'raw_enabled': 0,
77 'raw_enabled': 0,
78 '_disable_config': 1}
78 '_disable_config': 1}
79 html = publish_string(strng, writer_name='html',
79 html = publish_string(strng, writer_name='html',
80 settings_overrides=defaults)
80 settings_overrides=defaults)
81 except:
81 except:
82 pass
82 pass
83
83
84 payload = dict(
84 payload = dict(
85 source='IPython.zmq.page.page',
85 source='IPython.zmq.page.page',
86 text=strng,
86 text=strng,
87 html=html,
87 html=html,
88 start_line_number=start
88 start_line_number=start
89 )
89 )
90 shell.payload_manager.write_payload(payload)
90 shell.payload_manager.write_payload(payload)
91
91
92
92
93 def install_payload_page():
93 def install_payload_page():
94 """Install this version of page as IPython.core.page.page."""
94 """Install this version of page as IPython.core.page.page."""
95 from IPython.core import page as corepage
95 from IPython.core import page as corepage
96 corepage.page = page
96 corepage.page = page
@@ -1,51 +1,51 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """IPython plugins.
2 """IPython plugins.
3
3
4 Authors:
4 Authors:
5
5
6 * Brian Granger
6 * Brian Granger
7 """
7 """
8
8
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2010 The IPython Development Team
10 # Copyright (C) 2010-2011 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
19
20 from IPython.config.configurable import Configurable
20 from IPython.config.configurable import Configurable
21 from IPython.utils.traitlets import Dict
21 from IPython.utils.traitlets import Dict
22
22
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24 # Main class
24 # Main class
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26
26
27 class PluginManager(Configurable):
27 class PluginManager(Configurable):
28 """A manager for IPython plugins."""
28 """A manager for IPython plugins."""
29
29
30 plugins = Dict({})
30 plugins = Dict({})
31
31
32 def __init__(self, config=None):
32 def __init__(self, config=None):
33 super(PluginManager, self).__init__(config=config)
33 super(PluginManager, self).__init__(config=config)
34
34
35 def register_plugin(self, name, plugin):
35 def register_plugin(self, name, plugin):
36 if not isinstance(plugin, Plugin):
36 if not isinstance(plugin, Plugin):
37 raise TypeError('Expected Plugin, got: %r' % plugin)
37 raise TypeError('Expected Plugin, got: %r' % plugin)
38 if self.plugins.has_key(name):
38 if self.plugins.has_key(name):
39 raise KeyError('Plugin with name already exists: %r' % name)
39 raise KeyError('Plugin with name already exists: %r' % name)
40 self.plugins[name] = plugin
40 self.plugins[name] = plugin
41
41
42 def unregister_plugin(self, name):
42 def unregister_plugin(self, name):
43 del self.plugins[name]
43 del self.plugins[name]
44
44
45 def get_plugin(self, name, default=None):
45 def get_plugin(self, name, default=None):
46 return self.plugins.get(name, default)
46 return self.plugins.get(name, default)
47
47
48
48
49 class Plugin(Configurable):
49 class Plugin(Configurable):
50 """Base class for IPython plugins."""
50 """Base class for IPython plugins."""
51 pass
51 pass
@@ -1,946 +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-2011 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.autoattr import auto_attr
39 from IPython.utils.autoattr import auto_attr
40
40
41 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
42 # Global utilities, errors and constants
42 # Global utilities, errors and constants
43 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
44
44
45 # Warning, these cannot be changed unless various regular expressions
45 # Warning, these cannot be changed unless various regular expressions
46 # 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.
47 ESC_SHELL = '!'
47 ESC_SHELL = '!'
48 ESC_SH_CAP = '!!'
48 ESC_SH_CAP = '!!'
49 ESC_HELP = '?'
49 ESC_HELP = '?'
50 ESC_MAGIC = '%'
50 ESC_MAGIC = '%'
51 ESC_QUOTE = ','
51 ESC_QUOTE = ','
52 ESC_QUOTE2 = ';'
52 ESC_QUOTE2 = ';'
53 ESC_PAREN = '/'
53 ESC_PAREN = '/'
54
54
55
55
56 class PrefilterError(Exception):
56 class PrefilterError(Exception):
57 pass
57 pass
58
58
59
59
60 # RegExp to identify potential function names
60 # RegExp to identify potential function names
61 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_.]*) *$')
62
62
63 # RegExp to exclude strings with this start from autocalling. In
63 # RegExp to exclude strings with this start from autocalling. In
64 # 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
65 # 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
66 # characters '!=()' don't need to be checked for, as the checkPythonChars
66 # characters '!=()' don't need to be checked for, as the checkPythonChars
67 # routine explicitely does so, to catch direct calls and rebindings of
67 # routine explicitely does so, to catch direct calls and rebindings of
68 # existing names.
68 # existing names.
69
69
70 # 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
71 # it affects the rest of the group in square brackets.
71 # it affects the rest of the group in square brackets.
72 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
72 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
73 r'|^is |^not |^in |^and |^or ')
73 r'|^is |^not |^in |^and |^or ')
74
74
75 # 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
76 # (experimental). For this to work, the line_split regexp would need
76 # (experimental). For this to work, the line_split regexp would need
77 # 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
78 # 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_.
79 #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_.\[\]]*) ?$')
80
80
81
81
82 # Handler Check Utilities
82 # Handler Check Utilities
83 def is_shadowed(identifier, ip):
83 def is_shadowed(identifier, ip):
84 """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
85 the alias and magic namespaces? Note that an identifier is different
85 the alias and magic namespaces? Note that an identifier is different
86 than ifun, because it can not contain a '.' character."""
86 than ifun, because it can not contain a '.' character."""
87 # This is much safer than calling ofind, which can change state
87 # This is much safer than calling ofind, which can change state
88 return (identifier in ip.user_ns \
88 return (identifier in ip.user_ns \
89 or identifier in ip.internal_ns \
89 or identifier in ip.internal_ns \
90 or identifier in ip.ns_table['builtin'])
90 or identifier in ip.ns_table['builtin'])
91
91
92
92
93 #-----------------------------------------------------------------------------
93 #-----------------------------------------------------------------------------
94 # Main Prefilter manager
94 # Main Prefilter manager
95 #-----------------------------------------------------------------------------
95 #-----------------------------------------------------------------------------
96
96
97
97
98 class PrefilterManager(Configurable):
98 class PrefilterManager(Configurable):
99 """Main prefilter component.
99 """Main prefilter component.
100
100
101 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
102 prefilter consumes lines of input and produces transformed lines of
102 prefilter consumes lines of input and produces transformed lines of
103 input.
103 input.
104
104
105 The iplementation consists of two phases:
105 The iplementation consists of two phases:
106
106
107 1. Transformers
107 1. Transformers
108 2. Checkers and handlers
108 2. Checkers and handlers
109
109
110 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
111 everything in the transformers.
111 everything in the transformers.
112
112
113 The transformers are instances of :class:`PrefilterTransformer` and have
113 The transformers are instances of :class:`PrefilterTransformer` and have
114 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
115 transformed line. The transformation can be accomplished using any
115 transformed line. The transformation can be accomplished using any
116 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
117 ship :mod:`pyparsing` in :mod:`IPython.external` for use in transformers.
117 ship :mod:`pyparsing` in :mod:`IPython.external` for use in transformers.
118
118
119 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,
120 which are instances of :class:`PrefilterChecker`. The line is passed to
120 which are instances of :class:`PrefilterChecker`. The line is passed to
121 the :meth:`check` method, which either returns `None` or a
121 the :meth:`check` method, which either returns `None` or a
122 :class:`PrefilterHandler` instance. If `None` is returned, the other
122 :class:`PrefilterHandler` instance. If `None` is returned, the other
123 checkers are tried. If an :class:`PrefilterHandler` instance is returned,
123 checkers are tried. If an :class:`PrefilterHandler` instance is returned,
124 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
125 handler and no further checkers are tried.
125 handler and no further checkers are tried.
126
126
127 Both transformers and checkers have a `priority` attribute, that determines
127 Both transformers and checkers have a `priority` attribute, that determines
128 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.
129
129
130 Both transformers and checkers also have `enabled` attribute, which is
130 Both transformers and checkers also have `enabled` attribute, which is
131 a boolean that determines if the instance is used.
131 a boolean that determines if the instance is used.
132
132
133 Users or developers can change the priority or enabled attribute of
133 Users or developers can change the priority or enabled attribute of
134 transformers or checkers, but they must call the :meth:`sort_checkers`
134 transformers or checkers, but they must call the :meth:`sort_checkers`
135 or :meth:`sort_transformers` method after changing the priority.
135 or :meth:`sort_transformers` method after changing the priority.
136 """
136 """
137
137
138 multi_line_specials = CBool(True, config=True)
138 multi_line_specials = CBool(True, config=True)
139 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
139 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
140
140
141 def __init__(self, shell=None, config=None):
141 def __init__(self, shell=None, config=None):
142 super(PrefilterManager, self).__init__(shell=shell, config=config)
142 super(PrefilterManager, self).__init__(shell=shell, config=config)
143 self.shell = shell
143 self.shell = shell
144 self.init_transformers()
144 self.init_transformers()
145 self.init_handlers()
145 self.init_handlers()
146 self.init_checkers()
146 self.init_checkers()
147
147
148 #-------------------------------------------------------------------------
148 #-------------------------------------------------------------------------
149 # API for managing transformers
149 # API for managing transformers
150 #-------------------------------------------------------------------------
150 #-------------------------------------------------------------------------
151
151
152 def init_transformers(self):
152 def init_transformers(self):
153 """Create the default transformers."""
153 """Create the default transformers."""
154 self._transformers = []
154 self._transformers = []
155 for transformer_cls in _default_transformers:
155 for transformer_cls in _default_transformers:
156 transformer_cls(
156 transformer_cls(
157 shell=self.shell, prefilter_manager=self, config=self.config
157 shell=self.shell, prefilter_manager=self, config=self.config
158 )
158 )
159
159
160 def sort_transformers(self):
160 def sort_transformers(self):
161 """Sort the transformers by priority.
161 """Sort the transformers by priority.
162
162
163 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.
164 The :meth:`register_transformer` method calls this automatically.
164 The :meth:`register_transformer` method calls this automatically.
165 """
165 """
166 self._transformers.sort(key=lambda x: x.priority)
166 self._transformers.sort(key=lambda x: x.priority)
167
167
168 @property
168 @property
169 def transformers(self):
169 def transformers(self):
170 """Return a list of checkers, sorted by priority."""
170 """Return a list of checkers, sorted by priority."""
171 return self._transformers
171 return self._transformers
172
172
173 def register_transformer(self, transformer):
173 def register_transformer(self, transformer):
174 """Register a transformer instance."""
174 """Register a transformer instance."""
175 if transformer not in self._transformers:
175 if transformer not in self._transformers:
176 self._transformers.append(transformer)
176 self._transformers.append(transformer)
177 self.sort_transformers()
177 self.sort_transformers()
178
178
179 def unregister_transformer(self, transformer):
179 def unregister_transformer(self, transformer):
180 """Unregister a transformer instance."""
180 """Unregister a transformer instance."""
181 if transformer in self._transformers:
181 if transformer in self._transformers:
182 self._transformers.remove(transformer)
182 self._transformers.remove(transformer)
183
183
184 #-------------------------------------------------------------------------
184 #-------------------------------------------------------------------------
185 # API for managing checkers
185 # API for managing checkers
186 #-------------------------------------------------------------------------
186 #-------------------------------------------------------------------------
187
187
188 def init_checkers(self):
188 def init_checkers(self):
189 """Create the default checkers."""
189 """Create the default checkers."""
190 self._checkers = []
190 self._checkers = []
191 for checker in _default_checkers:
191 for checker in _default_checkers:
192 checker(
192 checker(
193 shell=self.shell, prefilter_manager=self, config=self.config
193 shell=self.shell, prefilter_manager=self, config=self.config
194 )
194 )
195
195
196 def sort_checkers(self):
196 def sort_checkers(self):
197 """Sort the checkers by priority.
197 """Sort the checkers by priority.
198
198
199 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.
200 The :meth:`register_checker` method calls this automatically.
200 The :meth:`register_checker` method calls this automatically.
201 """
201 """
202 self._checkers.sort(key=lambda x: x.priority)
202 self._checkers.sort(key=lambda x: x.priority)
203
203
204 @property
204 @property
205 def checkers(self):
205 def checkers(self):
206 """Return a list of checkers, sorted by priority."""
206 """Return a list of checkers, sorted by priority."""
207 return self._checkers
207 return self._checkers
208
208
209 def register_checker(self, checker):
209 def register_checker(self, checker):
210 """Register a checker instance."""
210 """Register a checker instance."""
211 if checker not in self._checkers:
211 if checker not in self._checkers:
212 self._checkers.append(checker)
212 self._checkers.append(checker)
213 self.sort_checkers()
213 self.sort_checkers()
214
214
215 def unregister_checker(self, checker):
215 def unregister_checker(self, checker):
216 """Unregister a checker instance."""
216 """Unregister a checker instance."""
217 if checker in self._checkers:
217 if checker in self._checkers:
218 self._checkers.remove(checker)
218 self._checkers.remove(checker)
219
219
220 #-------------------------------------------------------------------------
220 #-------------------------------------------------------------------------
221 # API for managing checkers
221 # API for managing checkers
222 #-------------------------------------------------------------------------
222 #-------------------------------------------------------------------------
223
223
224 def init_handlers(self):
224 def init_handlers(self):
225 """Create the default handlers."""
225 """Create the default handlers."""
226 self._handlers = {}
226 self._handlers = {}
227 self._esc_handlers = {}
227 self._esc_handlers = {}
228 for handler in _default_handlers:
228 for handler in _default_handlers:
229 handler(
229 handler(
230 shell=self.shell, prefilter_manager=self, config=self.config
230 shell=self.shell, prefilter_manager=self, config=self.config
231 )
231 )
232
232
233 @property
233 @property
234 def handlers(self):
234 def handlers(self):
235 """Return a dict of all the handlers."""
235 """Return a dict of all the handlers."""
236 return self._handlers
236 return self._handlers
237
237
238 def register_handler(self, name, handler, esc_strings):
238 def register_handler(self, name, handler, esc_strings):
239 """Register a handler instance by name with esc_strings."""
239 """Register a handler instance by name with esc_strings."""
240 self._handlers[name] = handler
240 self._handlers[name] = handler
241 for esc_str in esc_strings:
241 for esc_str in esc_strings:
242 self._esc_handlers[esc_str] = handler
242 self._esc_handlers[esc_str] = handler
243
243
244 def unregister_handler(self, name, handler, esc_strings):
244 def unregister_handler(self, name, handler, esc_strings):
245 """Unregister a handler instance by name with esc_strings."""
245 """Unregister a handler instance by name with esc_strings."""
246 try:
246 try:
247 del self._handlers[name]
247 del self._handlers[name]
248 except KeyError:
248 except KeyError:
249 pass
249 pass
250 for esc_str in esc_strings:
250 for esc_str in esc_strings:
251 h = self._esc_handlers.get(esc_str)
251 h = self._esc_handlers.get(esc_str)
252 if h is handler:
252 if h is handler:
253 del self._esc_handlers[esc_str]
253 del self._esc_handlers[esc_str]
254
254
255 def get_handler_by_name(self, name):
255 def get_handler_by_name(self, name):
256 """Get a handler by its name."""
256 """Get a handler by its name."""
257 return self._handlers.get(name)
257 return self._handlers.get(name)
258
258
259 def get_handler_by_esc(self, esc_str):
259 def get_handler_by_esc(self, esc_str):
260 """Get a handler by its escape string."""
260 """Get a handler by its escape string."""
261 return self._esc_handlers.get(esc_str)
261 return self._esc_handlers.get(esc_str)
262
262
263 #-------------------------------------------------------------------------
263 #-------------------------------------------------------------------------
264 # Main prefiltering API
264 # Main prefiltering API
265 #-------------------------------------------------------------------------
265 #-------------------------------------------------------------------------
266
266
267 def prefilter_line_info(self, line_info):
267 def prefilter_line_info(self, line_info):
268 """Prefilter a line that has been converted to a LineInfo object.
268 """Prefilter a line that has been converted to a LineInfo object.
269
269
270 This implements the checker/handler part of the prefilter pipe.
270 This implements the checker/handler part of the prefilter pipe.
271 """
271 """
272 # print "prefilter_line_info: ", line_info
272 # print "prefilter_line_info: ", line_info
273 handler = self.find_handler(line_info)
273 handler = self.find_handler(line_info)
274 return handler.handle(line_info)
274 return handler.handle(line_info)
275
275
276 def find_handler(self, line_info):
276 def find_handler(self, line_info):
277 """Find a handler for the line_info by trying checkers."""
277 """Find a handler for the line_info by trying checkers."""
278 for checker in self.checkers:
278 for checker in self.checkers:
279 if checker.enabled:
279 if checker.enabled:
280 handler = checker.check(line_info)
280 handler = checker.check(line_info)
281 if handler:
281 if handler:
282 return handler
282 return handler
283 return self.get_handler_by_name('normal')
283 return self.get_handler_by_name('normal')
284
284
285 def transform_line(self, line, continue_prompt):
285 def transform_line(self, line, continue_prompt):
286 """Calls the enabled transformers in order of increasing priority."""
286 """Calls the enabled transformers in order of increasing priority."""
287 for transformer in self.transformers:
287 for transformer in self.transformers:
288 if transformer.enabled:
288 if transformer.enabled:
289 line = transformer.transform(line, continue_prompt)
289 line = transformer.transform(line, continue_prompt)
290 return line
290 return line
291
291
292 def prefilter_line(self, line, continue_prompt=False):
292 def prefilter_line(self, line, continue_prompt=False):
293 """Prefilter a single input line as text.
293 """Prefilter a single input line as text.
294
294
295 This method prefilters a single line of text by calling the
295 This method prefilters a single line of text by calling the
296 transformers and then the checkers/handlers.
296 transformers and then the checkers/handlers.
297 """
297 """
298
298
299 # print "prefilter_line: ", line, continue_prompt
299 # print "prefilter_line: ", line, continue_prompt
300 # All handlers *must* return a value, even if it's blank ('').
300 # All handlers *must* return a value, even if it's blank ('').
301
301
302 # 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
303 # record it
303 # record it
304 self.shell._last_input_line = line
304 self.shell._last_input_line = line
305
305
306 if not line:
306 if not line:
307 # Return immediately on purely empty lines, so that if the user
307 # Return immediately on purely empty lines, so that if the user
308 # previously typed some whitespace that started a continuation
308 # previously typed some whitespace that started a continuation
309 # 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.
310 # This is how the default python prompt works.
310 # This is how the default python prompt works.
311 return ''
311 return ''
312
312
313 # At this point, we invoke our transformers.
313 # At this point, we invoke our transformers.
314 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):
315 line = self.transform_line(line, continue_prompt)
315 line = self.transform_line(line, continue_prompt)
316
316
317 # Now we compute line_info for the checkers and handlers
317 # Now we compute line_info for the checkers and handlers
318 line_info = LineInfo(line, continue_prompt)
318 line_info = LineInfo(line, continue_prompt)
319
319
320 # the input history needs to track even empty lines
320 # the input history needs to track even empty lines
321 stripped = line.strip()
321 stripped = line.strip()
322
322
323 normal_handler = self.get_handler_by_name('normal')
323 normal_handler = self.get_handler_by_name('normal')
324 if not stripped:
324 if not stripped:
325 if not continue_prompt:
325 if not continue_prompt:
326 self.shell.displayhook.prompt_count -= 1
326 self.shell.displayhook.prompt_count -= 1
327
327
328 return normal_handler.handle(line_info)
328 return normal_handler.handle(line_info)
329
329
330 # special handlers are only allowed for single line statements
330 # special handlers are only allowed for single line statements
331 if continue_prompt and not self.multi_line_specials:
331 if continue_prompt and not self.multi_line_specials:
332 return normal_handler.handle(line_info)
332 return normal_handler.handle(line_info)
333
333
334 prefiltered = self.prefilter_line_info(line_info)
334 prefiltered = self.prefilter_line_info(line_info)
335 # print "prefiltered line: %r" % prefiltered
335 # print "prefiltered line: %r" % prefiltered
336 return prefiltered
336 return prefiltered
337
337
338 def prefilter_lines(self, lines, continue_prompt=False):
338 def prefilter_lines(self, lines, continue_prompt=False):
339 """Prefilter multiple input lines of text.
339 """Prefilter multiple input lines of text.
340
340
341 This is the main entry point for prefiltering multiple lines of
341 This is the main entry point for prefiltering multiple lines of
342 input. This simply calls :meth:`prefilter_line` for each line of
342 input. This simply calls :meth:`prefilter_line` for each line of
343 input.
343 input.
344
344
345 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,
346 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
347 entry and presses enter.
347 entry and presses enter.
348 """
348 """
349 llines = lines.rstrip('\n').split('\n')
349 llines = lines.rstrip('\n').split('\n')
350 # 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'
351 # into one line, in cases like recalling from the readline history
351 # into one line, in cases like recalling from the readline history
352 # 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
353 # communicate downstream which line is first and which are continuation
353 # communicate downstream which line is first and which are continuation
354 # ones.
354 # ones.
355 if len(llines) > 1:
355 if len(llines) > 1:
356 out = '\n'.join([self.prefilter_line(line, lnum>0)
356 out = '\n'.join([self.prefilter_line(line, lnum>0)
357 for lnum, line in enumerate(llines) ])
357 for lnum, line in enumerate(llines) ])
358 else:
358 else:
359 out = self.prefilter_line(llines[0], continue_prompt)
359 out = self.prefilter_line(llines[0], continue_prompt)
360
360
361 return out
361 return out
362
362
363 #-----------------------------------------------------------------------------
363 #-----------------------------------------------------------------------------
364 # Prefilter transformers
364 # Prefilter transformers
365 #-----------------------------------------------------------------------------
365 #-----------------------------------------------------------------------------
366
366
367
367
368 class PrefilterTransformer(Configurable):
368 class PrefilterTransformer(Configurable):
369 """Transform a line of user input."""
369 """Transform a line of user input."""
370
370
371 priority = Integer(100, config=True)
371 priority = Integer(100, config=True)
372 # 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
373 # move away from checkers and handlers, they will need them.
373 # move away from checkers and handlers, they will need them.
374 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
374 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
375 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
375 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
376 enabled = Bool(True, config=True)
376 enabled = Bool(True, config=True)
377
377
378 def __init__(self, shell=None, prefilter_manager=None, config=None):
378 def __init__(self, shell=None, prefilter_manager=None, config=None):
379 super(PrefilterTransformer, self).__init__(
379 super(PrefilterTransformer, self).__init__(
380 shell=shell, prefilter_manager=prefilter_manager, config=config
380 shell=shell, prefilter_manager=prefilter_manager, config=config
381 )
381 )
382 self.prefilter_manager.register_transformer(self)
382 self.prefilter_manager.register_transformer(self)
383
383
384 def transform(self, line, continue_prompt):
384 def transform(self, line, continue_prompt):
385 """Transform a line, returning the new one."""
385 """Transform a line, returning the new one."""
386 return None
386 return None
387
387
388 def __repr__(self):
388 def __repr__(self):
389 return "<%s(priority=%r, enabled=%r)>" % (
389 return "<%s(priority=%r, enabled=%r)>" % (
390 self.__class__.__name__, self.priority, self.enabled)
390 self.__class__.__name__, self.priority, self.enabled)
391
391
392
392
393 _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\.]+)*))'
394 r'\s*=\s*!(?P<cmd>.*)')
394 r'\s*=\s*!(?P<cmd>.*)')
395
395
396
396
397 class AssignSystemTransformer(PrefilterTransformer):
397 class AssignSystemTransformer(PrefilterTransformer):
398 """Handle the `files = !ls` syntax."""
398 """Handle the `files = !ls` syntax."""
399
399
400 priority = Integer(100, config=True)
400 priority = Integer(100, config=True)
401
401
402 def transform(self, line, continue_prompt):
402 def transform(self, line, continue_prompt):
403 m = _assign_system_re.match(line)
403 m = _assign_system_re.match(line)
404 if m is not None:
404 if m is not None:
405 cmd = m.group('cmd')
405 cmd = m.group('cmd')
406 lhs = m.group('lhs')
406 lhs = m.group('lhs')
407 expr = "sc =%s" % cmd
407 expr = "sc =%s" % cmd
408 new_line = '%s = get_ipython().magic(%r)' % (lhs, expr)
408 new_line = '%s = get_ipython().magic(%r)' % (lhs, expr)
409 return new_line
409 return new_line
410 return line
410 return line
411
411
412
412
413 _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\.]+)*))'
414 r'\s*=\s*%(?P<cmd>.*)')
414 r'\s*=\s*%(?P<cmd>.*)')
415
415
416 class AssignMagicTransformer(PrefilterTransformer):
416 class AssignMagicTransformer(PrefilterTransformer):
417 """Handle the `a = %who` syntax."""
417 """Handle the `a = %who` syntax."""
418
418
419 priority = Integer(200, config=True)
419 priority = Integer(200, config=True)
420
420
421 def transform(self, line, continue_prompt):
421 def transform(self, line, continue_prompt):
422 m = _assign_magic_re.match(line)
422 m = _assign_magic_re.match(line)
423 if m is not None:
423 if m is not None:
424 cmd = m.group('cmd')
424 cmd = m.group('cmd')
425 lhs = m.group('lhs')
425 lhs = m.group('lhs')
426 new_line = '%s = get_ipython().magic(%r)' % (lhs, cmd)
426 new_line = '%s = get_ipython().magic(%r)' % (lhs, cmd)
427 return new_line
427 return new_line
428 return line
428 return line
429
429
430
430
431 _classic_prompt_re = re.compile(r'(^[ \t]*>>> |^[ \t]*\.\.\. )')
431 _classic_prompt_re = re.compile(r'(^[ \t]*>>> |^[ \t]*\.\.\. )')
432
432
433 class PyPromptTransformer(PrefilterTransformer):
433 class PyPromptTransformer(PrefilterTransformer):
434 """Handle inputs that start with '>>> ' syntax."""
434 """Handle inputs that start with '>>> ' syntax."""
435
435
436 priority = Integer(50, config=True)
436 priority = Integer(50, config=True)
437
437
438 def transform(self, line, continue_prompt):
438 def transform(self, line, continue_prompt):
439
439
440 if not line or line.isspace() or line.strip() == '...':
440 if not line or line.isspace() or line.strip() == '...':
441 # This allows us to recognize multiple input prompts separated by
441 # This allows us to recognize multiple input prompts separated by
442 # blank lines and pasted in a single chunk, very common when
442 # blank lines and pasted in a single chunk, very common when
443 # pasting doctests or long tutorial passages.
443 # pasting doctests or long tutorial passages.
444 return ''
444 return ''
445 m = _classic_prompt_re.match(line)
445 m = _classic_prompt_re.match(line)
446 if m:
446 if m:
447 return line[len(m.group(0)):]
447 return line[len(m.group(0)):]
448 else:
448 else:
449 return line
449 return line
450
450
451
451
452 _ipy_prompt_re = re.compile(r'(^[ \t]*In \[\d+\]: |^[ \t]*\ \ \ \.\.\.+: )')
452 _ipy_prompt_re = re.compile(r'(^[ \t]*In \[\d+\]: |^[ \t]*\ \ \ \.\.\.+: )')
453
453
454 class IPyPromptTransformer(PrefilterTransformer):
454 class IPyPromptTransformer(PrefilterTransformer):
455 """Handle inputs that start classic IPython prompt syntax."""
455 """Handle inputs that start classic IPython prompt syntax."""
456
456
457 priority = Integer(50, config=True)
457 priority = Integer(50, config=True)
458
458
459 def transform(self, line, continue_prompt):
459 def transform(self, line, continue_prompt):
460
460
461 if not line or line.isspace() or line.strip() == '...':
461 if not line or line.isspace() or line.strip() == '...':
462 # This allows us to recognize multiple input prompts separated by
462 # This allows us to recognize multiple input prompts separated by
463 # blank lines and pasted in a single chunk, very common when
463 # blank lines and pasted in a single chunk, very common when
464 # pasting doctests or long tutorial passages.
464 # pasting doctests or long tutorial passages.
465 return ''
465 return ''
466 m = _ipy_prompt_re.match(line)
466 m = _ipy_prompt_re.match(line)
467 if m:
467 if m:
468 return line[len(m.group(0)):]
468 return line[len(m.group(0)):]
469 else:
469 else:
470 return line
470 return line
471
471
472 #-----------------------------------------------------------------------------
472 #-----------------------------------------------------------------------------
473 # Prefilter checkers
473 # Prefilter checkers
474 #-----------------------------------------------------------------------------
474 #-----------------------------------------------------------------------------
475
475
476
476
477 class PrefilterChecker(Configurable):
477 class PrefilterChecker(Configurable):
478 """Inspect an input line and return a handler for that line."""
478 """Inspect an input line and return a handler for that line."""
479
479
480 priority = Integer(100, config=True)
480 priority = Integer(100, config=True)
481 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
481 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
482 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
482 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
483 enabled = Bool(True, config=True)
483 enabled = Bool(True, config=True)
484
484
485 def __init__(self, shell=None, prefilter_manager=None, config=None):
485 def __init__(self, shell=None, prefilter_manager=None, config=None):
486 super(PrefilterChecker, self).__init__(
486 super(PrefilterChecker, self).__init__(
487 shell=shell, prefilter_manager=prefilter_manager, config=config
487 shell=shell, prefilter_manager=prefilter_manager, config=config
488 )
488 )
489 self.prefilter_manager.register_checker(self)
489 self.prefilter_manager.register_checker(self)
490
490
491 def check(self, line_info):
491 def check(self, line_info):
492 """Inspect line_info and return a handler instance or None."""
492 """Inspect line_info and return a handler instance or None."""
493 return None
493 return None
494
494
495 def __repr__(self):
495 def __repr__(self):
496 return "<%s(priority=%r, enabled=%r)>" % (
496 return "<%s(priority=%r, enabled=%r)>" % (
497 self.__class__.__name__, self.priority, self.enabled)
497 self.__class__.__name__, self.priority, self.enabled)
498
498
499
499
500 class EmacsChecker(PrefilterChecker):
500 class EmacsChecker(PrefilterChecker):
501
501
502 priority = Integer(100, config=True)
502 priority = Integer(100, config=True)
503 enabled = Bool(False, config=True)
503 enabled = Bool(False, config=True)
504
504
505 def check(self, line_info):
505 def check(self, line_info):
506 "Emacs ipython-mode tags certain input lines."
506 "Emacs ipython-mode tags certain input lines."
507 if line_info.line.endswith('# PYTHON-MODE'):
507 if line_info.line.endswith('# PYTHON-MODE'):
508 return self.prefilter_manager.get_handler_by_name('emacs')
508 return self.prefilter_manager.get_handler_by_name('emacs')
509 else:
509 else:
510 return None
510 return None
511
511
512
512
513 class ShellEscapeChecker(PrefilterChecker):
513 class ShellEscapeChecker(PrefilterChecker):
514
514
515 priority = Integer(200, config=True)
515 priority = Integer(200, config=True)
516
516
517 def check(self, line_info):
517 def check(self, line_info):
518 if line_info.line.lstrip().startswith(ESC_SHELL):
518 if line_info.line.lstrip().startswith(ESC_SHELL):
519 return self.prefilter_manager.get_handler_by_name('shell')
519 return self.prefilter_manager.get_handler_by_name('shell')
520
520
521
521
522 class MacroChecker(PrefilterChecker):
522 class MacroChecker(PrefilterChecker):
523
523
524 priority = Integer(250, config=True)
524 priority = Integer(250, config=True)
525
525
526 def check(self, line_info):
526 def check(self, line_info):
527 obj = self.shell.user_ns.get(line_info.ifun)
527 obj = self.shell.user_ns.get(line_info.ifun)
528 if isinstance(obj, Macro):
528 if isinstance(obj, Macro):
529 return self.prefilter_manager.get_handler_by_name('macro')
529 return self.prefilter_manager.get_handler_by_name('macro')
530 else:
530 else:
531 return None
531 return None
532
532
533
533
534 class IPyAutocallChecker(PrefilterChecker):
534 class IPyAutocallChecker(PrefilterChecker):
535
535
536 priority = Integer(300, config=True)
536 priority = Integer(300, config=True)
537
537
538 def check(self, line_info):
538 def check(self, line_info):
539 "Instances of IPyAutocall in user_ns get autocalled immediately"
539 "Instances of IPyAutocall in user_ns get autocalled immediately"
540 obj = self.shell.user_ns.get(line_info.ifun, None)
540 obj = self.shell.user_ns.get(line_info.ifun, None)
541 if isinstance(obj, IPyAutocall):
541 if isinstance(obj, IPyAutocall):
542 obj.set_ip(self.shell)
542 obj.set_ip(self.shell)
543 return self.prefilter_manager.get_handler_by_name('auto')
543 return self.prefilter_manager.get_handler_by_name('auto')
544 else:
544 else:
545 return None
545 return None
546
546
547
547
548 class MultiLineMagicChecker(PrefilterChecker):
548 class MultiLineMagicChecker(PrefilterChecker):
549
549
550 priority = Integer(400, config=True)
550 priority = Integer(400, config=True)
551
551
552 def check(self, line_info):
552 def check(self, line_info):
553 "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"
554 # 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
555 # 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
556 # both ! and !!.
556 # both ! and !!.
557 if line_info.continue_prompt \
557 if line_info.continue_prompt \
558 and self.prefilter_manager.multi_line_specials:
558 and self.prefilter_manager.multi_line_specials:
559 if line_info.esc == ESC_MAGIC:
559 if line_info.esc == ESC_MAGIC:
560 return self.prefilter_manager.get_handler_by_name('magic')
560 return self.prefilter_manager.get_handler_by_name('magic')
561 else:
561 else:
562 return None
562 return None
563
563
564
564
565 class EscCharsChecker(PrefilterChecker):
565 class EscCharsChecker(PrefilterChecker):
566
566
567 priority = Integer(500, config=True)
567 priority = Integer(500, config=True)
568
568
569 def check(self, line_info):
569 def check(self, line_info):
570 """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,
571 or None if there is no escape char."""
571 or None if there is no escape char."""
572 if line_info.line[-1] == ESC_HELP \
572 if line_info.line[-1] == ESC_HELP \
573 and line_info.esc != ESC_SHELL \
573 and line_info.esc != ESC_SHELL \
574 and line_info.esc != ESC_SH_CAP:
574 and line_info.esc != ESC_SH_CAP:
575 # 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,
576 # 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
577 return self.prefilter_manager.get_handler_by_name('help')
577 return self.prefilter_manager.get_handler_by_name('help')
578 else:
578 else:
579 if line_info.pre:
579 if line_info.pre:
580 return None
580 return None
581 # This returns None like it should if no handler exists
581 # This returns None like it should if no handler exists
582 return self.prefilter_manager.get_handler_by_esc(line_info.esc)
582 return self.prefilter_manager.get_handler_by_esc(line_info.esc)
583
583
584
584
585 class AssignmentChecker(PrefilterChecker):
585 class AssignmentChecker(PrefilterChecker):
586
586
587 priority = Integer(600, config=True)
587 priority = Integer(600, config=True)
588
588
589 def check(self, line_info):
589 def check(self, line_info):
590 """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
591 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.
592
592
593 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
594 variables (the magic/alias systems always take second seat to true
594 variables (the magic/alias systems always take second seat to true
595 python code). E.g. ls='hi', or ls,that=1,2"""
595 python code). E.g. ls='hi', or ls,that=1,2"""
596 if line_info.the_rest:
596 if line_info.the_rest:
597 if line_info.the_rest[0] in '=,':
597 if line_info.the_rest[0] in '=,':
598 return self.prefilter_manager.get_handler_by_name('normal')
598 return self.prefilter_manager.get_handler_by_name('normal')
599 else:
599 else:
600 return None
600 return None
601
601
602
602
603 class AutoMagicChecker(PrefilterChecker):
603 class AutoMagicChecker(PrefilterChecker):
604
604
605 priority = Integer(700, config=True)
605 priority = Integer(700, config=True)
606
606
607 def check(self, line_info):
607 def check(self, line_info):
608 """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,
609 non-auto magic would already have been triggered via '%' in
609 non-auto magic would already have been triggered via '%' in
610 check_esc_chars. This just checks for automagic. Also, before
610 check_esc_chars. This just checks for automagic. Also, before
611 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
612 user namespace which could shadow it."""
612 user namespace which could shadow it."""
613 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):
614 return None
614 return None
615
615
616 # 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.
617 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:
618 return None
618 return None
619
619
620 head = line_info.ifun.split('.',1)[0]
620 head = line_info.ifun.split('.',1)[0]
621 if is_shadowed(head, self.shell):
621 if is_shadowed(head, self.shell):
622 return None
622 return None
623
623
624 return self.prefilter_manager.get_handler_by_name('magic')
624 return self.prefilter_manager.get_handler_by_name('magic')
625
625
626
626
627 class AliasChecker(PrefilterChecker):
627 class AliasChecker(PrefilterChecker):
628
628
629 priority = Integer(800, config=True)
629 priority = Integer(800, config=True)
630
630
631 def check(self, line_info):
631 def check(self, line_info):
632 "Check if the initital identifier on the line is an alias."
632 "Check if the initital identifier on the line is an alias."
633 # Note: aliases can not contain '.'
633 # Note: aliases can not contain '.'
634 head = line_info.ifun.split('.',1)[0]
634 head = line_info.ifun.split('.',1)[0]
635 if line_info.ifun not in self.shell.alias_manager \
635 if line_info.ifun not in self.shell.alias_manager \
636 or head not in self.shell.alias_manager \
636 or head not in self.shell.alias_manager \
637 or is_shadowed(head, self.shell):
637 or is_shadowed(head, self.shell):
638 return None
638 return None
639
639
640 return self.prefilter_manager.get_handler_by_name('alias')
640 return self.prefilter_manager.get_handler_by_name('alias')
641
641
642
642
643 class PythonOpsChecker(PrefilterChecker):
643 class PythonOpsChecker(PrefilterChecker):
644
644
645 priority = Integer(900, config=True)
645 priority = Integer(900, config=True)
646
646
647 def check(self, line_info):
647 def check(self, line_info):
648 """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
649 any python operator, we should simply execute the line (regardless of
649 any python operator, we should simply execute the line (regardless of
650 whether or not there's a possible autocall expansion). This avoids
650 whether or not there's a possible autocall expansion). This avoids
651 spurious (and very confusing) geattr() accesses."""
651 spurious (and very confusing) geattr() accesses."""
652 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 '!=()<>,+*/%^&|':
653 return self.prefilter_manager.get_handler_by_name('normal')
653 return self.prefilter_manager.get_handler_by_name('normal')
654 else:
654 else:
655 return None
655 return None
656
656
657
657
658 class AutocallChecker(PrefilterChecker):
658 class AutocallChecker(PrefilterChecker):
659
659
660 priority = Integer(1000, config=True)
660 priority = Integer(1000, config=True)
661
661
662 def check(self, line_info):
662 def check(self, line_info):
663 "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."
664 if not self.shell.autocall:
664 if not self.shell.autocall:
665 return None
665 return None
666
666
667 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
668 if not oinfo['found']:
668 if not oinfo['found']:
669 return None
669 return None
670
670
671 if callable(oinfo['obj']) \
671 if callable(oinfo['obj']) \
672 and (not re_exclude_auto.match(line_info.the_rest)) \
672 and (not re_exclude_auto.match(line_info.the_rest)) \
673 and re_fun_name.match(line_info.ifun):
673 and re_fun_name.match(line_info.ifun):
674 return self.prefilter_manager.get_handler_by_name('auto')
674 return self.prefilter_manager.get_handler_by_name('auto')
675 else:
675 else:
676 return None
676 return None
677
677
678
678
679 #-----------------------------------------------------------------------------
679 #-----------------------------------------------------------------------------
680 # Prefilter handlers
680 # Prefilter handlers
681 #-----------------------------------------------------------------------------
681 #-----------------------------------------------------------------------------
682
682
683
683
684 class PrefilterHandler(Configurable):
684 class PrefilterHandler(Configurable):
685
685
686 handler_name = Unicode('normal')
686 handler_name = Unicode('normal')
687 esc_strings = List([])
687 esc_strings = List([])
688 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
688 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
689 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
689 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
690
690
691 def __init__(self, shell=None, prefilter_manager=None, config=None):
691 def __init__(self, shell=None, prefilter_manager=None, config=None):
692 super(PrefilterHandler, self).__init__(
692 super(PrefilterHandler, self).__init__(
693 shell=shell, prefilter_manager=prefilter_manager, config=config
693 shell=shell, prefilter_manager=prefilter_manager, config=config
694 )
694 )
695 self.prefilter_manager.register_handler(
695 self.prefilter_manager.register_handler(
696 self.handler_name,
696 self.handler_name,
697 self,
697 self,
698 self.esc_strings
698 self.esc_strings
699 )
699 )
700
700
701 def handle(self, line_info):
701 def handle(self, line_info):
702 # print "normal: ", line_info
702 # print "normal: ", line_info
703 """Handle normal input lines. Use as a template for handlers."""
703 """Handle normal input lines. Use as a template for handlers."""
704
704
705 # 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
706 # 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
707 # 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
708 # 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
709 # 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.
710 line = line_info.line
710 line = line_info.line
711 continue_prompt = line_info.continue_prompt
711 continue_prompt = line_info.continue_prompt
712
712
713 if (continue_prompt and
713 if (continue_prompt and
714 self.shell.autoindent and
714 self.shell.autoindent and
715 line.isspace() and
715 line.isspace() and
716 0 < abs(len(line) - self.shell.indent_current_nsp) <= 2):
716 0 < abs(len(line) - self.shell.indent_current_nsp) <= 2):
717 line = ''
717 line = ''
718
718
719 return line
719 return line
720
720
721 def __str__(self):
721 def __str__(self):
722 return "<%s(name=%s)>" % (self.__class__.__name__, self.handler_name)
722 return "<%s(name=%s)>" % (self.__class__.__name__, self.handler_name)
723
723
724
724
725 class AliasHandler(PrefilterHandler):
725 class AliasHandler(PrefilterHandler):
726
726
727 handler_name = Unicode('alias')
727 handler_name = Unicode('alias')
728
728
729 def handle(self, line_info):
729 def handle(self, line_info):
730 """Handle alias input lines. """
730 """Handle alias input lines. """
731 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)
732 # pre is needed, because it carries the leading whitespace. Otherwise
732 # pre is needed, because it carries the leading whitespace. Otherwise
733 # aliases won't work in indented sections.
733 # aliases won't work in indented sections.
734 line_out = '%sget_ipython().system(%r)' % (line_info.pre_whitespace, transformed)
734 line_out = '%sget_ipython().system(%r)' % (line_info.pre_whitespace, transformed)
735
735
736 return line_out
736 return line_out
737
737
738
738
739 class ShellEscapeHandler(PrefilterHandler):
739 class ShellEscapeHandler(PrefilterHandler):
740
740
741 handler_name = Unicode('shell')
741 handler_name = Unicode('shell')
742 esc_strings = List([ESC_SHELL, ESC_SH_CAP])
742 esc_strings = List([ESC_SHELL, ESC_SH_CAP])
743
743
744 def handle(self, line_info):
744 def handle(self, line_info):
745 """Execute the line in a shell, empty return value"""
745 """Execute the line in a shell, empty return value"""
746 magic_handler = self.prefilter_manager.get_handler_by_name('magic')
746 magic_handler = self.prefilter_manager.get_handler_by_name('magic')
747
747
748 line = line_info.line
748 line = line_info.line
749 if line.lstrip().startswith(ESC_SH_CAP):
749 if line.lstrip().startswith(ESC_SH_CAP):
750 # 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
751 # call to %sx and the actual command to be executed, so
751 # call to %sx and the actual command to be executed, so
752 # handle_magic can work correctly. Note that this works even if
752 # handle_magic can work correctly. Note that this works even if
753 # the line is indented, so it handles multi_line_specials
753 # the line is indented, so it handles multi_line_specials
754 # properly.
754 # properly.
755 new_rest = line.lstrip()[2:]
755 new_rest = line.lstrip()[2:]
756 line_info.line = '%ssx %s' % (ESC_MAGIC, new_rest)
756 line_info.line = '%ssx %s' % (ESC_MAGIC, new_rest)
757 line_info.ifun = 'sx'
757 line_info.ifun = 'sx'
758 line_info.the_rest = new_rest
758 line_info.the_rest = new_rest
759 return magic_handler.handle(line_info)
759 return magic_handler.handle(line_info)
760 else:
760 else:
761 cmd = line.lstrip().lstrip(ESC_SHELL)
761 cmd = line.lstrip().lstrip(ESC_SHELL)
762 line_out = '%sget_ipython().system(%r)' % (line_info.pre_whitespace, cmd)
762 line_out = '%sget_ipython().system(%r)' % (line_info.pre_whitespace, cmd)
763 return line_out
763 return line_out
764
764
765
765
766 class MacroHandler(PrefilterHandler):
766 class MacroHandler(PrefilterHandler):
767 handler_name = Unicode("macro")
767 handler_name = Unicode("macro")
768
768
769 def handle(self, line_info):
769 def handle(self, line_info):
770 obj = self.shell.user_ns.get(line_info.ifun)
770 obj = self.shell.user_ns.get(line_info.ifun)
771 pre_space = line_info.pre_whitespace
771 pre_space = line_info.pre_whitespace
772 line_sep = "\n" + pre_space
772 line_sep = "\n" + pre_space
773 return pre_space + line_sep.join(obj.value.splitlines())
773 return pre_space + line_sep.join(obj.value.splitlines())
774
774
775
775
776 class MagicHandler(PrefilterHandler):
776 class MagicHandler(PrefilterHandler):
777
777
778 handler_name = Unicode('magic')
778 handler_name = Unicode('magic')
779 esc_strings = List([ESC_MAGIC])
779 esc_strings = List([ESC_MAGIC])
780
780
781 def handle(self, line_info):
781 def handle(self, line_info):
782 """Execute magic functions."""
782 """Execute magic functions."""
783 ifun = line_info.ifun
783 ifun = line_info.ifun
784 the_rest = line_info.the_rest
784 the_rest = line_info.the_rest
785 cmd = '%sget_ipython().magic(%r)' % (line_info.pre_whitespace,
785 cmd = '%sget_ipython().magic(%r)' % (line_info.pre_whitespace,
786 (ifun + " " + the_rest))
786 (ifun + " " + the_rest))
787 return cmd
787 return cmd
788
788
789
789
790 class AutoHandler(PrefilterHandler):
790 class AutoHandler(PrefilterHandler):
791
791
792 handler_name = Unicode('auto')
792 handler_name = Unicode('auto')
793 esc_strings = List([ESC_PAREN, ESC_QUOTE, ESC_QUOTE2])
793 esc_strings = List([ESC_PAREN, ESC_QUOTE, ESC_QUOTE2])
794
794
795 def handle(self, line_info):
795 def handle(self, line_info):
796 """Handle lines which can be auto-executed, quoting if requested."""
796 """Handle lines which can be auto-executed, quoting if requested."""
797 line = line_info.line
797 line = line_info.line
798 ifun = line_info.ifun
798 ifun = line_info.ifun
799 the_rest = line_info.the_rest
799 the_rest = line_info.the_rest
800 pre = line_info.pre
800 pre = line_info.pre
801 esc = line_info.esc
801 esc = line_info.esc
802 continue_prompt = line_info.continue_prompt
802 continue_prompt = line_info.continue_prompt
803 obj = line_info.ofind(self)['obj']
803 obj = line_info.ofind(self)['obj']
804 #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
805
805
806 # This should only be active for single-line input!
806 # This should only be active for single-line input!
807 if continue_prompt:
807 if continue_prompt:
808 return line
808 return line
809
809
810 force_auto = isinstance(obj, IPyAutocall)
810 force_auto = isinstance(obj, IPyAutocall)
811
811
812 # User objects sometimes raise exceptions on attribute access other
812 # User objects sometimes raise exceptions on attribute access other
813 # 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
814 # ultra-conservative here and catch all.
814 # ultra-conservative here and catch all.
815 try:
815 try:
816 auto_rewrite = obj.rewrite
816 auto_rewrite = obj.rewrite
817 except Exception:
817 except Exception:
818 auto_rewrite = True
818 auto_rewrite = True
819
819
820 if esc == ESC_QUOTE:
820 if esc == ESC_QUOTE:
821 # Auto-quote splitting on whitespace
821 # Auto-quote splitting on whitespace
822 newcmd = '%s("%s")' % (ifun,'", "'.join(the_rest.split()) )
822 newcmd = '%s("%s")' % (ifun,'", "'.join(the_rest.split()) )
823 elif esc == ESC_QUOTE2:
823 elif esc == ESC_QUOTE2:
824 # Auto-quote whole string
824 # Auto-quote whole string
825 newcmd = '%s("%s")' % (ifun,the_rest)
825 newcmd = '%s("%s")' % (ifun,the_rest)
826 elif esc == ESC_PAREN:
826 elif esc == ESC_PAREN:
827 newcmd = '%s(%s)' % (ifun,",".join(the_rest.split()))
827 newcmd = '%s(%s)' % (ifun,",".join(the_rest.split()))
828 else:
828 else:
829 # Auto-paren.
829 # Auto-paren.
830 # We only apply it to argument-less calls if the autocall
830 # We only apply it to argument-less calls if the autocall
831 # 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 <
832 # 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.
833 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:
834 newcmd = '%s %s' % (ifun,the_rest)
834 newcmd = '%s %s' % (ifun,the_rest)
835 auto_rewrite = False
835 auto_rewrite = False
836 else:
836 else:
837 if not force_auto and the_rest.startswith('['):
837 if not force_auto and the_rest.startswith('['):
838 if hasattr(obj,'__getitem__'):
838 if hasattr(obj,'__getitem__'):
839 # Don't autocall in this case: item access for an object
839 # Don't autocall in this case: item access for an object
840 # which is BOTH callable and implements __getitem__.
840 # which is BOTH callable and implements __getitem__.
841 newcmd = '%s %s' % (ifun,the_rest)
841 newcmd = '%s %s' % (ifun,the_rest)
842 auto_rewrite = False
842 auto_rewrite = False
843 else:
843 else:
844 # if the object doesn't support [] access, go ahead and
844 # if the object doesn't support [] access, go ahead and
845 # autocall
845 # autocall
846 newcmd = '%s(%s)' % (ifun.rstrip(),the_rest)
846 newcmd = '%s(%s)' % (ifun.rstrip(),the_rest)
847 elif the_rest.endswith(';'):
847 elif the_rest.endswith(';'):
848 newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1])
848 newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1])
849 else:
849 else:
850 newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
850 newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
851
851
852 if auto_rewrite:
852 if auto_rewrite:
853 self.shell.auto_rewrite_input(newcmd)
853 self.shell.auto_rewrite_input(newcmd)
854
854
855 return newcmd
855 return newcmd
856
856
857
857
858 class HelpHandler(PrefilterHandler):
858 class HelpHandler(PrefilterHandler):
859
859
860 handler_name = Unicode('help')
860 handler_name = Unicode('help')
861 esc_strings = List([ESC_HELP])
861 esc_strings = List([ESC_HELP])
862
862
863 def handle(self, line_info):
863 def handle(self, line_info):
864 """Try to get some help for the object.
864 """Try to get some help for the object.
865
865
866 obj? or ?obj -> basic information.
866 obj? or ?obj -> basic information.
867 obj?? or ??obj -> more details.
867 obj?? or ??obj -> more details.
868 """
868 """
869 normal_handler = self.prefilter_manager.get_handler_by_name('normal')
869 normal_handler = self.prefilter_manager.get_handler_by_name('normal')
870 line = line_info.line
870 line = line_info.line
871 # 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
872 # otherwise valid python, such as "x=1 # what?"
872 # otherwise valid python, such as "x=1 # what?"
873 try:
873 try:
874 codeop.compile_command(line)
874 codeop.compile_command(line)
875 except SyntaxError:
875 except SyntaxError:
876 # 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
877 if line[0]==ESC_HELP:
877 if line[0]==ESC_HELP:
878 line = line[1:]
878 line = line[1:]
879 elif line[-1]==ESC_HELP:
879 elif line[-1]==ESC_HELP:
880 line = line[:-1]
880 line = line[:-1]
881 if line:
881 if line:
882 #print 'line:<%r>' % line # dbg
882 #print 'line:<%r>' % line # dbg
883 self.shell.magic_pinfo(line_info.ifun)
883 self.shell.magic_pinfo(line_info.ifun)
884 else:
884 else:
885 self.shell.show_usage()
885 self.shell.show_usage()
886 return '' # Empty string is needed here!
886 return '' # Empty string is needed here!
887 except:
887 except:
888 raise
888 raise
889 # Pass any other exceptions through to the normal handler
889 # Pass any other exceptions through to the normal handler
890 return normal_handler.handle(line_info)
890 return normal_handler.handle(line_info)
891 else:
891 else:
892 # If the code compiles ok, we should handle it normally
892 # If the code compiles ok, we should handle it normally
893 return normal_handler.handle(line_info)
893 return normal_handler.handle(line_info)
894
894
895
895
896 class EmacsHandler(PrefilterHandler):
896 class EmacsHandler(PrefilterHandler):
897
897
898 handler_name = Unicode('emacs')
898 handler_name = Unicode('emacs')
899 esc_strings = List([])
899 esc_strings = List([])
900
900
901 def handle(self, line_info):
901 def handle(self, line_info):
902 """Handle input lines marked by python-mode."""
902 """Handle input lines marked by python-mode."""
903
903
904 # Currently, nothing is done. Later more functionality can be added
904 # Currently, nothing is done. Later more functionality can be added
905 # here if needed.
905 # here if needed.
906
906
907 # The input cache shouldn't be updated
907 # The input cache shouldn't be updated
908 return line_info.line
908 return line_info.line
909
909
910
910
911 #-----------------------------------------------------------------------------
911 #-----------------------------------------------------------------------------
912 # Defaults
912 # Defaults
913 #-----------------------------------------------------------------------------
913 #-----------------------------------------------------------------------------
914
914
915
915
916 _default_transformers = [
916 _default_transformers = [
917 AssignSystemTransformer,
917 AssignSystemTransformer,
918 AssignMagicTransformer,
918 AssignMagicTransformer,
919 PyPromptTransformer,
919 PyPromptTransformer,
920 IPyPromptTransformer,
920 IPyPromptTransformer,
921 ]
921 ]
922
922
923 _default_checkers = [
923 _default_checkers = [
924 EmacsChecker,
924 EmacsChecker,
925 ShellEscapeChecker,
925 ShellEscapeChecker,
926 MacroChecker,
926 MacroChecker,
927 IPyAutocallChecker,
927 IPyAutocallChecker,
928 MultiLineMagicChecker,
928 MultiLineMagicChecker,
929 EscCharsChecker,
929 EscCharsChecker,
930 AssignmentChecker,
930 AssignmentChecker,
931 AutoMagicChecker,
931 AutoMagicChecker,
932 AliasChecker,
932 AliasChecker,
933 PythonOpsChecker,
933 PythonOpsChecker,
934 AutocallChecker
934 AutocallChecker
935 ]
935 ]
936
936
937 _default_handlers = [
937 _default_handlers = [
938 PrefilterHandler,
938 PrefilterHandler,
939 AliasHandler,
939 AliasHandler,
940 ShellEscapeHandler,
940 ShellEscapeHandler,
941 MacroHandler,
941 MacroHandler,
942 MagicHandler,
942 MagicHandler,
943 AutoHandler,
943 AutoHandler,
944 HelpHandler,
944 HelpHandler,
945 EmacsHandler
945 EmacsHandler
946 ]
946 ]
@@ -1,436 +1,436 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Classes for handling input/output prompts.
2 """Classes for handling input/output prompts.
3
3
4 Authors:
4 Authors:
5
5
6 * Fernando Perez
6 * Fernando Perez
7 * Brian Granger
7 * Brian Granger
8 """
8 """
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Copyright (C) 2008-2010 The IPython Development Team
11 # Copyright (C) 2008-2011 The IPython Development Team
12 # Copyright (C) 2001-2007 Fernando Perez <fperez@colorado.edu>
12 # Copyright (C) 2001-2007 Fernando Perez <fperez@colorado.edu>
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 import os
22 import os
23 import re
23 import re
24 import socket
24 import socket
25 import sys
25 import sys
26
26
27 from IPython.core import release
27 from IPython.core import release
28 from IPython.external.Itpl import ItplNS
28 from IPython.external.Itpl import ItplNS
29 from IPython.utils import coloransi
29 from IPython.utils import coloransi
30
30
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32 # Color schemes for prompts
32 # Color schemes for prompts
33 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
34
34
35 PromptColors = coloransi.ColorSchemeTable()
35 PromptColors = coloransi.ColorSchemeTable()
36 InputColors = coloransi.InputTermColors # just a shorthand
36 InputColors = coloransi.InputTermColors # just a shorthand
37 Colors = coloransi.TermColors # just a shorthand
37 Colors = coloransi.TermColors # just a shorthand
38
38
39 PromptColors.add_scheme(coloransi.ColorScheme(
39 PromptColors.add_scheme(coloransi.ColorScheme(
40 'NoColor',
40 'NoColor',
41 in_prompt = InputColors.NoColor, # Input prompt
41 in_prompt = InputColors.NoColor, # Input prompt
42 in_number = InputColors.NoColor, # Input prompt number
42 in_number = InputColors.NoColor, # Input prompt number
43 in_prompt2 = InputColors.NoColor, # Continuation prompt
43 in_prompt2 = InputColors.NoColor, # Continuation prompt
44 in_normal = InputColors.NoColor, # color off (usu. Colors.Normal)
44 in_normal = InputColors.NoColor, # color off (usu. Colors.Normal)
45
45
46 out_prompt = Colors.NoColor, # Output prompt
46 out_prompt = Colors.NoColor, # Output prompt
47 out_number = Colors.NoColor, # Output prompt number
47 out_number = Colors.NoColor, # Output prompt number
48
48
49 normal = Colors.NoColor # color off (usu. Colors.Normal)
49 normal = Colors.NoColor # color off (usu. Colors.Normal)
50 ))
50 ))
51
51
52 # make some schemes as instances so we can copy them for modification easily:
52 # make some schemes as instances so we can copy them for modification easily:
53 __PColLinux = coloransi.ColorScheme(
53 __PColLinux = coloransi.ColorScheme(
54 'Linux',
54 'Linux',
55 in_prompt = InputColors.Green,
55 in_prompt = InputColors.Green,
56 in_number = InputColors.LightGreen,
56 in_number = InputColors.LightGreen,
57 in_prompt2 = InputColors.Green,
57 in_prompt2 = InputColors.Green,
58 in_normal = InputColors.Normal, # color off (usu. Colors.Normal)
58 in_normal = InputColors.Normal, # color off (usu. Colors.Normal)
59
59
60 out_prompt = Colors.Red,
60 out_prompt = Colors.Red,
61 out_number = Colors.LightRed,
61 out_number = Colors.LightRed,
62
62
63 normal = Colors.Normal
63 normal = Colors.Normal
64 )
64 )
65 # Don't forget to enter it into the table!
65 # Don't forget to enter it into the table!
66 PromptColors.add_scheme(__PColLinux)
66 PromptColors.add_scheme(__PColLinux)
67
67
68 # Slightly modified Linux for light backgrounds
68 # Slightly modified Linux for light backgrounds
69 __PColLightBG = __PColLinux.copy('LightBG')
69 __PColLightBG = __PColLinux.copy('LightBG')
70
70
71 __PColLightBG.colors.update(
71 __PColLightBG.colors.update(
72 in_prompt = InputColors.Blue,
72 in_prompt = InputColors.Blue,
73 in_number = InputColors.LightBlue,
73 in_number = InputColors.LightBlue,
74 in_prompt2 = InputColors.Blue
74 in_prompt2 = InputColors.Blue
75 )
75 )
76 PromptColors.add_scheme(__PColLightBG)
76 PromptColors.add_scheme(__PColLightBG)
77
77
78 del Colors,InputColors
78 del Colors,InputColors
79
79
80 #-----------------------------------------------------------------------------
80 #-----------------------------------------------------------------------------
81 # Utilities
81 # Utilities
82 #-----------------------------------------------------------------------------
82 #-----------------------------------------------------------------------------
83
83
84 def multiple_replace(dict, text):
84 def multiple_replace(dict, text):
85 """ Replace in 'text' all occurences of any key in the given
85 """ Replace in 'text' all occurences of any key in the given
86 dictionary by its corresponding value. Returns the new string."""
86 dictionary by its corresponding value. Returns the new string."""
87
87
88 # Function by Xavier Defrang, originally found at:
88 # Function by Xavier Defrang, originally found at:
89 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81330
89 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81330
90
90
91 # Create a regular expression from the dictionary keys
91 # Create a regular expression from the dictionary keys
92 regex = re.compile("(%s)" % "|".join(map(re.escape, dict.keys())))
92 regex = re.compile("(%s)" % "|".join(map(re.escape, dict.keys())))
93 # For each match, look-up corresponding value in dictionary
93 # For each match, look-up corresponding value in dictionary
94 return regex.sub(lambda mo: dict[mo.string[mo.start():mo.end()]], text)
94 return regex.sub(lambda mo: dict[mo.string[mo.start():mo.end()]], text)
95
95
96 #-----------------------------------------------------------------------------
96 #-----------------------------------------------------------------------------
97 # Special characters that can be used in prompt templates, mainly bash-like
97 # Special characters that can be used in prompt templates, mainly bash-like
98 #-----------------------------------------------------------------------------
98 #-----------------------------------------------------------------------------
99
99
100 # If $HOME isn't defined (Windows), make it an absurd string so that it can
100 # If $HOME isn't defined (Windows), make it an absurd string so that it can
101 # never be expanded out into '~'. Basically anything which can never be a
101 # never be expanded out into '~'. Basically anything which can never be a
102 # reasonable directory name will do, we just want the $HOME -> '~' operation
102 # reasonable directory name will do, we just want the $HOME -> '~' operation
103 # to become a no-op. We pre-compute $HOME here so it's not done on every
103 # to become a no-op. We pre-compute $HOME here so it's not done on every
104 # prompt call.
104 # prompt call.
105
105
106 # FIXME:
106 # FIXME:
107
107
108 # - This should be turned into a class which does proper namespace management,
108 # - This should be turned into a class which does proper namespace management,
109 # since the prompt specials need to be evaluated in a certain namespace.
109 # since the prompt specials need to be evaluated in a certain namespace.
110 # Currently it's just globals, which need to be managed manually by code
110 # Currently it's just globals, which need to be managed manually by code
111 # below.
111 # below.
112
112
113 # - I also need to split up the color schemes from the prompt specials
113 # - I also need to split up the color schemes from the prompt specials
114 # somehow. I don't have a clean design for that quite yet.
114 # somehow. I don't have a clean design for that quite yet.
115
115
116 HOME = os.environ.get("HOME","//////:::::ZZZZZ,,,~~~")
116 HOME = os.environ.get("HOME","//////:::::ZZZZZ,,,~~~")
117
117
118 # We precompute a few more strings here for the prompt_specials, which are
118 # We precompute a few more strings here for the prompt_specials, which are
119 # fixed once ipython starts. This reduces the runtime overhead of computing
119 # fixed once ipython starts. This reduces the runtime overhead of computing
120 # prompt strings.
120 # prompt strings.
121 USER = os.environ.get("USER")
121 USER = os.environ.get("USER")
122 HOSTNAME = socket.gethostname()
122 HOSTNAME = socket.gethostname()
123 HOSTNAME_SHORT = HOSTNAME.split(".")[0]
123 HOSTNAME_SHORT = HOSTNAME.split(".")[0]
124 ROOT_SYMBOL = "$#"[os.name=='nt' or os.getuid()==0]
124 ROOT_SYMBOL = "$#"[os.name=='nt' or os.getuid()==0]
125
125
126 prompt_specials_color = {
126 prompt_specials_color = {
127 # Prompt/history count
127 # Prompt/history count
128 '%n' : '${self.col_num}' '${self.cache.prompt_count}' '${self.col_p}',
128 '%n' : '${self.col_num}' '${self.cache.prompt_count}' '${self.col_p}',
129 r'\#': '${self.col_num}' '${self.cache.prompt_count}' '${self.col_p}',
129 r'\#': '${self.col_num}' '${self.cache.prompt_count}' '${self.col_p}',
130 # Just the prompt counter number, WITHOUT any coloring wrappers, so users
130 # Just the prompt counter number, WITHOUT any coloring wrappers, so users
131 # can get numbers displayed in whatever color they want.
131 # can get numbers displayed in whatever color they want.
132 r'\N': '${self.cache.prompt_count}',
132 r'\N': '${self.cache.prompt_count}',
133
133
134 # Prompt/history count, with the actual digits replaced by dots. Used
134 # Prompt/history count, with the actual digits replaced by dots. Used
135 # mainly in continuation prompts (prompt_in2)
135 # mainly in continuation prompts (prompt_in2)
136 #r'\D': '${"."*len(str(self.cache.prompt_count))}',
136 #r'\D': '${"."*len(str(self.cache.prompt_count))}',
137
137
138 # More robust form of the above expression, that uses the __builtin__
138 # More robust form of the above expression, that uses the __builtin__
139 # module. Note that we can NOT use __builtins__ (note the 's'), because
139 # module. Note that we can NOT use __builtins__ (note the 's'), because
140 # that can either be a dict or a module, and can even mutate at runtime,
140 # that can either be a dict or a module, and can even mutate at runtime,
141 # depending on the context (Python makes no guarantees on it). In
141 # depending on the context (Python makes no guarantees on it). In
142 # contrast, __builtin__ is always a module object, though it must be
142 # contrast, __builtin__ is always a module object, though it must be
143 # explicitly imported.
143 # explicitly imported.
144 r'\D': '${"."*__builtin__.len(__builtin__.str(self.cache.prompt_count))}',
144 r'\D': '${"."*__builtin__.len(__builtin__.str(self.cache.prompt_count))}',
145
145
146 # Current working directory
146 # Current working directory
147 r'\w': '${os.getcwd()}',
147 r'\w': '${os.getcwd()}',
148 # Current time
148 # Current time
149 r'\t' : '${time.strftime("%H:%M:%S")}',
149 r'\t' : '${time.strftime("%H:%M:%S")}',
150 # Basename of current working directory.
150 # Basename of current working directory.
151 # (use os.sep to make this portable across OSes)
151 # (use os.sep to make this portable across OSes)
152 r'\W' : '${os.getcwd().split("%s")[-1]}' % os.sep,
152 r'\W' : '${os.getcwd().split("%s")[-1]}' % os.sep,
153 # These X<N> are an extension to the normal bash prompts. They return
153 # These X<N> are an extension to the normal bash prompts. They return
154 # N terms of the path, after replacing $HOME with '~'
154 # N terms of the path, after replacing $HOME with '~'
155 r'\X0': '${os.getcwd().replace("%s","~")}' % HOME,
155 r'\X0': '${os.getcwd().replace("%s","~")}' % HOME,
156 r'\X1': '${self.cwd_filt(1)}',
156 r'\X1': '${self.cwd_filt(1)}',
157 r'\X2': '${self.cwd_filt(2)}',
157 r'\X2': '${self.cwd_filt(2)}',
158 r'\X3': '${self.cwd_filt(3)}',
158 r'\X3': '${self.cwd_filt(3)}',
159 r'\X4': '${self.cwd_filt(4)}',
159 r'\X4': '${self.cwd_filt(4)}',
160 r'\X5': '${self.cwd_filt(5)}',
160 r'\X5': '${self.cwd_filt(5)}',
161 # Y<N> are similar to X<N>, but they show '~' if it's the directory
161 # Y<N> are similar to X<N>, but they show '~' if it's the directory
162 # N+1 in the list. Somewhat like %cN in tcsh.
162 # N+1 in the list. Somewhat like %cN in tcsh.
163 r'\Y0': '${self.cwd_filt2(0)}',
163 r'\Y0': '${self.cwd_filt2(0)}',
164 r'\Y1': '${self.cwd_filt2(1)}',
164 r'\Y1': '${self.cwd_filt2(1)}',
165 r'\Y2': '${self.cwd_filt2(2)}',
165 r'\Y2': '${self.cwd_filt2(2)}',
166 r'\Y3': '${self.cwd_filt2(3)}',
166 r'\Y3': '${self.cwd_filt2(3)}',
167 r'\Y4': '${self.cwd_filt2(4)}',
167 r'\Y4': '${self.cwd_filt2(4)}',
168 r'\Y5': '${self.cwd_filt2(5)}',
168 r'\Y5': '${self.cwd_filt2(5)}',
169 # Hostname up to first .
169 # Hostname up to first .
170 r'\h': HOSTNAME_SHORT,
170 r'\h': HOSTNAME_SHORT,
171 # Full hostname
171 # Full hostname
172 r'\H': HOSTNAME,
172 r'\H': HOSTNAME,
173 # Username of current user
173 # Username of current user
174 r'\u': USER,
174 r'\u': USER,
175 # Escaped '\'
175 # Escaped '\'
176 '\\\\': '\\',
176 '\\\\': '\\',
177 # Newline
177 # Newline
178 r'\n': '\n',
178 r'\n': '\n',
179 # Carriage return
179 # Carriage return
180 r'\r': '\r',
180 r'\r': '\r',
181 # Release version
181 # Release version
182 r'\v': release.version,
182 r'\v': release.version,
183 # Root symbol ($ or #)
183 # Root symbol ($ or #)
184 r'\$': ROOT_SYMBOL,
184 r'\$': ROOT_SYMBOL,
185 }
185 }
186
186
187 # A copy of the prompt_specials dictionary but with all color escapes removed,
187 # A copy of the prompt_specials dictionary but with all color escapes removed,
188 # so we can correctly compute the prompt length for the auto_rewrite method.
188 # so we can correctly compute the prompt length for the auto_rewrite method.
189 prompt_specials_nocolor = prompt_specials_color.copy()
189 prompt_specials_nocolor = prompt_specials_color.copy()
190 prompt_specials_nocolor['%n'] = '${self.cache.prompt_count}'
190 prompt_specials_nocolor['%n'] = '${self.cache.prompt_count}'
191 prompt_specials_nocolor[r'\#'] = '${self.cache.prompt_count}'
191 prompt_specials_nocolor[r'\#'] = '${self.cache.prompt_count}'
192
192
193 # Add in all the InputTermColors color escapes as valid prompt characters.
193 # Add in all the InputTermColors color escapes as valid prompt characters.
194 # They all get added as \\C_COLORNAME, so that we don't have any conflicts
194 # They all get added as \\C_COLORNAME, so that we don't have any conflicts
195 # with a color name which may begin with a letter used by any other of the
195 # with a color name which may begin with a letter used by any other of the
196 # allowed specials. This of course means that \\C will never be allowed for
196 # allowed specials. This of course means that \\C will never be allowed for
197 # anything else.
197 # anything else.
198 input_colors = coloransi.InputTermColors
198 input_colors = coloransi.InputTermColors
199 for _color in dir(input_colors):
199 for _color in dir(input_colors):
200 if _color[0] != '_':
200 if _color[0] != '_':
201 c_name = r'\C_'+_color
201 c_name = r'\C_'+_color
202 prompt_specials_color[c_name] = getattr(input_colors,_color)
202 prompt_specials_color[c_name] = getattr(input_colors,_color)
203 prompt_specials_nocolor[c_name] = ''
203 prompt_specials_nocolor[c_name] = ''
204
204
205 # we default to no color for safety. Note that prompt_specials is a global
205 # we default to no color for safety. Note that prompt_specials is a global
206 # variable used by all prompt objects.
206 # variable used by all prompt objects.
207 prompt_specials = prompt_specials_nocolor
207 prompt_specials = prompt_specials_nocolor
208
208
209 #-----------------------------------------------------------------------------
209 #-----------------------------------------------------------------------------
210 # More utilities
210 # More utilities
211 #-----------------------------------------------------------------------------
211 #-----------------------------------------------------------------------------
212
212
213 def str_safe(arg):
213 def str_safe(arg):
214 """Convert to a string, without ever raising an exception.
214 """Convert to a string, without ever raising an exception.
215
215
216 If str(arg) fails, <ERROR: ... > is returned, where ... is the exception
216 If str(arg) fails, <ERROR: ... > is returned, where ... is the exception
217 error message."""
217 error message."""
218
218
219 try:
219 try:
220 out = str(arg)
220 out = str(arg)
221 except UnicodeError:
221 except UnicodeError:
222 try:
222 try:
223 out = arg.encode('utf_8','replace')
223 out = arg.encode('utf_8','replace')
224 except Exception,msg:
224 except Exception,msg:
225 # let's keep this little duplication here, so that the most common
225 # let's keep this little duplication here, so that the most common
226 # case doesn't suffer from a double try wrapping.
226 # case doesn't suffer from a double try wrapping.
227 out = '<ERROR: %s>' % msg
227 out = '<ERROR: %s>' % msg
228 except Exception,msg:
228 except Exception,msg:
229 out = '<ERROR: %s>' % msg
229 out = '<ERROR: %s>' % msg
230 #raise # dbg
230 #raise # dbg
231 return out
231 return out
232
232
233 #-----------------------------------------------------------------------------
233 #-----------------------------------------------------------------------------
234 # Prompt classes
234 # Prompt classes
235 #-----------------------------------------------------------------------------
235 #-----------------------------------------------------------------------------
236
236
237 class BasePrompt(object):
237 class BasePrompt(object):
238 """Interactive prompt similar to Mathematica's."""
238 """Interactive prompt similar to Mathematica's."""
239
239
240 def _get_p_template(self):
240 def _get_p_template(self):
241 return self._p_template
241 return self._p_template
242
242
243 def _set_p_template(self,val):
243 def _set_p_template(self,val):
244 self._p_template = val
244 self._p_template = val
245 self.set_p_str()
245 self.set_p_str()
246
246
247 p_template = property(_get_p_template,_set_p_template,
247 p_template = property(_get_p_template,_set_p_template,
248 doc='Template for prompt string creation')
248 doc='Template for prompt string creation')
249
249
250 def __init__(self, cache, sep, prompt, pad_left=False):
250 def __init__(self, cache, sep, prompt, pad_left=False):
251
251
252 # Hack: we access information about the primary prompt through the
252 # Hack: we access information about the primary prompt through the
253 # cache argument. We need this, because we want the secondary prompt
253 # cache argument. We need this, because we want the secondary prompt
254 # to be aligned with the primary one. Color table info is also shared
254 # to be aligned with the primary one. Color table info is also shared
255 # by all prompt classes through the cache. Nice OO spaghetti code!
255 # by all prompt classes through the cache. Nice OO spaghetti code!
256 self.cache = cache
256 self.cache = cache
257 self.sep = sep
257 self.sep = sep
258
258
259 # regexp to count the number of spaces at the end of a prompt
259 # regexp to count the number of spaces at the end of a prompt
260 # expression, useful for prompt auto-rewriting
260 # expression, useful for prompt auto-rewriting
261 self.rspace = re.compile(r'(\s*)$')
261 self.rspace = re.compile(r'(\s*)$')
262 # Flag to left-pad prompt strings to match the length of the primary
262 # Flag to left-pad prompt strings to match the length of the primary
263 # prompt
263 # prompt
264 self.pad_left = pad_left
264 self.pad_left = pad_left
265
265
266 # Set template to create each actual prompt (where numbers change).
266 # Set template to create each actual prompt (where numbers change).
267 # Use a property
267 # Use a property
268 self.p_template = prompt
268 self.p_template = prompt
269 self.set_p_str()
269 self.set_p_str()
270
270
271 def set_p_str(self):
271 def set_p_str(self):
272 """ Set the interpolating prompt strings.
272 """ Set the interpolating prompt strings.
273
273
274 This must be called every time the color settings change, because the
274 This must be called every time the color settings change, because the
275 prompt_specials global may have changed."""
275 prompt_specials global may have changed."""
276
276
277 import os,time # needed in locals for prompt string handling
277 import os,time # needed in locals for prompt string handling
278 loc = locals()
278 loc = locals()
279 try:
279 try:
280 self.p_str = ItplNS('%s%s%s' %
280 self.p_str = ItplNS('%s%s%s' %
281 ('${self.sep}${self.col_p}',
281 ('${self.sep}${self.col_p}',
282 multiple_replace(prompt_specials, self.p_template),
282 multiple_replace(prompt_specials, self.p_template),
283 '${self.col_norm}'),self.cache.shell.user_ns,loc)
283 '${self.col_norm}'),self.cache.shell.user_ns,loc)
284
284
285 self.p_str_nocolor = ItplNS(multiple_replace(prompt_specials_nocolor,
285 self.p_str_nocolor = ItplNS(multiple_replace(prompt_specials_nocolor,
286 self.p_template),
286 self.p_template),
287 self.cache.shell.user_ns,loc)
287 self.cache.shell.user_ns,loc)
288 except:
288 except:
289 print "Illegal prompt template (check $ usage!):",self.p_template
289 print "Illegal prompt template (check $ usage!):",self.p_template
290 self.p_str = self.p_template
290 self.p_str = self.p_template
291 self.p_str_nocolor = self.p_template
291 self.p_str_nocolor = self.p_template
292
292
293 def write(self, msg):
293 def write(self, msg):
294 sys.stdout.write(msg)
294 sys.stdout.write(msg)
295 return ''
295 return ''
296
296
297 def __str__(self):
297 def __str__(self):
298 """Return a string form of the prompt.
298 """Return a string form of the prompt.
299
299
300 This for is useful for continuation and output prompts, since it is
300 This for is useful for continuation and output prompts, since it is
301 left-padded to match lengths with the primary one (if the
301 left-padded to match lengths with the primary one (if the
302 self.pad_left attribute is set)."""
302 self.pad_left attribute is set)."""
303
303
304 out_str = str_safe(self.p_str)
304 out_str = str_safe(self.p_str)
305 if self.pad_left:
305 if self.pad_left:
306 # We must find the amount of padding required to match lengths,
306 # We must find the amount of padding required to match lengths,
307 # taking the color escapes (which are invisible on-screen) into
307 # taking the color escapes (which are invisible on-screen) into
308 # account.
308 # account.
309 esc_pad = len(out_str) - len(str_safe(self.p_str_nocolor))
309 esc_pad = len(out_str) - len(str_safe(self.p_str_nocolor))
310 format = '%%%ss' % (len(str(self.cache.last_prompt))+esc_pad)
310 format = '%%%ss' % (len(str(self.cache.last_prompt))+esc_pad)
311 return format % out_str
311 return format % out_str
312 else:
312 else:
313 return out_str
313 return out_str
314
314
315 # these path filters are put in as methods so that we can control the
315 # these path filters are put in as methods so that we can control the
316 # namespace where the prompt strings get evaluated
316 # namespace where the prompt strings get evaluated
317 def cwd_filt(self, depth):
317 def cwd_filt(self, depth):
318 """Return the last depth elements of the current working directory.
318 """Return the last depth elements of the current working directory.
319
319
320 $HOME is always replaced with '~'.
320 $HOME is always replaced with '~'.
321 If depth==0, the full path is returned."""
321 If depth==0, the full path is returned."""
322
322
323 cwd = os.getcwd().replace(HOME,"~")
323 cwd = os.getcwd().replace(HOME,"~")
324 out = os.sep.join(cwd.split(os.sep)[-depth:])
324 out = os.sep.join(cwd.split(os.sep)[-depth:])
325 if out:
325 if out:
326 return out
326 return out
327 else:
327 else:
328 return os.sep
328 return os.sep
329
329
330 def cwd_filt2(self, depth):
330 def cwd_filt2(self, depth):
331 """Return the last depth elements of the current working directory.
331 """Return the last depth elements of the current working directory.
332
332
333 $HOME is always replaced with '~'.
333 $HOME is always replaced with '~'.
334 If depth==0, the full path is returned."""
334 If depth==0, the full path is returned."""
335
335
336 full_cwd = os.getcwd()
336 full_cwd = os.getcwd()
337 cwd = full_cwd.replace(HOME,"~").split(os.sep)
337 cwd = full_cwd.replace(HOME,"~").split(os.sep)
338 if '~' in cwd and len(cwd) == depth+1:
338 if '~' in cwd and len(cwd) == depth+1:
339 depth += 1
339 depth += 1
340 drivepart = ''
340 drivepart = ''
341 if sys.platform == 'win32' and len(cwd) > depth:
341 if sys.platform == 'win32' and len(cwd) > depth:
342 drivepart = os.path.splitdrive(full_cwd)[0]
342 drivepart = os.path.splitdrive(full_cwd)[0]
343 out = drivepart + '/'.join(cwd[-depth:])
343 out = drivepart + '/'.join(cwd[-depth:])
344
344
345 if out:
345 if out:
346 return out
346 return out
347 else:
347 else:
348 return os.sep
348 return os.sep
349
349
350 def __nonzero__(self):
350 def __nonzero__(self):
351 """Implement boolean behavior.
351 """Implement boolean behavior.
352
352
353 Checks whether the p_str attribute is non-empty"""
353 Checks whether the p_str attribute is non-empty"""
354
354
355 return bool(self.p_template)
355 return bool(self.p_template)
356
356
357
357
358 class Prompt1(BasePrompt):
358 class Prompt1(BasePrompt):
359 """Input interactive prompt similar to Mathematica's."""
359 """Input interactive prompt similar to Mathematica's."""
360
360
361 def __init__(self, cache, sep='\n', prompt='In [\\#]: ', pad_left=True):
361 def __init__(self, cache, sep='\n', prompt='In [\\#]: ', pad_left=True):
362 BasePrompt.__init__(self, cache, sep, prompt, pad_left)
362 BasePrompt.__init__(self, cache, sep, prompt, pad_left)
363
363
364 def set_colors(self):
364 def set_colors(self):
365 self.set_p_str()
365 self.set_p_str()
366 Colors = self.cache.color_table.active_colors # shorthand
366 Colors = self.cache.color_table.active_colors # shorthand
367 self.col_p = Colors.in_prompt
367 self.col_p = Colors.in_prompt
368 self.col_num = Colors.in_number
368 self.col_num = Colors.in_number
369 self.col_norm = Colors.in_normal
369 self.col_norm = Colors.in_normal
370 # We need a non-input version of these escapes for the '--->'
370 # We need a non-input version of these escapes for the '--->'
371 # auto-call prompts used in the auto_rewrite() method.
371 # auto-call prompts used in the auto_rewrite() method.
372 self.col_p_ni = self.col_p.replace('\001','').replace('\002','')
372 self.col_p_ni = self.col_p.replace('\001','').replace('\002','')
373 self.col_norm_ni = Colors.normal
373 self.col_norm_ni = Colors.normal
374
374
375 def __str__(self):
375 def __str__(self):
376 self.cache.last_prompt = str_safe(self.p_str_nocolor).split('\n')[-1]
376 self.cache.last_prompt = str_safe(self.p_str_nocolor).split('\n')[-1]
377 return str_safe(self.p_str)
377 return str_safe(self.p_str)
378
378
379 def auto_rewrite(self):
379 def auto_rewrite(self):
380 """Return a string of the form '--->' which lines up with the previous
380 """Return a string of the form '--->' which lines up with the previous
381 input string. Useful for systems which re-write the user input when
381 input string. Useful for systems which re-write the user input when
382 handling automatically special syntaxes."""
382 handling automatically special syntaxes."""
383
383
384 curr = str(self.cache.last_prompt)
384 curr = str(self.cache.last_prompt)
385 nrspaces = len(self.rspace.search(curr).group())
385 nrspaces = len(self.rspace.search(curr).group())
386 return '%s%s>%s%s' % (self.col_p_ni,'-'*(len(curr)-nrspaces-1),
386 return '%s%s>%s%s' % (self.col_p_ni,'-'*(len(curr)-nrspaces-1),
387 ' '*nrspaces,self.col_norm_ni)
387 ' '*nrspaces,self.col_norm_ni)
388
388
389
389
390 class PromptOut(BasePrompt):
390 class PromptOut(BasePrompt):
391 """Output interactive prompt similar to Mathematica's."""
391 """Output interactive prompt similar to Mathematica's."""
392
392
393 def __init__(self, cache, sep='', prompt='Out[\\#]: ', pad_left=True):
393 def __init__(self, cache, sep='', prompt='Out[\\#]: ', pad_left=True):
394 BasePrompt.__init__(self, cache, sep, prompt, pad_left)
394 BasePrompt.__init__(self, cache, sep, prompt, pad_left)
395 if not self.p_template:
395 if not self.p_template:
396 self.__str__ = lambda: ''
396 self.__str__ = lambda: ''
397
397
398 def set_colors(self):
398 def set_colors(self):
399 self.set_p_str()
399 self.set_p_str()
400 Colors = self.cache.color_table.active_colors # shorthand
400 Colors = self.cache.color_table.active_colors # shorthand
401 self.col_p = Colors.out_prompt
401 self.col_p = Colors.out_prompt
402 self.col_num = Colors.out_number
402 self.col_num = Colors.out_number
403 self.col_norm = Colors.normal
403 self.col_norm = Colors.normal
404
404
405
405
406 class Prompt2(BasePrompt):
406 class Prompt2(BasePrompt):
407 """Interactive continuation prompt."""
407 """Interactive continuation prompt."""
408
408
409 def __init__(self, cache, prompt=' .\\D.: ', pad_left=True):
409 def __init__(self, cache, prompt=' .\\D.: ', pad_left=True):
410 self.cache = cache
410 self.cache = cache
411 self.p_template = prompt
411 self.p_template = prompt
412 self.pad_left = pad_left
412 self.pad_left = pad_left
413 self.set_p_str()
413 self.set_p_str()
414
414
415 def set_p_str(self):
415 def set_p_str(self):
416 import os,time # needed in locals for prompt string handling
416 import os,time # needed in locals for prompt string handling
417 loc = locals()
417 loc = locals()
418 self.p_str = ItplNS('%s%s%s' %
418 self.p_str = ItplNS('%s%s%s' %
419 ('${self.col_p2}',
419 ('${self.col_p2}',
420 multiple_replace(prompt_specials, self.p_template),
420 multiple_replace(prompt_specials, self.p_template),
421 '$self.col_norm'),
421 '$self.col_norm'),
422 self.cache.shell.user_ns,loc)
422 self.cache.shell.user_ns,loc)
423 self.p_str_nocolor = ItplNS(multiple_replace(prompt_specials_nocolor,
423 self.p_str_nocolor = ItplNS(multiple_replace(prompt_specials_nocolor,
424 self.p_template),
424 self.p_template),
425 self.cache.shell.user_ns,loc)
425 self.cache.shell.user_ns,loc)
426
426
427 def set_colors(self):
427 def set_colors(self):
428 self.set_p_str()
428 self.set_p_str()
429 Colors = self.cache.color_table.active_colors
429 Colors = self.cache.color_table.active_colors
430 self.col_p2 = Colors.in_prompt2
430 self.col_p2 = Colors.in_prompt2
431 self.col_norm = Colors.in_normal
431 self.col_norm = Colors.in_normal
432 # FIXME (2004-06-16) HACK: prevent crashes for users who haven't
432 # FIXME (2004-06-16) HACK: prevent crashes for users who haven't
433 # updated their prompt_in2 definitions. Remove eventually.
433 # updated their prompt_in2 definitions. Remove eventually.
434 self.col_p = Colors.out_prompt
434 self.col_p = Colors.out_prompt
435 self.col_num = Colors.out_number
435 self.col_num = Colors.out_number
436
436
@@ -1,138 +1,138 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Simple utility for splitting user input. This is used by both inputsplitter and
3 Simple utility for splitting user input. This is used by both inputsplitter and
4 prefilter.
4 prefilter.
5
5
6 Authors:
6 Authors:
7
7
8 * Brian Granger
8 * Brian Granger
9 * Fernando Perez
9 * Fernando Perez
10 """
10 """
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Copyright (C) 2008-2009 The IPython Development Team
13 # Copyright (C) 2008-2011 The IPython Development Team
14 #
14 #
15 # Distributed under the terms of the BSD License. The full license is in
15 # Distributed under the terms of the BSD License. The full license is in
16 # the file COPYING, distributed as part of this software.
16 # the file COPYING, distributed as part of this software.
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Imports
20 # Imports
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22
22
23 import re
23 import re
24 import sys
24 import sys
25
25
26 from IPython.utils import py3compat
26 from IPython.utils import py3compat
27
27
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29 # Main function
29 # Main function
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31
31
32 # RegExp for splitting line contents into pre-char//first word-method//rest.
32 # RegExp for splitting line contents into pre-char//first word-method//rest.
33 # For clarity, each group in on one line.
33 # For clarity, each group in on one line.
34
34
35 # WARNING: update the regexp if the escapes in interactiveshell are changed, as
35 # WARNING: update the regexp if the escapes in interactiveshell are changed, as
36 # they are hardwired in.
36 # they are hardwired in.
37
37
38 # Although it's not solely driven by the regex, note that:
38 # Although it's not solely driven by the regex, note that:
39 # ,;/% only trigger if they are the first character on the line
39 # ,;/% only trigger if they are the first character on the line
40 # ! and !! trigger if they are first char(s) *or* follow an indent
40 # ! and !! trigger if they are first char(s) *or* follow an indent
41 # ? triggers as first or last char.
41 # ? triggers as first or last char.
42
42
43 line_split = re.compile("""
43 line_split = re.compile("""
44 ^(\s*) # any leading space
44 ^(\s*) # any leading space
45 ([,;/%]|!!?|\?\??)? # escape character or characters
45 ([,;/%]|!!?|\?\??)? # escape character or characters
46 \s*(%?[\w\.\*]*) # function/method, possibly with leading %
46 \s*(%?[\w\.\*]*) # function/method, possibly with leading %
47 # to correctly treat things like '?%magic'
47 # to correctly treat things like '?%magic'
48 (.*?$|$) # rest of line
48 (.*?$|$) # rest of line
49 """, re.VERBOSE)
49 """, re.VERBOSE)
50
50
51 def split_user_input(line, pattern=None):
51 def split_user_input(line, pattern=None):
52 """Split user input into initial whitespace, escape character, function part
52 """Split user input into initial whitespace, escape character, function part
53 and the rest.
53 and the rest.
54 """
54 """
55 # We need to ensure that the rest of this routine deals only with unicode
55 # We need to ensure that the rest of this routine deals only with unicode
56 line = py3compat.cast_unicode(line, sys.stdin.encoding or 'utf-8')
56 line = py3compat.cast_unicode(line, sys.stdin.encoding or 'utf-8')
57
57
58 if pattern is None:
58 if pattern is None:
59 pattern = line_split
59 pattern = line_split
60 match = pattern.match(line)
60 match = pattern.match(line)
61 if not match:
61 if not match:
62 # print "match failed for line '%s'" % line
62 # print "match failed for line '%s'" % line
63 try:
63 try:
64 ifun, the_rest = line.split(None,1)
64 ifun, the_rest = line.split(None,1)
65 except ValueError:
65 except ValueError:
66 # print "split failed for line '%s'" % line
66 # print "split failed for line '%s'" % line
67 ifun, the_rest = line, u''
67 ifun, the_rest = line, u''
68 pre = re.match('^(\s*)(.*)',line).groups()[0]
68 pre = re.match('^(\s*)(.*)',line).groups()[0]
69 esc = ""
69 esc = ""
70 else:
70 else:
71 pre, esc, ifun, the_rest = match.groups()
71 pre, esc, ifun, the_rest = match.groups()
72
72
73 #print 'line:<%s>' % line # dbg
73 #print 'line:<%s>' % line # dbg
74 #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun.strip(),the_rest) # dbg
74 #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun.strip(),the_rest) # dbg
75 return pre, esc or '', ifun.strip(), the_rest.lstrip()
75 return pre, esc or '', ifun.strip(), the_rest.lstrip()
76
76
77 class LineInfo(object):
77 class LineInfo(object):
78 """A single line of input and associated info.
78 """A single line of input and associated info.
79
79
80 Includes the following as properties:
80 Includes the following as properties:
81
81
82 line
82 line
83 The original, raw line
83 The original, raw line
84
84
85 continue_prompt
85 continue_prompt
86 Is this line a continuation in a sequence of multiline input?
86 Is this line a continuation in a sequence of multiline input?
87
87
88 pre
88 pre
89 Any leading whitespace.
89 Any leading whitespace.
90
90
91 esc
91 esc
92 The escape character(s) in pre or the empty string if there isn't one.
92 The escape character(s) in pre or the empty string if there isn't one.
93 Note that '!!' and '??' are possible values for esc. Otherwise it will
93 Note that '!!' and '??' are possible values for esc. Otherwise it will
94 always be a single character.
94 always be a single character.
95
95
96 ifun
96 ifun
97 The 'function part', which is basically the maximal initial sequence
97 The 'function part', which is basically the maximal initial sequence
98 of valid python identifiers and the '.' character. This is what is
98 of valid python identifiers and the '.' character. This is what is
99 checked for alias and magic transformations, used for auto-calling,
99 checked for alias and magic transformations, used for auto-calling,
100 etc. In contrast to Python identifiers, it may start with "%" and contain
100 etc. In contrast to Python identifiers, it may start with "%" and contain
101 "*".
101 "*".
102
102
103 the_rest
103 the_rest
104 Everything else on the line.
104 Everything else on the line.
105 """
105 """
106 def __init__(self, line, continue_prompt=False):
106 def __init__(self, line, continue_prompt=False):
107 self.line = line
107 self.line = line
108 self.continue_prompt = continue_prompt
108 self.continue_prompt = continue_prompt
109 self.pre, self.esc, self.ifun, self.the_rest = split_user_input(line)
109 self.pre, self.esc, self.ifun, self.the_rest = split_user_input(line)
110
110
111 self.pre_char = self.pre.strip()
111 self.pre_char = self.pre.strip()
112 if self.pre_char:
112 if self.pre_char:
113 self.pre_whitespace = '' # No whitespace allowd before esc chars
113 self.pre_whitespace = '' # No whitespace allowd before esc chars
114 else:
114 else:
115 self.pre_whitespace = self.pre
115 self.pre_whitespace = self.pre
116
116
117 self._oinfo = None
117 self._oinfo = None
118
118
119 def ofind(self, ip):
119 def ofind(self, ip):
120 """Do a full, attribute-walking lookup of the ifun in the various
120 """Do a full, attribute-walking lookup of the ifun in the various
121 namespaces for the given IPython InteractiveShell instance.
121 namespaces for the given IPython InteractiveShell instance.
122
122
123 Return a dict with keys: found,obj,ospace,ismagic
123 Return a dict with keys: found,obj,ospace,ismagic
124
124
125 Note: can cause state changes because of calling getattr, but should
125 Note: can cause state changes because of calling getattr, but should
126 only be run if autocall is on and if the line hasn't matched any
126 only be run if autocall is on and if the line hasn't matched any
127 other, less dangerous handlers.
127 other, less dangerous handlers.
128
128
129 Does cache the results of the call, so can be called multiple times
129 Does cache the results of the call, so can be called multiple times
130 without worrying about *further* damaging state.
130 without worrying about *further* damaging state.
131 """
131 """
132 if not self._oinfo:
132 if not self._oinfo:
133 # ip.shell._ofind is actually on the Magic class!
133 # ip.shell._ofind is actually on the Magic class!
134 self._oinfo = ip.shell._ofind(self.ifun)
134 self._oinfo = ip.shell._ofind(self.ifun)
135 return self._oinfo
135 return self._oinfo
136
136
137 def __str__(self):
137 def __str__(self):
138 return "LineInfo [%s|%s|%s|%s]" %(self.pre, self.esc, self.ifun, self.the_rest)
138 return "LineInfo [%s|%s|%s|%s]" %(self.pre, self.esc, self.ifun, self.the_rest)
@@ -1,75 +1,75 b''
1 # coding: utf-8
1 # coding: utf-8
2 """Tests for the compilerop module.
2 """Tests for the compilerop module.
3 """
3 """
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (C) 2010 The IPython Development Team.
5 # Copyright (C) 2010-2011 The IPython Development Team.
6 #
6 #
7 # Distributed under the terms of the BSD License.
7 # Distributed under the terms of the BSD License.
8 #
8 #
9 # The full license is in the file COPYING.txt, distributed with this software.
9 # The full license is in the file COPYING.txt, distributed with this software.
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Imports
13 # Imports
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15 from __future__ import print_function
15 from __future__ import print_function
16
16
17 # Stdlib imports
17 # Stdlib imports
18 import linecache
18 import linecache
19 import sys
19 import sys
20
20
21 # Third-party imports
21 # Third-party imports
22 import nose.tools as nt
22 import nose.tools as nt
23
23
24 # Our own imports
24 # Our own imports
25 from IPython.core import compilerop
25 from IPython.core import compilerop
26 from IPython.utils import py3compat
26 from IPython.utils import py3compat
27
27
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29 # Test functions
29 # Test functions
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31
31
32 def test_code_name():
32 def test_code_name():
33 code = 'x=1'
33 code = 'x=1'
34 name = compilerop.code_name(code)
34 name = compilerop.code_name(code)
35 nt.assert_true(name.startswith('<ipython-input-0'))
35 nt.assert_true(name.startswith('<ipython-input-0'))
36
36
37
37
38 def test_code_name2():
38 def test_code_name2():
39 code = 'x=1'
39 code = 'x=1'
40 name = compilerop.code_name(code, 9)
40 name = compilerop.code_name(code, 9)
41 nt.assert_true(name.startswith('<ipython-input-9'))
41 nt.assert_true(name.startswith('<ipython-input-9'))
42
42
43
43
44 def test_cache():
44 def test_cache():
45 """Test the compiler correctly compiles and caches inputs
45 """Test the compiler correctly compiles and caches inputs
46 """
46 """
47 cp = compilerop.CachingCompiler()
47 cp = compilerop.CachingCompiler()
48 ncache = len(linecache.cache)
48 ncache = len(linecache.cache)
49 cp.cache('x=1')
49 cp.cache('x=1')
50 nt.assert_true(len(linecache.cache) > ncache)
50 nt.assert_true(len(linecache.cache) > ncache)
51
51
52 def setUp():
52 def setUp():
53 # Check we're in a proper Python 2 environment (some imports, such
53 # Check we're in a proper Python 2 environment (some imports, such
54 # as GTK, can change the default encoding, which can hide bugs.)
54 # as GTK, can change the default encoding, which can hide bugs.)
55 nt.assert_equal(sys.getdefaultencoding(), "utf-8" if py3compat.PY3 else "ascii")
55 nt.assert_equal(sys.getdefaultencoding(), "utf-8" if py3compat.PY3 else "ascii")
56
56
57 def test_cache_unicode():
57 def test_cache_unicode():
58 cp = compilerop.CachingCompiler()
58 cp = compilerop.CachingCompiler()
59 ncache = len(linecache.cache)
59 ncache = len(linecache.cache)
60 cp.cache(u"t = 'žćčšđ'")
60 cp.cache(u"t = 'žćčšđ'")
61 nt.assert_true(len(linecache.cache) > ncache)
61 nt.assert_true(len(linecache.cache) > ncache)
62
62
63 def test_compiler_check_cache():
63 def test_compiler_check_cache():
64 """Test the compiler properly manages the cache.
64 """Test the compiler properly manages the cache.
65 """
65 """
66 # Rather simple-minded tests that just exercise the API
66 # Rather simple-minded tests that just exercise the API
67 cp = compilerop.CachingCompiler()
67 cp = compilerop.CachingCompiler()
68 cp.cache('x=1', 99)
68 cp.cache('x=1', 99)
69 # Ensure now that after clearing the cache, our entries survive
69 # Ensure now that after clearing the cache, our entries survive
70 cp.check_cache()
70 cp.check_cache()
71 for k in linecache.cache:
71 for k in linecache.cache:
72 if k.startswith('<ipython-input-99'):
72 if k.startswith('<ipython-input-99'):
73 break
73 break
74 else:
74 else:
75 raise AssertionError('Entry for input-99 missing from linecache')
75 raise AssertionError('Entry for input-99 missing from linecache')
@@ -1,706 +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-2011 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 [(u'a =! ls', "a = get_ipython().getoutput({u}'ls')"),
408 [(u'a =! ls', "a = get_ipython().getoutput({u}'ls')"),
409 (u'b = !ls', "b = get_ipython().getoutput({u}'ls')"),
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 [(u'a =% who', "a = get_ipython().magic({u}'who')"),
416 [(u'a =% who', "a = get_ipython().magic({u}'who')"),
417 (u'b = %who', "b = get_ipython().magic({u}'who')"),
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 [ (u'!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 (u'!!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 [ (u'?', 'get_ipython().show_usage()'),
454 [ (u'?', 'get_ipython().show_usage()'),
455 (u'?x1', "get_ipython().magic({u}'pinfo x1')"),
455 (u'?x1', "get_ipython().magic({u}'pinfo x1')"),
456 (u'??x2', "get_ipython().magic({u}'pinfo2 x2')"),
456 (u'??x2', "get_ipython().magic({u}'pinfo2 x2')"),
457 (u'?a.*s', "get_ipython().magic({u}'psearch a.*s')"),
457 (u'?a.*s', "get_ipython().magic({u}'psearch a.*s')"),
458 (u'?%hist', "get_ipython().magic({u}'pinfo %hist')"),
458 (u'?%hist', "get_ipython().magic({u}'pinfo %hist')"),
459 (u'?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 [ (u'x3?', "get_ipython().magic({u}'pinfo x3')"),
464 [ (u'x3?', "get_ipython().magic({u}'pinfo x3')"),
465 (u'x4??', "get_ipython().magic({u}'pinfo2 x4')"),
465 (u'x4??', "get_ipython().magic({u}'pinfo2 x4')"),
466 (u'%hist?', "get_ipython().magic({u}'pinfo %hist')"),
466 (u'%hist?', "get_ipython().magic({u}'pinfo %hist')"),
467 (u'f*?', "get_ipython().magic({u}'psearch f*')"),
467 (u'f*?', "get_ipython().magic({u}'psearch f*')"),
468 (u'ax.*aspe*?', "get_ipython().magic({u}'psearch ax.*aspe*')"),
468 (u'ax.*aspe*?', "get_ipython().magic({u}'psearch ax.*aspe*')"),
469 (u'a = abc?', "get_ipython().magic({u}'pinfo abc', next_input={u}'a = abc')"),
469 (u'a = abc?', "get_ipython().magic({u}'pinfo abc', next_input={u}'a = abc')"),
470 (u'a = abc.qe??', "get_ipython().magic({u}'pinfo2 abc.qe', next_input={u}'a = abc.qe')"),
470 (u'a = abc.qe??', "get_ipython().magic({u}'pinfo2 abc.qe', next_input={u}'a = abc.qe')"),
471 (u'a = *.items?', "get_ipython().magic({u}'psearch *.items', next_input={u}'a = *.items')"),
471 (u'a = *.items?', "get_ipython().magic({u}'psearch *.items', next_input={u}'a = *.items')"),
472 (u'plot(a?', "get_ipython().magic({u}'pinfo a', next_input={u}'plot(a')"),
472 (u'plot(a?', "get_ipython().magic({u}'pinfo a', next_input={u}'plot(a')"),
473 (u'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 [ (u'%cd', "get_ipython().magic({u}'cd')"),
479 [ (u'%cd', "get_ipython().magic({u}'cd')"),
480 (u'%cd /home', "get_ipython().magic({u}'cd /home')"),
480 (u'%cd /home', "get_ipython().magic({u}'cd /home')"),
481 # Backslashes need to be escaped.
481 # Backslashes need to be escaped.
482 (u'%cd C:\\User', "get_ipython().magic({u}'cd C:\\\\User')"),
482 (u'%cd C:\\User', "get_ipython().magic({u}'cd C:\\\\User')"),
483 (u' %magic', " get_ipython().magic({u}'magic')"),
483 (u' %magic', " get_ipython().magic({u}'magic')"),
484 ]],
484 ]],
485
485
486 # Quoting with separate arguments
486 # Quoting with separate arguments
487 escaped_quote =
487 escaped_quote =
488 [ (',f', 'f("")'),
488 [ (',f', 'f("")'),
489 (',f x', 'f("x")'),
489 (',f x', 'f("x")'),
490 (' ,f y', ' f("y")'),
490 (' ,f y', ' f("y")'),
491 (',f a b', 'f("a", "b")'),
491 (',f a b', 'f("a", "b")'),
492 ],
492 ],
493
493
494 # Quoting with single argument
494 # Quoting with single argument
495 escaped_quote2 =
495 escaped_quote2 =
496 [ (';f', 'f("")'),
496 [ (';f', 'f("")'),
497 (';f x', 'f("x")'),
497 (';f x', 'f("x")'),
498 (' ;f y', ' f("y")'),
498 (' ;f y', ' f("y")'),
499 (';f a b', 'f("a b")'),
499 (';f a b', 'f("a b")'),
500 ],
500 ],
501
501
502 # Simply apply parens
502 # Simply apply parens
503 escaped_paren =
503 escaped_paren =
504 [ ('/f', 'f()'),
504 [ ('/f', 'f()'),
505 ('/f x', 'f(x)'),
505 ('/f x', 'f(x)'),
506 (' /f y', ' f(y)'),
506 (' /f y', ' f(y)'),
507 ('/f a b', 'f(a, b)'),
507 ('/f a b', 'f(a, b)'),
508 ],
508 ],
509
509
510 # Check that we transform prompts before other transforms
510 # Check that we transform prompts before other transforms
511 mixed =
511 mixed =
512 [(i,py3compat.u_format(o)) for i,o in \
512 [(i,py3compat.u_format(o)) for i,o in \
513 [ (u'In [1]: %lsmagic', "get_ipython().magic({u}'lsmagic')"),
513 [ (u'In [1]: %lsmagic', "get_ipython().magic({u}'lsmagic')"),
514 (u'>>> %lsmagic', "get_ipython().magic({u}'lsmagic')"),
514 (u'>>> %lsmagic', "get_ipython().magic({u}'lsmagic')"),
515 (u'In [2]: !ls', "get_ipython().system({u}'ls')"),
515 (u'In [2]: !ls', "get_ipython().system({u}'ls')"),
516 (u'In [3]: abs?', "get_ipython().magic({u}'pinfo abs')"),
516 (u'In [3]: abs?', "get_ipython().magic({u}'pinfo abs')"),
517 (u'In [4]: b = %who', "b = get_ipython().magic({u}'who')"),
517 (u'In [4]: b = %who', "b = get_ipython().magic({u}'who')"),
518 ]],
518 ]],
519 )
519 )
520
520
521 # 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
522 # 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
523 # '\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
524 # when fed the raw lines one at a time via push.
524 # when fed the raw lines one at a time via push.
525 syntax_ml = \
525 syntax_ml = \
526 dict(classic_prompt =
526 dict(classic_prompt =
527 [ [('>>> for i in range(10):','for i in range(10):'),
527 [ [('>>> for i in range(10):','for i in range(10):'),
528 ('... print i',' print i'),
528 ('... print i',' print i'),
529 ('... ', ''),
529 ('... ', ''),
530 ],
530 ],
531 ],
531 ],
532
532
533 ipy_prompt =
533 ipy_prompt =
534 [ [('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):'),
535 (' ....: print i',' print i'),
535 (' ....: print i',' print i'),
536 (' ....: ', ''),
536 (' ....: ', ''),
537 ],
537 ],
538 ],
538 ],
539
539
540 multiline_datastructure =
540 multiline_datastructure =
541 [ [('>>> a = [1,','a = [1,'),
541 [ [('>>> a = [1,','a = [1,'),
542 ('... 2]','2]'),
542 ('... 2]','2]'),
543 ],
543 ],
544 ],
544 ],
545 )
545 )
546
546
547
547
548 def test_assign_system():
548 def test_assign_system():
549 tt.check_pairs(isp.transform_assign_system, syntax['assign_system'])
549 tt.check_pairs(isp.transform_assign_system, syntax['assign_system'])
550
550
551
551
552 def test_assign_magic():
552 def test_assign_magic():
553 tt.check_pairs(isp.transform_assign_magic, syntax['assign_magic'])
553 tt.check_pairs(isp.transform_assign_magic, syntax['assign_magic'])
554
554
555
555
556 def test_classic_prompt():
556 def test_classic_prompt():
557 transform_checker(syntax['classic_prompt'], isp.transform_classic_prompt)
557 transform_checker(syntax['classic_prompt'], isp.transform_classic_prompt)
558 for example in syntax_ml['classic_prompt']:
558 for example in syntax_ml['classic_prompt']:
559 transform_checker(example, isp.transform_classic_prompt)
559 transform_checker(example, isp.transform_classic_prompt)
560
560
561
561
562 def test_ipy_prompt():
562 def test_ipy_prompt():
563 transform_checker(syntax['ipy_prompt'], isp.transform_ipy_prompt)
563 transform_checker(syntax['ipy_prompt'], isp.transform_ipy_prompt)
564 for example in syntax_ml['ipy_prompt']:
564 for example in syntax_ml['ipy_prompt']:
565 transform_checker(example, isp.transform_ipy_prompt)
565 transform_checker(example, isp.transform_ipy_prompt)
566
566
567 def test_end_help():
567 def test_end_help():
568 tt.check_pairs(isp.transform_help_end, syntax['end_help'])
568 tt.check_pairs(isp.transform_help_end, syntax['end_help'])
569
569
570 def test_escaped_noesc():
570 def test_escaped_noesc():
571 tt.check_pairs(isp.transform_escaped, syntax['escaped_noesc'])
571 tt.check_pairs(isp.transform_escaped, syntax['escaped_noesc'])
572
572
573
573
574 def test_escaped_shell():
574 def test_escaped_shell():
575 tt.check_pairs(isp.transform_escaped, syntax['escaped_shell'])
575 tt.check_pairs(isp.transform_escaped, syntax['escaped_shell'])
576
576
577
577
578 def test_escaped_help():
578 def test_escaped_help():
579 tt.check_pairs(isp.transform_escaped, syntax['escaped_help'])
579 tt.check_pairs(isp.transform_escaped, syntax['escaped_help'])
580
580
581
581
582 def test_escaped_magic():
582 def test_escaped_magic():
583 tt.check_pairs(isp.transform_escaped, syntax['escaped_magic'])
583 tt.check_pairs(isp.transform_escaped, syntax['escaped_magic'])
584
584
585
585
586 def test_escaped_quote():
586 def test_escaped_quote():
587 tt.check_pairs(isp.transform_escaped, syntax['escaped_quote'])
587 tt.check_pairs(isp.transform_escaped, syntax['escaped_quote'])
588
588
589
589
590 def test_escaped_quote2():
590 def test_escaped_quote2():
591 tt.check_pairs(isp.transform_escaped, syntax['escaped_quote2'])
591 tt.check_pairs(isp.transform_escaped, syntax['escaped_quote2'])
592
592
593
593
594 def test_escaped_paren():
594 def test_escaped_paren():
595 tt.check_pairs(isp.transform_escaped, syntax['escaped_paren'])
595 tt.check_pairs(isp.transform_escaped, syntax['escaped_paren'])
596
596
597
597
598 class IPythonInputTestCase(InputSplitterTestCase):
598 class IPythonInputTestCase(InputSplitterTestCase):
599 """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
600 re-run the same test battery on the new input splitter.
600 re-run the same test battery on the new input splitter.
601
601
602 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
603 were tested by individual functions, as part of the OO interface.
603 were tested by individual functions, as part of the OO interface.
604
604
605 It also makes some checks on the raw buffer storage.
605 It also makes some checks on the raw buffer storage.
606 """
606 """
607
607
608 def setUp(self):
608 def setUp(self):
609 self.isp = isp.IPythonInputSplitter(input_mode='line')
609 self.isp = isp.IPythonInputSplitter(input_mode='line')
610
610
611 def test_syntax(self):
611 def test_syntax(self):
612 """Call all single-line syntax tests from the main object"""
612 """Call all single-line syntax tests from the main object"""
613 isp = self.isp
613 isp = self.isp
614 for example in syntax.itervalues():
614 for example in syntax.itervalues():
615 for raw, out_t in example:
615 for raw, out_t in example:
616 if raw.startswith(' '):
616 if raw.startswith(' '):
617 continue
617 continue
618
618
619 isp.push(raw)
619 isp.push(raw)
620 out, out_raw = isp.source_raw_reset()
620 out, out_raw = isp.source_raw_reset()
621 self.assertEqual(out.rstrip(), out_t,
621 self.assertEqual(out.rstrip(), out_t,
622 tt.pair_fail_msg.format("inputsplitter",raw, out_t, out))
622 tt.pair_fail_msg.format("inputsplitter",raw, out_t, out))
623 self.assertEqual(out_raw.rstrip(), raw.rstrip())
623 self.assertEqual(out_raw.rstrip(), raw.rstrip())
624
624
625 def test_syntax_multiline(self):
625 def test_syntax_multiline(self):
626 isp = self.isp
626 isp = self.isp
627 for example in syntax_ml.itervalues():
627 for example in syntax_ml.itervalues():
628 out_t_parts = []
628 out_t_parts = []
629 raw_parts = []
629 raw_parts = []
630 for line_pairs in example:
630 for line_pairs in example:
631 for lraw, out_t_part in line_pairs:
631 for lraw, out_t_part in line_pairs:
632 isp.push(lraw)
632 isp.push(lraw)
633 out_t_parts.append(out_t_part)
633 out_t_parts.append(out_t_part)
634 raw_parts.append(lraw)
634 raw_parts.append(lraw)
635
635
636 out, out_raw = isp.source_raw_reset()
636 out, out_raw = isp.source_raw_reset()
637 out_t = '\n'.join(out_t_parts).rstrip()
637 out_t = '\n'.join(out_t_parts).rstrip()
638 raw = '\n'.join(raw_parts).rstrip()
638 raw = '\n'.join(raw_parts).rstrip()
639 self.assertEqual(out.rstrip(), out_t)
639 self.assertEqual(out.rstrip(), out_t)
640 self.assertEqual(out_raw.rstrip(), raw)
640 self.assertEqual(out_raw.rstrip(), raw)
641
641
642
642
643 class BlockIPythonInputTestCase(IPythonInputTestCase):
643 class BlockIPythonInputTestCase(IPythonInputTestCase):
644
644
645 # Deactivate tests that don't make sense for the block mode
645 # Deactivate tests that don't make sense for the block mode
646 test_push3 = test_split = lambda s: None
646 test_push3 = test_split = lambda s: None
647
647
648 def setUp(self):
648 def setUp(self):
649 self.isp = isp.IPythonInputSplitter(input_mode='cell')
649 self.isp = isp.IPythonInputSplitter(input_mode='cell')
650
650
651 def test_syntax_multiline(self):
651 def test_syntax_multiline(self):
652 isp = self.isp
652 isp = self.isp
653 for example in syntax_ml.itervalues():
653 for example in syntax_ml.itervalues():
654 raw_parts = []
654 raw_parts = []
655 out_t_parts = []
655 out_t_parts = []
656 for line_pairs in example:
656 for line_pairs in example:
657 for raw, out_t_part in line_pairs:
657 for raw, out_t_part in line_pairs:
658 raw_parts.append(raw)
658 raw_parts.append(raw)
659 out_t_parts.append(out_t_part)
659 out_t_parts.append(out_t_part)
660
660
661 raw = '\n'.join(raw_parts)
661 raw = '\n'.join(raw_parts)
662 out_t = '\n'.join(out_t_parts)
662 out_t = '\n'.join(out_t_parts)
663
663
664 isp.push(raw)
664 isp.push(raw)
665 out, out_raw = isp.source_raw_reset()
665 out, out_raw = isp.source_raw_reset()
666 # Match ignoring trailing whitespace
666 # Match ignoring trailing whitespace
667 self.assertEqual(out.rstrip(), out_t.rstrip())
667 self.assertEqual(out.rstrip(), out_t.rstrip())
668 self.assertEqual(out_raw.rstrip(), raw.rstrip())
668 self.assertEqual(out_raw.rstrip(), raw.rstrip())
669
669
670
670
671 #-----------------------------------------------------------------------------
671 #-----------------------------------------------------------------------------
672 # Main - use as a script, mostly for developer experiments
672 # Main - use as a script, mostly for developer experiments
673 #-----------------------------------------------------------------------------
673 #-----------------------------------------------------------------------------
674
674
675 if __name__ == '__main__':
675 if __name__ == '__main__':
676 # A simple demo for interactive experimentation. This code will not get
676 # A simple demo for interactive experimentation. This code will not get
677 # picked up by any test suite.
677 # picked up by any test suite.
678 from IPython.core.inputsplitter import InputSplitter, IPythonInputSplitter
678 from IPython.core.inputsplitter import InputSplitter, IPythonInputSplitter
679
679
680 # configure here the syntax to use, prompt and whether to autoindent
680 # configure here the syntax to use, prompt and whether to autoindent
681 #isp, start_prompt = InputSplitter(), '>>> '
681 #isp, start_prompt = InputSplitter(), '>>> '
682 isp, start_prompt = IPythonInputSplitter(), 'In> '
682 isp, start_prompt = IPythonInputSplitter(), 'In> '
683
683
684 autoindent = True
684 autoindent = True
685 #autoindent = False
685 #autoindent = False
686
686
687 try:
687 try:
688 while True:
688 while True:
689 prompt = start_prompt
689 prompt = start_prompt
690 while isp.push_accepts_more():
690 while isp.push_accepts_more():
691 indent = ' '*isp.indent_spaces
691 indent = ' '*isp.indent_spaces
692 if autoindent:
692 if autoindent:
693 line = indent + raw_input(prompt+indent)
693 line = indent + raw_input(prompt+indent)
694 else:
694 else:
695 line = raw_input(prompt)
695 line = raw_input(prompt)
696 isp.push(line)
696 isp.push(line)
697 prompt = '... '
697 prompt = '... '
698
698
699 # 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
700 # real interpreter would instead send it for execution somewhere.
700 # real interpreter would instead send it for execution somewhere.
701 #src = isp.source; raise EOFError # dbg
701 #src = isp.source; raise EOFError # dbg
702 src, raw = isp.source_raw_reset()
702 src, raw = isp.source_raw_reset()
703 print 'Input source was:\n', src
703 print 'Input source was:\n', src
704 print 'Raw source was:\n', raw
704 print 'Raw source was:\n', raw
705 except EOFError:
705 except EOFError:
706 print 'Bye'
706 print 'Bye'
@@ -1,121 +1,121 b''
1 #-----------------------------------------------------------------------------
1 #-----------------------------------------------------------------------------
2 # Copyright (c) 2010, IPython Development Team.
2 # Copyright (C) 2010-2011, IPython Development Team.
3 #
3 #
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5 #
5 #
6 # The full license is in the file COPYING.txt, distributed with this software.
6 # The full license is in the file COPYING.txt, distributed with this software.
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8
8
9 from nose.tools import assert_equal, assert_true
9 from nose.tools import assert_equal, assert_true
10
10
11 from IPython.external import argparse
11 from IPython.external import argparse
12 from IPython.core.magic_arguments import (argument, argument_group, kwds,
12 from IPython.core.magic_arguments import (argument, argument_group, kwds,
13 magic_arguments, parse_argstring, real_name)
13 magic_arguments, parse_argstring, real_name)
14 from IPython.testing.decorators import parametric
14 from IPython.testing.decorators import parametric
15
15
16
16
17 @magic_arguments()
17 @magic_arguments()
18 @argument('-f', '--foo', help="an argument")
18 @argument('-f', '--foo', help="an argument")
19 def magic_foo1(self, args):
19 def magic_foo1(self, args):
20 """ A docstring.
20 """ A docstring.
21 """
21 """
22 return parse_argstring(magic_foo1, args)
22 return parse_argstring(magic_foo1, args)
23
23
24
24
25 @magic_arguments()
25 @magic_arguments()
26 def magic_foo2(self, args):
26 def magic_foo2(self, args):
27 """ A docstring.
27 """ A docstring.
28 """
28 """
29 return parse_argstring(magic_foo2, args)
29 return parse_argstring(magic_foo2, args)
30
30
31
31
32 @magic_arguments()
32 @magic_arguments()
33 @argument('-f', '--foo', help="an argument")
33 @argument('-f', '--foo', help="an argument")
34 @argument_group('Group')
34 @argument_group('Group')
35 @argument('-b', '--bar', help="a grouped argument")
35 @argument('-b', '--bar', help="a grouped argument")
36 @argument_group('Second Group')
36 @argument_group('Second Group')
37 @argument('-z', '--baz', help="another grouped argument")
37 @argument('-z', '--baz', help="another grouped argument")
38 def magic_foo3(self, args):
38 def magic_foo3(self, args):
39 """ A docstring.
39 """ A docstring.
40 """
40 """
41 return parse_argstring(magic_foo3, args)
41 return parse_argstring(magic_foo3, args)
42
42
43
43
44 @magic_arguments()
44 @magic_arguments()
45 @kwds(argument_default=argparse.SUPPRESS)
45 @kwds(argument_default=argparse.SUPPRESS)
46 @argument('-f', '--foo', help="an argument")
46 @argument('-f', '--foo', help="an argument")
47 def magic_foo4(self, args):
47 def magic_foo4(self, args):
48 """ A docstring.
48 """ A docstring.
49 """
49 """
50 return parse_argstring(magic_foo4, args)
50 return parse_argstring(magic_foo4, args)
51
51
52
52
53 @magic_arguments('frobnicate')
53 @magic_arguments('frobnicate')
54 @argument('-f', '--foo', help="an argument")
54 @argument('-f', '--foo', help="an argument")
55 def magic_foo5(self, args):
55 def magic_foo5(self, args):
56 """ A docstring.
56 """ A docstring.
57 """
57 """
58 return parse_argstring(magic_foo5, args)
58 return parse_argstring(magic_foo5, args)
59
59
60
60
61 @magic_arguments()
61 @magic_arguments()
62 @argument('-f', '--foo', help="an argument")
62 @argument('-f', '--foo', help="an argument")
63 def magic_magic_foo(self, args):
63 def magic_magic_foo(self, args):
64 """ A docstring.
64 """ A docstring.
65 """
65 """
66 return parse_argstring(magic_magic_foo, args)
66 return parse_argstring(magic_magic_foo, args)
67
67
68
68
69 @magic_arguments()
69 @magic_arguments()
70 @argument('-f', '--foo', help="an argument")
70 @argument('-f', '--foo', help="an argument")
71 def foo(self, args):
71 def foo(self, args):
72 """ A docstring.
72 """ A docstring.
73 """
73 """
74 return parse_argstring(foo, args)
74 return parse_argstring(foo, args)
75
75
76
76
77 @parametric
77 @parametric
78 def test_magic_arguments():
78 def test_magic_arguments():
79 # Ideally, these would be doctests, but I could not get it to work.
79 # Ideally, these would be doctests, but I could not get it to work.
80 yield assert_equal(magic_foo1.__doc__, '%foo1 [-f FOO]\n\nA docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n')
80 yield assert_equal(magic_foo1.__doc__, '%foo1 [-f FOO]\n\nA docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n')
81 yield assert_equal(getattr(magic_foo1, 'argcmd_name', None), None)
81 yield assert_equal(getattr(magic_foo1, 'argcmd_name', None), None)
82 yield assert_equal(real_name(magic_foo1), 'foo1')
82 yield assert_equal(real_name(magic_foo1), 'foo1')
83 yield assert_equal(magic_foo1(None, ''), argparse.Namespace(foo=None))
83 yield assert_equal(magic_foo1(None, ''), argparse.Namespace(foo=None))
84 yield assert_true(hasattr(magic_foo1, 'has_arguments'))
84 yield assert_true(hasattr(magic_foo1, 'has_arguments'))
85
85
86 yield assert_equal(magic_foo2.__doc__, '%foo2\n\nA docstring.\n')
86 yield assert_equal(magic_foo2.__doc__, '%foo2\n\nA docstring.\n')
87 yield assert_equal(getattr(magic_foo2, 'argcmd_name', None), None)
87 yield assert_equal(getattr(magic_foo2, 'argcmd_name', None), None)
88 yield assert_equal(real_name(magic_foo2), 'foo2')
88 yield assert_equal(real_name(magic_foo2), 'foo2')
89 yield assert_equal(magic_foo2(None, ''), argparse.Namespace())
89 yield assert_equal(magic_foo2(None, ''), argparse.Namespace())
90 yield assert_true(hasattr(magic_foo2, 'has_arguments'))
90 yield assert_true(hasattr(magic_foo2, 'has_arguments'))
91
91
92 yield assert_equal(magic_foo3.__doc__, '%foo3 [-f FOO] [-b BAR] [-z BAZ]\n\nA docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n\nGroup:\n -b BAR, --bar BAR a grouped argument\n\nSecond Group:\n -z BAZ, --baz BAZ another grouped argument\n')
92 yield assert_equal(magic_foo3.__doc__, '%foo3 [-f FOO] [-b BAR] [-z BAZ]\n\nA docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n\nGroup:\n -b BAR, --bar BAR a grouped argument\n\nSecond Group:\n -z BAZ, --baz BAZ another grouped argument\n')
93 yield assert_equal(getattr(magic_foo3, 'argcmd_name', None), None)
93 yield assert_equal(getattr(magic_foo3, 'argcmd_name', None), None)
94 yield assert_equal(real_name(magic_foo3), 'foo3')
94 yield assert_equal(real_name(magic_foo3), 'foo3')
95 yield assert_equal(magic_foo3(None, ''),
95 yield assert_equal(magic_foo3(None, ''),
96 argparse.Namespace(bar=None, baz=None, foo=None))
96 argparse.Namespace(bar=None, baz=None, foo=None))
97 yield assert_true(hasattr(magic_foo3, 'has_arguments'))
97 yield assert_true(hasattr(magic_foo3, 'has_arguments'))
98
98
99 yield assert_equal(magic_foo4.__doc__, '%foo4 [-f FOO]\n\nA docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n')
99 yield assert_equal(magic_foo4.__doc__, '%foo4 [-f FOO]\n\nA docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n')
100 yield assert_equal(getattr(magic_foo4, 'argcmd_name', None), None)
100 yield assert_equal(getattr(magic_foo4, 'argcmd_name', None), None)
101 yield assert_equal(real_name(magic_foo4), 'foo4')
101 yield assert_equal(real_name(magic_foo4), 'foo4')
102 yield assert_equal(magic_foo4(None, ''), argparse.Namespace())
102 yield assert_equal(magic_foo4(None, ''), argparse.Namespace())
103 yield assert_true(hasattr(magic_foo4, 'has_arguments'))
103 yield assert_true(hasattr(magic_foo4, 'has_arguments'))
104
104
105 yield assert_equal(magic_foo5.__doc__, '%frobnicate [-f FOO]\n\nA docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n')
105 yield assert_equal(magic_foo5.__doc__, '%frobnicate [-f FOO]\n\nA docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n')
106 yield assert_equal(getattr(magic_foo5, 'argcmd_name', None), 'frobnicate')
106 yield assert_equal(getattr(magic_foo5, 'argcmd_name', None), 'frobnicate')
107 yield assert_equal(real_name(magic_foo5), 'frobnicate')
107 yield assert_equal(real_name(magic_foo5), 'frobnicate')
108 yield assert_equal(magic_foo5(None, ''), argparse.Namespace(foo=None))
108 yield assert_equal(magic_foo5(None, ''), argparse.Namespace(foo=None))
109 yield assert_true(hasattr(magic_foo5, 'has_arguments'))
109 yield assert_true(hasattr(magic_foo5, 'has_arguments'))
110
110
111 yield assert_equal(magic_magic_foo.__doc__, '%magic_foo [-f FOO]\n\nA docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n')
111 yield assert_equal(magic_magic_foo.__doc__, '%magic_foo [-f FOO]\n\nA docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n')
112 yield assert_equal(getattr(magic_magic_foo, 'argcmd_name', None), None)
112 yield assert_equal(getattr(magic_magic_foo, 'argcmd_name', None), None)
113 yield assert_equal(real_name(magic_magic_foo), 'magic_foo')
113 yield assert_equal(real_name(magic_magic_foo), 'magic_foo')
114 yield assert_equal(magic_magic_foo(None, ''), argparse.Namespace(foo=None))
114 yield assert_equal(magic_magic_foo(None, ''), argparse.Namespace(foo=None))
115 yield assert_true(hasattr(magic_magic_foo, 'has_arguments'))
115 yield assert_true(hasattr(magic_magic_foo, 'has_arguments'))
116
116
117 yield assert_equal(foo.__doc__, '%foo [-f FOO]\n\nA docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n')
117 yield assert_equal(foo.__doc__, '%foo [-f FOO]\n\nA docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n')
118 yield assert_equal(getattr(foo, 'argcmd_name', None), None)
118 yield assert_equal(getattr(foo, 'argcmd_name', None), None)
119 yield assert_equal(real_name(foo), 'foo')
119 yield assert_equal(real_name(foo), 'foo')
120 yield assert_equal(foo(None, ''), argparse.Namespace(foo=None))
120 yield assert_equal(foo(None, ''), argparse.Namespace(foo=None))
121 yield assert_true(hasattr(foo, 'has_arguments'))
121 yield assert_true(hasattr(foo, 'has_arguments'))
@@ -1,136 +1,136 b''
1 """Tests for the object inspection functionality.
1 """Tests for the object inspection functionality.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (C) 2010 The IPython Development Team.
4 # Copyright (C) 2010-2011 The IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the BSD License.
6 # Distributed under the terms of the BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 from __future__ import print_function
14 from __future__ import print_function
15
15
16 # Stdlib imports
16 # Stdlib imports
17
17
18 # Third-party imports
18 # Third-party imports
19 import nose.tools as nt
19 import nose.tools as nt
20
20
21 # Our own imports
21 # Our own imports
22 from .. import oinspect
22 from .. import oinspect
23 from IPython.utils import py3compat
23 from IPython.utils import py3compat
24
24
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26 # Globals and constants
26 # Globals and constants
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28
28
29 inspector = oinspect.Inspector()
29 inspector = oinspect.Inspector()
30
30
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32 # Local utilities
32 # Local utilities
33 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
34
34
35 # A few generic objects we can then inspect in the tests below
35 # A few generic objects we can then inspect in the tests below
36
36
37 class Call(object):
37 class Call(object):
38 """This is the class docstring."""
38 """This is the class docstring."""
39
39
40 def __init__(self, x, y=1):
40 def __init__(self, x, y=1):
41 """This is the constructor docstring."""
41 """This is the constructor docstring."""
42
42
43 def __call__(self, *a, **kw):
43 def __call__(self, *a, **kw):
44 """This is the call docstring."""
44 """This is the call docstring."""
45
45
46 def method(self, x, z=2):
46 def method(self, x, z=2):
47 """Some method's docstring"""
47 """Some method's docstring"""
48
48
49 class OldStyle:
49 class OldStyle:
50 """An old-style class for testing."""
50 """An old-style class for testing."""
51 pass
51 pass
52
52
53 def f(x, y=2, *a, **kw):
53 def f(x, y=2, *a, **kw):
54 """A simple function."""
54 """A simple function."""
55
55
56 def g(y, z=3, *a, **kw):
56 def g(y, z=3, *a, **kw):
57 pass # no docstring
57 pass # no docstring
58
58
59
59
60 def check_calltip(obj, name, call, docstring):
60 def check_calltip(obj, name, call, docstring):
61 """Generic check pattern all calltip tests will use"""
61 """Generic check pattern all calltip tests will use"""
62 info = inspector.info(obj, name)
62 info = inspector.info(obj, name)
63 call_line, ds = oinspect.call_tip(info)
63 call_line, ds = oinspect.call_tip(info)
64 nt.assert_equal(call_line, call)
64 nt.assert_equal(call_line, call)
65 nt.assert_equal(ds, docstring)
65 nt.assert_equal(ds, docstring)
66
66
67 #-----------------------------------------------------------------------------
67 #-----------------------------------------------------------------------------
68 # Tests
68 # Tests
69 #-----------------------------------------------------------------------------
69 #-----------------------------------------------------------------------------
70
70
71 def test_calltip_class():
71 def test_calltip_class():
72 check_calltip(Call, 'Call', 'Call(x, y=1)', Call.__init__.__doc__)
72 check_calltip(Call, 'Call', 'Call(x, y=1)', Call.__init__.__doc__)
73
73
74
74
75 def test_calltip_instance():
75 def test_calltip_instance():
76 c = Call(1)
76 c = Call(1)
77 check_calltip(c, 'c', 'c(*a, **kw)', c.__call__.__doc__)
77 check_calltip(c, 'c', 'c(*a, **kw)', c.__call__.__doc__)
78
78
79
79
80 def test_calltip_method():
80 def test_calltip_method():
81 c = Call(1)
81 c = Call(1)
82 check_calltip(c.method, 'c.method', 'c.method(x, z=2)', c.method.__doc__)
82 check_calltip(c.method, 'c.method', 'c.method(x, z=2)', c.method.__doc__)
83
83
84
84
85 def test_calltip_function():
85 def test_calltip_function():
86 check_calltip(f, 'f', 'f(x, y=2, *a, **kw)', f.__doc__)
86 check_calltip(f, 'f', 'f(x, y=2, *a, **kw)', f.__doc__)
87
87
88
88
89 def test_calltip_function2():
89 def test_calltip_function2():
90 check_calltip(g, 'g', 'g(y, z=3, *a, **kw)', '<no docstring>')
90 check_calltip(g, 'g', 'g(y, z=3, *a, **kw)', '<no docstring>')
91
91
92
92
93 def test_calltip_builtin():
93 def test_calltip_builtin():
94 check_calltip(sum, 'sum', None, sum.__doc__)
94 check_calltip(sum, 'sum', None, sum.__doc__)
95
95
96 def test_info():
96 def test_info():
97 "Check that Inspector.info fills out various fields as expected."
97 "Check that Inspector.info fills out various fields as expected."
98 i = inspector.info(Call, oname='Call')
98 i = inspector.info(Call, oname='Call')
99 nt.assert_equal(i['type_name'], 'type')
99 nt.assert_equal(i['type_name'], 'type')
100 expted_class = str(type(type)) # <class 'type'> (Python 3) or <type 'type'>
100 expted_class = str(type(type)) # <class 'type'> (Python 3) or <type 'type'>
101 nt.assert_equal(i['base_class'], expted_class)
101 nt.assert_equal(i['base_class'], expted_class)
102 nt.assert_equal(i['string_form'], "<class 'IPython.core.tests.test_oinspect.Call'>")
102 nt.assert_equal(i['string_form'], "<class 'IPython.core.tests.test_oinspect.Call'>")
103 fname = __file__
103 fname = __file__
104 if fname.endswith(".pyc"):
104 if fname.endswith(".pyc"):
105 fname = fname[:-1]
105 fname = fname[:-1]
106 # case-insensitive comparison needed on some filesystems
106 # case-insensitive comparison needed on some filesystems
107 # e.g. Windows:
107 # e.g. Windows:
108 nt.assert_equal(i['file'].lower(), fname.lower())
108 nt.assert_equal(i['file'].lower(), fname.lower())
109 nt.assert_equal(i['definition'], 'Call(self, *a, **kw)\n')
109 nt.assert_equal(i['definition'], 'Call(self, *a, **kw)\n')
110 nt.assert_equal(i['docstring'], Call.__doc__)
110 nt.assert_equal(i['docstring'], Call.__doc__)
111 nt.assert_equal(i['source'], None)
111 nt.assert_equal(i['source'], None)
112 nt.assert_true(i['isclass'])
112 nt.assert_true(i['isclass'])
113 nt.assert_equal(i['init_definition'], "Call(self, x, y=1)\n")
113 nt.assert_equal(i['init_definition'], "Call(self, x, y=1)\n")
114 nt.assert_equal(i['init_docstring'], Call.__init__.__doc__)
114 nt.assert_equal(i['init_docstring'], Call.__init__.__doc__)
115
115
116 i = inspector.info(Call, detail_level=1)
116 i = inspector.info(Call, detail_level=1)
117 nt.assert_not_equal(i['source'], None)
117 nt.assert_not_equal(i['source'], None)
118 nt.assert_equal(i['docstring'], None)
118 nt.assert_equal(i['docstring'], None)
119
119
120 c = Call(1)
120 c = Call(1)
121 c.__doc__ = "Modified instance docstring"
121 c.__doc__ = "Modified instance docstring"
122 i = inspector.info(c)
122 i = inspector.info(c)
123 nt.assert_equal(i['type_name'], 'Call')
123 nt.assert_equal(i['type_name'], 'Call')
124 nt.assert_equal(i['docstring'], "Modified instance docstring")
124 nt.assert_equal(i['docstring'], "Modified instance docstring")
125 nt.assert_equal(i['class_docstring'], Call.__doc__)
125 nt.assert_equal(i['class_docstring'], Call.__doc__)
126 nt.assert_equal(i['init_docstring'], Call.__init__.__doc__)
126 nt.assert_equal(i['init_docstring'], Call.__init__.__doc__)
127 nt.assert_equal(i['call_docstring'], c.__call__.__doc__)
127 nt.assert_equal(i['call_docstring'], c.__call__.__doc__)
128
128
129 # Test old-style classes, which for example may not have an __init__ method.
129 # Test old-style classes, which for example may not have an __init__ method.
130 if not py3compat.PY3:
130 if not py3compat.PY3:
131 i = inspector.info(OldStyle)
131 i = inspector.info(OldStyle)
132 nt.assert_equal(i['type_name'], 'classobj')
132 nt.assert_equal(i['type_name'], 'classobj')
133
133
134 i = inspector.info(OldStyle())
134 i = inspector.info(OldStyle())
135 nt.assert_equal(i['type_name'], 'instance')
135 nt.assert_equal(i['type_name'], 'instance')
136 nt.assert_equal(i['docstring'], OldStyle.__doc__)
136 nt.assert_equal(i['docstring'], OldStyle.__doc__)
@@ -1,20 +1,20 b''
1 #-----------------------------------------------------------------------------
1 #-----------------------------------------------------------------------------
2 # Copyright (C) 2010 The IPython Development Team.
2 # Copyright (C) 2010-2011 The IPython Development Team.
3 #
3 #
4 # Distributed under the terms of the BSD License.
4 # Distributed under the terms of the BSD License.
5 #
5 #
6 # The full license is in the file COPYING.txt, distributed with this software.
6 # The full license is in the file COPYING.txt, distributed with this software.
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 import io
8 import io
9
9
10 # N.B. For the test suite, page.page is overridden (see IPython.testing.globalipapp)
10 # N.B. For the test suite, page.page is overridden (see IPython.testing.globalipapp)
11 from IPython.core import page
11 from IPython.core import page
12
12
13 def test_detect_screen_size():
13 def test_detect_screen_size():
14 """Simple smoketest for page._detect_screen_size."""
14 """Simple smoketest for page._detect_screen_size."""
15 try:
15 try:
16 page._detect_screen_size(True, 25)
16 page._detect_screen_size(True, 25)
17 except (TypeError, io.UnsupportedOperation):
17 except (TypeError, io.UnsupportedOperation):
18 # This can happen in the test suite, because stdout may not have a
18 # This can happen in the test suite, because stdout may not have a
19 # fileno.
19 # fileno.
20 pass
20 pass
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now