##// END OF EJS Templates
update copyright to 2011/20xx-2011...
Matthias BUSSONNIER -
Show More
@@ -1,14 +1,14 b''
1 1 # encoding: utf-8
2 2
3 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 8 # Distributed under the terms of the BSD License. The full license is in
9 9 # the file COPYING, distributed as part of this software.
10 10 #-------------------------------------------------------------------------------
11 11
12 12 #-------------------------------------------------------------------------------
13 13 # Imports
14 14 #------------------------------------------------------------------------------- No newline at end of file
@@ -1,183 +1,183 b''
1 1 # encoding: utf-8
2 2 """
3 3 Tests for IPython.config.configurable
4 4
5 5 Authors:
6 6
7 7 * Brian Granger
8 8 * Fernando Perez (design help)
9 9 """
10 10
11 11 #-----------------------------------------------------------------------------
12 # Copyright (C) 2008-2010 The IPython Development Team
12 # Copyright (C) 2008-2011 The IPython Development Team
13 13 #
14 14 # Distributed under the terms of the BSD License. The full license is in
15 15 # the file COPYING, distributed as part of this software.
16 16 #-----------------------------------------------------------------------------
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Imports
20 20 #-----------------------------------------------------------------------------
21 21
22 22 from unittest import TestCase
23 23
24 24 from IPython.config.configurable import (
25 25 Configurable,
26 26 SingletonConfigurable
27 27 )
28 28
29 29 from IPython.utils.traitlets import (
30 30 Integer, Float, Unicode
31 31 )
32 32
33 33 from IPython.config.loader import Config
34 34 from IPython.utils.py3compat import PY3
35 35
36 36 #-----------------------------------------------------------------------------
37 37 # Test cases
38 38 #-----------------------------------------------------------------------------
39 39
40 40
41 41 class MyConfigurable(Configurable):
42 42 a = Integer(1, config=True, help="The integer a.")
43 43 b = Float(1.0, config=True, help="The integer b.")
44 44 c = Unicode('no config')
45 45
46 46
47 47 mc_help=u"""MyConfigurable options
48 48 ----------------------
49 49 --MyConfigurable.a=<Integer>
50 50 Default: 1
51 51 The integer a.
52 52 --MyConfigurable.b=<Float>
53 53 Default: 1.0
54 54 The integer b."""
55 55
56 56 mc_help_inst=u"""MyConfigurable options
57 57 ----------------------
58 58 --MyConfigurable.a=<Integer>
59 59 Current: 5
60 60 The integer a.
61 61 --MyConfigurable.b=<Float>
62 62 Current: 4.0
63 63 The integer b."""
64 64
65 65 # On Python 3, the Integer trait is a synonym for Int
66 66 if PY3:
67 67 mc_help = mc_help.replace(u"<Integer>", u"<Int>")
68 68 mc_help_inst = mc_help_inst.replace(u"<Integer>", u"<Int>")
69 69
70 70 class Foo(Configurable):
71 71 a = Integer(0, config=True, help="The integer a.")
72 72 b = Unicode('nope', config=True)
73 73
74 74
75 75 class Bar(Foo):
76 76 b = Unicode('gotit', config=False, help="The string b.")
77 77 c = Float(config=True, help="The string c.")
78 78
79 79
80 80 class TestConfigurable(TestCase):
81 81
82 82 def test_default(self):
83 83 c1 = Configurable()
84 84 c2 = Configurable(config=c1.config)
85 85 c3 = Configurable(config=c2.config)
86 86 self.assertEquals(c1.config, c2.config)
87 87 self.assertEquals(c2.config, c3.config)
88 88
89 89 def test_custom(self):
90 90 config = Config()
91 91 config.foo = 'foo'
92 92 config.bar = 'bar'
93 93 c1 = Configurable(config=config)
94 94 c2 = Configurable(config=c1.config)
95 95 c3 = Configurable(config=c2.config)
96 96 self.assertEquals(c1.config, config)
97 97 self.assertEquals(c2.config, config)
98 98 self.assertEquals(c3.config, config)
99 99 # Test that copies are not made
100 100 self.assert_(c1.config is config)
101 101 self.assert_(c2.config is config)
102 102 self.assert_(c3.config is config)
103 103 self.assert_(c1.config is c2.config)
104 104 self.assert_(c2.config is c3.config)
105 105
106 106 def test_inheritance(self):
107 107 config = Config()
108 108 config.MyConfigurable.a = 2
109 109 config.MyConfigurable.b = 2.0
110 110 c1 = MyConfigurable(config=config)
111 111 c2 = MyConfigurable(config=c1.config)
112 112 self.assertEquals(c1.a, config.MyConfigurable.a)
113 113 self.assertEquals(c1.b, config.MyConfigurable.b)
114 114 self.assertEquals(c2.a, config.MyConfigurable.a)
115 115 self.assertEquals(c2.b, config.MyConfigurable.b)
116 116
117 117 def test_parent(self):
118 118 config = Config()
119 119 config.Foo.a = 10
120 120 config.Foo.b = "wow"
121 121 config.Bar.b = 'later'
122 122 config.Bar.c = 100.0
123 123 f = Foo(config=config)
124 124 b = Bar(config=f.config)
125 125 self.assertEquals(f.a, 10)
126 126 self.assertEquals(f.b, 'wow')
127 127 self.assertEquals(b.b, 'gotit')
128 128 self.assertEquals(b.c, 100.0)
129 129
130 130 def test_override1(self):
131 131 config = Config()
132 132 config.MyConfigurable.a = 2
133 133 config.MyConfigurable.b = 2.0
134 134 c = MyConfigurable(a=3, config=config)
135 135 self.assertEquals(c.a, 3)
136 136 self.assertEquals(c.b, config.MyConfigurable.b)
137 137 self.assertEquals(c.c, 'no config')
138 138
139 139 def test_override2(self):
140 140 config = Config()
141 141 config.Foo.a = 1
142 142 config.Bar.b = 'or' # Up above b is config=False, so this won't do it.
143 143 config.Bar.c = 10.0
144 144 c = Bar(config=config)
145 145 self.assertEquals(c.a, config.Foo.a)
146 146 self.assertEquals(c.b, 'gotit')
147 147 self.assertEquals(c.c, config.Bar.c)
148 148 c = Bar(a=2, b='and', c=20.0, config=config)
149 149 self.assertEquals(c.a, 2)
150 150 self.assertEquals(c.b, 'and')
151 151 self.assertEquals(c.c, 20.0)
152 152
153 153 def test_help(self):
154 154 self.assertEquals(MyConfigurable.class_get_help(), mc_help)
155 155
156 156 def test_help_inst(self):
157 157 inst = MyConfigurable(a=5, b=4)
158 158 self.assertEquals(MyConfigurable.class_get_help(inst), mc_help_inst)
159 159
160 160
161 161 class TestSingletonConfigurable(TestCase):
162 162
163 163 def test_instance(self):
164 164 from IPython.config.configurable import SingletonConfigurable
165 165 class Foo(SingletonConfigurable): pass
166 166 self.assertEquals(Foo.initialized(), False)
167 167 foo = Foo.instance()
168 168 self.assertEquals(Foo.initialized(), True)
169 169 self.assertEquals(foo, Foo.instance())
170 170 self.assertEquals(SingletonConfigurable._instance, None)
171 171
172 172 def test_inheritance(self):
173 173 class Bar(SingletonConfigurable): pass
174 174 class Bam(Bar): pass
175 175 self.assertEquals(Bar.initialized(), False)
176 176 self.assertEquals(Bam.initialized(), False)
177 177 bam = Bam.instance()
178 178 bam == Bar.instance()
179 179 self.assertEquals(Bar.initialized(), True)
180 180 self.assertEquals(Bam.initialized(), True)
181 181 self.assertEquals(bam, Bam._instance)
182 182 self.assertEquals(bam, Bar._instance)
183 183 self.assertEquals(SingletonConfigurable._instance, None)
@@ -1,255 +1,255 b''
1 1 # encoding: utf-8
2 2 """
3 3 Tests for IPython.config.loader
4 4
5 5 Authors:
6 6
7 7 * Brian Granger
8 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 14 # Distributed under the terms of the BSD License. The full license is in
15 15 # the file COPYING, distributed as part of this software.
16 16 #-----------------------------------------------------------------------------
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Imports
20 20 #-----------------------------------------------------------------------------
21 21
22 22 import os
23 23 import sys
24 24 from tempfile import mkstemp
25 25 from unittest import TestCase
26 26
27 27 from nose import SkipTest
28 28
29 29 from IPython.testing.tools import mute_warn
30 30
31 31 from IPython.utils.traitlets import Unicode
32 32 from IPython.config.configurable import Configurable
33 33 from IPython.config.loader import (
34 34 Config,
35 35 PyFileConfigLoader,
36 36 KeyValueConfigLoader,
37 37 ArgParseConfigLoader,
38 38 KVArgParseConfigLoader,
39 39 ConfigError
40 40 )
41 41
42 42 #-----------------------------------------------------------------------------
43 43 # Actual tests
44 44 #-----------------------------------------------------------------------------
45 45
46 46
47 47 pyfile = """
48 48 c = get_config()
49 49 c.a=10
50 50 c.b=20
51 51 c.Foo.Bar.value=10
52 52 c.Foo.Bam.value=list(range(10)) # list() is just so it's the same on Python 3
53 53 c.D.C.value='hi there'
54 54 """
55 55
56 56 class TestPyFileCL(TestCase):
57 57
58 58 def test_basic(self):
59 59 fd, fname = mkstemp('.py')
60 60 f = os.fdopen(fd, 'w')
61 61 f.write(pyfile)
62 62 f.close()
63 63 # Unlink the file
64 64 cl = PyFileConfigLoader(fname)
65 65 config = cl.load_config()
66 66 self.assertEquals(config.a, 10)
67 67 self.assertEquals(config.b, 20)
68 68 self.assertEquals(config.Foo.Bar.value, 10)
69 69 self.assertEquals(config.Foo.Bam.value, range(10))
70 70 self.assertEquals(config.D.C.value, 'hi there')
71 71
72 72 class MyLoader1(ArgParseConfigLoader):
73 73 def _add_arguments(self, aliases=None, flags=None):
74 74 p = self.parser
75 75 p.add_argument('-f', '--foo', dest='Global.foo', type=str)
76 76 p.add_argument('-b', dest='MyClass.bar', type=int)
77 77 p.add_argument('-n', dest='n', action='store_true')
78 78 p.add_argument('Global.bam', type=str)
79 79
80 80 class MyLoader2(ArgParseConfigLoader):
81 81 def _add_arguments(self, aliases=None, flags=None):
82 82 subparsers = self.parser.add_subparsers(dest='subparser_name')
83 83 subparser1 = subparsers.add_parser('1')
84 84 subparser1.add_argument('-x',dest='Global.x')
85 85 subparser2 = subparsers.add_parser('2')
86 86 subparser2.add_argument('y')
87 87
88 88 class TestArgParseCL(TestCase):
89 89
90 90 def test_basic(self):
91 91 cl = MyLoader1()
92 92 config = cl.load_config('-f hi -b 10 -n wow'.split())
93 93 self.assertEquals(config.Global.foo, 'hi')
94 94 self.assertEquals(config.MyClass.bar, 10)
95 95 self.assertEquals(config.n, True)
96 96 self.assertEquals(config.Global.bam, 'wow')
97 97 config = cl.load_config(['wow'])
98 98 self.assertEquals(config.keys(), ['Global'])
99 99 self.assertEquals(config.Global.keys(), ['bam'])
100 100 self.assertEquals(config.Global.bam, 'wow')
101 101
102 102 def test_add_arguments(self):
103 103 cl = MyLoader2()
104 104 config = cl.load_config('2 frobble'.split())
105 105 self.assertEquals(config.subparser_name, '2')
106 106 self.assertEquals(config.y, 'frobble')
107 107 config = cl.load_config('1 -x frobble'.split())
108 108 self.assertEquals(config.subparser_name, '1')
109 109 self.assertEquals(config.Global.x, 'frobble')
110 110
111 111 def test_argv(self):
112 112 cl = MyLoader1(argv='-f hi -b 10 -n wow'.split())
113 113 config = cl.load_config()
114 114 self.assertEquals(config.Global.foo, 'hi')
115 115 self.assertEquals(config.MyClass.bar, 10)
116 116 self.assertEquals(config.n, True)
117 117 self.assertEquals(config.Global.bam, 'wow')
118 118
119 119
120 120 class TestKeyValueCL(TestCase):
121 121 klass = KeyValueConfigLoader
122 122
123 123 def test_basic(self):
124 124 cl = self.klass()
125 125 argv = ['--'+s.strip('c.') for s in pyfile.split('\n')[2:-1]]
126 126 with mute_warn():
127 127 config = cl.load_config(argv)
128 128 self.assertEquals(config.a, 10)
129 129 self.assertEquals(config.b, 20)
130 130 self.assertEquals(config.Foo.Bar.value, 10)
131 131 self.assertEquals(config.Foo.Bam.value, range(10))
132 132 self.assertEquals(config.D.C.value, 'hi there')
133 133
134 134 def test_expanduser(self):
135 135 cl = self.klass()
136 136 argv = ['--a=~/1/2/3', '--b=~', '--c=~/', '--d="~/"']
137 137 with mute_warn():
138 138 config = cl.load_config(argv)
139 139 self.assertEquals(config.a, os.path.expanduser('~/1/2/3'))
140 140 self.assertEquals(config.b, os.path.expanduser('~'))
141 141 self.assertEquals(config.c, os.path.expanduser('~/'))
142 142 self.assertEquals(config.d, '~/')
143 143
144 144 def test_extra_args(self):
145 145 cl = self.klass()
146 146 with mute_warn():
147 147 config = cl.load_config(['--a=5', 'b', '--c=10', 'd'])
148 148 self.assertEquals(cl.extra_args, ['b', 'd'])
149 149 self.assertEquals(config.a, 5)
150 150 self.assertEquals(config.c, 10)
151 151 with mute_warn():
152 152 config = cl.load_config(['--', '--a=5', '--c=10'])
153 153 self.assertEquals(cl.extra_args, ['--a=5', '--c=10'])
154 154
155 155 def test_unicode_args(self):
156 156 cl = self.klass()
157 157 argv = [u'--a=épsîlön']
158 158 with mute_warn():
159 159 config = cl.load_config(argv)
160 160 self.assertEquals(config.a, u'épsîlön')
161 161
162 162 def test_unicode_bytes_args(self):
163 163 uarg = u'--a=é'
164 164 try:
165 165 barg = uarg.encode(sys.stdin.encoding)
166 166 except (TypeError, UnicodeEncodeError):
167 167 raise SkipTest("sys.stdin.encoding can't handle 'é'")
168 168
169 169 cl = self.klass()
170 170 with mute_warn():
171 171 config = cl.load_config([barg])
172 172 self.assertEquals(config.a, u'é')
173 173
174 174 def test_unicode_alias(self):
175 175 cl = self.klass()
176 176 argv = [u'--a=épsîlön']
177 177 with mute_warn():
178 178 config = cl.load_config(argv, aliases=dict(a='A.a'))
179 179 self.assertEquals(config.A.a, u'épsîlön')
180 180
181 181
182 182 class TestArgParseKVCL(TestKeyValueCL):
183 183 klass = KVArgParseConfigLoader
184 184
185 185 def test_expanduser2(self):
186 186 cl = self.klass()
187 187 argv = ['-a', '~/1/2/3', '--b', "'~/1/2/3'"]
188 188 with mute_warn():
189 189 config = cl.load_config(argv, aliases=dict(a='A.a', b='A.b'))
190 190 self.assertEquals(config.A.a, os.path.expanduser('~/1/2/3'))
191 191 self.assertEquals(config.A.b, '~/1/2/3')
192 192
193 193 class TestConfig(TestCase):
194 194
195 195 def test_setget(self):
196 196 c = Config()
197 197 c.a = 10
198 198 self.assertEquals(c.a, 10)
199 199 self.assertEquals(c.has_key('b'), False)
200 200
201 201 def test_auto_section(self):
202 202 c = Config()
203 203 self.assertEquals(c.has_key('A'), True)
204 204 self.assertEquals(c._has_section('A'), False)
205 205 A = c.A
206 206 A.foo = 'hi there'
207 207 self.assertEquals(c._has_section('A'), True)
208 208 self.assertEquals(c.A.foo, 'hi there')
209 209 del c.A
210 210 self.assertEquals(len(c.A.keys()),0)
211 211
212 212 def test_merge_doesnt_exist(self):
213 213 c1 = Config()
214 214 c2 = Config()
215 215 c2.bar = 10
216 216 c2.Foo.bar = 10
217 217 c1._merge(c2)
218 218 self.assertEquals(c1.Foo.bar, 10)
219 219 self.assertEquals(c1.bar, 10)
220 220 c2.Bar.bar = 10
221 221 c1._merge(c2)
222 222 self.assertEquals(c1.Bar.bar, 10)
223 223
224 224 def test_merge_exists(self):
225 225 c1 = Config()
226 226 c2 = Config()
227 227 c1.Foo.bar = 10
228 228 c1.Foo.bam = 30
229 229 c2.Foo.bar = 20
230 230 c2.Foo.wow = 40
231 231 c1._merge(c2)
232 232 self.assertEquals(c1.Foo.bam, 30)
233 233 self.assertEquals(c1.Foo.bar, 20)
234 234 self.assertEquals(c1.Foo.wow, 40)
235 235 c2.Foo.Bam.bam = 10
236 236 c1._merge(c2)
237 237 self.assertEquals(c1.Foo.Bam.bam, 10)
238 238
239 239 def test_deepcopy(self):
240 240 c1 = Config()
241 241 c1.Foo.bar = 10
242 242 c1.Foo.bam = 30
243 243 c1.a = 'asdf'
244 244 c1.b = range(10)
245 245 import copy
246 246 c2 = copy.deepcopy(c1)
247 247 self.assertEquals(c1, c2)
248 248 self.assert_(c1 is not c2)
249 249 self.assert_(c1.Foo is not c2.Foo)
250 250
251 251 def test_builtin(self):
252 252 c1 = Config()
253 253 exec 'foo = True' in c1
254 254 self.assertEquals(c1.foo, True)
255 255 self.assertRaises(ConfigError, setattr, c1, 'ValueError', 10)
@@ -1,263 +1,263 b''
1 1 # encoding: utf-8
2 2 """
3 3 System command aliases.
4 4
5 5 Authors:
6 6
7 7 * Fernando Perez
8 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 14 # Distributed under the terms of the BSD License.
15 15 #
16 16 # The full license is in the file COPYING.txt, distributed with this software.
17 17 #-----------------------------------------------------------------------------
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Imports
21 21 #-----------------------------------------------------------------------------
22 22
23 23 import __builtin__
24 24 import keyword
25 25 import os
26 26 import re
27 27 import sys
28 28
29 29 from IPython.config.configurable import Configurable
30 30 from IPython.core.splitinput import split_user_input
31 31
32 32 from IPython.utils.traitlets import List, Instance
33 33 from IPython.utils.autoattr import auto_attr
34 34 from IPython.utils.warn import warn, error
35 35
36 36 #-----------------------------------------------------------------------------
37 37 # Utilities
38 38 #-----------------------------------------------------------------------------
39 39
40 40 # This is used as the pattern for calls to split_user_input.
41 41 shell_line_split = re.compile(r'^(\s*)()(\S+)(.*$)')
42 42
43 43 def default_aliases():
44 44 """Return list of shell aliases to auto-define.
45 45 """
46 46 # Note: the aliases defined here should be safe to use on a kernel
47 47 # regardless of what frontend it is attached to. Frontends that use a
48 48 # kernel in-process can define additional aliases that will only work in
49 49 # their case. For example, things like 'less' or 'clear' that manipulate
50 50 # the terminal should NOT be declared here, as they will only work if the
51 51 # kernel is running inside a true terminal, and not over the network.
52 52
53 53 if os.name == 'posix':
54 54 default_aliases = [('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
55 55 ('mv', 'mv -i'), ('rm', 'rm -i'), ('cp', 'cp -i'),
56 56 ('cat', 'cat'),
57 57 ]
58 58 # Useful set of ls aliases. The GNU and BSD options are a little
59 59 # different, so we make aliases that provide as similar as possible
60 60 # behavior in ipython, by passing the right flags for each platform
61 61 if sys.platform.startswith('linux'):
62 62 ls_aliases = [('ls', 'ls -F --color'),
63 63 # long ls
64 64 ('ll', 'ls -F -o --color'),
65 65 # ls normal files only
66 66 ('lf', 'ls -F -o --color %l | grep ^-'),
67 67 # ls symbolic links
68 68 ('lk', 'ls -F -o --color %l | grep ^l'),
69 69 # directories or links to directories,
70 70 ('ldir', 'ls -F -o --color %l | grep /$'),
71 71 # things which are executable
72 72 ('lx', 'ls -F -o --color %l | grep ^-..x'),
73 73 ]
74 74 else:
75 75 # BSD, OSX, etc.
76 76 ls_aliases = [('ls', 'ls -F'),
77 77 # long ls
78 78 ('ll', 'ls -F -l'),
79 79 # ls normal files only
80 80 ('lf', 'ls -F -l %l | grep ^-'),
81 81 # ls symbolic links
82 82 ('lk', 'ls -F -l %l | grep ^l'),
83 83 # directories or links to directories,
84 84 ('ldir', 'ls -F -l %l | grep /$'),
85 85 # things which are executable
86 86 ('lx', 'ls -F -l %l | grep ^-..x'),
87 87 ]
88 88 default_aliases = default_aliases + ls_aliases
89 89 elif os.name in ['nt', 'dos']:
90 90 default_aliases = [('ls', 'dir /on'),
91 91 ('ddir', 'dir /ad /on'), ('ldir', 'dir /ad /on'),
92 92 ('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
93 93 ('echo', 'echo'), ('ren', 'ren'), ('copy', 'copy'),
94 94 ]
95 95 else:
96 96 default_aliases = []
97 97
98 98 return default_aliases
99 99
100 100
101 101 class AliasError(Exception):
102 102 pass
103 103
104 104
105 105 class InvalidAliasError(AliasError):
106 106 pass
107 107
108 108 #-----------------------------------------------------------------------------
109 109 # Main AliasManager class
110 110 #-----------------------------------------------------------------------------
111 111
112 112 class AliasManager(Configurable):
113 113
114 114 default_aliases = List(default_aliases(), config=True)
115 115 user_aliases = List(default_value=[], config=True)
116 116 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
117 117
118 118 def __init__(self, shell=None, config=None):
119 119 super(AliasManager, self).__init__(shell=shell, config=config)
120 120 self.alias_table = {}
121 121 self.exclude_aliases()
122 122 self.init_aliases()
123 123
124 124 def __contains__(self, name):
125 125 return name in self.alias_table
126 126
127 127 @property
128 128 def aliases(self):
129 129 return [(item[0], item[1][1]) for item in self.alias_table.iteritems()]
130 130
131 131 def exclude_aliases(self):
132 132 # set of things NOT to alias (keywords, builtins and some magics)
133 133 no_alias = set(['cd','popd','pushd','dhist','alias','unalias'])
134 134 no_alias.update(set(keyword.kwlist))
135 135 no_alias.update(set(__builtin__.__dict__.keys()))
136 136 self.no_alias = no_alias
137 137
138 138 def init_aliases(self):
139 139 # Load default aliases
140 140 for name, cmd in self.default_aliases:
141 141 self.soft_define_alias(name, cmd)
142 142
143 143 # Load user aliases
144 144 for name, cmd in self.user_aliases:
145 145 self.soft_define_alias(name, cmd)
146 146
147 147 def clear_aliases(self):
148 148 self.alias_table.clear()
149 149
150 150 def soft_define_alias(self, name, cmd):
151 151 """Define an alias, but don't raise on an AliasError."""
152 152 try:
153 153 self.define_alias(name, cmd)
154 154 except AliasError, e:
155 155 error("Invalid alias: %s" % e)
156 156
157 157 def define_alias(self, name, cmd):
158 158 """Define a new alias after validating it.
159 159
160 160 This will raise an :exc:`AliasError` if there are validation
161 161 problems.
162 162 """
163 163 nargs = self.validate_alias(name, cmd)
164 164 self.alias_table[name] = (nargs, cmd)
165 165
166 166 def undefine_alias(self, name):
167 167 if self.alias_table.has_key(name):
168 168 del self.alias_table[name]
169 169
170 170 def validate_alias(self, name, cmd):
171 171 """Validate an alias and return the its number of arguments."""
172 172 if name in self.no_alias:
173 173 raise InvalidAliasError("The name %s can't be aliased "
174 174 "because it is a keyword or builtin." % name)
175 175 if not (isinstance(cmd, basestring)):
176 176 raise InvalidAliasError("An alias command must be a string, "
177 177 "got: %r" % cmd)
178 178 nargs = cmd.count('%s')
179 179 if nargs>0 and cmd.find('%l')>=0:
180 180 raise InvalidAliasError('The %s and %l specifiers are mutually '
181 181 'exclusive in alias definitions.')
182 182 return nargs
183 183
184 184 def call_alias(self, alias, rest=''):
185 185 """Call an alias given its name and the rest of the line."""
186 186 cmd = self.transform_alias(alias, rest)
187 187 try:
188 188 self.shell.system(cmd)
189 189 except:
190 190 self.shell.showtraceback()
191 191
192 192 def transform_alias(self, alias,rest=''):
193 193 """Transform alias to system command string."""
194 194 nargs, cmd = self.alias_table[alias]
195 195
196 196 if ' ' in cmd and os.path.isfile(cmd):
197 197 cmd = '"%s"' % cmd
198 198
199 199 # Expand the %l special to be the user's input line
200 200 if cmd.find('%l') >= 0:
201 201 cmd = cmd.replace('%l', rest)
202 202 rest = ''
203 203 if nargs==0:
204 204 # Simple, argument-less aliases
205 205 cmd = '%s %s' % (cmd, rest)
206 206 else:
207 207 # Handle aliases with positional arguments
208 208 args = rest.split(None, nargs)
209 209 if len(args) < nargs:
210 210 raise AliasError('Alias <%s> requires %s arguments, %s given.' %
211 211 (alias, nargs, len(args)))
212 212 cmd = '%s %s' % (cmd % tuple(args[:nargs]),' '.join(args[nargs:]))
213 213 return cmd
214 214
215 215 def expand_alias(self, line):
216 216 """ Expand an alias in the command line
217 217
218 218 Returns the provided command line, possibly with the first word
219 219 (command) translated according to alias expansion rules.
220 220
221 221 [ipython]|16> _ip.expand_aliases("np myfile.txt")
222 222 <16> 'q:/opt/np/notepad++.exe myfile.txt'
223 223 """
224 224
225 225 pre,_,fn,rest = split_user_input(line)
226 226 res = pre + self.expand_aliases(fn, rest)
227 227 return res
228 228
229 229 def expand_aliases(self, fn, rest):
230 230 """Expand multiple levels of aliases:
231 231
232 232 if:
233 233
234 234 alias foo bar /tmp
235 235 alias baz foo
236 236
237 237 then:
238 238
239 239 baz huhhahhei -> bar /tmp huhhahhei
240 240 """
241 241 line = fn + " " + rest
242 242
243 243 done = set()
244 244 while 1:
245 245 pre,_,fn,rest = split_user_input(line, shell_line_split)
246 246 if fn in self.alias_table:
247 247 if fn in done:
248 248 warn("Cyclic alias definition, repeated '%s'" % fn)
249 249 return ""
250 250 done.add(fn)
251 251
252 252 l2 = self.transform_alias(fn, rest)
253 253 if l2 == line:
254 254 break
255 255 # ls -> ls -F should not recurse forever
256 256 if l2.split(None,1)[0] == line.split(None,1)[0]:
257 257 line = l2
258 258 break
259 259 line=l2
260 260 else:
261 261 break
262 262
263 263 return line
@@ -1,70 +1,70 b''
1 1 # encoding: utf-8
2 2 """
3 3 Autocall capabilities for IPython.core.
4 4
5 5 Authors:
6 6
7 7 * Brian Granger
8 8 * Fernando Perez
9 9 * Thomas Kluyver
10 10
11 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 18 # Distributed under the terms of the BSD License. The full license is in
19 19 # the file COPYING, distributed as part of this software.
20 20 #-----------------------------------------------------------------------------
21 21
22 22 #-----------------------------------------------------------------------------
23 23 # Imports
24 24 #-----------------------------------------------------------------------------
25 25
26 26
27 27 #-----------------------------------------------------------------------------
28 28 # Code
29 29 #-----------------------------------------------------------------------------
30 30
31 31 class IPyAutocall(object):
32 32 """ Instances of this class are always autocalled
33 33
34 34 This happens regardless of 'autocall' variable state. Use this to
35 35 develop macro-like mechanisms.
36 36 """
37 37 _ip = None
38 38 rewrite = True
39 39 def __init__(self, ip=None):
40 40 self._ip = ip
41 41
42 42 def set_ip(self, ip):
43 43 """ Will be used to set _ip point to current ipython instance b/f call
44 44
45 45 Override this method if you don't want this to happen.
46 46
47 47 """
48 48 self._ip = ip
49 49
50 50
51 51 class ExitAutocall(IPyAutocall):
52 52 """An autocallable object which will be added to the user namespace so that
53 53 exit, exit(), quit or quit() are all valid ways to close the shell."""
54 54 rewrite = False
55 55
56 56 def __call__(self):
57 57 self._ip.ask_exit()
58 58
59 59 class ZMQExitAutocall(ExitAutocall):
60 60 """Exit IPython. Autocallable, so it needn't be explicitly called.
61 61
62 62 Parameters
63 63 ----------
64 64 keep_kernel : bool
65 65 If True, leave the kernel alive. Otherwise, tell the kernel to exit too
66 66 (default).
67 67 """
68 68 def __call__(self, keep_kernel=False):
69 69 self._ip.keepkernel_on_exit = keep_kernel
70 70 self._ip.ask_exit()
@@ -1,128 +1,128 b''
1 1 """
2 2 A context manager for managing things injected into :mod:`__builtin__`.
3 3
4 4 Authors:
5 5
6 6 * Brian Granger
7 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 12 # Distributed under the terms of the BSD License.
13 13 #
14 14 # Complete license in the file COPYING.txt, distributed with this software.
15 15 #-----------------------------------------------------------------------------
16 16
17 17 #-----------------------------------------------------------------------------
18 18 # Imports
19 19 #-----------------------------------------------------------------------------
20 20
21 21 import __builtin__
22 22
23 23 from IPython.config.configurable import Configurable
24 24
25 25 from IPython.utils.traitlets import Instance
26 26
27 27 #-----------------------------------------------------------------------------
28 28 # Classes and functions
29 29 #-----------------------------------------------------------------------------
30 30
31 31 class __BuiltinUndefined(object): pass
32 32 BuiltinUndefined = __BuiltinUndefined()
33 33
34 34 class __HideBuiltin(object): pass
35 35 HideBuiltin = __HideBuiltin()
36 36
37 37
38 38 class BuiltinTrap(Configurable):
39 39
40 40 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
41 41
42 42 def __init__(self, shell=None):
43 43 super(BuiltinTrap, self).__init__(shell=shell, config=None)
44 44 self._orig_builtins = {}
45 45 # We define this to track if a single BuiltinTrap is nested.
46 46 # Only turn off the trap when the outermost call to __exit__ is made.
47 47 self._nested_level = 0
48 48 self.shell = shell
49 49 # builtins we always add - if set to HideBuiltin, they will just
50 50 # be removed instead of being replaced by something else
51 51 self.auto_builtins = {'exit': HideBuiltin,
52 52 'quit': HideBuiltin,
53 53 'get_ipython': self.shell.get_ipython,
54 54 }
55 55 # Recursive reload function
56 56 try:
57 57 from IPython.lib import deepreload
58 58 if self.shell.deep_reload:
59 59 self.auto_builtins['reload'] = deepreload.reload
60 60 else:
61 61 self.auto_builtins['dreload']= deepreload.reload
62 62 except ImportError:
63 63 pass
64 64
65 65 def __enter__(self):
66 66 if self._nested_level == 0:
67 67 self.activate()
68 68 self._nested_level += 1
69 69 # I return self, so callers can use add_builtin in a with clause.
70 70 return self
71 71
72 72 def __exit__(self, type, value, traceback):
73 73 if self._nested_level == 1:
74 74 self.deactivate()
75 75 self._nested_level -= 1
76 76 # Returning False will cause exceptions to propagate
77 77 return False
78 78
79 79 def add_builtin(self, key, value):
80 80 """Add a builtin and save the original."""
81 81 bdict = __builtin__.__dict__
82 82 orig = bdict.get(key, BuiltinUndefined)
83 83 if value is HideBuiltin:
84 84 if orig is not BuiltinUndefined: #same as 'key in bdict'
85 85 self._orig_builtins[key] = orig
86 86 del bdict[key]
87 87 else:
88 88 self._orig_builtins[key] = orig
89 89 bdict[key] = value
90 90
91 91 def remove_builtin(self, key):
92 92 """Remove an added builtin and re-set the original."""
93 93 try:
94 94 orig = self._orig_builtins.pop(key)
95 95 except KeyError:
96 96 pass
97 97 else:
98 98 if orig is BuiltinUndefined:
99 99 del __builtin__.__dict__[key]
100 100 else:
101 101 __builtin__.__dict__[key] = orig
102 102
103 103 def activate(self):
104 104 """Store ipython references in the __builtin__ namespace."""
105 105
106 106 add_builtin = self.add_builtin
107 107 for name, func in self.auto_builtins.iteritems():
108 108 add_builtin(name, func)
109 109
110 110 # Keep in the builtins a flag for when IPython is active. We set it
111 111 # with setdefault so that multiple nested IPythons don't clobber one
112 112 # another.
113 113 __builtin__.__dict__.setdefault('__IPYTHON__active', 0)
114 114
115 115 def deactivate(self):
116 116 """Remove any builtins which might have been added by add_builtins, or
117 117 restore overwritten ones to their previous values."""
118 118 # Note: must iterate over a static keys() list because we'll be
119 119 # mutating the dict itself
120 120 remove_builtin = self.remove_builtin
121 121 for key in self._orig_builtins.keys():
122 122 remove_builtin(key)
123 123 self._orig_builtins.clear()
124 124 self._builtins_added = False
125 125 try:
126 126 del __builtin__.__dict__['__IPYTHON__active']
127 127 except KeyError:
128 128 pass
@@ -1,131 +1,131 b''
1 1 """Compiler tools with improved interactive support.
2 2
3 3 Provides compilation machinery similar to codeop, but with caching support so
4 4 we can provide interactive tracebacks.
5 5
6 6 Authors
7 7 -------
8 8 * Robert Kern
9 9 * Fernando Perez
10 10 * Thomas Kluyver
11 11 """
12 12
13 13 # Note: though it might be more natural to name this module 'compiler', that
14 14 # name is in the stdlib and name collisions with the stdlib tend to produce
15 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 20 # Distributed under the terms of the BSD License.
21 21 #
22 22 # The full license is in the file COPYING.txt, distributed with this software.
23 23 #-----------------------------------------------------------------------------
24 24
25 25 #-----------------------------------------------------------------------------
26 26 # Imports
27 27 #-----------------------------------------------------------------------------
28 28 from __future__ import print_function
29 29
30 30 # Stdlib imports
31 31 from ast import PyCF_ONLY_AST
32 32 import codeop
33 33 import hashlib
34 34 import linecache
35 35 import time
36 36
37 37 #-----------------------------------------------------------------------------
38 38 # Local utilities
39 39 #-----------------------------------------------------------------------------
40 40
41 41 def code_name(code, number=0):
42 42 """ Compute a (probably) unique name for code for caching.
43 43
44 44 This now expects code to be unicode.
45 45 """
46 46 hash_digest = hashlib.md5(code.encode("utf-8")).hexdigest()
47 47 # Include the number and 12 characters of the hash in the name. It's
48 48 # pretty much impossible that in a single session we'll have collisions
49 49 # even with truncated hashes, and the full one makes tracebacks too long
50 50 return '<ipython-input-{0}-{1}>'.format(number, hash_digest[:12])
51 51
52 52 #-----------------------------------------------------------------------------
53 53 # Classes and functions
54 54 #-----------------------------------------------------------------------------
55 55
56 56 class CachingCompiler(codeop.Compile):
57 57 """A compiler that caches code compiled from interactive statements.
58 58 """
59 59
60 60 def __init__(self):
61 61 codeop.Compile.__init__(self)
62 62
63 63 # This is ugly, but it must be done this way to allow multiple
64 64 # simultaneous ipython instances to coexist. Since Python itself
65 65 # directly accesses the data structures in the linecache module, and
66 66 # the cache therein is global, we must work with that data structure.
67 67 # We must hold a reference to the original checkcache routine and call
68 68 # that in our own check_cache() below, but the special IPython cache
69 69 # must also be shared by all IPython instances. If we were to hold
70 70 # separate caches (one in each CachingCompiler instance), any call made
71 71 # by Python itself to linecache.checkcache() would obliterate the
72 72 # cached data from the other IPython instances.
73 73 if not hasattr(linecache, '_ipython_cache'):
74 74 linecache._ipython_cache = {}
75 75 if not hasattr(linecache, '_checkcache_ori'):
76 76 linecache._checkcache_ori = linecache.checkcache
77 77 # Now, we must monkeypatch the linecache directly so that parts of the
78 78 # stdlib that call it outside our control go through our codepath
79 79 # (otherwise we'd lose our tracebacks).
80 80 linecache.checkcache = self.check_cache
81 81
82 82 def ast_parse(self, source, filename='<unknown>', symbol='exec'):
83 83 """Parse code to an AST with the current compiler flags active.
84 84
85 85 Arguments are exactly the same as ast.parse (in the standard library),
86 86 and are passed to the built-in compile function."""
87 87 return compile(source, filename, symbol, self.flags | PyCF_ONLY_AST, 1)
88 88
89 89 def reset_compiler_flags(self):
90 90 """Reset compiler flags to default state."""
91 91 # This value is copied from codeop.Compile.__init__, so if that ever
92 92 # changes, it will need to be updated.
93 93 self.flags = codeop.PyCF_DONT_IMPLY_DEDENT
94 94
95 95 @property
96 96 def compiler_flags(self):
97 97 """Flags currently active in the compilation process.
98 98 """
99 99 return self.flags
100 100
101 101 def cache(self, code, number=0):
102 102 """Make a name for a block of code, and cache the code.
103 103
104 104 Parameters
105 105 ----------
106 106 code : str
107 107 The Python source code to cache.
108 108 number : int
109 109 A number which forms part of the code's name. Used for the execution
110 110 counter.
111 111
112 112 Returns
113 113 -------
114 114 The name of the cached code (as a string). Pass this as the filename
115 115 argument to compilation, so that tracebacks are correctly hooked up.
116 116 """
117 117 name = code_name(code, number)
118 118 entry = (len(code), time.time(),
119 119 [line+'\n' for line in code.splitlines()], name)
120 120 linecache.cache[name] = entry
121 121 linecache._ipython_cache[name] = entry
122 122 return name
123 123
124 124 def check_cache(self, *args):
125 125 """Call linecache.checkcache() safely protecting our cached values.
126 126 """
127 127 # First call the orignal checkcache as intended
128 128 linecache._checkcache_ori(*args)
129 129 # Then, update back the cache with our data, so that tracebacks related
130 130 # to our compiled codes can be produced.
131 131 linecache.cache.update(linecache._ipython_cache)
@@ -1,925 +1,925 b''
1 1 """Word completion for IPython.
2 2
3 3 This module is a fork of the rlcompleter module in the Python standard
4 4 library. The original enhancements made to rlcompleter have been sent
5 5 upstream and were accepted as of Python 2.3, but we need a lot more
6 6 functionality specific to IPython, so this module will continue to live as an
7 7 IPython-specific utility.
8 8
9 9 Original rlcompleter documentation:
10 10
11 11 This requires the latest extension to the readline module (the
12 12 completes keywords, built-ins and globals in __main__; when completing
13 13 NAME.NAME..., it evaluates (!) the expression up to the last dot and
14 14 completes its attributes.
15 15
16 16 It's very cool to do "import string" type "string.", hit the
17 17 completion key (twice), and see the list of names defined by the
18 18 string module!
19 19
20 20 Tip: to use the tab key as the completion key, call
21 21
22 22 readline.parse_and_bind("tab: complete")
23 23
24 24 Notes:
25 25
26 26 - Exceptions raised by the completer function are *ignored* (and
27 27 generally cause the completion to fail). This is a feature -- since
28 28 readline sets the tty device in raw (or cbreak) mode, printing a
29 29 traceback wouldn't work well without some complicated hoopla to save,
30 30 reset and restore the tty state.
31 31
32 32 - The evaluation of the NAME.NAME... form may cause arbitrary
33 33 application defined code to be executed if an object with a
34 34 __getattr__ hook is found. Since it is the responsibility of the
35 35 application (or the user) to enable this feature, I consider this an
36 36 acceptable risk. More complicated expressions (e.g. function calls or
37 37 indexing operations) are *not* evaluated.
38 38
39 39 - GNU readline is also used by the built-in functions input() and
40 40 raw_input(), and thus these also benefit/suffer from the completer
41 41 features. Clearly an interactive application can benefit by
42 42 specifying its own completer function and using raw_input() for all
43 43 its input.
44 44
45 45 - When the original stdin is not a tty device, GNU readline is never
46 46 used, and this module (and the readline module) are silently inactive.
47 47 """
48 48
49 49 #*****************************************************************************
50 50 #
51 51 # Since this file is essentially a minimally modified copy of the rlcompleter
52 52 # module which is part of the standard Python distribution, I assume that the
53 53 # proper procedure is to maintain its copyright as belonging to the Python
54 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 57 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
58 58 # Copyright (C) 2001 Python Software Foundation, www.python.org
59 59 #
60 60 # Distributed under the terms of the BSD License. The full license is in
61 61 # the file COPYING, distributed as part of this software.
62 62 #
63 63 #*****************************************************************************
64 64 from __future__ import print_function
65 65
66 66 #-----------------------------------------------------------------------------
67 67 # Imports
68 68 #-----------------------------------------------------------------------------
69 69
70 70 import __builtin__
71 71 import __main__
72 72 import glob
73 73 import inspect
74 74 import itertools
75 75 import keyword
76 76 import os
77 77 import re
78 78 import shlex
79 79 import sys
80 80
81 81 from IPython.config.configurable import Configurable
82 82 from IPython.core.error import TryNext
83 83 from IPython.core.prefilter import ESC_MAGIC
84 84 from IPython.utils import generics
85 85 from IPython.utils import io
86 86 from IPython.utils.dir2 import dir2
87 87 from IPython.utils.process import arg_split
88 88 from IPython.utils.traitlets import CBool, Enum
89 89
90 90 #-----------------------------------------------------------------------------
91 91 # Globals
92 92 #-----------------------------------------------------------------------------
93 93
94 94 # Public API
95 95 __all__ = ['Completer','IPCompleter']
96 96
97 97 if sys.platform == 'win32':
98 98 PROTECTABLES = ' '
99 99 else:
100 100 PROTECTABLES = ' ()[]{}?=\\|;:\'#*"^&'
101 101
102 102 #-----------------------------------------------------------------------------
103 103 # Main functions and classes
104 104 #-----------------------------------------------------------------------------
105 105
106 106 def has_open_quotes(s):
107 107 """Return whether a string has open quotes.
108 108
109 109 This simply counts whether the number of quote characters of either type in
110 110 the string is odd.
111 111
112 112 Returns
113 113 -------
114 114 If there is an open quote, the quote character is returned. Else, return
115 115 False.
116 116 """
117 117 # We check " first, then ', so complex cases with nested quotes will get
118 118 # the " to take precedence.
119 119 if s.count('"') % 2:
120 120 return '"'
121 121 elif s.count("'") % 2:
122 122 return "'"
123 123 else:
124 124 return False
125 125
126 126
127 127 def protect_filename(s):
128 128 """Escape a string to protect certain characters."""
129 129
130 130 return "".join([(ch in PROTECTABLES and '\\' + ch or ch)
131 131 for ch in s])
132 132
133 133
134 134 def mark_dirs(matches):
135 135 """Mark directories in input list by appending '/' to their names."""
136 136 out = []
137 137 isdir = os.path.isdir
138 138 for x in matches:
139 139 if isdir(x):
140 140 out.append(x+'/')
141 141 else:
142 142 out.append(x)
143 143 return out
144 144
145 145
146 146 def expand_user(path):
147 147 """Expand '~'-style usernames in strings.
148 148
149 149 This is similar to :func:`os.path.expanduser`, but it computes and returns
150 150 extra information that will be useful if the input was being used in
151 151 computing completions, and you wish to return the completions with the
152 152 original '~' instead of its expanded value.
153 153
154 154 Parameters
155 155 ----------
156 156 path : str
157 157 String to be expanded. If no ~ is present, the output is the same as the
158 158 input.
159 159
160 160 Returns
161 161 -------
162 162 newpath : str
163 163 Result of ~ expansion in the input path.
164 164 tilde_expand : bool
165 165 Whether any expansion was performed or not.
166 166 tilde_val : str
167 167 The value that ~ was replaced with.
168 168 """
169 169 # Default values
170 170 tilde_expand = False
171 171 tilde_val = ''
172 172 newpath = path
173 173
174 174 if path.startswith('~'):
175 175 tilde_expand = True
176 176 rest = len(path)-1
177 177 newpath = os.path.expanduser(path)
178 178 if rest:
179 179 tilde_val = newpath[:-rest]
180 180 else:
181 181 tilde_val = newpath
182 182
183 183 return newpath, tilde_expand, tilde_val
184 184
185 185
186 186 def compress_user(path, tilde_expand, tilde_val):
187 187 """Does the opposite of expand_user, with its outputs.
188 188 """
189 189 if tilde_expand:
190 190 return path.replace(tilde_val, '~')
191 191 else:
192 192 return path
193 193
194 194
195 195 def single_dir_expand(matches):
196 196 "Recursively expand match lists containing a single dir."
197 197
198 198 if len(matches) == 1 and os.path.isdir(matches[0]):
199 199 # Takes care of links to directories also. Use '/'
200 200 # explicitly, even under Windows, so that name completions
201 201 # don't end up escaped.
202 202 d = matches[0]
203 203 if d[-1] in ['/','\\']:
204 204 d = d[:-1]
205 205
206 206 subdirs = os.listdir(d)
207 207 if subdirs:
208 208 matches = [ (d + '/' + p) for p in subdirs]
209 209 return single_dir_expand(matches)
210 210 else:
211 211 return matches
212 212 else:
213 213 return matches
214 214
215 215
216 216 class Bunch(object): pass
217 217
218 218 DELIMS = ' \t\n`!@#$^&*()=+[{]}\\|;:\'",<>?'
219 219 GREEDY_DELIMS = ' \r\n'
220 220
221 221 class CompletionSplitter(object):
222 222 """An object to split an input line in a manner similar to readline.
223 223
224 224 By having our own implementation, we can expose readline-like completion in
225 225 a uniform manner to all frontends. This object only needs to be given the
226 226 line of text to be split and the cursor position on said line, and it
227 227 returns the 'word' to be completed on at the cursor after splitting the
228 228 entire line.
229 229
230 230 What characters are used as splitting delimiters can be controlled by
231 231 setting the `delims` attribute (this is a property that internally
232 232 automatically builds the necessary """
233 233
234 234 # Private interface
235 235
236 236 # A string of delimiter characters. The default value makes sense for
237 237 # IPython's most typical usage patterns.
238 238 _delims = DELIMS
239 239
240 240 # The expression (a normal string) to be compiled into a regular expression
241 241 # for actual splitting. We store it as an attribute mostly for ease of
242 242 # debugging, since this type of code can be so tricky to debug.
243 243 _delim_expr = None
244 244
245 245 # The regular expression that does the actual splitting
246 246 _delim_re = None
247 247
248 248 def __init__(self, delims=None):
249 249 delims = CompletionSplitter._delims if delims is None else delims
250 250 self.set_delims(delims)
251 251
252 252 def set_delims(self, delims):
253 253 """Set the delimiters for line splitting."""
254 254 expr = '[' + ''.join('\\'+ c for c in delims) + ']'
255 255 self._delim_re = re.compile(expr)
256 256 self._delims = delims
257 257 self._delim_expr = expr
258 258
259 259 def get_delims(self):
260 260 """Return the string of delimiter characters."""
261 261 return self._delims
262 262
263 263 def split_line(self, line, cursor_pos=None):
264 264 """Split a line of text with a cursor at the given position.
265 265 """
266 266 l = line if cursor_pos is None else line[:cursor_pos]
267 267 return self._delim_re.split(l)[-1]
268 268
269 269
270 270 class Completer(Configurable):
271 271
272 272 greedy = CBool(False, config=True,
273 273 help="""Activate greedy completion
274 274
275 275 This will enable completion on elements of lists, results of function calls, etc.,
276 276 but can be unsafe because the code is actually evaluated on TAB.
277 277 """
278 278 )
279 279
280 280
281 281 def __init__(self, namespace=None, global_namespace=None, config=None, **kwargs):
282 282 """Create a new completer for the command line.
283 283
284 284 Completer(namespace=ns,global_namespace=ns2) -> completer instance.
285 285
286 286 If unspecified, the default namespace where completions are performed
287 287 is __main__ (technically, __main__.__dict__). Namespaces should be
288 288 given as dictionaries.
289 289
290 290 An optional second namespace can be given. This allows the completer
291 291 to handle cases where both the local and global scopes need to be
292 292 distinguished.
293 293
294 294 Completer instances should be used as the completion mechanism of
295 295 readline via the set_completer() call:
296 296
297 297 readline.set_completer(Completer(my_namespace).complete)
298 298 """
299 299
300 300 # Don't bind to namespace quite yet, but flag whether the user wants a
301 301 # specific namespace or to use __main__.__dict__. This will allow us
302 302 # to bind to __main__.__dict__ at completion time, not now.
303 303 if namespace is None:
304 304 self.use_main_ns = 1
305 305 else:
306 306 self.use_main_ns = 0
307 307 self.namespace = namespace
308 308
309 309 # The global namespace, if given, can be bound directly
310 310 if global_namespace is None:
311 311 self.global_namespace = {}
312 312 else:
313 313 self.global_namespace = global_namespace
314 314
315 315 super(Completer, self).__init__(config=config, **kwargs)
316 316
317 317 def complete(self, text, state):
318 318 """Return the next possible completion for 'text'.
319 319
320 320 This is called successively with state == 0, 1, 2, ... until it
321 321 returns None. The completion should begin with 'text'.
322 322
323 323 """
324 324 if self.use_main_ns:
325 325 self.namespace = __main__.__dict__
326 326
327 327 if state == 0:
328 328 if "." in text:
329 329 self.matches = self.attr_matches(text)
330 330 else:
331 331 self.matches = self.global_matches(text)
332 332 try:
333 333 return self.matches[state]
334 334 except IndexError:
335 335 return None
336 336
337 337 def global_matches(self, text):
338 338 """Compute matches when text is a simple name.
339 339
340 340 Return a list of all keywords, built-in functions and names currently
341 341 defined in self.namespace or self.global_namespace that match.
342 342
343 343 """
344 344 #print 'Completer->global_matches, txt=%r' % text # dbg
345 345 matches = []
346 346 match_append = matches.append
347 347 n = len(text)
348 348 for lst in [keyword.kwlist,
349 349 __builtin__.__dict__.keys(),
350 350 self.namespace.keys(),
351 351 self.global_namespace.keys()]:
352 352 for word in lst:
353 353 if word[:n] == text and word != "__builtins__":
354 354 match_append(word)
355 355 return matches
356 356
357 357 def attr_matches(self, text):
358 358 """Compute matches when text contains a dot.
359 359
360 360 Assuming the text is of the form NAME.NAME....[NAME], and is
361 361 evaluatable in self.namespace or self.global_namespace, it will be
362 362 evaluated and its attributes (as revealed by dir()) are used as
363 363 possible completions. (For class instances, class members are are
364 364 also considered.)
365 365
366 366 WARNING: this can still invoke arbitrary C code, if an object
367 367 with a __getattr__ hook is evaluated.
368 368
369 369 """
370 370
371 371 #io.rprint('Completer->attr_matches, txt=%r' % text) # dbg
372 372 # Another option, seems to work great. Catches things like ''.<tab>
373 373 m = re.match(r"(\S+(\.\w+)*)\.(\w*)$", text)
374 374
375 375 if m:
376 376 expr, attr = m.group(1, 3)
377 377 elif self.greedy:
378 378 m2 = re.match(r"(.+)\.(\w*)$", self.line_buffer)
379 379 if not m2:
380 380 return []
381 381 expr, attr = m2.group(1,2)
382 382 else:
383 383 return []
384 384
385 385 try:
386 386 obj = eval(expr, self.namespace)
387 387 except:
388 388 try:
389 389 obj = eval(expr, self.global_namespace)
390 390 except:
391 391 return []
392 392
393 393 words = dir2(obj)
394 394
395 395 try:
396 396 words = generics.complete_object(obj, words)
397 397 except TryNext:
398 398 pass
399 399 except Exception:
400 400 # Silence errors from completion function
401 401 #raise # dbg
402 402 pass
403 403 # Build match list to return
404 404 n = len(attr)
405 405 res = ["%s.%s" % (expr, w) for w in words if w[:n] == attr ]
406 406 return res
407 407
408 408
409 409 class IPCompleter(Completer):
410 410 """Extension of the completer class with IPython-specific features"""
411 411
412 412 def _greedy_changed(self, name, old, new):
413 413 """update the splitter and readline delims when greedy is changed"""
414 414 if new:
415 415 self.splitter.set_delims(GREEDY_DELIMS)
416 416 else:
417 417 self.splitter.set_delims(DELIMS)
418 418
419 419 if self.readline:
420 420 self.readline.set_completer_delims(self.splitter.get_delims())
421 421
422 422 merge_completions = CBool(True, config=True,
423 423 help="""Whether to merge completion results into a single list
424 424
425 425 If False, only the completion results from the first non-empty
426 426 completer will be returned.
427 427 """
428 428 )
429 429 omit__names = Enum((0,1,2), default_value=2, config=True,
430 430 help="""Instruct the completer to omit private method names
431 431
432 432 Specifically, when completing on ``object.<tab>``.
433 433
434 434 When 2 [default]: all names that start with '_' will be excluded.
435 435
436 436 When 1: all 'magic' names (``__foo__``) will be excluded.
437 437
438 438 When 0: nothing will be excluded.
439 439 """
440 440 )
441 441
442 442 def __init__(self, shell=None, namespace=None, global_namespace=None,
443 443 alias_table=None, use_readline=True,
444 444 config=None, **kwargs):
445 445 """IPCompleter() -> completer
446 446
447 447 Return a completer object suitable for use by the readline library
448 448 via readline.set_completer().
449 449
450 450 Inputs:
451 451
452 452 - shell: a pointer to the ipython shell itself. This is needed
453 453 because this completer knows about magic functions, and those can
454 454 only be accessed via the ipython instance.
455 455
456 456 - namespace: an optional dict where completions are performed.
457 457
458 458 - global_namespace: secondary optional dict for completions, to
459 459 handle cases (such as IPython embedded inside functions) where
460 460 both Python scopes are visible.
461 461
462 462 - If alias_table is supplied, it should be a dictionary of aliases
463 463 to complete.
464 464
465 465 use_readline : bool, optional
466 466 If true, use the readline library. This completer can still function
467 467 without readline, though in that case callers must provide some extra
468 468 information on each call about the current line."""
469 469
470 470 self.magic_escape = ESC_MAGIC
471 471 self.splitter = CompletionSplitter()
472 472
473 473 # Readline configuration, only used by the rlcompleter method.
474 474 if use_readline:
475 475 # We store the right version of readline so that later code
476 476 import IPython.utils.rlineimpl as readline
477 477 self.readline = readline
478 478 else:
479 479 self.readline = None
480 480
481 481 # _greedy_changed() depends on splitter and readline being defined:
482 482 Completer.__init__(self, namespace=namespace, global_namespace=global_namespace,
483 483 config=config, **kwargs)
484 484
485 485 # List where completion matches will be stored
486 486 self.matches = []
487 487 self.shell = shell.shell
488 488 if alias_table is None:
489 489 alias_table = {}
490 490 self.alias_table = alias_table
491 491 # Regexp to split filenames with spaces in them
492 492 self.space_name_re = re.compile(r'([^\\] )')
493 493 # Hold a local ref. to glob.glob for speed
494 494 self.glob = glob.glob
495 495
496 496 # Determine if we are running on 'dumb' terminals, like (X)Emacs
497 497 # buffers, to avoid completion problems.
498 498 term = os.environ.get('TERM','xterm')
499 499 self.dumb_terminal = term in ['dumb','emacs']
500 500
501 501 # Special handling of backslashes needed in win32 platforms
502 502 if sys.platform == "win32":
503 503 self.clean_glob = self._clean_glob_win32
504 504 else:
505 505 self.clean_glob = self._clean_glob
506 506
507 507 # All active matcher routines for completion
508 508 self.matchers = [self.python_matches,
509 509 self.file_matches,
510 510 self.magic_matches,
511 511 self.alias_matches,
512 512 self.python_func_kw_matches,
513 513 ]
514 514
515 515 def all_completions(self, text):
516 516 """
517 517 Wrapper around the complete method for the benefit of emacs
518 518 and pydb.
519 519 """
520 520 return self.complete(text)[1]
521 521
522 522 def _clean_glob(self,text):
523 523 return self.glob("%s*" % text)
524 524
525 525 def _clean_glob_win32(self,text):
526 526 return [f.replace("\\","/")
527 527 for f in self.glob("%s*" % text)]
528 528
529 529 def file_matches(self, text):
530 530 """Match filenames, expanding ~USER type strings.
531 531
532 532 Most of the seemingly convoluted logic in this completer is an
533 533 attempt to handle filenames with spaces in them. And yet it's not
534 534 quite perfect, because Python's readline doesn't expose all of the
535 535 GNU readline details needed for this to be done correctly.
536 536
537 537 For a filename with a space in it, the printed completions will be
538 538 only the parts after what's already been typed (instead of the
539 539 full completions, as is normally done). I don't think with the
540 540 current (as of Python 2.3) Python readline it's possible to do
541 541 better."""
542 542
543 543 #io.rprint('Completer->file_matches: <%r>' % text) # dbg
544 544
545 545 # chars that require escaping with backslash - i.e. chars
546 546 # that readline treats incorrectly as delimiters, but we
547 547 # don't want to treat as delimiters in filename matching
548 548 # when escaped with backslash
549 549 if text.startswith('!'):
550 550 text = text[1:]
551 551 text_prefix = '!'
552 552 else:
553 553 text_prefix = ''
554 554
555 555 text_until_cursor = self.text_until_cursor
556 556 # track strings with open quotes
557 557 open_quotes = has_open_quotes(text_until_cursor)
558 558
559 559 if '(' in text_until_cursor or '[' in text_until_cursor:
560 560 lsplit = text
561 561 else:
562 562 try:
563 563 # arg_split ~ shlex.split, but with unicode bugs fixed by us
564 564 lsplit = arg_split(text_until_cursor)[-1]
565 565 except ValueError:
566 566 # typically an unmatched ", or backslash without escaped char.
567 567 if open_quotes:
568 568 lsplit = text_until_cursor.split(open_quotes)[-1]
569 569 else:
570 570 return []
571 571 except IndexError:
572 572 # tab pressed on empty line
573 573 lsplit = ""
574 574
575 575 if not open_quotes and lsplit != protect_filename(lsplit):
576 576 # if protectables are found, do matching on the whole escaped name
577 577 has_protectables = True
578 578 text0,text = text,lsplit
579 579 else:
580 580 has_protectables = False
581 581 text = os.path.expanduser(text)
582 582
583 583 if text == "":
584 584 return [text_prefix + protect_filename(f) for f in self.glob("*")]
585 585
586 586 # Compute the matches from the filesystem
587 587 m0 = self.clean_glob(text.replace('\\',''))
588 588
589 589 if has_protectables:
590 590 # If we had protectables, we need to revert our changes to the
591 591 # beginning of filename so that we don't double-write the part
592 592 # of the filename we have so far
593 593 len_lsplit = len(lsplit)
594 594 matches = [text_prefix + text0 +
595 595 protect_filename(f[len_lsplit:]) for f in m0]
596 596 else:
597 597 if open_quotes:
598 598 # if we have a string with an open quote, we don't need to
599 599 # protect the names at all (and we _shouldn't_, as it
600 600 # would cause bugs when the filesystem call is made).
601 601 matches = m0
602 602 else:
603 603 matches = [text_prefix +
604 604 protect_filename(f) for f in m0]
605 605
606 606 #io.rprint('mm', matches) # dbg
607 607 return mark_dirs(matches)
608 608
609 609 def magic_matches(self, text):
610 610 """Match magics"""
611 611 #print 'Completer->magic_matches:',text,'lb',self.text_until_cursor # dbg
612 612 # Get all shell magics now rather than statically, so magics loaded at
613 613 # runtime show up too
614 614 magics = self.shell.lsmagic()
615 615 pre = self.magic_escape
616 616 baretext = text.lstrip(pre)
617 617 return [ pre+m for m in magics if m.startswith(baretext)]
618 618
619 619 def alias_matches(self, text):
620 620 """Match internal system aliases"""
621 621 #print 'Completer->alias_matches:',text,'lb',self.text_until_cursor # dbg
622 622
623 623 # if we are not in the first 'item', alias matching
624 624 # doesn't make sense - unless we are starting with 'sudo' command.
625 625 main_text = self.text_until_cursor.lstrip()
626 626 if ' ' in main_text and not main_text.startswith('sudo'):
627 627 return []
628 628 text = os.path.expanduser(text)
629 629 aliases = self.alias_table.keys()
630 630 if text == '':
631 631 return aliases
632 632 else:
633 633 return [a for a in aliases if a.startswith(text)]
634 634
635 635 def python_matches(self,text):
636 636 """Match attributes or global python names"""
637 637
638 638 #io.rprint('Completer->python_matches, txt=%r' % text) # dbg
639 639 if "." in text:
640 640 try:
641 641 matches = self.attr_matches(text)
642 642 if text.endswith('.') and self.omit__names:
643 643 if self.omit__names == 1:
644 644 # true if txt is _not_ a __ name, false otherwise:
645 645 no__name = (lambda txt:
646 646 re.match(r'.*\.__.*?__',txt) is None)
647 647 else:
648 648 # true if txt is _not_ a _ name, false otherwise:
649 649 no__name = (lambda txt:
650 650 re.match(r'.*\._.*?',txt) is None)
651 651 matches = filter(no__name, matches)
652 652 except NameError:
653 653 # catches <undefined attributes>.<tab>
654 654 matches = []
655 655 else:
656 656 matches = self.global_matches(text)
657 657
658 658 return matches
659 659
660 660 def _default_arguments(self, obj):
661 661 """Return the list of default arguments of obj if it is callable,
662 662 or empty list otherwise."""
663 663
664 664 if not (inspect.isfunction(obj) or inspect.ismethod(obj)):
665 665 # for classes, check for __init__,__new__
666 666 if inspect.isclass(obj):
667 667 obj = (getattr(obj,'__init__',None) or
668 668 getattr(obj,'__new__',None))
669 669 # for all others, check if they are __call__able
670 670 elif hasattr(obj, '__call__'):
671 671 obj = obj.__call__
672 672 # XXX: is there a way to handle the builtins ?
673 673 try:
674 674 args,_,_1,defaults = inspect.getargspec(obj)
675 675 if defaults:
676 676 return args[-len(defaults):]
677 677 except TypeError: pass
678 678 return []
679 679
680 680 def python_func_kw_matches(self,text):
681 681 """Match named parameters (kwargs) of the last open function"""
682 682
683 683 if "." in text: # a parameter cannot be dotted
684 684 return []
685 685 try: regexp = self.__funcParamsRegex
686 686 except AttributeError:
687 687 regexp = self.__funcParamsRegex = re.compile(r'''
688 688 '.*?' | # single quoted strings or
689 689 ".*?" | # double quoted strings or
690 690 \w+ | # identifier
691 691 \S # other characters
692 692 ''', re.VERBOSE | re.DOTALL)
693 693 # 1. find the nearest identifier that comes before an unclosed
694 694 # parenthesis e.g. for "foo (1+bar(x), pa", the candidate is "foo"
695 695 tokens = regexp.findall(self.line_buffer)
696 696 tokens.reverse()
697 697 iterTokens = iter(tokens); openPar = 0
698 698 for token in iterTokens:
699 699 if token == ')':
700 700 openPar -= 1
701 701 elif token == '(':
702 702 openPar += 1
703 703 if openPar > 0:
704 704 # found the last unclosed parenthesis
705 705 break
706 706 else:
707 707 return []
708 708 # 2. Concatenate dotted names ("foo.bar" for "foo.bar(x, pa" )
709 709 ids = []
710 710 isId = re.compile(r'\w+$').match
711 711 while True:
712 712 try:
713 713 ids.append(iterTokens.next())
714 714 if not isId(ids[-1]):
715 715 ids.pop(); break
716 716 if not iterTokens.next() == '.':
717 717 break
718 718 except StopIteration:
719 719 break
720 720 # lookup the candidate callable matches either using global_matches
721 721 # or attr_matches for dotted names
722 722 if len(ids) == 1:
723 723 callableMatches = self.global_matches(ids[0])
724 724 else:
725 725 callableMatches = self.attr_matches('.'.join(ids[::-1]))
726 726 argMatches = []
727 727 for callableMatch in callableMatches:
728 728 try:
729 729 namedArgs = self._default_arguments(eval(callableMatch,
730 730 self.namespace))
731 731 except:
732 732 continue
733 733 for namedArg in namedArgs:
734 734 if namedArg.startswith(text):
735 735 argMatches.append("%s=" %namedArg)
736 736 return argMatches
737 737
738 738 def dispatch_custom_completer(self, text):
739 739 #io.rprint("Custom! '%s' %s" % (text, self.custom_completers)) # dbg
740 740 line = self.line_buffer
741 741 if not line.strip():
742 742 return None
743 743
744 744 # Create a little structure to pass all the relevant information about
745 745 # the current completion to any custom completer.
746 746 event = Bunch()
747 747 event.line = line
748 748 event.symbol = text
749 749 cmd = line.split(None,1)[0]
750 750 event.command = cmd
751 751 event.text_until_cursor = self.text_until_cursor
752 752
753 753 #print "\ncustom:{%s]\n" % event # dbg
754 754
755 755 # for foo etc, try also to find completer for %foo
756 756 if not cmd.startswith(self.magic_escape):
757 757 try_magic = self.custom_completers.s_matches(
758 758 self.magic_escape + cmd)
759 759 else:
760 760 try_magic = []
761 761
762 762 for c in itertools.chain(self.custom_completers.s_matches(cmd),
763 763 try_magic,
764 764 self.custom_completers.flat_matches(self.text_until_cursor)):
765 765 #print "try",c # dbg
766 766 try:
767 767 res = c(event)
768 768 if res:
769 769 # first, try case sensitive match
770 770 withcase = [r for r in res if r.startswith(text)]
771 771 if withcase:
772 772 return withcase
773 773 # if none, then case insensitive ones are ok too
774 774 text_low = text.lower()
775 775 return [r for r in res if r.lower().startswith(text_low)]
776 776 except TryNext:
777 777 pass
778 778
779 779 return None
780 780
781 781 def complete(self, text=None, line_buffer=None, cursor_pos=None):
782 782 """Find completions for the given text and line context.
783 783
784 784 This is called successively with state == 0, 1, 2, ... until it
785 785 returns None. The completion should begin with 'text'.
786 786
787 787 Note that both the text and the line_buffer are optional, but at least
788 788 one of them must be given.
789 789
790 790 Parameters
791 791 ----------
792 792 text : string, optional
793 793 Text to perform the completion on. If not given, the line buffer
794 794 is split using the instance's CompletionSplitter object.
795 795
796 796 line_buffer : string, optional
797 797 If not given, the completer attempts to obtain the current line
798 798 buffer via readline. This keyword allows clients which are
799 799 requesting for text completions in non-readline contexts to inform
800 800 the completer of the entire text.
801 801
802 802 cursor_pos : int, optional
803 803 Index of the cursor in the full line buffer. Should be provided by
804 804 remote frontends where kernel has no access to frontend state.
805 805
806 806 Returns
807 807 -------
808 808 text : str
809 809 Text that was actually used in the completion.
810 810
811 811 matches : list
812 812 A list of completion matches.
813 813 """
814 814 #io.rprint('\nCOMP1 %r %r %r' % (text, line_buffer, cursor_pos)) # dbg
815 815
816 816 # if the cursor position isn't given, the only sane assumption we can
817 817 # make is that it's at the end of the line (the common case)
818 818 if cursor_pos is None:
819 819 cursor_pos = len(line_buffer) if text is None else len(text)
820 820
821 821 # if text is either None or an empty string, rely on the line buffer
822 822 if not text:
823 823 text = self.splitter.split_line(line_buffer, cursor_pos)
824 824
825 825 # If no line buffer is given, assume the input text is all there was
826 826 if line_buffer is None:
827 827 line_buffer = text
828 828
829 829 self.line_buffer = line_buffer
830 830 self.text_until_cursor = self.line_buffer[:cursor_pos]
831 831 #io.rprint('\nCOMP2 %r %r %r' % (text, line_buffer, cursor_pos)) # dbg
832 832
833 833 # Start with a clean slate of completions
834 834 self.matches[:] = []
835 835 custom_res = self.dispatch_custom_completer(text)
836 836 if custom_res is not None:
837 837 # did custom completers produce something?
838 838 self.matches = custom_res
839 839 else:
840 840 # Extend the list of completions with the results of each
841 841 # matcher, so we return results to the user from all
842 842 # namespaces.
843 843 if self.merge_completions:
844 844 self.matches = []
845 845 for matcher in self.matchers:
846 846 try:
847 847 self.matches.extend(matcher(text))
848 848 except:
849 849 # Show the ugly traceback if the matcher causes an
850 850 # exception, but do NOT crash the kernel!
851 851 sys.excepthook(*sys.exc_info())
852 852 else:
853 853 for matcher in self.matchers:
854 854 self.matches = matcher(text)
855 855 if self.matches:
856 856 break
857 857 # FIXME: we should extend our api to return a dict with completions for
858 858 # different types of objects. The rlcomplete() method could then
859 859 # simply collapse the dict into a list for readline, but we'd have
860 860 # richer completion semantics in other evironments.
861 861 self.matches = sorted(set(self.matches))
862 862 #io.rprint('COMP TEXT, MATCHES: %r, %r' % (text, self.matches)) # dbg
863 863 return text, self.matches
864 864
865 865 def rlcomplete(self, text, state):
866 866 """Return the state-th possible completion for 'text'.
867 867
868 868 This is called successively with state == 0, 1, 2, ... until it
869 869 returns None. The completion should begin with 'text'.
870 870
871 871 Parameters
872 872 ----------
873 873 text : string
874 874 Text to perform the completion on.
875 875
876 876 state : int
877 877 Counter used by readline.
878 878 """
879 879 if state==0:
880 880
881 881 self.line_buffer = line_buffer = self.readline.get_line_buffer()
882 882 cursor_pos = self.readline.get_endidx()
883 883
884 884 #io.rprint("\nRLCOMPLETE: %r %r %r" %
885 885 # (text, line_buffer, cursor_pos) ) # dbg
886 886
887 887 # if there is only a tab on a line with only whitespace, instead of
888 888 # the mostly useless 'do you want to see all million completions'
889 889 # message, just do the right thing and give the user his tab!
890 890 # Incidentally, this enables pasting of tabbed text from an editor
891 891 # (as long as autoindent is off).
892 892
893 893 # It should be noted that at least pyreadline still shows file
894 894 # completions - is there a way around it?
895 895
896 896 # don't apply this on 'dumb' terminals, such as emacs buffers, so
897 897 # we don't interfere with their own tab-completion mechanism.
898 898 if not (self.dumb_terminal or line_buffer.strip()):
899 899 self.readline.insert_text('\t')
900 900 sys.stdout.flush()
901 901 return None
902 902
903 903 # Note: debugging exceptions that may occur in completion is very
904 904 # tricky, because readline unconditionally silences them. So if
905 905 # during development you suspect a bug in the completion code, turn
906 906 # this flag on temporarily by uncommenting the second form (don't
907 907 # flip the value in the first line, as the '# dbg' marker can be
908 908 # automatically detected and is used elsewhere).
909 909 DEBUG = False
910 910 #DEBUG = True # dbg
911 911 if DEBUG:
912 912 try:
913 913 self.complete(text, line_buffer, cursor_pos)
914 914 except:
915 915 import traceback; traceback.print_exc()
916 916 else:
917 917 # The normal production version is here
918 918
919 919 # This method computes the self.matches array
920 920 self.complete(text, line_buffer, cursor_pos)
921 921
922 922 try:
923 923 return self.matches[state]
924 924 except IndexError:
925 925 return None
@@ -1,347 +1,347 b''
1 1 """Implementations for various useful completers.
2 2
3 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 8 # Distributed under the terms of the BSD License.
9 9 #
10 10 # The full license is in the file COPYING.txt, distributed with this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16 from __future__ import print_function
17 17
18 18 # Stdlib imports
19 19 import glob
20 20 import inspect
21 21 import os
22 22 import re
23 23 import shlex
24 24 import sys
25 25
26 26 # Third-party imports
27 27 from time import time
28 28 from zipimport import zipimporter
29 29
30 30 # Our own imports
31 31 from IPython.core.completer import expand_user, compress_user
32 32 from IPython.core.error import TryNext
33 33 from IPython.utils import py3compat
34 34
35 35 # FIXME: this should be pulled in with the right call via the component system
36 36 from IPython.core.ipapi import get as get_ipython
37 37
38 38 #-----------------------------------------------------------------------------
39 39 # Globals and constants
40 40 #-----------------------------------------------------------------------------
41 41
42 42 # Time in seconds after which the rootmodules will be stored permanently in the
43 43 # ipython ip.db database (kept in the user's .ipython dir).
44 44 TIMEOUT_STORAGE = 2
45 45
46 46 # Time in seconds after which we give up
47 47 TIMEOUT_GIVEUP = 20
48 48
49 49 # Regular expression for the python import statement
50 50 import_re = re.compile(r'.*(\.so|\.py[cod]?)$')
51 51
52 52 # RE for the ipython %run command (python + ipython scripts)
53 53 magic_run_re = re.compile(r'.*(\.ipy|\.py[w]?)$')
54 54
55 55 #-----------------------------------------------------------------------------
56 56 # Local utilities
57 57 #-----------------------------------------------------------------------------
58 58
59 59 def shlex_split(x):
60 60 """Helper function to split lines into segments.
61 61 """
62 62 # shlex.split raises an exception if there is a syntax error in sh syntax
63 63 # for example if no closing " is found. This function keeps dropping the
64 64 # last character of the line until shlex.split does not raise
65 65 # an exception. It adds end of the line to the result of shlex.split
66 66 #
67 67 # Example:
68 68 # %run "c:/python -> ['%run','"c:/python']
69 69
70 70 # shlex.split has unicode bugs in Python 2, so encode first to str
71 71 if not py3compat.PY3:
72 72 x = py3compat.cast_bytes(x)
73 73
74 74 endofline = []
75 75 while x != '':
76 76 try:
77 77 comps = shlex.split(x)
78 78 if len(endofline) >= 1:
79 79 comps.append(''.join(endofline))
80 80 return comps
81 81
82 82 except ValueError:
83 83 endofline = [x[-1:]]+endofline
84 84 x = x[:-1]
85 85
86 86 return [''.join(endofline)]
87 87
88 88 def module_list(path):
89 89 """
90 90 Return the list containing the names of the modules available in the given
91 91 folder.
92 92 """
93 93
94 94 if os.path.isdir(path):
95 95 folder_list = os.listdir(path)
96 96 elif path.endswith('.egg'):
97 97 try:
98 98 folder_list = [f for f in zipimporter(path)._files]
99 99 except:
100 100 folder_list = []
101 101 else:
102 102 folder_list = []
103 103
104 104 if not folder_list:
105 105 return []
106 106
107 107 # A few local constants to be used in loops below
108 108 isfile = os.path.isfile
109 109 pjoin = os.path.join
110 110 basename = os.path.basename
111 111
112 112 # Now find actual path matches for packages or modules
113 113 folder_list = [p for p in folder_list
114 114 if isfile(pjoin(path, p,'__init__.py'))
115 115 or import_re.match(p) ]
116 116
117 117 return [basename(p).split('.')[0] for p in folder_list]
118 118
119 119 def get_root_modules():
120 120 """
121 121 Returns a list containing the names of all the modules available in the
122 122 folders of the pythonpath.
123 123 """
124 124 ip = get_ipython()
125 125
126 126 if 'rootmodules' in ip.db:
127 127 return ip.db['rootmodules']
128 128
129 129 t = time()
130 130 store = False
131 131 modules = list(sys.builtin_module_names)
132 132 for path in sys.path:
133 133 modules += module_list(path)
134 134 if time() - t >= TIMEOUT_STORAGE and not store:
135 135 store = True
136 136 print("\nCaching the list of root modules, please wait!")
137 137 print("(This will only be done once - type '%rehashx' to "
138 138 "reset cache!)\n")
139 139 sys.stdout.flush()
140 140 if time() - t > TIMEOUT_GIVEUP:
141 141 print("This is taking too long, we give up.\n")
142 142 ip.db['rootmodules'] = []
143 143 return []
144 144
145 145 modules = set(modules)
146 146 if '__init__' in modules:
147 147 modules.remove('__init__')
148 148 modules = list(modules)
149 149 if store:
150 150 ip.db['rootmodules'] = modules
151 151 return modules
152 152
153 153
154 154 def is_importable(module, attr, only_modules):
155 155 if only_modules:
156 156 return inspect.ismodule(getattr(module, attr))
157 157 else:
158 158 return not(attr[:2] == '__' and attr[-2:] == '__')
159 159
160 160
161 161 def try_import(mod, only_modules=False):
162 162 try:
163 163 m = __import__(mod)
164 164 except:
165 165 return []
166 166 mods = mod.split('.')
167 167 for module in mods[1:]:
168 168 m = getattr(m, module)
169 169
170 170 m_is_init = hasattr(m, '__file__') and '__init__' in m.__file__
171 171
172 172 completions = []
173 173 if (not hasattr(m, '__file__')) or (not only_modules) or m_is_init:
174 174 completions.extend( [attr for attr in dir(m) if
175 175 is_importable(m, attr, only_modules)])
176 176
177 177 completions.extend(getattr(m, '__all__', []))
178 178 if m_is_init:
179 179 completions.extend(module_list(os.path.dirname(m.__file__)))
180 180 completions = set(completions)
181 181 if '__init__' in completions:
182 182 completions.remove('__init__')
183 183 return list(completions)
184 184
185 185
186 186 #-----------------------------------------------------------------------------
187 187 # Completion-related functions.
188 188 #-----------------------------------------------------------------------------
189 189
190 190 def quick_completer(cmd, completions):
191 191 """ Easily create a trivial completer for a command.
192 192
193 193 Takes either a list of completions, or all completions in string (that will
194 194 be split on whitespace).
195 195
196 196 Example::
197 197
198 198 [d:\ipython]|1> import ipy_completers
199 199 [d:\ipython]|2> ipy_completers.quick_completer('foo', ['bar','baz'])
200 200 [d:\ipython]|3> foo b<TAB>
201 201 bar baz
202 202 [d:\ipython]|3> foo ba
203 203 """
204 204
205 205 if isinstance(completions, basestring):
206 206 completions = completions.split()
207 207
208 208 def do_complete(self, event):
209 209 return completions
210 210
211 211 get_ipython().set_hook('complete_command',do_complete, str_key = cmd)
212 212
213 213
214 214 def module_completion(line):
215 215 """
216 216 Returns a list containing the completion possibilities for an import line.
217 217
218 218 The line looks like this :
219 219 'import xml.d'
220 220 'from xml.dom import'
221 221 """
222 222
223 223 words = line.split(' ')
224 224 nwords = len(words)
225 225
226 226 # from whatever <tab> -> 'import '
227 227 if nwords == 3 and words[0] == 'from':
228 228 return ['import ']
229 229
230 230 # 'from xy<tab>' or 'import xy<tab>'
231 231 if nwords < 3 and (words[0] in ['import','from']) :
232 232 if nwords == 1:
233 233 return get_root_modules()
234 234 mod = words[1].split('.')
235 235 if len(mod) < 2:
236 236 return get_root_modules()
237 237 completion_list = try_import('.'.join(mod[:-1]), True)
238 238 return ['.'.join(mod[:-1] + [el]) for el in completion_list]
239 239
240 240 # 'from xyz import abc<tab>'
241 241 if nwords >= 3 and words[0] == 'from':
242 242 mod = words[1]
243 243 return try_import(mod)
244 244
245 245 #-----------------------------------------------------------------------------
246 246 # Completers
247 247 #-----------------------------------------------------------------------------
248 248 # These all have the func(self, event) signature to be used as custom
249 249 # completers
250 250
251 251 def module_completer(self,event):
252 252 """Give completions after user has typed 'import ...' or 'from ...'"""
253 253
254 254 # This works in all versions of python. While 2.5 has
255 255 # pkgutil.walk_packages(), that particular routine is fairly dangerous,
256 256 # since it imports *EVERYTHING* on sys.path. That is: a) very slow b) full
257 257 # of possibly problematic side effects.
258 258 # This search the folders in the sys.path for available modules.
259 259
260 260 return module_completion(event.line)
261 261
262 262 # FIXME: there's a lot of logic common to the run, cd and builtin file
263 263 # completers, that is currently reimplemented in each.
264 264
265 265 def magic_run_completer(self, event):
266 266 """Complete files that end in .py or .ipy for the %run command.
267 267 """
268 268 comps = shlex_split(event.line)
269 269 relpath = (len(comps) > 1 and comps[-1] or '').strip("'\"")
270 270
271 271 #print("\nev=", event) # dbg
272 272 #print("rp=", relpath) # dbg
273 273 #print('comps=', comps) # dbg
274 274
275 275 lglob = glob.glob
276 276 isdir = os.path.isdir
277 277 relpath, tilde_expand, tilde_val = expand_user(relpath)
278 278
279 279 dirs = [f.replace('\\','/') + "/" for f in lglob(relpath+'*') if isdir(f)]
280 280
281 281 # Find if the user has already typed the first filename, after which we
282 282 # should complete on all files, since after the first one other files may
283 283 # be arguments to the input script.
284 284
285 285 if filter(magic_run_re.match, comps):
286 286 pys = [f.replace('\\','/') for f in lglob('*')]
287 287 else:
288 288 pys = [f.replace('\\','/')
289 289 for f in lglob(relpath+'*.py') + lglob(relpath+'*.ipy') +
290 290 lglob(relpath + '*.pyw')]
291 291 #print('run comp:', dirs+pys) # dbg
292 292 return [compress_user(p, tilde_expand, tilde_val) for p in dirs+pys]
293 293
294 294
295 295 def cd_completer(self, event):
296 296 """Completer function for cd, which only returns directories."""
297 297 ip = get_ipython()
298 298 relpath = event.symbol
299 299
300 300 #print(event) # dbg
301 301 if event.line.endswith('-b') or ' -b ' in event.line:
302 302 # return only bookmark completions
303 303 bkms = self.db.get('bookmarks', None)
304 304 if bkms:
305 305 return bkms.keys()
306 306 else:
307 307 return []
308 308
309 309 if event.symbol == '-':
310 310 width_dh = str(len(str(len(ip.user_ns['_dh']) + 1)))
311 311 # jump in directory history by number
312 312 fmt = '-%0' + width_dh +'d [%s]'
313 313 ents = [ fmt % (i,s) for i,s in enumerate(ip.user_ns['_dh'])]
314 314 if len(ents) > 1:
315 315 return ents
316 316 return []
317 317
318 318 if event.symbol.startswith('--'):
319 319 return ["--" + os.path.basename(d) for d in ip.user_ns['_dh']]
320 320
321 321 # Expand ~ in path and normalize directory separators.
322 322 relpath, tilde_expand, tilde_val = expand_user(relpath)
323 323 relpath = relpath.replace('\\','/')
324 324
325 325 found = []
326 326 for d in [f.replace('\\','/') + '/' for f in glob.glob(relpath+'*')
327 327 if os.path.isdir(f)]:
328 328 if ' ' in d:
329 329 # we don't want to deal with any of that, complex code
330 330 # for this is elsewhere
331 331 raise TryNext
332 332
333 333 found.append(d)
334 334
335 335 if not found:
336 336 if os.path.isdir(relpath):
337 337 return [compress_user(relpath, tilde_expand, tilde_val)]
338 338
339 339 # if no completions so far, try bookmarks
340 340 bks = self.db.get('bookmarks',{}).iterkeys()
341 341 bkmatches = [s for s in bks if s.startswith(event.symbol)]
342 342 if bkmatches:
343 343 return bkmatches
344 344
345 345 raise TryNext
346 346
347 347 return [compress_user(p, tilde_expand, tilde_val) for p in found]
@@ -1,214 +1,214 b''
1 1 # encoding: utf-8
2 2 """sys.excepthook for IPython itself, leaves a detailed report on disk.
3 3
4 4 Authors:
5 5
6 6 * Fernando Perez
7 7 * Brian E. Granger
8 8 """
9 9
10 10 #-----------------------------------------------------------------------------
11 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 14 # Distributed under the terms of the BSD License. The full license is in
15 15 # the file COPYING, distributed as part of this software.
16 16 #-----------------------------------------------------------------------------
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Imports
20 20 #-----------------------------------------------------------------------------
21 21
22 22 import os
23 23 import sys
24 24 import traceback
25 25 from pprint import pformat
26 26
27 27 from IPython.core import ultratb
28 28 from IPython.core.release import author_email
29 29 from IPython.utils.sysinfo import sys_info
30 30
31 31 #-----------------------------------------------------------------------------
32 32 # Code
33 33 #-----------------------------------------------------------------------------
34 34
35 35 # Template for the user message.
36 36 _default_message_template = """\
37 37 Oops, {app_name} crashed. We do our best to make it stable, but...
38 38
39 39 A crash report was automatically generated with the following information:
40 40 - A verbatim copy of the crash traceback.
41 41 - A copy of your input history during this session.
42 42 - Data on your current {app_name} configuration.
43 43
44 44 It was left in the file named:
45 45 \t'{crash_report_fname}'
46 46 If you can email this file to the developers, the information in it will help
47 47 them in understanding and correcting the problem.
48 48
49 49 You can mail it to: {contact_name} at {contact_email}
50 50 with the subject '{app_name} Crash Report'.
51 51
52 52 If you want to do it now, the following command will work (under Unix):
53 53 mail -s '{app_name} Crash Report' {contact_email} < {crash_report_fname}
54 54
55 55 To ensure accurate tracking of this issue, please file a report about it at:
56 56 {bug_tracker}
57 57 """
58 58
59 59 _lite_message_template = """
60 60 If you suspect this is an IPython bug, please report it at:
61 61 https://github.com/ipython/ipython/issues
62 62 or send an email to the mailing list at {email}
63 63
64 64 You can print a more detailed traceback right now with "%tb", or use "%debug"
65 65 to interactively debug it.
66 66
67 67 Extra-detailed tracebacks for bug-reporting purposes can be enabled via:
68 68 {config}Application.verbose_crash=True
69 69 """
70 70
71 71
72 72 class CrashHandler(object):
73 73 """Customizable crash handlers for IPython applications.
74 74
75 75 Instances of this class provide a :meth:`__call__` method which can be
76 76 used as a ``sys.excepthook``. The :meth:`__call__` signature is::
77 77
78 78 def __call__(self, etype, evalue, etb)
79 79 """
80 80
81 81 message_template = _default_message_template
82 82 section_sep = '\n\n'+'*'*75+'\n\n'
83 83
84 84 def __init__(self, app, contact_name=None, contact_email=None,
85 85 bug_tracker=None, show_crash_traceback=True, call_pdb=False):
86 86 """Create a new crash handler
87 87
88 88 Parameters
89 89 ----------
90 90 app : Application
91 91 A running :class:`Application` instance, which will be queried at
92 92 crash time for internal information.
93 93
94 94 contact_name : str
95 95 A string with the name of the person to contact.
96 96
97 97 contact_email : str
98 98 A string with the email address of the contact.
99 99
100 100 bug_tracker : str
101 101 A string with the URL for your project's bug tracker.
102 102
103 103 show_crash_traceback : bool
104 104 If false, don't print the crash traceback on stderr, only generate
105 105 the on-disk report
106 106
107 107 Non-argument instance attributes:
108 108
109 109 These instances contain some non-argument attributes which allow for
110 110 further customization of the crash handler's behavior. Please see the
111 111 source for further details.
112 112 """
113 113 self.crash_report_fname = "Crash_report_%s.txt" % app.name
114 114 self.app = app
115 115 self.call_pdb = call_pdb
116 116 #self.call_pdb = True # dbg
117 117 self.show_crash_traceback = show_crash_traceback
118 118 self.info = dict(app_name = app.name,
119 119 contact_name = contact_name,
120 120 contact_email = contact_email,
121 121 bug_tracker = bug_tracker,
122 122 crash_report_fname = self.crash_report_fname)
123 123
124 124
125 125 def __call__(self, etype, evalue, etb):
126 126 """Handle an exception, call for compatible with sys.excepthook"""
127 127
128 128 # do not allow the crash handler to be called twice without reinstalling it
129 129 # this prevents unlikely errors in the crash handling from entering an
130 130 # infinite loop.
131 131 sys.excepthook = sys.__excepthook__
132 132
133 133 # Report tracebacks shouldn't use color in general (safer for users)
134 134 color_scheme = 'NoColor'
135 135
136 136 # Use this ONLY for developer debugging (keep commented out for release)
137 137 #color_scheme = 'Linux' # dbg
138 138 try:
139 139 rptdir = self.app.ipython_dir
140 140 except:
141 141 rptdir = os.getcwdu()
142 142 if rptdir is None or not os.path.isdir(rptdir):
143 143 rptdir = os.getcwdu()
144 144 report_name = os.path.join(rptdir,self.crash_report_fname)
145 145 # write the report filename into the instance dict so it can get
146 146 # properly expanded out in the user message template
147 147 self.crash_report_fname = report_name
148 148 self.info['crash_report_fname'] = report_name
149 149 TBhandler = ultratb.VerboseTB(
150 150 color_scheme=color_scheme,
151 151 long_header=1,
152 152 call_pdb=self.call_pdb,
153 153 )
154 154 if self.call_pdb:
155 155 TBhandler(etype,evalue,etb)
156 156 return
157 157 else:
158 158 traceback = TBhandler.text(etype,evalue,etb,context=31)
159 159
160 160 # print traceback to screen
161 161 if self.show_crash_traceback:
162 162 print >> sys.stderr, traceback
163 163
164 164 # and generate a complete report on disk
165 165 try:
166 166 report = open(report_name,'w')
167 167 except:
168 168 print >> sys.stderr, 'Could not create crash report on disk.'
169 169 return
170 170
171 171 # Inform user on stderr of what happened
172 172 print >> sys.stderr, '\n'+'*'*70+'\n'
173 173 print >> sys.stderr, self.message_template.format(**self.info)
174 174
175 175 # Construct report on disk
176 176 report.write(self.make_report(traceback))
177 177 report.close()
178 178 raw_input("Hit <Enter> to quit (your terminal may close):")
179 179
180 180 def make_report(self,traceback):
181 181 """Return a string containing a crash report."""
182 182
183 183 sec_sep = self.section_sep
184 184
185 185 report = ['*'*75+'\n\n'+'IPython post-mortem report\n\n']
186 186 rpt_add = report.append
187 187 rpt_add(sys_info())
188 188
189 189 try:
190 190 config = pformat(self.app.config)
191 191 rpt_add(sec_sep)
192 192 rpt_add('Application name: %s\n\n' % self.app_name)
193 193 rpt_add('Current user configuration structure:\n\n')
194 194 rpt_add(config)
195 195 except:
196 196 pass
197 197 rpt_add(sec_sep+'Crash traceback:\n\n' + traceback)
198 198
199 199 return ''.join(report)
200 200
201 201
202 202 def crash_handler_lite(etype, evalue, tb):
203 203 """a light excepthook, adding a small message to the usual traceback"""
204 204 traceback.print_exception(etype, evalue, tb)
205 205
206 206 from IPython.core.interactiveshell import InteractiveShell
207 207 if InteractiveShell.initialized():
208 208 # we are in a Shell environment, give %magic example
209 209 config = "%config "
210 210 else:
211 211 # we are not in a shell, show generic config
212 212 config = "c."
213 213 print >> sys.stderr, _lite_message_template.format(email=author_email, config=config)
214 214
@@ -1,407 +1,407 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Top-level display functions for displaying object in different formats.
3 3
4 4 Authors:
5 5
6 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 12 # Distributed under the terms of the BSD License. The full license is in
13 13 # the file COPYING, distributed as part of this software.
14 14 #-----------------------------------------------------------------------------
15 15
16 16 #-----------------------------------------------------------------------------
17 17 # Imports
18 18 #-----------------------------------------------------------------------------
19 19
20 20 from .displaypub import (
21 21 publish_pretty, publish_html,
22 22 publish_latex, publish_svg,
23 23 publish_png, publish_json,
24 24 publish_javascript, publish_jpeg
25 25 )
26 26
27 27 #-----------------------------------------------------------------------------
28 28 # Main functions
29 29 #-----------------------------------------------------------------------------
30 30
31 31 def display(*objs, **kwargs):
32 32 """Display a Python object in all frontends.
33 33
34 34 By default all representations will be computed and sent to the frontends.
35 35 Frontends can decide which representation is used and how.
36 36
37 37 Parameters
38 38 ----------
39 39 objs : tuple of objects
40 40 The Python objects to display.
41 41 include : list or tuple, optional
42 42 A list of format type strings (MIME types) to include in the
43 43 format data dict. If this is set *only* the format types included
44 44 in this list will be computed.
45 45 exclude : list or tuple, optional
46 46 A list of format type string (MIME types) to exclue in the format
47 47 data dict. If this is set all format types will be computed,
48 48 except for those included in this argument.
49 49 """
50 50 include = kwargs.get('include')
51 51 exclude = kwargs.get('exclude')
52 52
53 53 from IPython.core.interactiveshell import InteractiveShell
54 54 inst = InteractiveShell.instance()
55 55 format = inst.display_formatter.format
56 56 publish = inst.display_pub.publish
57 57
58 58 for obj in objs:
59 59 format_dict = format(obj, include=include, exclude=exclude)
60 60 publish('IPython.core.display.display', format_dict)
61 61
62 62
63 63 def display_pretty(*objs, **kwargs):
64 64 """Display the pretty (default) representation of an object.
65 65
66 66 Parameters
67 67 ----------
68 68 objs : tuple of objects
69 69 The Python objects to display, or if raw=True raw text data to
70 70 display.
71 71 raw : bool
72 72 Are the data objects raw data or Python objects that need to be
73 73 formatted before display? [default: False]
74 74 """
75 75 raw = kwargs.pop('raw',False)
76 76 if raw:
77 77 for obj in objs:
78 78 publish_pretty(obj)
79 79 else:
80 80 display(*objs, include=['text/plain'])
81 81
82 82
83 83 def display_html(*objs, **kwargs):
84 84 """Display the HTML representation of an object.
85 85
86 86 Parameters
87 87 ----------
88 88 objs : tuple of objects
89 89 The Python objects to display, or if raw=True raw HTML data to
90 90 display.
91 91 raw : bool
92 92 Are the data objects raw data or Python objects that need to be
93 93 formatted before display? [default: False]
94 94 """
95 95 raw = kwargs.pop('raw',False)
96 96 if raw:
97 97 for obj in objs:
98 98 publish_html(obj)
99 99 else:
100 100 display(*objs, include=['text/plain','text/html'])
101 101
102 102
103 103 def display_svg(*objs, **kwargs):
104 104 """Display the SVG representation of an object.
105 105
106 106 Parameters
107 107 ----------
108 108 objs : tuple of objects
109 109 The Python objects to display, or if raw=True raw svg data to
110 110 display.
111 111 raw : bool
112 112 Are the data objects raw data or Python objects that need to be
113 113 formatted before display? [default: False]
114 114 """
115 115 raw = kwargs.pop('raw',False)
116 116 if raw:
117 117 for obj in objs:
118 118 publish_svg(obj)
119 119 else:
120 120 display(*objs, include=['text/plain','image/svg+xml'])
121 121
122 122
123 123 def display_png(*objs, **kwargs):
124 124 """Display the PNG representation of an object.
125 125
126 126 Parameters
127 127 ----------
128 128 objs : tuple of objects
129 129 The Python objects to display, or if raw=True raw png data to
130 130 display.
131 131 raw : bool
132 132 Are the data objects raw data or Python objects that need to be
133 133 formatted before display? [default: False]
134 134 """
135 135 raw = kwargs.pop('raw',False)
136 136 if raw:
137 137 for obj in objs:
138 138 publish_png(obj)
139 139 else:
140 140 display(*objs, include=['text/plain','image/png'])
141 141
142 142
143 143 def display_jpeg(*objs, **kwargs):
144 144 """Display the JPEG representation of an object.
145 145
146 146 Parameters
147 147 ----------
148 148 objs : tuple of objects
149 149 The Python objects to display, or if raw=True raw JPEG data to
150 150 display.
151 151 raw : bool
152 152 Are the data objects raw data or Python objects that need to be
153 153 formatted before display? [default: False]
154 154 """
155 155 raw = kwargs.pop('raw',False)
156 156 if raw:
157 157 for obj in objs:
158 158 publish_jpeg(obj)
159 159 else:
160 160 display(*objs, include=['text/plain','image/jpeg'])
161 161
162 162
163 163 def display_latex(*objs, **kwargs):
164 164 """Display the LaTeX representation of an object.
165 165
166 166 Parameters
167 167 ----------
168 168 objs : tuple of objects
169 169 The Python objects to display, or if raw=True raw latex data to
170 170 display.
171 171 raw : bool
172 172 Are the data objects raw data or Python objects that need to be
173 173 formatted before display? [default: False]
174 174 """
175 175 raw = kwargs.pop('raw',False)
176 176 if raw:
177 177 for obj in objs:
178 178 publish_latex(obj)
179 179 else:
180 180 display(*objs, include=['text/plain','text/latex'])
181 181
182 182
183 183 def display_json(*objs, **kwargs):
184 184 """Display the JSON representation of an object.
185 185
186 186 Parameters
187 187 ----------
188 188 objs : tuple of objects
189 189 The Python objects to display, or if raw=True raw json data to
190 190 display.
191 191 raw : bool
192 192 Are the data objects raw data or Python objects that need to be
193 193 formatted before display? [default: False]
194 194 """
195 195 raw = kwargs.pop('raw',False)
196 196 if raw:
197 197 for obj in objs:
198 198 publish_json(obj)
199 199 else:
200 200 display(*objs, include=['text/plain','application/json'])
201 201
202 202
203 203 def display_javascript(*objs, **kwargs):
204 204 """Display the Javascript representation of an object.
205 205
206 206 Parameters
207 207 ----------
208 208 objs : tuple of objects
209 209 The Python objects to display, or if raw=True raw javascript data to
210 210 display.
211 211 raw : bool
212 212 Are the data objects raw data or Python objects that need to be
213 213 formatted before display? [default: False]
214 214 """
215 215 raw = kwargs.pop('raw',False)
216 216 if raw:
217 217 for obj in objs:
218 218 publish_javascript(obj)
219 219 else:
220 220 display(*objs, include=['text/plain','application/javascript'])
221 221
222 222 #-----------------------------------------------------------------------------
223 223 # Smart classes
224 224 #-----------------------------------------------------------------------------
225 225
226 226
227 227 class DisplayObject(object):
228 228 """An object that wraps data to be displayed."""
229 229
230 230 _read_flags = 'r'
231 231
232 232 def __init__(self, data=None, url=None, filename=None):
233 233 """Create a display object given raw data.
234 234
235 235 When this object is returned by an expression or passed to the
236 236 display function, it will result in the data being displayed
237 237 in the frontend. The MIME type of the data should match the
238 238 subclasses used, so the Png subclass should be used for 'image/png'
239 239 data. If the data is a URL, the data will first be downloaded
240 240 and then displayed. If
241 241
242 242 Parameters
243 243 ----------
244 244 data : unicode, str or bytes
245 245 The raw data or a URL to download the data from.
246 246 url : unicode
247 247 A URL to download the data from.
248 248 filename : unicode
249 249 Path to a local file to load the data from.
250 250 """
251 251 if data is not None and data.startswith('http'):
252 252 self.url = data
253 253 self.filename = None
254 254 self.data = None
255 255 else:
256 256 self.data = data
257 257 self.url = url
258 258 self.filename = None if filename is None else unicode(filename)
259 259 self.reload()
260 260
261 261 def reload(self):
262 262 """Reload the raw data from file or URL."""
263 263 if self.filename is not None:
264 264 with open(self.filename, self._read_flags) as f:
265 265 self.data = f.read()
266 266 elif self.url is not None:
267 267 try:
268 268 import urllib2
269 269 response = urllib2.urlopen(self.url)
270 270 self.data = response.read()
271 271 # extract encoding from header, if there is one:
272 272 encoding = None
273 273 for sub in response.headers['content-type'].split(';'):
274 274 sub = sub.strip()
275 275 if sub.startswith('charset'):
276 276 encoding = sub.split('=')[-1].strip()
277 277 break
278 278 # decode data, if an encoding was specified
279 279 if encoding:
280 280 self.data = self.data.decode(encoding, 'replace')
281 281 except:
282 282 self.data = None
283 283
284 284 class Pretty(DisplayObject):
285 285
286 286 def _repr_pretty_(self):
287 287 return self.data
288 288
289 289
290 290 class HTML(DisplayObject):
291 291
292 292 def _repr_html_(self):
293 293 return self.data
294 294
295 295
296 296 class Math(DisplayObject):
297 297
298 298 def _repr_latex_(self):
299 299 return self.data
300 300
301 301
302 302 class SVG(DisplayObject):
303 303
304 304 def _repr_svg_(self):
305 305 return self.data
306 306
307 307
308 308 class JSON(DisplayObject):
309 309
310 310 def _repr_json_(self):
311 311 return self.data
312 312
313 313
314 314 class Javascript(DisplayObject):
315 315
316 316 def _repr_javascript_(self):
317 317 return self.data
318 318
319 319
320 320 class Image(DisplayObject):
321 321
322 322 _read_flags = 'rb'
323 323
324 324 def __init__(self, data=None, url=None, filename=None, format=u'png', embed=False):
325 325 """Create a display an PNG/JPEG image given raw data.
326 326
327 327 When this object is returned by an expression or passed to the
328 328 display function, it will result in the image being displayed
329 329 in the frontend.
330 330
331 331 Parameters
332 332 ----------
333 333 data : unicode, str or bytes
334 334 The raw data or a URL to download the data from.
335 335 url : unicode
336 336 A URL to download the data from.
337 337 filename : unicode
338 338 Path to a local file to load the data from.
339 339 format : unicode
340 340 The format of the image data (png/jpeg/jpg). If a filename or URL is given
341 341 for format will be inferred from the filename extension.
342 342 embed : bool
343 343 Should the image data be embedded in the notebook using a data URI (True)
344 344 or be loaded using an <img> tag. Set this to True if you want the image
345 345 to be viewable later with no internet connection. If a filename is given
346 346 embed is always set to True.
347 347 """
348 348 if filename is not None:
349 349 ext = self._find_ext(filename)
350 350 elif url is not None:
351 351 ext = self._find_ext(url)
352 352 elif data.startswith('http'):
353 353 ext = self._find_ext(data)
354 354 else:
355 355 ext = None
356 356 if ext is not None:
357 357 if ext == u'jpg' or ext == u'jpeg':
358 358 format = u'jpeg'
359 359 if ext == u'png':
360 360 format = u'png'
361 361 self.format = unicode(format).lower()
362 362 self.embed = True if filename is not None else embed
363 363 super(Image, self).__init__(data=data, url=url, filename=filename)
364 364
365 365 def reload(self):
366 366 """Reload the raw data from file or URL."""
367 367 if self.embed:
368 368 super(Image,self).reload()
369 369
370 370 def _repr_html_(self):
371 371 if not self.embed:
372 372 return u'<img src="%s" />' % self.url
373 373
374 374 def _repr_png_(self):
375 375 if self.embed and self.format == u'png':
376 376 return self.data
377 377
378 378 def _repr_jpeg_(self):
379 379 if self.embed and (self.format == u'jpeg' or self.format == u'jpg'):
380 380 return self.data
381 381
382 382 def _find_ext(self, s):
383 383 return unicode(s.split('.')[-1].lower())
384 384
385 385
386 386 def clear_output(stdout=True, stderr=True, other=True):
387 387 """Clear the output of the current cell receiving output.
388 388
389 389 Optionally, each of stdout/stderr or other non-stream data (e.g. anything
390 390 produced by display()) can be excluded from the clear event.
391 391
392 392 By default, everything is cleared.
393 393
394 394 Parameters
395 395 ----------
396 396 stdout : bool [default: True]
397 397 Whether to clear stdout.
398 398 stderr : bool [default: True]
399 399 Whether to clear stderr.
400 400 other : bool [default: True]
401 401 Whether to clear everything else that is not stdout/stderr
402 402 (e.g. figures,images,HTML, any result of display()).
403 403 """
404 404 from IPython.core.interactiveshell import InteractiveShell
405 405 InteractiveShell.instance().display_pub.clear_output(
406 406 stdout=stdout, stderr=stderr, other=other,
407 407 )
@@ -1,70 +1,70 b''
1 1 # encoding: utf-8
2 2 """
3 3 A context manager for handling sys.displayhook.
4 4
5 5 Authors:
6 6
7 7 * Robert Kern
8 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 14 # Distributed under the terms of the BSD License. The full license is in
15 15 # the file COPYING, distributed as part of this software.
16 16 #-----------------------------------------------------------------------------
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Imports
20 20 #-----------------------------------------------------------------------------
21 21
22 22 import sys
23 23
24 24 from IPython.config.configurable import Configurable
25 25 from IPython.utils.traitlets import Any
26 26
27 27 #-----------------------------------------------------------------------------
28 28 # Classes and functions
29 29 #-----------------------------------------------------------------------------
30 30
31 31
32 32 class DisplayTrap(Configurable):
33 33 """Object to manage sys.displayhook.
34 34
35 35 This came from IPython.core.kernel.display_hook, but is simplified
36 36 (no callbacks or formatters) until more of the core is refactored.
37 37 """
38 38
39 39 hook = Any
40 40
41 41 def __init__(self, hook=None):
42 42 super(DisplayTrap, self).__init__(hook=hook, config=None)
43 43 self.old_hook = None
44 44 # We define this to track if a single BuiltinTrap is nested.
45 45 # Only turn off the trap when the outermost call to __exit__ is made.
46 46 self._nested_level = 0
47 47
48 48 def __enter__(self):
49 49 if self._nested_level == 0:
50 50 self.set()
51 51 self._nested_level += 1
52 52 return self
53 53
54 54 def __exit__(self, type, value, traceback):
55 55 if self._nested_level == 1:
56 56 self.unset()
57 57 self._nested_level -= 1
58 58 # Returning False will cause exceptions to propagate
59 59 return False
60 60
61 61 def set(self):
62 62 """Set the hook."""
63 63 if sys.displayhook is not self.hook:
64 64 self.old_hook = sys.displayhook
65 65 sys.displayhook = self.hook
66 66
67 67 def unset(self):
68 68 """Unset the hook."""
69 69 sys.displayhook = self.old_hook
70 70
@@ -1,329 +1,329 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Displayhook for IPython.
3 3
4 4 This defines a callable class that IPython uses for `sys.displayhook`.
5 5
6 6 Authors:
7 7
8 8 * Fernando Perez
9 9 * Brian Granger
10 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 15 # Copyright (C) 2001-2007 Fernando Perez <fperez@colorado.edu>
16 16 #
17 17 # Distributed under the terms of the BSD License. The full license is in
18 18 # the file COPYING, distributed as part of this software.
19 19 #-----------------------------------------------------------------------------
20 20
21 21 #-----------------------------------------------------------------------------
22 22 # Imports
23 23 #-----------------------------------------------------------------------------
24 24
25 25 import __builtin__
26 26
27 27 from IPython.config.configurable import Configurable
28 28 from IPython.core import prompts
29 29 from IPython.utils import io
30 30 from IPython.utils.traitlets import Instance, List
31 31 from IPython.utils.warn import warn
32 32
33 33 #-----------------------------------------------------------------------------
34 34 # Main displayhook class
35 35 #-----------------------------------------------------------------------------
36 36
37 37 # TODO: The DisplayHook class should be split into two classes, one that
38 38 # manages the prompts and their synchronization and another that just does the
39 39 # displayhook logic and calls into the prompt manager.
40 40
41 41 # TODO: Move the various attributes (cache_size, colors, input_sep,
42 42 # output_sep, output_sep2, ps1, ps2, ps_out, pad_left). Some of these are also
43 43 # attributes of InteractiveShell. They should be on ONE object only and the
44 44 # other objects should ask that one object for their values.
45 45
46 46 class DisplayHook(Configurable):
47 47 """The custom IPython displayhook to replace sys.displayhook.
48 48
49 49 This class does many things, but the basic idea is that it is a callable
50 50 that gets called anytime user code returns a value.
51 51
52 52 Currently this class does more than just the displayhook logic and that
53 53 extra logic should eventually be moved out of here.
54 54 """
55 55
56 56 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
57 57
58 58 def __init__(self, shell=None, cache_size=1000,
59 59 colors='NoColor', input_sep='\n',
60 60 output_sep='\n', output_sep2='',
61 61 ps1 = None, ps2 = None, ps_out = None, pad_left=True,
62 62 config=None):
63 63 super(DisplayHook, self).__init__(shell=shell, config=config)
64 64
65 65 cache_size_min = 3
66 66 if cache_size <= 0:
67 67 self.do_full_cache = 0
68 68 cache_size = 0
69 69 elif cache_size < cache_size_min:
70 70 self.do_full_cache = 0
71 71 cache_size = 0
72 72 warn('caching was disabled (min value for cache size is %s).' %
73 73 cache_size_min,level=3)
74 74 else:
75 75 self.do_full_cache = 1
76 76
77 77 self.cache_size = cache_size
78 78 self.input_sep = input_sep
79 79
80 80 # we need a reference to the user-level namespace
81 81 self.shell = shell
82 82
83 83 # Set input prompt strings and colors
84 84 if cache_size == 0:
85 85 if ps1.find('%n') > -1 or ps1.find(r'\#') > -1 \
86 86 or ps1.find(r'\N') > -1:
87 87 ps1 = '>>> '
88 88 if ps2.find('%n') > -1 or ps2.find(r'\#') > -1 \
89 89 or ps2.find(r'\N') > -1:
90 90 ps2 = '... '
91 91 self.ps1_str = self._set_prompt_str(ps1,'In [\\#]: ','>>> ')
92 92 self.ps2_str = self._set_prompt_str(ps2,' .\\D.: ','... ')
93 93 self.ps_out_str = self._set_prompt_str(ps_out,'Out[\\#]: ','')
94 94
95 95 self.color_table = prompts.PromptColors
96 96 self.prompt1 = prompts.Prompt1(self,sep=input_sep,prompt=self.ps1_str,
97 97 pad_left=pad_left)
98 98 self.prompt2 = prompts.Prompt2(self,prompt=self.ps2_str,pad_left=pad_left)
99 99 self.prompt_out = prompts.PromptOut(self,sep='',prompt=self.ps_out_str,
100 100 pad_left=pad_left)
101 101 self.set_colors(colors)
102 102
103 103 # Store the last prompt string each time, we need it for aligning
104 104 # continuation and auto-rewrite prompts
105 105 self.last_prompt = ''
106 106 self.output_sep = output_sep
107 107 self.output_sep2 = output_sep2
108 108 self._,self.__,self.___ = '','',''
109 109
110 110 # these are deliberately global:
111 111 to_user_ns = {'_':self._,'__':self.__,'___':self.___}
112 112 self.shell.user_ns.update(to_user_ns)
113 113
114 114 @property
115 115 def prompt_count(self):
116 116 return self.shell.execution_count
117 117
118 118 def _set_prompt_str(self,p_str,cache_def,no_cache_def):
119 119 if p_str is None:
120 120 if self.do_full_cache:
121 121 return cache_def
122 122 else:
123 123 return no_cache_def
124 124 else:
125 125 return p_str
126 126
127 127 def set_colors(self, colors):
128 128 """Set the active color scheme and configure colors for the three
129 129 prompt subsystems."""
130 130
131 131 # FIXME: This modifying of the global prompts.prompt_specials needs
132 132 # to be fixed. We need to refactor all of the prompts stuff to use
133 133 # proper configuration and traits notifications.
134 134 if colors.lower()=='nocolor':
135 135 prompts.prompt_specials = prompts.prompt_specials_nocolor
136 136 else:
137 137 prompts.prompt_specials = prompts.prompt_specials_color
138 138
139 139 self.color_table.set_active_scheme(colors)
140 140 self.prompt1.set_colors()
141 141 self.prompt2.set_colors()
142 142 self.prompt_out.set_colors()
143 143
144 144 #-------------------------------------------------------------------------
145 145 # Methods used in __call__. Override these methods to modify the behavior
146 146 # of the displayhook.
147 147 #-------------------------------------------------------------------------
148 148
149 149 def check_for_underscore(self):
150 150 """Check if the user has set the '_' variable by hand."""
151 151 # If something injected a '_' variable in __builtin__, delete
152 152 # ipython's automatic one so we don't clobber that. gettext() in
153 153 # particular uses _, so we need to stay away from it.
154 154 if '_' in __builtin__.__dict__:
155 155 try:
156 156 del self.shell.user_ns['_']
157 157 except KeyError:
158 158 pass
159 159
160 160 def quiet(self):
161 161 """Should we silence the display hook because of ';'?"""
162 162 # do not print output if input ends in ';'
163 163 try:
164 164 cell = self.shell.history_manager.input_hist_parsed[self.prompt_count]
165 165 if cell.rstrip().endswith(';'):
166 166 return True
167 167 except IndexError:
168 168 # some uses of ipshellembed may fail here
169 169 pass
170 170 return False
171 171
172 172 def start_displayhook(self):
173 173 """Start the displayhook, initializing resources."""
174 174 pass
175 175
176 176 def write_output_prompt(self):
177 177 """Write the output prompt.
178 178
179 179 The default implementation simply writes the prompt to
180 180 ``io.stdout``.
181 181 """
182 182 # Use write, not print which adds an extra space.
183 183 io.stdout.write(self.output_sep)
184 184 outprompt = str(self.prompt_out)
185 185 if self.do_full_cache:
186 186 io.stdout.write(outprompt)
187 187
188 188 def compute_format_data(self, result):
189 189 """Compute format data of the object to be displayed.
190 190
191 191 The format data is a generalization of the :func:`repr` of an object.
192 192 In the default implementation the format data is a :class:`dict` of
193 193 key value pair where the keys are valid MIME types and the values
194 194 are JSON'able data structure containing the raw data for that MIME
195 195 type. It is up to frontends to determine pick a MIME to to use and
196 196 display that data in an appropriate manner.
197 197
198 198 This method only computes the format data for the object and should
199 199 NOT actually print or write that to a stream.
200 200
201 201 Parameters
202 202 ----------
203 203 result : object
204 204 The Python object passed to the display hook, whose format will be
205 205 computed.
206 206
207 207 Returns
208 208 -------
209 209 format_data : dict
210 210 A :class:`dict` whose keys are valid MIME types and values are
211 211 JSON'able raw data for that MIME type. It is recommended that
212 212 all return values of this should always include the "text/plain"
213 213 MIME type representation of the object.
214 214 """
215 215 return self.shell.display_formatter.format(result)
216 216
217 217 def write_format_data(self, format_dict):
218 218 """Write the format data dict to the frontend.
219 219
220 220 This default version of this method simply writes the plain text
221 221 representation of the object to ``io.stdout``. Subclasses should
222 222 override this method to send the entire `format_dict` to the
223 223 frontends.
224 224
225 225 Parameters
226 226 ----------
227 227 format_dict : dict
228 228 The format dict for the object passed to `sys.displayhook`.
229 229 """
230 230 # We want to print because we want to always make sure we have a
231 231 # newline, even if all the prompt separators are ''. This is the
232 232 # standard IPython behavior.
233 233 result_repr = format_dict['text/plain']
234 234 if '\n' in result_repr:
235 235 # So that multi-line strings line up with the left column of
236 236 # the screen, instead of having the output prompt mess up
237 237 # their first line.
238 238 # We use the ps_out_str template instead of the expanded prompt
239 239 # because the expansion may add ANSI escapes that will interfere
240 240 # with our ability to determine whether or not we should add
241 241 # a newline.
242 242 if self.ps_out_str and not self.ps_out_str.endswith('\n'):
243 243 # But avoid extraneous empty lines.
244 244 result_repr = '\n' + result_repr
245 245
246 246 print >>io.stdout, result_repr
247 247
248 248 def update_user_ns(self, result):
249 249 """Update user_ns with various things like _, __, _1, etc."""
250 250
251 251 # Avoid recursive reference when displaying _oh/Out
252 252 if result is not self.shell.user_ns['_oh']:
253 253 if len(self.shell.user_ns['_oh']) >= self.cache_size and self.do_full_cache:
254 254 warn('Output cache limit (currently '+
255 255 `self.cache_size`+' entries) hit.\n'
256 256 'Flushing cache and resetting history counter...\n'
257 257 'The only history variables available will be _,__,___ and _1\n'
258 258 'with the current result.')
259 259
260 260 self.flush()
261 261 # Don't overwrite '_' and friends if '_' is in __builtin__ (otherwise
262 262 # we cause buggy behavior for things like gettext).
263 263
264 264 if '_' not in __builtin__.__dict__:
265 265 self.___ = self.__
266 266 self.__ = self._
267 267 self._ = result
268 268 self.shell.user_ns.update({'_':self._,
269 269 '__':self.__,
270 270 '___':self.___})
271 271
272 272 # hackish access to top-level namespace to create _1,_2... dynamically
273 273 to_main = {}
274 274 if self.do_full_cache:
275 275 new_result = '_'+`self.prompt_count`
276 276 to_main[new_result] = result
277 277 self.shell.user_ns.update(to_main)
278 278 self.shell.user_ns['_oh'][self.prompt_count] = result
279 279
280 280 def log_output(self, format_dict):
281 281 """Log the output."""
282 282 if self.shell.logger.log_output:
283 283 self.shell.logger.log_write(format_dict['text/plain'], 'output')
284 284 self.shell.history_manager.output_hist_reprs[self.prompt_count] = \
285 285 format_dict['text/plain']
286 286
287 287 def finish_displayhook(self):
288 288 """Finish up all displayhook activities."""
289 289 io.stdout.write(self.output_sep2)
290 290 io.stdout.flush()
291 291
292 292 def __call__(self, result=None):
293 293 """Printing with history cache management.
294 294
295 295 This is invoked everytime the interpreter needs to print, and is
296 296 activated by setting the variable sys.displayhook to it.
297 297 """
298 298 self.check_for_underscore()
299 299 if result is not None and not self.quiet():
300 300 self.start_displayhook()
301 301 self.write_output_prompt()
302 302 format_dict = self.compute_format_data(result)
303 303 self.write_format_data(format_dict)
304 304 self.update_user_ns(result)
305 305 self.log_output(format_dict)
306 306 self.finish_displayhook()
307 307
308 308 def flush(self):
309 309 if not self.do_full_cache:
310 310 raise ValueError,"You shouldn't have reached the cache flush "\
311 311 "if full caching is not enabled!"
312 312 # delete auto-generated vars from global namespace
313 313
314 314 for n in range(1,self.prompt_count + 1):
315 315 key = '_'+`n`
316 316 try:
317 317 del self.shell.user_ns[key]
318 318 except: pass
319 319 self.shell.user_ns['_oh'].clear()
320 320
321 321 # Release our own references to objects:
322 322 self._, self.__, self.___ = '', '', ''
323 323
324 324 if '_' not in __builtin__.__dict__:
325 325 self.shell.user_ns.update({'_':None,'__':None, '___':None})
326 326 import gc
327 327 # TODO: Is this really needed?
328 328 gc.collect()
329 329
@@ -1,302 +1,302 b''
1 1 """An interface for publishing rich data to frontends.
2 2
3 3 There are two components of the display system:
4 4
5 5 * Display formatters, which take a Python object and compute the
6 6 representation of the object in various formats (text, HTML, SVg, etc.).
7 7 * The display publisher that is used to send the representation data to the
8 8 various frontends.
9 9
10 10 This module defines the logic display publishing. The display publisher uses
11 11 the ``display_data`` message type that is defined in the IPython messaging
12 12 spec.
13 13
14 14 Authors:
15 15
16 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 22 # Distributed under the terms of the BSD License. The full license is in
23 23 # the file COPYING, distributed as part of this software.
24 24 #-----------------------------------------------------------------------------
25 25
26 26 #-----------------------------------------------------------------------------
27 27 # Imports
28 28 #-----------------------------------------------------------------------------
29 29
30 30 from __future__ import print_function
31 31
32 32 from IPython.config.configurable import Configurable
33 33
34 34 #-----------------------------------------------------------------------------
35 35 # Main payload class
36 36 #-----------------------------------------------------------------------------
37 37
38 38 class DisplayPublisher(Configurable):
39 39 """A traited class that publishes display data to frontends.
40 40
41 41 Instances of this class are created by the main IPython object and should
42 42 be accessed there.
43 43 """
44 44
45 45 def _validate_data(self, source, data, metadata=None):
46 46 """Validate the display data.
47 47
48 48 Parameters
49 49 ----------
50 50 source : str
51 51 The fully dotted name of the callable that created the data, like
52 52 :func:`foo.bar.my_formatter`.
53 53 data : dict
54 54 The formata data dictionary.
55 55 metadata : dict
56 56 Any metadata for the data.
57 57 """
58 58
59 59 if not isinstance(source, basestring):
60 60 raise TypeError('source must be a str, got: %r' % source)
61 61 if not isinstance(data, dict):
62 62 raise TypeError('data must be a dict, got: %r' % data)
63 63 if metadata is not None:
64 64 if not isinstance(metadata, dict):
65 65 raise TypeError('metadata must be a dict, got: %r' % data)
66 66
67 67 def publish(self, source, data, metadata=None):
68 68 """Publish data and metadata to all frontends.
69 69
70 70 See the ``display_data`` message in the messaging documentation for
71 71 more details about this message type.
72 72
73 73 The following MIME types are currently implemented:
74 74
75 75 * text/plain
76 76 * text/html
77 77 * text/latex
78 78 * application/json
79 79 * application/javascript
80 80 * image/png
81 81 * image/jpeg
82 82 * image/svg+xml
83 83
84 84 Parameters
85 85 ----------
86 86 source : str
87 87 A string that give the function or method that created the data,
88 88 such as 'IPython.core.page'.
89 89 data : dict
90 90 A dictionary having keys that are valid MIME types (like
91 91 'text/plain' or 'image/svg+xml') and values that are the data for
92 92 that MIME type. The data itself must be a JSON'able data
93 93 structure. Minimally all data should have the 'text/plain' data,
94 94 which can be displayed by all frontends. If more than the plain
95 95 text is given, it is up to the frontend to decide which
96 96 representation to use.
97 97 metadata : dict
98 98 A dictionary for metadata related to the data. This can contain
99 99 arbitrary key, value pairs that frontends can use to interpret
100 100 the data.
101 101 """
102 102 from IPython.utils import io
103 103 # The default is to simply write the plain text data using io.stdout.
104 104 if data.has_key('text/plain'):
105 105 print(data['text/plain'], file=io.stdout)
106 106
107 107 def clear_output(self, stdout=True, stderr=True, other=True):
108 108 """Clear the output of the cell receiving output."""
109 109 pass
110 110
111 111
112 112 def publish_display_data(source, data, metadata=None):
113 113 """Publish data and metadata to all frontends.
114 114
115 115 See the ``display_data`` message in the messaging documentation for
116 116 more details about this message type.
117 117
118 118 The following MIME types are currently implemented:
119 119
120 120 * text/plain
121 121 * text/html
122 122 * text/latex
123 123 * application/json
124 124 * application/javascript
125 125 * image/png
126 126 * image/jpeg
127 127 * image/svg+xml
128 128
129 129 Parameters
130 130 ----------
131 131 source : str
132 132 A string that give the function or method that created the data,
133 133 such as 'IPython.core.page'.
134 134 data : dict
135 135 A dictionary having keys that are valid MIME types (like
136 136 'text/plain' or 'image/svg+xml') and values that are the data for
137 137 that MIME type. The data itself must be a JSON'able data
138 138 structure. Minimally all data should have the 'text/plain' data,
139 139 which can be displayed by all frontends. If more than the plain
140 140 text is given, it is up to the frontend to decide which
141 141 representation to use.
142 142 metadata : dict
143 143 A dictionary for metadata related to the data. This can contain
144 144 arbitrary key, value pairs that frontends can use to interpret
145 145 the data.
146 146 """
147 147 from IPython.core.interactiveshell import InteractiveShell
148 148 InteractiveShell.instance().display_pub.publish(
149 149 source,
150 150 data,
151 151 metadata
152 152 )
153 153
154 154
155 155 def publish_pretty(data, metadata=None):
156 156 """Publish raw text data to all frontends.
157 157
158 158 Parameters
159 159 ----------
160 160 data : unicode
161 161 The raw text data to publish.
162 162 metadata : dict
163 163 A dictionary for metadata related to the data. This can contain
164 164 arbitrary key, value pairs that frontends can use to interpret
165 165 the data.
166 166 """
167 167 publish_display_data(
168 168 u'IPython.core.displaypub.publish_pretty',
169 169 {'text/plain':data},
170 170 metadata=metadata
171 171 )
172 172
173 173
174 174 def publish_html(data, metadata=None):
175 175 """Publish raw HTML data to all frontends.
176 176
177 177 Parameters
178 178 ----------
179 179 data : unicode
180 180 The raw HTML data to publish.
181 181 metadata : dict
182 182 A dictionary for metadata related to the data. This can contain
183 183 arbitrary key, value pairs that frontends can use to interpret
184 184 the data.
185 185 """
186 186 publish_display_data(
187 187 u'IPython.core.displaypub.publish_html',
188 188 {'text/html':data},
189 189 metadata=metadata
190 190 )
191 191
192 192
193 193 def publish_latex(data, metadata=None):
194 194 """Publish raw LaTeX data to all frontends.
195 195
196 196 Parameters
197 197 ----------
198 198 data : unicode
199 199 The raw LaTeX data to publish.
200 200 metadata : dict
201 201 A dictionary for metadata related to the data. This can contain
202 202 arbitrary key, value pairs that frontends can use to interpret
203 203 the data.
204 204 """
205 205 publish_display_data(
206 206 u'IPython.core.displaypub.publish_latex',
207 207 {'text/latex':data},
208 208 metadata=metadata
209 209 )
210 210
211 211 def publish_png(data, metadata=None):
212 212 """Publish raw binary PNG data to all frontends.
213 213
214 214 Parameters
215 215 ----------
216 216 data : str/bytes
217 217 The raw binary PNG data to publish.
218 218 metadata : dict
219 219 A dictionary for metadata related to the data. This can contain
220 220 arbitrary key, value pairs that frontends can use to interpret
221 221 the data.
222 222 """
223 223 publish_display_data(
224 224 u'IPython.core.displaypub.publish_png',
225 225 {'image/png':data},
226 226 metadata=metadata
227 227 )
228 228
229 229
230 230 def publish_jpeg(data, metadata=None):
231 231 """Publish raw binary JPEG data to all frontends.
232 232
233 233 Parameters
234 234 ----------
235 235 data : str/bytes
236 236 The raw binary JPEG data to publish.
237 237 metadata : dict
238 238 A dictionary for metadata related to the data. This can contain
239 239 arbitrary key, value pairs that frontends can use to interpret
240 240 the data.
241 241 """
242 242 publish_display_data(
243 243 u'IPython.core.displaypub.publish_jpeg',
244 244 {'image/jpeg':data},
245 245 metadata=metadata
246 246 )
247 247
248 248
249 249 def publish_svg(data, metadata=None):
250 250 """Publish raw SVG data to all frontends.
251 251
252 252 Parameters
253 253 ----------
254 254 data : unicode
255 255 The raw SVG data to publish.
256 256 metadata : dict
257 257 A dictionary for metadata related to the data. This can contain
258 258 arbitrary key, value pairs that frontends can use to interpret
259 259 the data.
260 260 """
261 261 publish_display_data(
262 262 u'IPython.core.displaypub.publish_svg',
263 263 {'image/svg+xml':data},
264 264 metadata=metadata
265 265 )
266 266
267 267 def publish_json(data, metadata=None):
268 268 """Publish raw JSON data to all frontends.
269 269
270 270 Parameters
271 271 ----------
272 272 data : unicode
273 273 The raw JSON data to publish.
274 274 metadata : dict
275 275 A dictionary for metadata related to the data. This can contain
276 276 arbitrary key, value pairs that frontends can use to interpret
277 277 the data.
278 278 """
279 279 publish_display_data(
280 280 u'IPython.core.displaypub.publish_json',
281 281 {'application/json':data},
282 282 metadata=metadata
283 283 )
284 284
285 285 def publish_javascript(data, metadata=None):
286 286 """Publish raw Javascript data to all frontends.
287 287
288 288 Parameters
289 289 ----------
290 290 data : unicode
291 291 The raw Javascript data to publish.
292 292 metadata : dict
293 293 A dictionary for metadata related to the data. This can contain
294 294 arbitrary key, value pairs that frontends can use to interpret
295 295 the data.
296 296 """
297 297 publish_display_data(
298 298 u'IPython.core.displaypub.publish_javascript',
299 299 {'application/javascript':data},
300 300 metadata=metadata
301 301 )
302 302
@@ -1,59 +1,59 b''
1 1 # encoding: utf-8
2 2 """
3 3 Global exception classes for IPython.core.
4 4
5 5 Authors:
6 6
7 7 * Brian Granger
8 8 * Fernando Perez
9 9 * Min Ragan-Kelley
10 10
11 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 18 # Distributed under the terms of the BSD License. The full license is in
19 19 # the file COPYING, distributed as part of this software.
20 20 #-----------------------------------------------------------------------------
21 21
22 22 #-----------------------------------------------------------------------------
23 23 # Imports
24 24 #-----------------------------------------------------------------------------
25 25
26 26 #-----------------------------------------------------------------------------
27 27 # Exception classes
28 28 #-----------------------------------------------------------------------------
29 29
30 30 class IPythonCoreError(Exception):
31 31 pass
32 32
33 33
34 34 class TryNext(IPythonCoreError):
35 35 """Try next hook exception.
36 36
37 37 Raise this in your hook function to indicate that the next hook handler
38 38 should be used to handle the operation. If you pass arguments to the
39 39 constructor those arguments will be used by the next hook instead of the
40 40 original ones.
41 41 """
42 42
43 43 def __init__(self, *args, **kwargs):
44 44 self.args = args
45 45 self.kwargs = kwargs
46 46
47 47 class UsageError(IPythonCoreError):
48 48 """Error in magic function arguments, etc.
49 49
50 50 Something that probably won't warrant a full traceback, but should
51 51 nevertheless interrupt a macro / batch file.
52 52 """
53 53
54 54 class StdinNotImplementedError(IPythonCoreError, NotImplementedError):
55 55 """raw_input was requested in a context where it is not supported
56 56
57 57 For use in IPython kernels, where only some frontends may support
58 58 stdin requests.
59 59 """
@@ -1,125 +1,125 b''
1 1 # encoding: utf-8
2 2 """A class for managing IPython extensions.
3 3
4 4 Authors:
5 5
6 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 12 # Distributed under the terms of the BSD License. The full license is in
13 13 # the file COPYING, distributed as part of this software.
14 14 #-----------------------------------------------------------------------------
15 15
16 16 #-----------------------------------------------------------------------------
17 17 # Imports
18 18 #-----------------------------------------------------------------------------
19 19
20 20 import os
21 21 import sys
22 22
23 23 from IPython.config.configurable import Configurable
24 24 from IPython.utils.traitlets import Instance
25 25
26 26 #-----------------------------------------------------------------------------
27 27 # Main class
28 28 #-----------------------------------------------------------------------------
29 29
30 30 class ExtensionManager(Configurable):
31 31 """A class to manage IPython extensions.
32 32
33 33 An IPython extension is an importable Python module that has
34 34 a function with the signature::
35 35
36 36 def load_ipython_extension(ipython):
37 37 # Do things with ipython
38 38
39 39 This function is called after your extension is imported and the
40 40 currently active :class:`InteractiveShell` instance is passed as
41 41 the only argument. You can do anything you want with IPython at
42 42 that point, including defining new magic and aliases, adding new
43 43 components, etc.
44 44
45 45 The :func:`load_ipython_extension` will be called again is you
46 46 load or reload the extension again. It is up to the extension
47 47 author to add code to manage that.
48 48
49 49 You can put your extension modules anywhere you want, as long as
50 50 they can be imported by Python's standard import mechanism. However,
51 51 to make it easy to write extensions, you can also put your extensions
52 52 in ``os.path.join(self.ipython_dir, 'extensions')``. This directory
53 53 is added to ``sys.path`` automatically.
54 54 """
55 55
56 56 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
57 57
58 58 def __init__(self, shell=None, config=None):
59 59 super(ExtensionManager, self).__init__(shell=shell, config=config)
60 60 self.shell.on_trait_change(
61 61 self._on_ipython_dir_changed, 'ipython_dir'
62 62 )
63 63
64 64 def __del__(self):
65 65 self.shell.on_trait_change(
66 66 self._on_ipython_dir_changed, 'ipython_dir', remove=True
67 67 )
68 68
69 69 @property
70 70 def ipython_extension_dir(self):
71 71 return os.path.join(self.shell.ipython_dir, u'extensions')
72 72
73 73 def _on_ipython_dir_changed(self):
74 74 if not os.path.isdir(self.ipython_extension_dir):
75 75 os.makedirs(self.ipython_extension_dir, mode = 0777)
76 76
77 77 def load_extension(self, module_str):
78 78 """Load an IPython extension by its module name.
79 79
80 80 If :func:`load_ipython_extension` returns anything, this function
81 81 will return that object.
82 82 """
83 83 from IPython.utils.syspathcontext import prepended_to_syspath
84 84
85 85 if module_str not in sys.modules:
86 86 with prepended_to_syspath(self.ipython_extension_dir):
87 87 __import__(module_str)
88 88 mod = sys.modules[module_str]
89 89 return self._call_load_ipython_extension(mod)
90 90
91 91 def unload_extension(self, module_str):
92 92 """Unload an IPython extension by its module name.
93 93
94 94 This function looks up the extension's name in ``sys.modules`` and
95 95 simply calls ``mod.unload_ipython_extension(self)``.
96 96 """
97 97 if module_str in sys.modules:
98 98 mod = sys.modules[module_str]
99 99 self._call_unload_ipython_extension(mod)
100 100
101 101 def reload_extension(self, module_str):
102 102 """Reload an IPython extension by calling reload.
103 103
104 104 If the module has not been loaded before,
105 105 :meth:`InteractiveShell.load_extension` is called. Otherwise
106 106 :func:`reload` is called and then the :func:`load_ipython_extension`
107 107 function of the module, if it exists is called.
108 108 """
109 109 from IPython.utils.syspathcontext import prepended_to_syspath
110 110
111 111 with prepended_to_syspath(self.ipython_extension_dir):
112 112 if module_str in sys.modules:
113 113 mod = sys.modules[module_str]
114 114 reload(mod)
115 115 self._call_load_ipython_extension(mod)
116 116 else:
117 117 self.load_extension(module_str)
118 118
119 119 def _call_load_ipython_extension(self, mod):
120 120 if hasattr(mod, 'load_ipython_extension'):
121 121 return mod.load_ipython_extension(self.shell)
122 122
123 123 def _call_unload_ipython_extension(self, mod):
124 124 if hasattr(mod, 'unload_ipython_extension'):
125 125 return mod.unload_ipython_extension(self.shell)
@@ -1,620 +1,620 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Display formatters.
3 3
4 4
5 5 Authors:
6 6
7 7 * Robert Kern
8 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 13 # Distributed under the terms of the Modified BSD License.
14 14 #
15 15 # The full license is in the file COPYING.txt, distributed with this software.
16 16 #-----------------------------------------------------------------------------
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Imports
20 20 #-----------------------------------------------------------------------------
21 21
22 22 # Stdlib imports
23 23 import abc
24 24 import sys
25 25 # We must use StringIO, as cStringIO doesn't handle unicode properly.
26 26 from StringIO import StringIO
27 27
28 28 # Our own imports
29 29 from IPython.config.configurable import Configurable
30 30 from IPython.lib import pretty
31 31 from IPython.utils.traitlets import Bool, Dict, Integer, Unicode, CUnicode, ObjectName
32 32 from IPython.utils.py3compat import unicode_to_str
33 33
34 34
35 35 #-----------------------------------------------------------------------------
36 36 # The main DisplayFormatter class
37 37 #-----------------------------------------------------------------------------
38 38
39 39
40 40 class DisplayFormatter(Configurable):
41 41
42 42 # When set to true only the default plain text formatter will be used.
43 43 plain_text_only = Bool(False, config=True)
44 44
45 45 # A dict of formatter whose keys are format types (MIME types) and whose
46 46 # values are subclasses of BaseFormatter.
47 47 formatters = Dict()
48 48 def _formatters_default(self):
49 49 """Activate the default formatters."""
50 50 formatter_classes = [
51 51 PlainTextFormatter,
52 52 HTMLFormatter,
53 53 SVGFormatter,
54 54 PNGFormatter,
55 55 JPEGFormatter,
56 56 LatexFormatter,
57 57 JSONFormatter,
58 58 JavascriptFormatter
59 59 ]
60 60 d = {}
61 61 for cls in formatter_classes:
62 62 f = cls(config=self.config)
63 63 d[f.format_type] = f
64 64 return d
65 65
66 66 def format(self, obj, include=None, exclude=None):
67 67 """Return a format data dict for an object.
68 68
69 69 By default all format types will be computed.
70 70
71 71 The following MIME types are currently implemented:
72 72
73 73 * text/plain
74 74 * text/html
75 75 * text/latex
76 76 * application/json
77 77 * application/javascript
78 78 * image/png
79 79 * image/jpeg
80 80 * image/svg+xml
81 81
82 82 Parameters
83 83 ----------
84 84 obj : object
85 85 The Python object whose format data will be computed.
86 86 include : list or tuple, optional
87 87 A list of format type strings (MIME types) to include in the
88 88 format data dict. If this is set *only* the format types included
89 89 in this list will be computed.
90 90 exclude : list or tuple, optional
91 91 A list of format type string (MIME types) to exclue in the format
92 92 data dict. If this is set all format types will be computed,
93 93 except for those included in this argument.
94 94
95 95 Returns
96 96 -------
97 97 format_dict : dict
98 98 A dictionary of key/value pairs, one or each format that was
99 99 generated for the object. The keys are the format types, which
100 100 will usually be MIME type strings and the values and JSON'able
101 101 data structure containing the raw data for the representation in
102 102 that format.
103 103 """
104 104 format_dict = {}
105 105
106 106 # If plain text only is active
107 107 if self.plain_text_only:
108 108 formatter = self.formatters['text/plain']
109 109 try:
110 110 data = formatter(obj)
111 111 except:
112 112 # FIXME: log the exception
113 113 raise
114 114 if data is not None:
115 115 format_dict['text/plain'] = data
116 116 return format_dict
117 117
118 118 for format_type, formatter in self.formatters.items():
119 119 if include is not None:
120 120 if format_type not in include:
121 121 continue
122 122 if exclude is not None:
123 123 if format_type in exclude:
124 124 continue
125 125 try:
126 126 data = formatter(obj)
127 127 except:
128 128 # FIXME: log the exception
129 129 raise
130 130 if data is not None:
131 131 format_dict[format_type] = data
132 132 return format_dict
133 133
134 134 @property
135 135 def format_types(self):
136 136 """Return the format types (MIME types) of the active formatters."""
137 137 return self.formatters.keys()
138 138
139 139
140 140 #-----------------------------------------------------------------------------
141 141 # Formatters for specific format types (text, html, svg, etc.)
142 142 #-----------------------------------------------------------------------------
143 143
144 144
145 145 class FormatterABC(object):
146 146 """ Abstract base class for Formatters.
147 147
148 148 A formatter is a callable class that is responsible for computing the
149 149 raw format data for a particular format type (MIME type). For example,
150 150 an HTML formatter would have a format type of `text/html` and would return
151 151 the HTML representation of the object when called.
152 152 """
153 153 __metaclass__ = abc.ABCMeta
154 154
155 155 # The format type of the data returned, usually a MIME type.
156 156 format_type = 'text/plain'
157 157
158 158 # Is the formatter enabled...
159 159 enabled = True
160 160
161 161 @abc.abstractmethod
162 162 def __call__(self, obj):
163 163 """Return a JSON'able representation of the object.
164 164
165 165 If the object cannot be formatted by this formatter, then return None
166 166 """
167 167 try:
168 168 return repr(obj)
169 169 except TypeError:
170 170 return None
171 171
172 172
173 173 class BaseFormatter(Configurable):
174 174 """A base formatter class that is configurable.
175 175
176 176 This formatter should usually be used as the base class of all formatters.
177 177 It is a traited :class:`Configurable` class and includes an extensible
178 178 API for users to determine how their objects are formatted. The following
179 179 logic is used to find a function to format an given object.
180 180
181 181 1. The object is introspected to see if it has a method with the name
182 182 :attr:`print_method`. If is does, that object is passed to that method
183 183 for formatting.
184 184 2. If no print method is found, three internal dictionaries are consulted
185 185 to find print method: :attr:`singleton_printers`, :attr:`type_printers`
186 186 and :attr:`deferred_printers`.
187 187
188 188 Users should use these dictionaries to register functions that will be
189 189 used to compute the format data for their objects (if those objects don't
190 190 have the special print methods). The easiest way of using these
191 191 dictionaries is through the :meth:`for_type` and :meth:`for_type_by_name`
192 192 methods.
193 193
194 194 If no function/callable is found to compute the format data, ``None`` is
195 195 returned and this format type is not used.
196 196 """
197 197
198 198 format_type = Unicode('text/plain')
199 199
200 200 enabled = Bool(True, config=True)
201 201
202 202 print_method = ObjectName('__repr__')
203 203
204 204 # The singleton printers.
205 205 # Maps the IDs of the builtin singleton objects to the format functions.
206 206 singleton_printers = Dict(config=True)
207 207 def _singleton_printers_default(self):
208 208 return {}
209 209
210 210 # The type-specific printers.
211 211 # Map type objects to the format functions.
212 212 type_printers = Dict(config=True)
213 213 def _type_printers_default(self):
214 214 return {}
215 215
216 216 # The deferred-import type-specific printers.
217 217 # Map (modulename, classname) pairs to the format functions.
218 218 deferred_printers = Dict(config=True)
219 219 def _deferred_printers_default(self):
220 220 return {}
221 221
222 222 def __call__(self, obj):
223 223 """Compute the format for an object."""
224 224 if self.enabled:
225 225 obj_id = id(obj)
226 226 try:
227 227 obj_class = getattr(obj, '__class__', None) or type(obj)
228 228 # First try to find registered singleton printers for the type.
229 229 try:
230 230 printer = self.singleton_printers[obj_id]
231 231 except (TypeError, KeyError):
232 232 pass
233 233 else:
234 234 return printer(obj)
235 235 # Next look for type_printers.
236 236 for cls in pretty._get_mro(obj_class):
237 237 if cls in self.type_printers:
238 238 return self.type_printers[cls](obj)
239 239 else:
240 240 printer = self._in_deferred_types(cls)
241 241 if printer is not None:
242 242 return printer(obj)
243 243 # Finally look for special method names.
244 244 if hasattr(obj_class, self.print_method):
245 245 printer = getattr(obj_class, self.print_method)
246 246 return printer(obj)
247 247 return None
248 248 except Exception:
249 249 pass
250 250 else:
251 251 return None
252 252
253 253 def for_type(self, typ, func):
254 254 """Add a format function for a given type.
255 255
256 256 Parameters
257 257 -----------
258 258 typ : class
259 259 The class of the object that will be formatted using `func`.
260 260 func : callable
261 261 The callable that will be called to compute the format data. The
262 262 call signature of this function is simple, it must take the
263 263 object to be formatted and return the raw data for the given
264 264 format. Subclasses may use a different call signature for the
265 265 `func` argument.
266 266 """
267 267 oldfunc = self.type_printers.get(typ, None)
268 268 if func is not None:
269 269 # To support easy restoration of old printers, we need to ignore
270 270 # Nones.
271 271 self.type_printers[typ] = func
272 272 return oldfunc
273 273
274 274 def for_type_by_name(self, type_module, type_name, func):
275 275 """Add a format function for a type specified by the full dotted
276 276 module and name of the type, rather than the type of the object.
277 277
278 278 Parameters
279 279 ----------
280 280 type_module : str
281 281 The full dotted name of the module the type is defined in, like
282 282 ``numpy``.
283 283 type_name : str
284 284 The name of the type (the class name), like ``dtype``
285 285 func : callable
286 286 The callable that will be called to compute the format data. The
287 287 call signature of this function is simple, it must take the
288 288 object to be formatted and return the raw data for the given
289 289 format. Subclasses may use a different call signature for the
290 290 `func` argument.
291 291 """
292 292 key = (type_module, type_name)
293 293 oldfunc = self.deferred_printers.get(key, None)
294 294 if func is not None:
295 295 # To support easy restoration of old printers, we need to ignore
296 296 # Nones.
297 297 self.deferred_printers[key] = func
298 298 return oldfunc
299 299
300 300 def _in_deferred_types(self, cls):
301 301 """
302 302 Check if the given class is specified in the deferred type registry.
303 303
304 304 Returns the printer from the registry if it exists, and None if the
305 305 class is not in the registry. Successful matches will be moved to the
306 306 regular type registry for future use.
307 307 """
308 308 mod = getattr(cls, '__module__', None)
309 309 name = getattr(cls, '__name__', None)
310 310 key = (mod, name)
311 311 printer = None
312 312 if key in self.deferred_printers:
313 313 # Move the printer over to the regular registry.
314 314 printer = self.deferred_printers.pop(key)
315 315 self.type_printers[cls] = printer
316 316 return printer
317 317
318 318
319 319 class PlainTextFormatter(BaseFormatter):
320 320 """The default pretty-printer.
321 321
322 322 This uses :mod:`IPython.external.pretty` to compute the format data of
323 323 the object. If the object cannot be pretty printed, :func:`repr` is used.
324 324 See the documentation of :mod:`IPython.external.pretty` for details on
325 325 how to write pretty printers. Here is a simple example::
326 326
327 327 def dtype_pprinter(obj, p, cycle):
328 328 if cycle:
329 329 return p.text('dtype(...)')
330 330 if hasattr(obj, 'fields'):
331 331 if obj.fields is None:
332 332 p.text(repr(obj))
333 333 else:
334 334 p.begin_group(7, 'dtype([')
335 335 for i, field in enumerate(obj.descr):
336 336 if i > 0:
337 337 p.text(',')
338 338 p.breakable()
339 339 p.pretty(field)
340 340 p.end_group(7, '])')
341 341 """
342 342
343 343 # The format type of data returned.
344 344 format_type = Unicode('text/plain')
345 345
346 346 # This subclass ignores this attribute as it always need to return
347 347 # something.
348 348 enabled = Bool(True, config=False)
349 349
350 350 # Look for a _repr_pretty_ methods to use for pretty printing.
351 351 print_method = ObjectName('_repr_pretty_')
352 352
353 353 # Whether to pretty-print or not.
354 354 pprint = Bool(True, config=True)
355 355
356 356 # Whether to be verbose or not.
357 357 verbose = Bool(False, config=True)
358 358
359 359 # The maximum width.
360 360 max_width = Integer(79, config=True)
361 361
362 362 # The newline character.
363 363 newline = Unicode('\n', config=True)
364 364
365 365 # format-string for pprinting floats
366 366 float_format = Unicode('%r')
367 367 # setter for float precision, either int or direct format-string
368 368 float_precision = CUnicode('', config=True)
369 369
370 370 def _float_precision_changed(self, name, old, new):
371 371 """float_precision changed, set float_format accordingly.
372 372
373 373 float_precision can be set by int or str.
374 374 This will set float_format, after interpreting input.
375 375 If numpy has been imported, numpy print precision will also be set.
376 376
377 377 integer `n` sets format to '%.nf', otherwise, format set directly.
378 378
379 379 An empty string returns to defaults (repr for float, 8 for numpy).
380 380
381 381 This parameter can be set via the '%precision' magic.
382 382 """
383 383
384 384 if '%' in new:
385 385 # got explicit format string
386 386 fmt = new
387 387 try:
388 388 fmt%3.14159
389 389 except Exception:
390 390 raise ValueError("Precision must be int or format string, not %r"%new)
391 391 elif new:
392 392 # otherwise, should be an int
393 393 try:
394 394 i = int(new)
395 395 assert i >= 0
396 396 except ValueError:
397 397 raise ValueError("Precision must be int or format string, not %r"%new)
398 398 except AssertionError:
399 399 raise ValueError("int precision must be non-negative, not %r"%i)
400 400
401 401 fmt = '%%.%if'%i
402 402 if 'numpy' in sys.modules:
403 403 # set numpy precision if it has been imported
404 404 import numpy
405 405 numpy.set_printoptions(precision=i)
406 406 else:
407 407 # default back to repr
408 408 fmt = '%r'
409 409 if 'numpy' in sys.modules:
410 410 import numpy
411 411 # numpy default is 8
412 412 numpy.set_printoptions(precision=8)
413 413 self.float_format = fmt
414 414
415 415 # Use the default pretty printers from IPython.external.pretty.
416 416 def _singleton_printers_default(self):
417 417 return pretty._singleton_pprinters.copy()
418 418
419 419 def _type_printers_default(self):
420 420 d = pretty._type_pprinters.copy()
421 421 d[float] = lambda obj,p,cycle: p.text(self.float_format%obj)
422 422 return d
423 423
424 424 def _deferred_printers_default(self):
425 425 return pretty._deferred_type_pprinters.copy()
426 426
427 427 #### FormatterABC interface ####
428 428
429 429 def __call__(self, obj):
430 430 """Compute the pretty representation of the object."""
431 431 if not self.pprint:
432 432 try:
433 433 return repr(obj)
434 434 except TypeError:
435 435 return ''
436 436 else:
437 437 # This uses use StringIO, as cStringIO doesn't handle unicode.
438 438 stream = StringIO()
439 439 # self.newline.encode() is a quick fix for issue gh-597. We need to
440 440 # ensure that stream does not get a mix of unicode and bytestrings,
441 441 # or it will cause trouble.
442 442 printer = pretty.RepresentationPrinter(stream, self.verbose,
443 443 self.max_width, unicode_to_str(self.newline),
444 444 singleton_pprinters=self.singleton_printers,
445 445 type_pprinters=self.type_printers,
446 446 deferred_pprinters=self.deferred_printers)
447 447 printer.pretty(obj)
448 448 printer.flush()
449 449 return stream.getvalue()
450 450
451 451
452 452 class HTMLFormatter(BaseFormatter):
453 453 """An HTML formatter.
454 454
455 455 To define the callables that compute the HTML representation of your
456 456 objects, define a :meth:`_repr_html_` method or use the :meth:`for_type`
457 457 or :meth:`for_type_by_name` methods to register functions that handle
458 458 this.
459 459
460 460 The return value of this formatter should be a valid HTML snippet that
461 461 could be injected into an existing DOM. It should *not* include the
462 462 ```<html>`` or ```<body>`` tags.
463 463 """
464 464 format_type = Unicode('text/html')
465 465
466 466 print_method = ObjectName('_repr_html_')
467 467
468 468
469 469 class SVGFormatter(BaseFormatter):
470 470 """An SVG formatter.
471 471
472 472 To define the callables that compute the SVG representation of your
473 473 objects, define a :meth:`_repr_svg_` method or use the :meth:`for_type`
474 474 or :meth:`for_type_by_name` methods to register functions that handle
475 475 this.
476 476
477 477 The return value of this formatter should be valid SVG enclosed in
478 478 ```<svg>``` tags, that could be injected into an existing DOM. It should
479 479 *not* include the ```<html>`` or ```<body>`` tags.
480 480 """
481 481 format_type = Unicode('image/svg+xml')
482 482
483 483 print_method = ObjectName('_repr_svg_')
484 484
485 485
486 486 class PNGFormatter(BaseFormatter):
487 487 """A PNG formatter.
488 488
489 489 To define the callables that compute the PNG representation of your
490 490 objects, define a :meth:`_repr_png_` method or use the :meth:`for_type`
491 491 or :meth:`for_type_by_name` methods to register functions that handle
492 492 this.
493 493
494 494 The return value of this formatter should be raw PNG data, *not*
495 495 base64 encoded.
496 496 """
497 497 format_type = Unicode('image/png')
498 498
499 499 print_method = ObjectName('_repr_png_')
500 500
501 501
502 502 class JPEGFormatter(BaseFormatter):
503 503 """A JPEG formatter.
504 504
505 505 To define the callables that compute the JPEG representation of your
506 506 objects, define a :meth:`_repr_jpeg_` method or use the :meth:`for_type`
507 507 or :meth:`for_type_by_name` methods to register functions that handle
508 508 this.
509 509
510 510 The return value of this formatter should be raw JPEG data, *not*
511 511 base64 encoded.
512 512 """
513 513 format_type = Unicode('image/jpeg')
514 514
515 515 print_method = ObjectName('_repr_jpeg_')
516 516
517 517
518 518 class LatexFormatter(BaseFormatter):
519 519 """A LaTeX formatter.
520 520
521 521 To define the callables that compute the LaTeX representation of your
522 522 objects, define a :meth:`_repr_latex_` method or use the :meth:`for_type`
523 523 or :meth:`for_type_by_name` methods to register functions that handle
524 524 this.
525 525
526 526 The return value of this formatter should be a valid LaTeX equation,
527 527 enclosed in either ```$``` or ```$$```.
528 528 """
529 529 format_type = Unicode('text/latex')
530 530
531 531 print_method = ObjectName('_repr_latex_')
532 532
533 533
534 534 class JSONFormatter(BaseFormatter):
535 535 """A JSON string formatter.
536 536
537 537 To define the callables that compute the JSON string representation of
538 538 your objects, define a :meth:`_repr_json_` method or use the :meth:`for_type`
539 539 or :meth:`for_type_by_name` methods to register functions that handle
540 540 this.
541 541
542 542 The return value of this formatter should be a valid JSON string.
543 543 """
544 544 format_type = Unicode('application/json')
545 545
546 546 print_method = ObjectName('_repr_json_')
547 547
548 548
549 549 class JavascriptFormatter(BaseFormatter):
550 550 """A Javascript formatter.
551 551
552 552 To define the callables that compute the Javascript representation of
553 553 your objects, define a :meth:`_repr_javascript_` method or use the
554 554 :meth:`for_type` or :meth:`for_type_by_name` methods to register functions
555 555 that handle this.
556 556
557 557 The return value of this formatter should be valid Javascript code and
558 558 should *not* be enclosed in ```<script>``` tags.
559 559 """
560 560 format_type = Unicode('application/javascript')
561 561
562 562 print_method = ObjectName('_repr_javascript_')
563 563
564 564 FormatterABC.register(BaseFormatter)
565 565 FormatterABC.register(PlainTextFormatter)
566 566 FormatterABC.register(HTMLFormatter)
567 567 FormatterABC.register(SVGFormatter)
568 568 FormatterABC.register(PNGFormatter)
569 569 FormatterABC.register(JPEGFormatter)
570 570 FormatterABC.register(LatexFormatter)
571 571 FormatterABC.register(JSONFormatter)
572 572 FormatterABC.register(JavascriptFormatter)
573 573
574 574
575 575 def format_display_data(obj, include=None, exclude=None):
576 576 """Return a format data dict for an object.
577 577
578 578 By default all format types will be computed.
579 579
580 580 The following MIME types are currently implemented:
581 581
582 582 * text/plain
583 583 * text/html
584 584 * text/latex
585 585 * application/json
586 586 * application/javascript
587 587 * image/png
588 588 * image/jpeg
589 589 * image/svg+xml
590 590
591 591 Parameters
592 592 ----------
593 593 obj : object
594 594 The Python object whose format data will be computed.
595 595
596 596 Returns
597 597 -------
598 598 format_dict : dict
599 599 A dictionary of key/value pairs, one or each format that was
600 600 generated for the object. The keys are the format types, which
601 601 will usually be MIME type strings and the values and JSON'able
602 602 data structure containing the raw data for the representation in
603 603 that format.
604 604 include : list or tuple, optional
605 605 A list of format type strings (MIME types) to include in the
606 606 format data dict. If this is set *only* the format types included
607 607 in this list will be computed.
608 608 exclude : list or tuple, optional
609 609 A list of format type string (MIME types) to exclue in the format
610 610 data dict. If this is set all format types will be computed,
611 611 except for those included in this argument.
612 612 """
613 613 from IPython.core.interactiveshell import InteractiveShell
614 614
615 615 InteractiveShell.instance().display_formatter.format(
616 616 obj,
617 617 include,
618 618 exclude
619 619 )
620 620
@@ -1,967 +1,967 b''
1 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 5 # Distributed under the terms of the BSD License.
6 6 #
7 7 # The full license is in the file COPYING.txt, distributed with this software.
8 8 #-----------------------------------------------------------------------------
9 9
10 10 #-----------------------------------------------------------------------------
11 11 # Imports
12 12 #-----------------------------------------------------------------------------
13 13 from __future__ import print_function
14 14
15 15 # Stdlib imports
16 16 import atexit
17 17 import datetime
18 18 import os
19 19 import re
20 20 try:
21 21 import sqlite3
22 22 except ImportError:
23 23 sqlite3 = None
24 24 import threading
25 25
26 26 # Our own packages
27 27 from IPython.config.configurable import Configurable
28 28 from IPython.external.decorator import decorator
29 29 from IPython.testing.skipdoctest import skip_doctest
30 30 from IPython.utils import io
31 31 from IPython.utils.path import locate_profile
32 32 from IPython.utils.traitlets import Bool, Dict, Instance, Integer, List, Unicode
33 33 from IPython.utils.warn import warn
34 34
35 35 #-----------------------------------------------------------------------------
36 36 # Classes and functions
37 37 #-----------------------------------------------------------------------------
38 38
39 39 class DummyDB(object):
40 40 """Dummy DB that will act as a black hole for history.
41 41
42 42 Only used in the absence of sqlite"""
43 43 def execute(*args, **kwargs):
44 44 return []
45 45
46 46 def commit(self, *args, **kwargs):
47 47 pass
48 48
49 49 def __enter__(self, *args, **kwargs):
50 50 pass
51 51
52 52 def __exit__(self, *args, **kwargs):
53 53 pass
54 54
55 55 @decorator
56 56 def needs_sqlite(f,*a,**kw):
57 57 """return an empty list in the absence of sqlite"""
58 58 if sqlite3 is None:
59 59 return []
60 60 else:
61 61 return f(*a,**kw)
62 62
63 63 class HistoryAccessor(Configurable):
64 64 """Access the history database without adding to it.
65 65
66 66 This is intended for use by standalone history tools. IPython shells use
67 67 HistoryManager, below, which is a subclass of this."""
68 68
69 69 # String holding the path to the history file
70 70 hist_file = Unicode(config=True,
71 71 help="""Path to file to use for SQLite history database.
72 72
73 73 By default, IPython will put the history database in the IPython profile
74 74 directory. If you would rather share one history among profiles,
75 75 you ca set this value in each, so that they are consistent.
76 76
77 77 Due to an issue with fcntl, SQLite is known to misbehave on some NFS mounts.
78 78 If you see IPython hanging, try setting this to something on a local disk,
79 79 e.g::
80 80
81 81 ipython --HistoryManager.hist_file=/tmp/ipython_hist.sqlite
82 82
83 83 """)
84 84
85 85
86 86 # The SQLite database
87 87 if sqlite3:
88 88 db = Instance(sqlite3.Connection)
89 89 else:
90 90 db = Instance(DummyDB)
91 91
92 92 def __init__(self, profile='default', hist_file=u'', config=None, **traits):
93 93 """Create a new history accessor.
94 94
95 95 Parameters
96 96 ----------
97 97 profile : str
98 98 The name of the profile from which to open history.
99 99 hist_file : str
100 100 Path to an SQLite history database stored by IPython. If specified,
101 101 hist_file overrides profile.
102 102 config :
103 103 Config object. hist_file can also be set through this.
104 104 """
105 105 # We need a pointer back to the shell for various tasks.
106 106 super(HistoryAccessor, self).__init__(config=config, **traits)
107 107 # defer setting hist_file from kwarg until after init,
108 108 # otherwise the default kwarg value would clobber any value
109 109 # set by config
110 110 if hist_file:
111 111 self.hist_file = hist_file
112 112
113 113 if self.hist_file == u'':
114 114 # No one has set the hist_file, yet.
115 115 self.hist_file = self._get_hist_file_name(profile)
116 116
117 117 if sqlite3 is None:
118 118 warn("IPython History requires SQLite, your history will not be saved\n")
119 119 self.db = DummyDB()
120 120 return
121 121
122 122 try:
123 123 self.init_db()
124 124 except sqlite3.DatabaseError:
125 125 if os.path.isfile(self.hist_file):
126 126 # Try to move the file out of the way
127 127 base,ext = os.path.splitext(self.hist_file)
128 128 newpath = base + '-corrupt' + ext
129 129 os.rename(self.hist_file, newpath)
130 130 print("ERROR! History file wasn't a valid SQLite database.",
131 131 "It was moved to %s" % newpath, "and a new file created.")
132 132 self.init_db()
133 133 else:
134 134 # The hist_file is probably :memory: or something else.
135 135 raise
136 136
137 137 def _get_hist_file_name(self, profile='default'):
138 138 """Find the history file for the given profile name.
139 139
140 140 This is overridden by the HistoryManager subclass, to use the shell's
141 141 active profile.
142 142
143 143 Parameters
144 144 ----------
145 145 profile : str
146 146 The name of a profile which has a history file.
147 147 """
148 148 return os.path.join(locate_profile(profile), 'history.sqlite')
149 149
150 150 def init_db(self):
151 151 """Connect to the database, and create tables if necessary."""
152 152 # use detect_types so that timestamps return datetime objects
153 153 self.db = sqlite3.connect(self.hist_file, detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
154 154 self.db.execute("""CREATE TABLE IF NOT EXISTS sessions (session integer
155 155 primary key autoincrement, start timestamp,
156 156 end timestamp, num_cmds integer, remark text)""")
157 157 self.db.execute("""CREATE TABLE IF NOT EXISTS history
158 158 (session integer, line integer, source text, source_raw text,
159 159 PRIMARY KEY (session, line))""")
160 160 # Output history is optional, but ensure the table's there so it can be
161 161 # enabled later.
162 162 self.db.execute("""CREATE TABLE IF NOT EXISTS output_history
163 163 (session integer, line integer, output text,
164 164 PRIMARY KEY (session, line))""")
165 165 self.db.commit()
166 166
167 167 def writeout_cache(self):
168 168 """Overridden by HistoryManager to dump the cache before certain
169 169 database lookups."""
170 170 pass
171 171
172 172 ## -------------------------------
173 173 ## Methods for retrieving history:
174 174 ## -------------------------------
175 175 def _run_sql(self, sql, params, raw=True, output=False):
176 176 """Prepares and runs an SQL query for the history database.
177 177
178 178 Parameters
179 179 ----------
180 180 sql : str
181 181 Any filtering expressions to go after SELECT ... FROM ...
182 182 params : tuple
183 183 Parameters passed to the SQL query (to replace "?")
184 184 raw, output : bool
185 185 See :meth:`get_range`
186 186
187 187 Returns
188 188 -------
189 189 Tuples as :meth:`get_range`
190 190 """
191 191 toget = 'source_raw' if raw else 'source'
192 192 sqlfrom = "history"
193 193 if output:
194 194 sqlfrom = "history LEFT JOIN output_history USING (session, line)"
195 195 toget = "history.%s, output_history.output" % toget
196 196 cur = self.db.execute("SELECT session, line, %s FROM %s " %\
197 197 (toget, sqlfrom) + sql, params)
198 198 if output: # Regroup into 3-tuples, and parse JSON
199 199 return ((ses, lin, (inp, out)) for ses, lin, inp, out in cur)
200 200 return cur
201 201
202 202 @needs_sqlite
203 203 def get_session_info(self, session=0):
204 204 """get info about a session
205 205
206 206 Parameters
207 207 ----------
208 208
209 209 session : int
210 210 Session number to retrieve. The current session is 0, and negative
211 211 numbers count back from current session, so -1 is previous session.
212 212
213 213 Returns
214 214 -------
215 215
216 216 (session_id [int], start [datetime], end [datetime], num_cmds [int], remark [unicode])
217 217
218 218 Sessions that are running or did not exit cleanly will have `end=None`
219 219 and `num_cmds=None`.
220 220
221 221 """
222 222
223 223 if session <= 0:
224 224 session += self.session_number
225 225
226 226 query = "SELECT * from sessions where session == ?"
227 227 return self.db.execute(query, (session,)).fetchone()
228 228
229 229 def get_tail(self, n=10, raw=True, output=False, include_latest=False):
230 230 """Get the last n lines from the history database.
231 231
232 232 Parameters
233 233 ----------
234 234 n : int
235 235 The number of lines to get
236 236 raw, output : bool
237 237 See :meth:`get_range`
238 238 include_latest : bool
239 239 If False (default), n+1 lines are fetched, and the latest one
240 240 is discarded. This is intended to be used where the function
241 241 is called by a user command, which it should not return.
242 242
243 243 Returns
244 244 -------
245 245 Tuples as :meth:`get_range`
246 246 """
247 247 self.writeout_cache()
248 248 if not include_latest:
249 249 n += 1
250 250 cur = self._run_sql("ORDER BY session DESC, line DESC LIMIT ?",
251 251 (n,), raw=raw, output=output)
252 252 if not include_latest:
253 253 return reversed(list(cur)[1:])
254 254 return reversed(list(cur))
255 255
256 256 def search(self, pattern="*", raw=True, search_raw=True,
257 257 output=False):
258 258 """Search the database using unix glob-style matching (wildcards
259 259 * and ?).
260 260
261 261 Parameters
262 262 ----------
263 263 pattern : str
264 264 The wildcarded pattern to match when searching
265 265 search_raw : bool
266 266 If True, search the raw input, otherwise, the parsed input
267 267 raw, output : bool
268 268 See :meth:`get_range`
269 269
270 270 Returns
271 271 -------
272 272 Tuples as :meth:`get_range`
273 273 """
274 274 tosearch = "source_raw" if search_raw else "source"
275 275 if output:
276 276 tosearch = "history." + tosearch
277 277 self.writeout_cache()
278 278 return self._run_sql("WHERE %s GLOB ?" % tosearch, (pattern,),
279 279 raw=raw, output=output)
280 280
281 281 def get_range(self, session, start=1, stop=None, raw=True,output=False):
282 282 """Retrieve input by session.
283 283
284 284 Parameters
285 285 ----------
286 286 session : int
287 287 Session number to retrieve.
288 288 start : int
289 289 First line to retrieve.
290 290 stop : int
291 291 End of line range (excluded from output itself). If None, retrieve
292 292 to the end of the session.
293 293 raw : bool
294 294 If True, return untranslated input
295 295 output : bool
296 296 If True, attempt to include output. This will be 'real' Python
297 297 objects for the current session, or text reprs from previous
298 298 sessions if db_log_output was enabled at the time. Where no output
299 299 is found, None is used.
300 300
301 301 Returns
302 302 -------
303 303 An iterator over the desired lines. Each line is a 3-tuple, either
304 304 (session, line, input) if output is False, or
305 305 (session, line, (input, output)) if output is True.
306 306 """
307 307 if stop:
308 308 lineclause = "line >= ? AND line < ?"
309 309 params = (session, start, stop)
310 310 else:
311 311 lineclause = "line>=?"
312 312 params = (session, start)
313 313
314 314 return self._run_sql("WHERE session==? AND %s""" % lineclause,
315 315 params, raw=raw, output=output)
316 316
317 317 def get_range_by_str(self, rangestr, raw=True, output=False):
318 318 """Get lines of history from a string of ranges, as used by magic
319 319 commands %hist, %save, %macro, etc.
320 320
321 321 Parameters
322 322 ----------
323 323 rangestr : str
324 324 A string specifying ranges, e.g. "5 ~2/1-4". See
325 325 :func:`magic_history` for full details.
326 326 raw, output : bool
327 327 As :meth:`get_range`
328 328
329 329 Returns
330 330 -------
331 331 Tuples as :meth:`get_range`
332 332 """
333 333 for sess, s, e in extract_hist_ranges(rangestr):
334 334 for line in self.get_range(sess, s, e, raw=raw, output=output):
335 335 yield line
336 336
337 337
338 338 class HistoryManager(HistoryAccessor):
339 339 """A class to organize all history-related functionality in one place.
340 340 """
341 341 # Public interface
342 342
343 343 # An instance of the IPython shell we are attached to
344 344 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
345 345 # Lists to hold processed and raw history. These start with a blank entry
346 346 # so that we can index them starting from 1
347 347 input_hist_parsed = List([""])
348 348 input_hist_raw = List([""])
349 349 # A list of directories visited during session
350 350 dir_hist = List()
351 351 def _dir_hist_default(self):
352 352 try:
353 353 return [os.getcwdu()]
354 354 except OSError:
355 355 return []
356 356
357 357 # A dict of output history, keyed with ints from the shell's
358 358 # execution count.
359 359 output_hist = Dict()
360 360 # The text/plain repr of outputs.
361 361 output_hist_reprs = Dict()
362 362
363 363 # The number of the current session in the history database
364 364 session_number = Integer()
365 365 # Should we log output to the database? (default no)
366 366 db_log_output = Bool(False, config=True)
367 367 # Write to database every x commands (higher values save disk access & power)
368 368 # Values of 1 or less effectively disable caching.
369 369 db_cache_size = Integer(0, config=True)
370 370 # The input and output caches
371 371 db_input_cache = List()
372 372 db_output_cache = List()
373 373
374 374 # History saving in separate thread
375 375 save_thread = Instance('IPython.core.history.HistorySavingThread')
376 376 try: # Event is a function returning an instance of _Event...
377 377 save_flag = Instance(threading._Event)
378 378 except AttributeError: # ...until Python 3.3, when it's a class.
379 379 save_flag = Instance(threading.Event)
380 380
381 381 # Private interface
382 382 # Variables used to store the three last inputs from the user. On each new
383 383 # history update, we populate the user's namespace with these, shifted as
384 384 # necessary.
385 385 _i00 = Unicode(u'')
386 386 _i = Unicode(u'')
387 387 _ii = Unicode(u'')
388 388 _iii = Unicode(u'')
389 389
390 390 # A regex matching all forms of the exit command, so that we don't store
391 391 # them in the history (it's annoying to rewind the first entry and land on
392 392 # an exit call).
393 393 _exit_re = re.compile(r"(exit|quit)(\s*\(.*\))?$")
394 394
395 395 def __init__(self, shell=None, config=None, **traits):
396 396 """Create a new history manager associated with a shell instance.
397 397 """
398 398 # We need a pointer back to the shell for various tasks.
399 399 super(HistoryManager, self).__init__(shell=shell, config=config,
400 400 **traits)
401 401 self.save_flag = threading.Event()
402 402 self.db_input_cache_lock = threading.Lock()
403 403 self.db_output_cache_lock = threading.Lock()
404 404 self.save_thread = HistorySavingThread(self)
405 405 self.save_thread.start()
406 406
407 407 self.new_session()
408 408
409 409 def _get_hist_file_name(self, profile=None):
410 410 """Get default history file name based on the Shell's profile.
411 411
412 412 The profile parameter is ignored, but must exist for compatibility with
413 413 the parent class."""
414 414 profile_dir = self.shell.profile_dir.location
415 415 return os.path.join(profile_dir, 'history.sqlite')
416 416
417 417 @needs_sqlite
418 418 def new_session(self, conn=None):
419 419 """Get a new session number."""
420 420 if conn is None:
421 421 conn = self.db
422 422
423 423 with conn:
424 424 cur = conn.execute("""INSERT INTO sessions VALUES (NULL, ?, NULL,
425 425 NULL, "") """, (datetime.datetime.now(),))
426 426 self.session_number = cur.lastrowid
427 427
428 428 def end_session(self):
429 429 """Close the database session, filling in the end time and line count."""
430 430 self.writeout_cache()
431 431 with self.db:
432 432 self.db.execute("""UPDATE sessions SET end=?, num_cmds=? WHERE
433 433 session==?""", (datetime.datetime.now(),
434 434 len(self.input_hist_parsed)-1, self.session_number))
435 435 self.session_number = 0
436 436
437 437 def name_session(self, name):
438 438 """Give the current session a name in the history database."""
439 439 with self.db:
440 440 self.db.execute("UPDATE sessions SET remark=? WHERE session==?",
441 441 (name, self.session_number))
442 442
443 443 def reset(self, new_session=True):
444 444 """Clear the session history, releasing all object references, and
445 445 optionally open a new session."""
446 446 self.output_hist.clear()
447 447 # The directory history can't be completely empty
448 448 self.dir_hist[:] = [os.getcwdu()]
449 449
450 450 if new_session:
451 451 if self.session_number:
452 452 self.end_session()
453 453 self.input_hist_parsed[:] = [""]
454 454 self.input_hist_raw[:] = [""]
455 455 self.new_session()
456 456
457 457 # ------------------------------
458 458 # Methods for retrieving history
459 459 # ------------------------------
460 460 def _get_range_session(self, start=1, stop=None, raw=True, output=False):
461 461 """Get input and output history from the current session. Called by
462 462 get_range, and takes similar parameters."""
463 463 input_hist = self.input_hist_raw if raw else self.input_hist_parsed
464 464
465 465 n = len(input_hist)
466 466 if start < 0:
467 467 start += n
468 468 if not stop or (stop > n):
469 469 stop = n
470 470 elif stop < 0:
471 471 stop += n
472 472
473 473 for i in range(start, stop):
474 474 if output:
475 475 line = (input_hist[i], self.output_hist_reprs.get(i))
476 476 else:
477 477 line = input_hist[i]
478 478 yield (0, i, line)
479 479
480 480 def get_range(self, session=0, start=1, stop=None, raw=True,output=False):
481 481 """Retrieve input by session.
482 482
483 483 Parameters
484 484 ----------
485 485 session : int
486 486 Session number to retrieve. The current session is 0, and negative
487 487 numbers count back from current session, so -1 is previous session.
488 488 start : int
489 489 First line to retrieve.
490 490 stop : int
491 491 End of line range (excluded from output itself). If None, retrieve
492 492 to the end of the session.
493 493 raw : bool
494 494 If True, return untranslated input
495 495 output : bool
496 496 If True, attempt to include output. This will be 'real' Python
497 497 objects for the current session, or text reprs from previous
498 498 sessions if db_log_output was enabled at the time. Where no output
499 499 is found, None is used.
500 500
501 501 Returns
502 502 -------
503 503 An iterator over the desired lines. Each line is a 3-tuple, either
504 504 (session, line, input) if output is False, or
505 505 (session, line, (input, output)) if output is True.
506 506 """
507 507 if session <= 0:
508 508 session += self.session_number
509 509 if session==self.session_number: # Current session
510 510 return self._get_range_session(start, stop, raw, output)
511 511 return super(HistoryManager, self).get_range(session, start, stop, raw, output)
512 512
513 513 ## ----------------------------
514 514 ## Methods for storing history:
515 515 ## ----------------------------
516 516 def store_inputs(self, line_num, source, source_raw=None):
517 517 """Store source and raw input in history and create input cache
518 518 variables _i*.
519 519
520 520 Parameters
521 521 ----------
522 522 line_num : int
523 523 The prompt number of this input.
524 524
525 525 source : str
526 526 Python input.
527 527
528 528 source_raw : str, optional
529 529 If given, this is the raw input without any IPython transformations
530 530 applied to it. If not given, ``source`` is used.
531 531 """
532 532 if source_raw is None:
533 533 source_raw = source
534 534 source = source.rstrip('\n')
535 535 source_raw = source_raw.rstrip('\n')
536 536
537 537 # do not store exit/quit commands
538 538 if self._exit_re.match(source_raw.strip()):
539 539 return
540 540
541 541 self.input_hist_parsed.append(source)
542 542 self.input_hist_raw.append(source_raw)
543 543
544 544 with self.db_input_cache_lock:
545 545 self.db_input_cache.append((line_num, source, source_raw))
546 546 # Trigger to flush cache and write to DB.
547 547 if len(self.db_input_cache) >= self.db_cache_size:
548 548 self.save_flag.set()
549 549
550 550 # update the auto _i variables
551 551 self._iii = self._ii
552 552 self._ii = self._i
553 553 self._i = self._i00
554 554 self._i00 = source_raw
555 555
556 556 # hackish access to user namespace to create _i1,_i2... dynamically
557 557 new_i = '_i%s' % line_num
558 558 to_main = {'_i': self._i,
559 559 '_ii': self._ii,
560 560 '_iii': self._iii,
561 561 new_i : self._i00 }
562 562 self.shell.user_ns.update(to_main)
563 563
564 564 def store_output(self, line_num):
565 565 """If database output logging is enabled, this saves all the
566 566 outputs from the indicated prompt number to the database. It's
567 567 called by run_cell after code has been executed.
568 568
569 569 Parameters
570 570 ----------
571 571 line_num : int
572 572 The line number from which to save outputs
573 573 """
574 574 if (not self.db_log_output) or (line_num not in self.output_hist_reprs):
575 575 return
576 576 output = self.output_hist_reprs[line_num]
577 577
578 578 with self.db_output_cache_lock:
579 579 self.db_output_cache.append((line_num, output))
580 580 if self.db_cache_size <= 1:
581 581 self.save_flag.set()
582 582
583 583 def _writeout_input_cache(self, conn):
584 584 with conn:
585 585 for line in self.db_input_cache:
586 586 conn.execute("INSERT INTO history VALUES (?, ?, ?, ?)",
587 587 (self.session_number,)+line)
588 588
589 589 def _writeout_output_cache(self, conn):
590 590 with conn:
591 591 for line in self.db_output_cache:
592 592 conn.execute("INSERT INTO output_history VALUES (?, ?, ?)",
593 593 (self.session_number,)+line)
594 594
595 595 @needs_sqlite
596 596 def writeout_cache(self, conn=None):
597 597 """Write any entries in the cache to the database."""
598 598 if conn is None:
599 599 conn = self.db
600 600
601 601 with self.db_input_cache_lock:
602 602 try:
603 603 self._writeout_input_cache(conn)
604 604 except sqlite3.IntegrityError:
605 605 self.new_session(conn)
606 606 print("ERROR! Session/line number was not unique in",
607 607 "database. History logging moved to new session",
608 608 self.session_number)
609 609 try: # Try writing to the new session. If this fails, don't recurse
610 610 self._writeout_input_cache(conn)
611 611 except sqlite3.IntegrityError:
612 612 pass
613 613 finally:
614 614 self.db_input_cache = []
615 615
616 616 with self.db_output_cache_lock:
617 617 try:
618 618 self._writeout_output_cache(conn)
619 619 except sqlite3.IntegrityError:
620 620 print("!! Session/line number for output was not unique",
621 621 "in database. Output will not be stored.")
622 622 finally:
623 623 self.db_output_cache = []
624 624
625 625
626 626 class HistorySavingThread(threading.Thread):
627 627 """This thread takes care of writing history to the database, so that
628 628 the UI isn't held up while that happens.
629 629
630 630 It waits for the HistoryManager's save_flag to be set, then writes out
631 631 the history cache. The main thread is responsible for setting the flag when
632 632 the cache size reaches a defined threshold."""
633 633 daemon = True
634 634 stop_now = False
635 635 def __init__(self, history_manager):
636 636 super(HistorySavingThread, self).__init__()
637 637 self.history_manager = history_manager
638 638 atexit.register(self.stop)
639 639
640 640 @needs_sqlite
641 641 def run(self):
642 642 # We need a separate db connection per thread:
643 643 try:
644 644 self.db = sqlite3.connect(self.history_manager.hist_file)
645 645 while True:
646 646 self.history_manager.save_flag.wait()
647 647 if self.stop_now:
648 648 return
649 649 self.history_manager.save_flag.clear()
650 650 self.history_manager.writeout_cache(self.db)
651 651 except Exception as e:
652 652 print(("The history saving thread hit an unexpected error (%s)."
653 653 "History will not be written to the database.") % repr(e))
654 654
655 655 def stop(self):
656 656 """This can be called from the main thread to safely stop this thread.
657 657
658 658 Note that it does not attempt to write out remaining history before
659 659 exiting. That should be done by calling the HistoryManager's
660 660 end_session method."""
661 661 self.stop_now = True
662 662 self.history_manager.save_flag.set()
663 663 self.join()
664 664
665 665
666 666 # To match, e.g. ~5/8-~2/3
667 667 range_re = re.compile(r"""
668 668 ((?P<startsess>~?\d+)/)?
669 669 (?P<start>\d+) # Only the start line num is compulsory
670 670 ((?P<sep>[\-:])
671 671 ((?P<endsess>~?\d+)/)?
672 672 (?P<end>\d+))?
673 673 $""", re.VERBOSE)
674 674
675 675 def extract_hist_ranges(ranges_str):
676 676 """Turn a string of history ranges into 3-tuples of (session, start, stop).
677 677
678 678 Examples
679 679 --------
680 680 list(extract_input_ranges("~8/5-~7/4 2"))
681 681 [(-8, 5, None), (-7, 1, 4), (0, 2, 3)]
682 682 """
683 683 for range_str in ranges_str.split():
684 684 rmatch = range_re.match(range_str)
685 685 if not rmatch:
686 686 continue
687 687 start = int(rmatch.group("start"))
688 688 end = rmatch.group("end")
689 689 end = int(end) if end else start+1 # If no end specified, get (a, a+1)
690 690 if rmatch.group("sep") == "-": # 1-3 == 1:4 --> [1, 2, 3]
691 691 end += 1
692 692 startsess = rmatch.group("startsess") or "0"
693 693 endsess = rmatch.group("endsess") or startsess
694 694 startsess = int(startsess.replace("~","-"))
695 695 endsess = int(endsess.replace("~","-"))
696 696 assert endsess >= startsess
697 697
698 698 if endsess == startsess:
699 699 yield (startsess, start, end)
700 700 continue
701 701 # Multiple sessions in one range:
702 702 yield (startsess, start, None)
703 703 for sess in range(startsess+1, endsess):
704 704 yield (sess, 1, None)
705 705 yield (endsess, 1, end)
706 706
707 707 def _format_lineno(session, line):
708 708 """Helper function to format line numbers properly."""
709 709 if session == 0:
710 710 return str(line)
711 711 return "%s#%s" % (session, line)
712 712
713 713 @skip_doctest
714 714 def magic_history(self, parameter_s = ''):
715 715 """Print input history (_i<n> variables), with most recent last.
716 716
717 717 %history -> print at most 40 inputs (some may be multi-line)\\
718 718 %history n -> print at most n inputs\\
719 719 %history n1 n2 -> print inputs between n1 and n2 (n2 not included)\\
720 720
721 721 By default, input history is printed without line numbers so it can be
722 722 directly pasted into an editor. Use -n to show them.
723 723
724 724 Ranges of history can be indicated using the syntax:
725 725 4 : Line 4, current session
726 726 4-6 : Lines 4-6, current session
727 727 243/1-5: Lines 1-5, session 243
728 728 ~2/7 : Line 7, session 2 before current
729 729 ~8/1-~6/5 : From the first line of 8 sessions ago, to the fifth line
730 730 of 6 sessions ago.
731 731 Multiple ranges can be entered, separated by spaces
732 732
733 733 The same syntax is used by %macro, %save, %edit, %rerun
734 734
735 735 Options:
736 736
737 737 -n: print line numbers for each input.
738 738 This feature is only available if numbered prompts are in use.
739 739
740 740 -o: also print outputs for each input.
741 741
742 742 -p: print classic '>>>' python prompts before each input. This is useful
743 743 for making documentation, and in conjunction with -o, for producing
744 744 doctest-ready output.
745 745
746 746 -r: (default) print the 'raw' history, i.e. the actual commands you typed.
747 747
748 748 -t: print the 'translated' history, as IPython understands it. IPython
749 749 filters your input and converts it all into valid Python source before
750 750 executing it (things like magics or aliases are turned into function
751 751 calls, for example). With this option, you'll see the native history
752 752 instead of the user-entered version: '%cd /' will be seen as
753 753 'get_ipython().magic("%cd /")' instead of '%cd /'.
754 754
755 755 -g: treat the arg as a pattern to grep for in (full) history.
756 756 This includes the saved history (almost all commands ever written).
757 757 Use '%hist -g' to show full saved history (may be very long).
758 758
759 759 -l: get the last n lines from all sessions. Specify n as a single arg, or
760 760 the default is the last 10 lines.
761 761
762 762 -f FILENAME: instead of printing the output to the screen, redirect it to
763 763 the given file. The file is always overwritten, though IPython asks for
764 764 confirmation first if it already exists.
765 765
766 766 Examples
767 767 --------
768 768 ::
769 769
770 770 In [6]: %hist -n 4 6
771 771 4:a = 12
772 772 5:print a**2
773 773
774 774 """
775 775
776 776 if not self.shell.displayhook.do_full_cache:
777 777 print('This feature is only available if numbered prompts are in use.')
778 778 return
779 779 opts,args = self.parse_options(parameter_s,'noprtglf:',mode='string')
780 780
781 781 # For brevity
782 782 history_manager = self.shell.history_manager
783 783
784 784 def _format_lineno(session, line):
785 785 """Helper function to format line numbers properly."""
786 786 if session in (0, history_manager.session_number):
787 787 return str(line)
788 788 return "%s/%s" % (session, line)
789 789
790 790 # Check if output to specific file was requested.
791 791 try:
792 792 outfname = opts['f']
793 793 except KeyError:
794 794 outfile = io.stdout # default
795 795 # We don't want to close stdout at the end!
796 796 close_at_end = False
797 797 else:
798 798 if os.path.exists(outfname):
799 799 if not io.ask_yes_no("File %r exists. Overwrite?" % outfname):
800 800 print('Aborting.')
801 801 return
802 802
803 803 outfile = open(outfname,'w')
804 804 close_at_end = True
805 805
806 806 print_nums = 'n' in opts
807 807 get_output = 'o' in opts
808 808 pyprompts = 'p' in opts
809 809 # Raw history is the default
810 810 raw = not('t' in opts)
811 811
812 812 default_length = 40
813 813 pattern = None
814 814
815 815 if 'g' in opts: # Glob search
816 816 pattern = "*" + args + "*" if args else "*"
817 817 hist = history_manager.search(pattern, raw=raw, output=get_output)
818 818 print_nums = True
819 819 elif 'l' in opts: # Get 'tail'
820 820 try:
821 821 n = int(args)
822 822 except ValueError, IndexError:
823 823 n = 10
824 824 hist = history_manager.get_tail(n, raw=raw, output=get_output)
825 825 else:
826 826 if args: # Get history by ranges
827 827 hist = history_manager.get_range_by_str(args, raw, get_output)
828 828 else: # Just get history for the current session
829 829 hist = history_manager.get_range(raw=raw, output=get_output)
830 830
831 831 # We could be displaying the entire history, so let's not try to pull it
832 832 # into a list in memory. Anything that needs more space will just misalign.
833 833 width = 4
834 834
835 835 for session, lineno, inline in hist:
836 836 # Print user history with tabs expanded to 4 spaces. The GUI clients
837 837 # use hard tabs for easier usability in auto-indented code, but we want
838 838 # to produce PEP-8 compliant history for safe pasting into an editor.
839 839 if get_output:
840 840 inline, output = inline
841 841 inline = inline.expandtabs(4).rstrip()
842 842
843 843 multiline = "\n" in inline
844 844 line_sep = '\n' if multiline else ' '
845 845 if print_nums:
846 846 print('%s:%s' % (_format_lineno(session, lineno).rjust(width),
847 847 line_sep), file=outfile, end='')
848 848 if pyprompts:
849 849 print(">>> ", end="", file=outfile)
850 850 if multiline:
851 851 inline = "\n... ".join(inline.splitlines()) + "\n..."
852 852 print(inline, file=outfile)
853 853 if get_output and output:
854 854 print(output, file=outfile)
855 855
856 856 if close_at_end:
857 857 outfile.close()
858 858
859 859
860 860 def magic_rep(self, arg):
861 861 r"""Repeat a command, or get command to input line for editing.
862 862
863 863 %recall and %rep are equivalent.
864 864
865 865 - %recall (no arguments):
866 866
867 867 Place a string version of last computation result (stored in the special '_'
868 868 variable) to the next input prompt. Allows you to create elaborate command
869 869 lines without using copy-paste::
870 870
871 871 In[1]: l = ["hei", "vaan"]
872 872 In[2]: "".join(l)
873 873 Out[2]: heivaan
874 874 In[3]: %rep
875 875 In[4]: heivaan_ <== cursor blinking
876 876
877 877 %recall 45
878 878
879 879 Place history line 45 on the next input prompt. Use %hist to find
880 880 out the number.
881 881
882 882 %recall 1-4
883 883
884 884 Combine the specified lines into one cell, and place it on the next
885 885 input prompt. See %history for the slice syntax.
886 886
887 887 %recall foo+bar
888 888
889 889 If foo+bar can be evaluated in the user namespace, the result is
890 890 placed at the next input prompt. Otherwise, the history is searched
891 891 for lines which contain that substring, and the most recent one is
892 892 placed at the next input prompt.
893 893 """
894 894 if not arg: # Last output
895 895 self.set_next_input(str(self.shell.user_ns["_"]))
896 896 return
897 897 # Get history range
898 898 histlines = self.history_manager.get_range_by_str(arg)
899 899 cmd = "\n".join(x[2] for x in histlines)
900 900 if cmd:
901 901 self.set_next_input(cmd.rstrip())
902 902 return
903 903
904 904 try: # Variable in user namespace
905 905 cmd = str(eval(arg, self.shell.user_ns))
906 906 except Exception: # Search for term in history
907 907 histlines = self.history_manager.search("*"+arg+"*")
908 908 for h in reversed([x[2] for x in histlines]):
909 909 if 'rep' in h:
910 910 continue
911 911 self.set_next_input(h.rstrip())
912 912 return
913 913 else:
914 914 self.set_next_input(cmd.rstrip())
915 915 print("Couldn't evaluate or find in history:", arg)
916 916
917 917 def magic_rerun(self, parameter_s=''):
918 918 """Re-run previous input
919 919
920 920 By default, you can specify ranges of input history to be repeated
921 921 (as with %history). With no arguments, it will repeat the last line.
922 922
923 923 Options:
924 924
925 925 -l <n> : Repeat the last n lines of input, not including the
926 926 current command.
927 927
928 928 -g foo : Repeat the most recent line which contains foo
929 929 """
930 930 opts, args = self.parse_options(parameter_s, 'l:g:', mode='string')
931 931 if "l" in opts: # Last n lines
932 932 n = int(opts['l'])
933 933 hist = self.history_manager.get_tail(n)
934 934 elif "g" in opts: # Search
935 935 p = "*"+opts['g']+"*"
936 936 hist = list(self.history_manager.search(p))
937 937 for l in reversed(hist):
938 938 if "rerun" not in l[2]:
939 939 hist = [l] # The last match which isn't a %rerun
940 940 break
941 941 else:
942 942 hist = [] # No matches except %rerun
943 943 elif args: # Specify history ranges
944 944 hist = self.history_manager.get_range_by_str(args)
945 945 else: # Last line
946 946 hist = self.history_manager.get_tail(1)
947 947 hist = [x[2] for x in hist]
948 948 if not hist:
949 949 print("No lines in history match specification")
950 950 return
951 951 histlines = "\n".join(hist)
952 952 print("=== Executing: ===")
953 953 print(histlines)
954 954 print("=== Output: ===")
955 955 self.run_cell("\n".join(hist), store_history=False)
956 956
957 957
958 958 def init_ipython(ip):
959 959 ip.define_magic("rep", magic_rep)
960 960 ip.define_magic("recall", magic_rep)
961 961 ip.define_magic("rerun", magic_rerun)
962 962 ip.define_magic("hist",magic_history) # Alternative name
963 963 ip.define_magic("history",magic_history)
964 964
965 965 # XXX - ipy_completers are in quarantine, need to be updated to new apis
966 966 #import ipy_completers
967 967 #ipy_completers.quick_completer('%hist' ,'-g -t -r -n')
@@ -1,767 +1,767 b''
1 1 """Analysis of text input into executable blocks.
2 2
3 3 The main class in this module, :class:`InputSplitter`, is designed to break
4 4 input from either interactive, line-by-line environments or block-based ones,
5 5 into standalone blocks that can be executed by Python as 'single' statements
6 6 (thus triggering sys.displayhook).
7 7
8 8 A companion, :class:`IPythonInputSplitter`, provides the same functionality but
9 9 with full support for the extended IPython syntax (magics, system calls, etc).
10 10
11 11 For more details, see the class docstring below.
12 12
13 13 Syntax Transformations
14 14 ----------------------
15 15
16 16 One of the main jobs of the code in this file is to apply all syntax
17 17 transformations that make up 'the IPython language', i.e. magics, shell
18 18 escapes, etc. All transformations should be implemented as *fully stateless*
19 19 entities, that simply take one line as their input and return a line.
20 20 Internally for implementation purposes they may be a normal function or a
21 21 callable object, but the only input they receive will be a single line and they
22 22 should only return a line, without holding any data-dependent state between
23 23 calls.
24 24
25 25 As an example, the EscapedTransformer is a class so we can more clearly group
26 26 together the functionality of dispatching to individual functions based on the
27 27 starting escape character, but the only method for public use is its call
28 28 method.
29 29
30 30
31 31 ToDo
32 32 ----
33 33
34 34 - Should we make push() actually raise an exception once push_accepts_more()
35 35 returns False?
36 36
37 37 - Naming cleanups. The tr_* names aren't the most elegant, though now they are
38 38 at least just attributes of a class so not really very exposed.
39 39
40 40 - Think about the best way to support dynamic things: automagic, autocall,
41 41 macros, etc.
42 42
43 43 - Think of a better heuristic for the application of the transforms in
44 44 IPythonInputSplitter.push() than looking at the buffer ending in ':'. Idea:
45 45 track indentation change events (indent, dedent, nothing) and apply them only
46 46 if the indentation went up, but not otherwise.
47 47
48 48 - Think of the cleanest way for supporting user-specified transformations (the
49 49 user prefilters we had before).
50 50
51 51 Authors
52 52 -------
53 53
54 54 * Fernando Perez
55 55 * Brian Granger
56 56 """
57 57 #-----------------------------------------------------------------------------
58 # Copyright (C) 2010 The IPython Development Team
58 # Copyright (C) 2010-2011 The IPython Development Team
59 59 #
60 60 # Distributed under the terms of the BSD License. The full license is in
61 61 # the file COPYING, distributed as part of this software.
62 62 #-----------------------------------------------------------------------------
63 63 from __future__ import print_function
64 64
65 65 #-----------------------------------------------------------------------------
66 66 # Imports
67 67 #-----------------------------------------------------------------------------
68 68 # stdlib
69 69 import ast
70 70 import codeop
71 71 import re
72 72 import sys
73 73 import tokenize
74 74 from StringIO import StringIO
75 75
76 76 # IPython modules
77 77 from IPython.core.splitinput import split_user_input, LineInfo
78 78 from IPython.utils.py3compat import cast_unicode
79 79
80 80 #-----------------------------------------------------------------------------
81 81 # Globals
82 82 #-----------------------------------------------------------------------------
83 83
84 84 # The escape sequences that define the syntax transformations IPython will
85 85 # apply to user input. These can NOT be just changed here: many regular
86 86 # expressions and other parts of the code may use their hardcoded values, and
87 87 # for all intents and purposes they constitute the 'IPython syntax', so they
88 88 # should be considered fixed.
89 89
90 90 ESC_SHELL = '!' # Send line to underlying system shell
91 91 ESC_SH_CAP = '!!' # Send line to system shell and capture output
92 92 ESC_HELP = '?' # Find information about object
93 93 ESC_HELP2 = '??' # Find extra-detailed information about object
94 94 ESC_MAGIC = '%' # Call magic function
95 95 ESC_QUOTE = ',' # Split args on whitespace, quote each as string and call
96 96 ESC_QUOTE2 = ';' # Quote all args as a single string, call
97 97 ESC_PAREN = '/' # Call first argument with rest of line as arguments
98 98
99 99 #-----------------------------------------------------------------------------
100 100 # Utilities
101 101 #-----------------------------------------------------------------------------
102 102
103 103 # FIXME: These are general-purpose utilities that later can be moved to the
104 104 # general ward. Kept here for now because we're being very strict about test
105 105 # coverage with this code, and this lets us ensure that we keep 100% coverage
106 106 # while developing.
107 107
108 108 # compiled regexps for autoindent management
109 109 dedent_re = re.compile('|'.join([
110 110 r'^\s+raise(\s.*)?$', # raise statement (+ space + other stuff, maybe)
111 111 r'^\s+raise\([^\)]*\).*$', # wacky raise with immediate open paren
112 112 r'^\s+return(\s.*)?$', # normal return (+ space + other stuff, maybe)
113 113 r'^\s+return\([^\)]*\).*$', # wacky return with immediate open paren
114 114 r'^\s+pass\s*$' # pass (optionally followed by trailing spaces)
115 115 ]))
116 116 ini_spaces_re = re.compile(r'^([ \t\r\f\v]+)')
117 117
118 118 # regexp to match pure comment lines so we don't accidentally insert 'if 1:'
119 119 # before pure comments
120 120 comment_line_re = re.compile('^\s*\#')
121 121
122 122
123 123 def num_ini_spaces(s):
124 124 """Return the number of initial spaces in a string.
125 125
126 126 Note that tabs are counted as a single space. For now, we do *not* support
127 127 mixing of tabs and spaces in the user's input.
128 128
129 129 Parameters
130 130 ----------
131 131 s : string
132 132
133 133 Returns
134 134 -------
135 135 n : int
136 136 """
137 137
138 138 ini_spaces = ini_spaces_re.match(s)
139 139 if ini_spaces:
140 140 return ini_spaces.end()
141 141 else:
142 142 return 0
143 143
144 144
145 145 def remove_comments(src):
146 146 """Remove all comments from input source.
147 147
148 148 Note: comments are NOT recognized inside of strings!
149 149
150 150 Parameters
151 151 ----------
152 152 src : string
153 153 A single or multiline input string.
154 154
155 155 Returns
156 156 -------
157 157 String with all Python comments removed.
158 158 """
159 159
160 160 return re.sub('#.*', '', src)
161 161
162 162 def has_comment(src):
163 163 """Indicate whether an input line has (i.e. ends in, or is) a comment.
164 164
165 165 This uses tokenize, so it can distinguish comments from # inside strings.
166 166
167 167 Parameters
168 168 ----------
169 169 src : string
170 170 A single line input string.
171 171
172 172 Returns
173 173 -------
174 174 Boolean: True if source has a comment.
175 175 """
176 176 readline = StringIO(src).readline
177 177 toktypes = set()
178 178 try:
179 179 for t in tokenize.generate_tokens(readline):
180 180 toktypes.add(t[0])
181 181 except tokenize.TokenError:
182 182 pass
183 183 return(tokenize.COMMENT in toktypes)
184 184
185 185
186 186 def get_input_encoding():
187 187 """Return the default standard input encoding.
188 188
189 189 If sys.stdin has no encoding, 'ascii' is returned."""
190 190 # There are strange environments for which sys.stdin.encoding is None. We
191 191 # ensure that a valid encoding is returned.
192 192 encoding = getattr(sys.stdin, 'encoding', None)
193 193 if encoding is None:
194 194 encoding = 'ascii'
195 195 return encoding
196 196
197 197 #-----------------------------------------------------------------------------
198 198 # Classes and functions for normal Python syntax handling
199 199 #-----------------------------------------------------------------------------
200 200
201 201 class InputSplitter(object):
202 202 """An object that can accumulate lines of Python source before execution.
203 203
204 204 This object is designed to be fed python source line-by-line, using
205 205 :meth:`push`. It will return on each push whether the currently pushed
206 206 code could be executed already. In addition, it provides a method called
207 207 :meth:`push_accepts_more` that can be used to query whether more input
208 208 can be pushed into a single interactive block.
209 209
210 210 This is a simple example of how an interactive terminal-based client can use
211 211 this tool::
212 212
213 213 isp = InputSplitter()
214 214 while isp.push_accepts_more():
215 215 indent = ' '*isp.indent_spaces
216 216 prompt = '>>> ' + indent
217 217 line = indent + raw_input(prompt)
218 218 isp.push(line)
219 219 print 'Input source was:\n', isp.source_reset(),
220 220 """
221 221 # Number of spaces of indentation computed from input that has been pushed
222 222 # so far. This is the attributes callers should query to get the current
223 223 # indentation level, in order to provide auto-indent facilities.
224 224 indent_spaces = 0
225 225 # String, indicating the default input encoding. It is computed by default
226 226 # at initialization time via get_input_encoding(), but it can be reset by a
227 227 # client with specific knowledge of the encoding.
228 228 encoding = ''
229 229 # String where the current full source input is stored, properly encoded.
230 230 # Reading this attribute is the normal way of querying the currently pushed
231 231 # source code, that has been properly encoded.
232 232 source = ''
233 233 # Code object corresponding to the current source. It is automatically
234 234 # synced to the source, so it can be queried at any time to obtain the code
235 235 # object; it will be None if the source doesn't compile to valid Python.
236 236 code = None
237 237 # Input mode
238 238 input_mode = 'line'
239 239
240 240 # Private attributes
241 241
242 242 # List with lines of input accumulated so far
243 243 _buffer = None
244 244 # Command compiler
245 245 _compile = None
246 246 # Mark when input has changed indentation all the way back to flush-left
247 247 _full_dedent = False
248 248 # Boolean indicating whether the current block is complete
249 249 _is_complete = None
250 250
251 251 def __init__(self, input_mode=None):
252 252 """Create a new InputSplitter instance.
253 253
254 254 Parameters
255 255 ----------
256 256 input_mode : str
257 257
258 258 One of ['line', 'cell']; default is 'line'.
259 259
260 260 The input_mode parameter controls how new inputs are used when fed via
261 261 the :meth:`push` method:
262 262
263 263 - 'line': meant for line-oriented clients, inputs are appended one at a
264 264 time to the internal buffer and the whole buffer is compiled.
265 265
266 266 - 'cell': meant for clients that can edit multi-line 'cells' of text at
267 267 a time. A cell can contain one or more blocks that can be compile in
268 268 'single' mode by Python. In this mode, each new input new input
269 269 completely replaces all prior inputs. Cell mode is thus equivalent
270 270 to prepending a full reset() to every push() call.
271 271 """
272 272 self._buffer = []
273 273 self._compile = codeop.CommandCompiler()
274 274 self.encoding = get_input_encoding()
275 275 self.input_mode = InputSplitter.input_mode if input_mode is None \
276 276 else input_mode
277 277
278 278 def reset(self):
279 279 """Reset the input buffer and associated state."""
280 280 self.indent_spaces = 0
281 281 self._buffer[:] = []
282 282 self.source = ''
283 283 self.code = None
284 284 self._is_complete = False
285 285 self._full_dedent = False
286 286
287 287 def source_reset(self):
288 288 """Return the input source and perform a full reset.
289 289 """
290 290 out = self.source
291 291 self.reset()
292 292 return out
293 293
294 294 def push(self, lines):
295 295 """Push one or more lines of input.
296 296
297 297 This stores the given lines and returns a status code indicating
298 298 whether the code forms a complete Python block or not.
299 299
300 300 Any exceptions generated in compilation are swallowed, but if an
301 301 exception was produced, the method returns True.
302 302
303 303 Parameters
304 304 ----------
305 305 lines : string
306 306 One or more lines of Python input.
307 307
308 308 Returns
309 309 -------
310 310 is_complete : boolean
311 311 True if the current input source (the result of the current input
312 312 plus prior inputs) forms a complete Python execution block. Note that
313 313 this value is also stored as a private attribute (_is_complete), so it
314 314 can be queried at any time.
315 315 """
316 316 if self.input_mode == 'cell':
317 317 self.reset()
318 318
319 319 self._store(lines)
320 320 source = self.source
321 321
322 322 # Before calling _compile(), reset the code object to None so that if an
323 323 # exception is raised in compilation, we don't mislead by having
324 324 # inconsistent code/source attributes.
325 325 self.code, self._is_complete = None, None
326 326
327 327 # Honor termination lines properly
328 328 if source.rstrip().endswith('\\'):
329 329 return False
330 330
331 331 self._update_indent(lines)
332 332 try:
333 333 self.code = self._compile(source, symbol="exec")
334 334 # Invalid syntax can produce any of a number of different errors from
335 335 # inside the compiler, so we have to catch them all. Syntax errors
336 336 # immediately produce a 'ready' block, so the invalid Python can be
337 337 # sent to the kernel for evaluation with possible ipython
338 338 # special-syntax conversion.
339 339 except (SyntaxError, OverflowError, ValueError, TypeError,
340 340 MemoryError):
341 341 self._is_complete = True
342 342 else:
343 343 # Compilation didn't produce any exceptions (though it may not have
344 344 # given a complete code object)
345 345 self._is_complete = self.code is not None
346 346
347 347 return self._is_complete
348 348
349 349 def push_accepts_more(self):
350 350 """Return whether a block of interactive input can accept more input.
351 351
352 352 This method is meant to be used by line-oriented frontends, who need to
353 353 guess whether a block is complete or not based solely on prior and
354 354 current input lines. The InputSplitter considers it has a complete
355 355 interactive block and will not accept more input only when either a
356 356 SyntaxError is raised, or *all* of the following are true:
357 357
358 358 1. The input compiles to a complete statement.
359 359
360 360 2. The indentation level is flush-left (because if we are indented,
361 361 like inside a function definition or for loop, we need to keep
362 362 reading new input).
363 363
364 364 3. There is one extra line consisting only of whitespace.
365 365
366 366 Because of condition #3, this method should be used only by
367 367 *line-oriented* frontends, since it means that intermediate blank lines
368 368 are not allowed in function definitions (or any other indented block).
369 369
370 370 If the current input produces a syntax error, this method immediately
371 371 returns False but does *not* raise the syntax error exception, as
372 372 typically clients will want to send invalid syntax to an execution
373 373 backend which might convert the invalid syntax into valid Python via
374 374 one of the dynamic IPython mechanisms.
375 375 """
376 376
377 377 # With incomplete input, unconditionally accept more
378 378 if not self._is_complete:
379 379 return True
380 380
381 381 # If we already have complete input and we're flush left, the answer
382 382 # depends. In line mode, if there hasn't been any indentation,
383 383 # that's it. If we've come back from some indentation, we need
384 384 # the blank final line to finish.
385 385 # In cell mode, we need to check how many blocks the input so far
386 386 # compiles into, because if there's already more than one full
387 387 # independent block of input, then the client has entered full
388 388 # 'cell' mode and is feeding lines that each is complete. In this
389 389 # case we should then keep accepting. The Qt terminal-like console
390 390 # does precisely this, to provide the convenience of terminal-like
391 391 # input of single expressions, but allowing the user (with a
392 392 # separate keystroke) to switch to 'cell' mode and type multiple
393 393 # expressions in one shot.
394 394 if self.indent_spaces==0:
395 395 if self.input_mode=='line':
396 396 if not self._full_dedent:
397 397 return False
398 398 else:
399 399 try:
400 400 code_ast = ast.parse(u''.join(self._buffer))
401 401 except Exception:
402 402 return False
403 403 else:
404 404 if len(code_ast.body) == 1:
405 405 return False
406 406
407 407 # When input is complete, then termination is marked by an extra blank
408 408 # line at the end.
409 409 last_line = self.source.splitlines()[-1]
410 410 return bool(last_line and not last_line.isspace())
411 411
412 412 #------------------------------------------------------------------------
413 413 # Private interface
414 414 #------------------------------------------------------------------------
415 415
416 416 def _find_indent(self, line):
417 417 """Compute the new indentation level for a single line.
418 418
419 419 Parameters
420 420 ----------
421 421 line : str
422 422 A single new line of non-whitespace, non-comment Python input.
423 423
424 424 Returns
425 425 -------
426 426 indent_spaces : int
427 427 New value for the indent level (it may be equal to self.indent_spaces
428 428 if indentation doesn't change.
429 429
430 430 full_dedent : boolean
431 431 Whether the new line causes a full flush-left dedent.
432 432 """
433 433 indent_spaces = self.indent_spaces
434 434 full_dedent = self._full_dedent
435 435
436 436 inisp = num_ini_spaces(line)
437 437 if inisp < indent_spaces:
438 438 indent_spaces = inisp
439 439 if indent_spaces <= 0:
440 440 #print 'Full dedent in text',self.source # dbg
441 441 full_dedent = True
442 442
443 443 if line.rstrip()[-1] == ':':
444 444 indent_spaces += 4
445 445 elif dedent_re.match(line):
446 446 indent_spaces -= 4
447 447 if indent_spaces <= 0:
448 448 full_dedent = True
449 449
450 450 # Safety
451 451 if indent_spaces < 0:
452 452 indent_spaces = 0
453 453 #print 'safety' # dbg
454 454
455 455 return indent_spaces, full_dedent
456 456
457 457 def _update_indent(self, lines):
458 458 for line in remove_comments(lines).splitlines():
459 459 if line and not line.isspace():
460 460 self.indent_spaces, self._full_dedent = self._find_indent(line)
461 461
462 462 def _store(self, lines, buffer=None, store='source'):
463 463 """Store one or more lines of input.
464 464
465 465 If input lines are not newline-terminated, a newline is automatically
466 466 appended."""
467 467
468 468 if buffer is None:
469 469 buffer = self._buffer
470 470
471 471 if lines.endswith('\n'):
472 472 buffer.append(lines)
473 473 else:
474 474 buffer.append(lines+'\n')
475 475 setattr(self, store, self._set_source(buffer))
476 476
477 477 def _set_source(self, buffer):
478 478 return u''.join(buffer)
479 479
480 480
481 481 #-----------------------------------------------------------------------------
482 482 # Functions and classes for IPython-specific syntactic support
483 483 #-----------------------------------------------------------------------------
484 484
485 485 # The escaped translators ALL receive a line where their own escape has been
486 486 # stripped. Only '?' is valid at the end of the line, all others can only be
487 487 # placed at the start.
488 488
489 489 # Transformations of the special syntaxes that don't rely on an explicit escape
490 490 # character but instead on patterns on the input line
491 491
492 492 # The core transformations are implemented as standalone functions that can be
493 493 # tested and validated in isolation. Each of these uses a regexp, we
494 494 # pre-compile these and keep them close to each function definition for clarity
495 495
496 496 _assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
497 497 r'\s*=\s*!\s*(?P<cmd>.*)')
498 498
499 499 def transform_assign_system(line):
500 500 """Handle the `files = !ls` syntax."""
501 501 m = _assign_system_re.match(line)
502 502 if m is not None:
503 503 cmd = m.group('cmd')
504 504 lhs = m.group('lhs')
505 505 new_line = '%s = get_ipython().getoutput(%r)' % (lhs, cmd)
506 506 return new_line
507 507 return line
508 508
509 509
510 510 _assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
511 511 r'\s*=\s*%\s*(?P<cmd>.*)')
512 512
513 513 def transform_assign_magic(line):
514 514 """Handle the `a = %who` syntax."""
515 515 m = _assign_magic_re.match(line)
516 516 if m is not None:
517 517 cmd = m.group('cmd')
518 518 lhs = m.group('lhs')
519 519 new_line = '%s = get_ipython().magic(%r)' % (lhs, cmd)
520 520 return new_line
521 521 return line
522 522
523 523
524 524 _classic_prompt_re = re.compile(r'^([ \t]*>>> |^[ \t]*\.\.\. )')
525 525
526 526 def transform_classic_prompt(line):
527 527 """Handle inputs that start with '>>> ' syntax."""
528 528
529 529 if not line or line.isspace():
530 530 return line
531 531 m = _classic_prompt_re.match(line)
532 532 if m:
533 533 return line[len(m.group(0)):]
534 534 else:
535 535 return line
536 536
537 537
538 538 _ipy_prompt_re = re.compile(r'^([ \t]*In \[\d+\]: |^[ \t]*\ \ \ \.\.\.+: )')
539 539
540 540 def transform_ipy_prompt(line):
541 541 """Handle inputs that start classic IPython prompt syntax."""
542 542
543 543 if not line or line.isspace():
544 544 return line
545 545 #print 'LINE: %r' % line # dbg
546 546 m = _ipy_prompt_re.match(line)
547 547 if m:
548 548 #print 'MATCH! %r -> %r' % (line, line[len(m.group(0)):]) # dbg
549 549 return line[len(m.group(0)):]
550 550 else:
551 551 return line
552 552
553 553
554 554 def _make_help_call(target, esc, lspace, next_input=None):
555 555 """Prepares a pinfo(2)/psearch call from a target name and the escape
556 556 (i.e. ? or ??)"""
557 557 method = 'pinfo2' if esc == '??' \
558 558 else 'psearch' if '*' in target \
559 559 else 'pinfo'
560 560 arg = " ".join([method, target])
561 561
562 562 if next_input:
563 563 tpl = '%sget_ipython().magic(%r, next_input=%r)'
564 564 return tpl % (lspace, arg, next_input)
565 565 else:
566 566 return '%sget_ipython().magic(%r)' % (lspace, arg)
567 567
568 568 _initial_space_re = re.compile(r'\s*')
569 569 _help_end_re = re.compile(r"""(%?
570 570 [a-zA-Z_*][\w*]* # Variable name
571 571 (\.[a-zA-Z_*][\w*]*)* # .etc.etc
572 572 )
573 573 (\?\??)$ # ? or ??""",
574 574 re.VERBOSE)
575 575 def transform_help_end(line):
576 576 """Translate lines with ?/?? at the end"""
577 577 m = _help_end_re.search(line)
578 578 if m is None or has_comment(line):
579 579 return line
580 580 target = m.group(1)
581 581 esc = m.group(3)
582 582 lspace = _initial_space_re.match(line).group(0)
583 583
584 584 # If we're mid-command, put it back on the next prompt for the user.
585 585 next_input = line.rstrip('?') if line.strip() != m.group(0) else None
586 586
587 587 return _make_help_call(target, esc, lspace, next_input)
588 588
589 589
590 590 class EscapedTransformer(object):
591 591 """Class to transform lines that are explicitly escaped out."""
592 592
593 593 def __init__(self):
594 594 tr = { ESC_SHELL : self._tr_system,
595 595 ESC_SH_CAP : self._tr_system2,
596 596 ESC_HELP : self._tr_help,
597 597 ESC_HELP2 : self._tr_help,
598 598 ESC_MAGIC : self._tr_magic,
599 599 ESC_QUOTE : self._tr_quote,
600 600 ESC_QUOTE2 : self._tr_quote2,
601 601 ESC_PAREN : self._tr_paren }
602 602 self.tr = tr
603 603
604 604 # Support for syntax transformations that use explicit escapes typed by the
605 605 # user at the beginning of a line
606 606 @staticmethod
607 607 def _tr_system(line_info):
608 608 "Translate lines escaped with: !"
609 609 cmd = line_info.line.lstrip().lstrip(ESC_SHELL)
610 610 return '%sget_ipython().system(%r)' % (line_info.pre, cmd)
611 611
612 612 @staticmethod
613 613 def _tr_system2(line_info):
614 614 "Translate lines escaped with: !!"
615 615 cmd = line_info.line.lstrip()[2:]
616 616 return '%sget_ipython().getoutput(%r)' % (line_info.pre, cmd)
617 617
618 618 @staticmethod
619 619 def _tr_help(line_info):
620 620 "Translate lines escaped with: ?/??"
621 621 # A naked help line should just fire the intro help screen
622 622 if not line_info.line[1:]:
623 623 return 'get_ipython().show_usage()'
624 624
625 625 return _make_help_call(line_info.ifun, line_info.esc, line_info.pre)
626 626
627 627 @staticmethod
628 628 def _tr_magic(line_info):
629 629 "Translate lines escaped with: %"
630 630 tpl = '%sget_ipython().magic(%r)'
631 631 cmd = ' '.join([line_info.ifun, line_info.the_rest]).strip()
632 632 return tpl % (line_info.pre, cmd)
633 633
634 634 @staticmethod
635 635 def _tr_quote(line_info):
636 636 "Translate lines escaped with: ,"
637 637 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
638 638 '", "'.join(line_info.the_rest.split()) )
639 639
640 640 @staticmethod
641 641 def _tr_quote2(line_info):
642 642 "Translate lines escaped with: ;"
643 643 return '%s%s("%s")' % (line_info.pre, line_info.ifun,
644 644 line_info.the_rest)
645 645
646 646 @staticmethod
647 647 def _tr_paren(line_info):
648 648 "Translate lines escaped with: /"
649 649 return '%s%s(%s)' % (line_info.pre, line_info.ifun,
650 650 ", ".join(line_info.the_rest.split()))
651 651
652 652 def __call__(self, line):
653 653 """Class to transform lines that are explicitly escaped out.
654 654
655 655 This calls the above _tr_* static methods for the actual line
656 656 translations."""
657 657
658 658 # Empty lines just get returned unmodified
659 659 if not line or line.isspace():
660 660 return line
661 661
662 662 # Get line endpoints, where the escapes can be
663 663 line_info = LineInfo(line)
664 664
665 665 if not line_info.esc in self.tr:
666 666 # If we don't recognize the escape, don't modify the line
667 667 return line
668 668
669 669 return self.tr[line_info.esc](line_info)
670 670
671 671
672 672 # A function-looking object to be used by the rest of the code. The purpose of
673 673 # the class in this case is to organize related functionality, more than to
674 674 # manage state.
675 675 transform_escaped = EscapedTransformer()
676 676
677 677
678 678 class IPythonInputSplitter(InputSplitter):
679 679 """An input splitter that recognizes all of IPython's special syntax."""
680 680
681 681 # String with raw, untransformed input.
682 682 source_raw = ''
683 683
684 684 # Private attributes
685 685
686 686 # List with lines of raw input accumulated so far.
687 687 _buffer_raw = None
688 688
689 689 def __init__(self, input_mode=None):
690 690 InputSplitter.__init__(self, input_mode)
691 691 self._buffer_raw = []
692 692
693 693 def reset(self):
694 694 """Reset the input buffer and associated state."""
695 695 InputSplitter.reset(self)
696 696 self._buffer_raw[:] = []
697 697 self.source_raw = ''
698 698
699 699 def source_raw_reset(self):
700 700 """Return input and raw source and perform a full reset.
701 701 """
702 702 out = self.source
703 703 out_r = self.source_raw
704 704 self.reset()
705 705 return out, out_r
706 706
707 707 def push(self, lines):
708 708 """Push one or more lines of IPython input.
709 709 """
710 710 if not lines:
711 711 return super(IPythonInputSplitter, self).push(lines)
712 712
713 713 # We must ensure all input is pure unicode
714 714 lines = cast_unicode(lines, self.encoding)
715 715
716 716 lines_list = lines.splitlines()
717 717
718 718 transforms = [transform_ipy_prompt, transform_classic_prompt,
719 719 transform_help_end, transform_escaped,
720 720 transform_assign_system, transform_assign_magic]
721 721
722 722 # Transform logic
723 723 #
724 724 # We only apply the line transformers to the input if we have either no
725 725 # input yet, or complete input, or if the last line of the buffer ends
726 726 # with ':' (opening an indented block). This prevents the accidental
727 727 # transformation of escapes inside multiline expressions like
728 728 # triple-quoted strings or parenthesized expressions.
729 729 #
730 730 # The last heuristic, while ugly, ensures that the first line of an
731 731 # indented block is correctly transformed.
732 732 #
733 733 # FIXME: try to find a cleaner approach for this last bit.
734 734
735 735 # If we were in 'block' mode, since we're going to pump the parent
736 736 # class by hand line by line, we need to temporarily switch out to
737 737 # 'line' mode, do a single manual reset and then feed the lines one
738 738 # by one. Note that this only matters if the input has more than one
739 739 # line.
740 740 changed_input_mode = False
741 741
742 742 if self.input_mode == 'cell':
743 743 self.reset()
744 744 changed_input_mode = True
745 745 saved_input_mode = 'cell'
746 746 self.input_mode = 'line'
747 747
748 748 # Store raw source before applying any transformations to it. Note
749 749 # that this must be done *after* the reset() call that would otherwise
750 750 # flush the buffer.
751 751 self._store(lines, self._buffer_raw, 'source_raw')
752 752
753 753 try:
754 754 push = super(IPythonInputSplitter, self).push
755 755 buf = self._buffer
756 756 for line in lines_list:
757 757 if self._is_complete or not buf or \
758 758 (buf and (buf[-1].rstrip().endswith(':') or
759 759 buf[-1].rstrip().endswith(',')) ):
760 760 for f in transforms:
761 761 line = f(line)
762 762
763 763 out = push(line)
764 764 finally:
765 765 if changed_input_mode:
766 766 self.input_mode = saved_input_mode
767 767 return out
@@ -1,29 +1,29 b''
1 1 # encoding: utf-8
2 2 """
3 3 This module is *completely* deprecated and should no longer be used for
4 4 any purpose. Currently, we have a few parts of the core that have
5 5 not been componentized and thus, still rely on this module. When everything
6 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 12 # Distributed under the terms of the BSD License. The full license is in
13 13 # the file COPYING, distributed as part of this software.
14 14 #-----------------------------------------------------------------------------
15 15
16 16 #-----------------------------------------------------------------------------
17 17 # Imports
18 18 #-----------------------------------------------------------------------------
19 19
20 20 #-----------------------------------------------------------------------------
21 21 # Classes and functions
22 22 #-----------------------------------------------------------------------------
23 23
24 24
25 25 def get():
26 26 """Get the global InteractiveShell instance."""
27 27 from IPython.core.interactiveshell import InteractiveShell
28 28 return InteractiveShell.instance()
29 29
@@ -1,3739 +1,3739 b''
1 1 # encoding: utf-8
2 2 """Magic functions for InteractiveShell.
3 3 """
4 4
5 5 #-----------------------------------------------------------------------------
6 6 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de> and
7 7 # Copyright (C) 2001-2007 Fernando Perez <fperez@colorado.edu>
8 # Copyright (C) 2008-2009 The IPython Development Team
8 # Copyright (C) 2008-2011 The IPython Development Team
9 9
10 10 # Distributed under the terms of the BSD License. The full license is in
11 11 # the file COPYING, distributed as part of this software.
12 12 #-----------------------------------------------------------------------------
13 13
14 14 #-----------------------------------------------------------------------------
15 15 # Imports
16 16 #-----------------------------------------------------------------------------
17 17
18 18 import __builtin__ as builtin_mod
19 19 import __future__
20 20 import bdb
21 21 import inspect
22 22 import imp
23 23 import os
24 24 import sys
25 25 import shutil
26 26 import re
27 27 import time
28 28 import textwrap
29 29 from StringIO import StringIO
30 30 from getopt import getopt,GetoptError
31 31 from pprint import pformat
32 32 from xmlrpclib import ServerProxy
33 33
34 34 # cProfile was added in Python2.5
35 35 try:
36 36 import cProfile as profile
37 37 import pstats
38 38 except ImportError:
39 39 # profile isn't bundled by default in Debian for license reasons
40 40 try:
41 41 import profile,pstats
42 42 except ImportError:
43 43 profile = pstats = None
44 44
45 45 import IPython
46 46 from IPython.core import debugger, oinspect
47 47 from IPython.core.error import TryNext
48 48 from IPython.core.error import UsageError
49 49 from IPython.core.fakemodule import FakeModule
50 50 from IPython.core.profiledir import ProfileDir
51 51 from IPython.core.macro import Macro
52 52 from IPython.core import magic_arguments, page
53 53 from IPython.core.prefilter import ESC_MAGIC
54 54 from IPython.lib.pylabtools import mpl_runner
55 55 from IPython.testing.skipdoctest import skip_doctest
56 56 from IPython.utils import py3compat
57 57 from IPython.utils.io import file_read, nlprint
58 58 from IPython.utils.module_paths import find_mod
59 59 from IPython.utils.path import get_py_filename, unquote_filename
60 60 from IPython.utils.process import arg_split, abbrev_cwd
61 61 from IPython.utils.terminal import set_term_title
62 62 from IPython.utils.text import LSString, SList, format_screen
63 63 from IPython.utils.timing import clock, clock2
64 64 from IPython.utils.warn import warn, error
65 65 from IPython.utils.ipstruct import Struct
66 66 from IPython.config.application import Application
67 67
68 68 #-----------------------------------------------------------------------------
69 69 # Utility functions
70 70 #-----------------------------------------------------------------------------
71 71
72 72 def on_off(tag):
73 73 """Return an ON/OFF string for a 1/0 input. Simple utility function."""
74 74 return ['OFF','ON'][tag]
75 75
76 76 class Bunch: pass
77 77
78 78 def compress_dhist(dh):
79 79 head, tail = dh[:-10], dh[-10:]
80 80
81 81 newhead = []
82 82 done = set()
83 83 for h in head:
84 84 if h in done:
85 85 continue
86 86 newhead.append(h)
87 87 done.add(h)
88 88
89 89 return newhead + tail
90 90
91 91 def needs_local_scope(func):
92 92 """Decorator to mark magic functions which need to local scope to run."""
93 93 func.needs_local_scope = True
94 94 return func
95 95
96 96
97 97 # Used for exception handling in magic_edit
98 98 class MacroToEdit(ValueError): pass
99 99
100 100 #***************************************************************************
101 101 # Main class implementing Magic functionality
102 102
103 103 # XXX - for some odd reason, if Magic is made a new-style class, we get errors
104 104 # on construction of the main InteractiveShell object. Something odd is going
105 105 # on with super() calls, Configurable and the MRO... For now leave it as-is, but
106 106 # eventually this needs to be clarified.
107 107 # BG: This is because InteractiveShell inherits from this, but is itself a
108 108 # Configurable. This messes up the MRO in some way. The fix is that we need to
109 109 # make Magic a configurable that InteractiveShell does not subclass.
110 110
111 111 class Magic:
112 112 """Magic functions for InteractiveShell.
113 113
114 114 Shell functions which can be reached as %function_name. All magic
115 115 functions should accept a string, which they can parse for their own
116 116 needs. This can make some functions easier to type, eg `%cd ../`
117 117 vs. `%cd("../")`
118 118
119 119 ALL definitions MUST begin with the prefix magic_. The user won't need it
120 120 at the command line, but it is is needed in the definition. """
121 121
122 122 # class globals
123 123 auto_status = ['Automagic is OFF, % prefix IS needed for magic functions.',
124 124 'Automagic is ON, % prefix NOT needed for magic functions.']
125 125
126 126
127 127 configurables = None
128 128 #......................................................................
129 129 # some utility functions
130 130
131 131 def __init__(self,shell):
132 132
133 133 self.options_table = {}
134 134 if profile is None:
135 135 self.magic_prun = self.profile_missing_notice
136 136 self.shell = shell
137 137 if self.configurables is None:
138 138 self.configurables = []
139 139
140 140 # namespace for holding state we may need
141 141 self._magic_state = Bunch()
142 142
143 143 def profile_missing_notice(self, *args, **kwargs):
144 144 error("""\
145 145 The profile module could not be found. It has been removed from the standard
146 146 python packages because of its non-free license. To use profiling, install the
147 147 python-profiler package from non-free.""")
148 148
149 149 def default_option(self,fn,optstr):
150 150 """Make an entry in the options_table for fn, with value optstr"""
151 151
152 152 if fn not in self.lsmagic():
153 153 error("%s is not a magic function" % fn)
154 154 self.options_table[fn] = optstr
155 155
156 156 def lsmagic(self):
157 157 """Return a list of currently available magic functions.
158 158
159 159 Gives a list of the bare names after mangling (['ls','cd', ...], not
160 160 ['magic_ls','magic_cd',...]"""
161 161
162 162 # FIXME. This needs a cleanup, in the way the magics list is built.
163 163
164 164 # magics in class definition
165 165 class_magic = lambda fn: fn.startswith('magic_') and \
166 166 callable(Magic.__dict__[fn])
167 167 # in instance namespace (run-time user additions)
168 168 inst_magic = lambda fn: fn.startswith('magic_') and \
169 169 callable(self.__dict__[fn])
170 170 # and bound magics by user (so they can access self):
171 171 inst_bound_magic = lambda fn: fn.startswith('magic_') and \
172 172 callable(self.__class__.__dict__[fn])
173 173 magics = filter(class_magic,Magic.__dict__.keys()) + \
174 174 filter(inst_magic,self.__dict__.keys()) + \
175 175 filter(inst_bound_magic,self.__class__.__dict__.keys())
176 176 out = []
177 177 for fn in set(magics):
178 178 out.append(fn.replace('magic_','',1))
179 179 out.sort()
180 180 return out
181 181
182 182 def extract_input_lines(self, range_str, raw=False):
183 183 """Return as a string a set of input history slices.
184 184
185 185 Inputs:
186 186
187 187 - range_str: the set of slices is given as a string, like
188 188 "~5/6-~4/2 4:8 9", since this function is for use by magic functions
189 189 which get their arguments as strings. The number before the / is the
190 190 session number: ~n goes n back from the current session.
191 191
192 192 Optional inputs:
193 193
194 194 - raw(False): by default, the processed input is used. If this is
195 195 true, the raw input history is used instead.
196 196
197 197 Note that slices can be called with two notations:
198 198
199 199 N:M -> standard python form, means including items N...(M-1).
200 200
201 201 N-M -> include items N..M (closed endpoint)."""
202 202 lines = self.shell.history_manager.\
203 203 get_range_by_str(range_str, raw=raw)
204 204 return "\n".join(x for _, _, x in lines)
205 205
206 206 def arg_err(self,func):
207 207 """Print docstring if incorrect arguments were passed"""
208 208 print 'Error in arguments:'
209 209 print oinspect.getdoc(func)
210 210
211 211 def format_latex(self,strng):
212 212 """Format a string for latex inclusion."""
213 213
214 214 # Characters that need to be escaped for latex:
215 215 escape_re = re.compile(r'(%|_|\$|#|&)',re.MULTILINE)
216 216 # Magic command names as headers:
217 217 cmd_name_re = re.compile(r'^(%s.*?):' % ESC_MAGIC,
218 218 re.MULTILINE)
219 219 # Magic commands
220 220 cmd_re = re.compile(r'(?P<cmd>%s.+?\b)(?!\}\}:)' % ESC_MAGIC,
221 221 re.MULTILINE)
222 222 # Paragraph continue
223 223 par_re = re.compile(r'\\$',re.MULTILINE)
224 224
225 225 # The "\n" symbol
226 226 newline_re = re.compile(r'\\n')
227 227
228 228 # Now build the string for output:
229 229 #strng = cmd_name_re.sub(r'\n\\texttt{\\textsl{\\large \1}}:',strng)
230 230 strng = cmd_name_re.sub(r'\n\\bigskip\n\\texttt{\\textbf{ \1}}:',
231 231 strng)
232 232 strng = cmd_re.sub(r'\\texttt{\g<cmd>}',strng)
233 233 strng = par_re.sub(r'\\\\',strng)
234 234 strng = escape_re.sub(r'\\\1',strng)
235 235 strng = newline_re.sub(r'\\textbackslash{}n',strng)
236 236 return strng
237 237
238 238 def parse_options(self,arg_str,opt_str,*long_opts,**kw):
239 239 """Parse options passed to an argument string.
240 240
241 241 The interface is similar to that of getopt(), but it returns back a
242 242 Struct with the options as keys and the stripped argument string still
243 243 as a string.
244 244
245 245 arg_str is quoted as a true sys.argv vector by using shlex.split.
246 246 This allows us to easily expand variables, glob files, quote
247 247 arguments, etc.
248 248
249 249 Options:
250 250 -mode: default 'string'. If given as 'list', the argument string is
251 251 returned as a list (split on whitespace) instead of a string.
252 252
253 253 -list_all: put all option values in lists. Normally only options
254 254 appearing more than once are put in a list.
255 255
256 256 -posix (True): whether to split the input line in POSIX mode or not,
257 257 as per the conventions outlined in the shlex module from the
258 258 standard library."""
259 259
260 260 # inject default options at the beginning of the input line
261 261 caller = sys._getframe(1).f_code.co_name.replace('magic_','')
262 262 arg_str = '%s %s' % (self.options_table.get(caller,''),arg_str)
263 263
264 264 mode = kw.get('mode','string')
265 265 if mode not in ['string','list']:
266 266 raise ValueError,'incorrect mode given: %s' % mode
267 267 # Get options
268 268 list_all = kw.get('list_all',0)
269 269 posix = kw.get('posix', os.name == 'posix')
270 270
271 271 # Check if we have more than one argument to warrant extra processing:
272 272 odict = {} # Dictionary with options
273 273 args = arg_str.split()
274 274 if len(args) >= 1:
275 275 # If the list of inputs only has 0 or 1 thing in it, there's no
276 276 # need to look for options
277 277 argv = arg_split(arg_str,posix)
278 278 # Do regular option processing
279 279 try:
280 280 opts,args = getopt(argv,opt_str,*long_opts)
281 281 except GetoptError,e:
282 282 raise UsageError('%s ( allowed: "%s" %s)' % (e.msg,opt_str,
283 283 " ".join(long_opts)))
284 284 for o,a in opts:
285 285 if o.startswith('--'):
286 286 o = o[2:]
287 287 else:
288 288 o = o[1:]
289 289 try:
290 290 odict[o].append(a)
291 291 except AttributeError:
292 292 odict[o] = [odict[o],a]
293 293 except KeyError:
294 294 if list_all:
295 295 odict[o] = [a]
296 296 else:
297 297 odict[o] = a
298 298
299 299 # Prepare opts,args for return
300 300 opts = Struct(odict)
301 301 if mode == 'string':
302 302 args = ' '.join(args)
303 303
304 304 return opts,args
305 305
306 306 #......................................................................
307 307 # And now the actual magic functions
308 308
309 309 # Functions for IPython shell work (vars,funcs, config, etc)
310 310 def magic_lsmagic(self, parameter_s = ''):
311 311 """List currently available magic functions."""
312 312 mesc = ESC_MAGIC
313 313 print 'Available magic functions:\n'+mesc+\
314 314 (' '+mesc).join(self.lsmagic())
315 315 print '\n' + Magic.auto_status[self.shell.automagic]
316 316 return None
317 317
318 318 def magic_magic(self, parameter_s = ''):
319 319 """Print information about the magic function system.
320 320
321 321 Supported formats: -latex, -brief, -rest
322 322 """
323 323
324 324 mode = ''
325 325 try:
326 326 if parameter_s.split()[0] == '-latex':
327 327 mode = 'latex'
328 328 if parameter_s.split()[0] == '-brief':
329 329 mode = 'brief'
330 330 if parameter_s.split()[0] == '-rest':
331 331 mode = 'rest'
332 332 rest_docs = []
333 333 except:
334 334 pass
335 335
336 336 magic_docs = []
337 337 for fname in self.lsmagic():
338 338 mname = 'magic_' + fname
339 339 for space in (Magic,self,self.__class__):
340 340 try:
341 341 fn = space.__dict__[mname]
342 342 except KeyError:
343 343 pass
344 344 else:
345 345 break
346 346 if mode == 'brief':
347 347 # only first line
348 348 if fn.__doc__:
349 349 fndoc = fn.__doc__.split('\n',1)[0]
350 350 else:
351 351 fndoc = 'No documentation'
352 352 else:
353 353 if fn.__doc__:
354 354 fndoc = fn.__doc__.rstrip()
355 355 else:
356 356 fndoc = 'No documentation'
357 357
358 358
359 359 if mode == 'rest':
360 360 rest_docs.append('**%s%s**::\n\n\t%s\n\n' %(ESC_MAGIC,
361 361 fname,fndoc))
362 362
363 363 else:
364 364 magic_docs.append('%s%s:\n\t%s\n' %(ESC_MAGIC,
365 365 fname,fndoc))
366 366
367 367 magic_docs = ''.join(magic_docs)
368 368
369 369 if mode == 'rest':
370 370 return "".join(rest_docs)
371 371
372 372 if mode == 'latex':
373 373 print self.format_latex(magic_docs)
374 374 return
375 375 else:
376 376 magic_docs = format_screen(magic_docs)
377 377 if mode == 'brief':
378 378 return magic_docs
379 379
380 380 outmsg = """
381 381 IPython's 'magic' functions
382 382 ===========================
383 383
384 384 The magic function system provides a series of functions which allow you to
385 385 control the behavior of IPython itself, plus a lot of system-type
386 386 features. All these functions are prefixed with a % character, but parameters
387 387 are given without parentheses or quotes.
388 388
389 389 NOTE: If you have 'automagic' enabled (via the command line option or with the
390 390 %automagic function), you don't need to type in the % explicitly. By default,
391 391 IPython ships with automagic on, so you should only rarely need the % escape.
392 392
393 393 Example: typing '%cd mydir' (without the quotes) changes you working directory
394 394 to 'mydir', if it exists.
395 395
396 396 For a list of the available magic functions, use %lsmagic. For a description
397 397 of any of them, type %magic_name?, e.g. '%cd?'.
398 398
399 399 Currently the magic system has the following functions:\n"""
400 400
401 401 mesc = ESC_MAGIC
402 402 outmsg = ("%s\n%s\n\nSummary of magic functions (from %slsmagic):"
403 403 "\n\n%s%s\n\n%s" % (outmsg,
404 404 magic_docs,mesc,mesc,
405 405 (' '+mesc).join(self.lsmagic()),
406 406 Magic.auto_status[self.shell.automagic] ) )
407 407 page.page(outmsg)
408 408
409 409 def magic_automagic(self, parameter_s = ''):
410 410 """Make magic functions callable without having to type the initial %.
411 411
412 412 Without argumentsl toggles on/off (when off, you must call it as
413 413 %automagic, of course). With arguments it sets the value, and you can
414 414 use any of (case insensitive):
415 415
416 416 - on,1,True: to activate
417 417
418 418 - off,0,False: to deactivate.
419 419
420 420 Note that magic functions have lowest priority, so if there's a
421 421 variable whose name collides with that of a magic fn, automagic won't
422 422 work for that function (you get the variable instead). However, if you
423 423 delete the variable (del var), the previously shadowed magic function
424 424 becomes visible to automagic again."""
425 425
426 426 arg = parameter_s.lower()
427 427 if parameter_s in ('on','1','true'):
428 428 self.shell.automagic = True
429 429 elif parameter_s in ('off','0','false'):
430 430 self.shell.automagic = False
431 431 else:
432 432 self.shell.automagic = not self.shell.automagic
433 433 print '\n' + Magic.auto_status[self.shell.automagic]
434 434
435 435 @skip_doctest
436 436 def magic_autocall(self, parameter_s = ''):
437 437 """Make functions callable without having to type parentheses.
438 438
439 439 Usage:
440 440
441 441 %autocall [mode]
442 442
443 443 The mode can be one of: 0->Off, 1->Smart, 2->Full. If not given, the
444 444 value is toggled on and off (remembering the previous state).
445 445
446 446 In more detail, these values mean:
447 447
448 448 0 -> fully disabled
449 449
450 450 1 -> active, but do not apply if there are no arguments on the line.
451 451
452 452 In this mode, you get:
453 453
454 454 In [1]: callable
455 455 Out[1]: <built-in function callable>
456 456
457 457 In [2]: callable 'hello'
458 458 ------> callable('hello')
459 459 Out[2]: False
460 460
461 461 2 -> Active always. Even if no arguments are present, the callable
462 462 object is called:
463 463
464 464 In [2]: float
465 465 ------> float()
466 466 Out[2]: 0.0
467 467
468 468 Note that even with autocall off, you can still use '/' at the start of
469 469 a line to treat the first argument on the command line as a function
470 470 and add parentheses to it:
471 471
472 472 In [8]: /str 43
473 473 ------> str(43)
474 474 Out[8]: '43'
475 475
476 476 # all-random (note for auto-testing)
477 477 """
478 478
479 479 if parameter_s:
480 480 arg = int(parameter_s)
481 481 else:
482 482 arg = 'toggle'
483 483
484 484 if not arg in (0,1,2,'toggle'):
485 485 error('Valid modes: (0->Off, 1->Smart, 2->Full')
486 486 return
487 487
488 488 if arg in (0,1,2):
489 489 self.shell.autocall = arg
490 490 else: # toggle
491 491 if self.shell.autocall:
492 492 self._magic_state.autocall_save = self.shell.autocall
493 493 self.shell.autocall = 0
494 494 else:
495 495 try:
496 496 self.shell.autocall = self._magic_state.autocall_save
497 497 except AttributeError:
498 498 self.shell.autocall = self._magic_state.autocall_save = 1
499 499
500 500 print "Automatic calling is:",['OFF','Smart','Full'][self.shell.autocall]
501 501
502 502
503 503 def magic_page(self, parameter_s=''):
504 504 """Pretty print the object and display it through a pager.
505 505
506 506 %page [options] OBJECT
507 507
508 508 If no object is given, use _ (last output).
509 509
510 510 Options:
511 511
512 512 -r: page str(object), don't pretty-print it."""
513 513
514 514 # After a function contributed by Olivier Aubert, slightly modified.
515 515
516 516 # Process options/args
517 517 opts,args = self.parse_options(parameter_s,'r')
518 518 raw = 'r' in opts
519 519
520 520 oname = args and args or '_'
521 521 info = self._ofind(oname)
522 522 if info['found']:
523 523 txt = (raw and str or pformat)( info['obj'] )
524 524 page.page(txt)
525 525 else:
526 526 print 'Object `%s` not found' % oname
527 527
528 528 def magic_profile(self, parameter_s=''):
529 529 """Print your currently active IPython profile."""
530 530 from IPython.core.application import BaseIPythonApplication
531 531 if BaseIPythonApplication.initialized():
532 532 print BaseIPythonApplication.instance().profile
533 533 else:
534 534 error("profile is an application-level value, but you don't appear to be in an IPython application")
535 535
536 536 def magic_pinfo(self, parameter_s='', namespaces=None):
537 537 """Provide detailed information about an object.
538 538
539 539 '%pinfo object' is just a synonym for object? or ?object."""
540 540
541 541 #print 'pinfo par: <%s>' % parameter_s # dbg
542 542
543 543
544 544 # detail_level: 0 -> obj? , 1 -> obj??
545 545 detail_level = 0
546 546 # We need to detect if we got called as 'pinfo pinfo foo', which can
547 547 # happen if the user types 'pinfo foo?' at the cmd line.
548 548 pinfo,qmark1,oname,qmark2 = \
549 549 re.match('(pinfo )?(\?*)(.*?)(\??$)',parameter_s).groups()
550 550 if pinfo or qmark1 or qmark2:
551 551 detail_level = 1
552 552 if "*" in oname:
553 553 self.magic_psearch(oname)
554 554 else:
555 555 self.shell._inspect('pinfo', oname, detail_level=detail_level,
556 556 namespaces=namespaces)
557 557
558 558 def magic_pinfo2(self, parameter_s='', namespaces=None):
559 559 """Provide extra detailed information about an object.
560 560
561 561 '%pinfo2 object' is just a synonym for object?? or ??object."""
562 562 self.shell._inspect('pinfo', parameter_s, detail_level=1,
563 563 namespaces=namespaces)
564 564
565 565 @skip_doctest
566 566 def magic_pdef(self, parameter_s='', namespaces=None):
567 567 """Print the definition header for any callable object.
568 568
569 569 If the object is a class, print the constructor information.
570 570
571 571 Examples
572 572 --------
573 573 ::
574 574
575 575 In [3]: %pdef urllib.urlopen
576 576 urllib.urlopen(url, data=None, proxies=None)
577 577 """
578 578 self._inspect('pdef',parameter_s, namespaces)
579 579
580 580 def magic_pdoc(self, parameter_s='', namespaces=None):
581 581 """Print the docstring for an object.
582 582
583 583 If the given object is a class, it will print both the class and the
584 584 constructor docstrings."""
585 585 self._inspect('pdoc',parameter_s, namespaces)
586 586
587 587 def magic_psource(self, parameter_s='', namespaces=None):
588 588 """Print (or run through pager) the source code for an object."""
589 589 self._inspect('psource',parameter_s, namespaces)
590 590
591 591 def magic_pfile(self, parameter_s=''):
592 592 """Print (or run through pager) the file where an object is defined.
593 593
594 594 The file opens at the line where the object definition begins. IPython
595 595 will honor the environment variable PAGER if set, and otherwise will
596 596 do its best to print the file in a convenient form.
597 597
598 598 If the given argument is not an object currently defined, IPython will
599 599 try to interpret it as a filename (automatically adding a .py extension
600 600 if needed). You can thus use %pfile as a syntax highlighting code
601 601 viewer."""
602 602
603 603 # first interpret argument as an object name
604 604 out = self._inspect('pfile',parameter_s)
605 605 # if not, try the input as a filename
606 606 if out == 'not found':
607 607 try:
608 608 filename = get_py_filename(parameter_s)
609 609 except IOError,msg:
610 610 print msg
611 611 return
612 612 page.page(self.shell.inspector.format(file(filename).read()))
613 613
614 614 def magic_psearch(self, parameter_s=''):
615 615 """Search for object in namespaces by wildcard.
616 616
617 617 %psearch [options] PATTERN [OBJECT TYPE]
618 618
619 619 Note: ? can be used as a synonym for %psearch, at the beginning or at
620 620 the end: both a*? and ?a* are equivalent to '%psearch a*'. Still, the
621 621 rest of the command line must be unchanged (options come first), so
622 622 for example the following forms are equivalent
623 623
624 624 %psearch -i a* function
625 625 -i a* function?
626 626 ?-i a* function
627 627
628 628 Arguments:
629 629
630 630 PATTERN
631 631
632 632 where PATTERN is a string containing * as a wildcard similar to its
633 633 use in a shell. The pattern is matched in all namespaces on the
634 634 search path. By default objects starting with a single _ are not
635 635 matched, many IPython generated objects have a single
636 636 underscore. The default is case insensitive matching. Matching is
637 637 also done on the attributes of objects and not only on the objects
638 638 in a module.
639 639
640 640 [OBJECT TYPE]
641 641
642 642 Is the name of a python type from the types module. The name is
643 643 given in lowercase without the ending type, ex. StringType is
644 644 written string. By adding a type here only objects matching the
645 645 given type are matched. Using all here makes the pattern match all
646 646 types (this is the default).
647 647
648 648 Options:
649 649
650 650 -a: makes the pattern match even objects whose names start with a
651 651 single underscore. These names are normally ommitted from the
652 652 search.
653 653
654 654 -i/-c: make the pattern case insensitive/sensitive. If neither of
655 655 these options are given, the default is read from your configuration
656 656 file, with the option ``InteractiveShell.wildcards_case_sensitive``.
657 657 If this option is not specified in your configuration file, IPython's
658 658 internal default is to do a case sensitive search.
659 659
660 660 -e/-s NAMESPACE: exclude/search a given namespace. The pattern you
661 661 specifiy can be searched in any of the following namespaces:
662 662 'builtin', 'user', 'user_global','internal', 'alias', where
663 663 'builtin' and 'user' are the search defaults. Note that you should
664 664 not use quotes when specifying namespaces.
665 665
666 666 'Builtin' contains the python module builtin, 'user' contains all
667 667 user data, 'alias' only contain the shell aliases and no python
668 668 objects, 'internal' contains objects used by IPython. The
669 669 'user_global' namespace is only used by embedded IPython instances,
670 670 and it contains module-level globals. You can add namespaces to the
671 671 search with -s or exclude them with -e (these options can be given
672 672 more than once).
673 673
674 674 Examples:
675 675
676 676 %psearch a* -> objects beginning with an a
677 677 %psearch -e builtin a* -> objects NOT in the builtin space starting in a
678 678 %psearch a* function -> all functions beginning with an a
679 679 %psearch re.e* -> objects beginning with an e in module re
680 680 %psearch r*.e* -> objects that start with e in modules starting in r
681 681 %psearch r*.* string -> all strings in modules beginning with r
682 682
683 683 Case sensitve search:
684 684
685 685 %psearch -c a* list all object beginning with lower case a
686 686
687 687 Show objects beginning with a single _:
688 688
689 689 %psearch -a _* list objects beginning with a single underscore"""
690 690 try:
691 691 parameter_s.encode('ascii')
692 692 except UnicodeEncodeError:
693 693 print 'Python identifiers can only contain ascii characters.'
694 694 return
695 695
696 696 # default namespaces to be searched
697 697 def_search = ['user','builtin']
698 698
699 699 # Process options/args
700 700 opts,args = self.parse_options(parameter_s,'cias:e:',list_all=True)
701 701 opt = opts.get
702 702 shell = self.shell
703 703 psearch = shell.inspector.psearch
704 704
705 705 # select case options
706 706 if opts.has_key('i'):
707 707 ignore_case = True
708 708 elif opts.has_key('c'):
709 709 ignore_case = False
710 710 else:
711 711 ignore_case = not shell.wildcards_case_sensitive
712 712
713 713 # Build list of namespaces to search from user options
714 714 def_search.extend(opt('s',[]))
715 715 ns_exclude = ns_exclude=opt('e',[])
716 716 ns_search = [nm for nm in def_search if nm not in ns_exclude]
717 717
718 718 # Call the actual search
719 719 try:
720 720 psearch(args,shell.ns_table,ns_search,
721 721 show_all=opt('a'),ignore_case=ignore_case)
722 722 except:
723 723 shell.showtraceback()
724 724
725 725 @skip_doctest
726 726 def magic_who_ls(self, parameter_s=''):
727 727 """Return a sorted list of all interactive variables.
728 728
729 729 If arguments are given, only variables of types matching these
730 730 arguments are returned.
731 731
732 732 Examples
733 733 --------
734 734
735 735 Define two variables and list them with who_ls::
736 736
737 737 In [1]: alpha = 123
738 738
739 739 In [2]: beta = 'test'
740 740
741 741 In [3]: %who_ls
742 742 Out[3]: ['alpha', 'beta']
743 743
744 744 In [4]: %who_ls int
745 745 Out[4]: ['alpha']
746 746
747 747 In [5]: %who_ls str
748 748 Out[5]: ['beta']
749 749 """
750 750
751 751 user_ns = self.shell.user_ns
752 752 internal_ns = self.shell.internal_ns
753 753 user_ns_hidden = self.shell.user_ns_hidden
754 754 out = [ i for i in user_ns
755 755 if not i.startswith('_') \
756 756 and not (i in internal_ns or i in user_ns_hidden) ]
757 757
758 758 typelist = parameter_s.split()
759 759 if typelist:
760 760 typeset = set(typelist)
761 761 out = [i for i in out if type(user_ns[i]).__name__ in typeset]
762 762
763 763 out.sort()
764 764 return out
765 765
766 766 @skip_doctest
767 767 def magic_who(self, parameter_s=''):
768 768 """Print all interactive variables, with some minimal formatting.
769 769
770 770 If any arguments are given, only variables whose type matches one of
771 771 these are printed. For example:
772 772
773 773 %who function str
774 774
775 775 will only list functions and strings, excluding all other types of
776 776 variables. To find the proper type names, simply use type(var) at a
777 777 command line to see how python prints type names. For example:
778 778
779 779 In [1]: type('hello')\\
780 780 Out[1]: <type 'str'>
781 781
782 782 indicates that the type name for strings is 'str'.
783 783
784 784 %who always excludes executed names loaded through your configuration
785 785 file and things which are internal to IPython.
786 786
787 787 This is deliberate, as typically you may load many modules and the
788 788 purpose of %who is to show you only what you've manually defined.
789 789
790 790 Examples
791 791 --------
792 792
793 793 Define two variables and list them with who::
794 794
795 795 In [1]: alpha = 123
796 796
797 797 In [2]: beta = 'test'
798 798
799 799 In [3]: %who
800 800 alpha beta
801 801
802 802 In [4]: %who int
803 803 alpha
804 804
805 805 In [5]: %who str
806 806 beta
807 807 """
808 808
809 809 varlist = self.magic_who_ls(parameter_s)
810 810 if not varlist:
811 811 if parameter_s:
812 812 print 'No variables match your requested type.'
813 813 else:
814 814 print 'Interactive namespace is empty.'
815 815 return
816 816
817 817 # if we have variables, move on...
818 818 count = 0
819 819 for i in varlist:
820 820 print i+'\t',
821 821 count += 1
822 822 if count > 8:
823 823 count = 0
824 824 print
825 825 print
826 826
827 827 @skip_doctest
828 828 def magic_whos(self, parameter_s=''):
829 829 """Like %who, but gives some extra information about each variable.
830 830
831 831 The same type filtering of %who can be applied here.
832 832
833 833 For all variables, the type is printed. Additionally it prints:
834 834
835 835 - For {},[],(): their length.
836 836
837 837 - For numpy arrays, a summary with shape, number of
838 838 elements, typecode and size in memory.
839 839
840 840 - Everything else: a string representation, snipping their middle if
841 841 too long.
842 842
843 843 Examples
844 844 --------
845 845
846 846 Define two variables and list them with whos::
847 847
848 848 In [1]: alpha = 123
849 849
850 850 In [2]: beta = 'test'
851 851
852 852 In [3]: %whos
853 853 Variable Type Data/Info
854 854 --------------------------------
855 855 alpha int 123
856 856 beta str test
857 857 """
858 858
859 859 varnames = self.magic_who_ls(parameter_s)
860 860 if not varnames:
861 861 if parameter_s:
862 862 print 'No variables match your requested type.'
863 863 else:
864 864 print 'Interactive namespace is empty.'
865 865 return
866 866
867 867 # if we have variables, move on...
868 868
869 869 # for these types, show len() instead of data:
870 870 seq_types = ['dict', 'list', 'tuple']
871 871
872 872 # for numpy arrays, display summary info
873 873 ndarray_type = None
874 874 if 'numpy' in sys.modules:
875 875 try:
876 876 from numpy import ndarray
877 877 except ImportError:
878 878 pass
879 879 else:
880 880 ndarray_type = ndarray.__name__
881 881
882 882 # Find all variable names and types so we can figure out column sizes
883 883 def get_vars(i):
884 884 return self.shell.user_ns[i]
885 885
886 886 # some types are well known and can be shorter
887 887 abbrevs = {'IPython.core.macro.Macro' : 'Macro'}
888 888 def type_name(v):
889 889 tn = type(v).__name__
890 890 return abbrevs.get(tn,tn)
891 891
892 892 varlist = map(get_vars,varnames)
893 893
894 894 typelist = []
895 895 for vv in varlist:
896 896 tt = type_name(vv)
897 897
898 898 if tt=='instance':
899 899 typelist.append( abbrevs.get(str(vv.__class__),
900 900 str(vv.__class__)))
901 901 else:
902 902 typelist.append(tt)
903 903
904 904 # column labels and # of spaces as separator
905 905 varlabel = 'Variable'
906 906 typelabel = 'Type'
907 907 datalabel = 'Data/Info'
908 908 colsep = 3
909 909 # variable format strings
910 910 vformat = "{0:<{varwidth}}{1:<{typewidth}}"
911 911 aformat = "%s: %s elems, type `%s`, %s bytes"
912 912 # find the size of the columns to format the output nicely
913 913 varwidth = max(max(map(len,varnames)), len(varlabel)) + colsep
914 914 typewidth = max(max(map(len,typelist)), len(typelabel)) + colsep
915 915 # table header
916 916 print varlabel.ljust(varwidth) + typelabel.ljust(typewidth) + \
917 917 ' '+datalabel+'\n' + '-'*(varwidth+typewidth+len(datalabel)+1)
918 918 # and the table itself
919 919 kb = 1024
920 920 Mb = 1048576 # kb**2
921 921 for vname,var,vtype in zip(varnames,varlist,typelist):
922 922 print vformat.format(vname, vtype, varwidth=varwidth, typewidth=typewidth),
923 923 if vtype in seq_types:
924 924 print "n="+str(len(var))
925 925 elif vtype == ndarray_type:
926 926 vshape = str(var.shape).replace(',','').replace(' ','x')[1:-1]
927 927 if vtype==ndarray_type:
928 928 # numpy
929 929 vsize = var.size
930 930 vbytes = vsize*var.itemsize
931 931 vdtype = var.dtype
932 932 else:
933 933 # Numeric
934 934 vsize = Numeric.size(var)
935 935 vbytes = vsize*var.itemsize()
936 936 vdtype = var.typecode()
937 937
938 938 if vbytes < 100000:
939 939 print aformat % (vshape,vsize,vdtype,vbytes)
940 940 else:
941 941 print aformat % (vshape,vsize,vdtype,vbytes),
942 942 if vbytes < Mb:
943 943 print '(%s kb)' % (vbytes/kb,)
944 944 else:
945 945 print '(%s Mb)' % (vbytes/Mb,)
946 946 else:
947 947 try:
948 948 vstr = str(var)
949 949 except UnicodeEncodeError:
950 950 vstr = unicode(var).encode(sys.getdefaultencoding(),
951 951 'backslashreplace')
952 952 vstr = vstr.replace('\n','\\n')
953 953 if len(vstr) < 50:
954 954 print vstr
955 955 else:
956 956 print vstr[:25] + "<...>" + vstr[-25:]
957 957
958 958 def magic_reset(self, parameter_s=''):
959 959 """Resets the namespace by removing all names defined by the user.
960 960
961 961 Parameters
962 962 ----------
963 963 -f : force reset without asking for confirmation.
964 964
965 965 -s : 'Soft' reset: Only clears your namespace, leaving history intact.
966 966 References to objects may be kept. By default (without this option),
967 967 we do a 'hard' reset, giving you a new session and removing all
968 968 references to objects from the current session.
969 969
970 970 Examples
971 971 --------
972 972 In [6]: a = 1
973 973
974 974 In [7]: a
975 975 Out[7]: 1
976 976
977 977 In [8]: 'a' in _ip.user_ns
978 978 Out[8]: True
979 979
980 980 In [9]: %reset -f
981 981
982 982 In [1]: 'a' in _ip.user_ns
983 983 Out[1]: False
984 984 """
985 985 opts, args = self.parse_options(parameter_s,'sf')
986 986 if 'f' in opts:
987 987 ans = True
988 988 else:
989 989 ans = self.shell.ask_yes_no(
990 990 "Once deleted, variables cannot be recovered. Proceed (y/[n])? ", default='n')
991 991 if not ans:
992 992 print 'Nothing done.'
993 993 return
994 994
995 995 if 's' in opts: # Soft reset
996 996 user_ns = self.shell.user_ns
997 997 for i in self.magic_who_ls():
998 998 del(user_ns[i])
999 999
1000 1000 else: # Hard reset
1001 1001 self.shell.reset(new_session = False)
1002 1002
1003 1003
1004 1004
1005 1005 def magic_reset_selective(self, parameter_s=''):
1006 1006 """Resets the namespace by removing names defined by the user.
1007 1007
1008 1008 Input/Output history are left around in case you need them.
1009 1009
1010 1010 %reset_selective [-f] regex
1011 1011
1012 1012 No action is taken if regex is not included
1013 1013
1014 1014 Options
1015 1015 -f : force reset without asking for confirmation.
1016 1016
1017 1017 Examples
1018 1018 --------
1019 1019
1020 1020 We first fully reset the namespace so your output looks identical to
1021 1021 this example for pedagogical reasons; in practice you do not need a
1022 1022 full reset.
1023 1023
1024 1024 In [1]: %reset -f
1025 1025
1026 1026 Now, with a clean namespace we can make a few variables and use
1027 1027 %reset_selective to only delete names that match our regexp:
1028 1028
1029 1029 In [2]: a=1; b=2; c=3; b1m=4; b2m=5; b3m=6; b4m=7; b2s=8
1030 1030
1031 1031 In [3]: who_ls
1032 1032 Out[3]: ['a', 'b', 'b1m', 'b2m', 'b2s', 'b3m', 'b4m', 'c']
1033 1033
1034 1034 In [4]: %reset_selective -f b[2-3]m
1035 1035
1036 1036 In [5]: who_ls
1037 1037 Out[5]: ['a', 'b', 'b1m', 'b2s', 'b4m', 'c']
1038 1038
1039 1039 In [6]: %reset_selective -f d
1040 1040
1041 1041 In [7]: who_ls
1042 1042 Out[7]: ['a', 'b', 'b1m', 'b2s', 'b4m', 'c']
1043 1043
1044 1044 In [8]: %reset_selective -f c
1045 1045
1046 1046 In [9]: who_ls
1047 1047 Out[9]: ['a', 'b', 'b1m', 'b2s', 'b4m']
1048 1048
1049 1049 In [10]: %reset_selective -f b
1050 1050
1051 1051 In [11]: who_ls
1052 1052 Out[11]: ['a']
1053 1053 """
1054 1054
1055 1055 opts, regex = self.parse_options(parameter_s,'f')
1056 1056
1057 1057 if opts.has_key('f'):
1058 1058 ans = True
1059 1059 else:
1060 1060 ans = self.shell.ask_yes_no(
1061 1061 "Once deleted, variables cannot be recovered. Proceed (y/[n])? ",
1062 1062 default='n')
1063 1063 if not ans:
1064 1064 print 'Nothing done.'
1065 1065 return
1066 1066 user_ns = self.shell.user_ns
1067 1067 if not regex:
1068 1068 print 'No regex pattern specified. Nothing done.'
1069 1069 return
1070 1070 else:
1071 1071 try:
1072 1072 m = re.compile(regex)
1073 1073 except TypeError:
1074 1074 raise TypeError('regex must be a string or compiled pattern')
1075 1075 for i in self.magic_who_ls():
1076 1076 if m.search(i):
1077 1077 del(user_ns[i])
1078 1078
1079 1079 def magic_xdel(self, parameter_s=''):
1080 1080 """Delete a variable, trying to clear it from anywhere that
1081 1081 IPython's machinery has references to it. By default, this uses
1082 1082 the identity of the named object in the user namespace to remove
1083 1083 references held under other names. The object is also removed
1084 1084 from the output history.
1085 1085
1086 1086 Options
1087 1087 -n : Delete the specified name from all namespaces, without
1088 1088 checking their identity.
1089 1089 """
1090 1090 opts, varname = self.parse_options(parameter_s,'n')
1091 1091 try:
1092 1092 self.shell.del_var(varname, ('n' in opts))
1093 1093 except (NameError, ValueError) as e:
1094 1094 print type(e).__name__ +": "+ str(e)
1095 1095
1096 1096 def magic_logstart(self,parameter_s=''):
1097 1097 """Start logging anywhere in a session.
1098 1098
1099 1099 %logstart [-o|-r|-t] [log_name [log_mode]]
1100 1100
1101 1101 If no name is given, it defaults to a file named 'ipython_log.py' in your
1102 1102 current directory, in 'rotate' mode (see below).
1103 1103
1104 1104 '%logstart name' saves to file 'name' in 'backup' mode. It saves your
1105 1105 history up to that point and then continues logging.
1106 1106
1107 1107 %logstart takes a second optional parameter: logging mode. This can be one
1108 1108 of (note that the modes are given unquoted):\\
1109 1109 append: well, that says it.\\
1110 1110 backup: rename (if exists) to name~ and start name.\\
1111 1111 global: single logfile in your home dir, appended to.\\
1112 1112 over : overwrite existing log.\\
1113 1113 rotate: create rotating logs name.1~, name.2~, etc.
1114 1114
1115 1115 Options:
1116 1116
1117 1117 -o: log also IPython's output. In this mode, all commands which
1118 1118 generate an Out[NN] prompt are recorded to the logfile, right after
1119 1119 their corresponding input line. The output lines are always
1120 1120 prepended with a '#[Out]# ' marker, so that the log remains valid
1121 1121 Python code.
1122 1122
1123 1123 Since this marker is always the same, filtering only the output from
1124 1124 a log is very easy, using for example a simple awk call:
1125 1125
1126 1126 awk -F'#\\[Out\\]# ' '{if($2) {print $2}}' ipython_log.py
1127 1127
1128 1128 -r: log 'raw' input. Normally, IPython's logs contain the processed
1129 1129 input, so that user lines are logged in their final form, converted
1130 1130 into valid Python. For example, %Exit is logged as
1131 1131 '_ip.magic("Exit"). If the -r flag is given, all input is logged
1132 1132 exactly as typed, with no transformations applied.
1133 1133
1134 1134 -t: put timestamps before each input line logged (these are put in
1135 1135 comments)."""
1136 1136
1137 1137 opts,par = self.parse_options(parameter_s,'ort')
1138 1138 log_output = 'o' in opts
1139 1139 log_raw_input = 'r' in opts
1140 1140 timestamp = 't' in opts
1141 1141
1142 1142 logger = self.shell.logger
1143 1143
1144 1144 # if no args are given, the defaults set in the logger constructor by
1145 1145 # ipytohn remain valid
1146 1146 if par:
1147 1147 try:
1148 1148 logfname,logmode = par.split()
1149 1149 except:
1150 1150 logfname = par
1151 1151 logmode = 'backup'
1152 1152 else:
1153 1153 logfname = logger.logfname
1154 1154 logmode = logger.logmode
1155 1155 # put logfname into rc struct as if it had been called on the command
1156 1156 # line, so it ends up saved in the log header Save it in case we need
1157 1157 # to restore it...
1158 1158 old_logfile = self.shell.logfile
1159 1159 if logfname:
1160 1160 logfname = os.path.expanduser(logfname)
1161 1161 self.shell.logfile = logfname
1162 1162
1163 1163 loghead = '# IPython log file\n\n'
1164 1164 try:
1165 1165 started = logger.logstart(logfname,loghead,logmode,
1166 1166 log_output,timestamp,log_raw_input)
1167 1167 except:
1168 1168 self.shell.logfile = old_logfile
1169 1169 warn("Couldn't start log: %s" % sys.exc_info()[1])
1170 1170 else:
1171 1171 # log input history up to this point, optionally interleaving
1172 1172 # output if requested
1173 1173
1174 1174 if timestamp:
1175 1175 # disable timestamping for the previous history, since we've
1176 1176 # lost those already (no time machine here).
1177 1177 logger.timestamp = False
1178 1178
1179 1179 if log_raw_input:
1180 1180 input_hist = self.shell.history_manager.input_hist_raw
1181 1181 else:
1182 1182 input_hist = self.shell.history_manager.input_hist_parsed
1183 1183
1184 1184 if log_output:
1185 1185 log_write = logger.log_write
1186 1186 output_hist = self.shell.history_manager.output_hist
1187 1187 for n in range(1,len(input_hist)-1):
1188 1188 log_write(input_hist[n].rstrip() + '\n')
1189 1189 if n in output_hist:
1190 1190 log_write(repr(output_hist[n]),'output')
1191 1191 else:
1192 1192 logger.log_write('\n'.join(input_hist[1:]))
1193 1193 logger.log_write('\n')
1194 1194 if timestamp:
1195 1195 # re-enable timestamping
1196 1196 logger.timestamp = True
1197 1197
1198 1198 print ('Activating auto-logging. '
1199 1199 'Current session state plus future input saved.')
1200 1200 logger.logstate()
1201 1201
1202 1202 def magic_logstop(self,parameter_s=''):
1203 1203 """Fully stop logging and close log file.
1204 1204
1205 1205 In order to start logging again, a new %logstart call needs to be made,
1206 1206 possibly (though not necessarily) with a new filename, mode and other
1207 1207 options."""
1208 1208 self.logger.logstop()
1209 1209
1210 1210 def magic_logoff(self,parameter_s=''):
1211 1211 """Temporarily stop logging.
1212 1212
1213 1213 You must have previously started logging."""
1214 1214 self.shell.logger.switch_log(0)
1215 1215
1216 1216 def magic_logon(self,parameter_s=''):
1217 1217 """Restart logging.
1218 1218
1219 1219 This function is for restarting logging which you've temporarily
1220 1220 stopped with %logoff. For starting logging for the first time, you
1221 1221 must use the %logstart function, which allows you to specify an
1222 1222 optional log filename."""
1223 1223
1224 1224 self.shell.logger.switch_log(1)
1225 1225
1226 1226 def magic_logstate(self,parameter_s=''):
1227 1227 """Print the status of the logging system."""
1228 1228
1229 1229 self.shell.logger.logstate()
1230 1230
1231 1231 def magic_pdb(self, parameter_s=''):
1232 1232 """Control the automatic calling of the pdb interactive debugger.
1233 1233
1234 1234 Call as '%pdb on', '%pdb 1', '%pdb off' or '%pdb 0'. If called without
1235 1235 argument it works as a toggle.
1236 1236
1237 1237 When an exception is triggered, IPython can optionally call the
1238 1238 interactive pdb debugger after the traceback printout. %pdb toggles
1239 1239 this feature on and off.
1240 1240
1241 1241 The initial state of this feature is set in your configuration
1242 1242 file (the option is ``InteractiveShell.pdb``).
1243 1243
1244 1244 If you want to just activate the debugger AFTER an exception has fired,
1245 1245 without having to type '%pdb on' and rerunning your code, you can use
1246 1246 the %debug magic."""
1247 1247
1248 1248 par = parameter_s.strip().lower()
1249 1249
1250 1250 if par:
1251 1251 try:
1252 1252 new_pdb = {'off':0,'0':0,'on':1,'1':1}[par]
1253 1253 except KeyError:
1254 1254 print ('Incorrect argument. Use on/1, off/0, '
1255 1255 'or nothing for a toggle.')
1256 1256 return
1257 1257 else:
1258 1258 # toggle
1259 1259 new_pdb = not self.shell.call_pdb
1260 1260
1261 1261 # set on the shell
1262 1262 self.shell.call_pdb = new_pdb
1263 1263 print 'Automatic pdb calling has been turned',on_off(new_pdb)
1264 1264
1265 1265 def magic_debug(self, parameter_s=''):
1266 1266 """Activate the interactive debugger in post-mortem mode.
1267 1267
1268 1268 If an exception has just occurred, this lets you inspect its stack
1269 1269 frames interactively. Note that this will always work only on the last
1270 1270 traceback that occurred, so you must call this quickly after an
1271 1271 exception that you wish to inspect has fired, because if another one
1272 1272 occurs, it clobbers the previous one.
1273 1273
1274 1274 If you want IPython to automatically do this on every exception, see
1275 1275 the %pdb magic for more details.
1276 1276 """
1277 1277 self.shell.debugger(force=True)
1278 1278
1279 1279 @skip_doctest
1280 1280 def magic_prun(self, parameter_s ='',user_mode=1,
1281 1281 opts=None,arg_lst=None,prog_ns=None):
1282 1282
1283 1283 """Run a statement through the python code profiler.
1284 1284
1285 1285 Usage:
1286 1286 %prun [options] statement
1287 1287
1288 1288 The given statement (which doesn't require quote marks) is run via the
1289 1289 python profiler in a manner similar to the profile.run() function.
1290 1290 Namespaces are internally managed to work correctly; profile.run
1291 1291 cannot be used in IPython because it makes certain assumptions about
1292 1292 namespaces which do not hold under IPython.
1293 1293
1294 1294 Options:
1295 1295
1296 1296 -l <limit>: you can place restrictions on what or how much of the
1297 1297 profile gets printed. The limit value can be:
1298 1298
1299 1299 * A string: only information for function names containing this string
1300 1300 is printed.
1301 1301
1302 1302 * An integer: only these many lines are printed.
1303 1303
1304 1304 * A float (between 0 and 1): this fraction of the report is printed
1305 1305 (for example, use a limit of 0.4 to see the topmost 40% only).
1306 1306
1307 1307 You can combine several limits with repeated use of the option. For
1308 1308 example, '-l __init__ -l 5' will print only the topmost 5 lines of
1309 1309 information about class constructors.
1310 1310
1311 1311 -r: return the pstats.Stats object generated by the profiling. This
1312 1312 object has all the information about the profile in it, and you can
1313 1313 later use it for further analysis or in other functions.
1314 1314
1315 1315 -s <key>: sort profile by given key. You can provide more than one key
1316 1316 by using the option several times: '-s key1 -s key2 -s key3...'. The
1317 1317 default sorting key is 'time'.
1318 1318
1319 1319 The following is copied verbatim from the profile documentation
1320 1320 referenced below:
1321 1321
1322 1322 When more than one key is provided, additional keys are used as
1323 1323 secondary criteria when the there is equality in all keys selected
1324 1324 before them.
1325 1325
1326 1326 Abbreviations can be used for any key names, as long as the
1327 1327 abbreviation is unambiguous. The following are the keys currently
1328 1328 defined:
1329 1329
1330 1330 Valid Arg Meaning
1331 1331 "calls" call count
1332 1332 "cumulative" cumulative time
1333 1333 "file" file name
1334 1334 "module" file name
1335 1335 "pcalls" primitive call count
1336 1336 "line" line number
1337 1337 "name" function name
1338 1338 "nfl" name/file/line
1339 1339 "stdname" standard name
1340 1340 "time" internal time
1341 1341
1342 1342 Note that all sorts on statistics are in descending order (placing
1343 1343 most time consuming items first), where as name, file, and line number
1344 1344 searches are in ascending order (i.e., alphabetical). The subtle
1345 1345 distinction between "nfl" and "stdname" is that the standard name is a
1346 1346 sort of the name as printed, which means that the embedded line
1347 1347 numbers get compared in an odd way. For example, lines 3, 20, and 40
1348 1348 would (if the file names were the same) appear in the string order
1349 1349 "20" "3" and "40". In contrast, "nfl" does a numeric compare of the
1350 1350 line numbers. In fact, sort_stats("nfl") is the same as
1351 1351 sort_stats("name", "file", "line").
1352 1352
1353 1353 -T <filename>: save profile results as shown on screen to a text
1354 1354 file. The profile is still shown on screen.
1355 1355
1356 1356 -D <filename>: save (via dump_stats) profile statistics to given
1357 1357 filename. This data is in a format understod by the pstats module, and
1358 1358 is generated by a call to the dump_stats() method of profile
1359 1359 objects. The profile is still shown on screen.
1360 1360
1361 1361 If you want to run complete programs under the profiler's control, use
1362 1362 '%run -p [prof_opts] filename.py [args to program]' where prof_opts
1363 1363 contains profiler specific options as described here.
1364 1364
1365 1365 You can read the complete documentation for the profile module with::
1366 1366
1367 1367 In [1]: import profile; profile.help()
1368 1368 """
1369 1369
1370 1370 opts_def = Struct(D=[''],l=[],s=['time'],T=[''])
1371 1371 # protect user quote marks
1372 1372 parameter_s = parameter_s.replace('"',r'\"').replace("'",r"\'")
1373 1373
1374 1374 if user_mode: # regular user call
1375 1375 opts,arg_str = self.parse_options(parameter_s,'D:l:rs:T:',
1376 1376 list_all=1)
1377 1377 namespace = self.shell.user_ns
1378 1378 else: # called to run a program by %run -p
1379 1379 try:
1380 1380 filename = get_py_filename(arg_lst[0])
1381 1381 except IOError as e:
1382 1382 try:
1383 1383 msg = str(e)
1384 1384 except UnicodeError:
1385 1385 msg = e.message
1386 1386 error(msg)
1387 1387 return
1388 1388
1389 1389 arg_str = 'execfile(filename,prog_ns)'
1390 1390 namespace = {
1391 1391 'execfile': self.shell.safe_execfile,
1392 1392 'prog_ns': prog_ns,
1393 1393 'filename': filename
1394 1394 }
1395 1395
1396 1396 opts.merge(opts_def)
1397 1397
1398 1398 prof = profile.Profile()
1399 1399 try:
1400 1400 prof = prof.runctx(arg_str,namespace,namespace)
1401 1401 sys_exit = ''
1402 1402 except SystemExit:
1403 1403 sys_exit = """*** SystemExit exception caught in code being profiled."""
1404 1404
1405 1405 stats = pstats.Stats(prof).strip_dirs().sort_stats(*opts.s)
1406 1406
1407 1407 lims = opts.l
1408 1408 if lims:
1409 1409 lims = [] # rebuild lims with ints/floats/strings
1410 1410 for lim in opts.l:
1411 1411 try:
1412 1412 lims.append(int(lim))
1413 1413 except ValueError:
1414 1414 try:
1415 1415 lims.append(float(lim))
1416 1416 except ValueError:
1417 1417 lims.append(lim)
1418 1418
1419 1419 # Trap output.
1420 1420 stdout_trap = StringIO()
1421 1421
1422 1422 if hasattr(stats,'stream'):
1423 1423 # In newer versions of python, the stats object has a 'stream'
1424 1424 # attribute to write into.
1425 1425 stats.stream = stdout_trap
1426 1426 stats.print_stats(*lims)
1427 1427 else:
1428 1428 # For older versions, we manually redirect stdout during printing
1429 1429 sys_stdout = sys.stdout
1430 1430 try:
1431 1431 sys.stdout = stdout_trap
1432 1432 stats.print_stats(*lims)
1433 1433 finally:
1434 1434 sys.stdout = sys_stdout
1435 1435
1436 1436 output = stdout_trap.getvalue()
1437 1437 output = output.rstrip()
1438 1438
1439 1439 page.page(output)
1440 1440 print sys_exit,
1441 1441
1442 1442 dump_file = opts.D[0]
1443 1443 text_file = opts.T[0]
1444 1444 if dump_file:
1445 1445 dump_file = unquote_filename(dump_file)
1446 1446 prof.dump_stats(dump_file)
1447 1447 print '\n*** Profile stats marshalled to file',\
1448 1448 `dump_file`+'.',sys_exit
1449 1449 if text_file:
1450 1450 text_file = unquote_filename(text_file)
1451 1451 pfile = file(text_file,'w')
1452 1452 pfile.write(output)
1453 1453 pfile.close()
1454 1454 print '\n*** Profile printout saved to text file',\
1455 1455 `text_file`+'.',sys_exit
1456 1456
1457 1457 if opts.has_key('r'):
1458 1458 return stats
1459 1459 else:
1460 1460 return None
1461 1461
1462 1462 @skip_doctest
1463 1463 def magic_run(self, parameter_s ='', runner=None,
1464 1464 file_finder=get_py_filename):
1465 1465 """Run the named file inside IPython as a program.
1466 1466
1467 1467 Usage:\\
1468 1468 %run [-n -i -t [-N<N>] -d [-b<N>] -p [profile options]] file [args]
1469 1469
1470 1470 Parameters after the filename are passed as command-line arguments to
1471 1471 the program (put in sys.argv). Then, control returns to IPython's
1472 1472 prompt.
1473 1473
1474 1474 This is similar to running at a system prompt:\\
1475 1475 $ python file args\\
1476 1476 but with the advantage of giving you IPython's tracebacks, and of
1477 1477 loading all variables into your interactive namespace for further use
1478 1478 (unless -p is used, see below).
1479 1479
1480 1480 The file is executed in a namespace initially consisting only of
1481 1481 __name__=='__main__' and sys.argv constructed as indicated. It thus
1482 1482 sees its environment as if it were being run as a stand-alone program
1483 1483 (except for sharing global objects such as previously imported
1484 1484 modules). But after execution, the IPython interactive namespace gets
1485 1485 updated with all variables defined in the program (except for __name__
1486 1486 and sys.argv). This allows for very convenient loading of code for
1487 1487 interactive work, while giving each program a 'clean sheet' to run in.
1488 1488
1489 1489 Options:
1490 1490
1491 1491 -n: __name__ is NOT set to '__main__', but to the running file's name
1492 1492 without extension (as python does under import). This allows running
1493 1493 scripts and reloading the definitions in them without calling code
1494 1494 protected by an ' if __name__ == "__main__" ' clause.
1495 1495
1496 1496 -i: run the file in IPython's namespace instead of an empty one. This
1497 1497 is useful if you are experimenting with code written in a text editor
1498 1498 which depends on variables defined interactively.
1499 1499
1500 1500 -e: ignore sys.exit() calls or SystemExit exceptions in the script
1501 1501 being run. This is particularly useful if IPython is being used to
1502 1502 run unittests, which always exit with a sys.exit() call. In such
1503 1503 cases you are interested in the output of the test results, not in
1504 1504 seeing a traceback of the unittest module.
1505 1505
1506 1506 -t: print timing information at the end of the run. IPython will give
1507 1507 you an estimated CPU time consumption for your script, which under
1508 1508 Unix uses the resource module to avoid the wraparound problems of
1509 1509 time.clock(). Under Unix, an estimate of time spent on system tasks
1510 1510 is also given (for Windows platforms this is reported as 0.0).
1511 1511
1512 1512 If -t is given, an additional -N<N> option can be given, where <N>
1513 1513 must be an integer indicating how many times you want the script to
1514 1514 run. The final timing report will include total and per run results.
1515 1515
1516 1516 For example (testing the script uniq_stable.py):
1517 1517
1518 1518 In [1]: run -t uniq_stable
1519 1519
1520 1520 IPython CPU timings (estimated):\\
1521 1521 User : 0.19597 s.\\
1522 1522 System: 0.0 s.\\
1523 1523
1524 1524 In [2]: run -t -N5 uniq_stable
1525 1525
1526 1526 IPython CPU timings (estimated):\\
1527 1527 Total runs performed: 5\\
1528 1528 Times : Total Per run\\
1529 1529 User : 0.910862 s, 0.1821724 s.\\
1530 1530 System: 0.0 s, 0.0 s.
1531 1531
1532 1532 -d: run your program under the control of pdb, the Python debugger.
1533 1533 This allows you to execute your program step by step, watch variables,
1534 1534 etc. Internally, what IPython does is similar to calling:
1535 1535
1536 1536 pdb.run('execfile("YOURFILENAME")')
1537 1537
1538 1538 with a breakpoint set on line 1 of your file. You can change the line
1539 1539 number for this automatic breakpoint to be <N> by using the -bN option
1540 1540 (where N must be an integer). For example:
1541 1541
1542 1542 %run -d -b40 myscript
1543 1543
1544 1544 will set the first breakpoint at line 40 in myscript.py. Note that
1545 1545 the first breakpoint must be set on a line which actually does
1546 1546 something (not a comment or docstring) for it to stop execution.
1547 1547
1548 1548 When the pdb debugger starts, you will see a (Pdb) prompt. You must
1549 1549 first enter 'c' (without qoutes) to start execution up to the first
1550 1550 breakpoint.
1551 1551
1552 1552 Entering 'help' gives information about the use of the debugger. You
1553 1553 can easily see pdb's full documentation with "import pdb;pdb.help()"
1554 1554 at a prompt.
1555 1555
1556 1556 -p: run program under the control of the Python profiler module (which
1557 1557 prints a detailed report of execution times, function calls, etc).
1558 1558
1559 1559 You can pass other options after -p which affect the behavior of the
1560 1560 profiler itself. See the docs for %prun for details.
1561 1561
1562 1562 In this mode, the program's variables do NOT propagate back to the
1563 1563 IPython interactive namespace (because they remain in the namespace
1564 1564 where the profiler executes them).
1565 1565
1566 1566 Internally this triggers a call to %prun, see its documentation for
1567 1567 details on the options available specifically for profiling.
1568 1568
1569 1569 There is one special usage for which the text above doesn't apply:
1570 1570 if the filename ends with .ipy, the file is run as ipython script,
1571 1571 just as if the commands were written on IPython prompt.
1572 1572
1573 1573 -m: specify module name to load instead of script path. Similar to
1574 1574 the -m option for the python interpreter. Use this option last if you
1575 1575 want to combine with other %run options. Unlike the python interpreter
1576 1576 only source modules are allowed no .pyc or .pyo files.
1577 1577 For example:
1578 1578
1579 1579 %run -m example
1580 1580
1581 1581 will run the example module.
1582 1582
1583 1583 """
1584 1584
1585 1585 # get arguments and set sys.argv for program to be run.
1586 1586 opts, arg_lst = self.parse_options(parameter_s, 'nidtN:b:pD:l:rs:T:em:',
1587 1587 mode='list', list_all=1)
1588 1588 if "m" in opts:
1589 1589 modulename = opts["m"][0]
1590 1590 modpath = find_mod(modulename)
1591 1591 if modpath is None:
1592 1592 warn('%r is not a valid modulename on sys.path'%modulename)
1593 1593 return
1594 1594 arg_lst = [modpath] + arg_lst
1595 1595 try:
1596 1596 filename = file_finder(arg_lst[0])
1597 1597 except IndexError:
1598 1598 warn('you must provide at least a filename.')
1599 1599 print '\n%run:\n', oinspect.getdoc(self.magic_run)
1600 1600 return
1601 1601 except IOError as e:
1602 1602 try:
1603 1603 msg = str(e)
1604 1604 except UnicodeError:
1605 1605 msg = e.message
1606 1606 error(msg)
1607 1607 return
1608 1608
1609 1609 if filename.lower().endswith('.ipy'):
1610 1610 self.shell.safe_execfile_ipy(filename)
1611 1611 return
1612 1612
1613 1613 # Control the response to exit() calls made by the script being run
1614 1614 exit_ignore = 'e' in opts
1615 1615
1616 1616 # Make sure that the running script gets a proper sys.argv as if it
1617 1617 # were run from a system shell.
1618 1618 save_argv = sys.argv # save it for later restoring
1619 1619
1620 1620 # simulate shell expansion on arguments, at least tilde expansion
1621 1621 args = [ os.path.expanduser(a) for a in arg_lst[1:] ]
1622 1622
1623 1623 sys.argv = [filename] + args # put in the proper filename
1624 1624 # protect sys.argv from potential unicode strings on Python 2:
1625 1625 if not py3compat.PY3:
1626 1626 sys.argv = [ py3compat.cast_bytes(a) for a in sys.argv ]
1627 1627
1628 1628 if 'i' in opts:
1629 1629 # Run in user's interactive namespace
1630 1630 prog_ns = self.shell.user_ns
1631 1631 __name__save = self.shell.user_ns['__name__']
1632 1632 prog_ns['__name__'] = '__main__'
1633 1633 main_mod = self.shell.new_main_mod(prog_ns)
1634 1634 else:
1635 1635 # Run in a fresh, empty namespace
1636 1636 if 'n' in opts:
1637 1637 name = os.path.splitext(os.path.basename(filename))[0]
1638 1638 else:
1639 1639 name = '__main__'
1640 1640
1641 1641 main_mod = self.shell.new_main_mod()
1642 1642 prog_ns = main_mod.__dict__
1643 1643 prog_ns['__name__'] = name
1644 1644
1645 1645 # Since '%run foo' emulates 'python foo.py' at the cmd line, we must
1646 1646 # set the __file__ global in the script's namespace
1647 1647 prog_ns['__file__'] = filename
1648 1648
1649 1649 # pickle fix. See interactiveshell for an explanation. But we need to make sure
1650 1650 # that, if we overwrite __main__, we replace it at the end
1651 1651 main_mod_name = prog_ns['__name__']
1652 1652
1653 1653 if main_mod_name == '__main__':
1654 1654 restore_main = sys.modules['__main__']
1655 1655 else:
1656 1656 restore_main = False
1657 1657
1658 1658 # This needs to be undone at the end to prevent holding references to
1659 1659 # every single object ever created.
1660 1660 sys.modules[main_mod_name] = main_mod
1661 1661
1662 1662 try:
1663 1663 stats = None
1664 1664 with self.readline_no_record:
1665 1665 if 'p' in opts:
1666 1666 stats = self.magic_prun('', 0, opts, arg_lst, prog_ns)
1667 1667 else:
1668 1668 if 'd' in opts:
1669 1669 deb = debugger.Pdb(self.shell.colors)
1670 1670 # reset Breakpoint state, which is moronically kept
1671 1671 # in a class
1672 1672 bdb.Breakpoint.next = 1
1673 1673 bdb.Breakpoint.bplist = {}
1674 1674 bdb.Breakpoint.bpbynumber = [None]
1675 1675 # Set an initial breakpoint to stop execution
1676 1676 maxtries = 10
1677 1677 bp = int(opts.get('b', [1])[0])
1678 1678 checkline = deb.checkline(filename, bp)
1679 1679 if not checkline:
1680 1680 for bp in range(bp + 1, bp + maxtries + 1):
1681 1681 if deb.checkline(filename, bp):
1682 1682 break
1683 1683 else:
1684 1684 msg = ("\nI failed to find a valid line to set "
1685 1685 "a breakpoint\n"
1686 1686 "after trying up to line: %s.\n"
1687 1687 "Please set a valid breakpoint manually "
1688 1688 "with the -b option." % bp)
1689 1689 error(msg)
1690 1690 return
1691 1691 # if we find a good linenumber, set the breakpoint
1692 1692 deb.do_break('%s:%s' % (filename, bp))
1693 1693 # Start file run
1694 1694 print "NOTE: Enter 'c' at the",
1695 1695 print "%s prompt to start your script." % deb.prompt
1696 1696 try:
1697 1697 deb.run('execfile("%s")' % filename, prog_ns)
1698 1698
1699 1699 except:
1700 1700 etype, value, tb = sys.exc_info()
1701 1701 # Skip three frames in the traceback: the %run one,
1702 1702 # one inside bdb.py, and the command-line typed by the
1703 1703 # user (run by exec in pdb itself).
1704 1704 self.shell.InteractiveTB(etype, value, tb, tb_offset=3)
1705 1705 else:
1706 1706 if runner is None:
1707 1707 runner = self.shell.safe_execfile
1708 1708 if 't' in opts:
1709 1709 # timed execution
1710 1710 try:
1711 1711 nruns = int(opts['N'][0])
1712 1712 if nruns < 1:
1713 1713 error('Number of runs must be >=1')
1714 1714 return
1715 1715 except (KeyError):
1716 1716 nruns = 1
1717 1717 twall0 = time.time()
1718 1718 if nruns == 1:
1719 1719 t0 = clock2()
1720 1720 runner(filename, prog_ns, prog_ns,
1721 1721 exit_ignore=exit_ignore)
1722 1722 t1 = clock2()
1723 1723 t_usr = t1[0] - t0[0]
1724 1724 t_sys = t1[1] - t0[1]
1725 1725 print "\nIPython CPU timings (estimated):"
1726 1726 print " User : %10.2f s." % t_usr
1727 1727 print " System : %10.2f s." % t_sys
1728 1728 else:
1729 1729 runs = range(nruns)
1730 1730 t0 = clock2()
1731 1731 for nr in runs:
1732 1732 runner(filename, prog_ns, prog_ns,
1733 1733 exit_ignore=exit_ignore)
1734 1734 t1 = clock2()
1735 1735 t_usr = t1[0] - t0[0]
1736 1736 t_sys = t1[1] - t0[1]
1737 1737 print "\nIPython CPU timings (estimated):"
1738 1738 print "Total runs performed:", nruns
1739 1739 print " Times : %10.2f %10.2f" % ('Total', 'Per run')
1740 1740 print " User : %10.2f s, %10.2f s." % (t_usr, t_usr / nruns)
1741 1741 print " System : %10.2f s, %10.2f s." % (t_sys, t_sys / nruns)
1742 1742 twall1 = time.time()
1743 1743 print "Wall time: %10.2f s." % (twall1 - twall0)
1744 1744
1745 1745 else:
1746 1746 # regular execution
1747 1747 runner(filename, prog_ns, prog_ns, exit_ignore=exit_ignore)
1748 1748
1749 1749 if 'i' in opts:
1750 1750 self.shell.user_ns['__name__'] = __name__save
1751 1751 else:
1752 1752 # The shell MUST hold a reference to prog_ns so after %run
1753 1753 # exits, the python deletion mechanism doesn't zero it out
1754 1754 # (leaving dangling references).
1755 1755 self.shell.cache_main_mod(prog_ns, filename)
1756 1756 # update IPython interactive namespace
1757 1757
1758 1758 # Some forms of read errors on the file may mean the
1759 1759 # __name__ key was never set; using pop we don't have to
1760 1760 # worry about a possible KeyError.
1761 1761 prog_ns.pop('__name__', None)
1762 1762
1763 1763 self.shell.user_ns.update(prog_ns)
1764 1764 finally:
1765 1765 # It's a bit of a mystery why, but __builtins__ can change from
1766 1766 # being a module to becoming a dict missing some key data after
1767 1767 # %run. As best I can see, this is NOT something IPython is doing
1768 1768 # at all, and similar problems have been reported before:
1769 1769 # http://coding.derkeiler.com/Archive/Python/comp.lang.python/2004-10/0188.html
1770 1770 # Since this seems to be done by the interpreter itself, the best
1771 1771 # we can do is to at least restore __builtins__ for the user on
1772 1772 # exit.
1773 1773 self.shell.user_ns['__builtins__'] = builtin_mod
1774 1774
1775 1775 # Ensure key global structures are restored
1776 1776 sys.argv = save_argv
1777 1777 if restore_main:
1778 1778 sys.modules['__main__'] = restore_main
1779 1779 else:
1780 1780 # Remove from sys.modules the reference to main_mod we'd
1781 1781 # added. Otherwise it will trap references to objects
1782 1782 # contained therein.
1783 1783 del sys.modules[main_mod_name]
1784 1784
1785 1785 return stats
1786 1786
1787 1787 @skip_doctest
1788 1788 def magic_timeit(self, parameter_s =''):
1789 1789 """Time execution of a Python statement or expression
1790 1790
1791 1791 Usage:\\
1792 1792 %timeit [-n<N> -r<R> [-t|-c]] statement
1793 1793
1794 1794 Time execution of a Python statement or expression using the timeit
1795 1795 module.
1796 1796
1797 1797 Options:
1798 1798 -n<N>: execute the given statement <N> times in a loop. If this value
1799 1799 is not given, a fitting value is chosen.
1800 1800
1801 1801 -r<R>: repeat the loop iteration <R> times and take the best result.
1802 1802 Default: 3
1803 1803
1804 1804 -t: use time.time to measure the time, which is the default on Unix.
1805 1805 This function measures wall time.
1806 1806
1807 1807 -c: use time.clock to measure the time, which is the default on
1808 1808 Windows and measures wall time. On Unix, resource.getrusage is used
1809 1809 instead and returns the CPU user time.
1810 1810
1811 1811 -p<P>: use a precision of <P> digits to display the timing result.
1812 1812 Default: 3
1813 1813
1814 1814
1815 1815 Examples:
1816 1816
1817 1817 In [1]: %timeit pass
1818 1818 10000000 loops, best of 3: 53.3 ns per loop
1819 1819
1820 1820 In [2]: u = None
1821 1821
1822 1822 In [3]: %timeit u is None
1823 1823 10000000 loops, best of 3: 184 ns per loop
1824 1824
1825 1825 In [4]: %timeit -r 4 u == None
1826 1826 1000000 loops, best of 4: 242 ns per loop
1827 1827
1828 1828 In [5]: import time
1829 1829
1830 1830 In [6]: %timeit -n1 time.sleep(2)
1831 1831 1 loops, best of 3: 2 s per loop
1832 1832
1833 1833
1834 1834 The times reported by %timeit will be slightly higher than those
1835 1835 reported by the timeit.py script when variables are accessed. This is
1836 1836 due to the fact that %timeit executes the statement in the namespace
1837 1837 of the shell, compared with timeit.py, which uses a single setup
1838 1838 statement to import function or create variables. Generally, the bias
1839 1839 does not matter as long as results from timeit.py are not mixed with
1840 1840 those from %timeit."""
1841 1841
1842 1842 import timeit
1843 1843 import math
1844 1844
1845 1845 # XXX: Unfortunately the unicode 'micro' symbol can cause problems in
1846 1846 # certain terminals. Until we figure out a robust way of
1847 1847 # auto-detecting if the terminal can deal with it, use plain 'us' for
1848 1848 # microseconds. I am really NOT happy about disabling the proper
1849 1849 # 'micro' prefix, but crashing is worse... If anyone knows what the
1850 1850 # right solution for this is, I'm all ears...
1851 1851 #
1852 1852 # Note: using
1853 1853 #
1854 1854 # s = u'\xb5'
1855 1855 # s.encode(sys.getdefaultencoding())
1856 1856 #
1857 1857 # is not sufficient, as I've seen terminals where that fails but
1858 1858 # print s
1859 1859 #
1860 1860 # succeeds
1861 1861 #
1862 1862 # See bug: https://bugs.launchpad.net/ipython/+bug/348466
1863 1863
1864 1864 #units = [u"s", u"ms",u'\xb5',"ns"]
1865 1865 units = [u"s", u"ms",u'us',"ns"]
1866 1866
1867 1867 scaling = [1, 1e3, 1e6, 1e9]
1868 1868
1869 1869 opts, stmt = self.parse_options(parameter_s,'n:r:tcp:',
1870 1870 posix=False)
1871 1871 if stmt == "":
1872 1872 return
1873 1873 timefunc = timeit.default_timer
1874 1874 number = int(getattr(opts, "n", 0))
1875 1875 repeat = int(getattr(opts, "r", timeit.default_repeat))
1876 1876 precision = int(getattr(opts, "p", 3))
1877 1877 if hasattr(opts, "t"):
1878 1878 timefunc = time.time
1879 1879 if hasattr(opts, "c"):
1880 1880 timefunc = clock
1881 1881
1882 1882 timer = timeit.Timer(timer=timefunc)
1883 1883 # this code has tight coupling to the inner workings of timeit.Timer,
1884 1884 # but is there a better way to achieve that the code stmt has access
1885 1885 # to the shell namespace?
1886 1886
1887 1887 src = timeit.template % {'stmt': timeit.reindent(stmt, 8),
1888 1888 'setup': "pass"}
1889 1889 # Track compilation time so it can be reported if too long
1890 1890 # Minimum time above which compilation time will be reported
1891 1891 tc_min = 0.1
1892 1892
1893 1893 t0 = clock()
1894 1894 code = compile(src, "<magic-timeit>", "exec")
1895 1895 tc = clock()-t0
1896 1896
1897 1897 ns = {}
1898 1898 exec code in self.shell.user_ns, ns
1899 1899 timer.inner = ns["inner"]
1900 1900
1901 1901 if number == 0:
1902 1902 # determine number so that 0.2 <= total time < 2.0
1903 1903 number = 1
1904 1904 for i in range(1, 10):
1905 1905 if timer.timeit(number) >= 0.2:
1906 1906 break
1907 1907 number *= 10
1908 1908
1909 1909 best = min(timer.repeat(repeat, number)) / number
1910 1910
1911 1911 if best > 0.0 and best < 1000.0:
1912 1912 order = min(-int(math.floor(math.log10(best)) // 3), 3)
1913 1913 elif best >= 1000.0:
1914 1914 order = 0
1915 1915 else:
1916 1916 order = 3
1917 1917 print u"%d loops, best of %d: %.*g %s per loop" % (number, repeat,
1918 1918 precision,
1919 1919 best * scaling[order],
1920 1920 units[order])
1921 1921 if tc > tc_min:
1922 1922 print "Compiler time: %.2f s" % tc
1923 1923
1924 1924 @skip_doctest
1925 1925 @needs_local_scope
1926 1926 def magic_time(self,parameter_s = ''):
1927 1927 """Time execution of a Python statement or expression.
1928 1928
1929 1929 The CPU and wall clock times are printed, and the value of the
1930 1930 expression (if any) is returned. Note that under Win32, system time
1931 1931 is always reported as 0, since it can not be measured.
1932 1932
1933 1933 This function provides very basic timing functionality. In Python
1934 1934 2.3, the timeit module offers more control and sophistication, so this
1935 1935 could be rewritten to use it (patches welcome).
1936 1936
1937 1937 Some examples:
1938 1938
1939 1939 In [1]: time 2**128
1940 1940 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1941 1941 Wall time: 0.00
1942 1942 Out[1]: 340282366920938463463374607431768211456L
1943 1943
1944 1944 In [2]: n = 1000000
1945 1945
1946 1946 In [3]: time sum(range(n))
1947 1947 CPU times: user 1.20 s, sys: 0.05 s, total: 1.25 s
1948 1948 Wall time: 1.37
1949 1949 Out[3]: 499999500000L
1950 1950
1951 1951 In [4]: time print 'hello world'
1952 1952 hello world
1953 1953 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1954 1954 Wall time: 0.00
1955 1955
1956 1956 Note that the time needed by Python to compile the given expression
1957 1957 will be reported if it is more than 0.1s. In this example, the
1958 1958 actual exponentiation is done by Python at compilation time, so while
1959 1959 the expression can take a noticeable amount of time to compute, that
1960 1960 time is purely due to the compilation:
1961 1961
1962 1962 In [5]: time 3**9999;
1963 1963 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1964 1964 Wall time: 0.00 s
1965 1965
1966 1966 In [6]: time 3**999999;
1967 1967 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
1968 1968 Wall time: 0.00 s
1969 1969 Compiler : 0.78 s
1970 1970 """
1971 1971
1972 1972 # fail immediately if the given expression can't be compiled
1973 1973
1974 1974 expr = self.shell.prefilter(parameter_s,False)
1975 1975
1976 1976 # Minimum time above which compilation time will be reported
1977 1977 tc_min = 0.1
1978 1978
1979 1979 try:
1980 1980 mode = 'eval'
1981 1981 t0 = clock()
1982 1982 code = compile(expr,'<timed eval>',mode)
1983 1983 tc = clock()-t0
1984 1984 except SyntaxError:
1985 1985 mode = 'exec'
1986 1986 t0 = clock()
1987 1987 code = compile(expr,'<timed exec>',mode)
1988 1988 tc = clock()-t0
1989 1989 # skew measurement as little as possible
1990 1990 glob = self.shell.user_ns
1991 1991 locs = self._magic_locals
1992 1992 clk = clock2
1993 1993 wtime = time.time
1994 1994 # time execution
1995 1995 wall_st = wtime()
1996 1996 if mode=='eval':
1997 1997 st = clk()
1998 1998 out = eval(code, glob, locs)
1999 1999 end = clk()
2000 2000 else:
2001 2001 st = clk()
2002 2002 exec code in glob, locs
2003 2003 end = clk()
2004 2004 out = None
2005 2005 wall_end = wtime()
2006 2006 # Compute actual times and report
2007 2007 wall_time = wall_end-wall_st
2008 2008 cpu_user = end[0]-st[0]
2009 2009 cpu_sys = end[1]-st[1]
2010 2010 cpu_tot = cpu_user+cpu_sys
2011 2011 print "CPU times: user %.2f s, sys: %.2f s, total: %.2f s" % \
2012 2012 (cpu_user,cpu_sys,cpu_tot)
2013 2013 print "Wall time: %.2f s" % wall_time
2014 2014 if tc > tc_min:
2015 2015 print "Compiler : %.2f s" % tc
2016 2016 return out
2017 2017
2018 2018 @skip_doctest
2019 2019 def magic_macro(self,parameter_s = ''):
2020 2020 """Define a macro for future re-execution. It accepts ranges of history,
2021 2021 filenames or string objects.
2022 2022
2023 2023 Usage:\\
2024 2024 %macro [options] name n1-n2 n3-n4 ... n5 .. n6 ...
2025 2025
2026 2026 Options:
2027 2027
2028 2028 -r: use 'raw' input. By default, the 'processed' history is used,
2029 2029 so that magics are loaded in their transformed version to valid
2030 2030 Python. If this option is given, the raw input as typed as the
2031 2031 command line is used instead.
2032 2032
2033 2033 This will define a global variable called `name` which is a string
2034 2034 made of joining the slices and lines you specify (n1,n2,... numbers
2035 2035 above) from your input history into a single string. This variable
2036 2036 acts like an automatic function which re-executes those lines as if
2037 2037 you had typed them. You just type 'name' at the prompt and the code
2038 2038 executes.
2039 2039
2040 2040 The syntax for indicating input ranges is described in %history.
2041 2041
2042 2042 Note: as a 'hidden' feature, you can also use traditional python slice
2043 2043 notation, where N:M means numbers N through M-1.
2044 2044
2045 2045 For example, if your history contains (%hist prints it):
2046 2046
2047 2047 44: x=1
2048 2048 45: y=3
2049 2049 46: z=x+y
2050 2050 47: print x
2051 2051 48: a=5
2052 2052 49: print 'x',x,'y',y
2053 2053
2054 2054 you can create a macro with lines 44 through 47 (included) and line 49
2055 2055 called my_macro with:
2056 2056
2057 2057 In [55]: %macro my_macro 44-47 49
2058 2058
2059 2059 Now, typing `my_macro` (without quotes) will re-execute all this code
2060 2060 in one pass.
2061 2061
2062 2062 You don't need to give the line-numbers in order, and any given line
2063 2063 number can appear multiple times. You can assemble macros with any
2064 2064 lines from your input history in any order.
2065 2065
2066 2066 The macro is a simple object which holds its value in an attribute,
2067 2067 but IPython's display system checks for macros and executes them as
2068 2068 code instead of printing them when you type their name.
2069 2069
2070 2070 You can view a macro's contents by explicitly printing it with:
2071 2071
2072 2072 'print macro_name'.
2073 2073
2074 2074 """
2075 2075 opts,args = self.parse_options(parameter_s,'r',mode='list')
2076 2076 if not args: # List existing macros
2077 2077 return sorted(k for k,v in self.shell.user_ns.iteritems() if\
2078 2078 isinstance(v, Macro))
2079 2079 if len(args) == 1:
2080 2080 raise UsageError(
2081 2081 "%macro insufficient args; usage '%macro name n1-n2 n3-4...")
2082 2082 name, codefrom = args[0], " ".join(args[1:])
2083 2083
2084 2084 #print 'rng',ranges # dbg
2085 2085 try:
2086 2086 lines = self.shell.find_user_code(codefrom, 'r' in opts)
2087 2087 except (ValueError, TypeError) as e:
2088 2088 print e.args[0]
2089 2089 return
2090 2090 macro = Macro(lines)
2091 2091 self.shell.define_macro(name, macro)
2092 2092 print 'Macro `%s` created. To execute, type its name (without quotes).' % name
2093 2093 print '=== Macro contents: ==='
2094 2094 print macro,
2095 2095
2096 2096 def magic_save(self,parameter_s = ''):
2097 2097 """Save a set of lines or a macro to a given filename.
2098 2098
2099 2099 Usage:\\
2100 2100 %save [options] filename n1-n2 n3-n4 ... n5 .. n6 ...
2101 2101
2102 2102 Options:
2103 2103
2104 2104 -r: use 'raw' input. By default, the 'processed' history is used,
2105 2105 so that magics are loaded in their transformed version to valid
2106 2106 Python. If this option is given, the raw input as typed as the
2107 2107 command line is used instead.
2108 2108
2109 2109 This function uses the same syntax as %history for input ranges,
2110 2110 then saves the lines to the filename you specify.
2111 2111
2112 2112 It adds a '.py' extension to the file if you don't do so yourself, and
2113 2113 it asks for confirmation before overwriting existing files."""
2114 2114
2115 2115 opts,args = self.parse_options(parameter_s,'r',mode='list')
2116 2116 fname, codefrom = unquote_filename(args[0]), " ".join(args[1:])
2117 2117 if not fname.endswith('.py'):
2118 2118 fname += '.py'
2119 2119 if os.path.isfile(fname):
2120 2120 ans = raw_input('File `%s` exists. Overwrite (y/[N])? ' % fname)
2121 2121 if ans.lower() not in ['y','yes']:
2122 2122 print 'Operation cancelled.'
2123 2123 return
2124 2124 try:
2125 2125 cmds = self.shell.find_user_code(codefrom, 'r' in opts)
2126 2126 except (TypeError, ValueError) as e:
2127 2127 print e.args[0]
2128 2128 return
2129 2129 with py3compat.open(fname,'w', encoding="utf-8") as f:
2130 2130 f.write(u"# coding: utf-8\n")
2131 2131 f.write(py3compat.cast_unicode(cmds))
2132 2132 print 'The following commands were written to file `%s`:' % fname
2133 2133 print cmds
2134 2134
2135 2135 def magic_pastebin(self, parameter_s = ''):
2136 2136 """Upload code to the 'Lodge it' paste bin, returning the URL."""
2137 2137 try:
2138 2138 code = self.shell.find_user_code(parameter_s)
2139 2139 except (ValueError, TypeError) as e:
2140 2140 print e.args[0]
2141 2141 return
2142 2142 pbserver = ServerProxy('http://paste.pocoo.org/xmlrpc/')
2143 2143 id = pbserver.pastes.newPaste("python", code)
2144 2144 return "http://paste.pocoo.org/show/" + id
2145 2145
2146 2146 def magic_loadpy(self, arg_s):
2147 2147 """Load a .py python script into the GUI console.
2148 2148
2149 2149 This magic command can either take a local filename or a url::
2150 2150
2151 2151 %loadpy myscript.py
2152 2152 %loadpy http://www.example.com/myscript.py
2153 2153 """
2154 2154 arg_s = unquote_filename(arg_s)
2155 2155 if not arg_s.endswith('.py'):
2156 2156 raise ValueError('%%load only works with .py files: %s' % arg_s)
2157 2157 if arg_s.startswith('http'):
2158 2158 import urllib2
2159 2159 response = urllib2.urlopen(arg_s)
2160 2160 content = response.read()
2161 2161 else:
2162 2162 with open(arg_s) as f:
2163 2163 content = f.read()
2164 2164 self.set_next_input(content)
2165 2165
2166 2166 def _find_edit_target(self, args, opts, last_call):
2167 2167 """Utility method used by magic_edit to find what to edit."""
2168 2168
2169 2169 def make_filename(arg):
2170 2170 "Make a filename from the given args"
2171 2171 arg = unquote_filename(arg)
2172 2172 try:
2173 2173 filename = get_py_filename(arg)
2174 2174 except IOError:
2175 2175 # If it ends with .py but doesn't already exist, assume we want
2176 2176 # a new file.
2177 2177 if arg.endswith('.py'):
2178 2178 filename = arg
2179 2179 else:
2180 2180 filename = None
2181 2181 return filename
2182 2182
2183 2183 # Set a few locals from the options for convenience:
2184 2184 opts_prev = 'p' in opts
2185 2185 opts_raw = 'r' in opts
2186 2186
2187 2187 # custom exceptions
2188 2188 class DataIsObject(Exception): pass
2189 2189
2190 2190 # Default line number value
2191 2191 lineno = opts.get('n',None)
2192 2192
2193 2193 if opts_prev:
2194 2194 args = '_%s' % last_call[0]
2195 2195 if not self.shell.user_ns.has_key(args):
2196 2196 args = last_call[1]
2197 2197
2198 2198 # use last_call to remember the state of the previous call, but don't
2199 2199 # let it be clobbered by successive '-p' calls.
2200 2200 try:
2201 2201 last_call[0] = self.shell.displayhook.prompt_count
2202 2202 if not opts_prev:
2203 2203 last_call[1] = parameter_s
2204 2204 except:
2205 2205 pass
2206 2206
2207 2207 # by default this is done with temp files, except when the given
2208 2208 # arg is a filename
2209 2209 use_temp = True
2210 2210
2211 2211 data = ''
2212 2212
2213 2213 # First, see if the arguments should be a filename.
2214 2214 filename = make_filename(args)
2215 2215 if filename:
2216 2216 use_temp = False
2217 2217 elif args:
2218 2218 # Mode where user specifies ranges of lines, like in %macro.
2219 2219 data = self.extract_input_lines(args, opts_raw)
2220 2220 if not data:
2221 2221 try:
2222 2222 # Load the parameter given as a variable. If not a string,
2223 2223 # process it as an object instead (below)
2224 2224
2225 2225 #print '*** args',args,'type',type(args) # dbg
2226 2226 data = eval(args, self.shell.user_ns)
2227 2227 if not isinstance(data, basestring):
2228 2228 raise DataIsObject
2229 2229
2230 2230 except (NameError,SyntaxError):
2231 2231 # given argument is not a variable, try as a filename
2232 2232 filename = make_filename(args)
2233 2233 if filename is None:
2234 2234 warn("Argument given (%s) can't be found as a variable "
2235 2235 "or as a filename." % args)
2236 2236 return
2237 2237 use_temp = False
2238 2238
2239 2239 except DataIsObject:
2240 2240 # macros have a special edit function
2241 2241 if isinstance(data, Macro):
2242 2242 raise MacroToEdit(data)
2243 2243
2244 2244 # For objects, try to edit the file where they are defined
2245 2245 try:
2246 2246 filename = inspect.getabsfile(data)
2247 2247 if 'fakemodule' in filename.lower() and inspect.isclass(data):
2248 2248 # class created by %edit? Try to find source
2249 2249 # by looking for method definitions instead, the
2250 2250 # __module__ in those classes is FakeModule.
2251 2251 attrs = [getattr(data, aname) for aname in dir(data)]
2252 2252 for attr in attrs:
2253 2253 if not inspect.ismethod(attr):
2254 2254 continue
2255 2255 filename = inspect.getabsfile(attr)
2256 2256 if filename and 'fakemodule' not in filename.lower():
2257 2257 # change the attribute to be the edit target instead
2258 2258 data = attr
2259 2259 break
2260 2260
2261 2261 datafile = 1
2262 2262 except TypeError:
2263 2263 filename = make_filename(args)
2264 2264 datafile = 1
2265 2265 warn('Could not find file where `%s` is defined.\n'
2266 2266 'Opening a file named `%s`' % (args,filename))
2267 2267 # Now, make sure we can actually read the source (if it was in
2268 2268 # a temp file it's gone by now).
2269 2269 if datafile:
2270 2270 try:
2271 2271 if lineno is None:
2272 2272 lineno = inspect.getsourcelines(data)[1]
2273 2273 except IOError:
2274 2274 filename = make_filename(args)
2275 2275 if filename is None:
2276 2276 warn('The file `%s` where `%s` was defined cannot '
2277 2277 'be read.' % (filename,data))
2278 2278 return
2279 2279 use_temp = False
2280 2280
2281 2281 if use_temp:
2282 2282 filename = self.shell.mktempfile(data)
2283 2283 print 'IPython will make a temporary file named:',filename
2284 2284
2285 2285 return filename, lineno, use_temp
2286 2286
2287 2287 def _edit_macro(self,mname,macro):
2288 2288 """open an editor with the macro data in a file"""
2289 2289 filename = self.shell.mktempfile(macro.value)
2290 2290 self.shell.hooks.editor(filename)
2291 2291
2292 2292 # and make a new macro object, to replace the old one
2293 2293 mfile = open(filename)
2294 2294 mvalue = mfile.read()
2295 2295 mfile.close()
2296 2296 self.shell.user_ns[mname] = Macro(mvalue)
2297 2297
2298 2298 def magic_ed(self,parameter_s=''):
2299 2299 """Alias to %edit."""
2300 2300 return self.magic_edit(parameter_s)
2301 2301
2302 2302 @skip_doctest
2303 2303 def magic_edit(self,parameter_s='',last_call=['','']):
2304 2304 """Bring up an editor and execute the resulting code.
2305 2305
2306 2306 Usage:
2307 2307 %edit [options] [args]
2308 2308
2309 2309 %edit runs IPython's editor hook. The default version of this hook is
2310 2310 set to call the editor specified by your $EDITOR environment variable.
2311 2311 If this isn't found, it will default to vi under Linux/Unix and to
2312 2312 notepad under Windows. See the end of this docstring for how to change
2313 2313 the editor hook.
2314 2314
2315 2315 You can also set the value of this editor via the
2316 2316 ``TerminalInteractiveShell.editor`` option in your configuration file.
2317 2317 This is useful if you wish to use a different editor from your typical
2318 2318 default with IPython (and for Windows users who typically don't set
2319 2319 environment variables).
2320 2320
2321 2321 This command allows you to conveniently edit multi-line code right in
2322 2322 your IPython session.
2323 2323
2324 2324 If called without arguments, %edit opens up an empty editor with a
2325 2325 temporary file and will execute the contents of this file when you
2326 2326 close it (don't forget to save it!).
2327 2327
2328 2328
2329 2329 Options:
2330 2330
2331 2331 -n <number>: open the editor at a specified line number. By default,
2332 2332 the IPython editor hook uses the unix syntax 'editor +N filename', but
2333 2333 you can configure this by providing your own modified hook if your
2334 2334 favorite editor supports line-number specifications with a different
2335 2335 syntax.
2336 2336
2337 2337 -p: this will call the editor with the same data as the previous time
2338 2338 it was used, regardless of how long ago (in your current session) it
2339 2339 was.
2340 2340
2341 2341 -r: use 'raw' input. This option only applies to input taken from the
2342 2342 user's history. By default, the 'processed' history is used, so that
2343 2343 magics are loaded in their transformed version to valid Python. If
2344 2344 this option is given, the raw input as typed as the command line is
2345 2345 used instead. When you exit the editor, it will be executed by
2346 2346 IPython's own processor.
2347 2347
2348 2348 -x: do not execute the edited code immediately upon exit. This is
2349 2349 mainly useful if you are editing programs which need to be called with
2350 2350 command line arguments, which you can then do using %run.
2351 2351
2352 2352
2353 2353 Arguments:
2354 2354
2355 2355 If arguments are given, the following possibilites exist:
2356 2356
2357 2357 - If the argument is a filename, IPython will load that into the
2358 2358 editor. It will execute its contents with execfile() when you exit,
2359 2359 loading any code in the file into your interactive namespace.
2360 2360
2361 2361 - The arguments are ranges of input history, e.g. "7 ~1/4-6".
2362 2362 The syntax is the same as in the %history magic.
2363 2363
2364 2364 - If the argument is a string variable, its contents are loaded
2365 2365 into the editor. You can thus edit any string which contains
2366 2366 python code (including the result of previous edits).
2367 2367
2368 2368 - If the argument is the name of an object (other than a string),
2369 2369 IPython will try to locate the file where it was defined and open the
2370 2370 editor at the point where it is defined. You can use `%edit function`
2371 2371 to load an editor exactly at the point where 'function' is defined,
2372 2372 edit it and have the file be executed automatically.
2373 2373
2374 2374 - If the object is a macro (see %macro for details), this opens up your
2375 2375 specified editor with a temporary file containing the macro's data.
2376 2376 Upon exit, the macro is reloaded with the contents of the file.
2377 2377
2378 2378 Note: opening at an exact line is only supported under Unix, and some
2379 2379 editors (like kedit and gedit up to Gnome 2.8) do not understand the
2380 2380 '+NUMBER' parameter necessary for this feature. Good editors like
2381 2381 (X)Emacs, vi, jed, pico and joe all do.
2382 2382
2383 2383 After executing your code, %edit will return as output the code you
2384 2384 typed in the editor (except when it was an existing file). This way
2385 2385 you can reload the code in further invocations of %edit as a variable,
2386 2386 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
2387 2387 the output.
2388 2388
2389 2389 Note that %edit is also available through the alias %ed.
2390 2390
2391 2391 This is an example of creating a simple function inside the editor and
2392 2392 then modifying it. First, start up the editor:
2393 2393
2394 2394 In [1]: ed
2395 2395 Editing... done. Executing edited code...
2396 2396 Out[1]: 'def foo():n print "foo() was defined in an editing session"n'
2397 2397
2398 2398 We can then call the function foo():
2399 2399
2400 2400 In [2]: foo()
2401 2401 foo() was defined in an editing session
2402 2402
2403 2403 Now we edit foo. IPython automatically loads the editor with the
2404 2404 (temporary) file where foo() was previously defined:
2405 2405
2406 2406 In [3]: ed foo
2407 2407 Editing... done. Executing edited code...
2408 2408
2409 2409 And if we call foo() again we get the modified version:
2410 2410
2411 2411 In [4]: foo()
2412 2412 foo() has now been changed!
2413 2413
2414 2414 Here is an example of how to edit a code snippet successive
2415 2415 times. First we call the editor:
2416 2416
2417 2417 In [5]: ed
2418 2418 Editing... done. Executing edited code...
2419 2419 hello
2420 2420 Out[5]: "print 'hello'n"
2421 2421
2422 2422 Now we call it again with the previous output (stored in _):
2423 2423
2424 2424 In [6]: ed _
2425 2425 Editing... done. Executing edited code...
2426 2426 hello world
2427 2427 Out[6]: "print 'hello world'n"
2428 2428
2429 2429 Now we call it with the output #8 (stored in _8, also as Out[8]):
2430 2430
2431 2431 In [7]: ed _8
2432 2432 Editing... done. Executing edited code...
2433 2433 hello again
2434 2434 Out[7]: "print 'hello again'n"
2435 2435
2436 2436
2437 2437 Changing the default editor hook:
2438 2438
2439 2439 If you wish to write your own editor hook, you can put it in a
2440 2440 configuration file which you load at startup time. The default hook
2441 2441 is defined in the IPython.core.hooks module, and you can use that as a
2442 2442 starting example for further modifications. That file also has
2443 2443 general instructions on how to set a new hook for use once you've
2444 2444 defined it."""
2445 2445 opts,args = self.parse_options(parameter_s,'prxn:')
2446 2446
2447 2447 try:
2448 2448 filename, lineno, is_temp = self._find_edit_target(args, opts, last_call)
2449 2449 except MacroToEdit as e:
2450 2450 self._edit_macro(args, e.args[0])
2451 2451 return
2452 2452
2453 2453 # do actual editing here
2454 2454 print 'Editing...',
2455 2455 sys.stdout.flush()
2456 2456 try:
2457 2457 # Quote filenames that may have spaces in them
2458 2458 if ' ' in filename:
2459 2459 filename = "'%s'" % filename
2460 2460 self.shell.hooks.editor(filename,lineno)
2461 2461 except TryNext:
2462 2462 warn('Could not open editor')
2463 2463 return
2464 2464
2465 2465 # XXX TODO: should this be generalized for all string vars?
2466 2466 # For now, this is special-cased to blocks created by cpaste
2467 2467 if args.strip() == 'pasted_block':
2468 2468 self.shell.user_ns['pasted_block'] = file_read(filename)
2469 2469
2470 2470 if 'x' in opts: # -x prevents actual execution
2471 2471 print
2472 2472 else:
2473 2473 print 'done. Executing edited code...'
2474 2474 if 'r' in opts: # Untranslated IPython code
2475 2475 self.shell.run_cell(file_read(filename),
2476 2476 store_history=False)
2477 2477 else:
2478 2478 self.shell.safe_execfile(filename,self.shell.user_ns,
2479 2479 self.shell.user_ns)
2480 2480
2481 2481 if is_temp:
2482 2482 try:
2483 2483 return open(filename).read()
2484 2484 except IOError,msg:
2485 2485 if msg.filename == filename:
2486 2486 warn('File not found. Did you forget to save?')
2487 2487 return
2488 2488 else:
2489 2489 self.shell.showtraceback()
2490 2490
2491 2491 def magic_xmode(self,parameter_s = ''):
2492 2492 """Switch modes for the exception handlers.
2493 2493
2494 2494 Valid modes: Plain, Context and Verbose.
2495 2495
2496 2496 If called without arguments, acts as a toggle."""
2497 2497
2498 2498 def xmode_switch_err(name):
2499 2499 warn('Error changing %s exception modes.\n%s' %
2500 2500 (name,sys.exc_info()[1]))
2501 2501
2502 2502 shell = self.shell
2503 2503 new_mode = parameter_s.strip().capitalize()
2504 2504 try:
2505 2505 shell.InteractiveTB.set_mode(mode=new_mode)
2506 2506 print 'Exception reporting mode:',shell.InteractiveTB.mode
2507 2507 except:
2508 2508 xmode_switch_err('user')
2509 2509
2510 2510 def magic_colors(self,parameter_s = ''):
2511 2511 """Switch color scheme for prompts, info system and exception handlers.
2512 2512
2513 2513 Currently implemented schemes: NoColor, Linux, LightBG.
2514 2514
2515 2515 Color scheme names are not case-sensitive.
2516 2516
2517 2517 Examples
2518 2518 --------
2519 2519 To get a plain black and white terminal::
2520 2520
2521 2521 %colors nocolor
2522 2522 """
2523 2523
2524 2524 def color_switch_err(name):
2525 2525 warn('Error changing %s color schemes.\n%s' %
2526 2526 (name,sys.exc_info()[1]))
2527 2527
2528 2528
2529 2529 new_scheme = parameter_s.strip()
2530 2530 if not new_scheme:
2531 2531 raise UsageError(
2532 2532 "%colors: you must specify a color scheme. See '%colors?'")
2533 2533 return
2534 2534 # local shortcut
2535 2535 shell = self.shell
2536 2536
2537 2537 import IPython.utils.rlineimpl as readline
2538 2538
2539 2539 if not shell.colors_force and \
2540 2540 not readline.have_readline and sys.platform == "win32":
2541 2541 msg = """\
2542 2542 Proper color support under MS Windows requires the pyreadline library.
2543 2543 You can find it at:
2544 2544 http://ipython.org/pyreadline.html
2545 2545 Gary's readline needs the ctypes module, from:
2546 2546 http://starship.python.net/crew/theller/ctypes
2547 2547 (Note that ctypes is already part of Python versions 2.5 and newer).
2548 2548
2549 2549 Defaulting color scheme to 'NoColor'"""
2550 2550 new_scheme = 'NoColor'
2551 2551 warn(msg)
2552 2552
2553 2553 # readline option is 0
2554 2554 if not shell.colors_force and not shell.has_readline:
2555 2555 new_scheme = 'NoColor'
2556 2556
2557 2557 # Set prompt colors
2558 2558 try:
2559 2559 shell.displayhook.set_colors(new_scheme)
2560 2560 except:
2561 2561 color_switch_err('prompt')
2562 2562 else:
2563 2563 shell.colors = \
2564 2564 shell.displayhook.color_table.active_scheme_name
2565 2565 # Set exception colors
2566 2566 try:
2567 2567 shell.InteractiveTB.set_colors(scheme = new_scheme)
2568 2568 shell.SyntaxTB.set_colors(scheme = new_scheme)
2569 2569 except:
2570 2570 color_switch_err('exception')
2571 2571
2572 2572 # Set info (for 'object?') colors
2573 2573 if shell.color_info:
2574 2574 try:
2575 2575 shell.inspector.set_active_scheme(new_scheme)
2576 2576 except:
2577 2577 color_switch_err('object inspector')
2578 2578 else:
2579 2579 shell.inspector.set_active_scheme('NoColor')
2580 2580
2581 2581 def magic_pprint(self, parameter_s=''):
2582 2582 """Toggle pretty printing on/off."""
2583 2583 ptformatter = self.shell.display_formatter.formatters['text/plain']
2584 2584 ptformatter.pprint = bool(1 - ptformatter.pprint)
2585 2585 print 'Pretty printing has been turned', \
2586 2586 ['OFF','ON'][ptformatter.pprint]
2587 2587
2588 2588 #......................................................................
2589 2589 # Functions to implement unix shell-type things
2590 2590
2591 2591 @skip_doctest
2592 2592 def magic_alias(self, parameter_s = ''):
2593 2593 """Define an alias for a system command.
2594 2594
2595 2595 '%alias alias_name cmd' defines 'alias_name' as an alias for 'cmd'
2596 2596
2597 2597 Then, typing 'alias_name params' will execute the system command 'cmd
2598 2598 params' (from your underlying operating system).
2599 2599
2600 2600 Aliases have lower precedence than magic functions and Python normal
2601 2601 variables, so if 'foo' is both a Python variable and an alias, the
2602 2602 alias can not be executed until 'del foo' removes the Python variable.
2603 2603
2604 2604 You can use the %l specifier in an alias definition to represent the
2605 2605 whole line when the alias is called. For example:
2606 2606
2607 2607 In [2]: alias bracket echo "Input in brackets: <%l>"
2608 2608 In [3]: bracket hello world
2609 2609 Input in brackets: <hello world>
2610 2610
2611 2611 You can also define aliases with parameters using %s specifiers (one
2612 2612 per parameter):
2613 2613
2614 2614 In [1]: alias parts echo first %s second %s
2615 2615 In [2]: %parts A B
2616 2616 first A second B
2617 2617 In [3]: %parts A
2618 2618 Incorrect number of arguments: 2 expected.
2619 2619 parts is an alias to: 'echo first %s second %s'
2620 2620
2621 2621 Note that %l and %s are mutually exclusive. You can only use one or
2622 2622 the other in your aliases.
2623 2623
2624 2624 Aliases expand Python variables just like system calls using ! or !!
2625 2625 do: all expressions prefixed with '$' get expanded. For details of
2626 2626 the semantic rules, see PEP-215:
2627 2627 http://www.python.org/peps/pep-0215.html. This is the library used by
2628 2628 IPython for variable expansion. If you want to access a true shell
2629 2629 variable, an extra $ is necessary to prevent its expansion by IPython:
2630 2630
2631 2631 In [6]: alias show echo
2632 2632 In [7]: PATH='A Python string'
2633 2633 In [8]: show $PATH
2634 2634 A Python string
2635 2635 In [9]: show $$PATH
2636 2636 /usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:...
2637 2637
2638 2638 You can use the alias facility to acess all of $PATH. See the %rehash
2639 2639 and %rehashx functions, which automatically create aliases for the
2640 2640 contents of your $PATH.
2641 2641
2642 2642 If called with no parameters, %alias prints the current alias table."""
2643 2643
2644 2644 par = parameter_s.strip()
2645 2645 if not par:
2646 2646 stored = self.db.get('stored_aliases', {} )
2647 2647 aliases = sorted(self.shell.alias_manager.aliases)
2648 2648 # for k, v in stored:
2649 2649 # atab.append(k, v[0])
2650 2650
2651 2651 print "Total number of aliases:", len(aliases)
2652 2652 sys.stdout.flush()
2653 2653 return aliases
2654 2654
2655 2655 # Now try to define a new one
2656 2656 try:
2657 2657 alias,cmd = par.split(None, 1)
2658 2658 except:
2659 2659 print oinspect.getdoc(self.magic_alias)
2660 2660 else:
2661 2661 self.shell.alias_manager.soft_define_alias(alias, cmd)
2662 2662 # end magic_alias
2663 2663
2664 2664 def magic_unalias(self, parameter_s = ''):
2665 2665 """Remove an alias"""
2666 2666
2667 2667 aname = parameter_s.strip()
2668 2668 self.shell.alias_manager.undefine_alias(aname)
2669 2669 stored = self.db.get('stored_aliases', {} )
2670 2670 if aname in stored:
2671 2671 print "Removing %stored alias",aname
2672 2672 del stored[aname]
2673 2673 self.db['stored_aliases'] = stored
2674 2674
2675 2675 def magic_rehashx(self, parameter_s = ''):
2676 2676 """Update the alias table with all executable files in $PATH.
2677 2677
2678 2678 This version explicitly checks that every entry in $PATH is a file
2679 2679 with execute access (os.X_OK), so it is much slower than %rehash.
2680 2680
2681 2681 Under Windows, it checks executability as a match agains a
2682 2682 '|'-separated string of extensions, stored in the IPython config
2683 2683 variable win_exec_ext. This defaults to 'exe|com|bat'.
2684 2684
2685 2685 This function also resets the root module cache of module completer,
2686 2686 used on slow filesystems.
2687 2687 """
2688 2688 from IPython.core.alias import InvalidAliasError
2689 2689
2690 2690 # for the benefit of module completer in ipy_completers.py
2691 2691 del self.db['rootmodules']
2692 2692
2693 2693 path = [os.path.abspath(os.path.expanduser(p)) for p in
2694 2694 os.environ.get('PATH','').split(os.pathsep)]
2695 2695 path = filter(os.path.isdir,path)
2696 2696
2697 2697 syscmdlist = []
2698 2698 # Now define isexec in a cross platform manner.
2699 2699 if os.name == 'posix':
2700 2700 isexec = lambda fname:os.path.isfile(fname) and \
2701 2701 os.access(fname,os.X_OK)
2702 2702 else:
2703 2703 try:
2704 2704 winext = os.environ['pathext'].replace(';','|').replace('.','')
2705 2705 except KeyError:
2706 2706 winext = 'exe|com|bat|py'
2707 2707 if 'py' not in winext:
2708 2708 winext += '|py'
2709 2709 execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE)
2710 2710 isexec = lambda fname:os.path.isfile(fname) and execre.match(fname)
2711 2711 savedir = os.getcwdu()
2712 2712
2713 2713 # Now walk the paths looking for executables to alias.
2714 2714 try:
2715 2715 # write the whole loop for posix/Windows so we don't have an if in
2716 2716 # the innermost part
2717 2717 if os.name == 'posix':
2718 2718 for pdir in path:
2719 2719 os.chdir(pdir)
2720 2720 for ff in os.listdir(pdir):
2721 2721 if isexec(ff):
2722 2722 try:
2723 2723 # Removes dots from the name since ipython
2724 2724 # will assume names with dots to be python.
2725 2725 self.shell.alias_manager.define_alias(
2726 2726 ff.replace('.',''), ff)
2727 2727 except InvalidAliasError:
2728 2728 pass
2729 2729 else:
2730 2730 syscmdlist.append(ff)
2731 2731 else:
2732 2732 no_alias = self.shell.alias_manager.no_alias
2733 2733 for pdir in path:
2734 2734 os.chdir(pdir)
2735 2735 for ff in os.listdir(pdir):
2736 2736 base, ext = os.path.splitext(ff)
2737 2737 if isexec(ff) and base.lower() not in no_alias:
2738 2738 if ext.lower() == '.exe':
2739 2739 ff = base
2740 2740 try:
2741 2741 # Removes dots from the name since ipython
2742 2742 # will assume names with dots to be python.
2743 2743 self.shell.alias_manager.define_alias(
2744 2744 base.lower().replace('.',''), ff)
2745 2745 except InvalidAliasError:
2746 2746 pass
2747 2747 syscmdlist.append(ff)
2748 2748 db = self.db
2749 2749 db['syscmdlist'] = syscmdlist
2750 2750 finally:
2751 2751 os.chdir(savedir)
2752 2752
2753 2753 @skip_doctest
2754 2754 def magic_pwd(self, parameter_s = ''):
2755 2755 """Return the current working directory path.
2756 2756
2757 2757 Examples
2758 2758 --------
2759 2759 ::
2760 2760
2761 2761 In [9]: pwd
2762 2762 Out[9]: '/home/tsuser/sprint/ipython'
2763 2763 """
2764 2764 return os.getcwdu()
2765 2765
2766 2766 @skip_doctest
2767 2767 def magic_cd(self, parameter_s=''):
2768 2768 """Change the current working directory.
2769 2769
2770 2770 This command automatically maintains an internal list of directories
2771 2771 you visit during your IPython session, in the variable _dh. The
2772 2772 command %dhist shows this history nicely formatted. You can also
2773 2773 do 'cd -<tab>' to see directory history conveniently.
2774 2774
2775 2775 Usage:
2776 2776
2777 2777 cd 'dir': changes to directory 'dir'.
2778 2778
2779 2779 cd -: changes to the last visited directory.
2780 2780
2781 2781 cd -<n>: changes to the n-th directory in the directory history.
2782 2782
2783 2783 cd --foo: change to directory that matches 'foo' in history
2784 2784
2785 2785 cd -b <bookmark_name>: jump to a bookmark set by %bookmark
2786 2786 (note: cd <bookmark_name> is enough if there is no
2787 2787 directory <bookmark_name>, but a bookmark with the name exists.)
2788 2788 'cd -b <tab>' allows you to tab-complete bookmark names.
2789 2789
2790 2790 Options:
2791 2791
2792 2792 -q: quiet. Do not print the working directory after the cd command is
2793 2793 executed. By default IPython's cd command does print this directory,
2794 2794 since the default prompts do not display path information.
2795 2795
2796 2796 Note that !cd doesn't work for this purpose because the shell where
2797 2797 !command runs is immediately discarded after executing 'command'.
2798 2798
2799 2799 Examples
2800 2800 --------
2801 2801 ::
2802 2802
2803 2803 In [10]: cd parent/child
2804 2804 /home/tsuser/parent/child
2805 2805 """
2806 2806
2807 2807 parameter_s = parameter_s.strip()
2808 2808 #bkms = self.shell.persist.get("bookmarks",{})
2809 2809
2810 2810 oldcwd = os.getcwdu()
2811 2811 numcd = re.match(r'(-)(\d+)$',parameter_s)
2812 2812 # jump in directory history by number
2813 2813 if numcd:
2814 2814 nn = int(numcd.group(2))
2815 2815 try:
2816 2816 ps = self.shell.user_ns['_dh'][nn]
2817 2817 except IndexError:
2818 2818 print 'The requested directory does not exist in history.'
2819 2819 return
2820 2820 else:
2821 2821 opts = {}
2822 2822 elif parameter_s.startswith('--'):
2823 2823 ps = None
2824 2824 fallback = None
2825 2825 pat = parameter_s[2:]
2826 2826 dh = self.shell.user_ns['_dh']
2827 2827 # first search only by basename (last component)
2828 2828 for ent in reversed(dh):
2829 2829 if pat in os.path.basename(ent) and os.path.isdir(ent):
2830 2830 ps = ent
2831 2831 break
2832 2832
2833 2833 if fallback is None and pat in ent and os.path.isdir(ent):
2834 2834 fallback = ent
2835 2835
2836 2836 # if we have no last part match, pick the first full path match
2837 2837 if ps is None:
2838 2838 ps = fallback
2839 2839
2840 2840 if ps is None:
2841 2841 print "No matching entry in directory history"
2842 2842 return
2843 2843 else:
2844 2844 opts = {}
2845 2845
2846 2846
2847 2847 else:
2848 2848 #turn all non-space-escaping backslashes to slashes,
2849 2849 # for c:\windows\directory\names\
2850 2850 parameter_s = re.sub(r'\\(?! )','/', parameter_s)
2851 2851 opts,ps = self.parse_options(parameter_s,'qb',mode='string')
2852 2852 # jump to previous
2853 2853 if ps == '-':
2854 2854 try:
2855 2855 ps = self.shell.user_ns['_dh'][-2]
2856 2856 except IndexError:
2857 2857 raise UsageError('%cd -: No previous directory to change to.')
2858 2858 # jump to bookmark if needed
2859 2859 else:
2860 2860 if not os.path.isdir(ps) or opts.has_key('b'):
2861 2861 bkms = self.db.get('bookmarks', {})
2862 2862
2863 2863 if bkms.has_key(ps):
2864 2864 target = bkms[ps]
2865 2865 print '(bookmark:%s) -> %s' % (ps,target)
2866 2866 ps = target
2867 2867 else:
2868 2868 if opts.has_key('b'):
2869 2869 raise UsageError("Bookmark '%s' not found. "
2870 2870 "Use '%%bookmark -l' to see your bookmarks." % ps)
2871 2871
2872 2872 # strip extra quotes on Windows, because os.chdir doesn't like them
2873 2873 ps = unquote_filename(ps)
2874 2874 # at this point ps should point to the target dir
2875 2875 if ps:
2876 2876 try:
2877 2877 os.chdir(os.path.expanduser(ps))
2878 2878 if hasattr(self.shell, 'term_title') and self.shell.term_title:
2879 2879 set_term_title('IPython: ' + abbrev_cwd())
2880 2880 except OSError:
2881 2881 print sys.exc_info()[1]
2882 2882 else:
2883 2883 cwd = os.getcwdu()
2884 2884 dhist = self.shell.user_ns['_dh']
2885 2885 if oldcwd != cwd:
2886 2886 dhist.append(cwd)
2887 2887 self.db['dhist'] = compress_dhist(dhist)[-100:]
2888 2888
2889 2889 else:
2890 2890 os.chdir(self.shell.home_dir)
2891 2891 if hasattr(self.shell, 'term_title') and self.shell.term_title:
2892 2892 set_term_title('IPython: ' + '~')
2893 2893 cwd = os.getcwdu()
2894 2894 dhist = self.shell.user_ns['_dh']
2895 2895
2896 2896 if oldcwd != cwd:
2897 2897 dhist.append(cwd)
2898 2898 self.db['dhist'] = compress_dhist(dhist)[-100:]
2899 2899 if not 'q' in opts and self.shell.user_ns['_dh']:
2900 2900 print self.shell.user_ns['_dh'][-1]
2901 2901
2902 2902
2903 2903 def magic_env(self, parameter_s=''):
2904 2904 """List environment variables."""
2905 2905
2906 2906 return os.environ.data
2907 2907
2908 2908 def magic_pushd(self, parameter_s=''):
2909 2909 """Place the current dir on stack and change directory.
2910 2910
2911 2911 Usage:\\
2912 2912 %pushd ['dirname']
2913 2913 """
2914 2914
2915 2915 dir_s = self.shell.dir_stack
2916 2916 tgt = os.path.expanduser(unquote_filename(parameter_s))
2917 2917 cwd = os.getcwdu().replace(self.home_dir,'~')
2918 2918 if tgt:
2919 2919 self.magic_cd(parameter_s)
2920 2920 dir_s.insert(0,cwd)
2921 2921 return self.magic_dirs()
2922 2922
2923 2923 def magic_popd(self, parameter_s=''):
2924 2924 """Change to directory popped off the top of the stack.
2925 2925 """
2926 2926 if not self.shell.dir_stack:
2927 2927 raise UsageError("%popd on empty stack")
2928 2928 top = self.shell.dir_stack.pop(0)
2929 2929 self.magic_cd(top)
2930 2930 print "popd ->",top
2931 2931
2932 2932 def magic_dirs(self, parameter_s=''):
2933 2933 """Return the current directory stack."""
2934 2934
2935 2935 return self.shell.dir_stack
2936 2936
2937 2937 def magic_dhist(self, parameter_s=''):
2938 2938 """Print your history of visited directories.
2939 2939
2940 2940 %dhist -> print full history\\
2941 2941 %dhist n -> print last n entries only\\
2942 2942 %dhist n1 n2 -> print entries between n1 and n2 (n1 not included)\\
2943 2943
2944 2944 This history is automatically maintained by the %cd command, and
2945 2945 always available as the global list variable _dh. You can use %cd -<n>
2946 2946 to go to directory number <n>.
2947 2947
2948 2948 Note that most of time, you should view directory history by entering
2949 2949 cd -<TAB>.
2950 2950
2951 2951 """
2952 2952
2953 2953 dh = self.shell.user_ns['_dh']
2954 2954 if parameter_s:
2955 2955 try:
2956 2956 args = map(int,parameter_s.split())
2957 2957 except:
2958 2958 self.arg_err(Magic.magic_dhist)
2959 2959 return
2960 2960 if len(args) == 1:
2961 2961 ini,fin = max(len(dh)-(args[0]),0),len(dh)
2962 2962 elif len(args) == 2:
2963 2963 ini,fin = args
2964 2964 else:
2965 2965 self.arg_err(Magic.magic_dhist)
2966 2966 return
2967 2967 else:
2968 2968 ini,fin = 0,len(dh)
2969 2969 nlprint(dh,
2970 2970 header = 'Directory history (kept in _dh)',
2971 2971 start=ini,stop=fin)
2972 2972
2973 2973 @skip_doctest
2974 2974 def magic_sc(self, parameter_s=''):
2975 2975 """Shell capture - execute a shell command and capture its output.
2976 2976
2977 2977 DEPRECATED. Suboptimal, retained for backwards compatibility.
2978 2978
2979 2979 You should use the form 'var = !command' instead. Example:
2980 2980
2981 2981 "%sc -l myfiles = ls ~" should now be written as
2982 2982
2983 2983 "myfiles = !ls ~"
2984 2984
2985 2985 myfiles.s, myfiles.l and myfiles.n still apply as documented
2986 2986 below.
2987 2987
2988 2988 --
2989 2989 %sc [options] varname=command
2990 2990
2991 2991 IPython will run the given command using commands.getoutput(), and
2992 2992 will then update the user's interactive namespace with a variable
2993 2993 called varname, containing the value of the call. Your command can
2994 2994 contain shell wildcards, pipes, etc.
2995 2995
2996 2996 The '=' sign in the syntax is mandatory, and the variable name you
2997 2997 supply must follow Python's standard conventions for valid names.
2998 2998
2999 2999 (A special format without variable name exists for internal use)
3000 3000
3001 3001 Options:
3002 3002
3003 3003 -l: list output. Split the output on newlines into a list before
3004 3004 assigning it to the given variable. By default the output is stored
3005 3005 as a single string.
3006 3006
3007 3007 -v: verbose. Print the contents of the variable.
3008 3008
3009 3009 In most cases you should not need to split as a list, because the
3010 3010 returned value is a special type of string which can automatically
3011 3011 provide its contents either as a list (split on newlines) or as a
3012 3012 space-separated string. These are convenient, respectively, either
3013 3013 for sequential processing or to be passed to a shell command.
3014 3014
3015 3015 For example:
3016 3016
3017 3017 # all-random
3018 3018
3019 3019 # Capture into variable a
3020 3020 In [1]: sc a=ls *py
3021 3021
3022 3022 # a is a string with embedded newlines
3023 3023 In [2]: a
3024 3024 Out[2]: 'setup.py\\nwin32_manual_post_install.py'
3025 3025
3026 3026 # which can be seen as a list:
3027 3027 In [3]: a.l
3028 3028 Out[3]: ['setup.py', 'win32_manual_post_install.py']
3029 3029
3030 3030 # or as a whitespace-separated string:
3031 3031 In [4]: a.s
3032 3032 Out[4]: 'setup.py win32_manual_post_install.py'
3033 3033
3034 3034 # a.s is useful to pass as a single command line:
3035 3035 In [5]: !wc -l $a.s
3036 3036 146 setup.py
3037 3037 130 win32_manual_post_install.py
3038 3038 276 total
3039 3039
3040 3040 # while the list form is useful to loop over:
3041 3041 In [6]: for f in a.l:
3042 3042 ...: !wc -l $f
3043 3043 ...:
3044 3044 146 setup.py
3045 3045 130 win32_manual_post_install.py
3046 3046
3047 3047 Similiarly, the lists returned by the -l option are also special, in
3048 3048 the sense that you can equally invoke the .s attribute on them to
3049 3049 automatically get a whitespace-separated string from their contents:
3050 3050
3051 3051 In [7]: sc -l b=ls *py
3052 3052
3053 3053 In [8]: b
3054 3054 Out[8]: ['setup.py', 'win32_manual_post_install.py']
3055 3055
3056 3056 In [9]: b.s
3057 3057 Out[9]: 'setup.py win32_manual_post_install.py'
3058 3058
3059 3059 In summary, both the lists and strings used for ouptut capture have
3060 3060 the following special attributes:
3061 3061
3062 3062 .l (or .list) : value as list.
3063 3063 .n (or .nlstr): value as newline-separated string.
3064 3064 .s (or .spstr): value as space-separated string.
3065 3065 """
3066 3066
3067 3067 opts,args = self.parse_options(parameter_s,'lv')
3068 3068 # Try to get a variable name and command to run
3069 3069 try:
3070 3070 # the variable name must be obtained from the parse_options
3071 3071 # output, which uses shlex.split to strip options out.
3072 3072 var,_ = args.split('=',1)
3073 3073 var = var.strip()
3074 3074 # But the the command has to be extracted from the original input
3075 3075 # parameter_s, not on what parse_options returns, to avoid the
3076 3076 # quote stripping which shlex.split performs on it.
3077 3077 _,cmd = parameter_s.split('=',1)
3078 3078 except ValueError:
3079 3079 var,cmd = '',''
3080 3080 # If all looks ok, proceed
3081 3081 split = 'l' in opts
3082 3082 out = self.shell.getoutput(cmd, split=split)
3083 3083 if opts.has_key('v'):
3084 3084 print '%s ==\n%s' % (var,pformat(out))
3085 3085 if var:
3086 3086 self.shell.user_ns.update({var:out})
3087 3087 else:
3088 3088 return out
3089 3089
3090 3090 def magic_sx(self, parameter_s=''):
3091 3091 """Shell execute - run a shell command and capture its output.
3092 3092
3093 3093 %sx command
3094 3094
3095 3095 IPython will run the given command using commands.getoutput(), and
3096 3096 return the result formatted as a list (split on '\\n'). Since the
3097 3097 output is _returned_, it will be stored in ipython's regular output
3098 3098 cache Out[N] and in the '_N' automatic variables.
3099 3099
3100 3100 Notes:
3101 3101
3102 3102 1) If an input line begins with '!!', then %sx is automatically
3103 3103 invoked. That is, while:
3104 3104 !ls
3105 3105 causes ipython to simply issue system('ls'), typing
3106 3106 !!ls
3107 3107 is a shorthand equivalent to:
3108 3108 %sx ls
3109 3109
3110 3110 2) %sx differs from %sc in that %sx automatically splits into a list,
3111 3111 like '%sc -l'. The reason for this is to make it as easy as possible
3112 3112 to process line-oriented shell output via further python commands.
3113 3113 %sc is meant to provide much finer control, but requires more
3114 3114 typing.
3115 3115
3116 3116 3) Just like %sc -l, this is a list with special attributes:
3117 3117
3118 3118 .l (or .list) : value as list.
3119 3119 .n (or .nlstr): value as newline-separated string.
3120 3120 .s (or .spstr): value as whitespace-separated string.
3121 3121
3122 3122 This is very useful when trying to use such lists as arguments to
3123 3123 system commands."""
3124 3124
3125 3125 if parameter_s:
3126 3126 return self.shell.getoutput(parameter_s)
3127 3127
3128 3128
3129 3129 def magic_bookmark(self, parameter_s=''):
3130 3130 """Manage IPython's bookmark system.
3131 3131
3132 3132 %bookmark <name> - set bookmark to current dir
3133 3133 %bookmark <name> <dir> - set bookmark to <dir>
3134 3134 %bookmark -l - list all bookmarks
3135 3135 %bookmark -d <name> - remove bookmark
3136 3136 %bookmark -r - remove all bookmarks
3137 3137
3138 3138 You can later on access a bookmarked folder with:
3139 3139 %cd -b <name>
3140 3140 or simply '%cd <name>' if there is no directory called <name> AND
3141 3141 there is such a bookmark defined.
3142 3142
3143 3143 Your bookmarks persist through IPython sessions, but they are
3144 3144 associated with each profile."""
3145 3145
3146 3146 opts,args = self.parse_options(parameter_s,'drl',mode='list')
3147 3147 if len(args) > 2:
3148 3148 raise UsageError("%bookmark: too many arguments")
3149 3149
3150 3150 bkms = self.db.get('bookmarks',{})
3151 3151
3152 3152 if opts.has_key('d'):
3153 3153 try:
3154 3154 todel = args[0]
3155 3155 except IndexError:
3156 3156 raise UsageError(
3157 3157 "%bookmark -d: must provide a bookmark to delete")
3158 3158 else:
3159 3159 try:
3160 3160 del bkms[todel]
3161 3161 except KeyError:
3162 3162 raise UsageError(
3163 3163 "%%bookmark -d: Can't delete bookmark '%s'" % todel)
3164 3164
3165 3165 elif opts.has_key('r'):
3166 3166 bkms = {}
3167 3167 elif opts.has_key('l'):
3168 3168 bks = bkms.keys()
3169 3169 bks.sort()
3170 3170 if bks:
3171 3171 size = max(map(len,bks))
3172 3172 else:
3173 3173 size = 0
3174 3174 fmt = '%-'+str(size)+'s -> %s'
3175 3175 print 'Current bookmarks:'
3176 3176 for bk in bks:
3177 3177 print fmt % (bk,bkms[bk])
3178 3178 else:
3179 3179 if not args:
3180 3180 raise UsageError("%bookmark: You must specify the bookmark name")
3181 3181 elif len(args)==1:
3182 3182 bkms[args[0]] = os.getcwdu()
3183 3183 elif len(args)==2:
3184 3184 bkms[args[0]] = args[1]
3185 3185 self.db['bookmarks'] = bkms
3186 3186
3187 3187 def magic_pycat(self, parameter_s=''):
3188 3188 """Show a syntax-highlighted file through a pager.
3189 3189
3190 3190 This magic is similar to the cat utility, but it will assume the file
3191 3191 to be Python source and will show it with syntax highlighting. """
3192 3192
3193 3193 try:
3194 3194 filename = get_py_filename(parameter_s)
3195 3195 cont = file_read(filename)
3196 3196 except IOError:
3197 3197 try:
3198 3198 cont = eval(parameter_s,self.user_ns)
3199 3199 except NameError:
3200 3200 cont = None
3201 3201 if cont is None:
3202 3202 print "Error: no such file or variable"
3203 3203 return
3204 3204
3205 3205 page.page(self.shell.pycolorize(cont))
3206 3206
3207 3207 def _rerun_pasted(self):
3208 3208 """ Rerun a previously pasted command.
3209 3209 """
3210 3210 b = self.user_ns.get('pasted_block', None)
3211 3211 if b is None:
3212 3212 raise UsageError('No previous pasted block available')
3213 3213 print "Re-executing '%s...' (%d chars)"% (b.split('\n',1)[0], len(b))
3214 3214 exec b in self.user_ns
3215 3215
3216 3216 def _get_pasted_lines(self, sentinel):
3217 3217 """ Yield pasted lines until the user enters the given sentinel value.
3218 3218 """
3219 3219 from IPython.core import interactiveshell
3220 3220 print "Pasting code; enter '%s' alone on the line to stop." % sentinel
3221 3221 while True:
3222 3222 try:
3223 3223 l = self.shell.raw_input_original(':')
3224 3224 if l == sentinel:
3225 3225 return
3226 3226 else:
3227 3227 yield l
3228 3228 except EOFError:
3229 3229 print '<EOF>'
3230 3230 return
3231 3231
3232 3232 def _strip_pasted_lines_for_code(self, raw_lines):
3233 3233 """ Strip non-code parts of a sequence of lines to return a block of
3234 3234 code.
3235 3235 """
3236 3236 # Regular expressions that declare text we strip from the input:
3237 3237 strip_re = [r'^\s*In \[\d+\]:', # IPython input prompt
3238 3238 r'^\s*(\s?>)+', # Python input prompt
3239 3239 r'^\s*\.{3,}', # Continuation prompts
3240 3240 r'^\++',
3241 3241 ]
3242 3242
3243 3243 strip_from_start = map(re.compile,strip_re)
3244 3244
3245 3245 lines = []
3246 3246 for l in raw_lines:
3247 3247 for pat in strip_from_start:
3248 3248 l = pat.sub('',l)
3249 3249 lines.append(l)
3250 3250
3251 3251 block = "\n".join(lines) + '\n'
3252 3252 #print "block:\n",block
3253 3253 return block
3254 3254
3255 3255 def _execute_block(self, block, par):
3256 3256 """ Execute a block, or store it in a variable, per the user's request.
3257 3257 """
3258 3258 if not par:
3259 3259 b = textwrap.dedent(block)
3260 3260 self.user_ns['pasted_block'] = b
3261 3261 self.run_cell(b)
3262 3262 else:
3263 3263 self.user_ns[par] = SList(block.splitlines())
3264 3264 print "Block assigned to '%s'" % par
3265 3265
3266 3266 def magic_quickref(self,arg):
3267 3267 """ Show a quick reference sheet """
3268 3268 import IPython.core.usage
3269 3269 qr = IPython.core.usage.quick_reference + self.magic_magic('-brief')
3270 3270
3271 3271 page.page(qr)
3272 3272
3273 3273 def magic_doctest_mode(self,parameter_s=''):
3274 3274 """Toggle doctest mode on and off.
3275 3275
3276 3276 This mode is intended to make IPython behave as much as possible like a
3277 3277 plain Python shell, from the perspective of how its prompts, exceptions
3278 3278 and output look. This makes it easy to copy and paste parts of a
3279 3279 session into doctests. It does so by:
3280 3280
3281 3281 - Changing the prompts to the classic ``>>>`` ones.
3282 3282 - Changing the exception reporting mode to 'Plain'.
3283 3283 - Disabling pretty-printing of output.
3284 3284
3285 3285 Note that IPython also supports the pasting of code snippets that have
3286 3286 leading '>>>' and '...' prompts in them. This means that you can paste
3287 3287 doctests from files or docstrings (even if they have leading
3288 3288 whitespace), and the code will execute correctly. You can then use
3289 3289 '%history -t' to see the translated history; this will give you the
3290 3290 input after removal of all the leading prompts and whitespace, which
3291 3291 can be pasted back into an editor.
3292 3292
3293 3293 With these features, you can switch into this mode easily whenever you
3294 3294 need to do testing and changes to doctests, without having to leave
3295 3295 your existing IPython session.
3296 3296 """
3297 3297
3298 3298 from IPython.utils.ipstruct import Struct
3299 3299
3300 3300 # Shorthands
3301 3301 shell = self.shell
3302 3302 oc = shell.displayhook
3303 3303 meta = shell.meta
3304 3304 disp_formatter = self.shell.display_formatter
3305 3305 ptformatter = disp_formatter.formatters['text/plain']
3306 3306 # dstore is a data store kept in the instance metadata bag to track any
3307 3307 # changes we make, so we can undo them later.
3308 3308 dstore = meta.setdefault('doctest_mode',Struct())
3309 3309 save_dstore = dstore.setdefault
3310 3310
3311 3311 # save a few values we'll need to recover later
3312 3312 mode = save_dstore('mode',False)
3313 3313 save_dstore('rc_pprint',ptformatter.pprint)
3314 3314 save_dstore('xmode',shell.InteractiveTB.mode)
3315 3315 save_dstore('rc_separate_out',shell.separate_out)
3316 3316 save_dstore('rc_separate_out2',shell.separate_out2)
3317 3317 save_dstore('rc_prompts_pad_left',shell.prompts_pad_left)
3318 3318 save_dstore('rc_separate_in',shell.separate_in)
3319 3319 save_dstore('rc_plain_text_only',disp_formatter.plain_text_only)
3320 3320
3321 3321 if mode == False:
3322 3322 # turn on
3323 3323 oc.prompt1.p_template = '>>> '
3324 3324 oc.prompt2.p_template = '... '
3325 3325 oc.prompt_out.p_template = ''
3326 3326
3327 3327 # Prompt separators like plain python
3328 3328 oc.input_sep = oc.prompt1.sep = ''
3329 3329 oc.output_sep = ''
3330 3330 oc.output_sep2 = ''
3331 3331
3332 3332 oc.prompt1.pad_left = oc.prompt2.pad_left = \
3333 3333 oc.prompt_out.pad_left = False
3334 3334
3335 3335 ptformatter.pprint = False
3336 3336 disp_formatter.plain_text_only = True
3337 3337
3338 3338 shell.magic_xmode('Plain')
3339 3339 else:
3340 3340 # turn off
3341 3341 oc.prompt1.p_template = shell.prompt_in1
3342 3342 oc.prompt2.p_template = shell.prompt_in2
3343 3343 oc.prompt_out.p_template = shell.prompt_out
3344 3344
3345 3345 oc.input_sep = oc.prompt1.sep = dstore.rc_separate_in
3346 3346
3347 3347 oc.output_sep = dstore.rc_separate_out
3348 3348 oc.output_sep2 = dstore.rc_separate_out2
3349 3349
3350 3350 oc.prompt1.pad_left = oc.prompt2.pad_left = \
3351 3351 oc.prompt_out.pad_left = dstore.rc_prompts_pad_left
3352 3352
3353 3353 ptformatter.pprint = dstore.rc_pprint
3354 3354 disp_formatter.plain_text_only = dstore.rc_plain_text_only
3355 3355
3356 3356 shell.magic_xmode(dstore.xmode)
3357 3357
3358 3358 # Store new mode and inform
3359 3359 dstore.mode = bool(1-int(mode))
3360 3360 mode_label = ['OFF','ON'][dstore.mode]
3361 3361 print 'Doctest mode is:', mode_label
3362 3362
3363 3363 def magic_gui(self, parameter_s=''):
3364 3364 """Enable or disable IPython GUI event loop integration.
3365 3365
3366 3366 %gui [GUINAME]
3367 3367
3368 3368 This magic replaces IPython's threaded shells that were activated
3369 3369 using the (pylab/wthread/etc.) command line flags. GUI toolkits
3370 3370 can now be enabled, disabled and changed at runtime and keyboard
3371 3371 interrupts should work without any problems. The following toolkits
3372 3372 are supported: wxPython, PyQt4, PyGTK, and Tk::
3373 3373
3374 3374 %gui wx # enable wxPython event loop integration
3375 3375 %gui qt4|qt # enable PyQt4 event loop integration
3376 3376 %gui gtk # enable PyGTK event loop integration
3377 3377 %gui tk # enable Tk event loop integration
3378 3378 %gui # disable all event loop integration
3379 3379
3380 3380 WARNING: after any of these has been called you can simply create
3381 3381 an application object, but DO NOT start the event loop yourself, as
3382 3382 we have already handled that.
3383 3383 """
3384 3384 from IPython.lib.inputhook import enable_gui
3385 3385 opts, arg = self.parse_options(parameter_s, '')
3386 3386 if arg=='': arg = None
3387 3387 return enable_gui(arg)
3388 3388
3389 3389 def magic_load_ext(self, module_str):
3390 3390 """Load an IPython extension by its module name."""
3391 3391 return self.extension_manager.load_extension(module_str)
3392 3392
3393 3393 def magic_unload_ext(self, module_str):
3394 3394 """Unload an IPython extension by its module name."""
3395 3395 self.extension_manager.unload_extension(module_str)
3396 3396
3397 3397 def magic_reload_ext(self, module_str):
3398 3398 """Reload an IPython extension by its module name."""
3399 3399 self.extension_manager.reload_extension(module_str)
3400 3400
3401 3401 @skip_doctest
3402 3402 def magic_install_profiles(self, s):
3403 3403 """Install the default IPython profiles into the .ipython dir.
3404 3404
3405 3405 If the default profiles have already been installed, they will not
3406 3406 be overwritten. You can force overwriting them by using the ``-o``
3407 3407 option::
3408 3408
3409 3409 In [1]: %install_profiles -o
3410 3410 """
3411 3411 if '-o' in s:
3412 3412 overwrite = True
3413 3413 else:
3414 3414 overwrite = False
3415 3415 from IPython.config import profile
3416 3416 profile_dir = os.path.dirname(profile.__file__)
3417 3417 ipython_dir = self.ipython_dir
3418 3418 print "Installing profiles to: %s [overwrite=%s]"%(ipython_dir,overwrite)
3419 3419 for src in os.listdir(profile_dir):
3420 3420 if src.startswith('profile_'):
3421 3421 name = src.replace('profile_', '')
3422 3422 print " %s"%name
3423 3423 pd = ProfileDir.create_profile_dir_by_name(ipython_dir, name)
3424 3424 pd.copy_config_file('ipython_config.py', path=src,
3425 3425 overwrite=overwrite)
3426 3426
3427 3427 @skip_doctest
3428 3428 def magic_install_default_config(self, s):
3429 3429 """Install IPython's default config file into the .ipython dir.
3430 3430
3431 3431 If the default config file (:file:`ipython_config.py`) is already
3432 3432 installed, it will not be overwritten. You can force overwriting
3433 3433 by using the ``-o`` option::
3434 3434
3435 3435 In [1]: %install_default_config
3436 3436 """
3437 3437 if '-o' in s:
3438 3438 overwrite = True
3439 3439 else:
3440 3440 overwrite = False
3441 3441 pd = self.shell.profile_dir
3442 3442 print "Installing default config file in: %s" % pd.location
3443 3443 pd.copy_config_file('ipython_config.py', overwrite=overwrite)
3444 3444
3445 3445 # Pylab support: simple wrappers that activate pylab, load gui input
3446 3446 # handling and modify slightly %run
3447 3447
3448 3448 @skip_doctest
3449 3449 def _pylab_magic_run(self, parameter_s=''):
3450 3450 Magic.magic_run(self, parameter_s,
3451 3451 runner=mpl_runner(self.shell.safe_execfile))
3452 3452
3453 3453 _pylab_magic_run.__doc__ = magic_run.__doc__
3454 3454
3455 3455 @skip_doctest
3456 3456 def magic_pylab(self, s):
3457 3457 """Load numpy and matplotlib to work interactively.
3458 3458
3459 3459 %pylab [GUINAME]
3460 3460
3461 3461 This function lets you activate pylab (matplotlib, numpy and
3462 3462 interactive support) at any point during an IPython session.
3463 3463
3464 3464 It will import at the top level numpy as np, pyplot as plt, matplotlib,
3465 3465 pylab and mlab, as well as all names from numpy and pylab.
3466 3466
3467 3467 If you are using the inline matplotlib backend for embedded figures,
3468 3468 you can adjust its behavior via the %config magic::
3469 3469
3470 3470 # enable SVG figures, necessary for SVG+XHTML export in the qtconsole
3471 3471 In [1]: %config InlineBackend.figure_format = 'svg'
3472 3472
3473 3473 # change the behavior of closing all figures at the end of each
3474 3474 # execution (cell), or allowing reuse of active figures across
3475 3475 # cells:
3476 3476 In [2]: %config InlineBackend.close_figures = False
3477 3477
3478 3478 Parameters
3479 3479 ----------
3480 3480 guiname : optional
3481 3481 One of the valid arguments to the %gui magic ('qt', 'wx', 'gtk', 'osx' or
3482 3482 'tk'). If given, the corresponding Matplotlib backend is used,
3483 3483 otherwise matplotlib's default (which you can override in your
3484 3484 matplotlib config file) is used.
3485 3485
3486 3486 Examples
3487 3487 --------
3488 3488 In this case, where the MPL default is TkAgg::
3489 3489
3490 3490 In [2]: %pylab
3491 3491
3492 3492 Welcome to pylab, a matplotlib-based Python environment.
3493 3493 Backend in use: TkAgg
3494 3494 For more information, type 'help(pylab)'.
3495 3495
3496 3496 But you can explicitly request a different backend::
3497 3497
3498 3498 In [3]: %pylab qt
3499 3499
3500 3500 Welcome to pylab, a matplotlib-based Python environment.
3501 3501 Backend in use: Qt4Agg
3502 3502 For more information, type 'help(pylab)'.
3503 3503 """
3504 3504
3505 3505 if Application.initialized():
3506 3506 app = Application.instance()
3507 3507 try:
3508 3508 import_all_status = app.pylab_import_all
3509 3509 except AttributeError:
3510 3510 import_all_status = True
3511 3511 else:
3512 3512 import_all_status = True
3513 3513
3514 3514 self.shell.enable_pylab(s,import_all=import_all_status)
3515 3515
3516 3516 def magic_tb(self, s):
3517 3517 """Print the last traceback with the currently active exception mode.
3518 3518
3519 3519 See %xmode for changing exception reporting modes."""
3520 3520 self.shell.showtraceback()
3521 3521
3522 3522 @skip_doctest
3523 3523 def magic_precision(self, s=''):
3524 3524 """Set floating point precision for pretty printing.
3525 3525
3526 3526 Can set either integer precision or a format string.
3527 3527
3528 3528 If numpy has been imported and precision is an int,
3529 3529 numpy display precision will also be set, via ``numpy.set_printoptions``.
3530 3530
3531 3531 If no argument is given, defaults will be restored.
3532 3532
3533 3533 Examples
3534 3534 --------
3535 3535 ::
3536 3536
3537 3537 In [1]: from math import pi
3538 3538
3539 3539 In [2]: %precision 3
3540 3540 Out[2]: u'%.3f'
3541 3541
3542 3542 In [3]: pi
3543 3543 Out[3]: 3.142
3544 3544
3545 3545 In [4]: %precision %i
3546 3546 Out[4]: u'%i'
3547 3547
3548 3548 In [5]: pi
3549 3549 Out[5]: 3
3550 3550
3551 3551 In [6]: %precision %e
3552 3552 Out[6]: u'%e'
3553 3553
3554 3554 In [7]: pi**10
3555 3555 Out[7]: 9.364805e+04
3556 3556
3557 3557 In [8]: %precision
3558 3558 Out[8]: u'%r'
3559 3559
3560 3560 In [9]: pi**10
3561 3561 Out[9]: 93648.047476082982
3562 3562
3563 3563 """
3564 3564
3565 3565 ptformatter = self.shell.display_formatter.formatters['text/plain']
3566 3566 ptformatter.float_precision = s
3567 3567 return ptformatter.float_format
3568 3568
3569 3569
3570 3570 @magic_arguments.magic_arguments()
3571 3571 @magic_arguments.argument(
3572 3572 '-e', '--export', action='store_true', default=False,
3573 3573 help='Export IPython history as a notebook. The filename argument '
3574 3574 'is used to specify the notebook name and format. For example '
3575 3575 'a filename of notebook.ipynb will result in a notebook name '
3576 3576 'of "notebook" and a format of "xml". Likewise using a ".json" '
3577 3577 'or ".py" file extension will write the notebook in the json '
3578 3578 'or py formats.'
3579 3579 )
3580 3580 @magic_arguments.argument(
3581 3581 '-f', '--format',
3582 3582 help='Convert an existing IPython notebook to a new format. This option '
3583 3583 'specifies the new format and can have the values: xml, json, py. '
3584 3584 'The target filename is choosen automatically based on the new '
3585 3585 'format. The filename argument gives the name of the source file.'
3586 3586 )
3587 3587 @magic_arguments.argument(
3588 3588 'filename', type=unicode,
3589 3589 help='Notebook name or filename'
3590 3590 )
3591 3591 def magic_notebook(self, s):
3592 3592 """Export and convert IPython notebooks.
3593 3593
3594 3594 This function can export the current IPython history to a notebook file
3595 3595 or can convert an existing notebook file into a different format. For
3596 3596 example, to export the history to "foo.ipynb" do "%notebook -e foo.ipynb".
3597 3597 To export the history to "foo.py" do "%notebook -e foo.py". To convert
3598 3598 "foo.ipynb" to "foo.json" do "%notebook -f json foo.ipynb". Possible
3599 3599 formats include (json/ipynb, py).
3600 3600 """
3601 3601 args = magic_arguments.parse_argstring(self.magic_notebook, s)
3602 3602
3603 3603 from IPython.nbformat import current
3604 3604 args.filename = unquote_filename(args.filename)
3605 3605 if args.export:
3606 3606 fname, name, format = current.parse_filename(args.filename)
3607 3607 cells = []
3608 3608 hist = list(self.history_manager.get_range())
3609 3609 for session, prompt_number, input in hist[:-1]:
3610 3610 cells.append(current.new_code_cell(prompt_number=prompt_number, input=input))
3611 3611 worksheet = current.new_worksheet(cells=cells)
3612 3612 nb = current.new_notebook(name=name,worksheets=[worksheet])
3613 3613 with open(fname, 'w') as f:
3614 3614 current.write(nb, f, format);
3615 3615 elif args.format is not None:
3616 3616 old_fname, old_name, old_format = current.parse_filename(args.filename)
3617 3617 new_format = args.format
3618 3618 if new_format == u'xml':
3619 3619 raise ValueError('Notebooks cannot be written as xml.')
3620 3620 elif new_format == u'ipynb' or new_format == u'json':
3621 3621 new_fname = old_name + u'.ipynb'
3622 3622 new_format = u'json'
3623 3623 elif new_format == u'py':
3624 3624 new_fname = old_name + u'.py'
3625 3625 else:
3626 3626 raise ValueError('Invalid notebook format: %s' % new_format)
3627 3627 with open(old_fname, 'r') as f:
3628 3628 s = f.read()
3629 3629 try:
3630 3630 nb = current.reads(s, old_format)
3631 3631 except:
3632 3632 nb = current.reads(s, u'xml')
3633 3633 with open(new_fname, 'w') as f:
3634 3634 current.write(nb, f, new_format)
3635 3635
3636 3636 def magic_config(self, s):
3637 3637 """configure IPython
3638 3638
3639 3639 %config Class[.trait=value]
3640 3640
3641 3641 This magic exposes most of the IPython config system. Any
3642 3642 Configurable class should be able to be configured with the simple
3643 3643 line::
3644 3644
3645 3645 %config Class.trait=value
3646 3646
3647 3647 Where `value` will be resolved in the user's namespace, if it is an
3648 3648 expression or variable name.
3649 3649
3650 3650 Examples
3651 3651 --------
3652 3652
3653 3653 To see what classes are availabe for config, pass no arguments::
3654 3654
3655 3655 In [1]: %config
3656 3656 Available objects for config:
3657 3657 TerminalInteractiveShell
3658 3658 HistoryManager
3659 3659 PrefilterManager
3660 3660 AliasManager
3661 3661 IPCompleter
3662 3662 DisplayFormatter
3663 3663
3664 3664 To view what is configurable on a given class, just pass the class name::
3665 3665
3666 3666 In [2]: %config IPCompleter
3667 3667 IPCompleter options
3668 3668 -----------------
3669 3669 IPCompleter.omit__names=<Enum>
3670 3670 Current: 2
3671 3671 Choices: (0, 1, 2)
3672 3672 Instruct the completer to omit private method names
3673 3673 Specifically, when completing on ``object.<tab>``.
3674 3674 When 2 [default]: all names that start with '_' will be excluded.
3675 3675 When 1: all 'magic' names (``__foo__``) will be excluded.
3676 3676 When 0: nothing will be excluded.
3677 3677 IPCompleter.merge_completions=<CBool>
3678 3678 Current: True
3679 3679 Whether to merge completion results into a single list
3680 3680 If False, only the completion results from the first non-empty completer
3681 3681 will be returned.
3682 3682 IPCompleter.greedy=<CBool>
3683 3683 Current: False
3684 3684 Activate greedy completion
3685 3685 This will enable completion on elements of lists, results of function calls,
3686 3686 etc., but can be unsafe because the code is actually evaluated on TAB.
3687 3687
3688 3688 but the real use is in setting values::
3689 3689
3690 3690 In [3]: %config IPCompleter.greedy = True
3691 3691
3692 3692 and these values are read from the user_ns if they are variables::
3693 3693
3694 3694 In [4]: feeling_greedy=False
3695 3695
3696 3696 In [5]: %config IPCompleter.greedy = feeling_greedy
3697 3697
3698 3698 """
3699 3699 from IPython.config.loader import Config
3700 3700 # some IPython objects are Configurable, but do not yet have
3701 3701 # any configurable traits. Exclude them from the effects of
3702 3702 # this magic, as their presence is just noise:
3703 3703 configurables = [ c for c in self.configurables if c.__class__.class_traits(config=True) ]
3704 3704 classnames = [ c.__class__.__name__ for c in configurables ]
3705 3705
3706 3706 line = s.strip()
3707 3707 if not line:
3708 3708 # print available configurable names
3709 3709 print "Available objects for config:"
3710 3710 for name in classnames:
3711 3711 print " ", name
3712 3712 return
3713 3713 elif line in classnames:
3714 3714 # `%config TerminalInteractiveShell` will print trait info for
3715 3715 # TerminalInteractiveShell
3716 3716 c = configurables[classnames.index(line)]
3717 3717 cls = c.__class__
3718 3718 help = cls.class_get_help(c)
3719 3719 # strip leading '--' from cl-args:
3720 3720 help = re.sub(re.compile(r'^--', re.MULTILINE), '', help)
3721 3721 print help
3722 3722 return
3723 3723 elif '=' not in line:
3724 3724 raise UsageError("Invalid config statement: %r, should be Class.trait = value" % line)
3725 3725
3726 3726
3727 3727 # otherwise, assume we are setting configurables.
3728 3728 # leave quotes on args when splitting, because we want
3729 3729 # unquoted args to eval in user_ns
3730 3730 cfg = Config()
3731 3731 exec "cfg."+line in locals(), self.user_ns
3732 3732
3733 3733 for configurable in configurables:
3734 3734 try:
3735 3735 configurable.update_config(cfg)
3736 3736 except Exception as e:
3737 3737 error(e)
3738 3738
3739 3739 # end Magic
@@ -1,217 +1,217 b''
1 1 ''' A decorator-based method of constructing IPython magics with `argparse`
2 2 option handling.
3 3
4 4 New magic functions can be defined like so::
5 5
6 6 from IPython.core.magic_arguments import (argument, magic_arguments,
7 7 parse_argstring)
8 8
9 9 @magic_arguments()
10 10 @argument('-o', '--option', help='An optional argument.')
11 11 @argument('arg', type=int, help='An integer positional argument.')
12 12 def magic_cool(self, arg):
13 13 """ A really cool magic command.
14 14
15 15 """
16 16 args = parse_argstring(magic_cool, arg)
17 17 ...
18 18
19 19 The `@magic_arguments` decorator marks the function as having argparse arguments.
20 20 The `@argument` decorator adds an argument using the same syntax as argparse's
21 21 `add_argument()` method. More sophisticated uses may also require the
22 22 `@argument_group` or `@kwds` decorator to customize the formatting and the
23 23 parsing.
24 24
25 25 Help text for the magic is automatically generated from the docstring and the
26 26 arguments::
27 27
28 28 In[1]: %cool?
29 29 %cool [-o OPTION] arg
30 30
31 31 A really cool magic command.
32 32
33 33 positional arguments:
34 34 arg An integer positional argument.
35 35
36 36 optional arguments:
37 37 -o OPTION, --option OPTION
38 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 44 # Distributed under the terms of the Modified BSD License.
45 45 #
46 46 # The full license is in the file COPYING.txt, distributed with this software.
47 47 #-----------------------------------------------------------------------------
48 48
49 49 # Our own imports
50 50 from IPython.external import argparse
51 51 from IPython.core.error import UsageError
52 52 from IPython.utils.process import arg_split
53 53
54 54
55 55 class MagicArgumentParser(argparse.ArgumentParser):
56 56 """ An ArgumentParser tweaked for use by IPython magics.
57 57 """
58 58 def __init__(self,
59 59 prog=None,
60 60 usage=None,
61 61 description=None,
62 62 epilog=None,
63 63 version=None,
64 64 parents=None,
65 65 formatter_class=argparse.HelpFormatter,
66 66 prefix_chars='-',
67 67 argument_default=None,
68 68 conflict_handler='error',
69 69 add_help=False):
70 70 if parents is None:
71 71 parents = []
72 72 super(MagicArgumentParser, self).__init__(prog=prog, usage=usage,
73 73 description=description, epilog=epilog, version=version,
74 74 parents=parents, formatter_class=formatter_class,
75 75 prefix_chars=prefix_chars, argument_default=argument_default,
76 76 conflict_handler=conflict_handler, add_help=add_help)
77 77
78 78 def error(self, message):
79 79 """ Raise a catchable error instead of exiting.
80 80 """
81 81 raise UsageError(message)
82 82
83 83 def parse_argstring(self, argstring):
84 84 """ Split a string into an argument list and parse that argument list.
85 85 """
86 86 argv = arg_split(argstring)
87 87 return self.parse_args(argv)
88 88
89 89
90 90 def construct_parser(magic_func):
91 91 """ Construct an argument parser using the function decorations.
92 92 """
93 93 kwds = getattr(magic_func, 'argcmd_kwds', {})
94 94 if 'description' not in kwds:
95 95 kwds['description'] = getattr(magic_func, '__doc__', None)
96 96 arg_name = real_name(magic_func)
97 97 parser = MagicArgumentParser(arg_name, **kwds)
98 98 # Reverse the list of decorators in order to apply them in the
99 99 # order in which they appear in the source.
100 100 group = None
101 101 for deco in magic_func.decorators[::-1]:
102 102 result = deco.add_to_parser(parser, group)
103 103 if result is not None:
104 104 group = result
105 105
106 106 # Replace the starting 'usage: ' with IPython's %.
107 107 help_text = parser.format_help()
108 108 if help_text.startswith('usage: '):
109 109 help_text = help_text.replace('usage: ', '%', 1)
110 110 else:
111 111 help_text = '%' + help_text
112 112
113 113 # Replace the magic function's docstring with the full help text.
114 114 magic_func.__doc__ = help_text
115 115
116 116 return parser
117 117
118 118
119 119 def parse_argstring(magic_func, argstring):
120 120 """ Parse the string of arguments for the given magic function.
121 121 """
122 122 return magic_func.parser.parse_argstring(argstring)
123 123
124 124
125 125 def real_name(magic_func):
126 126 """ Find the real name of the magic.
127 127 """
128 128 magic_name = magic_func.__name__
129 129 if magic_name.startswith('magic_'):
130 130 magic_name = magic_name[len('magic_'):]
131 131 return getattr(magic_func, 'argcmd_name', magic_name)
132 132
133 133
134 134 class ArgDecorator(object):
135 135 """ Base class for decorators to add ArgumentParser information to a method.
136 136 """
137 137
138 138 def __call__(self, func):
139 139 if not getattr(func, 'has_arguments', False):
140 140 func.has_arguments = True
141 141 func.decorators = []
142 142 func.decorators.append(self)
143 143 return func
144 144
145 145 def add_to_parser(self, parser, group):
146 146 """ Add this object's information to the parser, if necessary.
147 147 """
148 148 pass
149 149
150 150
151 151 class magic_arguments(ArgDecorator):
152 152 """ Mark the magic as having argparse arguments and possibly adjust the
153 153 name.
154 154 """
155 155
156 156 def __init__(self, name=None):
157 157 self.name = name
158 158
159 159 def __call__(self, func):
160 160 if not getattr(func, 'has_arguments', False):
161 161 func.has_arguments = True
162 162 func.decorators = []
163 163 if self.name is not None:
164 164 func.argcmd_name = self.name
165 165 # This should be the first decorator in the list of decorators, thus the
166 166 # last to execute. Build the parser.
167 167 func.parser = construct_parser(func)
168 168 return func
169 169
170 170
171 171 class argument(ArgDecorator):
172 172 """ Store arguments and keywords to pass to add_argument().
173 173
174 174 Instances also serve to decorate command methods.
175 175 """
176 176 def __init__(self, *args, **kwds):
177 177 self.args = args
178 178 self.kwds = kwds
179 179
180 180 def add_to_parser(self, parser, group):
181 181 """ Add this object's information to the parser.
182 182 """
183 183 if group is not None:
184 184 parser = group
185 185 parser.add_argument(*self.args, **self.kwds)
186 186 return None
187 187
188 188
189 189 class argument_group(ArgDecorator):
190 190 """ Store arguments and keywords to pass to add_argument_group().
191 191
192 192 Instances also serve to decorate command methods.
193 193 """
194 194 def __init__(self, *args, **kwds):
195 195 self.args = args
196 196 self.kwds = kwds
197 197
198 198 def add_to_parser(self, parser, group):
199 199 """ Add this object's information to the parser.
200 200 """
201 201 return parser.add_argument_group(*self.args, **self.kwds)
202 202
203 203
204 204 class kwds(ArgDecorator):
205 205 """ Provide other keywords to the sub-parser constructor.
206 206 """
207 207 def __init__(self, **kwds):
208 208 self.kwds = kwds
209 209
210 210 def __call__(self, func):
211 211 func = super(kwds, self).__call__(func)
212 212 func.argcmd_kwds = self.kwds
213 213 return func
214 214
215 215
216 216 __all__ = ['magic_arguments', 'argument', 'argument_group', 'kwds',
217 217 'parse_argstring']
@@ -1,340 +1,340 b''
1 1 # encoding: utf-8
2 2 """
3 3 Paging capabilities for IPython.core
4 4
5 5 Authors:
6 6
7 7 * Brian Granger
8 8 * Fernando Perez
9 9
10 10 Notes
11 11 -----
12 12
13 13 For now this uses ipapi, so it can't be in IPython.utils. If we can get
14 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 21 # Distributed under the terms of the BSD License. The full license is in
22 22 # the file COPYING, distributed as part of this software.
23 23 #-----------------------------------------------------------------------------
24 24
25 25 #-----------------------------------------------------------------------------
26 26 # Imports
27 27 #-----------------------------------------------------------------------------
28 28
29 29 import os
30 30 import re
31 31 import sys
32 32 import tempfile
33 33
34 34 from io import UnsupportedOperation
35 35
36 36 from IPython.core import ipapi
37 37 from IPython.core.error import TryNext
38 38 from IPython.utils.cursesimport import use_curses
39 39 from IPython.utils.data import chop
40 40 from IPython.utils import io
41 41 from IPython.utils.process import system
42 42 from IPython.utils.terminal import get_terminal_size
43 43
44 44
45 45 #-----------------------------------------------------------------------------
46 46 # Classes and functions
47 47 #-----------------------------------------------------------------------------
48 48
49 49 esc_re = re.compile(r"(\x1b[^m]+m)")
50 50
51 51 def page_dumb(strng, start=0, screen_lines=25):
52 52 """Very dumb 'pager' in Python, for when nothing else works.
53 53
54 54 Only moves forward, same interface as page(), except for pager_cmd and
55 55 mode."""
56 56
57 57 out_ln = strng.splitlines()[start:]
58 58 screens = chop(out_ln,screen_lines-1)
59 59 if len(screens) == 1:
60 60 print >>io.stdout, os.linesep.join(screens[0])
61 61 else:
62 62 last_escape = ""
63 63 for scr in screens[0:-1]:
64 64 hunk = os.linesep.join(scr)
65 65 print >>io.stdout, last_escape + hunk
66 66 if not page_more():
67 67 return
68 68 esc_list = esc_re.findall(hunk)
69 69 if len(esc_list) > 0:
70 70 last_escape = esc_list[-1]
71 71 print >>io.stdout, last_escape + os.linesep.join(screens[-1])
72 72
73 73 def _detect_screen_size(use_curses, screen_lines_def):
74 74 """Attempt to work out the number of lines on the screen.
75 75
76 76 This is called by page(). It can raise an error (e.g. when run in the
77 77 test suite), so it's separated out so it can easily be called in a try block.
78 78 """
79 79 TERM = os.environ.get('TERM',None)
80 80 if (TERM=='xterm' or TERM=='xterm-color') and sys.platform != 'sunos5':
81 81 local_use_curses = use_curses
82 82 else:
83 83 # curses causes problems on many terminals other than xterm, and
84 84 # some termios calls lock up on Sun OS5.
85 85 local_use_curses = False
86 86 if local_use_curses:
87 87 import termios
88 88 import curses
89 89 # There is a bug in curses, where *sometimes* it fails to properly
90 90 # initialize, and then after the endwin() call is made, the
91 91 # terminal is left in an unusable state. Rather than trying to
92 92 # check everytime for this (by requesting and comparing termios
93 93 # flags each time), we just save the initial terminal state and
94 94 # unconditionally reset it every time. It's cheaper than making
95 95 # the checks.
96 96 term_flags = termios.tcgetattr(sys.stdout)
97 97
98 98 # Curses modifies the stdout buffer size by default, which messes
99 99 # up Python's normal stdout buffering. This would manifest itself
100 100 # to IPython users as delayed printing on stdout after having used
101 101 # the pager.
102 102 #
103 103 # We can prevent this by manually setting the NCURSES_NO_SETBUF
104 104 # environment variable. For more details, see:
105 105 # http://bugs.python.org/issue10144
106 106 NCURSES_NO_SETBUF = os.environ.get('NCURSES_NO_SETBUF', None)
107 107 os.environ['NCURSES_NO_SETBUF'] = ''
108 108
109 109 # Proceed with curses initialization
110 110 scr = curses.initscr()
111 111 screen_lines_real,screen_cols = scr.getmaxyx()
112 112 curses.endwin()
113 113
114 114 # Restore environment
115 115 if NCURSES_NO_SETBUF is None:
116 116 del os.environ['NCURSES_NO_SETBUF']
117 117 else:
118 118 os.environ['NCURSES_NO_SETBUF'] = NCURSES_NO_SETBUF
119 119
120 120 # Restore terminal state in case endwin() didn't.
121 121 termios.tcsetattr(sys.stdout,termios.TCSANOW,term_flags)
122 122 # Now we have what we needed: the screen size in rows/columns
123 123 return screen_lines_real
124 124 #print '***Screen size:',screen_lines_real,'lines x',\
125 125 #screen_cols,'columns.' # dbg
126 126 else:
127 127 return screen_lines_def
128 128
129 129 def page(strng, start=0, screen_lines=0, pager_cmd=None):
130 130 """Print a string, piping through a pager after a certain length.
131 131
132 132 The screen_lines parameter specifies the number of *usable* lines of your
133 133 terminal screen (total lines minus lines you need to reserve to show other
134 134 information).
135 135
136 136 If you set screen_lines to a number <=0, page() will try to auto-determine
137 137 your screen size and will only use up to (screen_size+screen_lines) for
138 138 printing, paging after that. That is, if you want auto-detection but need
139 139 to reserve the bottom 3 lines of the screen, use screen_lines = -3, and for
140 140 auto-detection without any lines reserved simply use screen_lines = 0.
141 141
142 142 If a string won't fit in the allowed lines, it is sent through the
143 143 specified pager command. If none given, look for PAGER in the environment,
144 144 and ultimately default to less.
145 145
146 146 If no system pager works, the string is sent through a 'dumb pager'
147 147 written in python, very simplistic.
148 148 """
149 149
150 150 # Some routines may auto-compute start offsets incorrectly and pass a
151 151 # negative value. Offset to 0 for robustness.
152 152 start = max(0, start)
153 153
154 154 # first, try the hook
155 155 ip = ipapi.get()
156 156 if ip:
157 157 try:
158 158 ip.hooks.show_in_pager(strng)
159 159 return
160 160 except TryNext:
161 161 pass
162 162
163 163 # Ugly kludge, but calling curses.initscr() flat out crashes in emacs
164 164 TERM = os.environ.get('TERM','dumb')
165 165 if TERM in ['dumb','emacs'] and os.name != 'nt':
166 166 print strng
167 167 return
168 168 # chop off the topmost part of the string we don't want to see
169 169 str_lines = strng.splitlines()[start:]
170 170 str_toprint = os.linesep.join(str_lines)
171 171 num_newlines = len(str_lines)
172 172 len_str = len(str_toprint)
173 173
174 174 # Dumb heuristics to guesstimate number of on-screen lines the string
175 175 # takes. Very basic, but good enough for docstrings in reasonable
176 176 # terminals. If someone later feels like refining it, it's not hard.
177 177 numlines = max(num_newlines,int(len_str/80)+1)
178 178
179 179 screen_lines_def = get_terminal_size()[1]
180 180
181 181 # auto-determine screen size
182 182 if screen_lines <= 0:
183 183 try:
184 184 screen_lines += _detect_screen_size(use_curses, screen_lines_def)
185 185 except (TypeError, UnsupportedOperation):
186 186 print >>io.stdout, str_toprint
187 187 return
188 188
189 189 #print 'numlines',numlines,'screenlines',screen_lines # dbg
190 190 if numlines <= screen_lines :
191 191 #print '*** normal print' # dbg
192 192 print >>io.stdout, str_toprint
193 193 else:
194 194 # Try to open pager and default to internal one if that fails.
195 195 # All failure modes are tagged as 'retval=1', to match the return
196 196 # value of a failed system command. If any intermediate attempt
197 197 # sets retval to 1, at the end we resort to our own page_dumb() pager.
198 198 pager_cmd = get_pager_cmd(pager_cmd)
199 199 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
200 200 if os.name == 'nt':
201 201 if pager_cmd.startswith('type'):
202 202 # The default WinXP 'type' command is failing on complex strings.
203 203 retval = 1
204 204 else:
205 205 tmpname = tempfile.mktemp('.txt')
206 206 tmpfile = file(tmpname,'wt')
207 207 tmpfile.write(strng)
208 208 tmpfile.close()
209 209 cmd = "%s < %s" % (pager_cmd,tmpname)
210 210 if os.system(cmd):
211 211 retval = 1
212 212 else:
213 213 retval = None
214 214 os.remove(tmpname)
215 215 else:
216 216 try:
217 217 retval = None
218 218 # if I use popen4, things hang. No idea why.
219 219 #pager,shell_out = os.popen4(pager_cmd)
220 220 pager = os.popen(pager_cmd,'w')
221 221 pager.write(strng)
222 222 pager.close()
223 223 retval = pager.close() # success returns None
224 224 except IOError,msg: # broken pipe when user quits
225 225 if msg.args == (32,'Broken pipe'):
226 226 retval = None
227 227 else:
228 228 retval = 1
229 229 except OSError:
230 230 # Other strange problems, sometimes seen in Win2k/cygwin
231 231 retval = 1
232 232 if retval is not None:
233 233 page_dumb(strng,screen_lines=screen_lines)
234 234
235 235
236 236 def page_file(fname, start=0, pager_cmd=None):
237 237 """Page a file, using an optional pager command and starting line.
238 238 """
239 239
240 240 pager_cmd = get_pager_cmd(pager_cmd)
241 241 pager_cmd += ' ' + get_pager_start(pager_cmd,start)
242 242
243 243 try:
244 244 if os.environ['TERM'] in ['emacs','dumb']:
245 245 raise EnvironmentError
246 246 system(pager_cmd + ' ' + fname)
247 247 except:
248 248 try:
249 249 if start > 0:
250 250 start -= 1
251 251 page(open(fname).read(),start)
252 252 except:
253 253 print 'Unable to show file',`fname`
254 254
255 255
256 256 def get_pager_cmd(pager_cmd=None):
257 257 """Return a pager command.
258 258
259 259 Makes some attempts at finding an OS-correct one.
260 260 """
261 261 if os.name == 'posix':
262 262 default_pager_cmd = 'less -r' # -r for color control sequences
263 263 elif os.name in ['nt','dos']:
264 264 default_pager_cmd = 'type'
265 265
266 266 if pager_cmd is None:
267 267 try:
268 268 pager_cmd = os.environ['PAGER']
269 269 except:
270 270 pager_cmd = default_pager_cmd
271 271 return pager_cmd
272 272
273 273
274 274 def get_pager_start(pager, start):
275 275 """Return the string for paging files with an offset.
276 276
277 277 This is the '+N' argument which less and more (under Unix) accept.
278 278 """
279 279
280 280 if pager in ['less','more']:
281 281 if start:
282 282 start_string = '+' + str(start)
283 283 else:
284 284 start_string = ''
285 285 else:
286 286 start_string = ''
287 287 return start_string
288 288
289 289
290 290 # (X)emacs on win32 doesn't like to be bypassed with msvcrt.getch()
291 291 if os.name == 'nt' and os.environ.get('TERM','dumb') != 'emacs':
292 292 import msvcrt
293 293 def page_more():
294 294 """ Smart pausing between pages
295 295
296 296 @return: True if need print more lines, False if quit
297 297 """
298 298 io.stdout.write('---Return to continue, q to quit--- ')
299 299 ans = msvcrt.getch()
300 300 if ans in ("q", "Q"):
301 301 result = False
302 302 else:
303 303 result = True
304 304 io.stdout.write("\b"*37 + " "*37 + "\b"*37)
305 305 return result
306 306 else:
307 307 def page_more():
308 308 ans = raw_input('---Return to continue, q to quit--- ')
309 309 if ans.lower().startswith('q'):
310 310 return False
311 311 else:
312 312 return True
313 313
314 314
315 315 def snip_print(str,width = 75,print_full = 0,header = ''):
316 316 """Print a string snipping the midsection to fit in width.
317 317
318 318 print_full: mode control:
319 319 - 0: only snip long strings
320 320 - 1: send to page() directly.
321 321 - 2: snip long strings and ask for full length viewing with page()
322 322 Return 1 if snipping was necessary, 0 otherwise."""
323 323
324 324 if print_full == 1:
325 325 page(header+str)
326 326 return 0
327 327
328 328 print header,
329 329 if len(str) < width:
330 330 print str
331 331 snip = 0
332 332 else:
333 333 whalf = int((width -5)/2)
334 334 print str[:whalf] + ' <...> ' + str[-whalf:]
335 335 snip = 1
336 336 if snip and print_full == 2:
337 337 if raw_input(header+' Snipped. View (y/n)? [N]').lower() == 'y':
338 338 page(str)
339 339 return snip
340 340
@@ -1,41 +1,41 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Payload system for IPython.
3 3
4 4 Authors:
5 5
6 6 * Fernando Perez
7 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 13 # Distributed under the terms of the BSD License. The full license is in
14 14 # the file COPYING, distributed as part of this software.
15 15 #-----------------------------------------------------------------------------
16 16
17 17 #-----------------------------------------------------------------------------
18 18 # Imports
19 19 #-----------------------------------------------------------------------------
20 20
21 21 from IPython.config.configurable import Configurable
22 22 from IPython.utils.traitlets import List
23 23
24 24 #-----------------------------------------------------------------------------
25 25 # Main payload class
26 26 #-----------------------------------------------------------------------------
27 27
28 28 class PayloadManager(Configurable):
29 29
30 30 _payload = List([])
31 31
32 32 def write_payload(self, data):
33 33 if not isinstance(data, dict):
34 34 raise TypeError('Each payload write must be a dict, got: %r' % data)
35 35 self._payload.append(data)
36 36
37 37 def read_payload(self):
38 38 return self._payload
39 39
40 40 def clear_payload(self):
41 41 self._payload = []
@@ -1,96 +1,96 b''
1 1 # encoding: utf-8
2 2 """
3 3 A payload based version of page.
4 4
5 5 Authors:
6 6
7 7 * Brian Granger
8 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 14 # Distributed under the terms of the BSD License. The full license is in
15 15 # the file COPYING, distributed as part of this software.
16 16 #-----------------------------------------------------------------------------
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Imports
20 20 #-----------------------------------------------------------------------------
21 21
22 22 # Third-party
23 23 try:
24 24 from docutils.core import publish_string
25 25 except ImportError:
26 26 # html paging won't be available, but we don't raise any errors. It's a
27 27 # purely optional feature.
28 28 pass
29 29
30 30 # Our own
31 31 from IPython.core.interactiveshell import InteractiveShell
32 32
33 33 #-----------------------------------------------------------------------------
34 34 # Classes and functions
35 35 #-----------------------------------------------------------------------------
36 36
37 37 def page(strng, start=0, screen_lines=0, pager_cmd=None,
38 38 html=None, auto_html=False):
39 39 """Print a string, piping through a pager.
40 40
41 41 This version ignores the screen_lines and pager_cmd arguments and uses
42 42 IPython's payload system instead.
43 43
44 44 Parameters
45 45 ----------
46 46 strng : str
47 47 Text to page.
48 48
49 49 start : int
50 50 Starting line at which to place the display.
51 51
52 52 html : str, optional
53 53 If given, an html string to send as well.
54 54
55 55 auto_html : bool, optional
56 56 If true, the input string is assumed to be valid reStructuredText and is
57 57 converted to HTML with docutils. Note that if docutils is not found,
58 58 this option is silently ignored.
59 59
60 60 Note
61 61 ----
62 62
63 63 Only one of the ``html`` and ``auto_html`` options can be given, not
64 64 both.
65 65 """
66 66
67 67 # Some routines may auto-compute start offsets incorrectly and pass a
68 68 # negative value. Offset to 0 for robustness.
69 69 start = max(0, start)
70 70 shell = InteractiveShell.instance()
71 71
72 72 if auto_html:
73 73 try:
74 74 # These defaults ensure user configuration variables for docutils
75 75 # are not loaded, only our config is used here.
76 76 defaults = {'file_insertion_enabled': 0,
77 77 'raw_enabled': 0,
78 78 '_disable_config': 1}
79 79 html = publish_string(strng, writer_name='html',
80 80 settings_overrides=defaults)
81 81 except:
82 82 pass
83 83
84 84 payload = dict(
85 85 source='IPython.zmq.page.page',
86 86 text=strng,
87 87 html=html,
88 88 start_line_number=start
89 89 )
90 90 shell.payload_manager.write_payload(payload)
91 91
92 92
93 93 def install_payload_page():
94 94 """Install this version of page as IPython.core.page.page."""
95 95 from IPython.core import page as corepage
96 96 corepage.page = page
@@ -1,51 +1,51 b''
1 1 # encoding: utf-8
2 2 """IPython plugins.
3 3
4 4 Authors:
5 5
6 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 12 # Distributed under the terms of the BSD License. The full license is in
13 13 # the file COPYING, distributed as part of this software.
14 14 #-----------------------------------------------------------------------------
15 15
16 16 #-----------------------------------------------------------------------------
17 17 # Imports
18 18 #-----------------------------------------------------------------------------
19 19
20 20 from IPython.config.configurable import Configurable
21 21 from IPython.utils.traitlets import Dict
22 22
23 23 #-----------------------------------------------------------------------------
24 24 # Main class
25 25 #-----------------------------------------------------------------------------
26 26
27 27 class PluginManager(Configurable):
28 28 """A manager for IPython plugins."""
29 29
30 30 plugins = Dict({})
31 31
32 32 def __init__(self, config=None):
33 33 super(PluginManager, self).__init__(config=config)
34 34
35 35 def register_plugin(self, name, plugin):
36 36 if not isinstance(plugin, Plugin):
37 37 raise TypeError('Expected Plugin, got: %r' % plugin)
38 38 if self.plugins.has_key(name):
39 39 raise KeyError('Plugin with name already exists: %r' % name)
40 40 self.plugins[name] = plugin
41 41
42 42 def unregister_plugin(self, name):
43 43 del self.plugins[name]
44 44
45 45 def get_plugin(self, name, default=None):
46 46 return self.plugins.get(name, default)
47 47
48 48
49 49 class Plugin(Configurable):
50 50 """Base class for IPython plugins."""
51 51 pass
@@ -1,946 +1,946 b''
1 1 # encoding: utf-8
2 2 """
3 3 Prefiltering components.
4 4
5 5 Prefilters transform user input before it is exec'd by Python. These
6 6 transforms are used to implement additional syntax such as !ls and %magic.
7 7
8 8 Authors:
9 9
10 10 * Brian Granger
11 11 * Fernando Perez
12 12 * Dan Milstein
13 13 * Ville Vainio
14 14 """
15 15
16 16 #-----------------------------------------------------------------------------
17 # Copyright (C) 2008-2009 The IPython Development Team
17 # Copyright (C) 2008-2011 The IPython Development Team
18 18 #
19 19 # Distributed under the terms of the BSD License. The full license is in
20 20 # the file COPYING, distributed as part of this software.
21 21 #-----------------------------------------------------------------------------
22 22
23 23 #-----------------------------------------------------------------------------
24 24 # Imports
25 25 #-----------------------------------------------------------------------------
26 26
27 27 import __builtin__
28 28 import codeop
29 29 import re
30 30
31 31 from IPython.core.alias import AliasManager
32 32 from IPython.core.autocall import IPyAutocall
33 33 from IPython.config.configurable import Configurable
34 34 from IPython.core.macro import Macro
35 35 from IPython.core.splitinput import split_user_input, LineInfo
36 36 from IPython.core import page
37 37
38 38 from IPython.utils.traitlets import List, Integer, Any, Unicode, CBool, Bool, Instance
39 39 from IPython.utils.autoattr import auto_attr
40 40
41 41 #-----------------------------------------------------------------------------
42 42 # Global utilities, errors and constants
43 43 #-----------------------------------------------------------------------------
44 44
45 45 # Warning, these cannot be changed unless various regular expressions
46 46 # are updated in a number of places. Not great, but at least we told you.
47 47 ESC_SHELL = '!'
48 48 ESC_SH_CAP = '!!'
49 49 ESC_HELP = '?'
50 50 ESC_MAGIC = '%'
51 51 ESC_QUOTE = ','
52 52 ESC_QUOTE2 = ';'
53 53 ESC_PAREN = '/'
54 54
55 55
56 56 class PrefilterError(Exception):
57 57 pass
58 58
59 59
60 60 # RegExp to identify potential function names
61 61 re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$')
62 62
63 63 # RegExp to exclude strings with this start from autocalling. In
64 64 # particular, all binary operators should be excluded, so that if foo is
65 65 # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
66 66 # characters '!=()' don't need to be checked for, as the checkPythonChars
67 67 # routine explicitely does so, to catch direct calls and rebindings of
68 68 # existing names.
69 69
70 70 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
71 71 # it affects the rest of the group in square brackets.
72 72 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
73 73 r'|^is |^not |^in |^and |^or ')
74 74
75 75 # try to catch also methods for stuff in lists/tuples/dicts: off
76 76 # (experimental). For this to work, the line_split regexp would need
77 77 # to be modified so it wouldn't break things at '['. That line is
78 78 # nasty enough that I shouldn't change it until I can test it _well_.
79 79 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
80 80
81 81
82 82 # Handler Check Utilities
83 83 def is_shadowed(identifier, ip):
84 84 """Is the given identifier defined in one of the namespaces which shadow
85 85 the alias and magic namespaces? Note that an identifier is different
86 86 than ifun, because it can not contain a '.' character."""
87 87 # This is much safer than calling ofind, which can change state
88 88 return (identifier in ip.user_ns \
89 89 or identifier in ip.internal_ns \
90 90 or identifier in ip.ns_table['builtin'])
91 91
92 92
93 93 #-----------------------------------------------------------------------------
94 94 # Main Prefilter manager
95 95 #-----------------------------------------------------------------------------
96 96
97 97
98 98 class PrefilterManager(Configurable):
99 99 """Main prefilter component.
100 100
101 101 The IPython prefilter is run on all user input before it is run. The
102 102 prefilter consumes lines of input and produces transformed lines of
103 103 input.
104 104
105 105 The iplementation consists of two phases:
106 106
107 107 1. Transformers
108 108 2. Checkers and handlers
109 109
110 110 Over time, we plan on deprecating the checkers and handlers and doing
111 111 everything in the transformers.
112 112
113 113 The transformers are instances of :class:`PrefilterTransformer` and have
114 114 a single method :meth:`transform` that takes a line and returns a
115 115 transformed line. The transformation can be accomplished using any
116 116 tool, but our current ones use regular expressions for speed. We also
117 117 ship :mod:`pyparsing` in :mod:`IPython.external` for use in transformers.
118 118
119 119 After all the transformers have been run, the line is fed to the checkers,
120 120 which are instances of :class:`PrefilterChecker`. The line is passed to
121 121 the :meth:`check` method, which either returns `None` or a
122 122 :class:`PrefilterHandler` instance. If `None` is returned, the other
123 123 checkers are tried. If an :class:`PrefilterHandler` instance is returned,
124 124 the line is passed to the :meth:`handle` method of the returned
125 125 handler and no further checkers are tried.
126 126
127 127 Both transformers and checkers have a `priority` attribute, that determines
128 128 the order in which they are called. Smaller priorities are tried first.
129 129
130 130 Both transformers and checkers also have `enabled` attribute, which is
131 131 a boolean that determines if the instance is used.
132 132
133 133 Users or developers can change the priority or enabled attribute of
134 134 transformers or checkers, but they must call the :meth:`sort_checkers`
135 135 or :meth:`sort_transformers` method after changing the priority.
136 136 """
137 137
138 138 multi_line_specials = CBool(True, config=True)
139 139 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
140 140
141 141 def __init__(self, shell=None, config=None):
142 142 super(PrefilterManager, self).__init__(shell=shell, config=config)
143 143 self.shell = shell
144 144 self.init_transformers()
145 145 self.init_handlers()
146 146 self.init_checkers()
147 147
148 148 #-------------------------------------------------------------------------
149 149 # API for managing transformers
150 150 #-------------------------------------------------------------------------
151 151
152 152 def init_transformers(self):
153 153 """Create the default transformers."""
154 154 self._transformers = []
155 155 for transformer_cls in _default_transformers:
156 156 transformer_cls(
157 157 shell=self.shell, prefilter_manager=self, config=self.config
158 158 )
159 159
160 160 def sort_transformers(self):
161 161 """Sort the transformers by priority.
162 162
163 163 This must be called after the priority of a transformer is changed.
164 164 The :meth:`register_transformer` method calls this automatically.
165 165 """
166 166 self._transformers.sort(key=lambda x: x.priority)
167 167
168 168 @property
169 169 def transformers(self):
170 170 """Return a list of checkers, sorted by priority."""
171 171 return self._transformers
172 172
173 173 def register_transformer(self, transformer):
174 174 """Register a transformer instance."""
175 175 if transformer not in self._transformers:
176 176 self._transformers.append(transformer)
177 177 self.sort_transformers()
178 178
179 179 def unregister_transformer(self, transformer):
180 180 """Unregister a transformer instance."""
181 181 if transformer in self._transformers:
182 182 self._transformers.remove(transformer)
183 183
184 184 #-------------------------------------------------------------------------
185 185 # API for managing checkers
186 186 #-------------------------------------------------------------------------
187 187
188 188 def init_checkers(self):
189 189 """Create the default checkers."""
190 190 self._checkers = []
191 191 for checker in _default_checkers:
192 192 checker(
193 193 shell=self.shell, prefilter_manager=self, config=self.config
194 194 )
195 195
196 196 def sort_checkers(self):
197 197 """Sort the checkers by priority.
198 198
199 199 This must be called after the priority of a checker is changed.
200 200 The :meth:`register_checker` method calls this automatically.
201 201 """
202 202 self._checkers.sort(key=lambda x: x.priority)
203 203
204 204 @property
205 205 def checkers(self):
206 206 """Return a list of checkers, sorted by priority."""
207 207 return self._checkers
208 208
209 209 def register_checker(self, checker):
210 210 """Register a checker instance."""
211 211 if checker not in self._checkers:
212 212 self._checkers.append(checker)
213 213 self.sort_checkers()
214 214
215 215 def unregister_checker(self, checker):
216 216 """Unregister a checker instance."""
217 217 if checker in self._checkers:
218 218 self._checkers.remove(checker)
219 219
220 220 #-------------------------------------------------------------------------
221 221 # API for managing checkers
222 222 #-------------------------------------------------------------------------
223 223
224 224 def init_handlers(self):
225 225 """Create the default handlers."""
226 226 self._handlers = {}
227 227 self._esc_handlers = {}
228 228 for handler in _default_handlers:
229 229 handler(
230 230 shell=self.shell, prefilter_manager=self, config=self.config
231 231 )
232 232
233 233 @property
234 234 def handlers(self):
235 235 """Return a dict of all the handlers."""
236 236 return self._handlers
237 237
238 238 def register_handler(self, name, handler, esc_strings):
239 239 """Register a handler instance by name with esc_strings."""
240 240 self._handlers[name] = handler
241 241 for esc_str in esc_strings:
242 242 self._esc_handlers[esc_str] = handler
243 243
244 244 def unregister_handler(self, name, handler, esc_strings):
245 245 """Unregister a handler instance by name with esc_strings."""
246 246 try:
247 247 del self._handlers[name]
248 248 except KeyError:
249 249 pass
250 250 for esc_str in esc_strings:
251 251 h = self._esc_handlers.get(esc_str)
252 252 if h is handler:
253 253 del self._esc_handlers[esc_str]
254 254
255 255 def get_handler_by_name(self, name):
256 256 """Get a handler by its name."""
257 257 return self._handlers.get(name)
258 258
259 259 def get_handler_by_esc(self, esc_str):
260 260 """Get a handler by its escape string."""
261 261 return self._esc_handlers.get(esc_str)
262 262
263 263 #-------------------------------------------------------------------------
264 264 # Main prefiltering API
265 265 #-------------------------------------------------------------------------
266 266
267 267 def prefilter_line_info(self, line_info):
268 268 """Prefilter a line that has been converted to a LineInfo object.
269 269
270 270 This implements the checker/handler part of the prefilter pipe.
271 271 """
272 272 # print "prefilter_line_info: ", line_info
273 273 handler = self.find_handler(line_info)
274 274 return handler.handle(line_info)
275 275
276 276 def find_handler(self, line_info):
277 277 """Find a handler for the line_info by trying checkers."""
278 278 for checker in self.checkers:
279 279 if checker.enabled:
280 280 handler = checker.check(line_info)
281 281 if handler:
282 282 return handler
283 283 return self.get_handler_by_name('normal')
284 284
285 285 def transform_line(self, line, continue_prompt):
286 286 """Calls the enabled transformers in order of increasing priority."""
287 287 for transformer in self.transformers:
288 288 if transformer.enabled:
289 289 line = transformer.transform(line, continue_prompt)
290 290 return line
291 291
292 292 def prefilter_line(self, line, continue_prompt=False):
293 293 """Prefilter a single input line as text.
294 294
295 295 This method prefilters a single line of text by calling the
296 296 transformers and then the checkers/handlers.
297 297 """
298 298
299 299 # print "prefilter_line: ", line, continue_prompt
300 300 # All handlers *must* return a value, even if it's blank ('').
301 301
302 302 # save the line away in case we crash, so the post-mortem handler can
303 303 # record it
304 304 self.shell._last_input_line = line
305 305
306 306 if not line:
307 307 # Return immediately on purely empty lines, so that if the user
308 308 # previously typed some whitespace that started a continuation
309 309 # prompt, he can break out of that loop with just an empty line.
310 310 # This is how the default python prompt works.
311 311 return ''
312 312
313 313 # At this point, we invoke our transformers.
314 314 if not continue_prompt or (continue_prompt and self.multi_line_specials):
315 315 line = self.transform_line(line, continue_prompt)
316 316
317 317 # Now we compute line_info for the checkers and handlers
318 318 line_info = LineInfo(line, continue_prompt)
319 319
320 320 # the input history needs to track even empty lines
321 321 stripped = line.strip()
322 322
323 323 normal_handler = self.get_handler_by_name('normal')
324 324 if not stripped:
325 325 if not continue_prompt:
326 326 self.shell.displayhook.prompt_count -= 1
327 327
328 328 return normal_handler.handle(line_info)
329 329
330 330 # special handlers are only allowed for single line statements
331 331 if continue_prompt and not self.multi_line_specials:
332 332 return normal_handler.handle(line_info)
333 333
334 334 prefiltered = self.prefilter_line_info(line_info)
335 335 # print "prefiltered line: %r" % prefiltered
336 336 return prefiltered
337 337
338 338 def prefilter_lines(self, lines, continue_prompt=False):
339 339 """Prefilter multiple input lines of text.
340 340
341 341 This is the main entry point for prefiltering multiple lines of
342 342 input. This simply calls :meth:`prefilter_line` for each line of
343 343 input.
344 344
345 345 This covers cases where there are multiple lines in the user entry,
346 346 which is the case when the user goes back to a multiline history
347 347 entry and presses enter.
348 348 """
349 349 llines = lines.rstrip('\n').split('\n')
350 350 # We can get multiple lines in one shot, where multiline input 'blends'
351 351 # into one line, in cases like recalling from the readline history
352 352 # buffer. We need to make sure that in such cases, we correctly
353 353 # communicate downstream which line is first and which are continuation
354 354 # ones.
355 355 if len(llines) > 1:
356 356 out = '\n'.join([self.prefilter_line(line, lnum>0)
357 357 for lnum, line in enumerate(llines) ])
358 358 else:
359 359 out = self.prefilter_line(llines[0], continue_prompt)
360 360
361 361 return out
362 362
363 363 #-----------------------------------------------------------------------------
364 364 # Prefilter transformers
365 365 #-----------------------------------------------------------------------------
366 366
367 367
368 368 class PrefilterTransformer(Configurable):
369 369 """Transform a line of user input."""
370 370
371 371 priority = Integer(100, config=True)
372 372 # Transformers don't currently use shell or prefilter_manager, but as we
373 373 # move away from checkers and handlers, they will need them.
374 374 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
375 375 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
376 376 enabled = Bool(True, config=True)
377 377
378 378 def __init__(self, shell=None, prefilter_manager=None, config=None):
379 379 super(PrefilterTransformer, self).__init__(
380 380 shell=shell, prefilter_manager=prefilter_manager, config=config
381 381 )
382 382 self.prefilter_manager.register_transformer(self)
383 383
384 384 def transform(self, line, continue_prompt):
385 385 """Transform a line, returning the new one."""
386 386 return None
387 387
388 388 def __repr__(self):
389 389 return "<%s(priority=%r, enabled=%r)>" % (
390 390 self.__class__.__name__, self.priority, self.enabled)
391 391
392 392
393 393 _assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
394 394 r'\s*=\s*!(?P<cmd>.*)')
395 395
396 396
397 397 class AssignSystemTransformer(PrefilterTransformer):
398 398 """Handle the `files = !ls` syntax."""
399 399
400 400 priority = Integer(100, config=True)
401 401
402 402 def transform(self, line, continue_prompt):
403 403 m = _assign_system_re.match(line)
404 404 if m is not None:
405 405 cmd = m.group('cmd')
406 406 lhs = m.group('lhs')
407 407 expr = "sc =%s" % cmd
408 408 new_line = '%s = get_ipython().magic(%r)' % (lhs, expr)
409 409 return new_line
410 410 return line
411 411
412 412
413 413 _assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
414 414 r'\s*=\s*%(?P<cmd>.*)')
415 415
416 416 class AssignMagicTransformer(PrefilterTransformer):
417 417 """Handle the `a = %who` syntax."""
418 418
419 419 priority = Integer(200, config=True)
420 420
421 421 def transform(self, line, continue_prompt):
422 422 m = _assign_magic_re.match(line)
423 423 if m is not None:
424 424 cmd = m.group('cmd')
425 425 lhs = m.group('lhs')
426 426 new_line = '%s = get_ipython().magic(%r)' % (lhs, cmd)
427 427 return new_line
428 428 return line
429 429
430 430
431 431 _classic_prompt_re = re.compile(r'(^[ \t]*>>> |^[ \t]*\.\.\. )')
432 432
433 433 class PyPromptTransformer(PrefilterTransformer):
434 434 """Handle inputs that start with '>>> ' syntax."""
435 435
436 436 priority = Integer(50, config=True)
437 437
438 438 def transform(self, line, continue_prompt):
439 439
440 440 if not line or line.isspace() or line.strip() == '...':
441 441 # This allows us to recognize multiple input prompts separated by
442 442 # blank lines and pasted in a single chunk, very common when
443 443 # pasting doctests or long tutorial passages.
444 444 return ''
445 445 m = _classic_prompt_re.match(line)
446 446 if m:
447 447 return line[len(m.group(0)):]
448 448 else:
449 449 return line
450 450
451 451
452 452 _ipy_prompt_re = re.compile(r'(^[ \t]*In \[\d+\]: |^[ \t]*\ \ \ \.\.\.+: )')
453 453
454 454 class IPyPromptTransformer(PrefilterTransformer):
455 455 """Handle inputs that start classic IPython prompt syntax."""
456 456
457 457 priority = Integer(50, config=True)
458 458
459 459 def transform(self, line, continue_prompt):
460 460
461 461 if not line or line.isspace() or line.strip() == '...':
462 462 # This allows us to recognize multiple input prompts separated by
463 463 # blank lines and pasted in a single chunk, very common when
464 464 # pasting doctests or long tutorial passages.
465 465 return ''
466 466 m = _ipy_prompt_re.match(line)
467 467 if m:
468 468 return line[len(m.group(0)):]
469 469 else:
470 470 return line
471 471
472 472 #-----------------------------------------------------------------------------
473 473 # Prefilter checkers
474 474 #-----------------------------------------------------------------------------
475 475
476 476
477 477 class PrefilterChecker(Configurable):
478 478 """Inspect an input line and return a handler for that line."""
479 479
480 480 priority = Integer(100, config=True)
481 481 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
482 482 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
483 483 enabled = Bool(True, config=True)
484 484
485 485 def __init__(self, shell=None, prefilter_manager=None, config=None):
486 486 super(PrefilterChecker, self).__init__(
487 487 shell=shell, prefilter_manager=prefilter_manager, config=config
488 488 )
489 489 self.prefilter_manager.register_checker(self)
490 490
491 491 def check(self, line_info):
492 492 """Inspect line_info and return a handler instance or None."""
493 493 return None
494 494
495 495 def __repr__(self):
496 496 return "<%s(priority=%r, enabled=%r)>" % (
497 497 self.__class__.__name__, self.priority, self.enabled)
498 498
499 499
500 500 class EmacsChecker(PrefilterChecker):
501 501
502 502 priority = Integer(100, config=True)
503 503 enabled = Bool(False, config=True)
504 504
505 505 def check(self, line_info):
506 506 "Emacs ipython-mode tags certain input lines."
507 507 if line_info.line.endswith('# PYTHON-MODE'):
508 508 return self.prefilter_manager.get_handler_by_name('emacs')
509 509 else:
510 510 return None
511 511
512 512
513 513 class ShellEscapeChecker(PrefilterChecker):
514 514
515 515 priority = Integer(200, config=True)
516 516
517 517 def check(self, line_info):
518 518 if line_info.line.lstrip().startswith(ESC_SHELL):
519 519 return self.prefilter_manager.get_handler_by_name('shell')
520 520
521 521
522 522 class MacroChecker(PrefilterChecker):
523 523
524 524 priority = Integer(250, config=True)
525 525
526 526 def check(self, line_info):
527 527 obj = self.shell.user_ns.get(line_info.ifun)
528 528 if isinstance(obj, Macro):
529 529 return self.prefilter_manager.get_handler_by_name('macro')
530 530 else:
531 531 return None
532 532
533 533
534 534 class IPyAutocallChecker(PrefilterChecker):
535 535
536 536 priority = Integer(300, config=True)
537 537
538 538 def check(self, line_info):
539 539 "Instances of IPyAutocall in user_ns get autocalled immediately"
540 540 obj = self.shell.user_ns.get(line_info.ifun, None)
541 541 if isinstance(obj, IPyAutocall):
542 542 obj.set_ip(self.shell)
543 543 return self.prefilter_manager.get_handler_by_name('auto')
544 544 else:
545 545 return None
546 546
547 547
548 548 class MultiLineMagicChecker(PrefilterChecker):
549 549
550 550 priority = Integer(400, config=True)
551 551
552 552 def check(self, line_info):
553 553 "Allow ! and !! in multi-line statements if multi_line_specials is on"
554 554 # Note that this one of the only places we check the first character of
555 555 # ifun and *not* the pre_char. Also note that the below test matches
556 556 # both ! and !!.
557 557 if line_info.continue_prompt \
558 558 and self.prefilter_manager.multi_line_specials:
559 559 if line_info.esc == ESC_MAGIC:
560 560 return self.prefilter_manager.get_handler_by_name('magic')
561 561 else:
562 562 return None
563 563
564 564
565 565 class EscCharsChecker(PrefilterChecker):
566 566
567 567 priority = Integer(500, config=True)
568 568
569 569 def check(self, line_info):
570 570 """Check for escape character and return either a handler to handle it,
571 571 or None if there is no escape char."""
572 572 if line_info.line[-1] == ESC_HELP \
573 573 and line_info.esc != ESC_SHELL \
574 574 and line_info.esc != ESC_SH_CAP:
575 575 # the ? can be at the end, but *not* for either kind of shell escape,
576 576 # because a ? can be a vaild final char in a shell cmd
577 577 return self.prefilter_manager.get_handler_by_name('help')
578 578 else:
579 579 if line_info.pre:
580 580 return None
581 581 # This returns None like it should if no handler exists
582 582 return self.prefilter_manager.get_handler_by_esc(line_info.esc)
583 583
584 584
585 585 class AssignmentChecker(PrefilterChecker):
586 586
587 587 priority = Integer(600, config=True)
588 588
589 589 def check(self, line_info):
590 590 """Check to see if user is assigning to a var for the first time, in
591 591 which case we want to avoid any sort of automagic / autocall games.
592 592
593 593 This allows users to assign to either alias or magic names true python
594 594 variables (the magic/alias systems always take second seat to true
595 595 python code). E.g. ls='hi', or ls,that=1,2"""
596 596 if line_info.the_rest:
597 597 if line_info.the_rest[0] in '=,':
598 598 return self.prefilter_manager.get_handler_by_name('normal')
599 599 else:
600 600 return None
601 601
602 602
603 603 class AutoMagicChecker(PrefilterChecker):
604 604
605 605 priority = Integer(700, config=True)
606 606
607 607 def check(self, line_info):
608 608 """If the ifun is magic, and automagic is on, run it. Note: normal,
609 609 non-auto magic would already have been triggered via '%' in
610 610 check_esc_chars. This just checks for automagic. Also, before
611 611 triggering the magic handler, make sure that there is nothing in the
612 612 user namespace which could shadow it."""
613 613 if not self.shell.automagic or not hasattr(self.shell,'magic_'+line_info.ifun):
614 614 return None
615 615
616 616 # We have a likely magic method. Make sure we should actually call it.
617 617 if line_info.continue_prompt and not self.prefilter_manager.multi_line_specials:
618 618 return None
619 619
620 620 head = line_info.ifun.split('.',1)[0]
621 621 if is_shadowed(head, self.shell):
622 622 return None
623 623
624 624 return self.prefilter_manager.get_handler_by_name('magic')
625 625
626 626
627 627 class AliasChecker(PrefilterChecker):
628 628
629 629 priority = Integer(800, config=True)
630 630
631 631 def check(self, line_info):
632 632 "Check if the initital identifier on the line is an alias."
633 633 # Note: aliases can not contain '.'
634 634 head = line_info.ifun.split('.',1)[0]
635 635 if line_info.ifun not in self.shell.alias_manager \
636 636 or head not in self.shell.alias_manager \
637 637 or is_shadowed(head, self.shell):
638 638 return None
639 639
640 640 return self.prefilter_manager.get_handler_by_name('alias')
641 641
642 642
643 643 class PythonOpsChecker(PrefilterChecker):
644 644
645 645 priority = Integer(900, config=True)
646 646
647 647 def check(self, line_info):
648 648 """If the 'rest' of the line begins with a function call or pretty much
649 649 any python operator, we should simply execute the line (regardless of
650 650 whether or not there's a possible autocall expansion). This avoids
651 651 spurious (and very confusing) geattr() accesses."""
652 652 if line_info.the_rest and line_info.the_rest[0] in '!=()<>,+*/%^&|':
653 653 return self.prefilter_manager.get_handler_by_name('normal')
654 654 else:
655 655 return None
656 656
657 657
658 658 class AutocallChecker(PrefilterChecker):
659 659
660 660 priority = Integer(1000, config=True)
661 661
662 662 def check(self, line_info):
663 663 "Check if the initial word/function is callable and autocall is on."
664 664 if not self.shell.autocall:
665 665 return None
666 666
667 667 oinfo = line_info.ofind(self.shell) # This can mutate state via getattr
668 668 if not oinfo['found']:
669 669 return None
670 670
671 671 if callable(oinfo['obj']) \
672 672 and (not re_exclude_auto.match(line_info.the_rest)) \
673 673 and re_fun_name.match(line_info.ifun):
674 674 return self.prefilter_manager.get_handler_by_name('auto')
675 675 else:
676 676 return None
677 677
678 678
679 679 #-----------------------------------------------------------------------------
680 680 # Prefilter handlers
681 681 #-----------------------------------------------------------------------------
682 682
683 683
684 684 class PrefilterHandler(Configurable):
685 685
686 686 handler_name = Unicode('normal')
687 687 esc_strings = List([])
688 688 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
689 689 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
690 690
691 691 def __init__(self, shell=None, prefilter_manager=None, config=None):
692 692 super(PrefilterHandler, self).__init__(
693 693 shell=shell, prefilter_manager=prefilter_manager, config=config
694 694 )
695 695 self.prefilter_manager.register_handler(
696 696 self.handler_name,
697 697 self,
698 698 self.esc_strings
699 699 )
700 700
701 701 def handle(self, line_info):
702 702 # print "normal: ", line_info
703 703 """Handle normal input lines. Use as a template for handlers."""
704 704
705 705 # With autoindent on, we need some way to exit the input loop, and I
706 706 # don't want to force the user to have to backspace all the way to
707 707 # clear the line. The rule will be in this case, that either two
708 708 # lines of pure whitespace in a row, or a line of pure whitespace but
709 709 # of a size different to the indent level, will exit the input loop.
710 710 line = line_info.line
711 711 continue_prompt = line_info.continue_prompt
712 712
713 713 if (continue_prompt and
714 714 self.shell.autoindent and
715 715 line.isspace() and
716 716 0 < abs(len(line) - self.shell.indent_current_nsp) <= 2):
717 717 line = ''
718 718
719 719 return line
720 720
721 721 def __str__(self):
722 722 return "<%s(name=%s)>" % (self.__class__.__name__, self.handler_name)
723 723
724 724
725 725 class AliasHandler(PrefilterHandler):
726 726
727 727 handler_name = Unicode('alias')
728 728
729 729 def handle(self, line_info):
730 730 """Handle alias input lines. """
731 731 transformed = self.shell.alias_manager.expand_aliases(line_info.ifun,line_info.the_rest)
732 732 # pre is needed, because it carries the leading whitespace. Otherwise
733 733 # aliases won't work in indented sections.
734 734 line_out = '%sget_ipython().system(%r)' % (line_info.pre_whitespace, transformed)
735 735
736 736 return line_out
737 737
738 738
739 739 class ShellEscapeHandler(PrefilterHandler):
740 740
741 741 handler_name = Unicode('shell')
742 742 esc_strings = List([ESC_SHELL, ESC_SH_CAP])
743 743
744 744 def handle(self, line_info):
745 745 """Execute the line in a shell, empty return value"""
746 746 magic_handler = self.prefilter_manager.get_handler_by_name('magic')
747 747
748 748 line = line_info.line
749 749 if line.lstrip().startswith(ESC_SH_CAP):
750 750 # rewrite LineInfo's line, ifun and the_rest to properly hold the
751 751 # call to %sx and the actual command to be executed, so
752 752 # handle_magic can work correctly. Note that this works even if
753 753 # the line is indented, so it handles multi_line_specials
754 754 # properly.
755 755 new_rest = line.lstrip()[2:]
756 756 line_info.line = '%ssx %s' % (ESC_MAGIC, new_rest)
757 757 line_info.ifun = 'sx'
758 758 line_info.the_rest = new_rest
759 759 return magic_handler.handle(line_info)
760 760 else:
761 761 cmd = line.lstrip().lstrip(ESC_SHELL)
762 762 line_out = '%sget_ipython().system(%r)' % (line_info.pre_whitespace, cmd)
763 763 return line_out
764 764
765 765
766 766 class MacroHandler(PrefilterHandler):
767 767 handler_name = Unicode("macro")
768 768
769 769 def handle(self, line_info):
770 770 obj = self.shell.user_ns.get(line_info.ifun)
771 771 pre_space = line_info.pre_whitespace
772 772 line_sep = "\n" + pre_space
773 773 return pre_space + line_sep.join(obj.value.splitlines())
774 774
775 775
776 776 class MagicHandler(PrefilterHandler):
777 777
778 778 handler_name = Unicode('magic')
779 779 esc_strings = List([ESC_MAGIC])
780 780
781 781 def handle(self, line_info):
782 782 """Execute magic functions."""
783 783 ifun = line_info.ifun
784 784 the_rest = line_info.the_rest
785 785 cmd = '%sget_ipython().magic(%r)' % (line_info.pre_whitespace,
786 786 (ifun + " " + the_rest))
787 787 return cmd
788 788
789 789
790 790 class AutoHandler(PrefilterHandler):
791 791
792 792 handler_name = Unicode('auto')
793 793 esc_strings = List([ESC_PAREN, ESC_QUOTE, ESC_QUOTE2])
794 794
795 795 def handle(self, line_info):
796 796 """Handle lines which can be auto-executed, quoting if requested."""
797 797 line = line_info.line
798 798 ifun = line_info.ifun
799 799 the_rest = line_info.the_rest
800 800 pre = line_info.pre
801 801 esc = line_info.esc
802 802 continue_prompt = line_info.continue_prompt
803 803 obj = line_info.ofind(self)['obj']
804 804 #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun,the_rest) # dbg
805 805
806 806 # This should only be active for single-line input!
807 807 if continue_prompt:
808 808 return line
809 809
810 810 force_auto = isinstance(obj, IPyAutocall)
811 811
812 812 # User objects sometimes raise exceptions on attribute access other
813 813 # than AttributeError (we've seen it in the past), so it's safest to be
814 814 # ultra-conservative here and catch all.
815 815 try:
816 816 auto_rewrite = obj.rewrite
817 817 except Exception:
818 818 auto_rewrite = True
819 819
820 820 if esc == ESC_QUOTE:
821 821 # Auto-quote splitting on whitespace
822 822 newcmd = '%s("%s")' % (ifun,'", "'.join(the_rest.split()) )
823 823 elif esc == ESC_QUOTE2:
824 824 # Auto-quote whole string
825 825 newcmd = '%s("%s")' % (ifun,the_rest)
826 826 elif esc == ESC_PAREN:
827 827 newcmd = '%s(%s)' % (ifun,",".join(the_rest.split()))
828 828 else:
829 829 # Auto-paren.
830 830 # We only apply it to argument-less calls if the autocall
831 831 # parameter is set to 2. We only need to check that autocall is <
832 832 # 2, since this function isn't called unless it's at least 1.
833 833 if not the_rest and (self.shell.autocall < 2) and not force_auto:
834 834 newcmd = '%s %s' % (ifun,the_rest)
835 835 auto_rewrite = False
836 836 else:
837 837 if not force_auto and the_rest.startswith('['):
838 838 if hasattr(obj,'__getitem__'):
839 839 # Don't autocall in this case: item access for an object
840 840 # which is BOTH callable and implements __getitem__.
841 841 newcmd = '%s %s' % (ifun,the_rest)
842 842 auto_rewrite = False
843 843 else:
844 844 # if the object doesn't support [] access, go ahead and
845 845 # autocall
846 846 newcmd = '%s(%s)' % (ifun.rstrip(),the_rest)
847 847 elif the_rest.endswith(';'):
848 848 newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1])
849 849 else:
850 850 newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
851 851
852 852 if auto_rewrite:
853 853 self.shell.auto_rewrite_input(newcmd)
854 854
855 855 return newcmd
856 856
857 857
858 858 class HelpHandler(PrefilterHandler):
859 859
860 860 handler_name = Unicode('help')
861 861 esc_strings = List([ESC_HELP])
862 862
863 863 def handle(self, line_info):
864 864 """Try to get some help for the object.
865 865
866 866 obj? or ?obj -> basic information.
867 867 obj?? or ??obj -> more details.
868 868 """
869 869 normal_handler = self.prefilter_manager.get_handler_by_name('normal')
870 870 line = line_info.line
871 871 # We need to make sure that we don't process lines which would be
872 872 # otherwise valid python, such as "x=1 # what?"
873 873 try:
874 874 codeop.compile_command(line)
875 875 except SyntaxError:
876 876 # We should only handle as help stuff which is NOT valid syntax
877 877 if line[0]==ESC_HELP:
878 878 line = line[1:]
879 879 elif line[-1]==ESC_HELP:
880 880 line = line[:-1]
881 881 if line:
882 882 #print 'line:<%r>' % line # dbg
883 883 self.shell.magic_pinfo(line_info.ifun)
884 884 else:
885 885 self.shell.show_usage()
886 886 return '' # Empty string is needed here!
887 887 except:
888 888 raise
889 889 # Pass any other exceptions through to the normal handler
890 890 return normal_handler.handle(line_info)
891 891 else:
892 892 # If the code compiles ok, we should handle it normally
893 893 return normal_handler.handle(line_info)
894 894
895 895
896 896 class EmacsHandler(PrefilterHandler):
897 897
898 898 handler_name = Unicode('emacs')
899 899 esc_strings = List([])
900 900
901 901 def handle(self, line_info):
902 902 """Handle input lines marked by python-mode."""
903 903
904 904 # Currently, nothing is done. Later more functionality can be added
905 905 # here if needed.
906 906
907 907 # The input cache shouldn't be updated
908 908 return line_info.line
909 909
910 910
911 911 #-----------------------------------------------------------------------------
912 912 # Defaults
913 913 #-----------------------------------------------------------------------------
914 914
915 915
916 916 _default_transformers = [
917 917 AssignSystemTransformer,
918 918 AssignMagicTransformer,
919 919 PyPromptTransformer,
920 920 IPyPromptTransformer,
921 921 ]
922 922
923 923 _default_checkers = [
924 924 EmacsChecker,
925 925 ShellEscapeChecker,
926 926 MacroChecker,
927 927 IPyAutocallChecker,
928 928 MultiLineMagicChecker,
929 929 EscCharsChecker,
930 930 AssignmentChecker,
931 931 AutoMagicChecker,
932 932 AliasChecker,
933 933 PythonOpsChecker,
934 934 AutocallChecker
935 935 ]
936 936
937 937 _default_handlers = [
938 938 PrefilterHandler,
939 939 AliasHandler,
940 940 ShellEscapeHandler,
941 941 MacroHandler,
942 942 MagicHandler,
943 943 AutoHandler,
944 944 HelpHandler,
945 945 EmacsHandler
946 946 ]
@@ -1,436 +1,436 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Classes for handling input/output prompts.
3 3
4 4 Authors:
5 5
6 6 * Fernando Perez
7 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 # Copyright (C) 2001-2007 Fernando Perez <fperez@colorado.edu>
13 13 #
14 14 # Distributed under the terms of the BSD License. The full license is in
15 15 # the file COPYING, distributed as part of this software.
16 16 #-----------------------------------------------------------------------------
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Imports
20 20 #-----------------------------------------------------------------------------
21 21
22 22 import os
23 23 import re
24 24 import socket
25 25 import sys
26 26
27 27 from IPython.core import release
28 28 from IPython.external.Itpl import ItplNS
29 29 from IPython.utils import coloransi
30 30
31 31 #-----------------------------------------------------------------------------
32 32 # Color schemes for prompts
33 33 #-----------------------------------------------------------------------------
34 34
35 35 PromptColors = coloransi.ColorSchemeTable()
36 36 InputColors = coloransi.InputTermColors # just a shorthand
37 37 Colors = coloransi.TermColors # just a shorthand
38 38
39 39 PromptColors.add_scheme(coloransi.ColorScheme(
40 40 'NoColor',
41 41 in_prompt = InputColors.NoColor, # Input prompt
42 42 in_number = InputColors.NoColor, # Input prompt number
43 43 in_prompt2 = InputColors.NoColor, # Continuation prompt
44 44 in_normal = InputColors.NoColor, # color off (usu. Colors.Normal)
45 45
46 46 out_prompt = Colors.NoColor, # Output prompt
47 47 out_number = Colors.NoColor, # Output prompt number
48 48
49 49 normal = Colors.NoColor # color off (usu. Colors.Normal)
50 50 ))
51 51
52 52 # make some schemes as instances so we can copy them for modification easily:
53 53 __PColLinux = coloransi.ColorScheme(
54 54 'Linux',
55 55 in_prompt = InputColors.Green,
56 56 in_number = InputColors.LightGreen,
57 57 in_prompt2 = InputColors.Green,
58 58 in_normal = InputColors.Normal, # color off (usu. Colors.Normal)
59 59
60 60 out_prompt = Colors.Red,
61 61 out_number = Colors.LightRed,
62 62
63 63 normal = Colors.Normal
64 64 )
65 65 # Don't forget to enter it into the table!
66 66 PromptColors.add_scheme(__PColLinux)
67 67
68 68 # Slightly modified Linux for light backgrounds
69 69 __PColLightBG = __PColLinux.copy('LightBG')
70 70
71 71 __PColLightBG.colors.update(
72 72 in_prompt = InputColors.Blue,
73 73 in_number = InputColors.LightBlue,
74 74 in_prompt2 = InputColors.Blue
75 75 )
76 76 PromptColors.add_scheme(__PColLightBG)
77 77
78 78 del Colors,InputColors
79 79
80 80 #-----------------------------------------------------------------------------
81 81 # Utilities
82 82 #-----------------------------------------------------------------------------
83 83
84 84 def multiple_replace(dict, text):
85 85 """ Replace in 'text' all occurences of any key in the given
86 86 dictionary by its corresponding value. Returns the new string."""
87 87
88 88 # Function by Xavier Defrang, originally found at:
89 89 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81330
90 90
91 91 # Create a regular expression from the dictionary keys
92 92 regex = re.compile("(%s)" % "|".join(map(re.escape, dict.keys())))
93 93 # For each match, look-up corresponding value in dictionary
94 94 return regex.sub(lambda mo: dict[mo.string[mo.start():mo.end()]], text)
95 95
96 96 #-----------------------------------------------------------------------------
97 97 # Special characters that can be used in prompt templates, mainly bash-like
98 98 #-----------------------------------------------------------------------------
99 99
100 100 # If $HOME isn't defined (Windows), make it an absurd string so that it can
101 101 # never be expanded out into '~'. Basically anything which can never be a
102 102 # reasonable directory name will do, we just want the $HOME -> '~' operation
103 103 # to become a no-op. We pre-compute $HOME here so it's not done on every
104 104 # prompt call.
105 105
106 106 # FIXME:
107 107
108 108 # - This should be turned into a class which does proper namespace management,
109 109 # since the prompt specials need to be evaluated in a certain namespace.
110 110 # Currently it's just globals, which need to be managed manually by code
111 111 # below.
112 112
113 113 # - I also need to split up the color schemes from the prompt specials
114 114 # somehow. I don't have a clean design for that quite yet.
115 115
116 116 HOME = os.environ.get("HOME","//////:::::ZZZZZ,,,~~~")
117 117
118 118 # We precompute a few more strings here for the prompt_specials, which are
119 119 # fixed once ipython starts. This reduces the runtime overhead of computing
120 120 # prompt strings.
121 121 USER = os.environ.get("USER")
122 122 HOSTNAME = socket.gethostname()
123 123 HOSTNAME_SHORT = HOSTNAME.split(".")[0]
124 124 ROOT_SYMBOL = "$#"[os.name=='nt' or os.getuid()==0]
125 125
126 126 prompt_specials_color = {
127 127 # Prompt/history count
128 128 '%n' : '${self.col_num}' '${self.cache.prompt_count}' '${self.col_p}',
129 129 r'\#': '${self.col_num}' '${self.cache.prompt_count}' '${self.col_p}',
130 130 # Just the prompt counter number, WITHOUT any coloring wrappers, so users
131 131 # can get numbers displayed in whatever color they want.
132 132 r'\N': '${self.cache.prompt_count}',
133 133
134 134 # Prompt/history count, with the actual digits replaced by dots. Used
135 135 # mainly in continuation prompts (prompt_in2)
136 136 #r'\D': '${"."*len(str(self.cache.prompt_count))}',
137 137
138 138 # More robust form of the above expression, that uses the __builtin__
139 139 # module. Note that we can NOT use __builtins__ (note the 's'), because
140 140 # that can either be a dict or a module, and can even mutate at runtime,
141 141 # depending on the context (Python makes no guarantees on it). In
142 142 # contrast, __builtin__ is always a module object, though it must be
143 143 # explicitly imported.
144 144 r'\D': '${"."*__builtin__.len(__builtin__.str(self.cache.prompt_count))}',
145 145
146 146 # Current working directory
147 147 r'\w': '${os.getcwd()}',
148 148 # Current time
149 149 r'\t' : '${time.strftime("%H:%M:%S")}',
150 150 # Basename of current working directory.
151 151 # (use os.sep to make this portable across OSes)
152 152 r'\W' : '${os.getcwd().split("%s")[-1]}' % os.sep,
153 153 # These X<N> are an extension to the normal bash prompts. They return
154 154 # N terms of the path, after replacing $HOME with '~'
155 155 r'\X0': '${os.getcwd().replace("%s","~")}' % HOME,
156 156 r'\X1': '${self.cwd_filt(1)}',
157 157 r'\X2': '${self.cwd_filt(2)}',
158 158 r'\X3': '${self.cwd_filt(3)}',
159 159 r'\X4': '${self.cwd_filt(4)}',
160 160 r'\X5': '${self.cwd_filt(5)}',
161 161 # Y<N> are similar to X<N>, but they show '~' if it's the directory
162 162 # N+1 in the list. Somewhat like %cN in tcsh.
163 163 r'\Y0': '${self.cwd_filt2(0)}',
164 164 r'\Y1': '${self.cwd_filt2(1)}',
165 165 r'\Y2': '${self.cwd_filt2(2)}',
166 166 r'\Y3': '${self.cwd_filt2(3)}',
167 167 r'\Y4': '${self.cwd_filt2(4)}',
168 168 r'\Y5': '${self.cwd_filt2(5)}',
169 169 # Hostname up to first .
170 170 r'\h': HOSTNAME_SHORT,
171 171 # Full hostname
172 172 r'\H': HOSTNAME,
173 173 # Username of current user
174 174 r'\u': USER,
175 175 # Escaped '\'
176 176 '\\\\': '\\',
177 177 # Newline
178 178 r'\n': '\n',
179 179 # Carriage return
180 180 r'\r': '\r',
181 181 # Release version
182 182 r'\v': release.version,
183 183 # Root symbol ($ or #)
184 184 r'\$': ROOT_SYMBOL,
185 185 }
186 186
187 187 # A copy of the prompt_specials dictionary but with all color escapes removed,
188 188 # so we can correctly compute the prompt length for the auto_rewrite method.
189 189 prompt_specials_nocolor = prompt_specials_color.copy()
190 190 prompt_specials_nocolor['%n'] = '${self.cache.prompt_count}'
191 191 prompt_specials_nocolor[r'\#'] = '${self.cache.prompt_count}'
192 192
193 193 # Add in all the InputTermColors color escapes as valid prompt characters.
194 194 # They all get added as \\C_COLORNAME, so that we don't have any conflicts
195 195 # with a color name which may begin with a letter used by any other of the
196 196 # allowed specials. This of course means that \\C will never be allowed for
197 197 # anything else.
198 198 input_colors = coloransi.InputTermColors
199 199 for _color in dir(input_colors):
200 200 if _color[0] != '_':
201 201 c_name = r'\C_'+_color
202 202 prompt_specials_color[c_name] = getattr(input_colors,_color)
203 203 prompt_specials_nocolor[c_name] = ''
204 204
205 205 # we default to no color for safety. Note that prompt_specials is a global
206 206 # variable used by all prompt objects.
207 207 prompt_specials = prompt_specials_nocolor
208 208
209 209 #-----------------------------------------------------------------------------
210 210 # More utilities
211 211 #-----------------------------------------------------------------------------
212 212
213 213 def str_safe(arg):
214 214 """Convert to a string, without ever raising an exception.
215 215
216 216 If str(arg) fails, <ERROR: ... > is returned, where ... is the exception
217 217 error message."""
218 218
219 219 try:
220 220 out = str(arg)
221 221 except UnicodeError:
222 222 try:
223 223 out = arg.encode('utf_8','replace')
224 224 except Exception,msg:
225 225 # let's keep this little duplication here, so that the most common
226 226 # case doesn't suffer from a double try wrapping.
227 227 out = '<ERROR: %s>' % msg
228 228 except Exception,msg:
229 229 out = '<ERROR: %s>' % msg
230 230 #raise # dbg
231 231 return out
232 232
233 233 #-----------------------------------------------------------------------------
234 234 # Prompt classes
235 235 #-----------------------------------------------------------------------------
236 236
237 237 class BasePrompt(object):
238 238 """Interactive prompt similar to Mathematica's."""
239 239
240 240 def _get_p_template(self):
241 241 return self._p_template
242 242
243 243 def _set_p_template(self,val):
244 244 self._p_template = val
245 245 self.set_p_str()
246 246
247 247 p_template = property(_get_p_template,_set_p_template,
248 248 doc='Template for prompt string creation')
249 249
250 250 def __init__(self, cache, sep, prompt, pad_left=False):
251 251
252 252 # Hack: we access information about the primary prompt through the
253 253 # cache argument. We need this, because we want the secondary prompt
254 254 # to be aligned with the primary one. Color table info is also shared
255 255 # by all prompt classes through the cache. Nice OO spaghetti code!
256 256 self.cache = cache
257 257 self.sep = sep
258 258
259 259 # regexp to count the number of spaces at the end of a prompt
260 260 # expression, useful for prompt auto-rewriting
261 261 self.rspace = re.compile(r'(\s*)$')
262 262 # Flag to left-pad prompt strings to match the length of the primary
263 263 # prompt
264 264 self.pad_left = pad_left
265 265
266 266 # Set template to create each actual prompt (where numbers change).
267 267 # Use a property
268 268 self.p_template = prompt
269 269 self.set_p_str()
270 270
271 271 def set_p_str(self):
272 272 """ Set the interpolating prompt strings.
273 273
274 274 This must be called every time the color settings change, because the
275 275 prompt_specials global may have changed."""
276 276
277 277 import os,time # needed in locals for prompt string handling
278 278 loc = locals()
279 279 try:
280 280 self.p_str = ItplNS('%s%s%s' %
281 281 ('${self.sep}${self.col_p}',
282 282 multiple_replace(prompt_specials, self.p_template),
283 283 '${self.col_norm}'),self.cache.shell.user_ns,loc)
284 284
285 285 self.p_str_nocolor = ItplNS(multiple_replace(prompt_specials_nocolor,
286 286 self.p_template),
287 287 self.cache.shell.user_ns,loc)
288 288 except:
289 289 print "Illegal prompt template (check $ usage!):",self.p_template
290 290 self.p_str = self.p_template
291 291 self.p_str_nocolor = self.p_template
292 292
293 293 def write(self, msg):
294 294 sys.stdout.write(msg)
295 295 return ''
296 296
297 297 def __str__(self):
298 298 """Return a string form of the prompt.
299 299
300 300 This for is useful for continuation and output prompts, since it is
301 301 left-padded to match lengths with the primary one (if the
302 302 self.pad_left attribute is set)."""
303 303
304 304 out_str = str_safe(self.p_str)
305 305 if self.pad_left:
306 306 # We must find the amount of padding required to match lengths,
307 307 # taking the color escapes (which are invisible on-screen) into
308 308 # account.
309 309 esc_pad = len(out_str) - len(str_safe(self.p_str_nocolor))
310 310 format = '%%%ss' % (len(str(self.cache.last_prompt))+esc_pad)
311 311 return format % out_str
312 312 else:
313 313 return out_str
314 314
315 315 # these path filters are put in as methods so that we can control the
316 316 # namespace where the prompt strings get evaluated
317 317 def cwd_filt(self, depth):
318 318 """Return the last depth elements of the current working directory.
319 319
320 320 $HOME is always replaced with '~'.
321 321 If depth==0, the full path is returned."""
322 322
323 323 cwd = os.getcwd().replace(HOME,"~")
324 324 out = os.sep.join(cwd.split(os.sep)[-depth:])
325 325 if out:
326 326 return out
327 327 else:
328 328 return os.sep
329 329
330 330 def cwd_filt2(self, depth):
331 331 """Return the last depth elements of the current working directory.
332 332
333 333 $HOME is always replaced with '~'.
334 334 If depth==0, the full path is returned."""
335 335
336 336 full_cwd = os.getcwd()
337 337 cwd = full_cwd.replace(HOME,"~").split(os.sep)
338 338 if '~' in cwd and len(cwd) == depth+1:
339 339 depth += 1
340 340 drivepart = ''
341 341 if sys.platform == 'win32' and len(cwd) > depth:
342 342 drivepart = os.path.splitdrive(full_cwd)[0]
343 343 out = drivepart + '/'.join(cwd[-depth:])
344 344
345 345 if out:
346 346 return out
347 347 else:
348 348 return os.sep
349 349
350 350 def __nonzero__(self):
351 351 """Implement boolean behavior.
352 352
353 353 Checks whether the p_str attribute is non-empty"""
354 354
355 355 return bool(self.p_template)
356 356
357 357
358 358 class Prompt1(BasePrompt):
359 359 """Input interactive prompt similar to Mathematica's."""
360 360
361 361 def __init__(self, cache, sep='\n', prompt='In [\\#]: ', pad_left=True):
362 362 BasePrompt.__init__(self, cache, sep, prompt, pad_left)
363 363
364 364 def set_colors(self):
365 365 self.set_p_str()
366 366 Colors = self.cache.color_table.active_colors # shorthand
367 367 self.col_p = Colors.in_prompt
368 368 self.col_num = Colors.in_number
369 369 self.col_norm = Colors.in_normal
370 370 # We need a non-input version of these escapes for the '--->'
371 371 # auto-call prompts used in the auto_rewrite() method.
372 372 self.col_p_ni = self.col_p.replace('\001','').replace('\002','')
373 373 self.col_norm_ni = Colors.normal
374 374
375 375 def __str__(self):
376 376 self.cache.last_prompt = str_safe(self.p_str_nocolor).split('\n')[-1]
377 377 return str_safe(self.p_str)
378 378
379 379 def auto_rewrite(self):
380 380 """Return a string of the form '--->' which lines up with the previous
381 381 input string. Useful for systems which re-write the user input when
382 382 handling automatically special syntaxes."""
383 383
384 384 curr = str(self.cache.last_prompt)
385 385 nrspaces = len(self.rspace.search(curr).group())
386 386 return '%s%s>%s%s' % (self.col_p_ni,'-'*(len(curr)-nrspaces-1),
387 387 ' '*nrspaces,self.col_norm_ni)
388 388
389 389
390 390 class PromptOut(BasePrompt):
391 391 """Output interactive prompt similar to Mathematica's."""
392 392
393 393 def __init__(self, cache, sep='', prompt='Out[\\#]: ', pad_left=True):
394 394 BasePrompt.__init__(self, cache, sep, prompt, pad_left)
395 395 if not self.p_template:
396 396 self.__str__ = lambda: ''
397 397
398 398 def set_colors(self):
399 399 self.set_p_str()
400 400 Colors = self.cache.color_table.active_colors # shorthand
401 401 self.col_p = Colors.out_prompt
402 402 self.col_num = Colors.out_number
403 403 self.col_norm = Colors.normal
404 404
405 405
406 406 class Prompt2(BasePrompt):
407 407 """Interactive continuation prompt."""
408 408
409 409 def __init__(self, cache, prompt=' .\\D.: ', pad_left=True):
410 410 self.cache = cache
411 411 self.p_template = prompt
412 412 self.pad_left = pad_left
413 413 self.set_p_str()
414 414
415 415 def set_p_str(self):
416 416 import os,time # needed in locals for prompt string handling
417 417 loc = locals()
418 418 self.p_str = ItplNS('%s%s%s' %
419 419 ('${self.col_p2}',
420 420 multiple_replace(prompt_specials, self.p_template),
421 421 '$self.col_norm'),
422 422 self.cache.shell.user_ns,loc)
423 423 self.p_str_nocolor = ItplNS(multiple_replace(prompt_specials_nocolor,
424 424 self.p_template),
425 425 self.cache.shell.user_ns,loc)
426 426
427 427 def set_colors(self):
428 428 self.set_p_str()
429 429 Colors = self.cache.color_table.active_colors
430 430 self.col_p2 = Colors.in_prompt2
431 431 self.col_norm = Colors.in_normal
432 432 # FIXME (2004-06-16) HACK: prevent crashes for users who haven't
433 433 # updated their prompt_in2 definitions. Remove eventually.
434 434 self.col_p = Colors.out_prompt
435 435 self.col_num = Colors.out_number
436 436
@@ -1,138 +1,138 b''
1 1 # encoding: utf-8
2 2 """
3 3 Simple utility for splitting user input. This is used by both inputsplitter and
4 4 prefilter.
5 5
6 6 Authors:
7 7
8 8 * Brian Granger
9 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 15 # Distributed under the terms of the BSD License. The full license is in
16 16 # the file COPYING, distributed as part of this software.
17 17 #-----------------------------------------------------------------------------
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Imports
21 21 #-----------------------------------------------------------------------------
22 22
23 23 import re
24 24 import sys
25 25
26 26 from IPython.utils import py3compat
27 27
28 28 #-----------------------------------------------------------------------------
29 29 # Main function
30 30 #-----------------------------------------------------------------------------
31 31
32 32 # RegExp for splitting line contents into pre-char//first word-method//rest.
33 33 # For clarity, each group in on one line.
34 34
35 35 # WARNING: update the regexp if the escapes in interactiveshell are changed, as
36 36 # they are hardwired in.
37 37
38 38 # Although it's not solely driven by the regex, note that:
39 39 # ,;/% only trigger if they are the first character on the line
40 40 # ! and !! trigger if they are first char(s) *or* follow an indent
41 41 # ? triggers as first or last char.
42 42
43 43 line_split = re.compile("""
44 44 ^(\s*) # any leading space
45 45 ([,;/%]|!!?|\?\??)? # escape character or characters
46 46 \s*(%?[\w\.\*]*) # function/method, possibly with leading %
47 47 # to correctly treat things like '?%magic'
48 48 (.*?$|$) # rest of line
49 49 """, re.VERBOSE)
50 50
51 51 def split_user_input(line, pattern=None):
52 52 """Split user input into initial whitespace, escape character, function part
53 53 and the rest.
54 54 """
55 55 # We need to ensure that the rest of this routine deals only with unicode
56 56 line = py3compat.cast_unicode(line, sys.stdin.encoding or 'utf-8')
57 57
58 58 if pattern is None:
59 59 pattern = line_split
60 60 match = pattern.match(line)
61 61 if not match:
62 62 # print "match failed for line '%s'" % line
63 63 try:
64 64 ifun, the_rest = line.split(None,1)
65 65 except ValueError:
66 66 # print "split failed for line '%s'" % line
67 67 ifun, the_rest = line, u''
68 68 pre = re.match('^(\s*)(.*)',line).groups()[0]
69 69 esc = ""
70 70 else:
71 71 pre, esc, ifun, the_rest = match.groups()
72 72
73 73 #print 'line:<%s>' % line # dbg
74 74 #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun.strip(),the_rest) # dbg
75 75 return pre, esc or '', ifun.strip(), the_rest.lstrip()
76 76
77 77 class LineInfo(object):
78 78 """A single line of input and associated info.
79 79
80 80 Includes the following as properties:
81 81
82 82 line
83 83 The original, raw line
84 84
85 85 continue_prompt
86 86 Is this line a continuation in a sequence of multiline input?
87 87
88 88 pre
89 89 Any leading whitespace.
90 90
91 91 esc
92 92 The escape character(s) in pre or the empty string if there isn't one.
93 93 Note that '!!' and '??' are possible values for esc. Otherwise it will
94 94 always be a single character.
95 95
96 96 ifun
97 97 The 'function part', which is basically the maximal initial sequence
98 98 of valid python identifiers and the '.' character. This is what is
99 99 checked for alias and magic transformations, used for auto-calling,
100 100 etc. In contrast to Python identifiers, it may start with "%" and contain
101 101 "*".
102 102
103 103 the_rest
104 104 Everything else on the line.
105 105 """
106 106 def __init__(self, line, continue_prompt=False):
107 107 self.line = line
108 108 self.continue_prompt = continue_prompt
109 109 self.pre, self.esc, self.ifun, self.the_rest = split_user_input(line)
110 110
111 111 self.pre_char = self.pre.strip()
112 112 if self.pre_char:
113 113 self.pre_whitespace = '' # No whitespace allowd before esc chars
114 114 else:
115 115 self.pre_whitespace = self.pre
116 116
117 117 self._oinfo = None
118 118
119 119 def ofind(self, ip):
120 120 """Do a full, attribute-walking lookup of the ifun in the various
121 121 namespaces for the given IPython InteractiveShell instance.
122 122
123 123 Return a dict with keys: found,obj,ospace,ismagic
124 124
125 125 Note: can cause state changes because of calling getattr, but should
126 126 only be run if autocall is on and if the line hasn't matched any
127 127 other, less dangerous handlers.
128 128
129 129 Does cache the results of the call, so can be called multiple times
130 130 without worrying about *further* damaging state.
131 131 """
132 132 if not self._oinfo:
133 133 # ip.shell._ofind is actually on the Magic class!
134 134 self._oinfo = ip.shell._ofind(self.ifun)
135 135 return self._oinfo
136 136
137 137 def __str__(self):
138 138 return "LineInfo [%s|%s|%s|%s]" %(self.pre, self.esc, self.ifun, self.the_rest)
@@ -1,75 +1,75 b''
1 1 # coding: utf-8
2 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 7 # Distributed under the terms of the BSD License.
8 8 #
9 9 # The full license is in the file COPYING.txt, distributed with this software.
10 10 #-----------------------------------------------------------------------------
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Imports
14 14 #-----------------------------------------------------------------------------
15 15 from __future__ import print_function
16 16
17 17 # Stdlib imports
18 18 import linecache
19 19 import sys
20 20
21 21 # Third-party imports
22 22 import nose.tools as nt
23 23
24 24 # Our own imports
25 25 from IPython.core import compilerop
26 26 from IPython.utils import py3compat
27 27
28 28 #-----------------------------------------------------------------------------
29 29 # Test functions
30 30 #-----------------------------------------------------------------------------
31 31
32 32 def test_code_name():
33 33 code = 'x=1'
34 34 name = compilerop.code_name(code)
35 35 nt.assert_true(name.startswith('<ipython-input-0'))
36 36
37 37
38 38 def test_code_name2():
39 39 code = 'x=1'
40 40 name = compilerop.code_name(code, 9)
41 41 nt.assert_true(name.startswith('<ipython-input-9'))
42 42
43 43
44 44 def test_cache():
45 45 """Test the compiler correctly compiles and caches inputs
46 46 """
47 47 cp = compilerop.CachingCompiler()
48 48 ncache = len(linecache.cache)
49 49 cp.cache('x=1')
50 50 nt.assert_true(len(linecache.cache) > ncache)
51 51
52 52 def setUp():
53 53 # Check we're in a proper Python 2 environment (some imports, such
54 54 # as GTK, can change the default encoding, which can hide bugs.)
55 55 nt.assert_equal(sys.getdefaultencoding(), "utf-8" if py3compat.PY3 else "ascii")
56 56
57 57 def test_cache_unicode():
58 58 cp = compilerop.CachingCompiler()
59 59 ncache = len(linecache.cache)
60 60 cp.cache(u"t = 'žćčšđ'")
61 61 nt.assert_true(len(linecache.cache) > ncache)
62 62
63 63 def test_compiler_check_cache():
64 64 """Test the compiler properly manages the cache.
65 65 """
66 66 # Rather simple-minded tests that just exercise the API
67 67 cp = compilerop.CachingCompiler()
68 68 cp.cache('x=1', 99)
69 69 # Ensure now that after clearing the cache, our entries survive
70 70 cp.check_cache()
71 71 for k in linecache.cache:
72 72 if k.startswith('<ipython-input-99'):
73 73 break
74 74 else:
75 75 raise AssertionError('Entry for input-99 missing from linecache')
@@ -1,706 +1,706 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Tests for the inputsplitter module.
3 3
4 4 Authors
5 5 -------
6 6 * Fernando Perez
7 7 * Robert Kern
8 8 """
9 9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2010 The IPython Development Team
10 # Copyright (C) 2010-2011 The IPython Development Team
11 11 #
12 12 # Distributed under the terms of the BSD License. The full license is in
13 13 # the file COPYING, distributed as part of this software.
14 14 #-----------------------------------------------------------------------------
15 15
16 16 #-----------------------------------------------------------------------------
17 17 # Imports
18 18 #-----------------------------------------------------------------------------
19 19 # stdlib
20 20 import unittest
21 21 import sys
22 22
23 23 # Third party
24 24 import nose.tools as nt
25 25
26 26 # Our own
27 27 from IPython.core import inputsplitter as isp
28 28 from IPython.testing import tools as tt
29 29 from IPython.utils import py3compat
30 30
31 31 #-----------------------------------------------------------------------------
32 32 # Semi-complete examples (also used as tests)
33 33 #-----------------------------------------------------------------------------
34 34
35 35 # Note: at the bottom, there's a slightly more complete version of this that
36 36 # can be useful during development of code here.
37 37
38 38 def mini_interactive_loop(input_func):
39 39 """Minimal example of the logic of an interactive interpreter loop.
40 40
41 41 This serves as an example, and it is used by the test system with a fake
42 42 raw_input that simulates interactive input."""
43 43
44 44 from IPython.core.inputsplitter import InputSplitter
45 45
46 46 isp = InputSplitter()
47 47 # In practice, this input loop would be wrapped in an outside loop to read
48 48 # input indefinitely, until some exit/quit command was issued. Here we
49 49 # only illustrate the basic inner loop.
50 50 while isp.push_accepts_more():
51 51 indent = ' '*isp.indent_spaces
52 52 prompt = '>>> ' + indent
53 53 line = indent + input_func(prompt)
54 54 isp.push(line)
55 55
56 56 # Here we just return input so we can use it in a test suite, but a real
57 57 # interpreter would instead send it for execution somewhere.
58 58 src = isp.source_reset()
59 59 #print 'Input source was:\n', src # dbg
60 60 return src
61 61
62 62 #-----------------------------------------------------------------------------
63 63 # Test utilities, just for local use
64 64 #-----------------------------------------------------------------------------
65 65
66 66 def assemble(block):
67 67 """Assemble a block into multi-line sub-blocks."""
68 68 return ['\n'.join(sub_block)+'\n' for sub_block in block]
69 69
70 70
71 71 def pseudo_input(lines):
72 72 """Return a function that acts like raw_input but feeds the input list."""
73 73 ilines = iter(lines)
74 74 def raw_in(prompt):
75 75 try:
76 76 return next(ilines)
77 77 except StopIteration:
78 78 return ''
79 79 return raw_in
80 80
81 81 #-----------------------------------------------------------------------------
82 82 # Tests
83 83 #-----------------------------------------------------------------------------
84 84 def test_spaces():
85 85 tests = [('', 0),
86 86 (' ', 1),
87 87 ('\n', 0),
88 88 (' \n', 1),
89 89 ('x', 0),
90 90 (' x', 1),
91 91 (' x',2),
92 92 (' x',4),
93 93 # Note: tabs are counted as a single whitespace!
94 94 ('\tx', 1),
95 95 ('\t x', 2),
96 96 ]
97 97 tt.check_pairs(isp.num_ini_spaces, tests)
98 98
99 99
100 100 def test_remove_comments():
101 101 tests = [('text', 'text'),
102 102 ('text # comment', 'text '),
103 103 ('text # comment\n', 'text \n'),
104 104 ('text # comment \n', 'text \n'),
105 105 ('line # c \nline\n','line \nline\n'),
106 106 ('line # c \nline#c2 \nline\nline #c\n\n',
107 107 'line \nline\nline\nline \n\n'),
108 108 ]
109 109 tt.check_pairs(isp.remove_comments, tests)
110 110
111 111 def test_has_comment():
112 112 tests = [('text', False),
113 113 ('text #comment', True),
114 114 ('text #comment\n', True),
115 115 ('#comment', True),
116 116 ('#comment\n', True),
117 117 ('a = "#string"', False),
118 118 ('a = "#string" # comment', True),
119 119 ('a #comment not "string"', True),
120 120 ]
121 121 tt.check_pairs(isp.has_comment, tests)
122 122
123 123
124 124 def test_get_input_encoding():
125 125 encoding = isp.get_input_encoding()
126 126 nt.assert_true(isinstance(encoding, basestring))
127 127 # simple-minded check that at least encoding a simple string works with the
128 128 # encoding we got.
129 129 nt.assert_equal(u'test'.encode(encoding), b'test')
130 130
131 131
132 132 class NoInputEncodingTestCase(unittest.TestCase):
133 133 def setUp(self):
134 134 self.old_stdin = sys.stdin
135 135 class X: pass
136 136 fake_stdin = X()
137 137 sys.stdin = fake_stdin
138 138
139 139 def test(self):
140 140 # Verify that if sys.stdin has no 'encoding' attribute we do the right
141 141 # thing
142 142 enc = isp.get_input_encoding()
143 143 self.assertEqual(enc, 'ascii')
144 144
145 145 def tearDown(self):
146 146 sys.stdin = self.old_stdin
147 147
148 148
149 149 class InputSplitterTestCase(unittest.TestCase):
150 150 def setUp(self):
151 151 self.isp = isp.InputSplitter()
152 152
153 153 def test_reset(self):
154 154 isp = self.isp
155 155 isp.push('x=1')
156 156 isp.reset()
157 157 self.assertEqual(isp._buffer, [])
158 158 self.assertEqual(isp.indent_spaces, 0)
159 159 self.assertEqual(isp.source, '')
160 160 self.assertEqual(isp.code, None)
161 161 self.assertEqual(isp._is_complete, False)
162 162
163 163 def test_source(self):
164 164 self.isp._store('1')
165 165 self.isp._store('2')
166 166 self.assertEqual(self.isp.source, '1\n2\n')
167 167 self.assertTrue(len(self.isp._buffer)>0)
168 168 self.assertEqual(self.isp.source_reset(), '1\n2\n')
169 169 self.assertEqual(self.isp._buffer, [])
170 170 self.assertEqual(self.isp.source, '')
171 171
172 172 def test_indent(self):
173 173 isp = self.isp # shorthand
174 174 isp.push('x=1')
175 175 self.assertEqual(isp.indent_spaces, 0)
176 176 isp.push('if 1:\n x=1')
177 177 self.assertEqual(isp.indent_spaces, 4)
178 178 isp.push('y=2\n')
179 179 self.assertEqual(isp.indent_spaces, 0)
180 180
181 181 def test_indent2(self):
182 182 # In cell mode, inputs must be fed in whole blocks, so skip this test
183 183 if self.isp.input_mode == 'cell': return
184 184
185 185 isp = self.isp
186 186 isp.push('if 1:')
187 187 self.assertEqual(isp.indent_spaces, 4)
188 188 isp.push(' x=1')
189 189 self.assertEqual(isp.indent_spaces, 4)
190 190 # Blank lines shouldn't change the indent level
191 191 isp.push(' '*2)
192 192 self.assertEqual(isp.indent_spaces, 4)
193 193
194 194 def test_indent3(self):
195 195 # In cell mode, inputs must be fed in whole blocks, so skip this test
196 196 if self.isp.input_mode == 'cell': return
197 197
198 198 isp = self.isp
199 199 # When a multiline statement contains parens or multiline strings, we
200 200 # shouldn't get confused.
201 201 isp.push("if 1:")
202 202 isp.push(" x = (1+\n 2)")
203 203 self.assertEqual(isp.indent_spaces, 4)
204 204
205 205 def test_indent4(self):
206 206 # In cell mode, inputs must be fed in whole blocks, so skip this test
207 207 if self.isp.input_mode == 'cell': return
208 208
209 209 isp = self.isp
210 210 # whitespace after ':' should not screw up indent level
211 211 isp.push('if 1: \n x=1')
212 212 self.assertEqual(isp.indent_spaces, 4)
213 213 isp.push('y=2\n')
214 214 self.assertEqual(isp.indent_spaces, 0)
215 215 isp.push('if 1:\t\n x=1')
216 216 self.assertEqual(isp.indent_spaces, 4)
217 217 isp.push('y=2\n')
218 218 self.assertEqual(isp.indent_spaces, 0)
219 219
220 220 def test_dedent_pass(self):
221 221 isp = self.isp # shorthand
222 222 # should NOT cause dedent
223 223 isp.push('if 1:\n passes = 5')
224 224 self.assertEqual(isp.indent_spaces, 4)
225 225 isp.push('if 1:\n pass')
226 226 self.assertEqual(isp.indent_spaces, 0)
227 227 isp.push('if 1:\n pass ')
228 228 self.assertEqual(isp.indent_spaces, 0)
229 229
230 230 def test_dedent_raise(self):
231 231 isp = self.isp # shorthand
232 232 # should NOT cause dedent
233 233 isp.push('if 1:\n raised = 4')
234 234 self.assertEqual(isp.indent_spaces, 4)
235 235 isp.push('if 1:\n raise TypeError()')
236 236 self.assertEqual(isp.indent_spaces, 0)
237 237 isp.push('if 1:\n raise')
238 238 self.assertEqual(isp.indent_spaces, 0)
239 239 isp.push('if 1:\n raise ')
240 240 self.assertEqual(isp.indent_spaces, 0)
241 241
242 242 def test_dedent_return(self):
243 243 isp = self.isp # shorthand
244 244 # should NOT cause dedent
245 245 isp.push('if 1:\n returning = 4')
246 246 self.assertEqual(isp.indent_spaces, 4)
247 247 isp.push('if 1:\n return 5 + 493')
248 248 self.assertEqual(isp.indent_spaces, 0)
249 249 isp.push('if 1:\n return')
250 250 self.assertEqual(isp.indent_spaces, 0)
251 251 isp.push('if 1:\n return ')
252 252 self.assertEqual(isp.indent_spaces, 0)
253 253 isp.push('if 1:\n return(0)')
254 254 self.assertEqual(isp.indent_spaces, 0)
255 255
256 256 def test_push(self):
257 257 isp = self.isp
258 258 self.assertTrue(isp.push('x=1'))
259 259
260 260 def test_push2(self):
261 261 isp = self.isp
262 262 self.assertFalse(isp.push('if 1:'))
263 263 for line in [' x=1', '# a comment', ' y=2']:
264 264 self.assertTrue(isp.push(line))
265 265
266 266 def test_push3(self):
267 267 isp = self.isp
268 268 isp.push('if True:')
269 269 isp.push(' a = 1')
270 270 self.assertFalse(isp.push('b = [1,'))
271 271
272 272 def test_replace_mode(self):
273 273 isp = self.isp
274 274 isp.input_mode = 'cell'
275 275 isp.push('x=1')
276 276 self.assertEqual(isp.source, 'x=1\n')
277 277 isp.push('x=2')
278 278 self.assertEqual(isp.source, 'x=2\n')
279 279
280 280 def test_push_accepts_more(self):
281 281 isp = self.isp
282 282 isp.push('x=1')
283 283 self.assertFalse(isp.push_accepts_more())
284 284
285 285 def test_push_accepts_more2(self):
286 286 # In cell mode, inputs must be fed in whole blocks, so skip this test
287 287 if self.isp.input_mode == 'cell': return
288 288
289 289 isp = self.isp
290 290 isp.push('if 1:')
291 291 self.assertTrue(isp.push_accepts_more())
292 292 isp.push(' x=1')
293 293 self.assertTrue(isp.push_accepts_more())
294 294 isp.push('')
295 295 self.assertFalse(isp.push_accepts_more())
296 296
297 297 def test_push_accepts_more3(self):
298 298 isp = self.isp
299 299 isp.push("x = (2+\n3)")
300 300 self.assertFalse(isp.push_accepts_more())
301 301
302 302 def test_push_accepts_more4(self):
303 303 # In cell mode, inputs must be fed in whole blocks, so skip this test
304 304 if self.isp.input_mode == 'cell': return
305 305
306 306 isp = self.isp
307 307 # When a multiline statement contains parens or multiline strings, we
308 308 # shouldn't get confused.
309 309 # FIXME: we should be able to better handle de-dents in statements like
310 310 # multiline strings and multiline expressions (continued with \ or
311 311 # parens). Right now we aren't handling the indentation tracking quite
312 312 # correctly with this, though in practice it may not be too much of a
313 313 # problem. We'll need to see.
314 314 isp.push("if 1:")
315 315 isp.push(" x = (2+")
316 316 isp.push(" 3)")
317 317 self.assertTrue(isp.push_accepts_more())
318 318 isp.push(" y = 3")
319 319 self.assertTrue(isp.push_accepts_more())
320 320 isp.push('')
321 321 self.assertFalse(isp.push_accepts_more())
322 322
323 323 def test_push_accepts_more5(self):
324 324 # In cell mode, inputs must be fed in whole blocks, so skip this test
325 325 if self.isp.input_mode == 'cell': return
326 326
327 327 isp = self.isp
328 328 isp.push('try:')
329 329 isp.push(' a = 5')
330 330 isp.push('except:')
331 331 isp.push(' raise')
332 332 self.assertTrue(isp.push_accepts_more())
333 333
334 334 def test_continuation(self):
335 335 isp = self.isp
336 336 isp.push("import os, \\")
337 337 self.assertTrue(isp.push_accepts_more())
338 338 isp.push("sys")
339 339 self.assertFalse(isp.push_accepts_more())
340 340
341 341 def test_syntax_error(self):
342 342 isp = self.isp
343 343 # Syntax errors immediately produce a 'ready' block, so the invalid
344 344 # Python can be sent to the kernel for evaluation with possible ipython
345 345 # special-syntax conversion.
346 346 isp.push('run foo')
347 347 self.assertFalse(isp.push_accepts_more())
348 348
349 349 def test_unicode(self):
350 350 self.isp.push(u"Pérez")
351 351 self.isp.push(u'\xc3\xa9')
352 352 self.isp.push(u"u'\xc3\xa9'")
353 353
354 354 class InteractiveLoopTestCase(unittest.TestCase):
355 355 """Tests for an interactive loop like a python shell.
356 356 """
357 357 def check_ns(self, lines, ns):
358 358 """Validate that the given input lines produce the resulting namespace.
359 359
360 360 Note: the input lines are given exactly as they would be typed in an
361 361 auto-indenting environment, as mini_interactive_loop above already does
362 362 auto-indenting and prepends spaces to the input.
363 363 """
364 364 src = mini_interactive_loop(pseudo_input(lines))
365 365 test_ns = {}
366 366 exec src in test_ns
367 367 # We can't check that the provided ns is identical to the test_ns,
368 368 # because Python fills test_ns with extra keys (copyright, etc). But
369 369 # we can check that the given dict is *contained* in test_ns
370 370 for k,v in ns.iteritems():
371 371 self.assertEqual(test_ns[k], v)
372 372
373 373 def test_simple(self):
374 374 self.check_ns(['x=1'], dict(x=1))
375 375
376 376 def test_simple2(self):
377 377 self.check_ns(['if 1:', 'x=2'], dict(x=2))
378 378
379 379 def test_xy(self):
380 380 self.check_ns(['x=1; y=2'], dict(x=1, y=2))
381 381
382 382 def test_abc(self):
383 383 self.check_ns(['if 1:','a=1','b=2','c=3'], dict(a=1, b=2, c=3))
384 384
385 385 def test_multi(self):
386 386 self.check_ns(['x =(1+','1+','2)'], dict(x=4))
387 387
388 388
389 389 def test_LineInfo():
390 390 """Simple test for LineInfo construction and str()"""
391 391 linfo = isp.LineInfo(' %cd /home')
392 392 nt.assert_equals(str(linfo), 'LineInfo [ |%|cd|/home]')
393 393
394 394 # Transformer tests
395 395 def transform_checker(tests, func):
396 396 """Utility to loop over test inputs"""
397 397 for inp, tr in tests:
398 398 nt.assert_equals(func(inp), tr)
399 399
400 400 # Data for all the syntax tests in the form of lists of pairs of
401 401 # raw/transformed input. We store it here as a global dict so that we can use
402 402 # it both within single-function tests and also to validate the behavior of the
403 403 # larger objects
404 404
405 405 syntax = \
406 406 dict(assign_system =
407 407 [(i,py3compat.u_format(o)) for i,o in \
408 408 [(u'a =! ls', "a = get_ipython().getoutput({u}'ls')"),
409 409 (u'b = !ls', "b = get_ipython().getoutput({u}'ls')"),
410 410 ('x=1', 'x=1'), # normal input is unmodified
411 411 (' ',' '), # blank lines are kept intact
412 412 ]],
413 413
414 414 assign_magic =
415 415 [(i,py3compat.u_format(o)) for i,o in \
416 416 [(u'a =% who', "a = get_ipython().magic({u}'who')"),
417 417 (u'b = %who', "b = get_ipython().magic({u}'who')"),
418 418 ('x=1', 'x=1'), # normal input is unmodified
419 419 (' ',' '), # blank lines are kept intact
420 420 ]],
421 421
422 422 classic_prompt =
423 423 [('>>> x=1', 'x=1'),
424 424 ('x=1', 'x=1'), # normal input is unmodified
425 425 (' ', ' '), # blank lines are kept intact
426 426 ('... ', ''), # continuation prompts
427 427 ],
428 428
429 429 ipy_prompt =
430 430 [('In [1]: x=1', 'x=1'),
431 431 ('x=1', 'x=1'), # normal input is unmodified
432 432 (' ',' '), # blank lines are kept intact
433 433 (' ....: ', ''), # continuation prompts
434 434 ],
435 435
436 436 # Tests for the escape transformer to leave normal code alone
437 437 escaped_noesc =
438 438 [ (' ', ' '),
439 439 ('x=1', 'x=1'),
440 440 ],
441 441
442 442 # System calls
443 443 escaped_shell =
444 444 [(i,py3compat.u_format(o)) for i,o in \
445 445 [ (u'!ls', "get_ipython().system({u}'ls')"),
446 446 # Double-escape shell, this means to capture the output of the
447 447 # subprocess and return it
448 448 (u'!!ls', "get_ipython().getoutput({u}'ls')"),
449 449 ]],
450 450
451 451 # Help/object info
452 452 escaped_help =
453 453 [(i,py3compat.u_format(o)) for i,o in \
454 454 [ (u'?', 'get_ipython().show_usage()'),
455 455 (u'?x1', "get_ipython().magic({u}'pinfo x1')"),
456 456 (u'??x2', "get_ipython().magic({u}'pinfo2 x2')"),
457 457 (u'?a.*s', "get_ipython().magic({u}'psearch a.*s')"),
458 458 (u'?%hist', "get_ipython().magic({u}'pinfo %hist')"),
459 459 (u'?abc = qwe', "get_ipython().magic({u}'pinfo abc')"),
460 460 ]],
461 461
462 462 end_help =
463 463 [(i,py3compat.u_format(o)) for i,o in \
464 464 [ (u'x3?', "get_ipython().magic({u}'pinfo x3')"),
465 465 (u'x4??', "get_ipython().magic({u}'pinfo2 x4')"),
466 466 (u'%hist?', "get_ipython().magic({u}'pinfo %hist')"),
467 467 (u'f*?', "get_ipython().magic({u}'psearch f*')"),
468 468 (u'ax.*aspe*?', "get_ipython().magic({u}'psearch ax.*aspe*')"),
469 469 (u'a = abc?', "get_ipython().magic({u}'pinfo abc', next_input={u}'a = abc')"),
470 470 (u'a = abc.qe??', "get_ipython().magic({u}'pinfo2 abc.qe', next_input={u}'a = abc.qe')"),
471 471 (u'a = *.items?', "get_ipython().magic({u}'psearch *.items', next_input={u}'a = *.items')"),
472 472 (u'plot(a?', "get_ipython().magic({u}'pinfo a', next_input={u}'plot(a')"),
473 473 (u'a*2 #comment?', 'a*2 #comment?'),
474 474 ]],
475 475
476 476 # Explicit magic calls
477 477 escaped_magic =
478 478 [(i,py3compat.u_format(o)) for i,o in \
479 479 [ (u'%cd', "get_ipython().magic({u}'cd')"),
480 480 (u'%cd /home', "get_ipython().magic({u}'cd /home')"),
481 481 # Backslashes need to be escaped.
482 482 (u'%cd C:\\User', "get_ipython().magic({u}'cd C:\\\\User')"),
483 483 (u' %magic', " get_ipython().magic({u}'magic')"),
484 484 ]],
485 485
486 486 # Quoting with separate arguments
487 487 escaped_quote =
488 488 [ (',f', 'f("")'),
489 489 (',f x', 'f("x")'),
490 490 (' ,f y', ' f("y")'),
491 491 (',f a b', 'f("a", "b")'),
492 492 ],
493 493
494 494 # Quoting with single argument
495 495 escaped_quote2 =
496 496 [ (';f', 'f("")'),
497 497 (';f x', 'f("x")'),
498 498 (' ;f y', ' f("y")'),
499 499 (';f a b', 'f("a b")'),
500 500 ],
501 501
502 502 # Simply apply parens
503 503 escaped_paren =
504 504 [ ('/f', 'f()'),
505 505 ('/f x', 'f(x)'),
506 506 (' /f y', ' f(y)'),
507 507 ('/f a b', 'f(a, b)'),
508 508 ],
509 509
510 510 # Check that we transform prompts before other transforms
511 511 mixed =
512 512 [(i,py3compat.u_format(o)) for i,o in \
513 513 [ (u'In [1]: %lsmagic', "get_ipython().magic({u}'lsmagic')"),
514 514 (u'>>> %lsmagic', "get_ipython().magic({u}'lsmagic')"),
515 515 (u'In [2]: !ls', "get_ipython().system({u}'ls')"),
516 516 (u'In [3]: abs?', "get_ipython().magic({u}'pinfo abs')"),
517 517 (u'In [4]: b = %who', "b = get_ipython().magic({u}'who')"),
518 518 ]],
519 519 )
520 520
521 521 # multiline syntax examples. Each of these should be a list of lists, with
522 522 # each entry itself having pairs of raw/transformed input. The union (with
523 523 # '\n'.join() of the transformed inputs is what the splitter should produce
524 524 # when fed the raw lines one at a time via push.
525 525 syntax_ml = \
526 526 dict(classic_prompt =
527 527 [ [('>>> for i in range(10):','for i in range(10):'),
528 528 ('... print i',' print i'),
529 529 ('... ', ''),
530 530 ],
531 531 ],
532 532
533 533 ipy_prompt =
534 534 [ [('In [24]: for i in range(10):','for i in range(10):'),
535 535 (' ....: print i',' print i'),
536 536 (' ....: ', ''),
537 537 ],
538 538 ],
539 539
540 540 multiline_datastructure =
541 541 [ [('>>> a = [1,','a = [1,'),
542 542 ('... 2]','2]'),
543 543 ],
544 544 ],
545 545 )
546 546
547 547
548 548 def test_assign_system():
549 549 tt.check_pairs(isp.transform_assign_system, syntax['assign_system'])
550 550
551 551
552 552 def test_assign_magic():
553 553 tt.check_pairs(isp.transform_assign_magic, syntax['assign_magic'])
554 554
555 555
556 556 def test_classic_prompt():
557 557 transform_checker(syntax['classic_prompt'], isp.transform_classic_prompt)
558 558 for example in syntax_ml['classic_prompt']:
559 559 transform_checker(example, isp.transform_classic_prompt)
560 560
561 561
562 562 def test_ipy_prompt():
563 563 transform_checker(syntax['ipy_prompt'], isp.transform_ipy_prompt)
564 564 for example in syntax_ml['ipy_prompt']:
565 565 transform_checker(example, isp.transform_ipy_prompt)
566 566
567 567 def test_end_help():
568 568 tt.check_pairs(isp.transform_help_end, syntax['end_help'])
569 569
570 570 def test_escaped_noesc():
571 571 tt.check_pairs(isp.transform_escaped, syntax['escaped_noesc'])
572 572
573 573
574 574 def test_escaped_shell():
575 575 tt.check_pairs(isp.transform_escaped, syntax['escaped_shell'])
576 576
577 577
578 578 def test_escaped_help():
579 579 tt.check_pairs(isp.transform_escaped, syntax['escaped_help'])
580 580
581 581
582 582 def test_escaped_magic():
583 583 tt.check_pairs(isp.transform_escaped, syntax['escaped_magic'])
584 584
585 585
586 586 def test_escaped_quote():
587 587 tt.check_pairs(isp.transform_escaped, syntax['escaped_quote'])
588 588
589 589
590 590 def test_escaped_quote2():
591 591 tt.check_pairs(isp.transform_escaped, syntax['escaped_quote2'])
592 592
593 593
594 594 def test_escaped_paren():
595 595 tt.check_pairs(isp.transform_escaped, syntax['escaped_paren'])
596 596
597 597
598 598 class IPythonInputTestCase(InputSplitterTestCase):
599 599 """By just creating a new class whose .isp is a different instance, we
600 600 re-run the same test battery on the new input splitter.
601 601
602 602 In addition, this runs the tests over the syntax and syntax_ml dicts that
603 603 were tested by individual functions, as part of the OO interface.
604 604
605 605 It also makes some checks on the raw buffer storage.
606 606 """
607 607
608 608 def setUp(self):
609 609 self.isp = isp.IPythonInputSplitter(input_mode='line')
610 610
611 611 def test_syntax(self):
612 612 """Call all single-line syntax tests from the main object"""
613 613 isp = self.isp
614 614 for example in syntax.itervalues():
615 615 for raw, out_t in example:
616 616 if raw.startswith(' '):
617 617 continue
618 618
619 619 isp.push(raw)
620 620 out, out_raw = isp.source_raw_reset()
621 621 self.assertEqual(out.rstrip(), out_t,
622 622 tt.pair_fail_msg.format("inputsplitter",raw, out_t, out))
623 623 self.assertEqual(out_raw.rstrip(), raw.rstrip())
624 624
625 625 def test_syntax_multiline(self):
626 626 isp = self.isp
627 627 for example in syntax_ml.itervalues():
628 628 out_t_parts = []
629 629 raw_parts = []
630 630 for line_pairs in example:
631 631 for lraw, out_t_part in line_pairs:
632 632 isp.push(lraw)
633 633 out_t_parts.append(out_t_part)
634 634 raw_parts.append(lraw)
635 635
636 636 out, out_raw = isp.source_raw_reset()
637 637 out_t = '\n'.join(out_t_parts).rstrip()
638 638 raw = '\n'.join(raw_parts).rstrip()
639 639 self.assertEqual(out.rstrip(), out_t)
640 640 self.assertEqual(out_raw.rstrip(), raw)
641 641
642 642
643 643 class BlockIPythonInputTestCase(IPythonInputTestCase):
644 644
645 645 # Deactivate tests that don't make sense for the block mode
646 646 test_push3 = test_split = lambda s: None
647 647
648 648 def setUp(self):
649 649 self.isp = isp.IPythonInputSplitter(input_mode='cell')
650 650
651 651 def test_syntax_multiline(self):
652 652 isp = self.isp
653 653 for example in syntax_ml.itervalues():
654 654 raw_parts = []
655 655 out_t_parts = []
656 656 for line_pairs in example:
657 657 for raw, out_t_part in line_pairs:
658 658 raw_parts.append(raw)
659 659 out_t_parts.append(out_t_part)
660 660
661 661 raw = '\n'.join(raw_parts)
662 662 out_t = '\n'.join(out_t_parts)
663 663
664 664 isp.push(raw)
665 665 out, out_raw = isp.source_raw_reset()
666 666 # Match ignoring trailing whitespace
667 667 self.assertEqual(out.rstrip(), out_t.rstrip())
668 668 self.assertEqual(out_raw.rstrip(), raw.rstrip())
669 669
670 670
671 671 #-----------------------------------------------------------------------------
672 672 # Main - use as a script, mostly for developer experiments
673 673 #-----------------------------------------------------------------------------
674 674
675 675 if __name__ == '__main__':
676 676 # A simple demo for interactive experimentation. This code will not get
677 677 # picked up by any test suite.
678 678 from IPython.core.inputsplitter import InputSplitter, IPythonInputSplitter
679 679
680 680 # configure here the syntax to use, prompt and whether to autoindent
681 681 #isp, start_prompt = InputSplitter(), '>>> '
682 682 isp, start_prompt = IPythonInputSplitter(), 'In> '
683 683
684 684 autoindent = True
685 685 #autoindent = False
686 686
687 687 try:
688 688 while True:
689 689 prompt = start_prompt
690 690 while isp.push_accepts_more():
691 691 indent = ' '*isp.indent_spaces
692 692 if autoindent:
693 693 line = indent + raw_input(prompt+indent)
694 694 else:
695 695 line = raw_input(prompt)
696 696 isp.push(line)
697 697 prompt = '... '
698 698
699 699 # Here we just return input so we can use it in a test suite, but a
700 700 # real interpreter would instead send it for execution somewhere.
701 701 #src = isp.source; raise EOFError # dbg
702 702 src, raw = isp.source_raw_reset()
703 703 print 'Input source was:\n', src
704 704 print 'Raw source was:\n', raw
705 705 except EOFError:
706 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 4 # Distributed under the terms of the Modified BSD License.
5 5 #
6 6 # The full license is in the file COPYING.txt, distributed with this software.
7 7 #-----------------------------------------------------------------------------
8 8
9 9 from nose.tools import assert_equal, assert_true
10 10
11 11 from IPython.external import argparse
12 12 from IPython.core.magic_arguments import (argument, argument_group, kwds,
13 13 magic_arguments, parse_argstring, real_name)
14 14 from IPython.testing.decorators import parametric
15 15
16 16
17 17 @magic_arguments()
18 18 @argument('-f', '--foo', help="an argument")
19 19 def magic_foo1(self, args):
20 20 """ A docstring.
21 21 """
22 22 return parse_argstring(magic_foo1, args)
23 23
24 24
25 25 @magic_arguments()
26 26 def magic_foo2(self, args):
27 27 """ A docstring.
28 28 """
29 29 return parse_argstring(magic_foo2, args)
30 30
31 31
32 32 @magic_arguments()
33 33 @argument('-f', '--foo', help="an argument")
34 34 @argument_group('Group')
35 35 @argument('-b', '--bar', help="a grouped argument")
36 36 @argument_group('Second Group')
37 37 @argument('-z', '--baz', help="another grouped argument")
38 38 def magic_foo3(self, args):
39 39 """ A docstring.
40 40 """
41 41 return parse_argstring(magic_foo3, args)
42 42
43 43
44 44 @magic_arguments()
45 45 @kwds(argument_default=argparse.SUPPRESS)
46 46 @argument('-f', '--foo', help="an argument")
47 47 def magic_foo4(self, args):
48 48 """ A docstring.
49 49 """
50 50 return parse_argstring(magic_foo4, args)
51 51
52 52
53 53 @magic_arguments('frobnicate')
54 54 @argument('-f', '--foo', help="an argument")
55 55 def magic_foo5(self, args):
56 56 """ A docstring.
57 57 """
58 58 return parse_argstring(magic_foo5, args)
59 59
60 60
61 61 @magic_arguments()
62 62 @argument('-f', '--foo', help="an argument")
63 63 def magic_magic_foo(self, args):
64 64 """ A docstring.
65 65 """
66 66 return parse_argstring(magic_magic_foo, args)
67 67
68 68
69 69 @magic_arguments()
70 70 @argument('-f', '--foo', help="an argument")
71 71 def foo(self, args):
72 72 """ A docstring.
73 73 """
74 74 return parse_argstring(foo, args)
75 75
76 76
77 77 @parametric
78 78 def test_magic_arguments():
79 79 # Ideally, these would be doctests, but I could not get it to work.
80 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 81 yield assert_equal(getattr(magic_foo1, 'argcmd_name', None), None)
82 82 yield assert_equal(real_name(magic_foo1), 'foo1')
83 83 yield assert_equal(magic_foo1(None, ''), argparse.Namespace(foo=None))
84 84 yield assert_true(hasattr(magic_foo1, 'has_arguments'))
85 85
86 86 yield assert_equal(magic_foo2.__doc__, '%foo2\n\nA docstring.\n')
87 87 yield assert_equal(getattr(magic_foo2, 'argcmd_name', None), None)
88 88 yield assert_equal(real_name(magic_foo2), 'foo2')
89 89 yield assert_equal(magic_foo2(None, ''), argparse.Namespace())
90 90 yield assert_true(hasattr(magic_foo2, 'has_arguments'))
91 91
92 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 93 yield assert_equal(getattr(magic_foo3, 'argcmd_name', None), None)
94 94 yield assert_equal(real_name(magic_foo3), 'foo3')
95 95 yield assert_equal(magic_foo3(None, ''),
96 96 argparse.Namespace(bar=None, baz=None, foo=None))
97 97 yield assert_true(hasattr(magic_foo3, 'has_arguments'))
98 98
99 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 100 yield assert_equal(getattr(magic_foo4, 'argcmd_name', None), None)
101 101 yield assert_equal(real_name(magic_foo4), 'foo4')
102 102 yield assert_equal(magic_foo4(None, ''), argparse.Namespace())
103 103 yield assert_true(hasattr(magic_foo4, 'has_arguments'))
104 104
105 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 106 yield assert_equal(getattr(magic_foo5, 'argcmd_name', None), 'frobnicate')
107 107 yield assert_equal(real_name(magic_foo5), 'frobnicate')
108 108 yield assert_equal(magic_foo5(None, ''), argparse.Namespace(foo=None))
109 109 yield assert_true(hasattr(magic_foo5, 'has_arguments'))
110 110
111 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 112 yield assert_equal(getattr(magic_magic_foo, 'argcmd_name', None), None)
113 113 yield assert_equal(real_name(magic_magic_foo), 'magic_foo')
114 114 yield assert_equal(magic_magic_foo(None, ''), argparse.Namespace(foo=None))
115 115 yield assert_true(hasattr(magic_magic_foo, 'has_arguments'))
116 116
117 117 yield assert_equal(foo.__doc__, '%foo [-f FOO]\n\nA docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n')
118 118 yield assert_equal(getattr(foo, 'argcmd_name', None), None)
119 119 yield assert_equal(real_name(foo), 'foo')
120 120 yield assert_equal(foo(None, ''), argparse.Namespace(foo=None))
121 121 yield assert_true(hasattr(foo, 'has_arguments'))
@@ -1,136 +1,136 b''
1 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 6 # Distributed under the terms of the BSD License.
7 7 #
8 8 # The full license is in the file COPYING.txt, distributed with this software.
9 9 #-----------------------------------------------------------------------------
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Imports
13 13 #-----------------------------------------------------------------------------
14 14 from __future__ import print_function
15 15
16 16 # Stdlib imports
17 17
18 18 # Third-party imports
19 19 import nose.tools as nt
20 20
21 21 # Our own imports
22 22 from .. import oinspect
23 23 from IPython.utils import py3compat
24 24
25 25 #-----------------------------------------------------------------------------
26 26 # Globals and constants
27 27 #-----------------------------------------------------------------------------
28 28
29 29 inspector = oinspect.Inspector()
30 30
31 31 #-----------------------------------------------------------------------------
32 32 # Local utilities
33 33 #-----------------------------------------------------------------------------
34 34
35 35 # A few generic objects we can then inspect in the tests below
36 36
37 37 class Call(object):
38 38 """This is the class docstring."""
39 39
40 40 def __init__(self, x, y=1):
41 41 """This is the constructor docstring."""
42 42
43 43 def __call__(self, *a, **kw):
44 44 """This is the call docstring."""
45 45
46 46 def method(self, x, z=2):
47 47 """Some method's docstring"""
48 48
49 49 class OldStyle:
50 50 """An old-style class for testing."""
51 51 pass
52 52
53 53 def f(x, y=2, *a, **kw):
54 54 """A simple function."""
55 55
56 56 def g(y, z=3, *a, **kw):
57 57 pass # no docstring
58 58
59 59
60 60 def check_calltip(obj, name, call, docstring):
61 61 """Generic check pattern all calltip tests will use"""
62 62 info = inspector.info(obj, name)
63 63 call_line, ds = oinspect.call_tip(info)
64 64 nt.assert_equal(call_line, call)
65 65 nt.assert_equal(ds, docstring)
66 66
67 67 #-----------------------------------------------------------------------------
68 68 # Tests
69 69 #-----------------------------------------------------------------------------
70 70
71 71 def test_calltip_class():
72 72 check_calltip(Call, 'Call', 'Call(x, y=1)', Call.__init__.__doc__)
73 73
74 74
75 75 def test_calltip_instance():
76 76 c = Call(1)
77 77 check_calltip(c, 'c', 'c(*a, **kw)', c.__call__.__doc__)
78 78
79 79
80 80 def test_calltip_method():
81 81 c = Call(1)
82 82 check_calltip(c.method, 'c.method', 'c.method(x, z=2)', c.method.__doc__)
83 83
84 84
85 85 def test_calltip_function():
86 86 check_calltip(f, 'f', 'f(x, y=2, *a, **kw)', f.__doc__)
87 87
88 88
89 89 def test_calltip_function2():
90 90 check_calltip(g, 'g', 'g(y, z=3, *a, **kw)', '<no docstring>')
91 91
92 92
93 93 def test_calltip_builtin():
94 94 check_calltip(sum, 'sum', None, sum.__doc__)
95 95
96 96 def test_info():
97 97 "Check that Inspector.info fills out various fields as expected."
98 98 i = inspector.info(Call, oname='Call')
99 99 nt.assert_equal(i['type_name'], 'type')
100 100 expted_class = str(type(type)) # <class 'type'> (Python 3) or <type 'type'>
101 101 nt.assert_equal(i['base_class'], expted_class)
102 102 nt.assert_equal(i['string_form'], "<class 'IPython.core.tests.test_oinspect.Call'>")
103 103 fname = __file__
104 104 if fname.endswith(".pyc"):
105 105 fname = fname[:-1]
106 106 # case-insensitive comparison needed on some filesystems
107 107 # e.g. Windows:
108 108 nt.assert_equal(i['file'].lower(), fname.lower())
109 109 nt.assert_equal(i['definition'], 'Call(self, *a, **kw)\n')
110 110 nt.assert_equal(i['docstring'], Call.__doc__)
111 111 nt.assert_equal(i['source'], None)
112 112 nt.assert_true(i['isclass'])
113 113 nt.assert_equal(i['init_definition'], "Call(self, x, y=1)\n")
114 114 nt.assert_equal(i['init_docstring'], Call.__init__.__doc__)
115 115
116 116 i = inspector.info(Call, detail_level=1)
117 117 nt.assert_not_equal(i['source'], None)
118 118 nt.assert_equal(i['docstring'], None)
119 119
120 120 c = Call(1)
121 121 c.__doc__ = "Modified instance docstring"
122 122 i = inspector.info(c)
123 123 nt.assert_equal(i['type_name'], 'Call')
124 124 nt.assert_equal(i['docstring'], "Modified instance docstring")
125 125 nt.assert_equal(i['class_docstring'], Call.__doc__)
126 126 nt.assert_equal(i['init_docstring'], Call.__init__.__doc__)
127 127 nt.assert_equal(i['call_docstring'], c.__call__.__doc__)
128 128
129 129 # Test old-style classes, which for example may not have an __init__ method.
130 130 if not py3compat.PY3:
131 131 i = inspector.info(OldStyle)
132 132 nt.assert_equal(i['type_name'], 'classobj')
133 133
134 134 i = inspector.info(OldStyle())
135 135 nt.assert_equal(i['type_name'], 'instance')
136 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 4 # Distributed under the terms of the BSD License.
5 5 #
6 6 # The full license is in the file COPYING.txt, distributed with this software.
7 7 #-----------------------------------------------------------------------------
8 8 import io
9 9
10 10 # N.B. For the test suite, page.page is overridden (see IPython.testing.globalipapp)
11 11 from IPython.core import page
12 12
13 13 def test_detect_screen_size():
14 14 """Simple smoketest for page._detect_screen_size."""
15 15 try:
16 16 page._detect_screen_size(True, 25)
17 17 except (TypeError, io.UnsupportedOperation):
18 18 # This can happen in the test suite, because stdout may not have a
19 19 # fileno.
20 20 pass
@@ -1,529 +1,529 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Usage information for the main IPython applications.
3 3 """
4 4 #-----------------------------------------------------------------------------
5 # Copyright (C) 2008-2010 The IPython Development Team
5 # Copyright (C) 2008-2011 The IPython Development Team
6 6 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
7 7 #
8 8 # Distributed under the terms of the BSD License. The full license is in
9 9 # the file COPYING, distributed as part of this software.
10 10 #-----------------------------------------------------------------------------
11 11
12 12 import sys
13 13 from IPython.core import release
14 14
15 15 cl_usage = """\
16 16 =========
17 17 IPython
18 18 =========
19 19
20 20 Tools for Interactive Computing in Python
21 21 =========================================
22 22
23 23 A Python shell with automatic history (input and output), dynamic object
24 24 introspection, easier configuration, command completion, access to the
25 25 system shell and more. IPython can also be embedded in running programs.
26 26
27 27
28 28 Usage
29 29
30 30 ipython [subcommand] [options] [files]
31 31
32 32 If invoked with no options, it executes all the files listed in sequence
33 33 and exits, use -i to enter interactive mode after running the files. Files
34 34 ending in .py will be treated as normal Python, but files ending in .ipy
35 35 can contain special IPython syntax (magic commands, shell expansions, etc.)
36 36
37 37 Almost all configuration in IPython is available via the command-line. Do
38 38 `ipython --help-all` to see all available options. For persistent
39 39 configuration, look into your `ipython_config.py` configuration file for
40 40 details.
41 41
42 42 This file is typically installed in the `IPYTHON_DIR` directory, and there
43 43 is a separate configuration directory for each profile. The default profile
44 44 directory will be located in $IPYTHON_DIR/profile_default. For Linux users,
45 45 IPYTHON_DIR defaults to `$HOME/.config/ipython`, and for other Unix systems
46 46 to `$HOME/.ipython`. For Windows users, $HOME resolves to C:\\Documents
47 47 and Settings\\YourUserName in most instances.
48 48
49 49 To initialize a profile with the default configuration file, do::
50 50
51 51 $> ipython profile create
52 52
53 53 and start editing `IPYTHON_DIR/profile_default/ipython_config.py`
54 54
55 55 In IPython's documentation, we will refer to this directory as
56 56 `IPYTHON_DIR`, you can change its default location by creating an
57 57 environment variable with this name and setting it to the desired path.
58 58
59 59 For more information, see the manual available in HTML and PDF in your
60 60 installation, or online at http://ipython.org/documentation.html.
61 61 """
62 62
63 63 interactive_usage = """
64 64 IPython -- An enhanced Interactive Python
65 65 =========================================
66 66
67 67 IPython offers a combination of convenient shell features, special commands
68 68 and a history mechanism for both input (command history) and output (results
69 69 caching, similar to Mathematica). It is intended to be a fully compatible
70 70 replacement for the standard Python interpreter, while offering vastly
71 71 improved functionality and flexibility.
72 72
73 73 At your system command line, type 'ipython -h' to see the command line
74 74 options available. This document only describes interactive features.
75 75
76 76 MAIN FEATURES
77 77
78 78 * Access to the standard Python help. As of Python 2.1, a help system is
79 79 available with access to object docstrings and the Python manuals. Simply
80 80 type 'help' (no quotes) to access it.
81 81
82 82 * Magic commands: type %magic for information on the magic subsystem.
83 83
84 84 * System command aliases, via the %alias command or the configuration file(s).
85 85
86 86 * Dynamic object information:
87 87
88 88 Typing ?word or word? prints detailed information about an object. If
89 89 certain strings in the object are too long (docstrings, code, etc.) they get
90 90 snipped in the center for brevity.
91 91
92 92 Typing ??word or word?? gives access to the full information without
93 93 snipping long strings. Long strings are sent to the screen through the less
94 94 pager if longer than the screen, printed otherwise.
95 95
96 96 The ?/?? system gives access to the full source code for any object (if
97 97 available), shows function prototypes and other useful information.
98 98
99 99 If you just want to see an object's docstring, type '%pdoc object' (without
100 100 quotes, and without % if you have automagic on).
101 101
102 102 Both %pdoc and ?/?? give you access to documentation even on things which are
103 103 not explicitely defined. Try for example typing {}.get? or after import os,
104 104 type os.path.abspath??. The magic functions %pdef, %source and %file operate
105 105 similarly.
106 106
107 107 * Completion in the local namespace, by typing TAB at the prompt.
108 108
109 109 At any time, hitting tab will complete any available python commands or
110 110 variable names, and show you a list of the possible completions if there's
111 111 no unambiguous one. It will also complete filenames in the current directory.
112 112
113 113 This feature requires the readline and rlcomplete modules, so it won't work
114 114 if your Python lacks readline support (such as under Windows).
115 115
116 116 * Search previous command history in two ways (also requires readline):
117 117
118 118 - Start typing, and then use Ctrl-p (previous,up) and Ctrl-n (next,down) to
119 119 search through only the history items that match what you've typed so
120 120 far. If you use Ctrl-p/Ctrl-n at a blank prompt, they just behave like
121 121 normal arrow keys.
122 122
123 123 - Hit Ctrl-r: opens a search prompt. Begin typing and the system searches
124 124 your history for lines that match what you've typed so far, completing as
125 125 much as it can.
126 126
127 127 - %hist: search history by index (this does *not* require readline).
128 128
129 129 * Persistent command history across sessions.
130 130
131 131 * Logging of input with the ability to save and restore a working session.
132 132
133 133 * System escape with !. Typing !ls will run 'ls' in the current directory.
134 134
135 135 * The reload command does a 'deep' reload of a module: changes made to the
136 136 module since you imported will actually be available without having to exit.
137 137
138 138 * Verbose and colored exception traceback printouts. See the magic xmode and
139 139 xcolor functions for details (just type %magic).
140 140
141 141 * Input caching system:
142 142
143 143 IPython offers numbered prompts (In/Out) with input and output caching. All
144 144 input is saved and can be retrieved as variables (besides the usual arrow
145 145 key recall).
146 146
147 147 The following GLOBAL variables always exist (so don't overwrite them!):
148 148 _i: stores previous input.
149 149 _ii: next previous.
150 150 _iii: next-next previous.
151 151 _ih : a list of all input _ih[n] is the input from line n.
152 152
153 153 Additionally, global variables named _i<n> are dynamically created (<n>
154 154 being the prompt counter), such that _i<n> == _ih[<n>]
155 155
156 156 For example, what you typed at prompt 14 is available as _i14 and _ih[14].
157 157
158 158 You can create macros which contain multiple input lines from this history,
159 159 for later re-execution, with the %macro function.
160 160
161 161 The history function %hist allows you to see any part of your input history
162 162 by printing a range of the _i variables. Note that inputs which contain
163 163 magic functions (%) appear in the history with a prepended comment. This is
164 164 because they aren't really valid Python code, so you can't exec them.
165 165
166 166 * Output caching system:
167 167
168 168 For output that is returned from actions, a system similar to the input
169 169 cache exists but using _ instead of _i. Only actions that produce a result
170 170 (NOT assignments, for example) are cached. If you are familiar with
171 171 Mathematica, IPython's _ variables behave exactly like Mathematica's %
172 172 variables.
173 173
174 174 The following GLOBAL variables always exist (so don't overwrite them!):
175 175 _ (one underscore): previous output.
176 176 __ (two underscores): next previous.
177 177 ___ (three underscores): next-next previous.
178 178
179 179 Global variables named _<n> are dynamically created (<n> being the prompt
180 180 counter), such that the result of output <n> is always available as _<n>.
181 181
182 182 Finally, a global dictionary named _oh exists with entries for all lines
183 183 which generated output.
184 184
185 185 * Directory history:
186 186
187 187 Your history of visited directories is kept in the global list _dh, and the
188 188 magic %cd command can be used to go to any entry in that list.
189 189
190 190 * Auto-parentheses and auto-quotes (adapted from Nathan Gray's LazyPython)
191 191
192 192 1. Auto-parentheses
193 193 Callable objects (i.e. functions, methods, etc) can be invoked like
194 194 this (notice the commas between the arguments):
195 195 In [1]: callable_ob arg1, arg2, arg3
196 196 and the input will be translated to this:
197 197 ------> callable_ob(arg1, arg2, arg3)
198 198 You can force auto-parentheses by using '/' as the first character
199 199 of a line. For example:
200 200 In [1]: /globals # becomes 'globals()'
201 201 Note that the '/' MUST be the first character on the line! This
202 202 won't work:
203 203 In [2]: print /globals # syntax error
204 204
205 205 In most cases the automatic algorithm should work, so you should
206 206 rarely need to explicitly invoke /. One notable exception is if you
207 207 are trying to call a function with a list of tuples as arguments (the
208 208 parenthesis will confuse IPython):
209 209 In [1]: zip (1,2,3),(4,5,6) # won't work
210 210 but this will work:
211 211 In [2]: /zip (1,2,3),(4,5,6)
212 212 ------> zip ((1,2,3),(4,5,6))
213 213 Out[2]= [(1, 4), (2, 5), (3, 6)]
214 214
215 215 IPython tells you that it has altered your command line by
216 216 displaying the new command line preceded by -->. e.g.:
217 217 In [18]: callable list
218 218 -------> callable (list)
219 219
220 220 2. Auto-Quoting
221 221 You can force auto-quoting of a function's arguments by using ',' as
222 222 the first character of a line. For example:
223 223 In [1]: ,my_function /home/me # becomes my_function("/home/me")
224 224
225 225 If you use ';' instead, the whole argument is quoted as a single
226 226 string (while ',' splits on whitespace):
227 227 In [2]: ,my_function a b c # becomes my_function("a","b","c")
228 228 In [3]: ;my_function a b c # becomes my_function("a b c")
229 229
230 230 Note that the ',' MUST be the first character on the line! This
231 231 won't work:
232 232 In [4]: x = ,my_function /home/me # syntax error
233 233 """
234 234
235 235 interactive_usage_min = """\
236 236 An enhanced console for Python.
237 237 Some of its features are:
238 238 - Readline support if the readline library is present.
239 239 - Tab completion in the local namespace.
240 240 - Logging of input, see command-line options.
241 241 - System shell escape via ! , eg !ls.
242 242 - Magic commands, starting with a % (like %ls, %pwd, %cd, etc.)
243 243 - Keeps track of locally defined variables via %who, %whos.
244 244 - Show object information with a ? eg ?x or x? (use ?? for more info).
245 245 """
246 246
247 247 quick_reference = r"""
248 248 IPython -- An enhanced Interactive Python - Quick Reference Card
249 249 ================================================================
250 250
251 251 obj?, obj?? : Get help, or more help for object (also works as
252 252 ?obj, ??obj).
253 253 ?foo.*abc* : List names in 'foo' containing 'abc' in them.
254 254 %magic : Information about IPython's 'magic' % functions.
255 255
256 256 Magic functions are prefixed by %, and typically take their arguments without
257 257 parentheses, quotes or even commas for convenience.
258 258
259 259 Example magic function calls:
260 260
261 261 %alias d ls -F : 'd' is now an alias for 'ls -F'
262 262 alias d ls -F : Works if 'alias' not a python name
263 263 alist = %alias : Get list of aliases to 'alist'
264 264 cd /usr/share : Obvious. cd -<tab> to choose from visited dirs.
265 265 %cd?? : See help AND source for magic %cd
266 266
267 267 System commands:
268 268
269 269 !cp a.txt b/ : System command escape, calls os.system()
270 270 cp a.txt b/ : after %rehashx, most system commands work without !
271 271 cp ${f}.txt $bar : Variable expansion in magics and system commands
272 272 files = !ls /usr : Capture sytem command output
273 273 files.s, files.l, files.n: "a b c", ['a','b','c'], 'a\nb\nc'
274 274
275 275 History:
276 276
277 277 _i, _ii, _iii : Previous, next previous, next next previous input
278 278 _i4, _ih[2:5] : Input history line 4, lines 2-4
279 279 exec _i81 : Execute input history line #81 again
280 280 %rep 81 : Edit input history line #81
281 281 _, __, ___ : previous, next previous, next next previous output
282 282 _dh : Directory history
283 283 _oh : Output history
284 284 %hist : Command history. '%hist -g foo' search history for 'foo'
285 285
286 286 Autocall:
287 287
288 288 f 1,2 : f(1,2)
289 289 /f 1,2 : f(1,2) (forced autoparen)
290 290 ,f 1 2 : f("1","2")
291 291 ;f 1 2 : f("1 2")
292 292
293 293 Remember: TAB completion works in many contexts, not just file names
294 294 or python names.
295 295
296 296 The following magic functions are currently available:
297 297
298 298 """
299 299
300 300 gui_reference = """\
301 301 ===============================
302 302 The graphical IPython console
303 303 ===============================
304 304
305 305 This console is designed to emulate the look, feel and workflow of a terminal
306 306 environment, while adding a number of enhancements that are simply not possible
307 307 in a real terminal, such as inline syntax highlighting, true multiline editing,
308 308 inline graphics and much more.
309 309
310 310 This quick reference document contains the basic information you'll need to
311 311 know to make the most efficient use of it. For the various command line
312 312 options available at startup, type ``ipython qtconsole --help`` at the command line.
313 313
314 314
315 315 Multiline editing
316 316 =================
317 317
318 318 The graphical console is capable of true multiline editing, but it also tries
319 319 to behave intuitively like a terminal when possible. If you are used to
320 320 IPyhton's old terminal behavior, you should find the transition painless, and
321 321 once you learn a few basic keybindings it will be a much more efficient
322 322 environment.
323 323
324 324 For single expressions or indented blocks, the console behaves almost like the
325 325 terminal IPython: single expressions are immediately evaluated, and indented
326 326 blocks are evaluated once a single blank line is entered::
327 327
328 328 In [1]: print "Hello IPython!" # Enter was pressed at the end of the line
329 329 Hello IPython!
330 330
331 331 In [2]: for i in range(10):
332 332 ...: print i,
333 333 ...:
334 334 0 1 2 3 4 5 6 7 8 9
335 335
336 336 If you want to enter more than one expression in a single input block
337 337 (something not possible in the terminal), you can use ``Control-Enter`` at the
338 338 end of your first line instead of ``Enter``. At that point the console goes
339 339 into 'cell mode' and even if your inputs are not indented, it will continue
340 340 accepting arbitrarily many lines until either you enter an extra blank line or
341 341 you hit ``Shift-Enter`` (the key binding that forces execution). When a
342 342 multiline cell is entered, IPython analyzes it and executes its code producing
343 343 an ``Out[n]`` prompt only for the last expression in it, while the rest of the
344 344 cell is executed as if it was a script. An example should clarify this::
345 345
346 346 In [3]: x=1 # Hit C-Enter here
347 347 ...: y=2 # from now on, regular Enter is sufficient
348 348 ...: z=3
349 349 ...: x**2 # This does *not* produce an Out[] value
350 350 ...: x+y+z # Only the last expression does
351 351 ...:
352 352 Out[3]: 6
353 353
354 354 The behavior where an extra blank line forces execution is only active if you
355 355 are actually typing at the keyboard each line, and is meant to make it mimic
356 356 the IPython terminal behavior. If you paste a long chunk of input (for example
357 357 a long script copied form an editor or web browser), it can contain arbitrarily
358 358 many intermediate blank lines and they won't cause any problems. As always,
359 359 you can then make it execute by appending a blank line *at the end* or hitting
360 360 ``Shift-Enter`` anywhere within the cell.
361 361
362 362 With the up arrow key, you can retrieve previous blocks of input that contain
363 363 multiple lines. You can move inside of a multiline cell like you would in any
364 364 text editor. When you want it executed, the simplest thing to do is to hit the
365 365 force execution key, ``Shift-Enter`` (though you can also navigate to the end
366 366 and append a blank line by using ``Enter`` twice).
367 367
368 368 If you've edited a multiline cell and accidentally navigate out of it with the
369 369 up or down arrow keys, IPython will clear the cell and replace it with the
370 370 contents of the one above or below that you navigated to. If this was an
371 371 accident and you want to retrieve the cell you were editing, use the Undo
372 372 keybinding, ``Control-z``.
373 373
374 374
375 375 Key bindings
376 376 ============
377 377
378 378 The IPython console supports most of the basic Emacs line-oriented keybindings,
379 379 in addition to some of its own.
380 380
381 381 The keybinding prefixes mean:
382 382
383 383 - ``C``: Control
384 384 - ``S``: Shift
385 385 - ``M``: Meta (typically the Alt key)
386 386
387 387 The keybindings themselves are:
388 388
389 389 - ``Enter``: insert new line (may cause execution, see above).
390 390 - ``C-Enter``: *force* new line, *never* causes execution.
391 391 - ``S-Enter``: *force* execution regardless of where cursor is, no newline added.
392 392 - ``Up``: step backwards through the history.
393 393 - ``Down``: step forwards through the history.
394 394 - ``S-Up``: search backwards through the history (like ``C-r`` in bash).
395 395 - ``S-Down``: search forwards through the history.
396 396 - ``C-c``: copy highlighted text to clipboard (prompts are automatically stripped).
397 397 - ``C-S-c``: copy highlighted text to clipboard (prompts are not stripped).
398 398 - ``C-v``: paste text from clipboard.
399 399 - ``C-z``: undo (retrieves lost text if you move out of a cell with the arrows).
400 400 - ``C-S-z``: redo.
401 401 - ``C-o``: move to 'other' area, between pager and terminal.
402 402 - ``C-l``: clear terminal.
403 403 - ``C-a``: go to beginning of line.
404 404 - ``C-e``: go to end of line.
405 405 - ``C-k``: kill from cursor to the end of the line.
406 406 - ``C-y``: yank (paste)
407 407 - ``C-p``: previous line (like up arrow)
408 408 - ``C-n``: next line (like down arrow)
409 409 - ``C-f``: forward (like right arrow)
410 410 - ``C-b``: back (like left arrow)
411 411 - ``C-d``: delete next character.
412 412 - ``M-<``: move to the beginning of the input region.
413 413 - ``M->``: move to the end of the input region.
414 414 - ``M-d``: delete next word.
415 415 - ``M-Backspace``: delete previous word.
416 416 - ``C-.``: force a kernel restart (a confirmation dialog appears).
417 417 - ``C-+``: increase font size.
418 418 - ``C--``: decrease font size.
419 419 - ``C-M-Space``: toggle full screen. (Command-Control-Space on Mac OS X)
420 420
421 421 The IPython pager
422 422 =================
423 423
424 424 IPython will show long blocks of text from many sources using a builtin pager.
425 425 You can control where this pager appears with the ``--paging`` command-line
426 426 flag:
427 427
428 428 - ``inside`` [default]: the pager is overlaid on top of the main terminal. You
429 429 must quit the pager to get back to the terminal (similar to how a pager such
430 430 as ``less`` or ``more`` works).
431 431
432 432 - ``vsplit``: the console is made double-tall, and the pager appears on the
433 433 bottom area when needed. You can view its contents while using the terminal.
434 434
435 435 - ``hsplit``: the console is made double-wide, and the pager appears on the
436 436 right area when needed. You can view its contents while using the terminal.
437 437
438 438 - ``none``: the console never pages output.
439 439
440 440 If you use the vertical or horizontal paging modes, you can navigate between
441 441 terminal and pager as follows:
442 442
443 443 - Tab key: goes from pager to terminal (but not the other way around).
444 444 - Control-o: goes from one to another always.
445 445 - Mouse: click on either.
446 446
447 447 In all cases, the ``q`` or ``Escape`` keys quit the pager (when used with the
448 448 focus on the pager area).
449 449
450 450 Running subprocesses
451 451 ====================
452 452
453 453 The graphical IPython console uses the ``pexpect`` module to run subprocesses
454 454 when you type ``!command``. This has a number of advantages (true asynchronous
455 455 output from subprocesses as well as very robust termination of rogue
456 456 subprocesses with ``Control-C``), as well as some limitations. The main
457 457 limitation is that you can *not* interact back with the subprocess, so anything
458 458 that invokes a pager or expects you to type input into it will block and hang
459 459 (you can kill it with ``Control-C``).
460 460
461 461 We have provided as magics ``%less`` to page files (aliased to ``%more``),
462 462 ``%clear`` to clear the terminal, and ``%man`` on Linux/OSX. These cover the
463 463 most common commands you'd want to call in your subshell and that would cause
464 464 problems if invoked via ``!cmd``, but you need to be aware of this limitation.
465 465
466 466 Display
467 467 =======
468 468
469 469 The IPython console can now display objects in a variety of formats, including
470 470 HTML, PNG and SVG. This is accomplished using the display functions in
471 471 ``IPython.core.display``::
472 472
473 473 In [4]: from IPython.core.display import display, display_html
474 474
475 475 In [5]: from IPython.core.display import display_png, display_svg
476 476
477 477 Python objects can simply be passed to these functions and the appropriate
478 478 representations will be displayed in the console as long as the objects know
479 479 how to compute those representations. The easiest way of teaching objects how
480 480 to format themselves in various representations is to define special methods
481 481 such as: ``_repr_html_``, ``_repr_svg_`` and ``_repr_png_``. IPython's display formatters
482 482 can also be given custom formatter functions for various types::
483 483
484 484 In [6]: ip = get_ipython()
485 485
486 486 In [7]: html_formatter = ip.display_formatter.formatters['text/html']
487 487
488 488 In [8]: html_formatter.for_type(Foo, foo_to_html)
489 489
490 490 For further details, see ``IPython.core.formatters``.
491 491
492 492 Inline matplotlib graphics
493 493 ==========================
494 494
495 495 The IPython console is capable of displaying matplotlib figures inline, in SVG
496 496 or PNG format. If started with the ``pylab=inline``, then all figures are
497 497 rendered inline automatically (PNG by default). If started with ``--pylab``
498 498 or ``pylab=<your backend>``, then a GUI backend will be used, but IPython's
499 499 ``display()`` and ``getfigs()`` functions can be used to view plots inline::
500 500
501 501 In [9]: display(*getfigs()) # display all figures inline
502 502
503 503 In[10]: display(*getfigs(1,2)) # display figures 1 and 2 inline
504 504 """
505 505
506 506
507 507 quick_guide = """\
508 508 ? -> Introduction and overview of IPython's features.
509 509 %quickref -> Quick reference.
510 510 help -> Python's own help system.
511 511 object? -> Details about 'object', use 'object??' for extra details.
512 512 """
513 513
514 514 gui_note = """\
515 515 %guiref -> A brief reference about the graphical user interface.
516 516 """
517 517
518 518 default_banner_parts = [
519 519 'Python %s\n' % (sys.version.split('\n')[0],),
520 520 'Type "copyright", "credits" or "license" for more information.\n\n',
521 521 'IPython %s -- An enhanced Interactive Python.\n' % (release.version,),
522 522 quick_guide
523 523 ]
524 524
525 525 default_gui_banner_parts = default_banner_parts + [gui_note]
526 526
527 527 default_banner = ''.join(default_banner_parts)
528 528
529 529 default_gui_banner = ''.join(default_gui_banner_parts)
@@ -1,84 +1,84 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Modified input prompt for entering quantities with units.
3 3
4 4 Modify the behavior of the interactive interpreter to allow direct input of
5 5 quantities with units without having to make a function call.
6 6
7 7 Now the following forms are accepted:
8 8
9 9 x = 4 m
10 10 y = -.45e3 m/s
11 11 g = 9.8 m/s**2
12 12 a = 2.3 m/s^2 # ^ -> ** automatically
13 13
14 14 All other input is processed normally.
15 15
16 16 Authors
17 17 -------
18 18 - Fernando Perez <Fernando.Perez@berkeley.edu>
19 19 """
20 20 #*****************************************************************************
21 # Copyright (C) 2008-2009 The IPython Development Team
21 # Copyright (C) 2008-2011 The IPython Development Team
22 22 # Copyright (C) 2001-2007 Fernando Perez <fperez@colorado.edu>
23 23 #
24 24 # Distributed under the terms of the BSD License. The full license is in
25 25 # the file COPYING, distributed as part of this software.
26 26 #*****************************************************************************
27 27
28 28 # This file is an example of how to modify IPython's line-processing behavior
29 29 # without touching the internal code. We'll define an alternate pre-processing
30 30 # stage which allows a special form of input (which is invalid Python syntax)
31 31 # for certain quantities, rewrites a line of proper Python in those cases, and
32 32 # then passes it off to IPython's normal processor for further work.
33 33
34 34 # With this kind of customization, IPython can be adapted for many
35 35 # special-purpose scenarios providing alternate input syntaxes.
36 36
37 37 # This file can be imported like a regular module.
38 38
39 39 # IPython has a prefilter() function that analyzes each input line. We redefine
40 40 # it here to first pre-process certain forms of input
41 41
42 42 # The prototype of any alternate prefilter must be like this one (the name
43 43 # doesn't matter):
44 44 # - line is a string containing the user input line.
45 45 # - continuation is a parameter which tells us if we are processing a first line of
46 46 # user input or the second or higher of a multi-line statement.
47 47
48 48 def prefilter_PQ(self,line,continuation):
49 49 """Alternate prefilter for input of PhysicalQuantityInteractive objects.
50 50
51 51 This assumes that the function PhysicalQuantityInteractive() has been
52 52 imported."""
53 53
54 54 from re import match
55 55 from IPython.core.iplib import InteractiveShell
56 56
57 57 # This regexp is what does the real work
58 58 unit_split = match(r'\s*(\w+)\s*=\s*(-?\d*\.?\d*[eE]?-?\d*)\s+([a-zA-Z].*)',
59 59 line)
60 60
61 61 # If special input was ecnountered, process it:
62 62 if unit_split:
63 63 var,val,units = unit_split.groups()
64 64 if var and val and units:
65 65 units = units.replace('^','**')
66 66 # Now a valid line needs to be constructed for IPython to process:
67 67 line = var +" = PhysicalQuantityInteractive(" + val + ", '" + \
68 68 units + "')"
69 69 #print 'New line:',line # dbg
70 70
71 71 # In the end, always call the default IPython _prefilter() function. Note
72 72 # that self must be passed explicitly, b/c we're calling the unbound class
73 73 # method (since this method will overwrite the instance prefilter())
74 74 return InteractiveShell._prefilter(self,line,continuation)
75 75
76 76 # Rebind this to be the new IPython prefilter:
77 77 from IPython.core.iplib import InteractiveShell
78 78 InteractiveShell.prefilter = prefilter_PQ
79 79
80 80 # Clean up the namespace.
81 81 del InteractiveShell,prefilter_PQ
82 82
83 83 # Just a heads up at the console
84 84 print '*** Simplified input for physical quantities enabled.'
@@ -1,90 +1,90 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Modify the PhysicalQuantities class for more convenient interactive use.
3 3
4 4 Also redefine some math functions to operate on PhysQties with no need for
5 5 special method syntax. This just means moving them out to the global
6 6 namespace.
7 7
8 8 This module should always be loaded *after* math or Numeric, so it can
9 9 overwrite math functions with the versions that handle units.
10 10
11 11 Authors
12 12 -------
13 13 - Fernando Perez <Fernando.Perez@berkeley.edu>
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 # Copyright (C) 2001-2007 Fernando Perez <fperez@colorado.edu>
19 19 #
20 20 # Distributed under the terms of the BSD License. The full license is in
21 21 # the file COPYING, distributed as part of this software.
22 22 #*****************************************************************************
23 23
24 24 from Scientific.Physics.PhysicalQuantities import PhysicalQuantity
25 25
26 26 # This code can be set up to work with Numeric or with math for providing the
27 27 # mathematical functions. Uncomment the one you prefer to use below.
28 28
29 29 # If you use math, sin(x) won't work for x an array, only float or PhysQty
30 30 import math
31 31
32 32 # If you use Numeric, sin(x) works for x a float, PhysQty an array.
33 33 #import Numeric as math
34 34
35 35 class PhysicalQuantityFunction:
36 36 """Generic function wrapper for PhysicalQuantity instances.
37 37
38 38 Calls functions from either the math library or the instance's methods as
39 39 required. Allows using sin(theta) or sqrt(v**2) syntax irrespective of
40 40 whether theta is a pure number or a PhysicalQuantity.
41 41
42 42 This is *slow*. It's meant for convenient interactive use, not for
43 43 speed."""
44 44
45 45 def __init__(self,name):
46 46 self.name = name
47 47
48 48 def __call__(self,x):
49 49 if isinstance(x,PhysicalQuantity):
50 50 return PhysicalQuantity.__dict__[self.name](x)
51 51 else:
52 52 return math.__dict__[self.name](x)
53 53
54 54 class PhysicalQuantityInteractive(PhysicalQuantity):
55 55 """Physical quantity with units - modified for Interactive use.
56 56
57 57 Basically, the __str__ and __repr__ methods have been swapped for more
58 58 convenient interactive use. Powers are shown as ^ instead of ** and only 4
59 59 significant figures are shown.
60 60
61 61 Also adds the following aliases for commonly used methods:
62 62 b = PhysicalQuantity.inBaseUnits
63 63 u = PhysicalQuantity.inUnitsOf
64 64
65 65 These are useful when doing a lot of interactive calculations.
66 66 """
67 67
68 68 # shorthands for the most useful unit conversions
69 69 b = PhysicalQuantity.inBaseUnits # so you can just type x.b to get base units
70 70 u = PhysicalQuantity.inUnitsOf
71 71
72 72 # This can be done, but it can get dangerous when coupled with IPython's
73 73 # auto-calling. Everything ends up shown in baseunits and things like x*2
74 74 # get automatically converted to k(*2), which doesn't work.
75 75 # Probably not a good idea in general...
76 76 #__call__ = b
77 77
78 78 def __str__(self):
79 79 return PhysicalQuantity.__repr__(self)
80 80
81 81 def __repr__(self):
82 82 value = '%.4G' % self.value
83 83 units = self.unit.name().replace('**','^')
84 84 return value + ' ' + units
85 85
86 86 # implement the methods defined in PhysicalQuantity as PhysicalQuantityFunctions
87 87 sin = PhysicalQuantityFunction('sin')
88 88 cos = PhysicalQuantityFunction('cos')
89 89 tan = PhysicalQuantityFunction('tan')
90 90 sqrt = PhysicalQuantityFunction('sqrt')
@@ -1,42 +1,42 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 """
4 4 A backwards compatibility layer for IPython.Shell.
5 5
6 6 Previously, IPython had an IPython.Shell module. IPython.Shell has been moved
7 7 to IPython.core.shell and is being refactored. This new module is provided
8 8 for backwards compatability. We strongly encourage everyone to start using
9 9 the new code in IPython.core.shell.
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 15 # Distributed under the terms of the BSD License. The full license is in
16 16 # the file COPYING, distributed as part of this software.
17 17 #-----------------------------------------------------------------------------
18 18
19 19 from warnings import warn
20 20
21 21 msg = """
22 22 This module (IPython.Shell) is deprecated. The classes that were in this
23 23 module have been replaced by:
24 24
25 25 IPShell->IPython.core.iplib.InteractiveShell
26 26 IPShellEmbed->IPython.core.embed.InteractiveShellEmbed
27 27
28 28 Please migrate your code to use these classes instead.
29 29 """
30 30
31 31 warn(msg, category=DeprecationWarning, stacklevel=1)
32 32
33 33 from IPython.core.iplib import InteractiveShell as IPShell
34 34 from IPython.core.embed import InteractiveShellEmbed as IPShellEmbed
35 35
36 36 def start(user_ns=None, embedded=False):
37 37 """Return an instance of :class:`InteractiveShell`."""
38 38 if embedded:
39 39 return IPShellEmbed(user_ns=user_ns)
40 40 else:
41 41 return IPShell(user_ns=user_ns)
42 42
@@ -1,28 +1,28 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 """
4 4 A backwards compatibility layer for IPython.iplib.
5 5
6 6 Previously, IPython had an IPython.iplib module. IPython.iplib has been moved
7 7 to IPython.core.iplib and is being refactored. This new module is provided
8 8 for backwards compatability. We strongly encourage everyone to start using
9 9 the new code in IPython.core.iplib.
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 15 # Distributed under the terms of the BSD License. The full license is in
16 16 # the file COPYING, distributed as part of this software.
17 17 #-----------------------------------------------------------------------------
18 18
19 19 from warnings import warn
20 20
21 21 msg = """
22 22 This module (IPython.iplib) has been moved to a new location
23 23 (IPython.core.iplib) and is being refactored. Please update your code
24 24 to use the new IPython.core.iplib module"""
25 25
26 26 warn(msg, category=DeprecationWarning, stacklevel=1)
27 27
28 28 from IPython.core.iplib import *
@@ -1,82 +1,82 b''
1 1 """
2 2 Base front end class for all async frontends.
3 3 """
4 4 __docformat__ = "restructuredtext en"
5 5
6 6 # Tell nose to skip this module
7 7 __test__ = {}
8 8
9 9 #-------------------------------------------------------------------------------
10 # Copyright (C) 2008 The IPython Development Team
10 # Copyright (C) 2008-2011 The IPython Development Team
11 11 #
12 12 # Distributed under the terms of the BSD License. The full license is in
13 13 # the file COPYING, distributed as part of this software.
14 14 #-------------------------------------------------------------------------------
15 15
16 16 #-------------------------------------------------------------------------------
17 17 # Imports
18 18 #-------------------------------------------------------------------------------
19 19
20 20 # Third-party
21 21 from twisted.python.failure import Failure
22 22 from zope.interface import implements, classProvides
23 23
24 24 # From IPython
25 25 from IPython.external import guid
26 26
27 27 from IPython.frontend.frontendbase import (FrontEndBase, IFrontEnd,
28 28 IFrontEndFactory)
29 29 from IPython.kernel.core.history import FrontEndHistory
30 30 from IPython.kernel.engineservice import IEngineCore
31 31
32 32 #-----------------------------------------------------------------------------
33 33 # Classes and functions
34 34 #-----------------------------------------------------------------------------
35 35
36 36 class AsyncFrontEndBase(FrontEndBase):
37 37 """
38 38 Overrides FrontEndBase to wrap execute in a deferred result.
39 39 All callbacks are made as callbacks on the deferred result.
40 40 """
41 41
42 42 implements(IFrontEnd)
43 43 classProvides(IFrontEndFactory)
44 44
45 45 def __init__(self, engine=None, history=None):
46 46 assert(engine==None or IEngineCore.providedBy(engine))
47 47 self.engine = IEngineCore(engine)
48 48 if history is None:
49 49 self.history = FrontEndHistory(input_cache=[''])
50 50 else:
51 51 self.history = history
52 52
53 53 def execute(self, block, blockID=None):
54 54 """Execute the block and return the deferred result.
55 55
56 56 Parameters:
57 57 block : {str, AST}
58 58 blockID : any
59 59 Caller may provide an ID to identify this block.
60 60 result['blockID'] := blockID
61 61
62 62 Result:
63 63 Deferred result of self.interpreter.execute
64 64 """
65 65
66 66 if(not self.is_complete(block)):
67 67 return Failure(Exception("Block is not compilable"))
68 68
69 69 if(blockID == None):
70 70 blockID = guid.generate()
71 71
72 72 d = self.engine.execute(block)
73 73 d.addCallback(self._add_history, block=block)
74 74 d.addCallbacks(self._add_block_id_for_result,
75 75 errback=self._add_block_id_for_failure,
76 76 callbackArgs=(blockID,),
77 77 errbackArgs=(blockID,))
78 78 d.addBoth(self.update_cell_prompt, blockID=blockID)
79 79 d.addCallbacks(self.render_result,
80 80 errback=self.render_error)
81 81
82 82 return d
@@ -1,560 +1,560 b''
1 1 # encoding: utf-8
2 2 # -*- test-case-name: IPython.frontend.cocoa.tests.test_cocoa_frontend -*-
3 3
4 4 """PyObjC classes to provide a Cocoa frontend to the
5 5 IPython.kernel.engineservice.IEngineBase.
6 6
7 7 To add an IPython interpreter to a cocoa app, instantiate an
8 8 IPythonCocoaController in a XIB and connect its textView outlet to an
9 9 NSTextView instance in your UI. That's it.
10 10
11 11 Author: Barry Wark
12 12 """
13 13
14 14 __docformat__ = "restructuredtext en"
15 15
16 16 #-----------------------------------------------------------------------------
17 # Copyright (C) 2008 The IPython Development Team
17 # Copyright (C) 2008-2011 The IPython Development Team
18 18 #
19 19 # Distributed under the terms of the BSD License. The full license is in
20 20 # the file COPYING, distributed as part of this software.
21 21 #-----------------------------------------------------------------------------
22 22
23 23 #-----------------------------------------------------------------------------
24 24 # Imports
25 25 #-----------------------------------------------------------------------------
26 26
27 27 import sys
28 28 import objc
29 29 from IPython.external import guid
30 30
31 31 from Foundation import NSObject, NSMutableArray, NSMutableDictionary,\
32 32 NSLog, NSNotificationCenter, NSMakeRange,\
33 33 NSLocalizedString, NSIntersectionRange,\
34 34 NSString, NSAutoreleasePool
35 35
36 36 from AppKit import NSApplicationWillTerminateNotification, NSBeep,\
37 37 NSTextView, NSRulerView, NSVerticalRuler
38 38
39 39 from pprint import saferepr
40 40
41 41 import IPython
42 42 from IPython.kernel.engineservice import ThreadedEngineService
43 43 from IPython.frontend.asyncfrontendbase import AsyncFrontEndBase
44 44
45 45 from twisted.internet.threads import blockingCallFromThread
46 46 from twisted.python.failure import Failure
47 47
48 48 #-----------------------------------------------------------------------------
49 49 # Classes to implement the Cocoa frontend
50 50 #-----------------------------------------------------------------------------
51 51
52 52 # TODO:
53 53 # 1. use MultiEngineClient and out-of-process engine rather than
54 54 # ThreadedEngineService?
55 55 # 2. integrate Xgrid launching of engines
56 56
57 57 class AutoreleasePoolWrappedThreadedEngineService(ThreadedEngineService):
58 58 """Wrap all blocks in an NSAutoreleasePool"""
59 59
60 60 def wrapped_execute(self, msg, lines):
61 61 """wrapped_execute"""
62 62 try:
63 63 p = NSAutoreleasePool.alloc().init()
64 64 result = super(AutoreleasePoolWrappedThreadedEngineService,
65 65 self).wrapped_execute(msg, lines)
66 66 finally:
67 67 p.drain()
68 68
69 69 return result
70 70
71 71
72 72
73 73 class Cell(NSObject):
74 74 """
75 75 Representation of the prompts, input and output of a cell in the
76 76 frontend
77 77 """
78 78
79 79 blockNumber = objc.ivar().unsigned_long()
80 80 blockID = objc.ivar()
81 81 inputBlock = objc.ivar()
82 82 output = objc.ivar()
83 83
84 84
85 85
86 86 class CellBlock(object):
87 87 """
88 88 Storage for information about text ranges relating to a single cell
89 89 """
90 90
91 91
92 92 def __init__(self, inputPromptRange, inputRange=None, outputPromptRange=None,
93 93 outputRange=None):
94 94 super(CellBlock, self).__init__()
95 95 self.inputPromptRange = inputPromptRange
96 96 self.inputRange = inputRange
97 97 self.outputPromptRange = outputPromptRange
98 98 self.outputRange = outputRange
99 99
100 100 def update_ranges_for_insertion(self, text, textRange):
101 101 """Update ranges for text insertion at textRange"""
102 102
103 103 for r in [self.inputPromptRange,self.inputRange,
104 104 self.outputPromptRange, self.outputRange]:
105 105 if(r == None):
106 106 continue
107 107 intersection = NSIntersectionRange(r,textRange)
108 108 if(intersection.length == 0): #ranges don't intersect
109 109 if r.location >= textRange.location:
110 110 r.location += len(text)
111 111 else: #ranges intersect
112 112 if(r.location > textRange.location):
113 113 offset = len(text) - intersection.length
114 114 r.length -= offset
115 115 r.location += offset
116 116 elif(r.location == textRange.location):
117 117 r.length += len(text) - intersection.length
118 118 else:
119 119 r.length -= intersection.length
120 120
121 121
122 122 def update_ranges_for_deletion(self, textRange):
123 123 """Update ranges for text deletion at textRange"""
124 124
125 125 for r in [self.inputPromptRange,self.inputRange,
126 126 self.outputPromptRange, self.outputRange]:
127 127 if(r==None):
128 128 continue
129 129 intersection = NSIntersectionRange(r, textRange)
130 130 if(intersection.length == 0): #ranges don't intersect
131 131 if r.location >= textRange.location:
132 132 r.location -= textRange.length
133 133 else: #ranges intersect
134 134 if(r.location > textRange.location):
135 135 offset = intersection.length
136 136 r.length -= offset
137 137 r.location += offset
138 138 elif(r.location == textRange.location):
139 139 r.length += intersection.length
140 140 else:
141 141 r.length -= intersection.length
142 142
143 143 def __repr__(self):
144 144 return 'CellBlock('+ str((self.inputPromptRange,
145 145 self.inputRange,
146 146 self.outputPromptRange,
147 147 self.outputRange)) + ')'
148 148
149 149
150 150
151 151
152 152 class IPythonCocoaController(NSObject, AsyncFrontEndBase):
153 153 userNS = objc.ivar() #mirror of engine.user_ns (key=>str(value))
154 154 waitingForEngine = objc.ivar().bool()
155 155 textView = objc.IBOutlet()
156 156
157 157 def init(self):
158 158 self = super(IPythonCocoaController, self).init()
159 159 AsyncFrontEndBase.__init__(self,
160 160 engine=AutoreleasePoolWrappedThreadedEngineService())
161 161 if(self != None):
162 162 self._common_init()
163 163
164 164 return self
165 165
166 166 def _common_init(self):
167 167 """_common_init"""
168 168
169 169 self.userNS = NSMutableDictionary.dictionary()
170 170 self.waitingForEngine = False
171 171
172 172 self.lines = {}
173 173 self.tabSpaces = 4
174 174 self.tabUsesSpaces = True
175 175 self.currentBlockID = self.next_block_ID()
176 176 self.blockRanges = {} # blockID=>CellBlock
177 177
178 178
179 179 def awakeFromNib(self):
180 180 """awakeFromNib"""
181 181
182 182 self._common_init()
183 183
184 184 # Start the IPython engine
185 185 self.engine.startService()
186 186 NSLog('IPython engine started')
187 187
188 188 # Register for app termination
189 189 nc = NSNotificationCenter.defaultCenter()
190 190 nc.addObserver_selector_name_object_(
191 191 self,
192 192 'appWillTerminate:',
193 193 NSApplicationWillTerminateNotification,
194 194 None)
195 195
196 196 self.textView.setDelegate_(self)
197 197 self.textView.enclosingScrollView().setHasVerticalRuler_(True)
198 198 r = NSRulerView.alloc().initWithScrollView_orientation_(
199 199 self.textView.enclosingScrollView(),
200 200 NSVerticalRuler)
201 201 self.verticalRulerView = r
202 202 self.verticalRulerView.setClientView_(self.textView)
203 203 self._start_cli_banner()
204 204 self.start_new_block()
205 205
206 206
207 207 def appWillTerminate_(self, notification):
208 208 """appWillTerminate"""
209 209
210 210 self.engine.stopService()
211 211
212 212
213 213 def complete(self, token):
214 214 """Complete token in engine's user_ns
215 215
216 216 Parameters
217 217 ----------
218 218 token : string
219 219
220 220 Result
221 221 ------
222 222 Deferred result of
223 223 IPython.kernel.engineservice.IEngineBase.complete
224 224 """
225 225
226 226 return self.engine.complete(token)
227 227
228 228
229 229 def execute(self, block, blockID=None):
230 230 self.waitingForEngine = True
231 231 self.willChangeValueForKey_('commandHistory')
232 232 d = super(IPythonCocoaController, self).execute(block,
233 233 blockID)
234 234 d.addBoth(self._engine_done)
235 235 d.addCallback(self._update_user_ns)
236 236
237 237 return d
238 238
239 239
240 240 def push_(self, namespace):
241 241 """Push dictionary of key=>values to python namespace"""
242 242
243 243 self.waitingForEngine = True
244 244 self.willChangeValueForKey_('commandHistory')
245 245 d = self.engine.push(namespace)
246 246 d.addBoth(self._engine_done)
247 247 d.addCallback(self._update_user_ns)
248 248
249 249
250 250 def pull_(self, keys):
251 251 """Pull keys from python namespace"""
252 252
253 253 self.waitingForEngine = True
254 254 result = blockingCallFromThread(self.engine.pull, keys)
255 255 self.waitingForEngine = False
256 256
257 257 @objc.signature('v@:@I')
258 258 def executeFileAtPath_encoding_(self, path, encoding):
259 259 """Execute file at path in an empty namespace. Update the engine
260 260 user_ns with the resulting locals."""
261 261
262 262 lines,err = NSString.stringWithContentsOfFile_encoding_error_(
263 263 path,
264 264 encoding,
265 265 None)
266 266 self.engine.execute(lines)
267 267
268 268
269 269 def _engine_done(self, x):
270 270 self.waitingForEngine = False
271 271 self.didChangeValueForKey_('commandHistory')
272 272 return x
273 273
274 274 def _update_user_ns(self, result):
275 275 """Update self.userNS from self.engine's namespace"""
276 276 d = self.engine.keys()
277 277 d.addCallback(self._get_engine_namespace_values_for_keys)
278 278
279 279 return result
280 280
281 281
282 282 def _get_engine_namespace_values_for_keys(self, keys):
283 283 d = self.engine.pull(keys)
284 284 d.addCallback(self._store_engine_namespace_values, keys=keys)
285 285
286 286
287 287 def _store_engine_namespace_values(self, values, keys=[]):
288 288 assert(len(values) == len(keys))
289 289 self.willChangeValueForKey_('userNS')
290 290 for (k,v) in zip(keys,values):
291 291 self.userNS[k] = saferepr(v)
292 292 self.didChangeValueForKey_('userNS')
293 293
294 294
295 295 def update_cell_prompt(self, result, blockID=None):
296 296 print self.blockRanges
297 297 if(isinstance(result, Failure)):
298 298 prompt = self.input_prompt()
299 299
300 300 else:
301 301 prompt = self.input_prompt(number=result['number'])
302 302
303 303 r = self.blockRanges[blockID].inputPromptRange
304 304 self.insert_text(prompt,
305 305 textRange=r,
306 306 scrollToVisible=False
307 307 )
308 308
309 309 return result
310 310
311 311
312 312 def render_result(self, result):
313 313 blockID = result['blockID']
314 314 inputRange = self.blockRanges[blockID].inputRange
315 315 del self.blockRanges[blockID]
316 316
317 317 #print inputRange,self.current_block_range()
318 318 self.insert_text('\n' +
319 319 self.output_prompt(number=result['number']) +
320 320 result.get('display',{}).get('pprint','') +
321 321 '\n\n',
322 322 textRange=NSMakeRange(inputRange.location+inputRange.length,
323 323 0))
324 324 return result
325 325
326 326
327 327 def render_error(self, failure):
328 328 print failure
329 329 blockID = failure.blockID
330 330 inputRange = self.blockRanges[blockID].inputRange
331 331 self.insert_text('\n' +
332 332 self.output_prompt() +
333 333 '\n' +
334 334 failure.getErrorMessage() +
335 335 '\n\n',
336 336 textRange=NSMakeRange(inputRange.location +
337 337 inputRange.length,
338 338 0))
339 339 self.start_new_block()
340 340 return failure
341 341
342 342
343 343 def _start_cli_banner(self):
344 344 """Print banner"""
345 345
346 346 banner = """IPython1 %s -- An enhanced Interactive Python.""" % \
347 347 IPython.__version__
348 348
349 349 self.insert_text(banner + '\n\n')
350 350
351 351
352 352 def start_new_block(self):
353 353 """"""
354 354
355 355 self.currentBlockID = self.next_block_ID()
356 356 self.blockRanges[self.currentBlockID] = self.new_cell_block()
357 357 self.insert_text(self.input_prompt(),
358 358 textRange=self.current_block_range().inputPromptRange)
359 359
360 360
361 361
362 362 def next_block_ID(self):
363 363
364 364 return guid.generate()
365 365
366 366 def new_cell_block(self):
367 367 """A new CellBlock at the end of self.textView.textStorage()"""
368 368
369 369 return CellBlock(NSMakeRange(self.textView.textStorage().length(),
370 370 0), #len(self.input_prompt())),
371 371 NSMakeRange(self.textView.textStorage().length(),# + len(self.input_prompt()),
372 372 0))
373 373
374 374
375 375 def current_block_range(self):
376 376 return self.blockRanges.get(self.currentBlockID,
377 377 self.new_cell_block())
378 378
379 379 def current_block(self):
380 380 """The current block's text"""
381 381
382 382 return self.text_for_range(self.current_block_range().inputRange)
383 383
384 384 def text_for_range(self, textRange):
385 385 """text_for_range"""
386 386
387 387 ts = self.textView.textStorage()
388 388 return ts.string().substringWithRange_(textRange)
389 389
390 390 def current_line(self):
391 391 block = self.text_for_range(self.current_block_range().inputRange)
392 392 block = block.split('\n')
393 393 return block[-1]
394 394
395 395
396 396 def insert_text(self, string=None, textRange=None, scrollToVisible=True):
397 397 """Insert text into textView at textRange, updating blockRanges
398 398 as necessary
399 399 """
400 400 if(textRange == None):
401 401 #range for end of text
402 402 textRange = NSMakeRange(self.textView.textStorage().length(), 0)
403 403
404 404
405 405 self.textView.replaceCharactersInRange_withString_(
406 406 textRange, string)
407 407
408 408 for r in self.blockRanges.itervalues():
409 409 r.update_ranges_for_insertion(string, textRange)
410 410
411 411 self.textView.setSelectedRange_(textRange)
412 412 if(scrollToVisible):
413 413 self.textView.scrollRangeToVisible_(textRange)
414 414
415 415
416 416
417 417 def replace_current_block_with_string(self, textView, string):
418 418 textView.replaceCharactersInRange_withString_(
419 419 self.current_block_range().inputRange,
420 420 string)
421 421 self.current_block_range().inputRange.length = len(string)
422 422 r = NSMakeRange(textView.textStorage().length(), 0)
423 423 textView.scrollRangeToVisible_(r)
424 424 textView.setSelectedRange_(r)
425 425
426 426
427 427 def current_indent_string(self):
428 428 """returns string for indent or None if no indent"""
429 429
430 430 return self._indent_for_block(self.current_block())
431 431
432 432
433 433 def _indent_for_block(self, block):
434 434 lines = block.split('\n')
435 435 if(len(lines) > 1):
436 436 currentIndent = len(lines[-1]) - len(lines[-1].lstrip())
437 437 if(currentIndent == 0):
438 438 currentIndent = self.tabSpaces
439 439
440 440 if(self.tabUsesSpaces):
441 441 result = ' ' * currentIndent
442 442 else:
443 443 result = '\t' * (currentIndent/self.tabSpaces)
444 444 else:
445 445 result = None
446 446
447 447 return result
448 448
449 449
450 450 # NSTextView delegate methods...
451 451 def textView_doCommandBySelector_(self, textView, selector):
452 452 assert(textView == self.textView)
453 453 NSLog("textView_doCommandBySelector_: "+selector)
454 454
455 455
456 456 if(selector == 'insertNewline:'):
457 457 indent = self.current_indent_string()
458 458 if(indent):
459 459 line = indent + self.current_line()
460 460 else:
461 461 line = self.current_line()
462 462
463 463 if(self.is_complete(self.current_block())):
464 464 self.execute(self.current_block(),
465 465 blockID=self.currentBlockID)
466 466 self.start_new_block()
467 467
468 468 return True
469 469
470 470 return False
471 471
472 472 elif(selector == 'moveUp:'):
473 473 prevBlock = self.get_history_previous(self.current_block())
474 474 if(prevBlock != None):
475 475 self.replace_current_block_with_string(textView, prevBlock)
476 476 else:
477 477 NSBeep()
478 478 return True
479 479
480 480 elif(selector == 'moveDown:'):
481 481 nextBlock = self.get_history_next()
482 482 if(nextBlock != None):
483 483 self.replace_current_block_with_string(textView, nextBlock)
484 484 else:
485 485 NSBeep()
486 486 return True
487 487
488 488 elif(selector == 'moveToBeginningOfParagraph:'):
489 489 textView.setSelectedRange_(NSMakeRange(
490 490 self.current_block_range().inputRange.location,
491 491 0))
492 492 return True
493 493 elif(selector == 'moveToEndOfParagraph:'):
494 494 textView.setSelectedRange_(NSMakeRange(
495 495 self.current_block_range().inputRange.location + \
496 496 self.current_block_range().inputRange.length, 0))
497 497 return True
498 498 elif(selector == 'deleteToEndOfParagraph:'):
499 499 if(textView.selectedRange().location <= \
500 500 self.current_block_range().location):
501 501 raise NotImplemented()
502 502
503 503 return False # don't actually handle the delete
504 504
505 505 elif(selector == 'insertTab:'):
506 506 if(len(self.current_line().strip()) == 0): #only white space
507 507 return False
508 508 else:
509 509 self.textView.complete_(self)
510 510 return True
511 511
512 512 elif(selector == 'deleteBackward:'):
513 513 #if we're at the beginning of the current block, ignore
514 514 if(textView.selectedRange().location == \
515 515 self.current_block_range().inputRange.location):
516 516 return True
517 517 else:
518 518 for r in self.blockRanges.itervalues():
519 519 deleteRange = textView.selectedRange
520 520 if(deleteRange.length == 0):
521 521 deleteRange.location -= 1
522 522 deleteRange.length = 1
523 523 r.update_ranges_for_deletion(deleteRange)
524 524 return False
525 525 return False
526 526
527 527
528 528 def textView_shouldChangeTextInRanges_replacementStrings_(self,
529 529 textView, ranges, replacementStrings):
530 530 """
531 531 Delegate method for NSTextView.
532 532
533 533 Refuse change text in ranges not at end, but make those changes at
534 534 end.
535 535 """
536 536
537 537 assert(len(ranges) == len(replacementStrings))
538 538 allow = True
539 539 for r,s in zip(ranges, replacementStrings):
540 540 r = r.rangeValue()
541 541 if(textView.textStorage().length() > 0 and
542 542 r.location < self.current_block_range().inputRange.location):
543 543 self.insert_text(s)
544 544 allow = False
545 545
546 546 return allow
547 547
548 548 def textView_completions_forPartialWordRange_indexOfSelectedItem_(self,
549 549 textView, words, charRange, index):
550 550 try:
551 551 ts = textView.textStorage()
552 552 token = ts.string().substringWithRange_(charRange)
553 553 completions = blockingCallFromThread(self.complete, token)
554 554 except:
555 555 completions = objc.nil
556 556 NSBeep()
557 557
558 558 return (completions,0)
559 559
560 560
@@ -1,25 +1,25 b''
1 1 # encoding: utf-8
2 2 """
3 3 Provides a namespace for loading the Cocoa frontend via a Cocoa plugin.
4 4
5 5 Author: Barry Wark
6 6 """
7 7 __docformat__ = "restructuredtext en"
8 8
9 9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2008 The IPython Development Team
10 # Copyright (C) 2008-2011 The IPython Development Team
11 11 #
12 12 # Distributed under the terms of the BSD License. The full license is in
13 13 # the file COPYING, distributed as part of this software.
14 14 #-----------------------------------------------------------------------------
15 15
16 16 from PyObjCTools import AppHelper
17 17 from twisted.internet import _threadedselect
18 18
19 19 #make sure _threadedselect is installed first
20 20 reactor = _threadedselect.install()
21 21
22 22 # load the Cocoa frontend controller
23 23 from IPython.frontend.cocoa.cocoa_frontend import IPythonCocoaController
24 24 reactor.interleave(AppHelper.callAfter)
25 25 assert(reactor.running)
@@ -1,35 +1,35 b''
1 1 # encoding: utf-8
2 2 """
3 3 setup.py
4 4
5 5 Setuptools installer script for generating a Cocoa plugin for the
6 6 IPython cocoa frontend
7 7
8 8 Author: Barry Wark
9 9 """
10 10 __docformat__ = "restructuredtext en"
11 11
12 12 #-----------------------------------------------------------------------------
13 # Copyright (C) 2008 The IPython Development Team
13 # Copyright (C) 2008-2011 The IPython Development Team
14 14 #
15 15 # Distributed under the terms of the BSD License. The full license is in
16 16 # the file COPYING, distributed as part of this software.
17 17 #-----------------------------------------------------------------------------
18 18
19 19 from setuptools import setup
20 20
21 21 infoPlist = dict(
22 22 CFBundleDevelopmentRegion='English',
23 23 CFBundleIdentifier='org.scipy.ipython.cocoa_frontend',
24 24 NSPrincipalClass='IPythonCocoaController',
25 25 )
26 26
27 27 setup(
28 28 plugin=['IPythonCocoaFrontendLoader.py'],
29 29 setup_requires=['py2app'],
30 30 options=dict(py2app=dict(
31 31 plist=infoPlist,
32 32 site_packages=True,
33 33 excludes=['IPython','twisted','PyObjCTools']
34 34 )),
35 35 ) No newline at end of file
@@ -1,100 +1,100 b''
1 1 # encoding: utf-8
2 2 """This file contains unittests for the
3 3 IPython.frontend.cocoa.cocoa_frontend module.
4 4 """
5 5 __docformat__ = "restructuredtext en"
6 6
7 7 #---------------------------------------------------------------------------
8 # Copyright (C) 2005 The IPython Development Team
8 # Copyright (C) 2005-2011 The IPython Development Team
9 9 #
10 10 # Distributed under the terms of the BSD License. The full license is in
11 11 # the file COPYING, distributed as part of this software.
12 12 #---------------------------------------------------------------------------
13 13
14 14 #---------------------------------------------------------------------------
15 15 # Imports
16 16 #---------------------------------------------------------------------------
17 17
18 18 # Tell nose to skip this module
19 19 __test__ = {}
20 20
21 21 from twisted.trial import unittest
22 22 from twisted.internet.defer import succeed
23 23
24 24 from IPython.kernel.core.interpreter import Interpreter
25 25 import IPython.kernel.engineservice as es
26 26
27 27 try:
28 28 from IPython.frontend.cocoa.cocoa_frontend import IPythonCocoaController
29 29 from Foundation import NSMakeRect
30 30 from AppKit import NSTextView, NSScrollView
31 31 except ImportError:
32 32 # This tells twisted.trial to skip this module if PyObjC is not found
33 33 skip = True
34 34
35 35 #---------------------------------------------------------------------------
36 36 # Tests
37 37 #---------------------------------------------------------------------------
38 38 class TestIPythonCocoaControler(unittest.TestCase):
39 39 """Tests for IPythonCocoaController"""
40 40
41 41 def setUp(self):
42 42 self.controller = IPythonCocoaController.alloc().init()
43 43 self.engine = es.EngineService()
44 44 self.engine.startService()
45 45
46 46 def tearDown(self):
47 47 self.controller = None
48 48 self.engine.stopService()
49 49
50 50 def testControllerExecutesCode(self):
51 51 code ="""5+5"""
52 52 expected = Interpreter().execute(code)
53 53 del expected['number']
54 54 def removeNumberAndID(result):
55 55 del result['number']
56 56 del result['id']
57 57 return result
58 58 d = self.controller.execute(code)
59 59 d.addCallback(removeNumberAndID)
60 60 d.addCallback(lambda r: self.assertEquals(r, expected))
61 61
62 62 def testControllerMirrorsUserNSWithValuesAsStrings(self):
63 63 code = """userns1=1;userns2=2"""
64 64 def testControllerUserNS(result):
65 65 self.assertEquals(self.controller.userNS['userns1'], 1)
66 66 self.assertEquals(self.controller.userNS['userns2'], 2)
67 67 self.controller.execute(code).addCallback(testControllerUserNS)
68 68
69 69 def testControllerInstantiatesIEngine(self):
70 70 self.assert_(es.IEngineBase.providedBy(self.controller.engine))
71 71
72 72 def testControllerCompletesToken(self):
73 73 code = """longNameVariable=10"""
74 74 def testCompletes(result):
75 75 self.assert_("longNameVariable" in result)
76 76
77 77 def testCompleteToken(result):
78 78 self.controller.complete("longNa").addCallback(testCompletes)
79 79
80 80 self.controller.execute(code).addCallback(testCompletes)
81 81
82 82
83 83 def testCurrentIndent(self):
84 84 """test that current_indent_string returns current indent or None.
85 85 Uses _indent_for_block for direct unit testing.
86 86 """
87 87
88 88 self.controller.tabUsesSpaces = True
89 89 self.assert_(self.controller._indent_for_block("""a=3""") == None)
90 90 self.assert_(self.controller._indent_for_block("") == None)
91 91 block = """def test():\n a=3"""
92 92 self.assert_(self.controller._indent_for_block(block) == \
93 93 ' ' * self.controller.tabSpaces)
94 94
95 95 block = """if(True):\n%sif(False):\n%spass""" % \
96 96 (' '*self.controller.tabSpaces,
97 97 2*' '*self.controller.tabSpaces)
98 98 self.assert_(self.controller._indent_for_block(block) == \
99 99 2*(' '*self.controller.tabSpaces))
100 100
@@ -1,343 +1,343 b''
1 1 # encoding: utf-8
2 2 # -*- test-case-name: IPython.frontend.tests.test_frontendbase -*-
3 3 """
4 4 frontendbase provides an interface and base class for GUI frontends for
5 5 IPython.kernel/IPython.kernel.core.
6 6
7 7 Frontend implementations will likely want to subclass FrontEndBase.
8 8
9 9 Author: Barry Wark
10 10 """
11 11 __docformat__ = "restructuredtext en"
12 12
13 13 #-------------------------------------------------------------------------------
14 # Copyright (C) 2008 The IPython Development Team
14 # Copyright (C) 2008-2011 The IPython Development Team
15 15 #
16 16 # Distributed under the terms of the BSD License. The full license is in
17 17 # the file COPYING, distributed as part of this software.
18 18 #-------------------------------------------------------------------------------
19 19
20 20 #-------------------------------------------------------------------------------
21 21 # Imports
22 22 #-------------------------------------------------------------------------------
23 23 import string
24 24 import codeop
25 25 from IPython.external import guid
26 26
27 27
28 28 from IPython.frontend.zopeinterface import (
29 29 Interface,
30 30 Attribute,
31 31 )
32 32 from IPython.kernel.core.history import FrontEndHistory
33 33 from IPython.kernel.core.util import Bunch
34 34
35 35 ##############################################################################
36 36 # TEMPORARY!!! fake configuration, while we decide whether to use tconfig or
37 37 # not
38 38
39 39 rc = Bunch()
40 40 rc.prompt_in1 = r'In [$number]: '
41 41 rc.prompt_in2 = r'...'
42 42 rc.prompt_out = r'Out [$number]: '
43 43
44 44 ##############################################################################
45 45 # Interface definitions
46 46 ##############################################################################
47 47
48 48 class IFrontEndFactory(Interface):
49 49 """Factory interface for frontends."""
50 50
51 51 def __call__(engine=None, history=None):
52 52 """
53 53 Parameters:
54 54 interpreter : IPython.kernel.engineservice.IEngineCore
55 55 """
56 56
57 57 pass
58 58
59 59
60 60 class IFrontEnd(Interface):
61 61 """Interface for frontends. All methods return t.i.d.Deferred"""
62 62
63 63 Attribute("input_prompt_template", "string.Template instance\
64 64 substituteable with execute result.")
65 65 Attribute("output_prompt_template", "string.Template instance\
66 66 substituteable with execute result.")
67 67 Attribute("continuation_prompt_template", "string.Template instance\
68 68 substituteable with execute result.")
69 69
70 70 def update_cell_prompt(result, blockID=None):
71 71 """Subclass may override to update the input prompt for a block.
72 72
73 73 In asynchronous frontends, this method will be called as a
74 74 twisted.internet.defer.Deferred's callback/errback.
75 75 Implementations should thus return result when finished.
76 76
77 77 Result is a result dict in case of success, and a
78 78 twisted.python.util.failure.Failure in case of an error
79 79 """
80 80
81 81 pass
82 82
83 83 def render_result(result):
84 84 """Render the result of an execute call. Implementors may choose the
85 85 method of rendering.
86 86 For example, a notebook-style frontend might render a Chaco plot
87 87 inline.
88 88
89 89 Parameters:
90 90 result : dict (result of IEngineBase.execute )
91 91 blockID = result['blockID']
92 92
93 93 Result:
94 94 Output of frontend rendering
95 95 """
96 96
97 97 pass
98 98
99 99 def render_error(failure):
100 100 """Subclasses must override to render the failure.
101 101
102 102 In asynchronous frontend, since this method will be called as a
103 103 twisted.internet.defer.Deferred's callback. Implementations
104 104 should thus return result when finished.
105 105
106 106 blockID = failure.blockID
107 107 """
108 108
109 109 pass
110 110
111 111 def input_prompt(number=''):
112 112 """Returns the input prompt by subsituting into
113 113 self.input_prompt_template
114 114 """
115 115 pass
116 116
117 117 def output_prompt(number=''):
118 118 """Returns the output prompt by subsituting into
119 119 self.output_prompt_template
120 120 """
121 121
122 122 pass
123 123
124 124 def continuation_prompt():
125 125 """Returns the continuation prompt by subsituting into
126 126 self.continuation_prompt_template
127 127 """
128 128
129 129 pass
130 130
131 131 def is_complete(block):
132 132 """Returns True if block is complete, False otherwise."""
133 133
134 134 pass
135 135
136 136
137 137 def get_history_previous(current_block):
138 138 """Returns the block previous in the history. Saves currentBlock if
139 139 the history_cursor is currently at the end of the input history"""
140 140 pass
141 141
142 142 def get_history_next():
143 143 """Returns the next block in the history."""
144 144
145 145 pass
146 146
147 147 def complete(self, line):
148 148 """Returns the list of possible completions, and the completed
149 149 line.
150 150
151 151 The input argument is the full line to be completed. This method
152 152 returns both the line completed as much as possible, and the list
153 153 of further possible completions (full words).
154 154 """
155 155 pass
156 156
157 157
158 158 ##############################################################################
159 159 # Base class for all the frontends.
160 160 ##############################################################################
161 161
162 162 class FrontEndBase(object):
163 163 """
164 164 FrontEndBase manages the state tasks for a CLI frontend:
165 165 - Input and output history management
166 166 - Input/continuation and output prompt generation
167 167
168 168 Some issues (due to possibly unavailable engine):
169 169 - How do we get the current cell number for the engine?
170 170 - How do we handle completions?
171 171 """
172 172
173 173 history_cursor = 0
174 174
175 175 input_prompt_template = string.Template(rc.prompt_in1)
176 176 output_prompt_template = string.Template(rc.prompt_out)
177 177 continuation_prompt_template = string.Template(rc.prompt_in2)
178 178
179 179 def __init__(self, shell=None, history=None):
180 180 self.shell = shell
181 181 if history is None:
182 182 self.history = FrontEndHistory(input_cache=[''])
183 183 else:
184 184 self.history = history
185 185
186 186
187 187 def input_prompt(self, number=''):
188 188 """Returns the current input prompt
189 189
190 190 It would be great to use ipython1.core.prompts.Prompt1 here
191 191 """
192 192 return self.input_prompt_template.safe_substitute({'number':number})
193 193
194 194
195 195 def continuation_prompt(self):
196 196 """Returns the current continuation prompt"""
197 197
198 198 return self.continuation_prompt_template.safe_substitute()
199 199
200 200 def output_prompt(self, number=''):
201 201 """Returns the output prompt for result"""
202 202
203 203 return self.output_prompt_template.safe_substitute({'number':number})
204 204
205 205
206 206 def is_complete(self, block):
207 207 """Determine if block is complete.
208 208
209 209 Parameters
210 210 block : string
211 211
212 212 Result
213 213 True if block can be sent to the engine without compile errors.
214 214 False otherwise.
215 215 """
216 216
217 217 try:
218 218 is_complete = codeop.compile_command(block.rstrip() + '\n\n',
219 219 "<string>", "exec")
220 220 except:
221 221 return False
222 222
223 223 lines = block.split('\n')
224 224 return ((is_complete is not None)
225 225 and (len(lines)==1 or str(lines[-1])==''))
226 226
227 227
228 228 def execute(self, block, blockID=None):
229 229 """Execute the block and return the result.
230 230
231 231 Parameters:
232 232 block : {str, AST}
233 233 blockID : any
234 234 Caller may provide an ID to identify this block.
235 235 result['blockID'] := blockID
236 236
237 237 Result:
238 238 Deferred result of self.interpreter.execute
239 239 """
240 240
241 241 if(not self.is_complete(block)):
242 242 raise Exception("Block is not compilable")
243 243
244 244 if(blockID == None):
245 245 blockID = guid.generate()
246 246
247 247 try:
248 248 result = self.shell.execute(block)
249 249 except Exception,e:
250 250 e = self._add_block_id_for_failure(e, blockID=blockID)
251 251 e = self.update_cell_prompt(e, blockID=blockID)
252 252 e = self.render_error(e)
253 253 else:
254 254 result = self._add_block_id_for_result(result, blockID=blockID)
255 255 result = self.update_cell_prompt(result, blockID=blockID)
256 256 result = self.render_result(result)
257 257
258 258 return result
259 259
260 260
261 261 def _add_block_id_for_result(self, result, blockID):
262 262 """Add the blockID to result or failure. Unfortunatley, we have to
263 263 treat failures differently than result dicts.
264 264 """
265 265
266 266 result['blockID'] = blockID
267 267
268 268 return result
269 269
270 270 def _add_block_id_for_failure(self, failure, blockID):
271 271 """_add_block_id_for_failure"""
272 272 failure.blockID = blockID
273 273 return failure
274 274
275 275
276 276 def _add_history(self, result, block=None):
277 277 """Add block to the history"""
278 278
279 279 assert(block != None)
280 280 self.history.add_items([block])
281 281 self.history_cursor += 1
282 282
283 283 return result
284 284
285 285
286 286 def get_history_previous(self, current_block):
287 287 """ Returns previous history string and decrement history cursor.
288 288 """
289 289 command = self.history.get_history_item(self.history_cursor - 1)
290 290
291 291 if command is not None:
292 292 if(self.history_cursor+1 == len(self.history.input_cache)):
293 293 self.history.input_cache[self.history_cursor] = current_block
294 294 self.history_cursor -= 1
295 295 return command
296 296
297 297
298 298 def get_history_next(self):
299 299 """ Returns next history string and increment history cursor.
300 300 """
301 301 command = self.history.get_history_item(self.history_cursor+1)
302 302
303 303 if command is not None:
304 304 self.history_cursor += 1
305 305 return command
306 306
307 307 ###
308 308 # Subclasses probably want to override these methods...
309 309 ###
310 310
311 311 def update_cell_prompt(self, result, blockID=None):
312 312 """Subclass may override to update the input prompt for a block.
313 313
314 314 This method only really makes sens in asyncrhonous frontend.
315 315 Since this method will be called as a
316 316 twisted.internet.defer.Deferred's callback, implementations should
317 317 return result when finished.
318 318 """
319 319
320 320 raise NotImplementedError
321 321
322 322
323 323 def render_result(self, result):
324 324 """Subclasses must override to render result.
325 325
326 326 In asynchronous frontends, this method will be called as a
327 327 twisted.internet.defer.Deferred's callback. Implementations
328 328 should thus return result when finished.
329 329 """
330 330
331 331 raise NotImplementedError
332 332
333 333
334 334 def render_error(self, failure):
335 335 """Subclasses must override to render the failure.
336 336
337 337 In asynchronous frontends, this method will be called as a
338 338 twisted.internet.defer.Deferred's callback. Implementations
339 339 should thus return result when finished.
340 340 """
341 341
342 342 raise NotImplementedError
343 343
@@ -1,373 +1,373 b''
1 1 """
2 2 Base front end class for all line-oriented frontends, rather than
3 3 block-oriented.
4 4
5 5 Currently this focuses on synchronous frontends.
6 6 """
7 7 __docformat__ = "restructuredtext en"
8 8
9 9 #-------------------------------------------------------------------------------
10 # Copyright (C) 2008 The IPython Development Team
10 # Copyright (C) 2008-2011 The IPython Development Team
11 11 #
12 12 # Distributed under the terms of the BSD License. The full license is in
13 13 # the file COPYING, distributed as part of this software.
14 14 #-------------------------------------------------------------------------------
15 15
16 16 #-------------------------------------------------------------------------------
17 17 # Imports
18 18 #-------------------------------------------------------------------------------
19 19 import re
20 20
21 21 import sys
22 22 import codeop
23 23
24 24 from frontendbase import FrontEndBase
25 25 from IPython.kernel.core.interpreter import Interpreter
26 26
27 27 def common_prefix(strings):
28 28 """ Given a list of strings, return the common prefix between all
29 29 these strings.
30 30 """
31 31 ref = strings[0]
32 32 prefix = ''
33 33 for size in range(len(ref)):
34 34 test_prefix = ref[:size+1]
35 35 for string in strings[1:]:
36 36 if not string.startswith(test_prefix):
37 37 return prefix
38 38 prefix = test_prefix
39 39
40 40 return prefix
41 41
42 42 #-----------------------------------------------------------------------------
43 43 # Base class for the line-oriented front ends
44 44 #-----------------------------------------------------------------------------
45 45
46 46 class LineFrontEndBase(FrontEndBase):
47 47 """ Concrete implementation of the FrontEndBase class. This is meant
48 48 to be the base class behind all the frontend that are line-oriented,
49 49 rather than block-oriented.
50 50 """
51 51
52 52 # We need to keep the prompt number, to be able to increment
53 53 # it when there is an exception.
54 54 prompt_number = 1
55 55
56 56 # We keep a reference to the last result: it helps testing and
57 57 # programatic control of the frontend.
58 58 last_result = dict(number=0)
59 59
60 60 # The last prompt displayed. Useful for continuation prompts.
61 61 last_prompt = ''
62 62
63 63 # The input buffer being edited
64 64 input_buffer = ''
65 65
66 66 # Set to true for debug output
67 67 debug = False
68 68
69 69 # A banner to print at startup
70 70 banner = None
71 71
72 72 #--------------------------------------------------------------------------
73 73 # FrontEndBase interface
74 74 #--------------------------------------------------------------------------
75 75
76 76 def __init__(self, shell=None, history=None, banner=None, *args, **kwargs):
77 77 if shell is None:
78 78 shell = Interpreter()
79 79 FrontEndBase.__init__(self, shell=shell, history=history)
80 80
81 81 if banner is not None:
82 82 self.banner = banner
83 83
84 84 def start(self):
85 85 """ Put the frontend in a state where it is ready for user
86 86 interaction.
87 87 """
88 88 if self.banner is not None:
89 89 self.write(self.banner, refresh=False)
90 90
91 91 self.new_prompt(self.input_prompt_template.substitute(number=1))
92 92
93 93
94 94 def complete(self, line):
95 95 """Complete line in engine's user_ns
96 96
97 97 Parameters
98 98 ----------
99 99 line : string
100 100
101 101 Returns
102 102 -------
103 103 The replacement for the line and the list of possible completions.
104 104 """
105 105 completions = self.shell.complete(line)
106 106 complete_sep = re.compile('[\s\{\}\[\]\(\)\=]')
107 107 if completions:
108 108 prefix = common_prefix(completions)
109 109 residual = complete_sep.split(line)[:-1]
110 110 line = line[:-len(residual)] + prefix
111 111 return line, completions
112 112
113 113
114 114 def render_result(self, result):
115 115 """ Frontend-specific rendering of the result of a calculation
116 116 that has been sent to an engine.
117 117 """
118 118 if 'stdout' in result and result['stdout']:
119 119 self.write('\n' + result['stdout'])
120 120 if 'display' in result and result['display']:
121 121 self.write("%s%s\n" % (
122 122 self.output_prompt_template.substitute(
123 123 number=result['number']),
124 124 result['display']['pprint']
125 125 ) )
126 126
127 127
128 128 def render_error(self, failure):
129 129 """ Frontend-specific rendering of error.
130 130 """
131 131 self.write('\n\n'+str(failure)+'\n\n')
132 132 return failure
133 133
134 134
135 135 def is_complete(self, string):
136 136 """ Check if a string forms a complete, executable set of
137 137 commands.
138 138
139 139 For the line-oriented frontend, multi-line code is not executed
140 140 as soon as it is complete: the users has to enter two line
141 141 returns.
142 142 """
143 143 if string in ('', '\n'):
144 144 # Prefiltering, eg through ipython0, may return an empty
145 145 # string although some operations have been accomplished. We
146 146 # thus want to consider an empty string as a complete
147 147 # statement.
148 148 return True
149 149 elif ( len(self.input_buffer.split('\n'))>2
150 150 and not re.findall(r"\n[\t ]*\n[\t ]*$", string)):
151 151 return False
152 152 else:
153 153 self.capture_output()
154 154 try:
155 155 # Add line returns here, to make sure that the statement is
156 156 # complete (except if '\' was used).
157 157 # This should probably be done in a different place (like
158 158 # maybe 'prefilter_input' method? For now, this works.
159 159 clean_string = string.rstrip('\n')
160 160 if not clean_string.endswith('\\'): clean_string +='\n\n'
161 161 is_complete = codeop.compile_command(clean_string,
162 162 "<string>", "exec")
163 163 self.release_output()
164 164 except Exception, e:
165 165 # XXX: Hack: return True so that the
166 166 # code gets executed and the error captured.
167 167 is_complete = True
168 168 return is_complete
169 169
170 170
171 171 def write(self, string, refresh=True):
172 172 """ Write some characters to the display.
173 173
174 174 Subclass should overide this method.
175 175
176 176 The refresh keyword argument is used in frontends with an
177 177 event loop, to choose whether the write should trigget an UI
178 178 refresh, and thus be syncrhonous, or not.
179 179 """
180 180 print >>sys.__stderr__, string
181 181
182 182
183 183 def execute(self, python_string, raw_string=None):
184 184 """ Stores the raw_string in the history, and sends the
185 185 python string to the interpreter.
186 186 """
187 187 if raw_string is None:
188 188 raw_string = python_string
189 189 # Create a false result, in case there is an exception
190 190 self.last_result = dict(number=self.prompt_number)
191 191
192 192 try:
193 193 try:
194 194 self.history.input_cache[-1] = raw_string.rstrip()
195 195 result = self.shell.execute(python_string)
196 196 self.last_result = result
197 197 self.render_result(result)
198 198 except:
199 199 self.show_traceback()
200 200 finally:
201 201 self.after_execute()
202 202
203 203
204 204 #--------------------------------------------------------------------------
205 205 # LineFrontEndBase interface
206 206 #--------------------------------------------------------------------------
207 207
208 208 def prefilter_input(self, string):
209 209 """ Prefilter the input to turn it in valid python.
210 210 """
211 211 string = string.replace('\r\n', '\n')
212 212 string = string.replace('\t', 4*' ')
213 213 # Clean the trailing whitespace
214 214 string = '\n'.join(l.rstrip() for l in string.split('\n'))
215 215 return string
216 216
217 217
218 218 def after_execute(self):
219 219 """ All the operations required after an execution to put the
220 220 terminal back in a shape where it is usable.
221 221 """
222 222 self.prompt_number += 1
223 223 self.new_prompt(self.input_prompt_template.substitute(
224 224 number=(self.last_result['number'] + 1)))
225 225 # Start a new empty history entry
226 226 self._add_history(None, '')
227 227 self.history_cursor = len(self.history.input_cache) - 1
228 228
229 229
230 230 def complete_current_input(self):
231 231 """ Do code completion on current line.
232 232 """
233 233 if self.debug:
234 234 print >>sys.__stdout__, "complete_current_input",
235 235 line = self.input_buffer
236 236 new_line, completions = self.complete(line)
237 237 if len(completions)>1:
238 238 self.write_completion(completions, new_line=new_line)
239 239 elif not line == new_line:
240 240 self.input_buffer = new_line
241 241 if self.debug:
242 242 print >>sys.__stdout__, 'line', line
243 243 print >>sys.__stdout__, 'new_line', new_line
244 244 print >>sys.__stdout__, completions
245 245
246 246
247 247 def get_line_width(self):
248 248 """ Return the width of the line in characters.
249 249 """
250 250 return 80
251 251
252 252
253 253 def write_completion(self, possibilities, new_line=None):
254 254 """ Write the list of possible completions.
255 255
256 256 new_line is the completed input line that should be displayed
257 257 after the completion are writen. If None, the input_buffer
258 258 before the completion is used.
259 259 """
260 260 if new_line is None:
261 261 new_line = self.input_buffer
262 262
263 263 self.write('\n')
264 264 max_len = len(max(possibilities, key=len)) + 1
265 265
266 266 # Now we check how much symbol we can put on a line...
267 267 chars_per_line = self.get_line_width()
268 268 symbols_per_line = max(1, chars_per_line/max_len)
269 269
270 270 pos = 1
271 271 completion_string = []
272 272 for symbol in possibilities:
273 273 if pos < symbols_per_line:
274 274 completion_string.append(symbol.ljust(max_len))
275 275 pos += 1
276 276 else:
277 277 completion_string.append(symbol.rstrip() + '\n')
278 278 pos = 1
279 279 self.write(''.join(completion_string))
280 280 self.new_prompt(self.input_prompt_template.substitute(
281 281 number=self.last_result['number'] + 1))
282 282 self.input_buffer = new_line
283 283
284 284
285 285 def new_prompt(self, prompt):
286 286 """ Prints a prompt and starts a new editing buffer.
287 287
288 288 Subclasses should use this method to make sure that the
289 289 terminal is put in a state favorable for a new line
290 290 input.
291 291 """
292 292 self.input_buffer = ''
293 293 self.write(prompt)
294 294
295 295
296 296 def continuation_prompt(self):
297 297 """Returns the current continuation prompt.
298 298 """
299 299 return ("."*(len(self.last_prompt)-2) + ': ')
300 300
301 301
302 302 def execute_command(self, command, hidden=False):
303 303 """ Execute a command, not only in the model, but also in the
304 304 view, if any.
305 305 """
306 306 return self.shell.execute(command)
307 307
308 308 #--------------------------------------------------------------------------
309 309 # Private API
310 310 #--------------------------------------------------------------------------
311 311
312 312 def _on_enter(self, new_line_pos=0):
313 313 """ Called when the return key is pressed in a line editing
314 314 buffer.
315 315
316 316 Parameters
317 317 ----------
318 318 new_line_pos : integer, optional
319 319 Position of the new line to add, starting from the
320 320 end (0 adds a new line after the last line, -1 before
321 321 the last line...)
322 322
323 323 Returns
324 324 -------
325 325 True if execution is triggered
326 326 """
327 327 current_buffer = self.input_buffer
328 328 # XXX: This string replace is ugly, but there should be no way it
329 329 # fails.
330 330 prompt_less_buffer = re.sub('^' + self.continuation_prompt(),
331 331 '', current_buffer).replace('\n' + self.continuation_prompt(),
332 332 '\n')
333 333 cleaned_buffer = self.prefilter_input(prompt_less_buffer)
334 334 if self.is_complete(cleaned_buffer):
335 335 self.execute(cleaned_buffer, raw_string=current_buffer)
336 336 return True
337 337 else:
338 338 # Start a new line.
339 339 new_line_pos = -new_line_pos
340 340 lines = current_buffer.split('\n')[:-1]
341 341 prompt_less_lines = prompt_less_buffer.split('\n')
342 342 # Create the new line, with the continuation prompt, and the
343 343 # same amount of indent than the line above it.
344 344 new_line = self.continuation_prompt() + \
345 345 self._get_indent_string('\n'.join(
346 346 prompt_less_lines[:new_line_pos-1]))
347 347 if len(lines) == 1:
348 348 # We are starting a first continuation line. Indent it.
349 349 new_line += '\t'
350 350 elif current_buffer[:-1].split('\n')[-1].rstrip().endswith(':'):
351 351 # The last line ends with ":", autoindent the new line.
352 352 new_line += '\t'
353 353
354 354 if new_line_pos == 0:
355 355 lines.append(new_line)
356 356 else:
357 357 lines.insert(new_line_pos, new_line)
358 358 self.input_buffer = '\n'.join(lines)
359 359
360 360
361 361 def _get_indent_string(self, string):
362 362 """ Return the string of whitespace that prefixes a line. Used to
363 363 add the right amount of indendation when creating a new line.
364 364 """
365 365 string = string.replace('\t', ' '*4)
366 366 string = string.split('\n')[-1]
367 367 indent_chars = len(string) - len(string.lstrip())
368 368 indent_string = '\t'*(indent_chars // 4) + \
369 369 ' '*(indent_chars % 4)
370 370
371 371 return indent_string
372 372
373 373
@@ -1,256 +1,256 b''
1 1 """
2 2 Frontend class that uses IPython0 to prefilter the inputs.
3 3
4 4 Using the IPython0 mechanism gives us access to the magics.
5 5
6 6 This is a transitory class, used here to do the transition between
7 7 ipython0 and ipython1. This class is meant to be short-lived as more
8 8 functionnality is abstracted out of ipython0 in reusable functions and
9 9 is added on the interpreter. This class can be a used to guide this
10 10 refactoring.
11 11 """
12 12
13 13 #-------------------------------------------------------------------------------
14 # Copyright (C) 2008 The IPython Development Team
14 # Copyright (C) 2008-2011 The IPython Development Team
15 15 #
16 16 # Distributed under the terms of the BSD License. The full license is in
17 17 # the file COPYING, distributed as part of this software.
18 18 #-------------------------------------------------------------------------------
19 19
20 20 #-------------------------------------------------------------------------------
21 21 # Imports
22 22 #-------------------------------------------------------------------------------
23 23 import sys
24 24 import pydoc
25 25 import os
26 26 import re
27 27 import __builtin__
28 28
29 29 from IPython.core.iplib import InteractiveShell
30 30 from IPython.kernel.core.redirector_output_trap import RedirectorOutputTrap
31 31
32 32 from IPython.kernel.core.sync_traceback_trap import SyncTracebackTrap
33 33
34 34 import IPython.utils.io
35 35
36 36 from linefrontendbase import LineFrontEndBase, common_prefix
37 37
38 38 #-----------------------------------------------------------------------------
39 39 # Utility functions
40 40 #-----------------------------------------------------------------------------
41 41
42 42 def mk_system_call(system_call_function, command):
43 43 """ given a os.system replacement, and a leading string command,
44 44 returns a function that will execute the command with the given
45 45 argument string.
46 46 """
47 47 def my_system_call(args):
48 48 system_call_function("%s %s" % (command, args))
49 49
50 50 my_system_call.__doc__ = "Calls %s" % command
51 51 return my_system_call
52 52
53 53 #-----------------------------------------------------------------------------
54 54 # Frontend class using ipython0 to do the prefiltering.
55 55 #-----------------------------------------------------------------------------
56 56
57 57 class PrefilterFrontEnd(LineFrontEndBase):
58 58 """ Class that uses ipython0 to do prefilter the input, do the
59 59 completion and the magics.
60 60
61 61 The core trick is to use an ipython0 instance to prefilter the
62 62 input, and share the namespace between the interpreter instance used
63 63 to execute the statements and the ipython0 used for code
64 64 completion...
65 65 """
66 66
67 67 debug = False
68 68
69 69 def __init__(self, ipython0=None, *args, **kwargs):
70 70 """ Parameters
71 71 ----------
72 72
73 73 ipython0: an optional ipython0 instance to use for command
74 74 prefiltering and completion.
75 75 """
76 76 LineFrontEndBase.__init__(self, *args, **kwargs)
77 77 self.shell.output_trap = RedirectorOutputTrap(
78 78 out_callback=self.write,
79 79 err_callback=self.write,
80 80 )
81 81 self.shell.traceback_trap = SyncTracebackTrap(
82 82 formatters=self.shell.traceback_trap.formatters,
83 83 )
84 84
85 85 # Start the ipython0 instance:
86 86 self.save_output_hooks()
87 87 if ipython0 is None:
88 88 # Instanciate an IPython0 InteractiveShell to be able to use the
89 89 # prefiltering.
90 90 # Suppress all key input, to avoid waiting
91 91 def my_rawinput(x=None):
92 92 return '\n'
93 93 old_rawinput = __builtin__.raw_input
94 94 __builtin__.raw_input = my_rawinput
95 95 ipython0 = InteractiveShell(
96 96 parent=None, user_ns=self.shell.user_ns,
97 97 user_global_ns=self.shell.user_global_ns
98 98 )
99 99 __builtin__.raw_input = old_rawinput
100 100 self.ipython0 = ipython0
101 101 # Set the pager:
102 102 self.ipython0.set_hook('show_in_pager',
103 103 lambda s, string: self.write("\n" + string))
104 104 self.ipython0.write = self.write
105 105 self._ip = _ip = self.ipython0
106 106 # Make sure the raw system call doesn't get called, as we don't
107 107 # have a stdin accessible.
108 108 self._ip.system = self.system_call
109 109 # XXX: Muck around with magics so that they work better
110 110 # in our environment
111 111 if not sys.platform.startswith('win'):
112 112 self.ipython0.magic_ls = mk_system_call(self.system_call,
113 113 'ls -CF')
114 114 # And now clean up the mess created by ipython0
115 115 self.release_output()
116 116
117 117
118 118 if not 'banner' in kwargs and self.banner is None:
119 119 self.banner = self.ipython0.banner
120 120
121 121 # FIXME: __init__ and start should be two different steps
122 122 self.start()
123 123
124 124 #--------------------------------------------------------------------------
125 125 # FrontEndBase interface
126 126 #--------------------------------------------------------------------------
127 127
128 128 def show_traceback(self):
129 129 """ Use ipython0 to capture the last traceback and display it.
130 130 """
131 131 # Don't do the capture; the except_hook has already done some
132 132 # modifications to the IO streams, if we store them, we'll be
133 133 # storing the wrong ones.
134 134 #self.capture_output()
135 135 self.ipython0.showtraceback(tb_offset=-1)
136 136 self.release_output()
137 137
138 138
139 139 def execute(self, python_string, raw_string=None):
140 140 if self.debug:
141 141 print 'Executing Python code:', repr(python_string)
142 142 self.capture_output()
143 143 LineFrontEndBase.execute(self, python_string,
144 144 raw_string=raw_string)
145 145 self.release_output()
146 146
147 147
148 148 def save_output_hooks(self):
149 149 """ Store all the output hooks we can think of, to be able to
150 150 restore them.
151 151
152 152 We need to do this early, as starting the ipython0 instance will
153 153 screw ouput hooks.
154 154 """
155 155 self.__old_cout_write = Term.cout.write
156 156 self.__old_cerr_write = Term.cerr.write
157 157 self.__old_stdout = sys.stdout
158 158 self.__old_stderr= sys.stderr
159 159 self.__old_help_output = pydoc.help.output
160 160 self.__old_display_hook = sys.displayhook
161 161
162 162
163 163 def capture_output(self):
164 164 """ Capture all the output mechanisms we can think of.
165 165 """
166 166 self.save_output_hooks()
167 167 Term.cout.write = self.write
168 168 Term.cerr.write = self.write
169 169 sys.stdout = Term.cout
170 170 sys.stderr = Term.cerr
171 171 pydoc.help.output = self.shell.output_trap.out
172 172
173 173
174 174 def release_output(self):
175 175 """ Release all the different captures we have made.
176 176 """
177 177 Term.cout.write = self.__old_cout_write
178 178 Term.cerr.write = self.__old_cerr_write
179 179 sys.stdout = self.__old_stdout
180 180 sys.stderr = self.__old_stderr
181 181 pydoc.help.output = self.__old_help_output
182 182 sys.displayhook = self.__old_display_hook
183 183
184 184
185 185 def complete(self, line):
186 186 # FIXME: This should be factored out in the linefrontendbase
187 187 # method.
188 188 word = self._get_completion_text(line)
189 189 completions = self.ipython0.complete(word)
190 190 # FIXME: The proper sort should be done in the complete method.
191 191 key = lambda x: x.replace('_', '')
192 192 completions.sort(key=key)
193 193 if completions:
194 194 prefix = common_prefix(completions)
195 195 line = line[:-len(word)] + prefix
196 196 return line, completions
197 197
198 198 #--------------------------------------------------------------------------
199 199 # LineFrontEndBase interface
200 200 #--------------------------------------------------------------------------
201 201
202 202 def prefilter_input(self, input_string):
203 203 """ Using IPython0 to prefilter the commands to turn them
204 204 in executable statements that are valid Python strings.
205 205 """
206 206 input_string = LineFrontEndBase.prefilter_input(self, input_string)
207 207 filtered_lines = []
208 208 # The IPython0 prefilters sometime produce output. We need to
209 209 # capture it.
210 210 self.capture_output()
211 211 self.last_result = dict(number=self.prompt_number)
212 212
213 213 try:
214 214 try:
215 215 for line in input_string.split('\n'):
216 216 pf = self.ipython0.prefilter_manager.prefilter_lines
217 217 filtered_lines.append(pf(line, False).rstrip())
218 218 except:
219 219 # XXX: probably not the right thing to do.
220 220 self.ipython0.showsyntaxerror()
221 221 self.after_execute()
222 222 finally:
223 223 self.release_output()
224 224
225 225 # Clean up the trailing whitespace, to avoid indentation errors
226 226 filtered_string = '\n'.join(filtered_lines)
227 227 return filtered_string
228 228
229 229 #--------------------------------------------------------------------------
230 230 # PrefilterFrontEnd interface
231 231 #--------------------------------------------------------------------------
232 232
233 233 def system_call(self, command_string):
234 234 """ Allows for frontend to define their own system call, to be
235 235 able capture output and redirect input.
236 236 """
237 237 return os.system(command_string)
238 238
239 239 def do_exit(self):
240 240 """ Exit the shell, cleanup and save the history.
241 241 """
242 242 self.ipython0.atexit_operations()
243 243
244 244 def _get_completion_text(self, line):
245 245 """ Returns the text to be completed by breaking the line at specified
246 246 delimiters.
247 247 """
248 248 # Break at: spaces, '=', all parentheses (except if balanced).
249 249 # FIXME2: In the future, we need to make the implementation similar to
250 250 # that in the 'pyreadline' module (modes/basemode.py) where we break at
251 251 # each delimiter and try to complete the residual line, until we get a
252 252 # successful list of completions.
253 253 expression = '\s|=|,|:|\((?!.*\))|\[(?!.*\])|\{(?!.*\})'
254 254 complete_sep = re.compile(expression)
255 255 text = complete_sep.split(line)[-1]
256 256 return text
@@ -1,74 +1,74 b''
1 1 # encoding: utf-8
2 2 """
3 3 Object for encapsulating process execution by using callbacks for stdout,
4 4 stderr and stdin.
5 5 """
6 6 __docformat__ = "restructuredtext en"
7 7
8 8 #-------------------------------------------------------------------------------
9 # Copyright (C) 2008 The IPython Development Team
9 # Copyright (C) 2008-2011 The IPython Development Team
10 10 #
11 11 # Distributed under the terms of the BSD License. The full license is in
12 12 # the file COPYING, distributed as part of this software.
13 13 #-------------------------------------------------------------------------------
14 14
15 15 #-------------------------------------------------------------------------------
16 16 # Imports
17 17 #-------------------------------------------------------------------------------
18 18 from killableprocess import Popen, PIPE
19 19 from threading import Thread
20 20 from time import sleep
21 21 import os
22 22
23 23 class PipedProcess(Thread):
24 24 """ Class that encapsulates process execution by using callbacks for
25 25 stdout, stderr and stdin, and providing a reliable way of
26 26 killing it.
27 27 """
28 28
29 29 def __init__(self, command_string, out_callback,
30 30 end_callback=None,):
31 31 """ command_string: the command line executed to start the
32 32 process.
33 33
34 34 out_callback: the python callable called on stdout/stderr.
35 35
36 36 end_callback: an optional callable called when the process
37 37 finishes.
38 38
39 39 These callbacks are called from a different thread as the
40 40 thread from which is started.
41 41 """
42 42 self.command_string = command_string
43 43 self.out_callback = out_callback
44 44 self.end_callback = end_callback
45 45 Thread.__init__(self)
46 46
47 47
48 48 def run(self):
49 49 """ Start the process and hook up the callbacks.
50 50 """
51 51 env = os.environ
52 52 env['TERM'] = 'xterm'
53 53 process = Popen(self.command_string + ' 2>&1', shell=True,
54 54 env=env,
55 55 universal_newlines=True,
56 56 stdout=PIPE, stdin=PIPE, )
57 57 self.process = process
58 58 while True:
59 59 out_char = process.stdout.read(1)
60 60 if out_char == '':
61 61 if process.poll() is not None:
62 62 # The process has finished
63 63 break
64 64 else:
65 65 # The process is not giving any interesting
66 66 # output. No use polling it immediatly.
67 67 sleep(0.1)
68 68 else:
69 69 self.out_callback(out_char)
70 70
71 71 if self.end_callback is not None:
72 72 self.end_callback()
73 73
74 74
@@ -1,106 +1,106 b''
1 1 # encoding: utf-8
2 2 """This file contains unittests for the asyncfrontendbase module."""
3 3
4 4 #---------------------------------------------------------------------------
5 # Copyright (C) 2008-2009 The IPython Development Team
5 # Copyright (C) 2008-2011 The IPython Development Team
6 6 #
7 7 # Distributed under the terms of the BSD License. The full license is in
8 8 # the file COPYING, distributed as part of this software.
9 9 #---------------------------------------------------------------------------
10 10
11 11 #---------------------------------------------------------------------------
12 12 # Imports
13 13 #---------------------------------------------------------------------------
14 14
15 15 from twisted.trial import unittest
16 16
17 17 from IPython.frontend.asyncfrontendbase import AsyncFrontEndBase
18 18 from IPython.frontend import frontendbase
19 19 from IPython.kernel.engineservice import EngineService
20 20 from IPython.testing.parametric import Parametric, parametric
21 21
22 22 #-----------------------------------------------------------------------------
23 23 # Classes and functions
24 24 #-----------------------------------------------------------------------------
25 25
26 26 class FrontEndCallbackChecker(AsyncFrontEndBase):
27 27 """FrontEndBase subclass for checking callbacks"""
28 28 def __init__(self, engine=None, history=None):
29 29 super(FrontEndCallbackChecker, self).__init__(engine=engine,
30 30 history=history)
31 31 self.updateCalled = False
32 32 self.renderResultCalled = False
33 33 self.renderErrorCalled = False
34 34
35 35 def update_cell_prompt(self, result, blockID=None):
36 36 self.updateCalled = True
37 37 return result
38 38
39 39 def render_result(self, result):
40 40 self.renderResultCalled = True
41 41 return result
42 42
43 43 def render_error(self, failure):
44 44 self.renderErrorCalled = True
45 45 return failure
46 46
47 47
48 48 class TestAsyncFrontendBase(unittest.TestCase):
49 49 def setUp(self):
50 50 """Setup the EngineService and FrontEndBase"""
51 51
52 52 self.fb = FrontEndCallbackChecker(engine=EngineService())
53 53
54 54 def test_implements_IFrontEnd(self):
55 55 self.assert_(frontendbase.IFrontEnd.implementedBy(
56 56 AsyncFrontEndBase))
57 57
58 58 def test_is_complete_returns_False_for_incomplete_block(self):
59 59 block = """def test(a):"""
60 60 self.assert_(self.fb.is_complete(block) == False)
61 61
62 62 def test_is_complete_returns_True_for_complete_block(self):
63 63 block = """def test(a): pass"""
64 64 self.assert_(self.fb.is_complete(block))
65 65 block = """a=3"""
66 66 self.assert_(self.fb.is_complete(block))
67 67
68 68 def test_blockID_added_to_result(self):
69 69 block = """3+3"""
70 70 d = self.fb.execute(block, blockID='TEST_ID')
71 71 d.addCallback(lambda r: self.assert_(r['blockID']=='TEST_ID'))
72 72 return d
73 73
74 74 def test_blockID_added_to_failure(self):
75 75 block = "raise Exception()"
76 76 d = self.fb.execute(block,blockID='TEST_ID')
77 77 d.addErrback(lambda f: self.assert_(f.blockID=='TEST_ID'))
78 78 return d
79 79
80 80 def test_callbacks_added_to_execute(self):
81 81 d = self.fb.execute("10+10")
82 82 d.addCallback(lambda r: self.assert_(self.fb.updateCalled and self.fb.renderResultCalled))
83 83 return d
84 84
85 85 def test_error_callback_added_to_execute(self):
86 86 """Test that render_error called on execution error."""
87 87
88 88 d = self.fb.execute("raise Exception()")
89 89 d.addErrback(lambda f: self.assert_(self.fb.renderErrorCalled))
90 90 return d
91 91
92 92 def test_history_returns_expected_block(self):
93 93 """Make sure history browsing doesn't fail."""
94 94
95 95 blocks = ["a=1","a=2","a=3"]
96 96 d = self.fb.execute(blocks[0])
97 97 d.addCallback(lambda _: self.fb.execute(blocks[1]))
98 98 d.addCallback(lambda _: self.fb.execute(blocks[2]))
99 99 d.addCallback(lambda _: self.assert_(self.fb.get_history_previous("")==blocks[-2]))
100 100 d.addCallback(lambda _: self.assert_(self.fb.get_history_previous("")==blocks[-3]))
101 101 d.addCallback(lambda _: self.assert_(self.fb.get_history_next()==blocks[-2]))
102 102 return d
103 103
104 104 def test_history_returns_none_at_startup(self):
105 105 self.assert_(self.fb.get_history_previous("")==None)
106 106 self.assert_(self.fb.get_history_next()==None)
@@ -1,32 +1,32 b''
1 1 # encoding: utf-8
2 2 """
3 3 Test the basic functionality of frontendbase.
4 4 """
5 5
6 6 __docformat__ = "restructuredtext en"
7 7
8 8 #-------------------------------------------------------------------------------
9 # Copyright (C) 2008 The IPython Development Team
9 # Copyright (C) 2008-2011 The IPython Development Team
10 10 #
11 11 # Distributed under the terms of the BSD License. The full license is
12 12 # in the file COPYING, distributed as part of this software.
13 13 #-------------------------------------------------------------------------------
14 14
15 15 from IPython.frontend.frontendbase import FrontEndBase
16 16
17 17 def test_iscomplete():
18 18 """ Check that is_complete works.
19 19 """
20 20 f = FrontEndBase()
21 21 assert f.is_complete('(a + a)')
22 22 assert not f.is_complete('(a + a')
23 23 assert f.is_complete('1')
24 24 assert not f.is_complete('1 + ')
25 25 assert not f.is_complete('1 + \n\n')
26 26 assert f.is_complete('if True:\n print 1\n')
27 27 assert not f.is_complete('if True:\n print 1')
28 28 assert f.is_complete('def f():\n print 1\n')
29 29
30 30 if __name__ == '__main__':
31 31 test_iscomplete()
32 32
@@ -1,37 +1,37 b''
1 1 # encoding: utf-8
2 2 """
3 3 Test the LineFrontEnd
4 4 """
5 5
6 6 __docformat__ = "restructuredtext en"
7 7
8 8 #-------------------------------------------------------------------------------
9 # Copyright (C) 2008 The IPython Development Team
9 # Copyright (C) 2008-2011 The IPython Development Team
10 10 #
11 11 # Distributed under the terms of the BSD License. The full license is
12 12 # in the file COPYING, distributed as part of this software.
13 13 #-------------------------------------------------------------------------------
14 14
15 15 from IPython.frontend.linefrontendbase import LineFrontEndBase
16 16 from copy import deepcopy
17 17 import nose.tools as nt
18 18
19 19 class ConcreteLineFrontEnd(LineFrontEndBase):
20 20 """ A concrete class to test the LineFrontEndBase.
21 21 """
22 22 def capture_output(self):
23 23 pass
24 24
25 25 def release_output(self):
26 26 pass
27 27
28 28
29 29 def test_is_complete():
30 30 """ Tests line completion heuristic.
31 31 """
32 32 frontend = ConcreteLineFrontEnd()
33 33 yield nt.assert_true, not frontend.is_complete('for x in \\')
34 34 yield nt.assert_true, not frontend.is_complete('for x in (1, ):')
35 35 yield nt.assert_true, frontend.is_complete('for x in (1, ):\n pass')
36 36
37 37
@@ -1,268 +1,268 b''
1 1 # encoding: utf-8
2 2 """
3 3 Test process execution and IO redirection.
4 4 """
5 5
6 6 __docformat__ = "restructuredtext en"
7 7
8 8 #-------------------------------------------------------------------------------
9 # Copyright (C) 2008 The IPython Development Team
9 # Copyright (C) 2008-2011 The IPython Development Team
10 10 #
11 11 # Distributed under the terms of the BSD License. The full license is
12 12 # in the file COPYING, distributed as part of this software.
13 13 #-------------------------------------------------------------------------------
14 14
15 15 from copy import copy, deepcopy
16 16 from cStringIO import StringIO
17 17 import string
18 18 import sys
19 19
20 20 from nose.tools import assert_equal
21 21
22 22 from IPython.frontend.prefilterfrontend import PrefilterFrontEnd
23 23 from IPython.testing.globalipapp import get_ipython
24 24
25 25 #-----------------------------------------------------------------------------
26 26 # Support utilities
27 27 #-----------------------------------------------------------------------------
28 28
29 29 class TestPrefilterFrontEnd(PrefilterFrontEnd):
30 30
31 31 input_prompt_template = string.Template('')
32 32 output_prompt_template = string.Template('')
33 33 banner = ''
34 34
35 35 def __init__(self):
36 36 self.out = StringIO()
37 37 PrefilterFrontEnd.__init__(self)
38 38 # Some more code for isolation (yeah, crazy)
39 39 self._on_enter()
40 40 self.out.flush()
41 41 self.out.reset()
42 42 self.out.truncate()
43 43
44 44 def write(self, string, *args, **kwargs):
45 45 self.out.write(string)
46 46
47 47 def _on_enter(self):
48 48 self.input_buffer += '\n'
49 49 PrefilterFrontEnd._on_enter(self)
50 50
51 51
52 52 def isolate_ipython0(func):
53 53 """ Decorator to isolate execution that involves an iptyhon0.
54 54
55 55 Notes
56 56 -----
57 57
58 58 Apply only to functions with no arguments. Nose skips functions
59 59 with arguments.
60 60 """
61 61 def my_func():
62 62 ip0 = get_ipython()
63 63 if ip0 is None:
64 64 return func()
65 65 # We have a real ipython running...
66 66 user_ns = ip0.user_ns
67 67 user_global_ns = ip0.user_global_ns
68 68
69 69 # Previously the isolation was attempted with a deep copy of the user
70 70 # dicts, but we found cases where this didn't work correctly. I'm not
71 71 # quite sure why, but basically it did damage the user namespace, such
72 72 # that later tests stopped working correctly. Instead we use a simpler
73 73 # approach, just computing the list of added keys to the namespace and
74 74 # eliminating those afterwards. Existing keys that may have been
75 75 # modified remain modified. So far this has proven to be robust.
76 76
77 77 # Compute set of old local/global keys
78 78 old_locals = set(user_ns.keys())
79 79 old_globals = set(user_global_ns.keys())
80 80 try:
81 81 out = func()
82 82 finally:
83 83 # Find new keys, and if any, remove them
84 84 new_locals = set(user_ns.keys()) - old_locals
85 85 new_globals = set(user_global_ns.keys()) - old_globals
86 86 for k in new_locals:
87 87 del user_ns[k]
88 88 for k in new_globals:
89 89 del user_global_ns[k]
90 90 return out
91 91
92 92 my_func.__name__ = func.__name__
93 93 return my_func
94 94
95 95 #-----------------------------------------------------------------------------
96 96 # Tests
97 97 #-----------------------------------------------------------------------------
98 98
99 99 @isolate_ipython0
100 100 def test_execution():
101 101 """ Test execution of a command.
102 102 """
103 103 f = TestPrefilterFrontEnd()
104 104 f.input_buffer = 'print(1)'
105 105 f._on_enter()
106 106 out_value = f.out.getvalue()
107 107 assert_equal(out_value, '1\n')
108 108
109 109
110 110 @isolate_ipython0
111 111 def test_multiline():
112 112 """ Test execution of a multiline command.
113 113 """
114 114 f = TestPrefilterFrontEnd()
115 115 f.input_buffer = 'if True:'
116 116 f._on_enter()
117 117 f.input_buffer += 'print 1'
118 118 f._on_enter()
119 119 out_value = f.out.getvalue()
120 120 yield assert_equal, out_value, ''
121 121 f._on_enter()
122 122 out_value = f.out.getvalue()
123 123 yield assert_equal, out_value, '1\n'
124 124 f = TestPrefilterFrontEnd()
125 125 f.input_buffer='(1 +'
126 126 f._on_enter()
127 127 f.input_buffer += '0)'
128 128 f._on_enter()
129 129 out_value = f.out.getvalue()
130 130 yield assert_equal, out_value, ''
131 131 f._on_enter()
132 132 out_value = f.out.getvalue()
133 133 yield assert_equal, out_value, '1\n'
134 134
135 135
136 136 @isolate_ipython0
137 137 def test_capture():
138 138 """ Test the capture of output in different channels.
139 139 """
140 140 # Test on the OS-level stdout, stderr.
141 141 f = TestPrefilterFrontEnd()
142 142 f.input_buffer = \
143 143 'import os; out=os.fdopen(1, "w"); out.write("1") ; out.flush()'
144 144 f._on_enter()
145 145 out_value = f.out.getvalue()
146 146 yield assert_equal, out_value, '1'
147 147 f = TestPrefilterFrontEnd()
148 148 f.input_buffer = \
149 149 'import os; out=os.fdopen(2, "w"); out.write("1") ; out.flush()'
150 150 f._on_enter()
151 151 out_value = f.out.getvalue()
152 152 yield assert_equal, out_value, '1'
153 153
154 154
155 155 @isolate_ipython0
156 156 def test_magic():
157 157 """ Test the magic expansion and history.
158 158
159 159 This test is fairly fragile and will break when magics change.
160 160 """
161 161 f = TestPrefilterFrontEnd()
162 162 # Before checking the interactive namespace, make sure it's clear (it can
163 163 # otherwise pick up things stored in the user's local db)
164 164 f.input_buffer += '%reset -f'
165 165 f._on_enter()
166 166 f.complete_current_input()
167 167 # Now, run the %who magic and check output
168 168 f.input_buffer += '%who'
169 169 f._on_enter()
170 170 out_value = f.out.getvalue()
171 171 assert_equal(out_value, 'Interactive namespace is empty.\n')
172 172
173 173
174 174 @isolate_ipython0
175 175 def test_help():
176 176 """ Test object inspection.
177 177 """
178 178 f = TestPrefilterFrontEnd()
179 179 f.input_buffer += "def f():"
180 180 f._on_enter()
181 181 f.input_buffer += "'foobar'"
182 182 f._on_enter()
183 183 f.input_buffer += "pass"
184 184 f._on_enter()
185 185 f._on_enter()
186 186 f.input_buffer += "f?"
187 187 f._on_enter()
188 188 assert 'traceback' not in f.last_result
189 189 ## XXX: ipython doctest magic breaks this. I have no clue why
190 190 #out_value = f.out.getvalue()
191 191 #assert out_value.split()[-1] == 'foobar'
192 192
193 193
194 194 @isolate_ipython0
195 195 def test_completion_simple():
196 196 """ Test command-line completion on trivial examples.
197 197 """
198 198 f = TestPrefilterFrontEnd()
199 199 f.input_buffer = 'zzza = 1'
200 200 f._on_enter()
201 201 f.input_buffer = 'zzzb = 2'
202 202 f._on_enter()
203 203 f.input_buffer = 'zz'
204 204 f.complete_current_input()
205 205 out_value = f.out.getvalue()
206 206 yield assert_equal, out_value, '\nzzza zzzb '
207 207 yield assert_equal, f.input_buffer, 'zzz'
208 208
209 209
210 210 @isolate_ipython0
211 211 def test_completion_parenthesis():
212 212 """ Test command-line completion when a parenthesis is open.
213 213 """
214 214 f = TestPrefilterFrontEnd()
215 215 f.input_buffer = 'zzza = 1'
216 216 f._on_enter()
217 217 f.input_buffer = 'zzzb = 2'
218 218 f._on_enter()
219 219 f.input_buffer = 'map(zz'
220 220 f.complete_current_input()
221 221 out_value = f.out.getvalue()
222 222 yield assert_equal, out_value, '\nzzza zzzb '
223 223 yield assert_equal, f.input_buffer, 'map(zzz'
224 224
225 225
226 226 @isolate_ipython0
227 227 def test_completion_indexing():
228 228 """ Test command-line completion when indexing on objects.
229 229 """
230 230 f = TestPrefilterFrontEnd()
231 231 f.input_buffer = 'a = [0]'
232 232 f._on_enter()
233 233 f.input_buffer = 'a[0].'
234 234 f.complete_current_input()
235 235
236 236 if sys.version_info[:2] >= (2,6):
237 237 # In Python 2.6, ints picked up a few non __ methods, so now there are
238 238 # no completions.
239 239 assert_equal(f.input_buffer, 'a[0].')
240 240 else:
241 241 # Right answer for 2.4/2.5
242 242 assert_equal(f.input_buffer, 'a[0].__')
243 243
244 244
245 245 @isolate_ipython0
246 246 def test_completion_equal():
247 247 """ Test command-line completion when the delimiter is "=", not " ".
248 248 """
249 249 f = TestPrefilterFrontEnd()
250 250 f.input_buffer = 'a=1.'
251 251 f.complete_current_input()
252 252 if sys.version_info[:2] >= (2,6):
253 253 # In Python 2.6, ints picked up a few non __ methods, so now there are
254 254 # no completions.
255 255 assert_equal(f.input_buffer, 'a=1.')
256 256 else:
257 257 # Right answer for 2.4/2.5
258 258 assert_equal(f.input_buffer, 'a=1.__')
259 259
260 260
261 261 if __name__ == '__main__':
262 262 test_magic()
263 263 test_help()
264 264 test_execution()
265 265 test_multiline()
266 266 test_capture()
267 267 test_completion_simple()
268 268 test_completion_complex()
@@ -1,68 +1,68 b''
1 1 # encoding: utf-8
2 2 """
3 3 Test process execution and IO redirection.
4 4 """
5 5
6 6 __docformat__ = "restructuredtext en"
7 7
8 8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2008-2009 The IPython Development Team
9 # Copyright (C) 2008-2011 The IPython Development Team
10 10 #
11 11 # Distributed under the terms of the BSD License. The full license is
12 12 # in the file COPYING, distributed as part of this software.
13 13 #-----------------------------------------------------------------------------
14 14
15 15 from cStringIO import StringIO
16 16 from time import sleep
17 17 import sys
18 18
19 19 from IPython.frontend.process import PipedProcess
20 20 from IPython.testing import decorators as testdec
21 21
22 22
23 23 def test_capture_out():
24 24 """ A simple test to see if we can execute a process and get the output.
25 25 """
26 26 s = StringIO()
27 27 p = PipedProcess('echo 1', out_callback=s.write, )
28 28 p.start()
29 29 p.join()
30 30 result = s.getvalue().rstrip()
31 31 assert result == '1'
32 32
33 33
34 34 def test_io():
35 35 """ Checks that we can send characters on stdin to the process.
36 36 """
37 37 s = StringIO()
38 38 p = PipedProcess(sys.executable + ' -c "a = raw_input(); print a"',
39 39 out_callback=s.write, )
40 40 p.start()
41 41 test_string = '12345\n'
42 42 while not hasattr(p, 'process'):
43 43 sleep(0.1)
44 44 p.process.stdin.write(test_string)
45 45 p.join()
46 46 result = s.getvalue()
47 47 assert result == test_string
48 48
49 49
50 50 @testdec.skip_win32
51 51 def test_kill():
52 52 """ Check that we can kill a process, and its subprocess.
53 53 """
54 54 s = StringIO()
55 55 p = PipedProcess(sys.executable + ' -c "a = raw_input();"',
56 56 out_callback=s.write, )
57 57 p.start()
58 58 while not hasattr(p, 'process'):
59 59 sleep(0.1)
60 60 p.process.kill()
61 61 assert p.process.poll() is not None
62 62
63 63
64 64 if __name__ == '__main__':
65 65 test_capture_out()
66 66 test_io()
67 67 test_kill()
68 68
@@ -1,625 +1,625 b''
1 1 # encoding: utf-8
2 2 """
3 3 A Wx widget to act as a console and input commands.
4 4
5 5 This widget deals with prompts and provides an edit buffer
6 6 restricted to after the last prompt.
7 7 """
8 8
9 9 __docformat__ = "restructuredtext en"
10 10
11 11 #-------------------------------------------------------------------------------
12 # Copyright (C) 2008 The IPython Development Team
12 # Copyright (C) 2008-2011 The IPython Development Team
13 13 #
14 14 # Distributed under the terms of the BSD License. The full license is
15 15 # in the file COPYING, distributed as part of this software.
16 16 #-------------------------------------------------------------------------------
17 17
18 18 #-------------------------------------------------------------------------------
19 19 # Imports
20 20 #-------------------------------------------------------------------------------
21 21
22 22 import wx
23 23 import wx.stc as stc
24 24
25 25 from wx.py import editwindow
26 26 import time
27 27 import sys
28 28 import string
29 29
30 30 LINESEP = '\n'
31 31 if sys.platform == 'win32':
32 32 LINESEP = '\n\r'
33 33
34 34 import re
35 35
36 36 # FIXME: Need to provide an API for non user-generated display on the
37 37 # screen: this should not be editable by the user.
38 38 #-------------------------------------------------------------------------------
39 39 # Constants
40 40 #-------------------------------------------------------------------------------
41 41 _COMPLETE_BUFFER_MARKER = 31
42 42 _ERROR_MARKER = 30
43 43 _INPUT_MARKER = 29
44 44
45 45 _DEFAULT_SIZE = 10
46 46 if sys.platform == 'darwin':
47 47 _DEFAULT_SIZE = 12
48 48
49 49 _DEFAULT_STYLE = {
50 50 #background definition
51 51 'default' : 'size:%d' % _DEFAULT_SIZE,
52 52 'bracegood' : 'fore:#00AA00,back:#000000,bold',
53 53 'bracebad' : 'fore:#FF0000,back:#000000,bold',
54 54
55 55 # Edge column: a number of None
56 56 'edge_column' : -1,
57 57
58 58 # properties for the various Python lexer styles
59 59 'comment' : 'fore:#007F00',
60 60 'number' : 'fore:#007F7F',
61 61 'string' : 'fore:#7F007F,italic',
62 62 'char' : 'fore:#7F007F,italic',
63 63 'keyword' : 'fore:#00007F,bold',
64 64 'triple' : 'fore:#7F0000',
65 65 'tripledouble' : 'fore:#7F0000',
66 66 'class' : 'fore:#0000FF,bold,underline',
67 67 'def' : 'fore:#007F7F,bold',
68 68 'operator' : 'bold',
69 69
70 70 # Default colors
71 71 'trace' : '#FAFAF1', # Nice green
72 72 'stdout' : '#FDFFD3', # Nice yellow
73 73 'stderr' : '#FFF1F1', # Nice red
74 74
75 75 # Default scintilla settings
76 76 'antialiasing' : True,
77 77 'carret_color' : 'BLACK',
78 78 'background_color' :'WHITE',
79 79
80 80 #prompt definition
81 81 'prompt_in1' : \
82 82 '\n\x01\x1b[0;34m\x02In [\x01\x1b[1;34m\x02$number\x01\x1b[0;34m\x02]: \x01\x1b[0m\x02',
83 83
84 84 'prompt_out': \
85 85 '\x01\x1b[0;31m\x02Out[\x01\x1b[1;31m\x02$number\x01\x1b[0;31m\x02]: \x01\x1b[0m\x02',
86 86 }
87 87
88 88 # new style numbers
89 89 _STDOUT_STYLE = 15
90 90 _STDERR_STYLE = 16
91 91 _TRACE_STYLE = 17
92 92
93 93
94 94 # system colors
95 95 #SYS_COLOUR_BACKGROUND = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND)
96 96
97 97 # Translation table from ANSI escape sequences to color.
98 98 ANSI_STYLES = {'0;30': [0, 'BLACK'], '0;31': [1, 'RED'],
99 99 '0;32': [2, 'GREEN'], '0;33': [3, 'BROWN'],
100 100 '0;34': [4, 'BLUE'], '0;35': [5, 'PURPLE'],
101 101 '0;36': [6, 'CYAN'], '0;37': [7, 'LIGHT GREY'],
102 102 '1;30': [8, 'DARK GREY'], '1;31': [9, 'RED'],
103 103 '1;32': [10, 'SEA GREEN'], '1;33': [11, 'YELLOW'],
104 104 '1;34': [12, 'LIGHT BLUE'], '1;35':
105 105 [13, 'MEDIUM VIOLET RED'],
106 106 '1;36': [14, 'LIGHT STEEL BLUE'], '1;37': [15, 'YELLOW']}
107 107
108 108 # XXX: Maybe one day we should factor this code with coloransi. Right now
109 109 # coloransi is hard to reuse and makes our code more complex.
110 110
111 111 #we define platform specific fonts
112 112 if wx.Platform == '__WXMSW__':
113 113 FACES = { 'times': 'Times New Roman',
114 114 'mono' : 'Courier New',
115 115 'helv' : 'Arial',
116 116 'other': 'Comic Sans MS',
117 117 'size' : 10,
118 118 'size2': 8,
119 119 }
120 120 elif wx.Platform == '__WXMAC__':
121 121 FACES = { 'times': 'Times New Roman',
122 122 'mono' : 'Monaco',
123 123 'helv' : 'Arial',
124 124 'other': 'Comic Sans MS',
125 125 'size' : 10,
126 126 'size2': 8,
127 127 }
128 128 else:
129 129 FACES = { 'times': 'Times',
130 130 'mono' : 'Courier',
131 131 'helv' : 'Helvetica',
132 132 'other': 'new century schoolbook',
133 133 'size' : 10,
134 134 'size2': 8,
135 135 }
136 136
137 137
138 138 #-----------------------------------------------------------------------------
139 139 # The console widget class
140 140 #-----------------------------------------------------------------------------
141 141
142 142 class ConsoleWidget(editwindow.EditWindow):
143 143 """ Specialized styled text control view for console-like workflow.
144 144
145 145 This widget is mainly interested in dealing with the prompt and
146 146 keeping the cursor inside the editing line.
147 147 """
148 148
149 149 # This is where the title captured from the ANSI escape sequences are
150 150 # stored.
151 151 title = 'Console'
152 152
153 153 # Last prompt printed
154 154 last_prompt = ''
155 155
156 156 # The buffer being edited.
157 157 def _set_input_buffer(self, string):
158 158 self.SetSelection(self.current_prompt_pos, self.GetLength())
159 159 self.ReplaceSelection(string)
160 160 self.GotoPos(self.GetLength())
161 161
162 162 def _get_input_buffer(self):
163 163 """ Returns the text in current edit buffer.
164 164 """
165 165 input_buffer = self.GetTextRange(self.current_prompt_pos,
166 166 self.GetLength())
167 167 input_buffer = input_buffer.replace(LINESEP, '\n')
168 168 return input_buffer
169 169
170 170 input_buffer = property(_get_input_buffer, _set_input_buffer)
171 171
172 172 style = _DEFAULT_STYLE.copy()
173 173
174 174 # Translation table from ANSI escape sequences to color. Override
175 175 # this to specify your colors.
176 176 ANSI_STYLES = ANSI_STYLES.copy()
177 177
178 178 # Font faces
179 179 faces = FACES.copy()
180 180
181 181 # Store the last time a refresh was done
182 182 _last_refresh_time = 0
183 183
184 184 #--------------------------------------------------------------------------
185 185 # Public API
186 186 #--------------------------------------------------------------------------
187 187
188 188 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
189 189 size=wx.DefaultSize, style=wx.WANTS_CHARS, ):
190 190 editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
191 191 self.configure_scintilla()
192 192 # Track if 'enter' key as ever been processed
193 193 # This variable will only be reallowed until key goes up
194 194 self.enter_catched = False
195 195 self.current_prompt_pos = 0
196 196
197 197 self.Bind(wx.EVT_KEY_DOWN, self._on_key_down)
198 198 self.Bind(wx.EVT_KEY_UP, self._on_key_up)
199 199
200 200
201 201 def write(self, text, refresh=True):
202 202 """ Write given text to buffer, while translating the ansi escape
203 203 sequences.
204 204 """
205 205 # XXX: do not put print statements to sys.stdout/sys.stderr in
206 206 # this method, the print statements will call this method, as
207 207 # you will end up with an infinit loop
208 208 title = self.title_pat.split(text)
209 209 if len(title)>1:
210 210 self.title = title[-2]
211 211
212 212 text = self.title_pat.sub('', text)
213 213 segments = self.color_pat.split(text)
214 214 segment = segments.pop(0)
215 215 self.GotoPos(self.GetLength())
216 216 self.StartStyling(self.GetLength(), 0xFF)
217 217 try:
218 218 self.AppendText(segment)
219 219 except UnicodeDecodeError:
220 220 # XXX: Do I really want to skip the exception?
221 221 pass
222 222
223 223 if segments:
224 224 for ansi_tag, text in zip(segments[::2], segments[1::2]):
225 225 self.StartStyling(self.GetLength(), 0xFF)
226 226 try:
227 227 self.AppendText(text)
228 228 except UnicodeDecodeError:
229 229 # XXX: Do I really want to skip the exception?
230 230 pass
231 231
232 232 if ansi_tag not in self.ANSI_STYLES:
233 233 style = 0
234 234 else:
235 235 style = self.ANSI_STYLES[ansi_tag][0]
236 236
237 237 self.SetStyling(len(text), style)
238 238
239 239 self.GotoPos(self.GetLength())
240 240 if refresh:
241 241 current_time = time.time()
242 242 if current_time - self._last_refresh_time > 0.03:
243 243 if sys.platform == 'win32':
244 244 wx.SafeYield()
245 245 else:
246 246 wx.Yield()
247 247 # self.ProcessEvent(wx.PaintEvent())
248 248 self._last_refresh_time = current_time
249 249
250 250
251 251 def new_prompt(self, prompt):
252 252 """ Prints a prompt at start of line, and move the start of the
253 253 current block there.
254 254
255 255 The prompt can be given with ascii escape sequences.
256 256 """
257 257 self.write(prompt, refresh=False)
258 258 # now we update our cursor giving end of prompt
259 259 self.current_prompt_pos = self.GetLength()
260 260 self.current_prompt_line = self.GetCurrentLine()
261 261 self.EnsureCaretVisible()
262 262 self.last_prompt = prompt
263 263
264 264
265 265 def continuation_prompt(self):
266 266 """ Returns the current continuation prompt.
267 267 We need to implement this method here to deal with the
268 268 ascii escape sequences cleaning up.
269 269 """
270 270 # ASCII-less prompt
271 271 ascii_less = ''.join(self.color_pat.split(self.last_prompt)[2::2])
272 272 return "."*(len(ascii_less)-2) + ': '
273 273
274 274
275 275 def scroll_to_bottom(self):
276 276 maxrange = self.GetScrollRange(wx.VERTICAL)
277 277 self.ScrollLines(maxrange)
278 278
279 279
280 280 def pop_completion(self, possibilities, offset=0):
281 281 """ Pops up an autocompletion menu. Offset is the offset
282 282 in characters of the position at which the menu should
283 283 appear, relativ to the cursor.
284 284 """
285 285 self.AutoCompSetIgnoreCase(False)
286 286 self.AutoCompSetAutoHide(False)
287 287 self.AutoCompSetMaxHeight(len(possibilities))
288 288 self.AutoCompShow(offset, " ".join(possibilities))
289 289
290 290
291 291 def get_line_width(self):
292 292 """ Return the width of the line in characters.
293 293 """
294 294 return self.GetSize()[0]/self.GetCharWidth()
295 295
296 296
297 297 def configure_scintilla(self):
298 298 """ Set up all the styling option of the embedded scintilla
299 299 widget.
300 300 """
301 301 p = self.style.copy()
302 302
303 303 # Marker for complete buffer.
304 304 self.MarkerDefine(_COMPLETE_BUFFER_MARKER, stc.STC_MARK_BACKGROUND,
305 305 background=p['trace'])
306 306
307 307 # Marker for current input buffer.
308 308 self.MarkerDefine(_INPUT_MARKER, stc.STC_MARK_BACKGROUND,
309 309 background=p['stdout'])
310 310 # Marker for tracebacks.
311 311 self.MarkerDefine(_ERROR_MARKER, stc.STC_MARK_BACKGROUND,
312 312 background=p['stderr'])
313 313
314 314 self.SetEOLMode(stc.STC_EOL_LF)
315 315
316 316 # Ctrl"+" or Ctrl "-" can be used to zoomin/zoomout the text inside
317 317 # the widget
318 318 self.CmdKeyAssign(ord('+'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
319 319 self.CmdKeyAssign(ord('-'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
320 320 # Also allow Ctrl Shift "=" for poor non US keyboard users.
321 321 self.CmdKeyAssign(ord('='), stc.STC_SCMOD_CTRL|stc.STC_SCMOD_SHIFT,
322 322 stc.STC_CMD_ZOOMIN)
323 323
324 324 # Keys: we need to clear some of the keys the that don't play
325 325 # well with a console.
326 326 self.CmdKeyClear(ord('D'), stc.STC_SCMOD_CTRL)
327 327 self.CmdKeyClear(ord('L'), stc.STC_SCMOD_CTRL)
328 328 self.CmdKeyClear(ord('T'), stc.STC_SCMOD_CTRL)
329 329 self.CmdKeyClear(ord('A'), stc.STC_SCMOD_CTRL)
330 330
331 331 self.SetEOLMode(stc.STC_EOL_CRLF)
332 332 self.SetWrapMode(stc.STC_WRAP_CHAR)
333 333 self.SetWrapMode(stc.STC_WRAP_WORD)
334 334 self.SetBufferedDraw(True)
335 335
336 336 self.SetUseAntiAliasing(p['antialiasing'])
337 337
338 338 self.SetLayoutCache(stc.STC_CACHE_PAGE)
339 339 self.SetUndoCollection(False)
340 340 self.SetUseTabs(True)
341 341 self.SetIndent(4)
342 342 self.SetTabWidth(4)
343 343
344 344 # we don't want scintilla's autocompletion to choose
345 345 # automaticaly out of a single choice list, as we pop it up
346 346 # automaticaly
347 347 self.AutoCompSetChooseSingle(False)
348 348 self.AutoCompSetMaxHeight(10)
349 349 # XXX: this doesn't seem to have an effect.
350 350 self.AutoCompSetFillUps('\n')
351 351
352 352 self.SetMargins(3, 3) #text is moved away from border with 3px
353 353 # Suppressing Scintilla margins
354 354 self.SetMarginWidth(0, 0)
355 355 self.SetMarginWidth(1, 0)
356 356 self.SetMarginWidth(2, 0)
357 357
358 358 # Xterm escape sequences
359 359 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
360 360 self.title_pat = re.compile('\x1b]0;(.*?)\x07')
361 361
362 362 # styles
363 363
364 364 self.SetCaretForeground(p['carret_color'])
365 365
366 366 background_color = p['background_color']
367 367
368 368 if 'default' in p:
369 369 if 'back' not in p['default']:
370 370 p['default'] += ',back:%s' % background_color
371 371 if 'size' not in p['default']:
372 372 p['default'] += ',size:%s' % self.faces['size']
373 373 if 'face' not in p['default']:
374 374 p['default'] += ',face:%s' % self.faces['mono']
375 375
376 376 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, p['default'])
377 377 else:
378 378 self.StyleSetSpec(stc.STC_STYLE_DEFAULT,
379 379 "fore:%s,back:%s,size:%d,face:%s"
380 380 % (self.ANSI_STYLES['0;30'][1],
381 381 background_color,
382 382 self.faces['size'], self.faces['mono']))
383 383
384 384 self.StyleClearAll()
385 385
386 386 # XXX: two lines below are usefull if not using the lexer
387 387 #for style in self.ANSI_STYLES.values():
388 388 # self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
389 389
390 390 # prompt definition
391 391 self.prompt_in1 = p['prompt_in1']
392 392 self.prompt_out = p['prompt_out']
393 393
394 394 self.output_prompt_template = string.Template(self.prompt_out)
395 395 self.input_prompt_template = string.Template(self.prompt_in1)
396 396
397 397 self.StyleSetSpec(_STDOUT_STYLE, p['stdout'])
398 398 self.StyleSetSpec(_STDERR_STYLE, p['stderr'])
399 399 self.StyleSetSpec(_TRACE_STYLE, p['trace'])
400 400 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, p['bracegood'])
401 401 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, p['bracebad'])
402 402 self.StyleSetSpec(stc.STC_P_COMMENTLINE, p['comment'])
403 403 self.StyleSetSpec(stc.STC_P_NUMBER, p['number'])
404 404 self.StyleSetSpec(stc.STC_P_STRING, p['string'])
405 405 self.StyleSetSpec(stc.STC_P_CHARACTER, p['char'])
406 406 self.StyleSetSpec(stc.STC_P_WORD, p['keyword'])
407 407 self.StyleSetSpec(stc.STC_P_WORD2, p['keyword'])
408 408 self.StyleSetSpec(stc.STC_P_TRIPLE, p['triple'])
409 409 self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, p['tripledouble'])
410 410 self.StyleSetSpec(stc.STC_P_CLASSNAME, p['class'])
411 411 self.StyleSetSpec(stc.STC_P_DEFNAME, p['def'])
412 412 self.StyleSetSpec(stc.STC_P_OPERATOR, p['operator'])
413 413 self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, p['comment'])
414 414
415 415 edge_column = p['edge_column']
416 416 if edge_column is not None and edge_column > 0:
417 417 #we add a vertical line to console widget
418 418 self.SetEdgeMode(stc.STC_EDGE_LINE)
419 419 self.SetEdgeColumn(edge_column)
420 420
421 421
422 422 #--------------------------------------------------------------------------
423 423 # EditWindow API
424 424 #--------------------------------------------------------------------------
425 425
426 426 def OnUpdateUI(self, event):
427 427 """ Override the OnUpdateUI of the EditWindow class, to prevent
428 428 syntax highlighting both for faster redraw, and for more
429 429 consistent look and feel.
430 430 """
431 431
432 432
433 433 #--------------------------------------------------------------------------
434 434 # Private API
435 435 #--------------------------------------------------------------------------
436 436
437 437 def _on_key_down(self, event, skip=True):
438 438 """ Key press callback used for correcting behavior for
439 439 console-like interfaces: the cursor is constraint to be after
440 440 the last prompt.
441 441
442 442 Return True if event as been catched.
443 443 """
444 444 catched = True
445 445 # XXX: Would the right way to do this be to have a
446 446 # dictionary at the instance level associating keys with
447 447 # callbacks? How would we deal with inheritance? And Do the
448 448 # different callbacks share local variables?
449 449
450 450 # Intercept some specific keys.
451 451 key_code = event.GetKeyCode()
452 452 if key_code == ord('L') and event.ControlDown() :
453 453 self.scroll_to_bottom()
454 454 elif key_code == ord('K') and event.ControlDown() :
455 455 self.input_buffer = ''
456 456 elif key_code == ord('A') and event.ControlDown() :
457 457 self.GotoPos(self.GetLength())
458 458 self.SetSelectionStart(self.current_prompt_pos)
459 459 self.SetSelectionEnd(self.GetCurrentPos())
460 460 catched = True
461 461 elif key_code == ord('E') and event.ControlDown() :
462 462 self.GotoPos(self.GetLength())
463 463 catched = True
464 464 elif key_code == wx.WXK_PAGEUP:
465 465 self.ScrollPages(-1)
466 466 elif key_code == wx.WXK_PAGEDOWN:
467 467 self.ScrollPages(1)
468 468 elif key_code == wx.WXK_HOME:
469 469 self.GotoPos(self.GetLength())
470 470 elif key_code == wx.WXK_END:
471 471 self.GotoPos(self.GetLength())
472 472 elif key_code == wx.WXK_UP and event.ShiftDown():
473 473 self.ScrollLines(-1)
474 474 elif key_code == wx.WXK_DOWN and event.ShiftDown():
475 475 self.ScrollLines(1)
476 476 else:
477 477 catched = False
478 478
479 479 if self.AutoCompActive():
480 480 event.Skip()
481 481 else:
482 482 if key_code in (13, wx.WXK_NUMPAD_ENTER):
483 483 # XXX: not catching modifiers, to be wx2.6-compatible
484 484 catched = True
485 485 if not self.enter_catched:
486 486 self.CallTipCancel()
487 487 if event.ShiftDown():
488 488 # Try to force execution
489 489 self.GotoPos(self.GetLength())
490 490 self.write('\n' + self.continuation_prompt(),
491 491 refresh=False)
492 492 self._on_enter()
493 493 else:
494 494 self._on_enter()
495 495 self.enter_catched = True
496 496
497 497 elif key_code == wx.WXK_HOME:
498 498 if not event.ShiftDown():
499 499 self.GotoPos(self.current_prompt_pos)
500 500 catched = True
501 501 else:
502 502 # FIXME: This behavior is not ideal: if the selection
503 503 # is already started, it will jump.
504 504 self.SetSelectionStart(self.current_prompt_pos)
505 505 self.SetSelectionEnd(self.GetCurrentPos())
506 506 catched = True
507 507
508 508 elif key_code == wx.WXK_UP:
509 509 if self.GetCurrentLine() > self.current_prompt_line:
510 510 if self.GetCurrentLine() == self.current_prompt_line + 1 \
511 511 and self.GetColumn(self.GetCurrentPos()) < \
512 512 self.GetColumn(self.current_prompt_pos):
513 513 self.GotoPos(self.current_prompt_pos)
514 514 else:
515 515 event.Skip()
516 516 catched = True
517 517
518 518 elif key_code in (wx.WXK_LEFT, wx.WXK_BACK):
519 519 if not self._keep_cursor_in_buffer(self.GetCurrentPos() - 1):
520 520 event.Skip()
521 521 catched = True
522 522
523 523 elif key_code == wx.WXK_RIGHT:
524 524 if not self._keep_cursor_in_buffer(self.GetCurrentPos() + 1):
525 525 event.Skip()
526 526 catched = True
527 527
528 528
529 529 elif key_code == wx.WXK_DELETE:
530 530 if not self._keep_cursor_in_buffer(self.GetCurrentPos() - 1):
531 531 event.Skip()
532 532 catched = True
533 533
534 534 if skip and not catched:
535 535 # Put the cursor back in the edit region
536 536 if not self._keep_cursor_in_buffer():
537 537 if not (self.GetCurrentPos() == self.GetLength()
538 538 and key_code == wx.WXK_DELETE):
539 539 event.Skip()
540 540 catched = True
541 541
542 542 return catched
543 543
544 544
545 545 def _on_key_up(self, event, skip=True):
546 546 """ If cursor is outside the editing region, put it back.
547 547 """
548 548 if skip:
549 549 event.Skip()
550 550 self._keep_cursor_in_buffer()
551 551
552 552
553 553 # XXX: I need to avoid the problem of having an empty glass;
554 554 def _keep_cursor_in_buffer(self, pos=None):
555 555 """ Checks if the cursor is where it is allowed to be. If not,
556 556 put it back.
557 557
558 558 Returns
559 559 -------
560 560 cursor_moved: Boolean
561 561 whether or not the cursor was moved by this routine.
562 562
563 563 Notes
564 564 ------
565 565 WARNING: This does proper checks only for horizontal
566 566 movements.
567 567 """
568 568 if pos is None:
569 569 current_pos = self.GetCurrentPos()
570 570 else:
571 571 current_pos = pos
572 572 if current_pos < self.current_prompt_pos:
573 573 self.GotoPos(self.current_prompt_pos)
574 574 return True
575 575 line_num = self.LineFromPosition(current_pos)
576 576 if not current_pos > self.GetLength():
577 577 line_pos = self.GetColumn(current_pos)
578 578 else:
579 579 line_pos = self.GetColumn(self.GetLength())
580 580 line = self.GetLine(line_num)
581 581 # Jump the continuation prompt
582 582 continuation_prompt = self.continuation_prompt()
583 583 if ( line.startswith(continuation_prompt)
584 584 and line_pos < len(continuation_prompt)):
585 585 if line_pos < 2:
586 586 # We are at the beginning of the line, trying to move
587 587 # forward: jump forward.
588 588 self.GotoPos(current_pos + 1 +
589 589 len(continuation_prompt) - line_pos)
590 590 else:
591 591 # Jump back up
592 592 self.GotoPos(self.GetLineEndPosition(line_num-1))
593 593 return True
594 594 elif ( current_pos > self.GetLineEndPosition(line_num)
595 595 and not current_pos == self.GetLength()):
596 596 # Jump to next line
597 597 self.GotoPos(current_pos + 1 +
598 598 len(continuation_prompt))
599 599 return True
600 600
601 601 # We re-allow enter event processing
602 602 self.enter_catched = False
603 603 return False
604 604
605 605
606 606 if __name__ == '__main__':
607 607 # Some simple code to test the console widget.
608 608 class MainWindow(wx.Frame):
609 609 def __init__(self, parent, id, title):
610 610 wx.Frame.__init__(self, parent, id, title, size=(300, 250))
611 611 self._sizer = wx.BoxSizer(wx.VERTICAL)
612 612 self.console_widget = ConsoleWidget(self)
613 613 self._sizer.Add(self.console_widget, 1, wx.EXPAND)
614 614 self.SetSizer(self._sizer)
615 615 self.SetAutoLayout(1)
616 616 self.Show(True)
617 617
618 618 app = wx.PySimpleApp()
619 619 w = MainWindow(None, wx.ID_ANY, 'ConsoleWidget')
620 620 w.SetSize((780, 460))
621 621 w.Show()
622 622
623 623 app.MainLoop()
624 624
625 625
@@ -1,602 +1,602 b''
1 1 # encoding: utf-8 -*- test-case-name:
2 2 # FIXME: Need to add tests.
3 3 # ipython1.frontend.wx.tests.test_wx_frontend -*-
4 4
5 5 """Classes to provide a Wx frontend to the
6 6 IPython.kernel.core.interpreter.
7 7
8 8 This class inherits from ConsoleWidget, that provides a console-like
9 9 widget to provide a text-rendering widget suitable for a terminal.
10 10 """
11 11
12 12 __docformat__ = "restructuredtext en"
13 13
14 14 #-------------------------------------------------------------------------------
15 # Copyright (C) 2008 The IPython Development Team
15 # Copyright (C) 2008-2011 The IPython Development Team
16 16 #
17 17 # Distributed under the terms of the BSD License. The full license is in
18 18 # the file COPYING, distributed as part of this software.
19 19 #-------------------------------------------------------------------------------
20 20
21 21 #-------------------------------------------------------------------------------
22 22 # Imports
23 23 #-------------------------------------------------------------------------------
24 24
25 25 # Major library imports
26 26 import re
27 27 import __builtin__
28 28 import sys
29 29 from threading import Lock
30 30
31 31 import wx
32 32 from wx import stc
33 33
34 34 # Ipython-specific imports.
35 35 from IPython.frontend.process import PipedProcess
36 36 from console_widget import ConsoleWidget, _COMPLETE_BUFFER_MARKER, \
37 37 _ERROR_MARKER, _INPUT_MARKER
38 38 from IPython.frontend.prefilterfrontend import PrefilterFrontEnd
39 39
40 40 #-------------------------------------------------------------------------------
41 41 # Classes to implement the Wx frontend
42 42 #-------------------------------------------------------------------------------
43 43 class WxController(ConsoleWidget, PrefilterFrontEnd):
44 44 """Classes to provide a Wx frontend to the
45 45 IPython.kernel.core.interpreter.
46 46
47 47 This class inherits from ConsoleWidget, that provides a console-like
48 48 widget to provide a text-rendering widget suitable for a terminal.
49 49 """
50 50
51 51 # Print debug info on what is happening to the console.
52 52 debug = False
53 53
54 54 # The title of the terminal, as captured through the ANSI escape
55 55 # sequences.
56 56 def _set_title(self, title):
57 57 return self.Parent.SetTitle(title)
58 58
59 59 def _get_title(self):
60 60 return self.Parent.GetTitle()
61 61
62 62 title = property(_get_title, _set_title)
63 63
64 64
65 65 # The buffer being edited.
66 66 # We are duplicating the definition here because of multiple
67 67 # inheritence
68 68 def _set_input_buffer(self, string):
69 69 ConsoleWidget._set_input_buffer(self, string)
70 70 self._colorize_input_buffer()
71 71
72 72 def _get_input_buffer(self):
73 73 """ Returns the text in current edit buffer.
74 74 """
75 75 return ConsoleWidget._get_input_buffer(self)
76 76
77 77 input_buffer = property(_get_input_buffer, _set_input_buffer)
78 78
79 79
80 80 #--------------------------------------------------------------------------
81 81 # Private Attributes
82 82 #--------------------------------------------------------------------------
83 83
84 84 # A flag governing the behavior of the input. Can be:
85 85 #
86 86 # 'readline' for readline-like behavior with a prompt
87 87 # and an edit buffer.
88 88 # 'raw_input' similar to readline, but triggered by a raw-input
89 89 # call. Can be used by subclasses to act differently.
90 90 # 'subprocess' for sending the raw input directly to a
91 91 # subprocess.
92 92 # 'buffering' for buffering of the input, that will be used
93 93 # when the input state switches back to another state.
94 94 _input_state = 'readline'
95 95
96 96 # Attribute to store reference to the pipes of a subprocess, if we
97 97 # are running any.
98 98 _running_process = False
99 99
100 100 # A queue for writing fast streams to the screen without flooding the
101 101 # event loop
102 102 _out_buffer = []
103 103
104 104 # A lock to lock the _out_buffer to make sure we don't empty it
105 105 # while it is being swapped
106 106 _out_buffer_lock = Lock()
107 107
108 108 # The different line markers used to higlight the prompts.
109 109 _markers = dict()
110 110
111 111 #--------------------------------------------------------------------------
112 112 # Public API
113 113 #--------------------------------------------------------------------------
114 114
115 115 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
116 116 size=wx.DefaultSize,
117 117 style=wx.CLIP_CHILDREN|wx.WANTS_CHARS,
118 118 styledef=None,
119 119 *args, **kwds):
120 120 """ Create Shell instance.
121 121
122 122 Parameters
123 123 -----------
124 124 styledef : dict, optional
125 125 styledef is the dictionary of options used to define the
126 126 style.
127 127 """
128 128 if styledef is not None:
129 129 self.style = styledef
130 130 ConsoleWidget.__init__(self, parent, id, pos, size, style)
131 131 PrefilterFrontEnd.__init__(self, **kwds)
132 132
133 133 # Stick in our own raw_input:
134 134 self.ipython0.raw_input = self.raw_input
135 135
136 136 # A time for flushing the write buffer
137 137 BUFFER_FLUSH_TIMER_ID = 100
138 138 self._buffer_flush_timer = wx.Timer(self, BUFFER_FLUSH_TIMER_ID)
139 139 wx.EVT_TIMER(self, BUFFER_FLUSH_TIMER_ID, self._buffer_flush)
140 140
141 141 if 'debug' in kwds:
142 142 self.debug = kwds['debug']
143 143 kwds.pop('debug')
144 144
145 145 # Inject self in namespace, for debug
146 146 if self.debug:
147 147 self.shell.user_ns['self'] = self
148 148 # Inject our own raw_input in namespace
149 149 self.shell.user_ns['raw_input'] = self.raw_input
150 150
151 151 def raw_input(self, prompt=''):
152 152 """ A replacement from python's raw_input.
153 153 """
154 154 self.new_prompt(prompt)
155 155 self._input_state = 'raw_input'
156 156 if hasattr(self, '_cursor'):
157 157 del self._cursor
158 158 self.SetCursor(wx.StockCursor(wx.CURSOR_CROSS))
159 159 self.__old_on_enter = self._on_enter
160 160 event_loop = wx.EventLoop()
161 161 def my_on_enter():
162 162 event_loop.Exit()
163 163 self._on_enter = my_on_enter
164 164 # XXX: Running a separate event_loop. Ugly.
165 165 event_loop.Run()
166 166 self._on_enter = self.__old_on_enter
167 167 self._input_state = 'buffering'
168 168 self._cursor = wx.BusyCursor()
169 169 return self.input_buffer.rstrip('\n')
170 170
171 171
172 172 def system_call(self, command_string):
173 173 self._input_state = 'subprocess'
174 174 event_loop = wx.EventLoop()
175 175 def _end_system_call():
176 176 self._input_state = 'buffering'
177 177 self._running_process = False
178 178 event_loop.Exit()
179 179
180 180 self._running_process = PipedProcess(command_string,
181 181 out_callback=self.buffered_write,
182 182 end_callback = _end_system_call)
183 183 self._running_process.start()
184 184 # XXX: Running a separate event_loop. Ugly.
185 185 event_loop.Run()
186 186 # Be sure to flush the buffer.
187 187 self._buffer_flush(event=None)
188 188
189 189
190 190 def do_calltip(self):
191 191 """ Analyse current and displays useful calltip for it.
192 192 """
193 193 if self.debug:
194 194 print >>sys.__stdout__, "do_calltip"
195 195 separators = re.compile('[\s\{\}\[\]\(\)\= ,:]')
196 196 symbol = self.input_buffer
197 197 symbol_string = separators.split(symbol)[-1]
198 198 base_symbol_string = symbol_string.split('.')[0]
199 199 if base_symbol_string in self.shell.user_ns:
200 200 symbol = self.shell.user_ns[base_symbol_string]
201 201 elif base_symbol_string in self.shell.user_global_ns:
202 202 symbol = self.shell.user_global_ns[base_symbol_string]
203 203 elif base_symbol_string in __builtin__.__dict__:
204 204 symbol = __builtin__.__dict__[base_symbol_string]
205 205 else:
206 206 return False
207 207 try:
208 208 for name in symbol_string.split('.')[1:] + ['__doc__']:
209 209 symbol = getattr(symbol, name)
210 210 self.AutoCompCancel()
211 211 # Check that the symbol can indeed be converted to a string:
212 212 symbol += ''
213 213 wx.CallAfter(self.CallTipShow, self.GetCurrentPos(), symbol)
214 214 except:
215 215 # The retrieve symbol couldn't be converted to a string
216 216 pass
217 217
218 218
219 219 def _popup_completion(self, create=False):
220 220 """ Updates the popup completion menu if it exists. If create is
221 221 true, open the menu.
222 222 """
223 223 if self.debug:
224 224 print >>sys.__stdout__, "_popup_completion"
225 225 line = self.input_buffer
226 226 if (self.AutoCompActive() and line and not line[-1] == '.') \
227 227 or create==True:
228 228 suggestion, completions = self.complete(line)
229 229 if completions:
230 230 offset = len(self._get_completion_text(line))
231 231 self.pop_completion(completions, offset=offset)
232 232 if self.debug:
233 233 print >>sys.__stdout__, completions
234 234
235 235
236 236 def buffered_write(self, text):
237 237 """ A write method for streams, that caches the stream in order
238 238 to avoid flooding the event loop.
239 239
240 240 This can be called outside of the main loop, in separate
241 241 threads.
242 242 """
243 243 self._out_buffer_lock.acquire()
244 244 self._out_buffer.append(text)
245 245 self._out_buffer_lock.release()
246 246 if not self._buffer_flush_timer.IsRunning():
247 247 wx.CallAfter(self._buffer_flush_timer.Start,
248 248 milliseconds=100, oneShot=True)
249 249
250 250
251 251 def clear_screen(self):
252 252 """ Empty completely the widget.
253 253 """
254 254 self.ClearAll()
255 255 self.new_prompt(self.input_prompt_template.substitute(
256 256 number=(self.last_result['number'] + 1)))
257 257
258 258
259 259 #--------------------------------------------------------------------------
260 260 # LineFrontEnd interface
261 261 #--------------------------------------------------------------------------
262 262
263 263 def execute(self, python_string, raw_string=None):
264 264 self._input_state = 'buffering'
265 265 self.CallTipCancel()
266 266 self._cursor = wx.BusyCursor()
267 267 if raw_string is None:
268 268 raw_string = python_string
269 269 end_line = self.current_prompt_line \
270 270 + max(1, len(raw_string.split('\n'))-1)
271 271 for i in range(self.current_prompt_line, end_line):
272 272 if i in self._markers:
273 273 self.MarkerDeleteHandle(self._markers[i])
274 274 self._markers[i] = self.MarkerAdd(i, _COMPLETE_BUFFER_MARKER)
275 275 # Use a callafter to update the display robustly under windows
276 276 def callback():
277 277 self.GotoPos(self.GetLength())
278 278 PrefilterFrontEnd.execute(self, python_string,
279 279 raw_string=raw_string)
280 280 wx.CallAfter(callback)
281 281
282 282
283 283 def execute_command(self, command, hidden=False):
284 284 """ Execute a command, not only in the model, but also in the
285 285 view.
286 286 """
287 287 # XXX: This method needs to be integrated in the base fronted
288 288 # interface
289 289 if hidden:
290 290 return self.shell.execute(command)
291 291 else:
292 292 # XXX: we are not storing the input buffer previous to the
293 293 # execution, as this forces us to run the execution
294 294 # input_buffer a yield, which is not good.
295 295 ##current_buffer = self.shell.control.input_buffer
296 296 command = command.rstrip()
297 297 if len(command.split('\n')) > 1:
298 298 # The input command is several lines long, we need to
299 299 # force the execution to happen
300 300 command += '\n'
301 301 cleaned_command = self.prefilter_input(command)
302 302 self.input_buffer = command
303 303 # Do not use wx.Yield() (aka GUI.process_events()) to avoid
304 304 # recursive yields.
305 305 self.ProcessEvent(wx.PaintEvent())
306 306 self.write('\n')
307 307 if not self.is_complete(cleaned_command + '\n'):
308 308 self._colorize_input_buffer()
309 309 self.render_error('Incomplete or invalid input')
310 310 self.new_prompt(self.input_prompt_template.substitute(
311 311 number=(self.last_result['number'] + 1)))
312 312 return False
313 313 self._on_enter()
314 314 return True
315 315
316 316
317 317 def save_output_hooks(self):
318 318 self.__old_raw_input = __builtin__.raw_input
319 319 PrefilterFrontEnd.save_output_hooks(self)
320 320
321 321 def capture_output(self):
322 322 self.SetLexer(stc.STC_LEX_NULL)
323 323 PrefilterFrontEnd.capture_output(self)
324 324 __builtin__.raw_input = self.raw_input
325 325
326 326
327 327 def release_output(self):
328 328 __builtin__.raw_input = self.__old_raw_input
329 329 PrefilterFrontEnd.release_output(self)
330 330 self.SetLexer(stc.STC_LEX_PYTHON)
331 331
332 332
333 333 def after_execute(self):
334 334 PrefilterFrontEnd.after_execute(self)
335 335 # Clear the wait cursor
336 336 if hasattr(self, '_cursor'):
337 337 del self._cursor
338 338 self.SetCursor(wx.StockCursor(wx.CURSOR_CHAR))
339 339
340 340
341 341 def show_traceback(self):
342 342 start_line = self.GetCurrentLine()
343 343 PrefilterFrontEnd.show_traceback(self)
344 344 self.ProcessEvent(wx.PaintEvent())
345 345 #wx.Yield()
346 346 for i in range(start_line, self.GetCurrentLine()):
347 347 self._markers[i] = self.MarkerAdd(i, _ERROR_MARKER)
348 348
349 349
350 350 #--------------------------------------------------------------------------
351 351 # FrontEndBase interface
352 352 #--------------------------------------------------------------------------
353 353
354 354 def render_error(self, e):
355 355 start_line = self.GetCurrentLine()
356 356 self.write('\n' + e + '\n')
357 357 for i in range(start_line, self.GetCurrentLine()):
358 358 self._markers[i] = self.MarkerAdd(i, _ERROR_MARKER)
359 359
360 360
361 361 #--------------------------------------------------------------------------
362 362 # ConsoleWidget interface
363 363 #--------------------------------------------------------------------------
364 364
365 365 def new_prompt(self, prompt):
366 366 """ Display a new prompt, and start a new input buffer.
367 367 """
368 368 self._input_state = 'readline'
369 369 ConsoleWidget.new_prompt(self, prompt)
370 370 i = self.current_prompt_line
371 371 self._markers[i] = self.MarkerAdd(i, _INPUT_MARKER)
372 372
373 373
374 374 def continuation_prompt(self, *args, **kwargs):
375 375 # Avoid multiple inheritence, be explicit about which
376 376 # parent method class gets called
377 377 return ConsoleWidget.continuation_prompt(self, *args, **kwargs)
378 378
379 379
380 380 def write(self, *args, **kwargs):
381 381 # Avoid multiple inheritence, be explicit about which
382 382 # parent method class gets called
383 383 return ConsoleWidget.write(self, *args, **kwargs)
384 384
385 385
386 386 def _on_key_down(self, event, skip=True):
387 387 """ Capture the character events, let the parent
388 388 widget handle them, and put our logic afterward.
389 389 """
390 390 # FIXME: This method needs to be broken down in smaller ones.
391 391 current_line_num = self.GetCurrentLine()
392 392 key_code = event.GetKeyCode()
393 393 if key_code in (ord('c'), ord('C')) and event.ControlDown():
394 394 # Capture Control-C
395 395 if self._input_state == 'subprocess':
396 396 if self.debug:
397 397 print >>sys.__stderr__, 'Killing running process'
398 398 if hasattr(self._running_process, 'process'):
399 399 self._running_process.process.kill()
400 400 elif self._input_state == 'buffering':
401 401 if self.debug:
402 402 print >>sys.__stderr__, 'Raising KeyboardInterrupt'
403 403 raise KeyboardInterrupt
404 404 # XXX: We need to make really sure we
405 405 # get back to a prompt.
406 406 elif self._input_state == 'subprocess' and (
407 407 ( key_code <256 and not event.ControlDown() )
408 408 or
409 409 ( key_code in (ord('d'), ord('D')) and
410 410 event.ControlDown())):
411 411 # We are running a process, we redirect keys.
412 412 ConsoleWidget._on_key_down(self, event, skip=skip)
413 413 char = chr(key_code)
414 414 # Deal with some inconsistency in wx keycodes:
415 415 if char == '\r':
416 416 char = '\n'
417 417 elif not event.ShiftDown():
418 418 char = char.lower()
419 419 if event.ControlDown() and key_code in (ord('d'), ord('D')):
420 420 char = '\04'
421 421 self._running_process.process.stdin.write(char)
422 422 self._running_process.process.stdin.flush()
423 423 elif key_code in (ord('('), 57, 53):
424 424 # Calltips
425 425 event.Skip()
426 426 self.do_calltip()
427 427 elif self.AutoCompActive() and not key_code == ord('\t'):
428 428 event.Skip()
429 429 if key_code in (wx.WXK_BACK, wx.WXK_DELETE):
430 430 wx.CallAfter(self._popup_completion, create=True)
431 431 elif not key_code in (wx.WXK_UP, wx.WXK_DOWN, wx.WXK_LEFT,
432 432 wx.WXK_RIGHT, wx.WXK_ESCAPE):
433 433 wx.CallAfter(self._popup_completion)
434 434 else:
435 435 # Up history
436 436 if key_code == wx.WXK_UP and (
437 437 event.ControlDown() or
438 438 current_line_num == self.current_prompt_line
439 439 ):
440 440 new_buffer = self.get_history_previous(
441 441 self.input_buffer)
442 442 if new_buffer is not None:
443 443 self.input_buffer = new_buffer
444 444 if self.GetCurrentLine() > self.current_prompt_line:
445 445 # Go to first line, for seemless history up.
446 446 self.GotoPos(self.current_prompt_pos)
447 447 # Down history
448 448 elif key_code == wx.WXK_DOWN and (
449 449 event.ControlDown() or
450 450 current_line_num == self.LineCount -1
451 451 ):
452 452 new_buffer = self.get_history_next()
453 453 if new_buffer is not None:
454 454 self.input_buffer = new_buffer
455 455 # Tab-completion
456 456 elif key_code == ord('\t'):
457 457 current_line, current_line_num = self.CurLine
458 458 if not re.match(r'^%s\s*$' % self.continuation_prompt(),
459 459 current_line):
460 460 self.complete_current_input()
461 461 if self.AutoCompActive():
462 462 wx.CallAfter(self._popup_completion, create=True)
463 463 else:
464 464 event.Skip()
465 465 elif key_code == wx.WXK_BACK:
466 466 # If characters where erased, check if we have to
467 467 # remove a line.
468 468 # XXX: What about DEL?
469 469 # FIXME: This logics should be in ConsoleWidget, as it is
470 470 # independant of IPython
471 471 current_line, _ = self.CurLine
472 472 current_pos = self.GetCurrentPos()
473 473 current_line_num = self.LineFromPosition(current_pos)
474 474 current_col = self.GetColumn(current_pos)
475 475 len_prompt = len(self.continuation_prompt())
476 476 if ( current_line.startswith(self.continuation_prompt())
477 477 and current_col == len_prompt):
478 478 new_lines = []
479 479 for line_num, line in enumerate(
480 480 self.input_buffer.split('\n')):
481 481 if (line_num + self.current_prompt_line ==
482 482 current_line_num):
483 483 new_lines.append(line[len_prompt:])
484 484 else:
485 485 new_lines.append('\n'+line)
486 486 # The first character is '\n', due to the above
487 487 # code:
488 488 self.input_buffer = ''.join(new_lines)[1:]
489 489 self.GotoPos(current_pos - 1 - len_prompt)
490 490 else:
491 491 ConsoleWidget._on_key_down(self, event, skip=skip)
492 492 else:
493 493 ConsoleWidget._on_key_down(self, event, skip=skip)
494 494
495 495
496 496
497 497 def _on_key_up(self, event, skip=True):
498 498 """ Called when any key is released.
499 499 """
500 500 if event.GetKeyCode() in (59, ord('.')):
501 501 # Intercepting '.'
502 502 event.Skip()
503 503 wx.CallAfter(self._popup_completion, create=True)
504 504 else:
505 505 ConsoleWidget._on_key_up(self, event, skip=skip)
506 506 # Make sure the continuation_prompts are always followed by a
507 507 # whitespace
508 508 new_lines = []
509 509 if self._input_state == 'readline':
510 510 position = self.GetCurrentPos()
511 511 continuation_prompt = self.continuation_prompt()[:-1]
512 512 for line in self.input_buffer.split('\n'):
513 513 if not line == continuation_prompt:
514 514 new_lines.append(line)
515 515 self.input_buffer = '\n'.join(new_lines)
516 516 self.GotoPos(position)
517 517
518 518
519 519 def _on_enter(self):
520 520 """ Called on return key down, in readline input_state.
521 521 """
522 522 last_line_num = self.LineFromPosition(self.GetLength())
523 523 current_line_num = self.LineFromPosition(self.GetCurrentPos())
524 524 new_line_pos = (last_line_num - current_line_num)
525 525 if self.debug:
526 526 print >>sys.__stdout__, repr(self.input_buffer)
527 527 self.write('\n', refresh=False)
528 528 # Under windows scintilla seems to be doing funny
529 529 # stuff to the line returns here, but the getter for
530 530 # input_buffer filters this out.
531 531 if sys.platform == 'win32':
532 532 self.input_buffer = self.input_buffer
533 533 old_prompt_num = self.current_prompt_pos
534 534 has_executed = PrefilterFrontEnd._on_enter(self,
535 535 new_line_pos=new_line_pos)
536 536 if old_prompt_num == self.current_prompt_pos:
537 537 # No execution has happened
538 538 self.GotoPos(self.GetLineEndPosition(current_line_num + 1))
539 539 return has_executed
540 540
541 541
542 542 #--------------------------------------------------------------------------
543 543 # EditWindow API
544 544 #--------------------------------------------------------------------------
545 545
546 546 def OnUpdateUI(self, event):
547 547 """ Override the OnUpdateUI of the EditWindow class, to prevent
548 548 syntax highlighting both for faster redraw, and for more
549 549 consistent look and feel.
550 550 """
551 551 if not self._input_state == 'readline':
552 552 ConsoleWidget.OnUpdateUI(self, event)
553 553
554 554 #--------------------------------------------------------------------------
555 555 # Private API
556 556 #--------------------------------------------------------------------------
557 557
558 558 def _buffer_flush(self, event):
559 559 """ Called by the timer to flush the write buffer.
560 560
561 561 This is always called in the mainloop, by the wx timer.
562 562 """
563 563 self._out_buffer_lock.acquire()
564 564 _out_buffer = self._out_buffer
565 565 self._out_buffer = []
566 566 self._out_buffer_lock.release()
567 567 self.write(''.join(_out_buffer), refresh=False)
568 568
569 569
570 570 def _colorize_input_buffer(self):
571 571 """ Keep the input buffer lines at a bright color.
572 572 """
573 573 if not self._input_state in ('readline', 'raw_input'):
574 574 return
575 575 end_line = self.GetCurrentLine()
576 576 if not sys.platform == 'win32':
577 577 end_line += 1
578 578 for i in range(self.current_prompt_line, end_line):
579 579 if i in self._markers:
580 580 self.MarkerDeleteHandle(self._markers[i])
581 581 self._markers[i] = self.MarkerAdd(i, _INPUT_MARKER)
582 582
583 583
584 584 if __name__ == '__main__':
585 585 class MainWindow(wx.Frame):
586 586 def __init__(self, parent, id, title):
587 587 wx.Frame.__init__(self, parent, id, title, size=(300,250))
588 588 self._sizer = wx.BoxSizer(wx.VERTICAL)
589 589 self.shell = WxController(self)
590 590 self._sizer.Add(self.shell, 1, wx.EXPAND)
591 591 self.SetSizer(self._sizer)
592 592 self.SetAutoLayout(1)
593 593 self.Show(True)
594 594
595 595 app = wx.PySimpleApp()
596 596 frame = MainWindow(None, wx.ID_ANY, 'Ipython')
597 597 frame.shell.SetFocus()
598 598 frame.SetSize((680, 460))
599 599 self = frame.shell
600 600
601 601 app.MainLoop()
602 602
@@ -1,27 +1,27 b''
1 1 # encoding: utf-8
2 2 # -*- test-case-name: IPython.frontend.tests.test_frontendbase -*-
3 3 """
4 4 zope.interface mock. If zope is installed, this module provides a zope
5 5 interface classes, if not it provides mocks for them.
6 6
7 7 Classes provided:
8 8 Interface, Attribute, implements, classProvides
9 9 """
10 10 __docformat__ = "restructuredtext en"
11 11
12 12 #-------------------------------------------------------------------------------
13 # Copyright (C) 2008 The IPython Development Team
13 # Copyright (C) 2008-2011 The IPython Development Team
14 14 #
15 15 # Distributed under the terms of the BSD License. The full license is in
16 16 # the file COPYING, distributed as part of this software.
17 17 #-------------------------------------------------------------------------------
18 18
19 19 try:
20 20 from zope.interface import Interface, Attribute, implements, classProvides
21 21 except ImportError:
22 22 #zope.interface is not available
23 23 Interface = object
24 24 def Attribute(name, doc): pass
25 25 def implements(interface): pass
26 26 def classProvides(interface): pass
27 27
@@ -1,47 +1,47 b''
1 1 # coding: utf-8
2 2 """
3 3 A simple class for quitting IPython.
4 4
5 5 Authors
6 6 -------
7 7 * Fernando Perez
8 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 14 # Distributed under the terms of the BSD License. The full license is in
15 15 # the file COPYING, distributed as part of this software.
16 16 #-----------------------------------------------------------------------------
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Imports
20 20 #-----------------------------------------------------------------------------
21 21
22 22
23 23 #-----------------------------------------------------------------------------
24 24 # Code
25 25 #-----------------------------------------------------------------------------
26 26
27 27
28 28 class Quitter(object):
29 29 """Simple class to handle exit, similar to Python 2.5's.
30 30
31 31 It handles exiting in an ipython-safe manner, which the one in Python 2.5
32 32 doesn't do (obviously, since it doesn't know about ipython)."""
33 33
34 34 def __init__(self, shell, name):
35 35 self.shell = shell
36 36 self.name = name
37 37
38 38 def __str__(self):
39 39 return 'Type %s() to exit.' % self.name
40 40
41 41 def __call__(self):
42 42 self.shell.ask_exit()
43 43
44 44 # Repr MUST return a string, else display like pprint hooks get confused
45 45 def __repr__(self):
46 46 self.shell.ask_exit()
47 47 return ''
@@ -1,325 +1,325 b''
1 1 # encoding: utf-8
2 2 """
3 3 =============
4 4 parallelmagic
5 5 =============
6 6
7 7 Magic command interface for interactive parallel work.
8 8
9 9 Usage
10 10 =====
11 11
12 12 ``%autopx``
13 13
14 14 @AUTOPX_DOC@
15 15
16 16 ``%px``
17 17
18 18 @PX_DOC@
19 19
20 20 ``%result``
21 21
22 22 @RESULT_DOC@
23 23
24 24 """
25 25
26 26 #-----------------------------------------------------------------------------
27 # Copyright (C) 2008-2009 The IPython Development Team
27 # Copyright (C) 2008-2011 The IPython Development Team
28 28 #
29 29 # Distributed under the terms of the BSD License. The full license is in
30 30 # the file COPYING, distributed as part of this software.
31 31 #-----------------------------------------------------------------------------
32 32
33 33 #-----------------------------------------------------------------------------
34 34 # Imports
35 35 #-----------------------------------------------------------------------------
36 36
37 37 import ast
38 38 import re
39 39
40 40 from IPython.core.plugin import Plugin
41 41 from IPython.utils.traitlets import Bool, Any, Instance
42 42 from IPython.testing.skipdoctest import skip_doctest
43 43
44 44 #-----------------------------------------------------------------------------
45 45 # Definitions of magic functions for use with IPython
46 46 #-----------------------------------------------------------------------------
47 47
48 48
49 49 NO_ACTIVE_VIEW = """
50 50 Use activate() on a DirectView object to activate it for magics.
51 51 """
52 52
53 53
54 54 class ParalleMagic(Plugin):
55 55 """A component to manage the %result, %px and %autopx magics."""
56 56
57 57 active_view = Instance('IPython.parallel.client.view.DirectView')
58 58 verbose = Bool(False, config=True)
59 59 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
60 60
61 61 def __init__(self, shell=None, config=None):
62 62 super(ParalleMagic, self).__init__(shell=shell, config=config)
63 63 self._define_magics()
64 64 # A flag showing if autopx is activated or not
65 65 self.autopx = False
66 66
67 67 def _define_magics(self):
68 68 """Define the magic functions."""
69 69 self.shell.define_magic('result', self.magic_result)
70 70 self.shell.define_magic('px', self.magic_px)
71 71 self.shell.define_magic('autopx', self.magic_autopx)
72 72
73 73 @skip_doctest
74 74 def magic_result(self, ipself, parameter_s=''):
75 75 """Print the result of command i on all engines..
76 76
77 77 To use this a :class:`DirectView` instance must be created
78 78 and then activated by calling its :meth:`activate` method.
79 79
80 80 Then you can do the following::
81 81
82 82 In [23]: %result
83 83 Out[23]:
84 84 <Results List>
85 85 [0] In [6]: a = 10
86 86 [1] In [6]: a = 10
87 87
88 88 In [22]: %result 6
89 89 Out[22]:
90 90 <Results List>
91 91 [0] In [6]: a = 10
92 92 [1] In [6]: a = 10
93 93 """
94 94 if self.active_view is None:
95 95 print NO_ACTIVE_VIEW
96 96 return
97 97
98 98 try:
99 99 index = int(parameter_s)
100 100 except:
101 101 index = None
102 102 result = self.active_view.get_result(index)
103 103 return result
104 104
105 105 @skip_doctest
106 106 def magic_px(self, ipself, parameter_s=''):
107 107 """Executes the given python command in parallel.
108 108
109 109 To use this a :class:`DirectView` instance must be created
110 110 and then activated by calling its :meth:`activate` method.
111 111
112 112 Then you can do the following::
113 113
114 114 In [24]: %px a = 5
115 115 Parallel execution on engine(s): all
116 116 Out[24]:
117 117 <Results List>
118 118 [0] In [7]: a = 5
119 119 [1] In [7]: a = 5
120 120 """
121 121
122 122 if self.active_view is None:
123 123 print NO_ACTIVE_VIEW
124 124 return
125 125 print "Parallel execution on engine(s): %s" % self.active_view.targets
126 126 result = self.active_view.execute(parameter_s, block=False)
127 127 if self.active_view.block:
128 128 result.get()
129 129 self._maybe_display_output(result)
130 130
131 131 @skip_doctest
132 132 def magic_autopx(self, ipself, parameter_s=''):
133 133 """Toggles auto parallel mode.
134 134
135 135 To use this a :class:`DirectView` instance must be created
136 136 and then activated by calling its :meth:`activate` method. Once this
137 137 is called, all commands typed at the command line are send to
138 138 the engines to be executed in parallel. To control which engine
139 139 are used, set the ``targets`` attributed of the multiengine client
140 140 before entering ``%autopx`` mode.
141 141
142 142 Then you can do the following::
143 143
144 144 In [25]: %autopx
145 145 %autopx to enabled
146 146
147 147 In [26]: a = 10
148 148 Parallel execution on engine(s): [0,1,2,3]
149 149 In [27]: print a
150 150 Parallel execution on engine(s): [0,1,2,3]
151 151 [stdout:0] 10
152 152 [stdout:1] 10
153 153 [stdout:2] 10
154 154 [stdout:3] 10
155 155
156 156
157 157 In [27]: %autopx
158 158 %autopx disabled
159 159 """
160 160 if self.autopx:
161 161 self._disable_autopx()
162 162 else:
163 163 self._enable_autopx()
164 164
165 165 def _enable_autopx(self):
166 166 """Enable %autopx mode by saving the original run_cell and installing
167 167 pxrun_cell.
168 168 """
169 169 if self.active_view is None:
170 170 print NO_ACTIVE_VIEW
171 171 return
172 172
173 173 # override run_cell and run_code
174 174 self._original_run_cell = self.shell.run_cell
175 175 self.shell.run_cell = self.pxrun_cell
176 176 self._original_run_code = self.shell.run_code
177 177 self.shell.run_code = self.pxrun_code
178 178
179 179 self.autopx = True
180 180 print "%autopx enabled"
181 181
182 182 def _disable_autopx(self):
183 183 """Disable %autopx by restoring the original InteractiveShell.run_cell.
184 184 """
185 185 if self.autopx:
186 186 self.shell.run_cell = self._original_run_cell
187 187 self.shell.run_code = self._original_run_code
188 188 self.autopx = False
189 189 print "%autopx disabled"
190 190
191 191 def _maybe_display_output(self, result):
192 192 """Maybe display the output of a parallel result.
193 193
194 194 If self.active_view.block is True, wait for the result
195 195 and display the result. Otherwise, this is a noop.
196 196 """
197 197 if isinstance(result.stdout, basestring):
198 198 # single result
199 199 stdouts = [result.stdout.rstrip()]
200 200 else:
201 201 stdouts = [s.rstrip() for s in result.stdout]
202 202
203 203 targets = self.active_view.targets
204 204 if isinstance(targets, int):
205 205 targets = [targets]
206 206 elif targets == 'all':
207 207 targets = self.active_view.client.ids
208 208
209 209 if any(stdouts):
210 210 for eid,stdout in zip(targets, stdouts):
211 211 print '[stdout:%i]'%eid, stdout
212 212
213 213
214 214 def pxrun_cell(self, raw_cell, store_history=True):
215 215 """drop-in replacement for InteractiveShell.run_cell.
216 216
217 217 This executes code remotely, instead of in the local namespace.
218 218
219 219 See InteractiveShell.run_cell for details.
220 220 """
221 221
222 222 if (not raw_cell) or raw_cell.isspace():
223 223 return
224 224
225 225 ipself = self.shell
226 226
227 227 with ipself.builtin_trap:
228 228 cell = ipself.prefilter_manager.prefilter_lines(raw_cell)
229 229
230 230 # Store raw and processed history
231 231 if store_history:
232 232 ipself.history_manager.store_inputs(ipself.execution_count,
233 233 cell, raw_cell)
234 234
235 235 # ipself.logger.log(cell, raw_cell)
236 236
237 237 cell_name = ipself.compile.cache(cell, ipself.execution_count)
238 238
239 239 try:
240 240 code_ast = ast.parse(cell, filename=cell_name)
241 241 except (OverflowError, SyntaxError, ValueError, TypeError, MemoryError):
242 242 # Case 1
243 243 ipself.showsyntaxerror()
244 244 ipself.execution_count += 1
245 245 return None
246 246 except NameError:
247 247 # ignore name errors, because we don't know the remote keys
248 248 pass
249 249
250 250 if store_history:
251 251 # Write output to the database. Does nothing unless
252 252 # history output logging is enabled.
253 253 ipself.history_manager.store_output(ipself.execution_count)
254 254 # Each cell is a *single* input, regardless of how many lines it has
255 255 ipself.execution_count += 1
256 256 if re.search(r'get_ipython\(\)\.magic\(u?["\']%?autopx', cell):
257 257 self._disable_autopx()
258 258 return False
259 259 else:
260 260 try:
261 261 result = self.active_view.execute(cell, block=False)
262 262 except:
263 263 ipself.showtraceback()
264 264 return True
265 265 else:
266 266 if self.active_view.block:
267 267 try:
268 268 result.get()
269 269 except:
270 270 self.shell.showtraceback()
271 271 return True
272 272 else:
273 273 self._maybe_display_output(result)
274 274 return False
275 275
276 276 def pxrun_code(self, code_obj):
277 277 """drop-in replacement for InteractiveShell.run_code.
278 278
279 279 This executes code remotely, instead of in the local namespace.
280 280
281 281 See InteractiveShell.run_code for details.
282 282 """
283 283 ipself = self.shell
284 284 # check code object for the autopx magic
285 285 if 'get_ipython' in code_obj.co_names and 'magic' in code_obj.co_names and \
286 286 any( [ isinstance(c, basestring) and 'autopx' in c for c in code_obj.co_consts ]):
287 287 self._disable_autopx()
288 288 return False
289 289 else:
290 290 try:
291 291 result = self.active_view.execute(code_obj, block=False)
292 292 except:
293 293 ipself.showtraceback()
294 294 return True
295 295 else:
296 296 if self.active_view.block:
297 297 try:
298 298 result.get()
299 299 except:
300 300 self.shell.showtraceback()
301 301 return True
302 302 else:
303 303 self._maybe_display_output(result)
304 304 return False
305 305
306 306
307 307 __doc__ = __doc__.replace('@AUTOPX_DOC@',
308 308 " " + ParalleMagic.magic_autopx.__doc__)
309 309 __doc__ = __doc__.replace('@PX_DOC@',
310 310 " " + ParalleMagic.magic_px.__doc__)
311 311 __doc__ = __doc__.replace('@RESULT_DOC@',
312 312 " " + ParalleMagic.magic_result.__doc__)
313 313
314 314
315 315 _loaded = False
316 316
317 317
318 318 def load_ipython_extension(ip):
319 319 """Load the extension in IPython."""
320 320 global _loaded
321 321 if not _loaded:
322 322 plugin = ParalleMagic(shell=ip, config=ip.config)
323 323 ip.plugin_manager.register_plugin('parallelmagic', plugin)
324 324 _loaded = True
325 325
@@ -1,249 +1,249 b''
1 1 # encoding: utf-8
2 2 """
3 3 An embedded IPython shell.
4 4
5 5 Authors:
6 6
7 7 * Brian Granger
8 8 * Fernando Perez
9 9
10 10 Notes
11 11 -----
12 12 """
13 13
14 14 #-----------------------------------------------------------------------------
15 # Copyright (C) 2008-2009 The IPython Development Team
15 # Copyright (C) 2008-2011 The IPython Development Team
16 16 #
17 17 # Distributed under the terms of the BSD License. The full license is in
18 18 # the file COPYING, distributed as part of this software.
19 19 #-----------------------------------------------------------------------------
20 20
21 21 #-----------------------------------------------------------------------------
22 22 # Imports
23 23 #-----------------------------------------------------------------------------
24 24
25 25 from __future__ import with_statement
26 26 import __main__
27 27
28 28 import sys
29 29 try:
30 30 from contextlib import nested
31 31 except:
32 32 from IPython.utils.nested_context import nested
33 33
34 34 from IPython.core import ultratb
35 35 from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
36 36 from IPython.frontend.terminal.ipapp import load_default_config
37 37
38 38 from IPython.utils.traitlets import Bool, CBool, Unicode
39 39 from IPython.utils.io import ask_yes_no
40 40
41 41
42 42 #-----------------------------------------------------------------------------
43 43 # Classes and functions
44 44 #-----------------------------------------------------------------------------
45 45
46 46 # This is an additional magic that is exposed in embedded shells.
47 47 def kill_embedded(self,parameter_s=''):
48 48 """%kill_embedded : deactivate for good the current embedded IPython.
49 49
50 50 This function (after asking for confirmation) sets an internal flag so that
51 51 an embedded IPython will never activate again. This is useful to
52 52 permanently disable a shell that is being called inside a loop: once you've
53 53 figured out what you needed from it, you may then kill it and the program
54 54 will then continue to run without the interactive shell interfering again.
55 55 """
56 56
57 57 kill = ask_yes_no("Are you sure you want to kill this embedded instance "
58 58 "(y/n)? [y/N] ",'n')
59 59 if kill:
60 60 self.embedded_active = False
61 61 print "This embedded IPython will not reactivate anymore once you exit."
62 62
63 63
64 64 class InteractiveShellEmbed(TerminalInteractiveShell):
65 65
66 66 dummy_mode = Bool(False)
67 67 exit_msg = Unicode('')
68 68 embedded = CBool(True)
69 69 embedded_active = CBool(True)
70 70 # Like the base class display_banner is not configurable, but here it
71 71 # is True by default.
72 72 display_banner = CBool(True)
73 73
74 74 def __init__(self, config=None, ipython_dir=None, user_ns=None,
75 75 user_global_ns=None, custom_exceptions=((),None),
76 76 usage=None, banner1=None, banner2=None,
77 77 display_banner=None, exit_msg=u''):
78 78
79 79 super(InteractiveShellEmbed,self).__init__(
80 80 config=config, ipython_dir=ipython_dir, user_ns=user_ns,
81 81 user_global_ns=user_global_ns, custom_exceptions=custom_exceptions,
82 82 usage=usage, banner1=banner1, banner2=banner2,
83 83 display_banner=display_banner
84 84 )
85 85
86 86 self.exit_msg = exit_msg
87 87 self.define_magic("kill_embedded", kill_embedded)
88 88
89 89 # don't use the ipython crash handler so that user exceptions aren't
90 90 # trapped
91 91 sys.excepthook = ultratb.FormattedTB(color_scheme=self.colors,
92 92 mode=self.xmode,
93 93 call_pdb=self.pdb)
94 94
95 95 def init_sys_modules(self):
96 96 pass
97 97
98 98 def __call__(self, header='', local_ns=None, global_ns=None, dummy=None,
99 99 stack_depth=1):
100 100 """Activate the interactive interpreter.
101 101
102 102 __call__(self,header='',local_ns=None,global_ns,dummy=None) -> Start
103 103 the interpreter shell with the given local and global namespaces, and
104 104 optionally print a header string at startup.
105 105
106 106 The shell can be globally activated/deactivated using the
107 107 set/get_dummy_mode methods. This allows you to turn off a shell used
108 108 for debugging globally.
109 109
110 110 However, *each* time you call the shell you can override the current
111 111 state of dummy_mode with the optional keyword parameter 'dummy'. For
112 112 example, if you set dummy mode on with IPShell.set_dummy_mode(1), you
113 113 can still have a specific call work by making it as IPShell(dummy=0).
114 114
115 115 The optional keyword parameter dummy controls whether the call
116 116 actually does anything.
117 117 """
118 118
119 119 # If the user has turned it off, go away
120 120 if not self.embedded_active:
121 121 return
122 122
123 123 # Normal exits from interactive mode set this flag, so the shell can't
124 124 # re-enter (it checks this variable at the start of interactive mode).
125 125 self.exit_now = False
126 126
127 127 # Allow the dummy parameter to override the global __dummy_mode
128 128 if dummy or (dummy != 0 and self.dummy_mode):
129 129 return
130 130
131 131 if self.has_readline:
132 132 self.set_readline_completer()
133 133
134 134 # self.banner is auto computed
135 135 if header:
136 136 self.old_banner2 = self.banner2
137 137 self.banner2 = self.banner2 + '\n' + header + '\n'
138 138 else:
139 139 self.old_banner2 = ''
140 140
141 141 # Call the embedding code with a stack depth of 1 so it can skip over
142 142 # our call and get the original caller's namespaces.
143 143 self.mainloop(local_ns, global_ns, stack_depth=stack_depth)
144 144
145 145 self.banner2 = self.old_banner2
146 146
147 147 if self.exit_msg is not None:
148 148 print self.exit_msg
149 149
150 150 def mainloop(self, local_ns=None, global_ns=None, stack_depth=0,
151 151 display_banner=None):
152 152 """Embeds IPython into a running python program.
153 153
154 154 Input:
155 155
156 156 - header: An optional header message can be specified.
157 157
158 158 - local_ns, global_ns: working namespaces. If given as None, the
159 159 IPython-initialized one is updated with __main__.__dict__, so that
160 160 program variables become visible but user-specific configuration
161 161 remains possible.
162 162
163 163 - stack_depth: specifies how many levels in the stack to go to
164 164 looking for namespaces (when local_ns and global_ns are None). This
165 165 allows an intermediate caller to make sure that this function gets
166 166 the namespace from the intended level in the stack. By default (0)
167 167 it will get its locals and globals from the immediate caller.
168 168
169 169 Warning: it's possible to use this in a program which is being run by
170 170 IPython itself (via %run), but some funny things will happen (a few
171 171 globals get overwritten). In the future this will be cleaned up, as
172 172 there is no fundamental reason why it can't work perfectly."""
173 173
174 174 # Get locals and globals from caller
175 175 if local_ns is None or global_ns is None:
176 176 call_frame = sys._getframe(stack_depth).f_back
177 177
178 178 if local_ns is None:
179 179 local_ns = call_frame.f_locals
180 180 if global_ns is None:
181 181 global_ns = call_frame.f_globals
182 182
183 183 # Update namespaces and fire up interpreter
184 184
185 185 # The global one is easy, we can just throw it in
186 186 self.user_global_ns = global_ns
187 187
188 188 # but the user/local one is tricky: ipython needs it to store internal
189 189 # data, but we also need the locals. We'll copy locals in the user
190 190 # one, but will track what got copied so we can delete them at exit.
191 191 # This is so that a later embedded call doesn't see locals from a
192 192 # previous call (which most likely existed in a separate scope).
193 193 local_varnames = local_ns.keys()
194 194 self.user_ns.update(local_ns)
195 195 #self.user_ns['local_ns'] = local_ns # dbg
196 196
197 197 # Patch for global embedding to make sure that things don't overwrite
198 198 # user globals accidentally. Thanks to Richard <rxe@renre-europe.com>
199 199 # FIXME. Test this a bit more carefully (the if.. is new)
200 200 if local_ns is None and global_ns is None:
201 201 self.user_global_ns.update(__main__.__dict__)
202 202
203 203 # make sure the tab-completer has the correct frame information, so it
204 204 # actually completes using the frame's locals/globals
205 205 self.set_completer_frame()
206 206
207 207 with nested(self.builtin_trap, self.display_trap):
208 208 self.interact(display_banner=display_banner)
209 209
210 210 # now, purge out the user namespace from anything we might have added
211 211 # from the caller's local namespace
212 212 delvar = self.user_ns.pop
213 213 for var in local_varnames:
214 214 delvar(var,None)
215 215
216 216
217 217 _embedded_shell = None
218 218
219 219
220 220 def embed(**kwargs):
221 221 """Call this to embed IPython at the current point in your program.
222 222
223 223 The first invocation of this will create an :class:`InteractiveShellEmbed`
224 224 instance and then call it. Consecutive calls just call the already
225 225 created instance.
226 226
227 227 Here is a simple example::
228 228
229 229 from IPython import embed
230 230 a = 10
231 231 b = 20
232 232 embed('First time')
233 233 c = 30
234 234 d = 40
235 235 embed
236 236
237 237 Full customization can be done by passing a :class:`Struct` in as the
238 238 config argument.
239 239 """
240 240 config = kwargs.get('config')
241 241 header = kwargs.pop('header', u'')
242 242 if config is None:
243 243 config = load_default_config()
244 244 config.InteractiveShellEmbed = config.TerminalInteractiveShell
245 245 kwargs['config'] = config
246 246 global _embedded_shell
247 247 if _embedded_shell is None:
248 248 _embedded_shell = InteractiveShellEmbed(**kwargs)
249 249 _embedded_shell(header=header, stack_depth=2)
@@ -1,646 +1,646 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Subclass of InteractiveShell for terminal based frontends."""
3 3
4 4 #-----------------------------------------------------------------------------
5 5 # Copyright (C) 2001 Janko Hauser <jhauser@zscout.de>
6 6 # Copyright (C) 2001-2007 Fernando Perez. <fperez@colorado.edu>
7 # Copyright (C) 2008-2010 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 import __builtin__
18 18 import bdb
19 19 import os
20 20 import re
21 21 import sys
22 22
23 23 try:
24 24 from contextlib import nested
25 25 except:
26 26 from IPython.utils.nested_context import nested
27 27
28 28 from IPython.core.error import TryNext
29 29 from IPython.core.usage import interactive_usage, default_banner
30 30 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
31 31 from IPython.lib.inputhook import enable_gui
32 32 from IPython.lib.pylabtools import pylab_activate
33 33 from IPython.testing.skipdoctest import skip_doctest
34 34 from IPython.utils import py3compat
35 35 from IPython.utils.terminal import toggle_set_term_title, set_term_title
36 36 from IPython.utils.process import abbrev_cwd
37 37 from IPython.utils.warn import warn, error
38 38 from IPython.utils.text import num_ini_spaces
39 39 from IPython.utils.traitlets import Integer, CBool, Unicode
40 40
41 41 #-----------------------------------------------------------------------------
42 42 # Utilities
43 43 #-----------------------------------------------------------------------------
44 44
45 45 def get_default_editor():
46 46 try:
47 47 ed = os.environ['EDITOR']
48 48 except KeyError:
49 49 if os.name == 'posix':
50 50 ed = 'vi' # the only one guaranteed to be there!
51 51 else:
52 52 ed = 'notepad' # same in Windows!
53 53 return ed
54 54
55 55 #-----------------------------------------------------------------------------
56 56 # Main class
57 57 #-----------------------------------------------------------------------------
58 58
59 59 class TerminalInteractiveShell(InteractiveShell):
60 60
61 61 autoedit_syntax = CBool(False, config=True,
62 62 help="auto editing of files with syntax errors.")
63 63 banner = Unicode('')
64 64 banner1 = Unicode(default_banner, config=True,
65 65 help="""The part of the banner to be printed before the profile"""
66 66 )
67 67 banner2 = Unicode('', config=True,
68 68 help="""The part of the banner to be printed after the profile"""
69 69 )
70 70 confirm_exit = CBool(True, config=True,
71 71 help="""
72 72 Set to confirm when you try to exit IPython with an EOF (Control-D
73 73 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
74 74 you can force a direct exit without any confirmation.""",
75 75 )
76 76 # This display_banner only controls whether or not self.show_banner()
77 77 # is called when mainloop/interact are called. The default is False
78 78 # because for the terminal based application, the banner behavior
79 79 # is controlled by Global.display_banner, which IPythonApp looks at
80 80 # to determine if *it* should call show_banner() by hand or not.
81 81 display_banner = CBool(False) # This isn't configurable!
82 82 embedded = CBool(False)
83 83 embedded_active = CBool(False)
84 84 editor = Unicode(get_default_editor(), config=True,
85 85 help="Set the editor used by IPython (default to $EDITOR/vi/notepad)."
86 86 )
87 87 pager = Unicode('less', config=True,
88 88 help="The shell program to be used for paging.")
89 89
90 90 screen_length = Integer(0, config=True,
91 91 help=
92 92 """Number of lines of your screen, used to control printing of very
93 93 long strings. Strings longer than this number of lines will be sent
94 94 through a pager instead of directly printed. The default value for
95 95 this is 0, which means IPython will auto-detect your screen size every
96 96 time it needs to print certain potentially long strings (this doesn't
97 97 change the behavior of the 'print' keyword, it's only triggered
98 98 internally). If for some reason this isn't working well (it needs
99 99 curses support), specify it yourself. Otherwise don't change the
100 100 default.""",
101 101 )
102 102 term_title = CBool(False, config=True,
103 103 help="Enable auto setting the terminal title."
104 104 )
105 105
106 106 def __init__(self, config=None, ipython_dir=None, profile_dir=None, user_ns=None,
107 107 user_global_ns=None, custom_exceptions=((),None),
108 108 usage=None, banner1=None, banner2=None,
109 109 display_banner=None):
110 110
111 111 super(TerminalInteractiveShell, self).__init__(
112 112 config=config, profile_dir=profile_dir, user_ns=user_ns,
113 113 user_global_ns=user_global_ns, custom_exceptions=custom_exceptions
114 114 )
115 115 # use os.system instead of utils.process.system by default,
116 116 # because piped system doesn't make sense in the Terminal:
117 117 self.system = self.system_raw
118 118
119 119 self.init_term_title()
120 120 self.init_usage(usage)
121 121 self.init_banner(banner1, banner2, display_banner)
122 122
123 123 #-------------------------------------------------------------------------
124 124 # Things related to the terminal
125 125 #-------------------------------------------------------------------------
126 126
127 127 @property
128 128 def usable_screen_length(self):
129 129 if self.screen_length == 0:
130 130 return 0
131 131 else:
132 132 num_lines_bot = self.separate_in.count('\n')+1
133 133 return self.screen_length - num_lines_bot
134 134
135 135 def init_term_title(self):
136 136 # Enable or disable the terminal title.
137 137 if self.term_title:
138 138 toggle_set_term_title(True)
139 139 set_term_title('IPython: ' + abbrev_cwd())
140 140 else:
141 141 toggle_set_term_title(False)
142 142
143 143 #-------------------------------------------------------------------------
144 144 # Things related to aliases
145 145 #-------------------------------------------------------------------------
146 146
147 147 def init_alias(self):
148 148 # The parent class defines aliases that can be safely used with any
149 149 # frontend.
150 150 super(TerminalInteractiveShell, self).init_alias()
151 151
152 152 # Now define aliases that only make sense on the terminal, because they
153 153 # need direct access to the console in a way that we can't emulate in
154 154 # GUI or web frontend
155 155 if os.name == 'posix':
156 156 aliases = [('clear', 'clear'), ('more', 'more'), ('less', 'less'),
157 157 ('man', 'man')]
158 158 elif os.name == 'nt':
159 159 aliases = [('cls', 'cls')]
160 160
161 161
162 162 for name, cmd in aliases:
163 163 self.alias_manager.define_alias(name, cmd)
164 164
165 165 #-------------------------------------------------------------------------
166 166 # Things related to the banner and usage
167 167 #-------------------------------------------------------------------------
168 168
169 169 def _banner1_changed(self):
170 170 self.compute_banner()
171 171
172 172 def _banner2_changed(self):
173 173 self.compute_banner()
174 174
175 175 def _term_title_changed(self, name, new_value):
176 176 self.init_term_title()
177 177
178 178 def init_banner(self, banner1, banner2, display_banner):
179 179 if banner1 is not None:
180 180 self.banner1 = banner1
181 181 if banner2 is not None:
182 182 self.banner2 = banner2
183 183 if display_banner is not None:
184 184 self.display_banner = display_banner
185 185 self.compute_banner()
186 186
187 187 def show_banner(self, banner=None):
188 188 if banner is None:
189 189 banner = self.banner
190 190 self.write(banner)
191 191
192 192 def compute_banner(self):
193 193 self.banner = self.banner1
194 194 if self.profile and self.profile != 'default':
195 195 self.banner += '\nIPython profile: %s\n' % self.profile
196 196 if self.banner2:
197 197 self.banner += '\n' + self.banner2
198 198
199 199 def init_usage(self, usage=None):
200 200 if usage is None:
201 201 self.usage = interactive_usage
202 202 else:
203 203 self.usage = usage
204 204
205 205 #-------------------------------------------------------------------------
206 206 # Mainloop and code execution logic
207 207 #-------------------------------------------------------------------------
208 208
209 209 def mainloop(self, display_banner=None):
210 210 """Start the mainloop.
211 211
212 212 If an optional banner argument is given, it will override the
213 213 internally created default banner.
214 214 """
215 215
216 216 with nested(self.builtin_trap, self.display_trap):
217 217
218 218 while 1:
219 219 try:
220 220 self.interact(display_banner=display_banner)
221 221 #self.interact_with_readline()
222 222 # XXX for testing of a readline-decoupled repl loop, call
223 223 # interact_with_readline above
224 224 break
225 225 except KeyboardInterrupt:
226 226 # this should not be necessary, but KeyboardInterrupt
227 227 # handling seems rather unpredictable...
228 228 self.write("\nKeyboardInterrupt in interact()\n")
229 229
230 230 def _replace_rlhist_multiline(self, source_raw, hlen_before_cell):
231 231 """Store multiple lines as a single entry in history"""
232 232
233 233 # do nothing without readline or disabled multiline
234 234 if not self.has_readline or not self.multiline_history:
235 235 return hlen_before_cell
236 236
237 237 # windows rl has no remove_history_item
238 238 if not hasattr(self.readline, "remove_history_item"):
239 239 return hlen_before_cell
240 240
241 241 # skip empty cells
242 242 if not source_raw.rstrip():
243 243 return hlen_before_cell
244 244
245 245 # nothing changed do nothing, e.g. when rl removes consecutive dups
246 246 hlen = self.readline.get_current_history_length()
247 247 if hlen == hlen_before_cell:
248 248 return hlen_before_cell
249 249
250 250 for i in range(hlen - hlen_before_cell):
251 251 self.readline.remove_history_item(hlen - i - 1)
252 252 stdin_encoding = sys.stdin.encoding or "utf-8"
253 253 self.readline.add_history(py3compat.unicode_to_str(source_raw.rstrip(),
254 254 stdin_encoding))
255 255 return self.readline.get_current_history_length()
256 256
257 257 def interact(self, display_banner=None):
258 258 """Closely emulate the interactive Python console."""
259 259
260 260 # batch run -> do not interact
261 261 if self.exit_now:
262 262 return
263 263
264 264 if display_banner is None:
265 265 display_banner = self.display_banner
266 266
267 267 if isinstance(display_banner, basestring):
268 268 self.show_banner(display_banner)
269 269 elif display_banner:
270 270 self.show_banner()
271 271
272 272 more = False
273 273
274 274 # Mark activity in the builtins
275 275 __builtin__.__dict__['__IPYTHON__active'] += 1
276 276
277 277 if self.has_readline:
278 278 self.readline_startup_hook(self.pre_readline)
279 279 hlen_b4_cell = self.readline.get_current_history_length()
280 280 else:
281 281 hlen_b4_cell = 0
282 282 # exit_now is set by a call to %Exit or %Quit, through the
283 283 # ask_exit callback.
284 284
285 285 while not self.exit_now:
286 286 self.hooks.pre_prompt_hook()
287 287 if more:
288 288 try:
289 289 prompt = self.hooks.generate_prompt(True)
290 290 except:
291 291 self.showtraceback()
292 292 if self.autoindent:
293 293 self.rl_do_indent = True
294 294
295 295 else:
296 296 try:
297 297 prompt = self.hooks.generate_prompt(False)
298 298 except:
299 299 self.showtraceback()
300 300 try:
301 301 line = self.raw_input(prompt)
302 302 if self.exit_now:
303 303 # quick exit on sys.std[in|out] close
304 304 break
305 305 if self.autoindent:
306 306 self.rl_do_indent = False
307 307
308 308 except KeyboardInterrupt:
309 309 #double-guard against keyboardinterrupts during kbdint handling
310 310 try:
311 311 self.write('\nKeyboardInterrupt\n')
312 312 source_raw = self.input_splitter.source_raw_reset()[1]
313 313 hlen_b4_cell = \
314 314 self._replace_rlhist_multiline(source_raw, hlen_b4_cell)
315 315 more = False
316 316 except KeyboardInterrupt:
317 317 pass
318 318 except EOFError:
319 319 if self.autoindent:
320 320 self.rl_do_indent = False
321 321 if self.has_readline:
322 322 self.readline_startup_hook(None)
323 323 self.write('\n')
324 324 self.exit()
325 325 except bdb.BdbQuit:
326 326 warn('The Python debugger has exited with a BdbQuit exception.\n'
327 327 'Because of how pdb handles the stack, it is impossible\n'
328 328 'for IPython to properly format this particular exception.\n'
329 329 'IPython will resume normal operation.')
330 330 except:
331 331 # exceptions here are VERY RARE, but they can be triggered
332 332 # asynchronously by signal handlers, for example.
333 333 self.showtraceback()
334 334 else:
335 335 self.input_splitter.push(line)
336 336 more = self.input_splitter.push_accepts_more()
337 337 if (self.SyntaxTB.last_syntax_error and
338 338 self.autoedit_syntax):
339 339 self.edit_syntax_error()
340 340 if not more:
341 341 source_raw = self.input_splitter.source_raw_reset()[1]
342 342 self.run_cell(source_raw, store_history=True)
343 343 hlen_b4_cell = \
344 344 self._replace_rlhist_multiline(source_raw, hlen_b4_cell)
345 345
346 346 # We are off again...
347 347 __builtin__.__dict__['__IPYTHON__active'] -= 1
348 348
349 349 # Turn off the exit flag, so the mainloop can be restarted if desired
350 350 self.exit_now = False
351 351
352 352 def raw_input(self, prompt=''):
353 353 """Write a prompt and read a line.
354 354
355 355 The returned line does not include the trailing newline.
356 356 When the user enters the EOF key sequence, EOFError is raised.
357 357
358 358 Optional inputs:
359 359
360 360 - prompt(''): a string to be printed to prompt the user.
361 361
362 362 - continue_prompt(False): whether this line is the first one or a
363 363 continuation in a sequence of inputs.
364 364 """
365 365 # Code run by the user may have modified the readline completer state.
366 366 # We must ensure that our completer is back in place.
367 367
368 368 if self.has_readline:
369 369 self.set_readline_completer()
370 370
371 371 try:
372 372 line = py3compat.str_to_unicode(self.raw_input_original(prompt))
373 373 except ValueError:
374 374 warn("\n********\nYou or a %run:ed script called sys.stdin.close()"
375 375 " or sys.stdout.close()!\nExiting IPython!")
376 376 self.ask_exit()
377 377 return ""
378 378
379 379 # Try to be reasonably smart about not re-indenting pasted input more
380 380 # than necessary. We do this by trimming out the auto-indent initial
381 381 # spaces, if the user's actual input started itself with whitespace.
382 382 if self.autoindent:
383 383 if num_ini_spaces(line) > self.indent_current_nsp:
384 384 line = line[self.indent_current_nsp:]
385 385 self.indent_current_nsp = 0
386 386
387 387 return line
388 388
389 389 #-------------------------------------------------------------------------
390 390 # Methods to support auto-editing of SyntaxErrors.
391 391 #-------------------------------------------------------------------------
392 392
393 393 def edit_syntax_error(self):
394 394 """The bottom half of the syntax error handler called in the main loop.
395 395
396 396 Loop until syntax error is fixed or user cancels.
397 397 """
398 398
399 399 while self.SyntaxTB.last_syntax_error:
400 400 # copy and clear last_syntax_error
401 401 err = self.SyntaxTB.clear_err_state()
402 402 if not self._should_recompile(err):
403 403 return
404 404 try:
405 405 # may set last_syntax_error again if a SyntaxError is raised
406 406 self.safe_execfile(err.filename,self.user_ns)
407 407 except:
408 408 self.showtraceback()
409 409 else:
410 410 try:
411 411 f = file(err.filename)
412 412 try:
413 413 # This should be inside a display_trap block and I
414 414 # think it is.
415 415 sys.displayhook(f.read())
416 416 finally:
417 417 f.close()
418 418 except:
419 419 self.showtraceback()
420 420
421 421 def _should_recompile(self,e):
422 422 """Utility routine for edit_syntax_error"""
423 423
424 424 if e.filename in ('<ipython console>','<input>','<string>',
425 425 '<console>','<BackgroundJob compilation>',
426 426 None):
427 427
428 428 return False
429 429 try:
430 430 if (self.autoedit_syntax and
431 431 not self.ask_yes_no('Return to editor to correct syntax error? '
432 432 '[Y/n] ','y')):
433 433 return False
434 434 except EOFError:
435 435 return False
436 436
437 437 def int0(x):
438 438 try:
439 439 return int(x)
440 440 except TypeError:
441 441 return 0
442 442 # always pass integer line and offset values to editor hook
443 443 try:
444 444 self.hooks.fix_error_editor(e.filename,
445 445 int0(e.lineno),int0(e.offset),e.msg)
446 446 except TryNext:
447 447 warn('Could not open editor')
448 448 return False
449 449 return True
450 450
451 451 #-------------------------------------------------------------------------
452 452 # Things related to GUI support and pylab
453 453 #-------------------------------------------------------------------------
454 454
455 455 def enable_pylab(self, gui=None, import_all=True):
456 456 """Activate pylab support at runtime.
457 457
458 458 This turns on support for matplotlib, preloads into the interactive
459 459 namespace all of numpy and pylab, and configures IPython to correcdtly
460 460 interact with the GUI event loop. The GUI backend to be used can be
461 461 optionally selected with the optional :param:`gui` argument.
462 462
463 463 Parameters
464 464 ----------
465 465 gui : optional, string
466 466
467 467 If given, dictates the choice of matplotlib GUI backend to use
468 468 (should be one of IPython's supported backends, 'tk', 'qt', 'wx' or
469 469 'gtk'), otherwise we use the default chosen by matplotlib (as
470 470 dictated by the matplotlib build-time options plus the user's
471 471 matplotlibrc configuration file).
472 472 """
473 473 # We want to prevent the loading of pylab to pollute the user's
474 474 # namespace as shown by the %who* magics, so we execute the activation
475 475 # code in an empty namespace, and we update *both* user_ns and
476 476 # user_ns_hidden with this information.
477 477 ns = {}
478 478 try:
479 479 gui = pylab_activate(ns, gui, import_all)
480 480 except KeyError:
481 481 error("Backend %r not supported" % gui)
482 482 return
483 483 self.user_ns.update(ns)
484 484 self.user_ns_hidden.update(ns)
485 485 # Now we must activate the gui pylab wants to use, and fix %run to take
486 486 # plot updates into account
487 487 enable_gui(gui)
488 488 self.magic_run = self._pylab_magic_run
489 489
490 490 #-------------------------------------------------------------------------
491 491 # Things related to exiting
492 492 #-------------------------------------------------------------------------
493 493
494 494 def ask_exit(self):
495 495 """ Ask the shell to exit. Can be overiden and used as a callback. """
496 496 self.exit_now = True
497 497
498 498 def exit(self):
499 499 """Handle interactive exit.
500 500
501 501 This method calls the ask_exit callback."""
502 502 if self.confirm_exit:
503 503 if self.ask_yes_no('Do you really want to exit ([y]/n)?','y'):
504 504 self.ask_exit()
505 505 else:
506 506 self.ask_exit()
507 507
508 508 #------------------------------------------------------------------------
509 509 # Magic overrides
510 510 #------------------------------------------------------------------------
511 511 # Once the base class stops inheriting from magic, this code needs to be
512 512 # moved into a separate machinery as well. For now, at least isolate here
513 513 # the magics which this class needs to implement differently from the base
514 514 # class, or that are unique to it.
515 515
516 516 def magic_autoindent(self, parameter_s = ''):
517 517 """Toggle autoindent on/off (if available)."""
518 518
519 519 self.shell.set_autoindent()
520 520 print "Automatic indentation is:",['OFF','ON'][self.shell.autoindent]
521 521
522 522 @skip_doctest
523 523 def magic_cpaste(self, parameter_s=''):
524 524 """Paste & execute a pre-formatted code block from clipboard.
525 525
526 526 You must terminate the block with '--' (two minus-signs) or Ctrl-D alone on the
527 527 line. You can also provide your own sentinel with '%paste -s %%' ('%%'
528 528 is the new sentinel for this operation)
529 529
530 530 The block is dedented prior to execution to enable execution of method
531 531 definitions. '>' and '+' characters at the beginning of a line are
532 532 ignored, to allow pasting directly from e-mails, diff files and
533 533 doctests (the '...' continuation prompt is also stripped). The
534 534 executed block is also assigned to variable named 'pasted_block' for
535 535 later editing with '%edit pasted_block'.
536 536
537 537 You can also pass a variable name as an argument, e.g. '%cpaste foo'.
538 538 This assigns the pasted block to variable 'foo' as string, without
539 539 dedenting or executing it (preceding >>> and + is still stripped)
540 540
541 541 '%cpaste -r' re-executes the block previously entered by cpaste.
542 542
543 543 Do not be alarmed by garbled output on Windows (it's a readline bug).
544 544 Just press enter and type -- (and press enter again) and the block
545 545 will be what was just pasted.
546 546
547 547 IPython statements (magics, shell escapes) are not supported (yet).
548 548
549 549 See also
550 550 --------
551 551 paste: automatically pull code from clipboard.
552 552
553 553 Examples
554 554 --------
555 555 ::
556 556
557 557 In [8]: %cpaste
558 558 Pasting code; enter '--' alone on the line to stop.
559 559 :>>> a = ["world!", "Hello"]
560 560 :>>> print " ".join(sorted(a))
561 561 :--
562 562 Hello world!
563 563 """
564 564
565 565 opts,args = self.parse_options(parameter_s,'rs:',mode='string')
566 566 par = args.strip()
567 567 if opts.has_key('r'):
568 568 self._rerun_pasted()
569 569 return
570 570
571 571 sentinel = opts.get('s','--')
572 572
573 573 block = self._strip_pasted_lines_for_code(
574 574 self._get_pasted_lines(sentinel))
575 575
576 576 self._execute_block(block, par)
577 577
578 578 def magic_paste(self, parameter_s=''):
579 579 """Paste & execute a pre-formatted code block from clipboard.
580 580
581 581 The text is pulled directly from the clipboard without user
582 582 intervention and printed back on the screen before execution (unless
583 583 the -q flag is given to force quiet mode).
584 584
585 585 The block is dedented prior to execution to enable execution of method
586 586 definitions. '>' and '+' characters at the beginning of a line are
587 587 ignored, to allow pasting directly from e-mails, diff files and
588 588 doctests (the '...' continuation prompt is also stripped). The
589 589 executed block is also assigned to variable named 'pasted_block' for
590 590 later editing with '%edit pasted_block'.
591 591
592 592 You can also pass a variable name as an argument, e.g. '%paste foo'.
593 593 This assigns the pasted block to variable 'foo' as string, without
594 594 dedenting or executing it (preceding >>> and + is still stripped)
595 595
596 596 Options
597 597 -------
598 598
599 599 -r: re-executes the block previously entered by cpaste.
600 600
601 601 -q: quiet mode: do not echo the pasted text back to the terminal.
602 602
603 603 IPython statements (magics, shell escapes) are not supported (yet).
604 604
605 605 See also
606 606 --------
607 607 cpaste: manually paste code into terminal until you mark its end.
608 608 """
609 609 opts,args = self.parse_options(parameter_s,'rq',mode='string')
610 610 par = args.strip()
611 611 if opts.has_key('r'):
612 612 self._rerun_pasted()
613 613 return
614 614 try:
615 615 text = self.shell.hooks.clipboard_get()
616 616 block = self._strip_pasted_lines_for_code(text.splitlines())
617 617 except TryNext as clipboard_exc:
618 618 message = getattr(clipboard_exc, 'args')
619 619 if message:
620 620 error(message[0])
621 621 else:
622 622 error('Could not get text from the clipboard.')
623 623 return
624 624
625 625 # By default, echo back to terminal unless quiet mode is requested
626 626 if not opts.has_key('q'):
627 627 write = self.shell.write
628 628 write(self.shell.pycolorize(block))
629 629 if not block.endswith('\n'):
630 630 write('\n')
631 631 write("## -- End pasted text --\n")
632 632
633 633 self._execute_block(block, par)
634 634
635 635 if sys.platform == 'win32':
636 636 def magic_cls(self, s):
637 637 """Clear screen.
638 638 """
639 639 os.system("cls")
640 640
641 641 def showindentationerror(self):
642 642 super(TerminalInteractiveShell, self).showindentationerror()
643 643 print("If you want to paste code into IPython, try the %paste magic function.")
644 644
645 645
646 646 InteractiveShellABC.register(TerminalInteractiveShell)
@@ -1,397 +1,397 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 """
4 4 The :class:`~IPython.core.application.Application` object for the command
5 5 line :command:`ipython` program.
6 6
7 7 Authors
8 8 -------
9 9
10 10 * Brian Granger
11 11 * Fernando Perez
12 12 * Min Ragan-Kelley
13 13 """
14 14
15 15 #-----------------------------------------------------------------------------
16 # Copyright (C) 2008-2010 The IPython Development Team
16 # Copyright (C) 2008-2011 The IPython Development Team
17 17 #
18 18 # Distributed under the terms of the BSD License. The full license is in
19 19 # the file COPYING, distributed as part of this software.
20 20 #-----------------------------------------------------------------------------
21 21
22 22 #-----------------------------------------------------------------------------
23 23 # Imports
24 24 #-----------------------------------------------------------------------------
25 25
26 26 from __future__ import absolute_import
27 27
28 28 import logging
29 29 import os
30 30 import sys
31 31
32 32 from IPython.config.loader import (
33 33 Config, PyFileConfigLoader, ConfigFileNotFound
34 34 )
35 35 from IPython.config.application import boolean_flag, catch_config_error
36 36 from IPython.core import release
37 37 from IPython.core import usage
38 38 from IPython.core.completer import IPCompleter
39 39 from IPython.core.crashhandler import CrashHandler
40 40 from IPython.core.formatters import PlainTextFormatter
41 41 from IPython.core.application import (
42 42 ProfileDir, BaseIPythonApplication, base_flags, base_aliases
43 43 )
44 44 from IPython.core.shellapp import (
45 45 InteractiveShellApp, shell_flags, shell_aliases
46 46 )
47 47 from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
48 48 from IPython.lib import inputhook
49 49 from IPython.utils import warn
50 50 from IPython.utils.path import get_ipython_dir, check_for_old_config
51 51 from IPython.utils.traitlets import (
52 52 Bool, List, Dict, CaselessStrEnum
53 53 )
54 54
55 55 #-----------------------------------------------------------------------------
56 56 # Globals, utilities and helpers
57 57 #-----------------------------------------------------------------------------
58 58
59 59 #: The default config file name for this application.
60 60 default_config_file_name = u'ipython_config.py'
61 61
62 62 _examples = """
63 63 ipython --pylab # start in pylab mode
64 64 ipython --pylab=qt # start in pylab mode with the qt4 backend
65 65 ipython --log-level=DEBUG # set logging to DEBUG
66 66 ipython --profile=foo # start with profile foo
67 67
68 68 ipython qtconsole # start the qtconsole GUI application
69 69 ipython qtconsole -h # show the help string for the qtconsole subcmd
70 70
71 71 ipython profile create foo # create profile foo w/ default config files
72 72 ipython profile -h # show the help string for the profile subcmd
73 73 """
74 74
75 75 #-----------------------------------------------------------------------------
76 76 # Crash handler for this application
77 77 #-----------------------------------------------------------------------------
78 78
79 79 class IPAppCrashHandler(CrashHandler):
80 80 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
81 81
82 82 def __init__(self, app):
83 83 contact_name = release.authors['Fernando'][0]
84 84 contact_email = release.author_email
85 85 bug_tracker = 'https://github.com/ipython/ipython/issues'
86 86 super(IPAppCrashHandler,self).__init__(
87 87 app, contact_name, contact_email, bug_tracker
88 88 )
89 89
90 90 def make_report(self,traceback):
91 91 """Return a string containing a crash report."""
92 92
93 93 sec_sep = self.section_sep
94 94 # Start with parent report
95 95 report = [super(IPAppCrashHandler, self).make_report(traceback)]
96 96 # Add interactive-specific info we may have
97 97 rpt_add = report.append
98 98 try:
99 99 rpt_add(sec_sep+"History of session input:")
100 100 for line in self.app.shell.user_ns['_ih']:
101 101 rpt_add(line)
102 102 rpt_add('\n*** Last line of input (may not be in above history):\n')
103 103 rpt_add(self.app.shell._last_input_line+'\n')
104 104 except:
105 105 pass
106 106
107 107 return ''.join(report)
108 108
109 109 #-----------------------------------------------------------------------------
110 110 # Aliases and Flags
111 111 #-----------------------------------------------------------------------------
112 112 flags = dict(base_flags)
113 113 flags.update(shell_flags)
114 114 addflag = lambda *args: flags.update(boolean_flag(*args))
115 115 addflag('autoedit-syntax', 'TerminalInteractiveShell.autoedit_syntax',
116 116 'Turn on auto editing of files with syntax errors.',
117 117 'Turn off auto editing of files with syntax errors.'
118 118 )
119 119 addflag('banner', 'TerminalIPythonApp.display_banner',
120 120 "Display a banner upon starting IPython.",
121 121 "Don't display a banner upon starting IPython."
122 122 )
123 123 addflag('confirm-exit', 'TerminalInteractiveShell.confirm_exit',
124 124 """Set to confirm when you try to exit IPython with an EOF (Control-D
125 125 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
126 126 you can force a direct exit without any confirmation.""",
127 127 "Don't prompt the user when exiting."
128 128 )
129 129 addflag('term-title', 'TerminalInteractiveShell.term_title',
130 130 "Enable auto setting the terminal title.",
131 131 "Disable auto setting the terminal title."
132 132 )
133 133 classic_config = Config()
134 134 classic_config.InteractiveShell.cache_size = 0
135 135 classic_config.PlainTextFormatter.pprint = False
136 136 classic_config.InteractiveShell.prompt_in1 = '>>> '
137 137 classic_config.InteractiveShell.prompt_in2 = '... '
138 138 classic_config.InteractiveShell.prompt_out = ''
139 139 classic_config.InteractiveShell.separate_in = ''
140 140 classic_config.InteractiveShell.separate_out = ''
141 141 classic_config.InteractiveShell.separate_out2 = ''
142 142 classic_config.InteractiveShell.colors = 'NoColor'
143 143 classic_config.InteractiveShell.xmode = 'Plain'
144 144
145 145 flags['classic']=(
146 146 classic_config,
147 147 "Gives IPython a similar feel to the classic Python prompt."
148 148 )
149 149 # # log doesn't make so much sense this way anymore
150 150 # paa('--log','-l',
151 151 # action='store_true', dest='InteractiveShell.logstart',
152 152 # help="Start logging to the default log file (./ipython_log.py).")
153 153 #
154 154 # # quick is harder to implement
155 155 flags['quick']=(
156 156 {'TerminalIPythonApp' : {'quick' : True}},
157 157 "Enable quick startup with no config files."
158 158 )
159 159
160 160 flags['i'] = (
161 161 {'TerminalIPythonApp' : {'force_interact' : True}},
162 162 """If running code from the command line, become interactive afterwards.
163 163 Note: can also be given simply as '-i.'"""
164 164 )
165 165 flags['pylab'] = (
166 166 {'TerminalIPythonApp' : {'pylab' : 'auto'}},
167 167 """Pre-load matplotlib and numpy for interactive use with
168 168 the default matplotlib backend."""
169 169 )
170 170
171 171 aliases = dict(base_aliases)
172 172 aliases.update(shell_aliases)
173 173
174 174 # it's possible we don't want short aliases for *all* of these:
175 175 aliases.update(dict(
176 176 gui='TerminalIPythonApp.gui',
177 177 pylab='TerminalIPythonApp.pylab',
178 178 ))
179 179
180 180 #-----------------------------------------------------------------------------
181 181 # Main classes and functions
182 182 #-----------------------------------------------------------------------------
183 183
184 184 class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):
185 185 name = u'ipython'
186 186 description = usage.cl_usage
187 187 default_config_file_name = default_config_file_name
188 188 crash_handler_class = IPAppCrashHandler
189 189 examples = _examples
190 190
191 191 flags = Dict(flags)
192 192 aliases = Dict(aliases)
193 193 classes = List()
194 194 def _classes_default(self):
195 195 """This has to be in a method, for TerminalIPythonApp to be available."""
196 196 return [
197 197 InteractiveShellApp, # ShellApp comes before TerminalApp, because
198 198 self.__class__, # it will also affect subclasses (e.g. QtConsole)
199 199 TerminalInteractiveShell,
200 200 ProfileDir,
201 201 PlainTextFormatter,
202 202 IPCompleter,
203 203 ]
204 204
205 205 subcommands = Dict(dict(
206 206 qtconsole=('IPython.frontend.qt.console.qtconsoleapp.IPythonQtConsoleApp',
207 207 """Launch the IPython Qt Console."""
208 208 ),
209 209 notebook=('IPython.frontend.html.notebook.notebookapp.NotebookApp',
210 210 """Launch the IPython HTML Notebook Server"""
211 211 ),
212 212 profile = ("IPython.core.profileapp.ProfileApp",
213 213 "Create and manage IPython profiles."
214 214 ),
215 215 kernel = ("IPython.zmq.ipkernel.IPKernelApp",
216 216 "Start a kernel without an attached frontend."
217 217 ),
218 218 ))
219 219
220 220 # *do* autocreate requested profile, but don't create the config file.
221 221 auto_create=Bool(True)
222 222 # configurables
223 223 ignore_old_config=Bool(False, config=True,
224 224 help="Suppress warning messages about legacy config files"
225 225 )
226 226 quick = Bool(False, config=True,
227 227 help="""Start IPython quickly by skipping the loading of config files."""
228 228 )
229 229 def _quick_changed(self, name, old, new):
230 230 if new:
231 231 self.load_config_file = lambda *a, **kw: None
232 232 self.ignore_old_config=True
233 233
234 234 gui = CaselessStrEnum(('qt', 'wx', 'gtk', 'glut', 'pyglet'), config=True,
235 235 help="Enable GUI event loop integration ('qt', 'wx', 'gtk', 'glut', 'pyglet')."
236 236 )
237 237 pylab = CaselessStrEnum(['tk', 'qt', 'wx', 'gtk', 'osx', 'auto'],
238 238 config=True,
239 239 help="""Pre-load matplotlib and numpy for interactive use,
240 240 selecting a particular matplotlib backend and loop integration.
241 241 """
242 242 )
243 243 display_banner = Bool(True, config=True,
244 244 help="Whether to display a banner upon starting IPython."
245 245 )
246 246
247 247 # if there is code of files to run from the cmd line, don't interact
248 248 # unless the --i flag (App.force_interact) is true.
249 249 force_interact = Bool(False, config=True,
250 250 help="""If a command or file is given via the command-line,
251 251 e.g. 'ipython foo.py"""
252 252 )
253 253 def _force_interact_changed(self, name, old, new):
254 254 if new:
255 255 self.interact = True
256 256
257 257 def _file_to_run_changed(self, name, old, new):
258 258 if new and not self.force_interact:
259 259 self.interact = False
260 260 _code_to_run_changed = _file_to_run_changed
261 261
262 262 # internal, not-configurable
263 263 interact=Bool(True)
264 264
265 265
266 266 def parse_command_line(self, argv=None):
267 267 """override to allow old '-pylab' flag with deprecation warning"""
268 268
269 269 argv = sys.argv[1:] if argv is None else argv
270 270
271 271 if '-pylab' in argv:
272 272 # deprecated `-pylab` given,
273 273 # warn and transform into current syntax
274 274 argv = argv[:] # copy, don't clobber
275 275 idx = argv.index('-pylab')
276 276 warn.warn("`-pylab` flag has been deprecated.\n"
277 277 " Use `--pylab` instead, or `--pylab=foo` to specify a backend.")
278 278 sub = '--pylab'
279 279 if len(argv) > idx+1:
280 280 # check for gui arg, as in '-pylab qt'
281 281 gui = argv[idx+1]
282 282 if gui in ('wx', 'qt', 'qt4', 'gtk', 'auto'):
283 283 sub = '--pylab='+gui
284 284 argv.pop(idx+1)
285 285 argv[idx] = sub
286 286
287 287 return super(TerminalIPythonApp, self).parse_command_line(argv)
288 288
289 289 @catch_config_error
290 290 def initialize(self, argv=None):
291 291 """Do actions after construct, but before starting the app."""
292 292 super(TerminalIPythonApp, self).initialize(argv)
293 293 if self.subapp is not None:
294 294 # don't bother initializing further, starting subapp
295 295 return
296 296 if not self.ignore_old_config:
297 297 check_for_old_config(self.ipython_dir)
298 298 # print self.extra_args
299 299 if self.extra_args:
300 300 self.file_to_run = self.extra_args[0]
301 301 # create the shell
302 302 self.init_shell()
303 303 # and draw the banner
304 304 self.init_banner()
305 305 # Now a variety of things that happen after the banner is printed.
306 306 self.init_gui_pylab()
307 307 self.init_extensions()
308 308 self.init_code()
309 309
310 310 def init_shell(self):
311 311 """initialize the InteractiveShell instance"""
312 312 # I am a little hesitant to put these into InteractiveShell itself.
313 313 # But that might be the place for them
314 314 sys.path.insert(0, '')
315 315
316 316 # Create an InteractiveShell instance.
317 317 # shell.display_banner should always be False for the terminal
318 318 # based app, because we call shell.show_banner() by hand below
319 319 # so the banner shows *before* all extension loading stuff.
320 320 self.shell = TerminalInteractiveShell.instance(config=self.config,
321 321 display_banner=False, profile_dir=self.profile_dir,
322 322 ipython_dir=self.ipython_dir)
323 323 self.shell.configurables.append(self)
324 324
325 325 def init_banner(self):
326 326 """optionally display the banner"""
327 327 if self.display_banner and self.interact:
328 328 self.shell.show_banner()
329 329 # Make sure there is a space below the banner.
330 330 if self.log_level <= logging.INFO: print
331 331
332 332
333 333 def init_gui_pylab(self):
334 334 """Enable GUI event loop integration, taking pylab into account."""
335 335 gui = self.gui
336 336
337 337 # Using `pylab` will also require gui activation, though which toolkit
338 338 # to use may be chosen automatically based on mpl configuration.
339 339 if self.pylab:
340 340 activate = self.shell.enable_pylab
341 341 if self.pylab == 'auto':
342 342 gui = None
343 343 else:
344 344 gui = self.pylab
345 345 else:
346 346 # Enable only GUI integration, no pylab
347 347 activate = inputhook.enable_gui
348 348
349 349 if gui or self.pylab:
350 350 try:
351 351 self.log.info("Enabling GUI event loop integration, "
352 352 "toolkit=%s, pylab=%s" % (gui, self.pylab) )
353 353 if self.pylab:
354 354 activate(gui, import_all=self.pylab_import_all)
355 355 else:
356 356 activate(gui)
357 357 except:
358 358 self.log.warn("Error in enabling GUI event loop integration:")
359 359 self.shell.showtraceback()
360 360
361 361 def start(self):
362 362 if self.subapp is not None:
363 363 return self.subapp.start()
364 364 # perform any prexec steps:
365 365 if self.interact:
366 366 self.log.debug("Starting IPython's mainloop...")
367 367 self.shell.mainloop()
368 368 else:
369 369 self.log.debug("IPython not interactive...")
370 370
371 371
372 372 def load_default_config(ipython_dir=None):
373 373 """Load the default config file from the default ipython_dir.
374 374
375 375 This is useful for embedded shells.
376 376 """
377 377 if ipython_dir is None:
378 378 ipython_dir = get_ipython_dir()
379 379 profile_dir = os.path.join(ipython_dir, 'profile_default')
380 380 cl = PyFileConfigLoader(default_config_file_name, profile_dir)
381 381 try:
382 382 config = cl.load_config()
383 383 except ConfigFileNotFound:
384 384 # no config found
385 385 config = Config()
386 386 return config
387 387
388 388
389 389 def launch_new_instance():
390 390 """Create and run a full blown IPython instance"""
391 391 app = TerminalIPythonApp.instance()
392 392 app.initialize()
393 393 app.start()
394 394
395 395
396 396 if __name__ == '__main__':
397 397 launch_new_instance()
@@ -1,32 +1,32 b''
1 1 # encoding: utf-8
2 2 """
3 3 Extra capabilities for IPython
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2009 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 from IPython.lib.inputhook import (
18 18 enable_wx, disable_wx,
19 19 enable_gtk, disable_gtk,
20 20 enable_qt4, disable_qt4,
21 21 enable_tk, disable_tk,
22 22 enable_glut, disable_glut,
23 23 enable_pyglet, disable_pyglet,
24 24 set_inputhook, clear_inputhook,
25 25 current_gui
26 26 )
27 27
28 28 from IPython.lib.security import passwd
29 29
30 30 #-----------------------------------------------------------------------------
31 31 # Code
32 32 #-----------------------------------------------------------------------------
@@ -1,146 +1,146 b''
1 1 # coding: utf-8
2 2 """
3 3 Support for creating GUI apps and starting event loops.
4 4
5 5 IPython's GUI integration allows interative plotting and GUI usage in IPython
6 6 session. IPython has two different types of GUI integration:
7 7
8 8 1. The terminal based IPython supports GUI event loops through Python's
9 9 PyOS_InputHook. PyOS_InputHook is a hook that Python calls periodically
10 10 whenever raw_input is waiting for a user to type code. We implement GUI
11 11 support in the terminal by setting PyOS_InputHook to a function that
12 12 iterates the event loop for a short while. It is important to note that
13 13 in this situation, the real GUI event loop is NOT run in the normal
14 14 manner, so you can't use the normal means to detect that it is running.
15 15 2. In the two process IPython kernel/frontend, the GUI event loop is run in
16 16 the kernel. In this case, the event loop is run in the normal manner by
17 17 calling the function or method of the GUI toolkit that starts the event
18 18 loop.
19 19
20 20 In addition to starting the GUI event loops in one of these two ways, IPython
21 21 will *always* create an appropriate GUI application object when GUi
22 22 integration is enabled.
23 23
24 24 If you want your GUI apps to run in IPython you need to do two things:
25 25
26 26 1. Test to see if there is already an existing main application object. If
27 27 there is, you should use it. If there is not an existing application object
28 28 you should create one.
29 29 2. Test to see if the GUI event loop is running. If it is, you should not
30 30 start it. If the event loop is not running you may start it.
31 31
32 32 This module contains functions for each toolkit that perform these things
33 33 in a consistent manner. Because of how PyOS_InputHook runs the event loop
34 34 you cannot detect if the event loop is running using the traditional calls
35 35 (such as ``wx.GetApp.IsMainLoopRunning()`` in wxPython). If PyOS_InputHook is
36 36 set These methods will return a false negative. That is, they will say the
37 37 event loop is not running, when is actually is. To work around this limitation
38 38 we proposed the following informal protocol:
39 39
40 40 * Whenever someone starts the event loop, they *must* set the ``_in_event_loop``
41 41 attribute of the main application object to ``True``. This should be done
42 42 regardless of how the event loop is actually run.
43 43 * Whenever someone stops the event loop, they *must* set the ``_in_event_loop``
44 44 attribute of the main application object to ``False``.
45 45 * If you want to see if the event loop is running, you *must* use ``hasattr``
46 46 to see if ``_in_event_loop`` attribute has been set. If it is set, you
47 47 *must* use its value. If it has not been set, you can query the toolkit
48 48 in the normal manner.
49 49 * If you want GUI support and no one else has created an application or
50 50 started the event loop you *must* do this. We don't want projects to
51 51 attempt to defer these things to someone else if they themselves need it.
52 52
53 53 The functions below implement this logic for each GUI toolkit. If you need
54 54 to create custom application subclasses, you will likely have to modify this
55 55 code for your own purposes. This code can be copied into your own project
56 56 so you don't have to depend on IPython.
57 57
58 58 """
59 59
60 60 #-----------------------------------------------------------------------------
61 # Copyright (C) 2008-2010 The IPython Development Team
61 # Copyright (C) 2008-2011 The IPython Development Team
62 62 #
63 63 # Distributed under the terms of the BSD License. The full license is in
64 64 # the file COPYING, distributed as part of this software.
65 65 #-----------------------------------------------------------------------------
66 66
67 67 #-----------------------------------------------------------------------------
68 68 # Imports
69 69 #-----------------------------------------------------------------------------
70 70
71 71 #-----------------------------------------------------------------------------
72 72 # wx
73 73 #-----------------------------------------------------------------------------
74 74
75 75 def get_app_wx(*args, **kwargs):
76 76 """Create a new wx app or return an exiting one."""
77 77 import wx
78 78 app = wx.GetApp()
79 79 if app is None:
80 80 if not kwargs.has_key('redirect'):
81 81 kwargs['redirect'] = False
82 82 app = wx.PySimpleApp(*args, **kwargs)
83 83 return app
84 84
85 85 def is_event_loop_running_wx(app=None):
86 86 """Is the wx event loop running."""
87 87 if app is None:
88 88 app = get_app_wx()
89 89 if hasattr(app, '_in_event_loop'):
90 90 return app._in_event_loop
91 91 else:
92 92 return app.IsMainLoopRunning()
93 93
94 94 def start_event_loop_wx(app=None):
95 95 """Start the wx event loop in a consistent manner."""
96 96 if app is None:
97 97 app = get_app_wx()
98 98 if not is_event_loop_running_wx(app):
99 99 app._in_event_loop = True
100 100 app.MainLoop()
101 101 app._in_event_loop = False
102 102 else:
103 103 app._in_event_loop = True
104 104
105 105 #-----------------------------------------------------------------------------
106 106 # qt4
107 107 #-----------------------------------------------------------------------------
108 108
109 109 def get_app_qt4(*args, **kwargs):
110 110 """Create a new qt4 app or return an existing one."""
111 111 from IPython.external.qt_for_kernel import QtGui
112 112 app = QtGui.QApplication.instance()
113 113 if app is None:
114 114 if not args:
115 115 args = ([''],)
116 116 app = QtGui.QApplication(*args, **kwargs)
117 117 return app
118 118
119 119 def is_event_loop_running_qt4(app=None):
120 120 """Is the qt4 event loop running."""
121 121 if app is None:
122 122 app = get_app_qt4([''])
123 123 if hasattr(app, '_in_event_loop'):
124 124 return app._in_event_loop
125 125 else:
126 126 # Does qt4 provide a other way to detect this?
127 127 return False
128 128
129 129 def start_event_loop_qt4(app=None):
130 130 """Start the qt4 event loop in a consistent manner."""
131 131 if app is None:
132 132 app = get_app_qt4([''])
133 133 if not is_event_loop_running_qt4(app):
134 134 app._in_event_loop = True
135 135 app.exec_()
136 136 app._in_event_loop = False
137 137 else:
138 138 app._in_event_loop = True
139 139
140 140 #-----------------------------------------------------------------------------
141 141 # Tk
142 142 #-----------------------------------------------------------------------------
143 143
144 144 #-----------------------------------------------------------------------------
145 145 # gtk
146 146 #-----------------------------------------------------------------------------
@@ -1,483 +1,483 b''
1 1 # coding: utf-8
2 2 """
3 3 Inputhook management for GUI event loop integration.
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2009 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 import ctypes
18 18 import os
19 19 import sys
20 20 import warnings
21 21
22 22 #-----------------------------------------------------------------------------
23 23 # Constants
24 24 #-----------------------------------------------------------------------------
25 25
26 26 # Constants for identifying the GUI toolkits.
27 27 GUI_WX = 'wx'
28 28 GUI_QT = 'qt'
29 29 GUI_QT4 = 'qt4'
30 30 GUI_GTK = 'gtk'
31 31 GUI_TK = 'tk'
32 32 GUI_OSX = 'osx'
33 33 GUI_GLUT = 'glut'
34 34 GUI_PYGLET = 'pyglet'
35 35 GUI_NONE = 'none' # i.e. disable
36 36
37 37 #-----------------------------------------------------------------------------
38 38 # Utilities
39 39 #-----------------------------------------------------------------------------
40 40
41 41 def _stdin_ready_posix():
42 42 """Return True if there's something to read on stdin (posix version)."""
43 43 infds, outfds, erfds = select.select([sys.stdin],[],[],0)
44 44 return bool(infds)
45 45
46 46 def _stdin_ready_nt():
47 47 """Return True if there's something to read on stdin (nt version)."""
48 48 return msvcrt.kbhit()
49 49
50 50 def _stdin_ready_other():
51 51 """Return True, assuming there's something to read on stdin."""
52 52 return True #
53 53
54 54
55 55 def _ignore_CTRL_C_posix():
56 56 """Ignore CTRL+C (SIGINT)."""
57 57 signal.signal(signal.SIGINT, signal.SIG_IGN)
58 58
59 59 def _allow_CTRL_C_posix():
60 60 """Take CTRL+C into account (SIGINT)."""
61 61 signal.signal(signal.SIGINT, signal.default_int_handler)
62 62
63 63 def _ignore_CTRL_C_other():
64 64 """Ignore CTRL+C (not implemented)."""
65 65 pass
66 66
67 67 def _allow_CTRL_C_other():
68 68 """Take CTRL+C into account (not implemented)."""
69 69 pass
70 70
71 71 if os.name == 'posix':
72 72 import select
73 73 import signal
74 74 stdin_ready = _stdin_ready_posix
75 75 ignore_CTRL_C = _ignore_CTRL_C_posix
76 76 allow_CTRL_C = _allow_CTRL_C_posix
77 77 elif os.name == 'nt':
78 78 import msvcrt
79 79 stdin_ready = _stdin_ready_nt
80 80 ignore_CTRL_C = _ignore_CTRL_C_other
81 81 allow_CTRL_C = _allow_CTRL_C_other
82 82 else:
83 83 stdin_ready = _stdin_ready_other
84 84 ignore_CTRL_C = _ignore_CTRL_C_other
85 85 allow_CTRL_C = _allow_CTRL_C_other
86 86
87 87
88 88 #-----------------------------------------------------------------------------
89 89 # Main InputHookManager class
90 90 #-----------------------------------------------------------------------------
91 91
92 92
93 93 class InputHookManager(object):
94 94 """Manage PyOS_InputHook for different GUI toolkits.
95 95
96 96 This class installs various hooks under ``PyOSInputHook`` to handle
97 97 GUI event loop integration.
98 98 """
99 99
100 100 def __init__(self):
101 101 self.PYFUNC = ctypes.PYFUNCTYPE(ctypes.c_int)
102 102 self._apps = {}
103 103 self._reset()
104 104
105 105 def _reset(self):
106 106 self._callback_pyfunctype = None
107 107 self._callback = None
108 108 self._installed = False
109 109 self._current_gui = None
110 110
111 111 def get_pyos_inputhook(self):
112 112 """Return the current PyOS_InputHook as a ctypes.c_void_p."""
113 113 return ctypes.c_void_p.in_dll(ctypes.pythonapi,"PyOS_InputHook")
114 114
115 115 def get_pyos_inputhook_as_func(self):
116 116 """Return the current PyOS_InputHook as a ctypes.PYFUNCYPE."""
117 117 return self.PYFUNC.in_dll(ctypes.pythonapi,"PyOS_InputHook")
118 118
119 119 def set_inputhook(self, callback):
120 120 """Set PyOS_InputHook to callback and return the previous one."""
121 121 # On platforms with 'readline' support, it's all too likely to
122 122 # have a KeyboardInterrupt signal delivered *even before* an
123 123 # initial ``try:`` clause in the callback can be executed, so
124 124 # we need to disable CTRL+C in this situation.
125 125 ignore_CTRL_C()
126 126 self._callback = callback
127 127 self._callback_pyfunctype = self.PYFUNC(callback)
128 128 pyos_inputhook_ptr = self.get_pyos_inputhook()
129 129 original = self.get_pyos_inputhook_as_func()
130 130 pyos_inputhook_ptr.value = \
131 131 ctypes.cast(self._callback_pyfunctype, ctypes.c_void_p).value
132 132 self._installed = True
133 133 return original
134 134
135 135 def clear_inputhook(self, app=None):
136 136 """Set PyOS_InputHook to NULL and return the previous one.
137 137
138 138 Parameters
139 139 ----------
140 140 app : optional, ignored
141 141 This parameter is allowed only so that clear_inputhook() can be
142 142 called with a similar interface as all the ``enable_*`` methods. But
143 143 the actual value of the parameter is ignored. This uniform interface
144 144 makes it easier to have user-level entry points in the main IPython
145 145 app like :meth:`enable_gui`."""
146 146 pyos_inputhook_ptr = self.get_pyos_inputhook()
147 147 original = self.get_pyos_inputhook_as_func()
148 148 pyos_inputhook_ptr.value = ctypes.c_void_p(None).value
149 149 allow_CTRL_C()
150 150 self._reset()
151 151 return original
152 152
153 153 def clear_app_refs(self, gui=None):
154 154 """Clear IPython's internal reference to an application instance.
155 155
156 156 Whenever we create an app for a user on qt4 or wx, we hold a
157 157 reference to the app. This is needed because in some cases bad things
158 158 can happen if a user doesn't hold a reference themselves. This
159 159 method is provided to clear the references we are holding.
160 160
161 161 Parameters
162 162 ----------
163 163 gui : None or str
164 164 If None, clear all app references. If ('wx', 'qt4') clear
165 165 the app for that toolkit. References are not held for gtk or tk
166 166 as those toolkits don't have the notion of an app.
167 167 """
168 168 if gui is None:
169 169 self._apps = {}
170 170 elif self._apps.has_key(gui):
171 171 del self._apps[gui]
172 172
173 173 def enable_wx(self, app=None):
174 174 """Enable event loop integration with wxPython.
175 175
176 176 Parameters
177 177 ----------
178 178 app : WX Application, optional.
179 179 Running application to use. If not given, we probe WX for an
180 180 existing application object, and create a new one if none is found.
181 181
182 182 Notes
183 183 -----
184 184 This methods sets the ``PyOS_InputHook`` for wxPython, which allows
185 185 the wxPython to integrate with terminal based applications like
186 186 IPython.
187 187
188 188 If ``app`` is not given we probe for an existing one, and return it if
189 189 found. If no existing app is found, we create an :class:`wx.App` as
190 190 follows::
191 191
192 192 import wx
193 193 app = wx.App(redirect=False, clearSigInt=False)
194 194 """
195 195 from IPython.lib.inputhookwx import inputhook_wx
196 196 self.set_inputhook(inputhook_wx)
197 197 self._current_gui = GUI_WX
198 198 import wx
199 199 if app is None:
200 200 app = wx.GetApp()
201 201 if app is None:
202 202 app = wx.App(redirect=False, clearSigInt=False)
203 203 app._in_event_loop = True
204 204 self._apps[GUI_WX] = app
205 205 return app
206 206
207 207 def disable_wx(self):
208 208 """Disable event loop integration with wxPython.
209 209
210 210 This merely sets PyOS_InputHook to NULL.
211 211 """
212 212 if self._apps.has_key(GUI_WX):
213 213 self._apps[GUI_WX]._in_event_loop = False
214 214 self.clear_inputhook()
215 215
216 216 def enable_qt4(self, app=None):
217 217 """Enable event loop integration with PyQt4.
218 218
219 219 Parameters
220 220 ----------
221 221 app : Qt Application, optional.
222 222 Running application to use. If not given, we probe Qt for an
223 223 existing application object, and create a new one if none is found.
224 224
225 225 Notes
226 226 -----
227 227 This methods sets the PyOS_InputHook for PyQt4, which allows
228 228 the PyQt4 to integrate with terminal based applications like
229 229 IPython.
230 230
231 231 If ``app`` is not given we probe for an existing one, and return it if
232 232 found. If no existing app is found, we create an :class:`QApplication`
233 233 as follows::
234 234
235 235 from PyQt4 import QtCore
236 236 app = QtGui.QApplication(sys.argv)
237 237 """
238 238 from IPython.lib.inputhookqt4 import create_inputhook_qt4
239 239 app, inputhook_qt4 = create_inputhook_qt4(self, app)
240 240 self.set_inputhook(inputhook_qt4)
241 241
242 242 self._current_gui = GUI_QT4
243 243 app._in_event_loop = True
244 244 self._apps[GUI_QT4] = app
245 245 return app
246 246
247 247 def disable_qt4(self):
248 248 """Disable event loop integration with PyQt4.
249 249
250 250 This merely sets PyOS_InputHook to NULL.
251 251 """
252 252 if self._apps.has_key(GUI_QT4):
253 253 self._apps[GUI_QT4]._in_event_loop = False
254 254 self.clear_inputhook()
255 255
256 256 def enable_gtk(self, app=None):
257 257 """Enable event loop integration with PyGTK.
258 258
259 259 Parameters
260 260 ----------
261 261 app : ignored
262 262 Ignored, it's only a placeholder to keep the call signature of all
263 263 gui activation methods consistent, which simplifies the logic of
264 264 supporting magics.
265 265
266 266 Notes
267 267 -----
268 268 This methods sets the PyOS_InputHook for PyGTK, which allows
269 269 the PyGTK to integrate with terminal based applications like
270 270 IPython.
271 271 """
272 272 import gtk
273 273 try:
274 274 gtk.set_interactive(True)
275 275 self._current_gui = GUI_GTK
276 276 except AttributeError:
277 277 # For older versions of gtk, use our own ctypes version
278 278 from IPython.lib.inputhookgtk import inputhook_gtk
279 279 self.set_inputhook(inputhook_gtk)
280 280 self._current_gui = GUI_GTK
281 281
282 282 def disable_gtk(self):
283 283 """Disable event loop integration with PyGTK.
284 284
285 285 This merely sets PyOS_InputHook to NULL.
286 286 """
287 287 self.clear_inputhook()
288 288
289 289 def enable_tk(self, app=None):
290 290 """Enable event loop integration with Tk.
291 291
292 292 Parameters
293 293 ----------
294 294 app : toplevel :class:`Tkinter.Tk` widget, optional.
295 295 Running toplevel widget to use. If not given, we probe Tk for an
296 296 existing one, and create a new one if none is found.
297 297
298 298 Notes
299 299 -----
300 300 If you have already created a :class:`Tkinter.Tk` object, the only
301 301 thing done by this method is to register with the
302 302 :class:`InputHookManager`, since creating that object automatically
303 303 sets ``PyOS_InputHook``.
304 304 """
305 305 self._current_gui = GUI_TK
306 306 if app is None:
307 307 import Tkinter
308 308 app = Tkinter.Tk()
309 309 app.withdraw()
310 310 self._apps[GUI_TK] = app
311 311 return app
312 312
313 313 def disable_tk(self):
314 314 """Disable event loop integration with Tkinter.
315 315
316 316 This merely sets PyOS_InputHook to NULL.
317 317 """
318 318 self.clear_inputhook()
319 319
320 320
321 321 def enable_glut(self, app=None):
322 322 """ Enable event loop integration with GLUT.
323 323
324 324 Parameters
325 325 ----------
326 326
327 327 app : ignored
328 328 Ignored, it's only a placeholder to keep the call signature of all
329 329 gui activation methods consistent, which simplifies the logic of
330 330 supporting magics.
331 331
332 332 Notes
333 333 -----
334 334
335 335 This methods sets the PyOS_InputHook for GLUT, which allows the GLUT to
336 336 integrate with terminal based applications like IPython. Due to GLUT
337 337 limitations, it is currently not possible to start the event loop
338 338 without first creating a window. You should thus not create another
339 339 window but use instead the created one. See 'gui-glut.py' in the
340 340 docs/examples/lib directory.
341 341
342 342 The default screen mode is set to:
343 343 glut.GLUT_DOUBLE | glut.GLUT_RGBA | glut.GLUT_DEPTH
344 344 """
345 345
346 346 import OpenGL.GLUT as glut
347 347 from IPython.lib.inputhookglut import glut_display_mode, \
348 348 glut_close, glut_display, \
349 349 glut_idle, inputhook_glut
350 350
351 351 if not self._apps.has_key( GUI_GLUT ):
352 352 glut.glutInit( sys.argv )
353 353 glut.glutInitDisplayMode( glut_display_mode )
354 354 # This is specific to freeglut
355 355 if bool(glut.glutSetOption):
356 356 glut.glutSetOption( glut.GLUT_ACTION_ON_WINDOW_CLOSE,
357 357 glut.GLUT_ACTION_GLUTMAINLOOP_RETURNS )
358 358 glut.glutCreateWindow( sys.argv[0] )
359 359 glut.glutReshapeWindow( 1, 1 )
360 360 glut.glutHideWindow( )
361 361 glut.glutWMCloseFunc( glut_close )
362 362 glut.glutDisplayFunc( glut_display )
363 363 glut.glutIdleFunc( glut_idle )
364 364 else:
365 365 glut.glutWMCloseFunc( glut_close )
366 366 glut.glutDisplayFunc( glut_display )
367 367 glut.glutIdleFunc( glut_idle)
368 368 self.set_inputhook( inputhook_glut )
369 369 self._current_gui = GUI_GLUT
370 370 self._apps[GUI_GLUT] = True
371 371
372 372
373 373 def disable_glut(self):
374 374 """Disable event loop integration with glut.
375 375
376 376 This sets PyOS_InputHook to NULL and set the display function to a
377 377 dummy one and set the timer to a dummy timer that will be triggered
378 378 very far in the future.
379 379 """
380 380 import OpenGL.GLUT as glut
381 381 from glut_support import glutMainLoopEvent
382 382
383 383 glut.glutHideWindow() # This is an event to be processed below
384 384 glutMainLoopEvent()
385 385 self.clear_inputhook()
386 386
387 387 def enable_pyglet(self, app=None):
388 388 """Enable event loop integration with pyglet.
389 389
390 390 Parameters
391 391 ----------
392 392 app : ignored
393 393 Ignored, it's only a placeholder to keep the call signature of all
394 394 gui activation methods consistent, which simplifies the logic of
395 395 supporting magics.
396 396
397 397 Notes
398 398 -----
399 399 This methods sets the ``PyOS_InputHook`` for pyglet, which allows
400 400 pyglet to integrate with terminal based applications like
401 401 IPython.
402 402
403 403 """
404 404 import pyglet
405 405 from IPython.lib.inputhookpyglet import inputhook_pyglet
406 406 self.set_inputhook(inputhook_pyglet)
407 407 self._current_gui = GUI_PYGLET
408 408 return app
409 409
410 410 def disable_pyglet(self):
411 411 """Disable event loop integration with pyglet.
412 412
413 413 This merely sets PyOS_InputHook to NULL.
414 414 """
415 415 self.clear_inputhook()
416 416
417 417 def current_gui(self):
418 418 """Return a string indicating the currently active GUI or None."""
419 419 return self._current_gui
420 420
421 421 inputhook_manager = InputHookManager()
422 422
423 423 enable_wx = inputhook_manager.enable_wx
424 424 disable_wx = inputhook_manager.disable_wx
425 425 enable_qt4 = inputhook_manager.enable_qt4
426 426 disable_qt4 = inputhook_manager.disable_qt4
427 427 enable_gtk = inputhook_manager.enable_gtk
428 428 disable_gtk = inputhook_manager.disable_gtk
429 429 enable_tk = inputhook_manager.enable_tk
430 430 disable_tk = inputhook_manager.disable_tk
431 431 enable_glut = inputhook_manager.enable_glut
432 432 disable_glut = inputhook_manager.disable_glut
433 433 enable_pyglet = inputhook_manager.enable_pyglet
434 434 disable_pyglet = inputhook_manager.disable_pyglet
435 435 clear_inputhook = inputhook_manager.clear_inputhook
436 436 set_inputhook = inputhook_manager.set_inputhook
437 437 current_gui = inputhook_manager.current_gui
438 438 clear_app_refs = inputhook_manager.clear_app_refs
439 439
440 440
441 441 # Convenience function to switch amongst them
442 442 def enable_gui(gui=None, app=None):
443 443 """Switch amongst GUI input hooks by name.
444 444
445 445 This is just a utility wrapper around the methods of the InputHookManager
446 446 object.
447 447
448 448 Parameters
449 449 ----------
450 450 gui : optional, string or None
451 451 If None (or 'none'), clears input hook, otherwise it must be one
452 452 of the recognized GUI names (see ``GUI_*`` constants in module).
453 453
454 454 app : optional, existing application object.
455 455 For toolkits that have the concept of a global app, you can supply an
456 456 existing one. If not given, the toolkit will be probed for one, and if
457 457 none is found, a new one will be created. Note that GTK does not have
458 458 this concept, and passing an app if `gui`=="GTK" will raise an error.
459 459
460 460 Returns
461 461 -------
462 462 The output of the underlying gui switch routine, typically the actual
463 463 PyOS_InputHook wrapper object or the GUI toolkit app created, if there was
464 464 one.
465 465 """
466 466 guis = {None: clear_inputhook,
467 467 GUI_NONE: clear_inputhook,
468 468 GUI_OSX: lambda app=False: None,
469 469 GUI_TK: enable_tk,
470 470 GUI_GTK: enable_gtk,
471 471 GUI_WX: enable_wx,
472 472 GUI_QT: enable_qt4, # qt3 not supported
473 473 GUI_QT4: enable_qt4,
474 474 GUI_GLUT: enable_glut,
475 475 GUI_PYGLET: enable_pyglet,
476 476 }
477 477 try:
478 478 gui_hook = guis[gui]
479 479 except KeyError:
480 480 e = "Invalid GUI request %r, valid ones are:%s" % (gui, guis.keys())
481 481 raise ValueError(e)
482 482 return gui_hook(app)
483 483
@@ -1,176 +1,176 b''
1 1 # coding: utf-8
2 2 """
3 3 GLUT Inputhook support functions
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2009 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 # GLUT is quite an old library and it is difficult to ensure proper
14 14 # integration within IPython since original GLUT does not allow to handle
15 15 # events one by one. Instead, it requires for the mainloop to be entered
16 16 # and never returned (there is not even a function to exit he
17 17 # mainloop). Fortunately, there are alternatives such as freeglut
18 18 # (available for linux and windows) and the OSX implementation gives
19 19 # access to a glutCheckLoop() function that blocks itself until a new
20 20 # event is received. This means we have to setup the idle callback to
21 21 # ensure we got at least one event that will unblock the function.
22 22 #
23 23 # Furthermore, it is not possible to install these handlers without a window
24 24 # being first created. We choose to make this window invisible. This means that
25 25 # display mode options are set at this level and user won't be able to change
26 26 # them later without modifying the code. This should probably be made available
27 27 # via IPython options system.
28 28
29 29 #-----------------------------------------------------------------------------
30 30 # Imports
31 31 #-----------------------------------------------------------------------------
32 32 import os
33 33 import sys
34 34 import time
35 35 import signal
36 36 import OpenGL
37 37 import OpenGL.GLUT as glut
38 38 import OpenGL.platform as platform
39 39 from timeit import default_timer as clock
40 40
41 41 #-----------------------------------------------------------------------------
42 42 # Constants
43 43 #-----------------------------------------------------------------------------
44 44
45 45 # Frame per second : 60
46 46 # Should probably be an IPython option
47 47 glut_fps = 60
48 48
49 49
50 50 # Display mode : double buffeed + rgba + depth
51 51 # Should probably be an IPython option
52 52 glut_display_mode = (glut.GLUT_DOUBLE |
53 53 glut.GLUT_RGBA |
54 54 glut.GLUT_DEPTH)
55 55
56 56 glutMainLoopEvent = None
57 57 if sys.platform == 'darwin':
58 58 try:
59 59 glutCheckLoop = platform.createBaseFunction(
60 60 'glutCheckLoop', dll=platform.GLUT, resultType=None,
61 61 argTypes=[],
62 62 doc='glutCheckLoop( ) -> None',
63 63 argNames=(),
64 64 )
65 65 except AttributeError:
66 66 raise RuntimeError(
67 67 '''Your glut implementation does not allow interactive sessions'''
68 68 '''Consider installing freeglut.''')
69 69 glutMainLoopEvent = glutCheckLoop
70 70 elif glut.HAVE_FREEGLUT:
71 71 glutMainLoopEvent = glut.glutMainLoopEvent
72 72 else:
73 73 raise RuntimeError(
74 74 '''Your glut implementation does not allow interactive sessions. '''
75 75 '''Consider installing freeglut.''')
76 76
77 77
78 78 #-----------------------------------------------------------------------------
79 79 # Platform-dependent imports and functions
80 80 #-----------------------------------------------------------------------------
81 81
82 82 if os.name == 'posix':
83 83 import select
84 84
85 85 def stdin_ready():
86 86 infds, outfds, erfds = select.select([sys.stdin],[],[],0)
87 87 if infds:
88 88 return True
89 89 else:
90 90 return False
91 91
92 92 elif sys.platform == 'win32':
93 93 import msvcrt
94 94
95 95 def stdin_ready():
96 96 return msvcrt.kbhit()
97 97
98 98 #-----------------------------------------------------------------------------
99 99 # Callback functions
100 100 #-----------------------------------------------------------------------------
101 101
102 102 def glut_display():
103 103 # Dummy display function
104 104 pass
105 105
106 106 def glut_idle():
107 107 # Dummy idle function
108 108 pass
109 109
110 110 def glut_close():
111 111 # Close function only hides the current window
112 112 glut.glutHideWindow()
113 113 glutMainLoopEvent()
114 114
115 115 def glut_int_handler(signum, frame):
116 116 # Catch sigint and print the defautl message
117 117 signal.signal(signal.SIGINT, signal.default_int_handler)
118 118 print '\nKeyboardInterrupt'
119 119 # Need to reprint the prompt at this stage
120 120
121 121
122 122
123 123 #-----------------------------------------------------------------------------
124 124 # Code
125 125 #-----------------------------------------------------------------------------
126 126 def inputhook_glut():
127 127 """Run the pyglet event loop by processing pending events only.
128 128
129 129 This keeps processing pending events until stdin is ready. After
130 130 processing all pending events, a call to time.sleep is inserted. This is
131 131 needed, otherwise, CPU usage is at 100%. This sleep time should be tuned
132 132 though for best performance.
133 133 """
134 134 # We need to protect against a user pressing Control-C when IPython is
135 135 # idle and this is running. We trap KeyboardInterrupt and pass.
136 136
137 137 signal.signal(signal.SIGINT, glut_int_handler)
138 138
139 139 try:
140 140 t = clock()
141 141
142 142 # Make sure the default window is set after a window has been closed
143 143 if glut.glutGetWindow() == 0:
144 144 glut.glutSetWindow( 1 )
145 145 glutMainLoopEvent()
146 146 return 0
147 147
148 148 while not stdin_ready():
149 149 glutMainLoopEvent()
150 150 # We need to sleep at this point to keep the idle CPU load
151 151 # low. However, if sleep to long, GUI response is poor. As
152 152 # a compromise, we watch how often GUI events are being processed
153 153 # and switch between a short and long sleep time. Here are some
154 154 # stats useful in helping to tune this.
155 155 # time CPU load
156 156 # 0.001 13%
157 157 # 0.005 3%
158 158 # 0.01 1.5%
159 159 # 0.05 0.5%
160 160 used_time = clock() - t
161 161 if used_time > 5*60.0:
162 162 # print 'Sleep for 5 s' # dbg
163 163 time.sleep(5.0)
164 164 elif used_time > 10.0:
165 165 # print 'Sleep for 1 s' # dbg
166 166 time.sleep(1.0)
167 167 elif used_time > 0.1:
168 168 # Few GUI events coming in, so we can sleep longer
169 169 # print 'Sleep for 0.05 s' # dbg
170 170 time.sleep(0.05)
171 171 else:
172 172 # Many GUI events coming in, so sleep only very little
173 173 time.sleep(0.001)
174 174 except KeyboardInterrupt:
175 175 pass
176 176 return 0
@@ -1,35 +1,35 b''
1 1 # encoding: utf-8
2 2 """
3 3 Enable pygtk to be used interacive by setting PyOS_InputHook.
4 4
5 5 Authors: Brian Granger
6 6 """
7 7
8 8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2008-2009 The IPython Development Team
9 # Copyright (C) 2008-2011 The IPython Development Team
10 10 #
11 11 # Distributed under the terms of the BSD License. The full license is in
12 12 # the file COPYING, distributed as part of this software.
13 13 #-----------------------------------------------------------------------------
14 14
15 15 #-----------------------------------------------------------------------------
16 16 # Imports
17 17 #-----------------------------------------------------------------------------
18 18
19 19 import sys
20 20 import gtk, gobject
21 21
22 22 #-----------------------------------------------------------------------------
23 23 # Code
24 24 #-----------------------------------------------------------------------------
25 25
26 26
27 27 def _main_quit(*args, **kwargs):
28 28 gtk.main_quit()
29 29 return False
30 30
31 31 def inputhook_gtk():
32 32 gobject.io_add_watch(sys.stdin, gobject.IO_IN, _main_quit)
33 33 gtk.main()
34 34 return 0
35 35
@@ -1,115 +1,115 b''
1 1 # encoding: utf-8
2 2 """
3 3 Enable pyglet to be used interacive by setting PyOS_InputHook.
4 4
5 5 Authors
6 6 -------
7 7
8 8 * Nicolas P. Rougier
9 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 15 # Distributed under the terms of the BSD License. The full license is in
16 16 # the file COPYING, distributed as part of this software.
17 17 #-----------------------------------------------------------------------------
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Imports
21 21 #-----------------------------------------------------------------------------
22 22
23 23 import os
24 24 import signal
25 25 import sys
26 26 import time
27 27 from timeit import default_timer as clock
28 28 import pyglet
29 29
30 30 #-----------------------------------------------------------------------------
31 31 # Platform-dependent imports and functions
32 32 #-----------------------------------------------------------------------------
33 33
34 34 if os.name == 'posix':
35 35 import select
36 36
37 37 def stdin_ready():
38 38 infds, outfds, erfds = select.select([sys.stdin],[],[],0)
39 39 if infds:
40 40 return True
41 41 else:
42 42 return False
43 43
44 44 elif sys.platform == 'win32':
45 45 import msvcrt
46 46
47 47 def stdin_ready():
48 48 return msvcrt.kbhit()
49 49
50 50
51 51 # On linux only, window.flip() has a bug that causes an AttributeError on
52 52 # window close. For details, see:
53 53 # http://groups.google.com/group/pyglet-users/browse_thread/thread/47c1aab9aa4a3d23/c22f9e819826799e?#c22f9e819826799e
54 54
55 55 if sys.platform.startswith('linux'):
56 56 def flip(window):
57 57 try:
58 58 window.flip()
59 59 except AttributeError:
60 60 pass
61 61 else:
62 62 def flip(window):
63 63 window.flip()
64 64
65 65 #-----------------------------------------------------------------------------
66 66 # Code
67 67 #-----------------------------------------------------------------------------
68 68
69 69 def inputhook_pyglet():
70 70 """Run the pyglet event loop by processing pending events only.
71 71
72 72 This keeps processing pending events until stdin is ready. After
73 73 processing all pending events, a call to time.sleep is inserted. This is
74 74 needed, otherwise, CPU usage is at 100%. This sleep time should be tuned
75 75 though for best performance.
76 76 """
77 77 # We need to protect against a user pressing Control-C when IPython is
78 78 # idle and this is running. We trap KeyboardInterrupt and pass.
79 79 try:
80 80 t = clock()
81 81 while not stdin_ready():
82 82 pyglet.clock.tick()
83 83 for window in pyglet.app.windows:
84 84 window.switch_to()
85 85 window.dispatch_events()
86 86 window.dispatch_event('on_draw')
87 87 flip(window)
88 88
89 89 # We need to sleep at this point to keep the idle CPU load
90 90 # low. However, if sleep to long, GUI response is poor. As
91 91 # a compromise, we watch how often GUI events are being processed
92 92 # and switch between a short and long sleep time. Here are some
93 93 # stats useful in helping to tune this.
94 94 # time CPU load
95 95 # 0.001 13%
96 96 # 0.005 3%
97 97 # 0.01 1.5%
98 98 # 0.05 0.5%
99 99 used_time = clock() - t
100 100 if used_time > 5*60.0:
101 101 # print 'Sleep for 5 s' # dbg
102 102 time.sleep(5.0)
103 103 elif used_time > 10.0:
104 104 # print 'Sleep for 1 s' # dbg
105 105 time.sleep(1.0)
106 106 elif used_time > 0.1:
107 107 # Few GUI events coming in, so we can sleep longer
108 108 # print 'Sleep for 0.05 s' # dbg
109 109 time.sleep(0.05)
110 110 else:
111 111 # Many GUI events coming in, so sleep only very little
112 112 time.sleep(0.001)
113 113 except KeyboardInterrupt:
114 114 pass
115 115 return 0
@@ -1,165 +1,165 b''
1 1 # encoding: utf-8
2 2
3 3 """
4 4 Enable wxPython to be used interacive by setting PyOS_InputHook.
5 5
6 6 Authors: Robin Dunn, Brian Granger, Ondrej Certik
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 12 # Distributed under the terms of the BSD License. The full license is in
13 13 # the file COPYING, distributed as part of this software.
14 14 #-----------------------------------------------------------------------------
15 15
16 16 #-----------------------------------------------------------------------------
17 17 # Imports
18 18 #-----------------------------------------------------------------------------
19 19
20 20 import os
21 21 import signal
22 22 import sys
23 23 import time
24 24 from timeit import default_timer as clock
25 25 import wx
26 26
27 27 from IPython.lib.inputhook import stdin_ready
28 28
29 29
30 30 #-----------------------------------------------------------------------------
31 31 # Code
32 32 #-----------------------------------------------------------------------------
33 33
34 34 def inputhook_wx1():
35 35 """Run the wx event loop by processing pending events only.
36 36
37 37 This approach seems to work, but its performance is not great as it
38 38 relies on having PyOS_InputHook called regularly.
39 39 """
40 40 try:
41 41 app = wx.GetApp()
42 42 if app is not None:
43 43 assert wx.Thread_IsMain()
44 44
45 45 # Make a temporary event loop and process system events until
46 46 # there are no more waiting, then allow idle events (which
47 47 # will also deal with pending or posted wx events.)
48 48 evtloop = wx.EventLoop()
49 49 ea = wx.EventLoopActivator(evtloop)
50 50 while evtloop.Pending():
51 51 evtloop.Dispatch()
52 52 app.ProcessIdle()
53 53 del ea
54 54 except KeyboardInterrupt:
55 55 pass
56 56 return 0
57 57
58 58 class EventLoopTimer(wx.Timer):
59 59
60 60 def __init__(self, func):
61 61 self.func = func
62 62 wx.Timer.__init__(self)
63 63
64 64 def Notify(self):
65 65 self.func()
66 66
67 67 class EventLoopRunner(object):
68 68
69 69 def Run(self, time):
70 70 self.evtloop = wx.EventLoop()
71 71 self.timer = EventLoopTimer(self.check_stdin)
72 72 self.timer.Start(time)
73 73 self.evtloop.Run()
74 74
75 75 def check_stdin(self):
76 76 if stdin_ready():
77 77 self.timer.Stop()
78 78 self.evtloop.Exit()
79 79
80 80 def inputhook_wx2():
81 81 """Run the wx event loop, polling for stdin.
82 82
83 83 This version runs the wx eventloop for an undetermined amount of time,
84 84 during which it periodically checks to see if anything is ready on
85 85 stdin. If anything is ready on stdin, the event loop exits.
86 86
87 87 The argument to elr.Run controls how often the event loop looks at stdin.
88 88 This determines the responsiveness at the keyboard. A setting of 1000
89 89 enables a user to type at most 1 char per second. I have found that a
90 90 setting of 10 gives good keyboard response. We can shorten it further,
91 91 but eventually performance would suffer from calling select/kbhit too
92 92 often.
93 93 """
94 94 try:
95 95 app = wx.GetApp()
96 96 if app is not None:
97 97 assert wx.Thread_IsMain()
98 98 elr = EventLoopRunner()
99 99 # As this time is made shorter, keyboard response improves, but idle
100 100 # CPU load goes up. 10 ms seems like a good compromise.
101 101 elr.Run(time=10) # CHANGE time here to control polling interval
102 102 except KeyboardInterrupt:
103 103 pass
104 104 return 0
105 105
106 106 def inputhook_wx3():
107 107 """Run the wx event loop by processing pending events only.
108 108
109 109 This is like inputhook_wx1, but it keeps processing pending events
110 110 until stdin is ready. After processing all pending events, a call to
111 111 time.sleep is inserted. This is needed, otherwise, CPU usage is at 100%.
112 112 This sleep time should be tuned though for best performance.
113 113 """
114 114 # We need to protect against a user pressing Control-C when IPython is
115 115 # idle and this is running. We trap KeyboardInterrupt and pass.
116 116 try:
117 117 app = wx.GetApp()
118 118 if app is not None:
119 119 assert wx.Thread_IsMain()
120 120
121 121 # The import of wx on Linux sets the handler for signal.SIGINT
122 122 # to 0. This is a bug in wx or gtk. We fix by just setting it
123 123 # back to the Python default.
124 124 if not callable(signal.getsignal(signal.SIGINT)):
125 125 signal.signal(signal.SIGINT, signal.default_int_handler)
126 126
127 127 evtloop = wx.EventLoop()
128 128 ea = wx.EventLoopActivator(evtloop)
129 129 t = clock()
130 130 while not stdin_ready():
131 131 while evtloop.Pending():
132 132 t = clock()
133 133 evtloop.Dispatch()
134 134 app.ProcessIdle()
135 135 # We need to sleep at this point to keep the idle CPU load
136 136 # low. However, if sleep to long, GUI response is poor. As
137 137 # a compromise, we watch how often GUI events are being processed
138 138 # and switch between a short and long sleep time. Here are some
139 139 # stats useful in helping to tune this.
140 140 # time CPU load
141 141 # 0.001 13%
142 142 # 0.005 3%
143 143 # 0.01 1.5%
144 144 # 0.05 0.5%
145 145 used_time = clock() - t
146 146 if used_time > 5*60.0:
147 147 # print 'Sleep for 5 s' # dbg
148 148 time.sleep(5.0)
149 149 elif used_time > 10.0:
150 150 # print 'Sleep for 1 s' # dbg
151 151 time.sleep(1.0)
152 152 elif used_time > 0.1:
153 153 # Few GUI events coming in, so we can sleep longer
154 154 # print 'Sleep for 0.05 s' # dbg
155 155 time.sleep(0.05)
156 156 else:
157 157 # Many GUI events coming in, so sleep only very little
158 158 time.sleep(0.001)
159 159 del ea
160 160 except KeyboardInterrupt:
161 161 pass
162 162 return 0
163 163
164 164 # This is our default implementation
165 165 inputhook_wx = inputhook_wx3
@@ -1,110 +1,110 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Tools for handling LaTeX.
3 3
4 4 Authors:
5 5
6 6 * Brian Granger
7 7 """
8 8 #-----------------------------------------------------------------------------
9 # Copyright (c) 2010, IPython Development Team.
9 # Copyright (C) 2010-2011, IPython Development Team.
10 10 #
11 11 # Distributed under the terms of the Modified BSD License.
12 12 #
13 13 # The full license is in the file COPYING.txt, distributed with this software.
14 14 #-----------------------------------------------------------------------------
15 15
16 16 #-----------------------------------------------------------------------------
17 17 # Imports
18 18 #-----------------------------------------------------------------------------
19 19
20 20 from StringIO import StringIO
21 21 from base64 import encodestring
22 22
23 23 #-----------------------------------------------------------------------------
24 24 # Tools
25 25 #-----------------------------------------------------------------------------
26 26
27 27
28 28 def latex_to_png(s, encode=False):
29 29 """Render a LaTeX string to PNG using matplotlib.mathtext.
30 30
31 31 Parameters
32 32 ----------
33 33 s : str
34 34 The raw string containing valid inline LaTeX.
35 35 encode : bool, optional
36 36 Should the PNG data bebase64 encoded to make it JSON'able.
37 37 """
38 38 from matplotlib import mathtext
39 39
40 40 mt = mathtext.MathTextParser('bitmap')
41 41 f = StringIO()
42 42 mt.to_png(f, s, fontsize=12)
43 43 bin_data = f.getvalue()
44 44 if encode:
45 45 bin_data = encodestring(bin_data)
46 46 return bin_data
47 47
48 48
49 49 _data_uri_template_png = """<img src="data:image/png;base64,%s" alt=%s />"""
50 50
51 51 def latex_to_html(s, alt='image'):
52 52 """Render LaTeX to HTML with embedded PNG data using data URIs.
53 53
54 54 Parameters
55 55 ----------
56 56 s : str
57 57 The raw string containing valid inline LateX.
58 58 alt : str
59 59 The alt text to use for the HTML.
60 60 """
61 61 base64_data = latex_to_png(s, encode=True)
62 62 return _data_uri_template_png % (base64_data, alt)
63 63
64 64
65 65 # From matplotlib, thanks to mdboom. Once this is in matplotlib releases, we
66 66 # will remove.
67 67 def math_to_image(s, filename_or_obj, prop=None, dpi=None, format=None):
68 68 """
69 69 Given a math expression, renders it in a closely-clipped bounding
70 70 box to an image file.
71 71
72 72 *s*
73 73 A math expression. The math portion should be enclosed in
74 74 dollar signs.
75 75
76 76 *filename_or_obj*
77 77 A filepath or writable file-like object to write the image data
78 78 to.
79 79
80 80 *prop*
81 81 If provided, a FontProperties() object describing the size and
82 82 style of the text.
83 83
84 84 *dpi*
85 85 Override the output dpi, otherwise use the default associated
86 86 with the output format.
87 87
88 88 *format*
89 89 The output format, eg. 'svg', 'pdf', 'ps' or 'png'. If not
90 90 provided, will be deduced from the filename.
91 91 """
92 92 from matplotlib import figure
93 93 # backend_agg supports all of the core output formats
94 94 from matplotlib.backends import backend_agg
95 95 from matplotlib.font_manager import FontProperties
96 96 from matplotlib.mathtext import MathTextParser
97 97
98 98 if prop is None:
99 99 prop = FontProperties()
100 100
101 101 parser = MathTextParser('path')
102 102 width, height, depth, _, _ = parser.parse(s, dpi=72, prop=prop)
103 103
104 104 fig = figure.Figure(figsize=(width / 72.0, height / 72.0))
105 105 fig.text(0, depth/height, s, fontproperties=prop)
106 106 backend_agg.FigureCanvasAgg(fig)
107 107 fig.savefig(filename_or_obj, dpi=dpi, format=format)
108 108
109 109 return depth
110 110
@@ -1,322 +1,322 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Pylab (matplotlib) support utilities.
3 3
4 4 Authors
5 5 -------
6 6
7 7 * Fernando Perez.
8 8 * Brian Granger
9 9 """
10 10
11 11 #-----------------------------------------------------------------------------
12 # Copyright (C) 2009 The IPython Development Team
12 # Copyright (C) 2009-2011 The IPython Development Team
13 13 #
14 14 # Distributed under the terms of the BSD License. The full license is in
15 15 # the file COPYING, distributed as part of this software.
16 16 #-----------------------------------------------------------------------------
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Imports
20 20 #-----------------------------------------------------------------------------
21 21
22 22 from io import BytesIO
23 23
24 24 from IPython.utils.decorators import flag_calls
25 25
26 26 # If user specifies a GUI, that dictates the backend, otherwise we read the
27 27 # user's mpl default from the mpl rc structure
28 28 backends = {'tk': 'TkAgg',
29 29 'gtk': 'GTKAgg',
30 30 'wx': 'WXAgg',
31 31 'qt': 'Qt4Agg', # qt3 not supported
32 32 'qt4': 'Qt4Agg',
33 33 'osx': 'MacOSX',
34 34 'inline' : 'module://IPython.zmq.pylab.backend_inline'}
35 35
36 36 # We also need a reverse backends2guis mapping that will properly choose which
37 37 # GUI support to activate based on the desired matplotlib backend. For the
38 38 # most part it's just a reverse of the above dict, but we also need to add a
39 39 # few others that map to the same GUI manually:
40 40 backend2gui = dict(zip(backends.values(), backends.keys()))
41 41 # In the reverse mapping, there are a few extra valid matplotlib backends that
42 42 # map to the same GUI support
43 43 backend2gui['GTK'] = backend2gui['GTKCairo'] = 'gtk'
44 44 backend2gui['WX'] = 'wx'
45 45 backend2gui['CocoaAgg'] = 'osx'
46 46
47 47 #-----------------------------------------------------------------------------
48 48 # Matplotlib utilities
49 49 #-----------------------------------------------------------------------------
50 50
51 51
52 52 def getfigs(*fig_nums):
53 53 """Get a list of matplotlib figures by figure numbers.
54 54
55 55 If no arguments are given, all available figures are returned. If the
56 56 argument list contains references to invalid figures, a warning is printed
57 57 but the function continues pasting further figures.
58 58
59 59 Parameters
60 60 ----------
61 61 figs : tuple
62 62 A tuple of ints giving the figure numbers of the figures to return.
63 63 """
64 64 from matplotlib._pylab_helpers import Gcf
65 65 if not fig_nums:
66 66 fig_managers = Gcf.get_all_fig_managers()
67 67 return [fm.canvas.figure for fm in fig_managers]
68 68 else:
69 69 figs = []
70 70 for num in fig_nums:
71 71 f = Gcf.figs.get(num)
72 72 if f is None:
73 73 print('Warning: figure %s not available.' % num)
74 74 else:
75 75 figs.append(f.canvas.figure)
76 76 return figs
77 77
78 78
79 79 def figsize(sizex, sizey):
80 80 """Set the default figure size to be [sizex, sizey].
81 81
82 82 This is just an easy to remember, convenience wrapper that sets::
83 83
84 84 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
85 85 """
86 86 import matplotlib
87 87 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
88 88
89 89
90 90 def print_figure(fig, fmt='png'):
91 91 """Convert a figure to svg or png for inline display."""
92 92 # When there's an empty figure, we shouldn't return anything, otherwise we
93 93 # get big blank areas in the qt console.
94 94 if not fig.axes:
95 95 return
96 96
97 97 fc = fig.get_facecolor()
98 98 ec = fig.get_edgecolor()
99 99 fig.set_facecolor('white')
100 100 fig.set_edgecolor('white')
101 101 try:
102 102 bytes_io = BytesIO()
103 103 fig.canvas.print_figure(bytes_io, format=fmt, bbox_inches='tight')
104 104 data = bytes_io.getvalue()
105 105 finally:
106 106 fig.set_facecolor(fc)
107 107 fig.set_edgecolor(ec)
108 108 return data
109 109
110 110
111 111 # We need a little factory function here to create the closure where
112 112 # safe_execfile can live.
113 113 def mpl_runner(safe_execfile):
114 114 """Factory to return a matplotlib-enabled runner for %run.
115 115
116 116 Parameters
117 117 ----------
118 118 safe_execfile : function
119 119 This must be a function with the same interface as the
120 120 :meth:`safe_execfile` method of IPython.
121 121
122 122 Returns
123 123 -------
124 124 A function suitable for use as the ``runner`` argument of the %run magic
125 125 function.
126 126 """
127 127
128 128 def mpl_execfile(fname,*where,**kw):
129 129 """matplotlib-aware wrapper around safe_execfile.
130 130
131 131 Its interface is identical to that of the :func:`execfile` builtin.
132 132
133 133 This is ultimately a call to execfile(), but wrapped in safeties to
134 134 properly handle interactive rendering."""
135 135
136 136 import matplotlib
137 137 import matplotlib.pylab as pylab
138 138
139 139 #print '*** Matplotlib runner ***' # dbg
140 140 # turn off rendering until end of script
141 141 is_interactive = matplotlib.rcParams['interactive']
142 142 matplotlib.interactive(False)
143 143 safe_execfile(fname,*where,**kw)
144 144 matplotlib.interactive(is_interactive)
145 145 # make rendering call now, if the user tried to do it
146 146 if pylab.draw_if_interactive.called:
147 147 pylab.draw()
148 148 pylab.draw_if_interactive.called = False
149 149
150 150 return mpl_execfile
151 151
152 152
153 153 def select_figure_format(shell, fmt):
154 154 """Select figure format for inline backend, either 'png' or 'svg'.
155 155
156 156 Using this method ensures only one figure format is active at a time.
157 157 """
158 158 from matplotlib.figure import Figure
159 159 from IPython.zmq.pylab import backend_inline
160 160
161 161 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
162 162 png_formatter = shell.display_formatter.formatters['image/png']
163 163
164 164 if fmt=='png':
165 165 svg_formatter.type_printers.pop(Figure, None)
166 166 png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png'))
167 167 elif fmt=='svg':
168 168 png_formatter.type_printers.pop(Figure, None)
169 169 svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg'))
170 170 else:
171 171 raise ValueError("supported formats are: 'png', 'svg', not %r"%fmt)
172 172
173 173 # set the format to be used in the backend()
174 174 backend_inline._figure_format = fmt
175 175
176 176 #-----------------------------------------------------------------------------
177 177 # Code for initializing matplotlib and importing pylab
178 178 #-----------------------------------------------------------------------------
179 179
180 180
181 181 def find_gui_and_backend(gui=None):
182 182 """Given a gui string return the gui and mpl backend.
183 183
184 184 Parameters
185 185 ----------
186 186 gui : str
187 187 Can be one of ('tk','gtk','wx','qt','qt4','inline').
188 188
189 189 Returns
190 190 -------
191 191 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
192 192 'WXAgg','Qt4Agg','module://IPython.zmq.pylab.backend_inline').
193 193 """
194 194
195 195 import matplotlib
196 196
197 197 if gui and gui != 'auto':
198 198 # select backend based on requested gui
199 199 backend = backends[gui]
200 200 else:
201 201 backend = matplotlib.rcParams['backend']
202 202 # In this case, we need to find what the appropriate gui selection call
203 203 # should be for IPython, so we can activate inputhook accordingly
204 204 gui = backend2gui.get(backend, None)
205 205 return gui, backend
206 206
207 207
208 208 def activate_matplotlib(backend):
209 209 """Activate the given backend and set interactive to True."""
210 210
211 211 import matplotlib
212 212 if backend.startswith('module://'):
213 213 # Work around bug in matplotlib: matplotlib.use converts the
214 214 # backend_id to lowercase even if a module name is specified!
215 215 matplotlib.rcParams['backend'] = backend
216 216 else:
217 217 matplotlib.use(backend)
218 218 matplotlib.interactive(True)
219 219
220 220 # This must be imported last in the matplotlib series, after
221 221 # backend/interactivity choices have been made
222 222 import matplotlib.pylab as pylab
223 223
224 224 # XXX For now leave this commented out, but depending on discussions with
225 225 # mpl-dev, we may be able to allow interactive switching...
226 226 #import matplotlib.pyplot
227 227 #matplotlib.pyplot.switch_backend(backend)
228 228
229 229 pylab.show._needmain = False
230 230 # We need to detect at runtime whether show() is called by the user.
231 231 # For this, we wrap it into a decorator which adds a 'called' flag.
232 232 pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
233 233
234 234 def import_pylab(user_ns, backend, import_all=True, shell=None):
235 235 """Import the standard pylab symbols into user_ns."""
236 236
237 237 # Import numpy as np/pyplot as plt are conventions we're trying to
238 238 # somewhat standardize on. Making them available to users by default
239 239 # will greatly help this.
240 240 s = ("import numpy\n"
241 241 "import matplotlib\n"
242 242 "from matplotlib import pylab, mlab, pyplot\n"
243 243 "np = numpy\n"
244 244 "plt = pyplot\n"
245 245 )
246 246 exec s in user_ns
247 247
248 248 if shell is not None:
249 249 exec s in shell.user_ns_hidden
250 250 # If using our svg payload backend, register the post-execution
251 251 # function that will pick up the results for display. This can only be
252 252 # done with access to the real shell object.
253 253 #
254 254 from IPython.zmq.pylab.backend_inline import InlineBackend
255 255
256 256 cfg = InlineBackend.instance(config=shell.config)
257 257 cfg.shell = shell
258 258 if cfg not in shell.configurables:
259 259 shell.configurables.append(cfg)
260 260
261 261 if backend == backends['inline']:
262 262 from IPython.zmq.pylab.backend_inline import flush_figures
263 263 from matplotlib import pyplot
264 264 shell.register_post_execute(flush_figures)
265 265 # load inline_rc
266 266 pyplot.rcParams.update(cfg.rc)
267 267
268 268 # Add 'figsize' to pyplot and to the user's namespace
269 269 user_ns['figsize'] = pyplot.figsize = figsize
270 270 shell.user_ns_hidden['figsize'] = figsize
271 271
272 272 # Setup the default figure format
273 273 fmt = cfg.figure_format
274 274 select_figure_format(shell, fmt)
275 275
276 276 # The old pastefig function has been replaced by display
277 277 from IPython.core.display import display
278 278 # Add display and display_png to the user's namespace
279 279 user_ns['display'] = display
280 280 shell.user_ns_hidden['display'] = display
281 281 user_ns['getfigs'] = getfigs
282 282 shell.user_ns_hidden['getfigs'] = getfigs
283 283
284 284 if import_all:
285 285 s = ("from matplotlib.pylab import *\n"
286 286 "from numpy import *\n")
287 287 exec s in user_ns
288 288 if shell is not None:
289 289 exec s in shell.user_ns_hidden
290 290
291 291
292 292 def pylab_activate(user_ns, gui=None, import_all=True, shell=None):
293 293 """Activate pylab mode in the user's namespace.
294 294
295 295 Loads and initializes numpy, matplotlib and friends for interactive use.
296 296
297 297 Parameters
298 298 ----------
299 299 user_ns : dict
300 300 Namespace where the imports will occur.
301 301
302 302 gui : optional, string
303 303 A valid gui name following the conventions of the %gui magic.
304 304
305 305 import_all : optional, boolean
306 306 If true, an 'import *' is done from numpy and pylab.
307 307
308 308 Returns
309 309 -------
310 310 The actual gui used (if not given as input, it was obtained from matplotlib
311 311 itself, and will be needed next to configure IPython's gui integration.
312 312 """
313 313 gui, backend = find_gui_and_backend(gui)
314 314 activate_matplotlib(backend)
315 315 import_pylab(user_ns, backend, import_all, shell)
316 316
317 317 print """
318 318 Welcome to pylab, a matplotlib-based Python environment [backend: %s].
319 319 For more information, type 'help(pylab)'.""" % backend
320 320
321 321 return gui
322 322
@@ -1,1290 +1,1290 b''
1 1 """The IPython Controller Hub with 0MQ
2 2 This is the master object that handles connections from engines and clients,
3 3 and monitors traffic through the various queues.
4 4
5 5 Authors:
6 6
7 7 * Min RK
8 8 """
9 9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2010 The IPython Development Team
10 # Copyright (C) 2010-2011 The IPython Development Team
11 11 #
12 12 # Distributed under the terms of the BSD License. The full license is in
13 13 # the file COPYING, distributed as part of this software.
14 14 #-----------------------------------------------------------------------------
15 15
16 16 #-----------------------------------------------------------------------------
17 17 # Imports
18 18 #-----------------------------------------------------------------------------
19 19 from __future__ import print_function
20 20
21 21 import sys
22 22 import time
23 23 from datetime import datetime
24 24
25 25 import zmq
26 26 from zmq.eventloop import ioloop
27 27 from zmq.eventloop.zmqstream import ZMQStream
28 28
29 29 # internal:
30 30 from IPython.utils.importstring import import_item
31 31 from IPython.utils.traitlets import (
32 32 HasTraits, Instance, Integer, Unicode, Dict, Set, Tuple, CBytes, DottedObjectName
33 33 )
34 34
35 35 from IPython.parallel import error, util
36 36 from IPython.parallel.factory import RegistrationFactory
37 37
38 38 from IPython.zmq.session import SessionFactory
39 39
40 40 from .heartmonitor import HeartMonitor
41 41
42 42 #-----------------------------------------------------------------------------
43 43 # Code
44 44 #-----------------------------------------------------------------------------
45 45
46 46 def _passer(*args, **kwargs):
47 47 return
48 48
49 49 def _printer(*args, **kwargs):
50 50 print (args)
51 51 print (kwargs)
52 52
53 53 def empty_record():
54 54 """Return an empty dict with all record keys."""
55 55 return {
56 56 'msg_id' : None,
57 57 'header' : None,
58 58 'content': None,
59 59 'buffers': None,
60 60 'submitted': None,
61 61 'client_uuid' : None,
62 62 'engine_uuid' : None,
63 63 'started': None,
64 64 'completed': None,
65 65 'resubmitted': None,
66 66 'result_header' : None,
67 67 'result_content' : None,
68 68 'result_buffers' : None,
69 69 'queue' : None,
70 70 'pyin' : None,
71 71 'pyout': None,
72 72 'pyerr': None,
73 73 'stdout': '',
74 74 'stderr': '',
75 75 }
76 76
77 77 def init_record(msg):
78 78 """Initialize a TaskRecord based on a request."""
79 79 header = msg['header']
80 80 return {
81 81 'msg_id' : header['msg_id'],
82 82 'header' : header,
83 83 'content': msg['content'],
84 84 'buffers': msg['buffers'],
85 85 'submitted': header['date'],
86 86 'client_uuid' : None,
87 87 'engine_uuid' : None,
88 88 'started': None,
89 89 'completed': None,
90 90 'resubmitted': None,
91 91 'result_header' : None,
92 92 'result_content' : None,
93 93 'result_buffers' : None,
94 94 'queue' : None,
95 95 'pyin' : None,
96 96 'pyout': None,
97 97 'pyerr': None,
98 98 'stdout': '',
99 99 'stderr': '',
100 100 }
101 101
102 102
103 103 class EngineConnector(HasTraits):
104 104 """A simple object for accessing the various zmq connections of an object.
105 105 Attributes are:
106 106 id (int): engine ID
107 107 uuid (str): uuid (unused?)
108 108 queue (str): identity of queue's XREQ socket
109 109 registration (str): identity of registration XREQ socket
110 110 heartbeat (str): identity of heartbeat XREQ socket
111 111 """
112 112 id=Integer(0)
113 113 queue=CBytes()
114 114 control=CBytes()
115 115 registration=CBytes()
116 116 heartbeat=CBytes()
117 117 pending=Set()
118 118
119 119 class HubFactory(RegistrationFactory):
120 120 """The Configurable for setting up a Hub."""
121 121
122 122 # port-pairs for monitoredqueues:
123 123 hb = Tuple(Integer,Integer,config=True,
124 124 help="""XREQ/SUB Port pair for Engine heartbeats""")
125 125 def _hb_default(self):
126 126 return tuple(util.select_random_ports(2))
127 127
128 128 mux = Tuple(Integer,Integer,config=True,
129 129 help="""Engine/Client Port pair for MUX queue""")
130 130
131 131 def _mux_default(self):
132 132 return tuple(util.select_random_ports(2))
133 133
134 134 task = Tuple(Integer,Integer,config=True,
135 135 help="""Engine/Client Port pair for Task queue""")
136 136 def _task_default(self):
137 137 return tuple(util.select_random_ports(2))
138 138
139 139 control = Tuple(Integer,Integer,config=True,
140 140 help="""Engine/Client Port pair for Control queue""")
141 141
142 142 def _control_default(self):
143 143 return tuple(util.select_random_ports(2))
144 144
145 145 iopub = Tuple(Integer,Integer,config=True,
146 146 help="""Engine/Client Port pair for IOPub relay""")
147 147
148 148 def _iopub_default(self):
149 149 return tuple(util.select_random_ports(2))
150 150
151 151 # single ports:
152 152 mon_port = Integer(config=True,
153 153 help="""Monitor (SUB) port for queue traffic""")
154 154
155 155 def _mon_port_default(self):
156 156 return util.select_random_ports(1)[0]
157 157
158 158 notifier_port = Integer(config=True,
159 159 help="""PUB port for sending engine status notifications""")
160 160
161 161 def _notifier_port_default(self):
162 162 return util.select_random_ports(1)[0]
163 163
164 164 engine_ip = Unicode('127.0.0.1', config=True,
165 165 help="IP on which to listen for engine connections. [default: loopback]")
166 166 engine_transport = Unicode('tcp', config=True,
167 167 help="0MQ transport for engine connections. [default: tcp]")
168 168
169 169 client_ip = Unicode('127.0.0.1', config=True,
170 170 help="IP on which to listen for client connections. [default: loopback]")
171 171 client_transport = Unicode('tcp', config=True,
172 172 help="0MQ transport for client connections. [default : tcp]")
173 173
174 174 monitor_ip = Unicode('127.0.0.1', config=True,
175 175 help="IP on which to listen for monitor messages. [default: loopback]")
176 176 monitor_transport = Unicode('tcp', config=True,
177 177 help="0MQ transport for monitor messages. [default : tcp]")
178 178
179 179 monitor_url = Unicode('')
180 180
181 181 db_class = DottedObjectName('IPython.parallel.controller.dictdb.DictDB',
182 182 config=True, help="""The class to use for the DB backend""")
183 183
184 184 # not configurable
185 185 db = Instance('IPython.parallel.controller.dictdb.BaseDB')
186 186 heartmonitor = Instance('IPython.parallel.controller.heartmonitor.HeartMonitor')
187 187
188 188 def _ip_changed(self, name, old, new):
189 189 self.engine_ip = new
190 190 self.client_ip = new
191 191 self.monitor_ip = new
192 192 self._update_monitor_url()
193 193
194 194 def _update_monitor_url(self):
195 195 self.monitor_url = "%s://%s:%i"%(self.monitor_transport, self.monitor_ip, self.mon_port)
196 196
197 197 def _transport_changed(self, name, old, new):
198 198 self.engine_transport = new
199 199 self.client_transport = new
200 200 self.monitor_transport = new
201 201 self._update_monitor_url()
202 202
203 203 def __init__(self, **kwargs):
204 204 super(HubFactory, self).__init__(**kwargs)
205 205 self._update_monitor_url()
206 206
207 207
208 208 def construct(self):
209 209 self.init_hub()
210 210
211 211 def start(self):
212 212 self.heartmonitor.start()
213 213 self.log.info("Heartmonitor started")
214 214
215 215 def init_hub(self):
216 216 """construct"""
217 217 client_iface = "%s://%s:"%(self.client_transport, self.client_ip) + "%i"
218 218 engine_iface = "%s://%s:"%(self.engine_transport, self.engine_ip) + "%i"
219 219
220 220 ctx = self.context
221 221 loop = self.loop
222 222
223 223 # Registrar socket
224 224 q = ZMQStream(ctx.socket(zmq.ROUTER), loop)
225 225 q.bind(client_iface % self.regport)
226 226 self.log.info("Hub listening on %s for registration."%(client_iface%self.regport))
227 227 if self.client_ip != self.engine_ip:
228 228 q.bind(engine_iface % self.regport)
229 229 self.log.info("Hub listening on %s for registration."%(engine_iface%self.regport))
230 230
231 231 ### Engine connections ###
232 232
233 233 # heartbeat
234 234 hpub = ctx.socket(zmq.PUB)
235 235 hpub.bind(engine_iface % self.hb[0])
236 236 hrep = ctx.socket(zmq.ROUTER)
237 237 hrep.bind(engine_iface % self.hb[1])
238 238 self.heartmonitor = HeartMonitor(loop=loop, config=self.config, log=self.log,
239 239 pingstream=ZMQStream(hpub,loop),
240 240 pongstream=ZMQStream(hrep,loop)
241 241 )
242 242
243 243 ### Client connections ###
244 244 # Notifier socket
245 245 n = ZMQStream(ctx.socket(zmq.PUB), loop)
246 246 n.bind(client_iface%self.notifier_port)
247 247
248 248 ### build and launch the queues ###
249 249
250 250 # monitor socket
251 251 sub = ctx.socket(zmq.SUB)
252 252 sub.setsockopt(zmq.SUBSCRIBE, b"")
253 253 sub.bind(self.monitor_url)
254 254 sub.bind('inproc://monitor')
255 255 sub = ZMQStream(sub, loop)
256 256
257 257 # connect the db
258 258 self.log.info('Hub using DB backend: %r'%(self.db_class.split()[-1]))
259 259 # cdir = self.config.Global.cluster_dir
260 260 self.db = import_item(str(self.db_class))(session=self.session.session,
261 261 config=self.config, log=self.log)
262 262 time.sleep(.25)
263 263 try:
264 264 scheme = self.config.TaskScheduler.scheme_name
265 265 except AttributeError:
266 266 from .scheduler import TaskScheduler
267 267 scheme = TaskScheduler.scheme_name.get_default_value()
268 268 # build connection dicts
269 269 self.engine_info = {
270 270 'control' : engine_iface%self.control[1],
271 271 'mux': engine_iface%self.mux[1],
272 272 'heartbeat': (engine_iface%self.hb[0], engine_iface%self.hb[1]),
273 273 'task' : engine_iface%self.task[1],
274 274 'iopub' : engine_iface%self.iopub[1],
275 275 # 'monitor' : engine_iface%self.mon_port,
276 276 }
277 277
278 278 self.client_info = {
279 279 'control' : client_iface%self.control[0],
280 280 'mux': client_iface%self.mux[0],
281 281 'task' : (scheme, client_iface%self.task[0]),
282 282 'iopub' : client_iface%self.iopub[0],
283 283 'notification': client_iface%self.notifier_port
284 284 }
285 285 self.log.debug("Hub engine addrs: %s"%self.engine_info)
286 286 self.log.debug("Hub client addrs: %s"%self.client_info)
287 287
288 288 # resubmit stream
289 289 r = ZMQStream(ctx.socket(zmq.DEALER), loop)
290 290 url = util.disambiguate_url(self.client_info['task'][-1])
291 291 r.setsockopt(zmq.IDENTITY, self.session.bsession)
292 292 r.connect(url)
293 293
294 294 self.hub = Hub(loop=loop, session=self.session, monitor=sub, heartmonitor=self.heartmonitor,
295 295 query=q, notifier=n, resubmit=r, db=self.db,
296 296 engine_info=self.engine_info, client_info=self.client_info,
297 297 log=self.log)
298 298
299 299
300 300 class Hub(SessionFactory):
301 301 """The IPython Controller Hub with 0MQ connections
302 302
303 303 Parameters
304 304 ==========
305 305 loop: zmq IOLoop instance
306 306 session: Session object
307 307 <removed> context: zmq context for creating new connections (?)
308 308 queue: ZMQStream for monitoring the command queue (SUB)
309 309 query: ZMQStream for engine registration and client queries requests (XREP)
310 310 heartbeat: HeartMonitor object checking the pulse of the engines
311 311 notifier: ZMQStream for broadcasting engine registration changes (PUB)
312 312 db: connection to db for out of memory logging of commands
313 313 NotImplemented
314 314 engine_info: dict of zmq connection information for engines to connect
315 315 to the queues.
316 316 client_info: dict of zmq connection information for engines to connect
317 317 to the queues.
318 318 """
319 319 # internal data structures:
320 320 ids=Set() # engine IDs
321 321 keytable=Dict()
322 322 by_ident=Dict()
323 323 engines=Dict()
324 324 clients=Dict()
325 325 hearts=Dict()
326 326 pending=Set()
327 327 queues=Dict() # pending msg_ids keyed by engine_id
328 328 tasks=Dict() # pending msg_ids submitted as tasks, keyed by client_id
329 329 completed=Dict() # completed msg_ids keyed by engine_id
330 330 all_completed=Set() # completed msg_ids keyed by engine_id
331 331 dead_engines=Set() # completed msg_ids keyed by engine_id
332 332 unassigned=Set() # set of task msg_ds not yet assigned a destination
333 333 incoming_registrations=Dict()
334 334 registration_timeout=Integer()
335 335 _idcounter=Integer(0)
336 336
337 337 # objects from constructor:
338 338 query=Instance(ZMQStream)
339 339 monitor=Instance(ZMQStream)
340 340 notifier=Instance(ZMQStream)
341 341 resubmit=Instance(ZMQStream)
342 342 heartmonitor=Instance(HeartMonitor)
343 343 db=Instance(object)
344 344 client_info=Dict()
345 345 engine_info=Dict()
346 346
347 347
348 348 def __init__(self, **kwargs):
349 349 """
350 350 # universal:
351 351 loop: IOLoop for creating future connections
352 352 session: streamsession for sending serialized data
353 353 # engine:
354 354 queue: ZMQStream for monitoring queue messages
355 355 query: ZMQStream for engine+client registration and client requests
356 356 heartbeat: HeartMonitor object for tracking engines
357 357 # extra:
358 358 db: ZMQStream for db connection (NotImplemented)
359 359 engine_info: zmq address/protocol dict for engine connections
360 360 client_info: zmq address/protocol dict for client connections
361 361 """
362 362
363 363 super(Hub, self).__init__(**kwargs)
364 364 self.registration_timeout = max(5000, 2*self.heartmonitor.period)
365 365
366 366 # validate connection dicts:
367 367 for k,v in self.client_info.iteritems():
368 368 if k == 'task':
369 369 util.validate_url_container(v[1])
370 370 else:
371 371 util.validate_url_container(v)
372 372 # util.validate_url_container(self.client_info)
373 373 util.validate_url_container(self.engine_info)
374 374
375 375 # register our callbacks
376 376 self.query.on_recv(self.dispatch_query)
377 377 self.monitor.on_recv(self.dispatch_monitor_traffic)
378 378
379 379 self.heartmonitor.add_heart_failure_handler(self.handle_heart_failure)
380 380 self.heartmonitor.add_new_heart_handler(self.handle_new_heart)
381 381
382 382 self.monitor_handlers = {b'in' : self.save_queue_request,
383 383 b'out': self.save_queue_result,
384 384 b'intask': self.save_task_request,
385 385 b'outtask': self.save_task_result,
386 386 b'tracktask': self.save_task_destination,
387 387 b'incontrol': _passer,
388 388 b'outcontrol': _passer,
389 389 b'iopub': self.save_iopub_message,
390 390 }
391 391
392 392 self.query_handlers = {'queue_request': self.queue_status,
393 393 'result_request': self.get_results,
394 394 'history_request': self.get_history,
395 395 'db_request': self.db_query,
396 396 'purge_request': self.purge_results,
397 397 'load_request': self.check_load,
398 398 'resubmit_request': self.resubmit_task,
399 399 'shutdown_request': self.shutdown_request,
400 400 'registration_request' : self.register_engine,
401 401 'unregistration_request' : self.unregister_engine,
402 402 'connection_request': self.connection_request,
403 403 }
404 404
405 405 # ignore resubmit replies
406 406 self.resubmit.on_recv(lambda msg: None, copy=False)
407 407
408 408 self.log.info("hub::created hub")
409 409
410 410 @property
411 411 def _next_id(self):
412 412 """gemerate a new ID.
413 413
414 414 No longer reuse old ids, just count from 0."""
415 415 newid = self._idcounter
416 416 self._idcounter += 1
417 417 return newid
418 418 # newid = 0
419 419 # incoming = [id[0] for id in self.incoming_registrations.itervalues()]
420 420 # # print newid, self.ids, self.incoming_registrations
421 421 # while newid in self.ids or newid in incoming:
422 422 # newid += 1
423 423 # return newid
424 424
425 425 #-----------------------------------------------------------------------------
426 426 # message validation
427 427 #-----------------------------------------------------------------------------
428 428
429 429 def _validate_targets(self, targets):
430 430 """turn any valid targets argument into a list of integer ids"""
431 431 if targets is None:
432 432 # default to all
433 433 targets = self.ids
434 434
435 435 if isinstance(targets, (int,str,unicode)):
436 436 # only one target specified
437 437 targets = [targets]
438 438 _targets = []
439 439 for t in targets:
440 440 # map raw identities to ids
441 441 if isinstance(t, (str,unicode)):
442 442 t = self.by_ident.get(t, t)
443 443 _targets.append(t)
444 444 targets = _targets
445 445 bad_targets = [ t for t in targets if t not in self.ids ]
446 446 if bad_targets:
447 447 raise IndexError("No Such Engine: %r"%bad_targets)
448 448 if not targets:
449 449 raise IndexError("No Engines Registered")
450 450 return targets
451 451
452 452 #-----------------------------------------------------------------------------
453 453 # dispatch methods (1 per stream)
454 454 #-----------------------------------------------------------------------------
455 455
456 456
457 457 def dispatch_monitor_traffic(self, msg):
458 458 """all ME and Task queue messages come through here, as well as
459 459 IOPub traffic."""
460 460 self.log.debug("monitor traffic: %r"%msg[:2])
461 461 switch = msg[0]
462 462 try:
463 463 idents, msg = self.session.feed_identities(msg[1:])
464 464 except ValueError:
465 465 idents=[]
466 466 if not idents:
467 467 self.log.error("Bad Monitor Message: %r"%msg)
468 468 return
469 469 handler = self.monitor_handlers.get(switch, None)
470 470 if handler is not None:
471 471 handler(idents, msg)
472 472 else:
473 473 self.log.error("Invalid monitor topic: %r"%switch)
474 474
475 475
476 476 def dispatch_query(self, msg):
477 477 """Route registration requests and queries from clients."""
478 478 try:
479 479 idents, msg = self.session.feed_identities(msg)
480 480 except ValueError:
481 481 idents = []
482 482 if not idents:
483 483 self.log.error("Bad Query Message: %r"%msg)
484 484 return
485 485 client_id = idents[0]
486 486 try:
487 487 msg = self.session.unserialize(msg, content=True)
488 488 except Exception:
489 489 content = error.wrap_exception()
490 490 self.log.error("Bad Query Message: %r"%msg, exc_info=True)
491 491 self.session.send(self.query, "hub_error", ident=client_id,
492 492 content=content)
493 493 return
494 494 # print client_id, header, parent, content
495 495 #switch on message type:
496 496 msg_type = msg['header']['msg_type']
497 497 self.log.info("client::client %r requested %r"%(client_id, msg_type))
498 498 handler = self.query_handlers.get(msg_type, None)
499 499 try:
500 500 assert handler is not None, "Bad Message Type: %r"%msg_type
501 501 except:
502 502 content = error.wrap_exception()
503 503 self.log.error("Bad Message Type: %r"%msg_type, exc_info=True)
504 504 self.session.send(self.query, "hub_error", ident=client_id,
505 505 content=content)
506 506 return
507 507
508 508 else:
509 509 handler(idents, msg)
510 510
511 511 def dispatch_db(self, msg):
512 512 """"""
513 513 raise NotImplementedError
514 514
515 515 #---------------------------------------------------------------------------
516 516 # handler methods (1 per event)
517 517 #---------------------------------------------------------------------------
518 518
519 519 #----------------------- Heartbeat --------------------------------------
520 520
521 521 def handle_new_heart(self, heart):
522 522 """handler to attach to heartbeater.
523 523 Called when a new heart starts to beat.
524 524 Triggers completion of registration."""
525 525 self.log.debug("heartbeat::handle_new_heart(%r)"%heart)
526 526 if heart not in self.incoming_registrations:
527 527 self.log.info("heartbeat::ignoring new heart: %r"%heart)
528 528 else:
529 529 self.finish_registration(heart)
530 530
531 531
532 532 def handle_heart_failure(self, heart):
533 533 """handler to attach to heartbeater.
534 534 called when a previously registered heart fails to respond to beat request.
535 535 triggers unregistration"""
536 536 self.log.debug("heartbeat::handle_heart_failure(%r)"%heart)
537 537 eid = self.hearts.get(heart, None)
538 538 queue = self.engines[eid].queue
539 539 if eid is None:
540 540 self.log.info("heartbeat::ignoring heart failure %r"%heart)
541 541 else:
542 542 self.unregister_engine(heart, dict(content=dict(id=eid, queue=queue)))
543 543
544 544 #----------------------- MUX Queue Traffic ------------------------------
545 545
546 546 def save_queue_request(self, idents, msg):
547 547 if len(idents) < 2:
548 548 self.log.error("invalid identity prefix: %r"%idents)
549 549 return
550 550 queue_id, client_id = idents[:2]
551 551 try:
552 552 msg = self.session.unserialize(msg)
553 553 except Exception:
554 554 self.log.error("queue::client %r sent invalid message to %r: %r"%(client_id, queue_id, msg), exc_info=True)
555 555 return
556 556
557 557 eid = self.by_ident.get(queue_id, None)
558 558 if eid is None:
559 559 self.log.error("queue::target %r not registered"%queue_id)
560 560 self.log.debug("queue:: valid are: %r"%(self.by_ident.keys()))
561 561 return
562 562 record = init_record(msg)
563 563 msg_id = record['msg_id']
564 564 # Unicode in records
565 565 record['engine_uuid'] = queue_id.decode('ascii')
566 566 record['client_uuid'] = client_id.decode('ascii')
567 567 record['queue'] = 'mux'
568 568
569 569 try:
570 570 # it's posible iopub arrived first:
571 571 existing = self.db.get_record(msg_id)
572 572 for key,evalue in existing.iteritems():
573 573 rvalue = record.get(key, None)
574 574 if evalue and rvalue and evalue != rvalue:
575 575 self.log.warn("conflicting initial state for record: %r:%r <%r> %r"%(msg_id, rvalue, key, evalue))
576 576 elif evalue and not rvalue:
577 577 record[key] = evalue
578 578 try:
579 579 self.db.update_record(msg_id, record)
580 580 except Exception:
581 581 self.log.error("DB Error updating record %r"%msg_id, exc_info=True)
582 582 except KeyError:
583 583 try:
584 584 self.db.add_record(msg_id, record)
585 585 except Exception:
586 586 self.log.error("DB Error adding record %r"%msg_id, exc_info=True)
587 587
588 588
589 589 self.pending.add(msg_id)
590 590 self.queues[eid].append(msg_id)
591 591
592 592 def save_queue_result(self, idents, msg):
593 593 if len(idents) < 2:
594 594 self.log.error("invalid identity prefix: %r"%idents)
595 595 return
596 596
597 597 client_id, queue_id = idents[:2]
598 598 try:
599 599 msg = self.session.unserialize(msg)
600 600 except Exception:
601 601 self.log.error("queue::engine %r sent invalid message to %r: %r"%(
602 602 queue_id,client_id, msg), exc_info=True)
603 603 return
604 604
605 605 eid = self.by_ident.get(queue_id, None)
606 606 if eid is None:
607 607 self.log.error("queue::unknown engine %r is sending a reply: "%queue_id)
608 608 return
609 609
610 610 parent = msg['parent_header']
611 611 if not parent:
612 612 return
613 613 msg_id = parent['msg_id']
614 614 if msg_id in self.pending:
615 615 self.pending.remove(msg_id)
616 616 self.all_completed.add(msg_id)
617 617 self.queues[eid].remove(msg_id)
618 618 self.completed[eid].append(msg_id)
619 619 elif msg_id not in self.all_completed:
620 620 # it could be a result from a dead engine that died before delivering the
621 621 # result
622 622 self.log.warn("queue:: unknown msg finished %r"%msg_id)
623 623 return
624 624 # update record anyway, because the unregistration could have been premature
625 625 rheader = msg['header']
626 626 completed = rheader['date']
627 627 started = rheader.get('started', None)
628 628 result = {
629 629 'result_header' : rheader,
630 630 'result_content': msg['content'],
631 631 'started' : started,
632 632 'completed' : completed
633 633 }
634 634
635 635 result['result_buffers'] = msg['buffers']
636 636 try:
637 637 self.db.update_record(msg_id, result)
638 638 except Exception:
639 639 self.log.error("DB Error updating record %r"%msg_id, exc_info=True)
640 640
641 641
642 642 #--------------------- Task Queue Traffic ------------------------------
643 643
644 644 def save_task_request(self, idents, msg):
645 645 """Save the submission of a task."""
646 646 client_id = idents[0]
647 647
648 648 try:
649 649 msg = self.session.unserialize(msg)
650 650 except Exception:
651 651 self.log.error("task::client %r sent invalid task message: %r"%(
652 652 client_id, msg), exc_info=True)
653 653 return
654 654 record = init_record(msg)
655 655
656 656 record['client_uuid'] = client_id
657 657 record['queue'] = 'task'
658 658 header = msg['header']
659 659 msg_id = header['msg_id']
660 660 self.pending.add(msg_id)
661 661 self.unassigned.add(msg_id)
662 662 try:
663 663 # it's posible iopub arrived first:
664 664 existing = self.db.get_record(msg_id)
665 665 if existing['resubmitted']:
666 666 for key in ('submitted', 'client_uuid', 'buffers'):
667 667 # don't clobber these keys on resubmit
668 668 # submitted and client_uuid should be different
669 669 # and buffers might be big, and shouldn't have changed
670 670 record.pop(key)
671 671 # still check content,header which should not change
672 672 # but are not expensive to compare as buffers
673 673
674 674 for key,evalue in existing.iteritems():
675 675 if key.endswith('buffers'):
676 676 # don't compare buffers
677 677 continue
678 678 rvalue = record.get(key, None)
679 679 if evalue and rvalue and evalue != rvalue:
680 680 self.log.warn("conflicting initial state for record: %r:%r <%r> %r"%(msg_id, rvalue, key, evalue))
681 681 elif evalue and not rvalue:
682 682 record[key] = evalue
683 683 try:
684 684 self.db.update_record(msg_id, record)
685 685 except Exception:
686 686 self.log.error("DB Error updating record %r"%msg_id, exc_info=True)
687 687 except KeyError:
688 688 try:
689 689 self.db.add_record(msg_id, record)
690 690 except Exception:
691 691 self.log.error("DB Error adding record %r"%msg_id, exc_info=True)
692 692 except Exception:
693 693 self.log.error("DB Error saving task request %r"%msg_id, exc_info=True)
694 694
695 695 def save_task_result(self, idents, msg):
696 696 """save the result of a completed task."""
697 697 client_id = idents[0]
698 698 try:
699 699 msg = self.session.unserialize(msg)
700 700 except Exception:
701 701 self.log.error("task::invalid task result message send to %r: %r"%(
702 702 client_id, msg), exc_info=True)
703 703 return
704 704
705 705 parent = msg['parent_header']
706 706 if not parent:
707 707 # print msg
708 708 self.log.warn("Task %r had no parent!"%msg)
709 709 return
710 710 msg_id = parent['msg_id']
711 711 if msg_id in self.unassigned:
712 712 self.unassigned.remove(msg_id)
713 713
714 714 header = msg['header']
715 715 engine_uuid = header.get('engine', None)
716 716 eid = self.by_ident.get(engine_uuid, None)
717 717
718 718 if msg_id in self.pending:
719 719 self.pending.remove(msg_id)
720 720 self.all_completed.add(msg_id)
721 721 if eid is not None:
722 722 self.completed[eid].append(msg_id)
723 723 if msg_id in self.tasks[eid]:
724 724 self.tasks[eid].remove(msg_id)
725 725 completed = header['date']
726 726 started = header.get('started', None)
727 727 result = {
728 728 'result_header' : header,
729 729 'result_content': msg['content'],
730 730 'started' : started,
731 731 'completed' : completed,
732 732 'engine_uuid': engine_uuid
733 733 }
734 734
735 735 result['result_buffers'] = msg['buffers']
736 736 try:
737 737 self.db.update_record(msg_id, result)
738 738 except Exception:
739 739 self.log.error("DB Error saving task request %r"%msg_id, exc_info=True)
740 740
741 741 else:
742 742 self.log.debug("task::unknown task %r finished"%msg_id)
743 743
744 744 def save_task_destination(self, idents, msg):
745 745 try:
746 746 msg = self.session.unserialize(msg, content=True)
747 747 except Exception:
748 748 self.log.error("task::invalid task tracking message", exc_info=True)
749 749 return
750 750 content = msg['content']
751 751 # print (content)
752 752 msg_id = content['msg_id']
753 753 engine_uuid = content['engine_id']
754 754 eid = self.by_ident[util.asbytes(engine_uuid)]
755 755
756 756 self.log.info("task::task %r arrived on %r"%(msg_id, eid))
757 757 if msg_id in self.unassigned:
758 758 self.unassigned.remove(msg_id)
759 759 # else:
760 760 # self.log.debug("task::task %r not listed as MIA?!"%(msg_id))
761 761
762 762 self.tasks[eid].append(msg_id)
763 763 # self.pending[msg_id][1].update(received=datetime.now(),engine=(eid,engine_uuid))
764 764 try:
765 765 self.db.update_record(msg_id, dict(engine_uuid=engine_uuid))
766 766 except Exception:
767 767 self.log.error("DB Error saving task destination %r"%msg_id, exc_info=True)
768 768
769 769
770 770 def mia_task_request(self, idents, msg):
771 771 raise NotImplementedError
772 772 client_id = idents[0]
773 773 # content = dict(mia=self.mia,status='ok')
774 774 # self.session.send('mia_reply', content=content, idents=client_id)
775 775
776 776
777 777 #--------------------- IOPub Traffic ------------------------------
778 778
779 779 def save_iopub_message(self, topics, msg):
780 780 """save an iopub message into the db"""
781 781 # print (topics)
782 782 try:
783 783 msg = self.session.unserialize(msg, content=True)
784 784 except Exception:
785 785 self.log.error("iopub::invalid IOPub message", exc_info=True)
786 786 return
787 787
788 788 parent = msg['parent_header']
789 789 if not parent:
790 790 self.log.error("iopub::invalid IOPub message: %r"%msg)
791 791 return
792 792 msg_id = parent['msg_id']
793 793 msg_type = msg['header']['msg_type']
794 794 content = msg['content']
795 795
796 796 # ensure msg_id is in db
797 797 try:
798 798 rec = self.db.get_record(msg_id)
799 799 except KeyError:
800 800 rec = empty_record()
801 801 rec['msg_id'] = msg_id
802 802 self.db.add_record(msg_id, rec)
803 803 # stream
804 804 d = {}
805 805 if msg_type == 'stream':
806 806 name = content['name']
807 807 s = rec[name] or ''
808 808 d[name] = s + content['data']
809 809
810 810 elif msg_type == 'pyerr':
811 811 d['pyerr'] = content
812 812 elif msg_type == 'pyin':
813 813 d['pyin'] = content['code']
814 814 else:
815 815 d[msg_type] = content.get('data', '')
816 816
817 817 try:
818 818 self.db.update_record(msg_id, d)
819 819 except Exception:
820 820 self.log.error("DB Error saving iopub message %r"%msg_id, exc_info=True)
821 821
822 822
823 823
824 824 #-------------------------------------------------------------------------
825 825 # Registration requests
826 826 #-------------------------------------------------------------------------
827 827
828 828 def connection_request(self, client_id, msg):
829 829 """Reply with connection addresses for clients."""
830 830 self.log.info("client::client %r connected"%client_id)
831 831 content = dict(status='ok')
832 832 content.update(self.client_info)
833 833 jsonable = {}
834 834 for k,v in self.keytable.iteritems():
835 835 if v not in self.dead_engines:
836 836 jsonable[str(k)] = v.decode('ascii')
837 837 content['engines'] = jsonable
838 838 self.session.send(self.query, 'connection_reply', content, parent=msg, ident=client_id)
839 839
840 840 def register_engine(self, reg, msg):
841 841 """Register a new engine."""
842 842 content = msg['content']
843 843 try:
844 844 queue = util.asbytes(content['queue'])
845 845 except KeyError:
846 846 self.log.error("registration::queue not specified", exc_info=True)
847 847 return
848 848 heart = content.get('heartbeat', None)
849 849 if heart:
850 850 heart = util.asbytes(heart)
851 851 """register a new engine, and create the socket(s) necessary"""
852 852 eid = self._next_id
853 853 # print (eid, queue, reg, heart)
854 854
855 855 self.log.debug("registration::register_engine(%i, %r, %r, %r)"%(eid, queue, reg, heart))
856 856
857 857 content = dict(id=eid,status='ok')
858 858 content.update(self.engine_info)
859 859 # check if requesting available IDs:
860 860 if queue in self.by_ident:
861 861 try:
862 862 raise KeyError("queue_id %r in use"%queue)
863 863 except:
864 864 content = error.wrap_exception()
865 865 self.log.error("queue_id %r in use"%queue, exc_info=True)
866 866 elif heart in self.hearts: # need to check unique hearts?
867 867 try:
868 868 raise KeyError("heart_id %r in use"%heart)
869 869 except:
870 870 self.log.error("heart_id %r in use"%heart, exc_info=True)
871 871 content = error.wrap_exception()
872 872 else:
873 873 for h, pack in self.incoming_registrations.iteritems():
874 874 if heart == h:
875 875 try:
876 876 raise KeyError("heart_id %r in use"%heart)
877 877 except:
878 878 self.log.error("heart_id %r in use"%heart, exc_info=True)
879 879 content = error.wrap_exception()
880 880 break
881 881 elif queue == pack[1]:
882 882 try:
883 883 raise KeyError("queue_id %r in use"%queue)
884 884 except:
885 885 self.log.error("queue_id %r in use"%queue, exc_info=True)
886 886 content = error.wrap_exception()
887 887 break
888 888
889 889 msg = self.session.send(self.query, "registration_reply",
890 890 content=content,
891 891 ident=reg)
892 892
893 893 if content['status'] == 'ok':
894 894 if heart in self.heartmonitor.hearts:
895 895 # already beating
896 896 self.incoming_registrations[heart] = (eid,queue,reg[0],None)
897 897 self.finish_registration(heart)
898 898 else:
899 899 purge = lambda : self._purge_stalled_registration(heart)
900 900 dc = ioloop.DelayedCallback(purge, self.registration_timeout, self.loop)
901 901 dc.start()
902 902 self.incoming_registrations[heart] = (eid,queue,reg[0],dc)
903 903 else:
904 904 self.log.error("registration::registration %i failed: %r"%(eid, content['evalue']))
905 905 return eid
906 906
907 907 def unregister_engine(self, ident, msg):
908 908 """Unregister an engine that explicitly requested to leave."""
909 909 try:
910 910 eid = msg['content']['id']
911 911 except:
912 912 self.log.error("registration::bad engine id for unregistration: %r"%ident, exc_info=True)
913 913 return
914 914 self.log.info("registration::unregister_engine(%r)"%eid)
915 915 # print (eid)
916 916 uuid = self.keytable[eid]
917 917 content=dict(id=eid, queue=uuid.decode('ascii'))
918 918 self.dead_engines.add(uuid)
919 919 # self.ids.remove(eid)
920 920 # uuid = self.keytable.pop(eid)
921 921 #
922 922 # ec = self.engines.pop(eid)
923 923 # self.hearts.pop(ec.heartbeat)
924 924 # self.by_ident.pop(ec.queue)
925 925 # self.completed.pop(eid)
926 926 handleit = lambda : self._handle_stranded_msgs(eid, uuid)
927 927 dc = ioloop.DelayedCallback(handleit, self.registration_timeout, self.loop)
928 928 dc.start()
929 929 ############## TODO: HANDLE IT ################
930 930
931 931 if self.notifier:
932 932 self.session.send(self.notifier, "unregistration_notification", content=content)
933 933
934 934 def _handle_stranded_msgs(self, eid, uuid):
935 935 """Handle messages known to be on an engine when the engine unregisters.
936 936
937 937 It is possible that this will fire prematurely - that is, an engine will
938 938 go down after completing a result, and the client will be notified
939 939 that the result failed and later receive the actual result.
940 940 """
941 941
942 942 outstanding = self.queues[eid]
943 943
944 944 for msg_id in outstanding:
945 945 self.pending.remove(msg_id)
946 946 self.all_completed.add(msg_id)
947 947 try:
948 948 raise error.EngineError("Engine %r died while running task %r"%(eid, msg_id))
949 949 except:
950 950 content = error.wrap_exception()
951 951 # build a fake header:
952 952 header = {}
953 953 header['engine'] = uuid
954 954 header['date'] = datetime.now()
955 955 rec = dict(result_content=content, result_header=header, result_buffers=[])
956 956 rec['completed'] = header['date']
957 957 rec['engine_uuid'] = uuid
958 958 try:
959 959 self.db.update_record(msg_id, rec)
960 960 except Exception:
961 961 self.log.error("DB Error handling stranded msg %r"%msg_id, exc_info=True)
962 962
963 963
964 964 def finish_registration(self, heart):
965 965 """Second half of engine registration, called after our HeartMonitor
966 966 has received a beat from the Engine's Heart."""
967 967 try:
968 968 (eid,queue,reg,purge) = self.incoming_registrations.pop(heart)
969 969 except KeyError:
970 970 self.log.error("registration::tried to finish nonexistant registration", exc_info=True)
971 971 return
972 972 self.log.info("registration::finished registering engine %i:%r"%(eid,queue))
973 973 if purge is not None:
974 974 purge.stop()
975 975 control = queue
976 976 self.ids.add(eid)
977 977 self.keytable[eid] = queue
978 978 self.engines[eid] = EngineConnector(id=eid, queue=queue, registration=reg,
979 979 control=control, heartbeat=heart)
980 980 self.by_ident[queue] = eid
981 981 self.queues[eid] = list()
982 982 self.tasks[eid] = list()
983 983 self.completed[eid] = list()
984 984 self.hearts[heart] = eid
985 985 content = dict(id=eid, queue=self.engines[eid].queue.decode('ascii'))
986 986 if self.notifier:
987 987 self.session.send(self.notifier, "registration_notification", content=content)
988 988 self.log.info("engine::Engine Connected: %i"%eid)
989 989
990 990 def _purge_stalled_registration(self, heart):
991 991 if heart in self.incoming_registrations:
992 992 eid = self.incoming_registrations.pop(heart)[0]
993 993 self.log.info("registration::purging stalled registration: %i"%eid)
994 994 else:
995 995 pass
996 996
997 997 #-------------------------------------------------------------------------
998 998 # Client Requests
999 999 #-------------------------------------------------------------------------
1000 1000
1001 1001 def shutdown_request(self, client_id, msg):
1002 1002 """handle shutdown request."""
1003 1003 self.session.send(self.query, 'shutdown_reply', content={'status': 'ok'}, ident=client_id)
1004 1004 # also notify other clients of shutdown
1005 1005 self.session.send(self.notifier, 'shutdown_notice', content={'status': 'ok'})
1006 1006 dc = ioloop.DelayedCallback(lambda : self._shutdown(), 1000, self.loop)
1007 1007 dc.start()
1008 1008
1009 1009 def _shutdown(self):
1010 1010 self.log.info("hub::hub shutting down.")
1011 1011 time.sleep(0.1)
1012 1012 sys.exit(0)
1013 1013
1014 1014
1015 1015 def check_load(self, client_id, msg):
1016 1016 content = msg['content']
1017 1017 try:
1018 1018 targets = content['targets']
1019 1019 targets = self._validate_targets(targets)
1020 1020 except:
1021 1021 content = error.wrap_exception()
1022 1022 self.session.send(self.query, "hub_error",
1023 1023 content=content, ident=client_id)
1024 1024 return
1025 1025
1026 1026 content = dict(status='ok')
1027 1027 # loads = {}
1028 1028 for t in targets:
1029 1029 content[bytes(t)] = len(self.queues[t])+len(self.tasks[t])
1030 1030 self.session.send(self.query, "load_reply", content=content, ident=client_id)
1031 1031
1032 1032
1033 1033 def queue_status(self, client_id, msg):
1034 1034 """Return the Queue status of one or more targets.
1035 1035 if verbose: return the msg_ids
1036 1036 else: return len of each type.
1037 1037 keys: queue (pending MUX jobs)
1038 1038 tasks (pending Task jobs)
1039 1039 completed (finished jobs from both queues)"""
1040 1040 content = msg['content']
1041 1041 targets = content['targets']
1042 1042 try:
1043 1043 targets = self._validate_targets(targets)
1044 1044 except:
1045 1045 content = error.wrap_exception()
1046 1046 self.session.send(self.query, "hub_error",
1047 1047 content=content, ident=client_id)
1048 1048 return
1049 1049 verbose = content.get('verbose', False)
1050 1050 content = dict(status='ok')
1051 1051 for t in targets:
1052 1052 queue = self.queues[t]
1053 1053 completed = self.completed[t]
1054 1054 tasks = self.tasks[t]
1055 1055 if not verbose:
1056 1056 queue = len(queue)
1057 1057 completed = len(completed)
1058 1058 tasks = len(tasks)
1059 1059 content[str(t)] = {'queue': queue, 'completed': completed , 'tasks': tasks}
1060 1060 content['unassigned'] = list(self.unassigned) if verbose else len(self.unassigned)
1061 1061 # print (content)
1062 1062 self.session.send(self.query, "queue_reply", content=content, ident=client_id)
1063 1063
1064 1064 def purge_results(self, client_id, msg):
1065 1065 """Purge results from memory. This method is more valuable before we move
1066 1066 to a DB based message storage mechanism."""
1067 1067 content = msg['content']
1068 1068 self.log.info("Dropping records with %s", content)
1069 1069 msg_ids = content.get('msg_ids', [])
1070 1070 reply = dict(status='ok')
1071 1071 if msg_ids == 'all':
1072 1072 try:
1073 1073 self.db.drop_matching_records(dict(completed={'$ne':None}))
1074 1074 except Exception:
1075 1075 reply = error.wrap_exception()
1076 1076 else:
1077 1077 pending = filter(lambda m: m in self.pending, msg_ids)
1078 1078 if pending:
1079 1079 try:
1080 1080 raise IndexError("msg pending: %r"%pending[0])
1081 1081 except:
1082 1082 reply = error.wrap_exception()
1083 1083 else:
1084 1084 try:
1085 1085 self.db.drop_matching_records(dict(msg_id={'$in':msg_ids}))
1086 1086 except Exception:
1087 1087 reply = error.wrap_exception()
1088 1088
1089 1089 if reply['status'] == 'ok':
1090 1090 eids = content.get('engine_ids', [])
1091 1091 for eid in eids:
1092 1092 if eid not in self.engines:
1093 1093 try:
1094 1094 raise IndexError("No such engine: %i"%eid)
1095 1095 except:
1096 1096 reply = error.wrap_exception()
1097 1097 break
1098 1098 uid = self.engines[eid].queue
1099 1099 try:
1100 1100 self.db.drop_matching_records(dict(engine_uuid=uid, completed={'$ne':None}))
1101 1101 except Exception:
1102 1102 reply = error.wrap_exception()
1103 1103 break
1104 1104
1105 1105 self.session.send(self.query, 'purge_reply', content=reply, ident=client_id)
1106 1106
1107 1107 def resubmit_task(self, client_id, msg):
1108 1108 """Resubmit one or more tasks."""
1109 1109 def finish(reply):
1110 1110 self.session.send(self.query, 'resubmit_reply', content=reply, ident=client_id)
1111 1111
1112 1112 content = msg['content']
1113 1113 msg_ids = content['msg_ids']
1114 1114 reply = dict(status='ok')
1115 1115 try:
1116 1116 records = self.db.find_records({'msg_id' : {'$in' : msg_ids}}, keys=[
1117 1117 'header', 'content', 'buffers'])
1118 1118 except Exception:
1119 1119 self.log.error('db::db error finding tasks to resubmit', exc_info=True)
1120 1120 return finish(error.wrap_exception())
1121 1121
1122 1122 # validate msg_ids
1123 1123 found_ids = [ rec['msg_id'] for rec in records ]
1124 1124 invalid_ids = filter(lambda m: m in self.pending, found_ids)
1125 1125 if len(records) > len(msg_ids):
1126 1126 try:
1127 1127 raise RuntimeError("DB appears to be in an inconsistent state."
1128 1128 "More matching records were found than should exist")
1129 1129 except Exception:
1130 1130 return finish(error.wrap_exception())
1131 1131 elif len(records) < len(msg_ids):
1132 1132 missing = [ m for m in msg_ids if m not in found_ids ]
1133 1133 try:
1134 1134 raise KeyError("No such msg(s): %r"%missing)
1135 1135 except KeyError:
1136 1136 return finish(error.wrap_exception())
1137 1137 elif invalid_ids:
1138 1138 msg_id = invalid_ids[0]
1139 1139 try:
1140 1140 raise ValueError("Task %r appears to be inflight"%(msg_id))
1141 1141 except Exception:
1142 1142 return finish(error.wrap_exception())
1143 1143
1144 1144 # clear the existing records
1145 1145 now = datetime.now()
1146 1146 rec = empty_record()
1147 1147 map(rec.pop, ['msg_id', 'header', 'content', 'buffers', 'submitted'])
1148 1148 rec['resubmitted'] = now
1149 1149 rec['queue'] = 'task'
1150 1150 rec['client_uuid'] = client_id[0]
1151 1151 try:
1152 1152 for msg_id in msg_ids:
1153 1153 self.all_completed.discard(msg_id)
1154 1154 self.db.update_record(msg_id, rec)
1155 1155 except Exception:
1156 1156 self.log.error('db::db error upating record', exc_info=True)
1157 1157 reply = error.wrap_exception()
1158 1158 else:
1159 1159 # send the messages
1160 1160 for rec in records:
1161 1161 header = rec['header']
1162 1162 # include resubmitted in header to prevent digest collision
1163 1163 header['resubmitted'] = now
1164 1164 msg = self.session.msg(header['msg_type'])
1165 1165 msg['content'] = rec['content']
1166 1166 msg['header'] = header
1167 1167 msg['header']['msg_id'] = rec['msg_id']
1168 1168 self.session.send(self.resubmit, msg, buffers=rec['buffers'])
1169 1169
1170 1170 finish(dict(status='ok'))
1171 1171
1172 1172
1173 1173 def _extract_record(self, rec):
1174 1174 """decompose a TaskRecord dict into subsection of reply for get_result"""
1175 1175 io_dict = {}
1176 1176 for key in 'pyin pyout pyerr stdout stderr'.split():
1177 1177 io_dict[key] = rec[key]
1178 1178 content = { 'result_content': rec['result_content'],
1179 1179 'header': rec['header'],
1180 1180 'result_header' : rec['result_header'],
1181 1181 'io' : io_dict,
1182 1182 }
1183 1183 if rec['result_buffers']:
1184 1184 buffers = map(bytes, rec['result_buffers'])
1185 1185 else:
1186 1186 buffers = []
1187 1187
1188 1188 return content, buffers
1189 1189
1190 1190 def get_results(self, client_id, msg):
1191 1191 """Get the result of 1 or more messages."""
1192 1192 content = msg['content']
1193 1193 msg_ids = sorted(set(content['msg_ids']))
1194 1194 statusonly = content.get('status_only', False)
1195 1195 pending = []
1196 1196 completed = []
1197 1197 content = dict(status='ok')
1198 1198 content['pending'] = pending
1199 1199 content['completed'] = completed
1200 1200 buffers = []
1201 1201 if not statusonly:
1202 1202 try:
1203 1203 matches = self.db.find_records(dict(msg_id={'$in':msg_ids}))
1204 1204 # turn match list into dict, for faster lookup
1205 1205 records = {}
1206 1206 for rec in matches:
1207 1207 records[rec['msg_id']] = rec
1208 1208 except Exception:
1209 1209 content = error.wrap_exception()
1210 1210 self.session.send(self.query, "result_reply", content=content,
1211 1211 parent=msg, ident=client_id)
1212 1212 return
1213 1213 else:
1214 1214 records = {}
1215 1215 for msg_id in msg_ids:
1216 1216 if msg_id in self.pending:
1217 1217 pending.append(msg_id)
1218 1218 elif msg_id in self.all_completed:
1219 1219 completed.append(msg_id)
1220 1220 if not statusonly:
1221 1221 c,bufs = self._extract_record(records[msg_id])
1222 1222 content[msg_id] = c
1223 1223 buffers.extend(bufs)
1224 1224 elif msg_id in records:
1225 1225 if rec['completed']:
1226 1226 completed.append(msg_id)
1227 1227 c,bufs = self._extract_record(records[msg_id])
1228 1228 content[msg_id] = c
1229 1229 buffers.extend(bufs)
1230 1230 else:
1231 1231 pending.append(msg_id)
1232 1232 else:
1233 1233 try:
1234 1234 raise KeyError('No such message: '+msg_id)
1235 1235 except:
1236 1236 content = error.wrap_exception()
1237 1237 break
1238 1238 self.session.send(self.query, "result_reply", content=content,
1239 1239 parent=msg, ident=client_id,
1240 1240 buffers=buffers)
1241 1241
1242 1242 def get_history(self, client_id, msg):
1243 1243 """Get a list of all msg_ids in our DB records"""
1244 1244 try:
1245 1245 msg_ids = self.db.get_history()
1246 1246 except Exception as e:
1247 1247 content = error.wrap_exception()
1248 1248 else:
1249 1249 content = dict(status='ok', history=msg_ids)
1250 1250
1251 1251 self.session.send(self.query, "history_reply", content=content,
1252 1252 parent=msg, ident=client_id)
1253 1253
1254 1254 def db_query(self, client_id, msg):
1255 1255 """Perform a raw query on the task record database."""
1256 1256 content = msg['content']
1257 1257 query = content.get('query', {})
1258 1258 keys = content.get('keys', None)
1259 1259 buffers = []
1260 1260 empty = list()
1261 1261 try:
1262 1262 records = self.db.find_records(query, keys)
1263 1263 except Exception as e:
1264 1264 content = error.wrap_exception()
1265 1265 else:
1266 1266 # extract buffers from reply content:
1267 1267 if keys is not None:
1268 1268 buffer_lens = [] if 'buffers' in keys else None
1269 1269 result_buffer_lens = [] if 'result_buffers' in keys else None
1270 1270 else:
1271 1271 buffer_lens = []
1272 1272 result_buffer_lens = []
1273 1273
1274 1274 for rec in records:
1275 1275 # buffers may be None, so double check
1276 1276 if buffer_lens is not None:
1277 1277 b = rec.pop('buffers', empty) or empty
1278 1278 buffer_lens.append(len(b))
1279 1279 buffers.extend(b)
1280 1280 if result_buffer_lens is not None:
1281 1281 rb = rec.pop('result_buffers', empty) or empty
1282 1282 result_buffer_lens.append(len(rb))
1283 1283 buffers.extend(rb)
1284 1284 content = dict(status='ok', records=records, buffer_lens=buffer_lens,
1285 1285 result_buffer_lens=result_buffer_lens)
1286 1286 # self.log.debug (content)
1287 1287 self.session.send(self.query, "db_reply", content=content,
1288 1288 parent=msg, ident=client_id,
1289 1289 buffers=buffers)
1290 1290
@@ -1,16 +1,16 b''
1 1 # encoding: utf-8
2 2
3 3 """"""
4 4
5 5 __docformat__ = "restructuredtext en"
6 6
7 7 #-------------------------------------------------------------------------------
8 # Copyright (C) 2008 The IPython Development Team
8 # Copyright (C) 2008-2011 The IPython Development Team
9 9 #
10 10 # Distributed under the terms of the BSD License. The full license is in
11 11 # the file COPYING, distributed as part of this software.
12 12 #-------------------------------------------------------------------------------
13 13
14 14 #-------------------------------------------------------------------------------
15 15 # Imports
16 16 #------------------------------------------------------------------------------- No newline at end of file
@@ -1,29 +1,29 b''
1 1 """Testing support (tools to test IPython itself).
2 2 """
3 3
4 4 #-----------------------------------------------------------------------------
5 # Copyright (C) 2009 The IPython Development Team
5 # Copyright (C) 2009-2011 The IPython Development Team
6 6 #
7 7 # Distributed under the terms of the BSD License. The full license is in
8 8 # the file COPYING, distributed as part of this software.
9 9 #-----------------------------------------------------------------------------
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Functions
13 13 #-----------------------------------------------------------------------------
14 14
15 15 # User-level entry point for testing
16 16 def test():
17 17 """Run the entire IPython test suite.
18 18
19 19 For fine-grained control, you should use the :file:`iptest` script supplied
20 20 with the IPython installation."""
21 21
22 22 # Do the import internally, so that this function doesn't increase total
23 23 # import time
24 24 from iptest import run_iptestall
25 25 run_iptestall()
26 26
27 27 # So nose doesn't try to run this as a test itself and we end up with an
28 28 # infinite test loop
29 29 test.__test__ = False
@@ -1,96 +1,96 b''
1 1 """Implementation of the parametric test support for Python 2.x
2 2 """
3 3
4 4 #-----------------------------------------------------------------------------
5 # Copyright (C) 2009 The IPython Development Team
5 # Copyright (C) 2009-2011 The IPython Development Team
6 6 #
7 7 # Distributed under the terms of the BSD License. The full license is in
8 8 # the file COPYING, distributed as part of this software.
9 9 #-----------------------------------------------------------------------------
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Imports
13 13 #-----------------------------------------------------------------------------
14 14
15 15 import unittest
16 16 from compiler.consts import CO_GENERATOR
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Classes and functions
20 20 #-----------------------------------------------------------------------------
21 21
22 22 def isgenerator(func):
23 23 try:
24 24 return func.func_code.co_flags & CO_GENERATOR != 0
25 25 except AttributeError:
26 26 return False
27 27
28 28 class ParametricTestCase(unittest.TestCase):
29 29 """Write parametric tests in normal unittest testcase form.
30 30
31 31 Limitations: the last iteration misses printing out a newline when running
32 32 in verbose mode.
33 33 """
34 34 def run_parametric(self, result, testMethod):
35 35 # But if we have a test generator, we iterate it ourselves
36 36 testgen = testMethod()
37 37 while True:
38 38 try:
39 39 # Initialize test
40 40 result.startTest(self)
41 41
42 42 # SetUp
43 43 try:
44 44 self.setUp()
45 45 except KeyboardInterrupt:
46 46 raise
47 47 except:
48 48 result.addError(self, self._exc_info())
49 49 return
50 50 # Test execution
51 51 ok = False
52 52 try:
53 53 testgen.next()
54 54 ok = True
55 55 except StopIteration:
56 56 # We stop the loop
57 57 break
58 58 except self.failureException:
59 59 result.addFailure(self, self._exc_info())
60 60 except KeyboardInterrupt:
61 61 raise
62 62 except:
63 63 result.addError(self, self._exc_info())
64 64 # TearDown
65 65 try:
66 66 self.tearDown()
67 67 except KeyboardInterrupt:
68 68 raise
69 69 except:
70 70 result.addError(self, self._exc_info())
71 71 ok = False
72 72 if ok: result.addSuccess(self)
73 73
74 74 finally:
75 75 result.stopTest(self)
76 76
77 77 def run(self, result=None):
78 78 if result is None:
79 79 result = self.defaultTestResult()
80 80 testMethod = getattr(self, self._testMethodName)
81 81 # For normal tests, we just call the base class and return that
82 82 if isgenerator(testMethod):
83 83 return self.run_parametric(result, testMethod)
84 84 else:
85 85 return super(ParametricTestCase, self).run(result)
86 86
87 87
88 88 def parametric(func):
89 89 """Decorator to make a simple function into a normal test via unittest."""
90 90
91 91 class Tester(ParametricTestCase):
92 92 test = staticmethod(func)
93 93
94 94 Tester.__name__ = func.__name__
95 95
96 96 return Tester
@@ -1,71 +1,71 b''
1 1 """Implementation of the parametric test support for Python 3.x.
2 2
3 3 Thanks for the py3 version to Robert Collins, from the Testing in Python
4 4 mailing list.
5 5 """
6 6
7 7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2009 The IPython Development Team
8 # Copyright (C) 2009-2011 The IPython Development Team
9 9 #
10 10 # Distributed under the terms of the BSD License. The full license is in
11 11 # the file COPYING, distributed as part of this software.
12 12 #-----------------------------------------------------------------------------
13 13
14 14 #-----------------------------------------------------------------------------
15 15 # Imports
16 16 #-----------------------------------------------------------------------------
17 17
18 18 import unittest
19 19 from unittest import TestSuite
20 20
21 21 #-----------------------------------------------------------------------------
22 22 # Classes and functions
23 23 #-----------------------------------------------------------------------------
24 24
25 25
26 26 def isgenerator(func):
27 27 return hasattr(func,'_generator')
28 28
29 29
30 30 class IterCallableSuite(TestSuite):
31 31 def __init__(self, iterator, adapter):
32 32 self._iter = iterator
33 33 self._adapter = adapter
34 34 def __iter__(self):
35 35 yield self._adapter(self._iter.__next__)
36 36
37 37 class ParametricTestCase(unittest.TestCase):
38 38 """Write parametric tests in normal unittest testcase form.
39 39
40 40 Limitations: the last iteration misses printing out a newline when
41 41 running in verbose mode.
42 42 """
43 43
44 44 def run(self, result=None):
45 45 testMethod = getattr(self, self._testMethodName)
46 46 # For normal tests, we just call the base class and return that
47 47 if isgenerator(testMethod):
48 48 def adapter(next_test):
49 49 ftc = unittest.FunctionTestCase(next_test,
50 50 self.setUp,
51 51 self.tearDown)
52 52 self._nose_case = ftc # Nose 1.0 rejects the test without this
53 53 return ftc
54 54
55 55 return IterCallableSuite(testMethod(),adapter).run(result)
56 56 else:
57 57 return super(ParametricTestCase, self).run(result)
58 58
59 59
60 60 def parametric(func):
61 61 """Decorator to make a simple function into a normal test via
62 62 unittest."""
63 63 # Hack, until I figure out how to write isgenerator() for python3!!
64 64 func._generator = True
65 65
66 66 class Tester(ParametricTestCase):
67 67 test = staticmethod(func)
68 68
69 69 Tester.__name__ = func.__name__
70 70
71 71 return Tester
@@ -1,344 +1,344 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Decorators for labeling test objects.
3 3
4 4 Decorators that merely return a modified version of the original function
5 5 object are straightforward. Decorators that return a new function object need
6 6 to use nose.tools.make_decorator(original_function)(decorator) in returning the
7 7 decorator, in order to preserve metadata such as function name, setup and
8 8 teardown functions and so on - see nose.tools for more information.
9 9
10 10 This module provides a set of useful decorators meant to be ready to use in
11 11 your own tests. See the bottom of the file for the ready-made ones, and if you
12 12 find yourself writing a new one that may be of generic use, add it here.
13 13
14 14 Included decorators:
15 15
16 16
17 17 Lightweight testing that remains unittest-compatible.
18 18
19 19 - @parametric, for parametric test support that is vastly easier to use than
20 20 nose's for debugging. With ours, if a test fails, the stack under inspection
21 21 is that of the test and not that of the test framework.
22 22
23 23 - An @as_unittest decorator can be used to tag any normal parameter-less
24 24 function as a unittest TestCase. Then, both nose and normal unittest will
25 25 recognize it as such. This will make it easier to migrate away from Nose if
26 26 we ever need/want to while maintaining very lightweight tests.
27 27
28 28 NOTE: This file contains IPython-specific decorators. Using the machinery in
29 29 IPython.external.decorators, we import either numpy.testing.decorators if numpy is
30 30 available, OR use equivalent code in IPython.external._decorators, which
31 31 we've copied verbatim from numpy.
32 32
33 33 Authors
34 34 -------
35 35
36 36 - Fernando Perez <Fernando.Perez@berkeley.edu>
37 37 """
38 38
39 39 #-----------------------------------------------------------------------------
40 # Copyright (C) 2009-2010 The IPython Development Team
40 # Copyright (C) 2009-2011 The IPython Development Team
41 41 #
42 42 # Distributed under the terms of the BSD License. The full license is in
43 43 # the file COPYING, distributed as part of this software.
44 44 #-----------------------------------------------------------------------------
45 45
46 46 #-----------------------------------------------------------------------------
47 47 # Imports
48 48 #-----------------------------------------------------------------------------
49 49
50 50 # Stdlib imports
51 51 import inspect
52 52 import sys
53 53 import tempfile
54 54 import unittest
55 55
56 56 # Third-party imports
57 57
58 58 # This is Michele Simionato's decorator module, kept verbatim.
59 59 from IPython.external.decorator import decorator
60 60
61 61 # We already have python3-compliant code for parametric tests
62 62 if sys.version[0]=='2':
63 63 from _paramtestpy2 import parametric, ParametricTestCase
64 64 else:
65 65 from _paramtestpy3 import parametric, ParametricTestCase
66 66
67 67 # Expose the unittest-driven decorators
68 68 from ipunittest import ipdoctest, ipdocstring
69 69
70 70 # Grab the numpy-specific decorators which we keep in a file that we
71 71 # occasionally update from upstream: decorators.py is a copy of
72 72 # numpy.testing.decorators, we expose all of it here.
73 73 from IPython.external.decorators import *
74 74
75 75 #-----------------------------------------------------------------------------
76 76 # Classes and functions
77 77 #-----------------------------------------------------------------------------
78 78
79 79 # Simple example of the basic idea
80 80 def as_unittest(func):
81 81 """Decorator to make a simple function into a normal test via unittest."""
82 82 class Tester(unittest.TestCase):
83 83 def test(self):
84 84 func()
85 85
86 86 Tester.__name__ = func.__name__
87 87
88 88 return Tester
89 89
90 90 # Utility functions
91 91
92 92 def apply_wrapper(wrapper,func):
93 93 """Apply a wrapper to a function for decoration.
94 94
95 95 This mixes Michele Simionato's decorator tool with nose's make_decorator,
96 96 to apply a wrapper in a decorator so that all nose attributes, as well as
97 97 function signature and other properties, survive the decoration cleanly.
98 98 This will ensure that wrapped functions can still be well introspected via
99 99 IPython, for example.
100 100 """
101 101 import nose.tools
102 102
103 103 return decorator(wrapper,nose.tools.make_decorator(func)(wrapper))
104 104
105 105
106 106 def make_label_dec(label,ds=None):
107 107 """Factory function to create a decorator that applies one or more labels.
108 108
109 109 Parameters
110 110 ----------
111 111 label : string or sequence
112 112 One or more labels that will be applied by the decorator to the functions
113 113 it decorates. Labels are attributes of the decorated function with their
114 114 value set to True.
115 115
116 116 ds : string
117 117 An optional docstring for the resulting decorator. If not given, a
118 118 default docstring is auto-generated.
119 119
120 120 Returns
121 121 -------
122 122 A decorator.
123 123
124 124 Examples
125 125 --------
126 126
127 127 A simple labeling decorator:
128 128 >>> slow = make_label_dec('slow')
129 129 >>> print slow.__doc__
130 130 Labels a test as 'slow'.
131 131
132 132 And one that uses multiple labels and a custom docstring:
133 133 >>> rare = make_label_dec(['slow','hard'],
134 134 ... "Mix labels 'slow' and 'hard' for rare tests.")
135 135 >>> print rare.__doc__
136 136 Mix labels 'slow' and 'hard' for rare tests.
137 137
138 138 Now, let's test using this one:
139 139 >>> @rare
140 140 ... def f(): pass
141 141 ...
142 142 >>>
143 143 >>> f.slow
144 144 True
145 145 >>> f.hard
146 146 True
147 147 """
148 148
149 149 if isinstance(label,basestring):
150 150 labels = [label]
151 151 else:
152 152 labels = label
153 153
154 154 # Validate that the given label(s) are OK for use in setattr() by doing a
155 155 # dry run on a dummy function.
156 156 tmp = lambda : None
157 157 for label in labels:
158 158 setattr(tmp,label,True)
159 159
160 160 # This is the actual decorator we'll return
161 161 def decor(f):
162 162 for label in labels:
163 163 setattr(f,label,True)
164 164 return f
165 165
166 166 # Apply the user's docstring, or autogenerate a basic one
167 167 if ds is None:
168 168 ds = "Labels a test as %r." % label
169 169 decor.__doc__ = ds
170 170
171 171 return decor
172 172
173 173
174 174 # Inspired by numpy's skipif, but uses the full apply_wrapper utility to
175 175 # preserve function metadata better and allows the skip condition to be a
176 176 # callable.
177 177 def skipif(skip_condition, msg=None):
178 178 ''' Make function raise SkipTest exception if skip_condition is true
179 179
180 180 Parameters
181 181 ----------
182 182 skip_condition : bool or callable.
183 183 Flag to determine whether to skip test. If the condition is a
184 184 callable, it is used at runtime to dynamically make the decision. This
185 185 is useful for tests that may require costly imports, to delay the cost
186 186 until the test suite is actually executed.
187 187 msg : string
188 188 Message to give on raising a SkipTest exception
189 189
190 190 Returns
191 191 -------
192 192 decorator : function
193 193 Decorator, which, when applied to a function, causes SkipTest
194 194 to be raised when the skip_condition was True, and the function
195 195 to be called normally otherwise.
196 196
197 197 Notes
198 198 -----
199 199 You will see from the code that we had to further decorate the
200 200 decorator with the nose.tools.make_decorator function in order to
201 201 transmit function name, and various other metadata.
202 202 '''
203 203
204 204 def skip_decorator(f):
205 205 # Local import to avoid a hard nose dependency and only incur the
206 206 # import time overhead at actual test-time.
207 207 import nose
208 208
209 209 # Allow for both boolean or callable skip conditions.
210 210 if callable(skip_condition):
211 211 skip_val = skip_condition
212 212 else:
213 213 skip_val = lambda : skip_condition
214 214
215 215 def get_msg(func,msg=None):
216 216 """Skip message with information about function being skipped."""
217 217 if msg is None: out = 'Test skipped due to test condition.'
218 218 else: out = msg
219 219 return "Skipping test: %s. %s" % (func.__name__,out)
220 220
221 221 # We need to define *two* skippers because Python doesn't allow both
222 222 # return with value and yield inside the same function.
223 223 def skipper_func(*args, **kwargs):
224 224 """Skipper for normal test functions."""
225 225 if skip_val():
226 226 raise nose.SkipTest(get_msg(f,msg))
227 227 else:
228 228 return f(*args, **kwargs)
229 229
230 230 def skipper_gen(*args, **kwargs):
231 231 """Skipper for test generators."""
232 232 if skip_val():
233 233 raise nose.SkipTest(get_msg(f,msg))
234 234 else:
235 235 for x in f(*args, **kwargs):
236 236 yield x
237 237
238 238 # Choose the right skipper to use when building the actual generator.
239 239 if nose.util.isgenerator(f):
240 240 skipper = skipper_gen
241 241 else:
242 242 skipper = skipper_func
243 243
244 244 return nose.tools.make_decorator(f)(skipper)
245 245
246 246 return skip_decorator
247 247
248 248 # A version with the condition set to true, common case just to attacha message
249 249 # to a skip decorator
250 250 def skip(msg=None):
251 251 """Decorator factory - mark a test function for skipping from test suite.
252 252
253 253 Parameters
254 254 ----------
255 255 msg : string
256 256 Optional message to be added.
257 257
258 258 Returns
259 259 -------
260 260 decorator : function
261 261 Decorator, which, when applied to a function, causes SkipTest
262 262 to be raised, with the optional message added.
263 263 """
264 264
265 265 return skipif(True,msg)
266 266
267 267
268 268 def onlyif(condition, msg):
269 269 """The reverse from skipif, see skipif for details."""
270 270
271 271 if callable(condition):
272 272 skip_condition = lambda : not condition()
273 273 else:
274 274 skip_condition = lambda : not condition
275 275
276 276 return skipif(skip_condition, msg)
277 277
278 278 #-----------------------------------------------------------------------------
279 279 # Utility functions for decorators
280 280 def module_not_available(module):
281 281 """Can module be imported? Returns true if module does NOT import.
282 282
283 283 This is used to make a decorator to skip tests that require module to be
284 284 available, but delay the 'import numpy' to test execution time.
285 285 """
286 286 try:
287 287 mod = __import__(module)
288 288 mod_not_avail = False
289 289 except ImportError:
290 290 mod_not_avail = True
291 291
292 292 return mod_not_avail
293 293
294 294 #-----------------------------------------------------------------------------
295 295 # Decorators for public use
296 296
297 297 # Decorators to skip certain tests on specific platforms.
298 298 skip_win32 = skipif(sys.platform == 'win32',
299 299 "This test does not run under Windows")
300 300 skip_linux = skipif(sys.platform.startswith('linux'),
301 301 "This test does not run under Linux")
302 302 skip_osx = skipif(sys.platform == 'darwin',"This test does not run under OS X")
303 303
304 304
305 305 # Decorators to skip tests if not on specific platforms.
306 306 skip_if_not_win32 = skipif(sys.platform != 'win32',
307 307 "This test only runs under Windows")
308 308 skip_if_not_linux = skipif(not sys.platform.startswith('linux'),
309 309 "This test only runs under Linux")
310 310 skip_if_not_osx = skipif(sys.platform != 'darwin',
311 311 "This test only runs under OSX")
312 312
313 313 # Other skip decorators
314 314
315 315 # generic skip without module
316 316 skip_without = lambda mod: skipif(module_not_available(mod), "This test requires %s" % mod)
317 317
318 318 skipif_not_numpy = skip_without('numpy')
319 319
320 320 skipif_not_matplotlib = skip_without('matplotlib')
321 321
322 322 skipif_not_sympy = skip_without('sympy')
323 323
324 324 skip_known_failure = knownfailureif(True,'This test is known to fail')
325 325
326 326 known_failure_py3 = knownfailureif(sys.version_info[0] >= 3,
327 327 'This test is known to fail on Python 3.')
328 328
329 329 # A null 'decorator', useful to make more readable code that needs to pick
330 330 # between different decorators based on OS or other conditions
331 331 null_deco = lambda f: f
332 332
333 333 # Some tests only run where we can use unicode paths. Note that we can't just
334 334 # check os.path.supports_unicode_filenames, which is always False on Linux.
335 335 try:
336 336 f = tempfile.NamedTemporaryFile(prefix=u"tmp€")
337 337 except UnicodeEncodeError:
338 338 unicode_paths = False
339 339 else:
340 340 unicode_paths = True
341 341 f.close()
342 342
343 343 onlyif_unicode_paths = onlyif(unicode_paths, ("This test is only applicable "
344 344 "where we can use unicode in filenames."))
@@ -1,240 +1,240 b''
1 1 """Global IPython app to support test running.
2 2
3 3 We must start our own ipython object and heavily muck with it so that all the
4 4 modifications IPython makes to system behavior don't send the doctest machinery
5 5 into a fit. This code should be considered a gross hack, but it gets the job
6 6 done.
7 7 """
8 8 from __future__ import absolute_import
9 9 from __future__ import print_function
10 10
11 11 #-----------------------------------------------------------------------------
12 # Copyright (C) 2009-2010 The IPython Development Team
12 # Copyright (C) 2009-2011 The IPython Development Team
13 13 #
14 14 # Distributed under the terms of the BSD License. The full license is in
15 15 # the file COPYING, distributed as part of this software.
16 16 #-----------------------------------------------------------------------------
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Imports
20 20 #-----------------------------------------------------------------------------
21 21
22 22 # stdlib
23 23 import __builtin__ as builtin_mod
24 24 import os
25 25 import sys
26 26
27 27 # our own
28 28 from . import tools
29 29
30 30 from IPython.core import page
31 31 from IPython.utils import io
32 32 from IPython.utils import py3compat
33 33 from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
34 34
35 35 #-----------------------------------------------------------------------------
36 36 # Functions
37 37 #-----------------------------------------------------------------------------
38 38
39 39 class StreamProxy(io.IOStream):
40 40 """Proxy for sys.stdout/err. This will request the stream *at call time*
41 41 allowing for nose's Capture plugin's redirection of sys.stdout/err.
42 42
43 43 Parameters
44 44 ----------
45 45 name : str
46 46 The name of the stream. This will be requested anew at every call
47 47 """
48 48
49 49 def __init__(self, name):
50 50 self.name=name
51 51
52 52 @property
53 53 def stream(self):
54 54 return getattr(sys, self.name)
55 55
56 56 def flush(self):
57 57 self.stream.flush()
58 58
59 59 # Hack to modify the %run command so we can sync the user's namespace with the
60 60 # test globals. Once we move over to a clean magic system, this will be done
61 61 # with much less ugliness.
62 62
63 63 class py_file_finder(object):
64 64 def __init__(self,test_filename):
65 65 self.test_filename = test_filename
66 66
67 67 def __call__(self,name,win32=False):
68 68 from IPython.utils.path import get_py_filename
69 69 try:
70 70 return get_py_filename(name,win32=win32)
71 71 except IOError:
72 72 test_dir = os.path.dirname(self.test_filename)
73 73 new_path = os.path.join(test_dir,name)
74 74 return get_py_filename(new_path,win32=win32)
75 75
76 76
77 77 def _run_ns_sync(self,arg_s,runner=None):
78 78 """Modified version of %run that syncs testing namespaces.
79 79
80 80 This is strictly needed for running doctests that call %run.
81 81 """
82 82 #print('in run_ns_sync', arg_s, file=sys.stderr) # dbg
83 83 finder = py_file_finder(arg_s)
84 84 return get_ipython().magic_run_ori(arg_s, runner, finder)
85 85
86 86
87 87 class ipnsdict(dict):
88 88 """A special subclass of dict for use as an IPython namespace in doctests.
89 89
90 90 This subclass adds a simple checkpointing capability so that when testing
91 91 machinery clears it (we use it as the test execution context), it doesn't
92 92 get completely destroyed.
93 93
94 94 In addition, it can handle the presence of the '_' key in a special manner,
95 95 which is needed because of how Python's doctest machinery operates with
96 96 '_'. See constructor and :meth:`update` for details.
97 97 """
98 98
99 99 def __init__(self,*a):
100 100 dict.__init__(self,*a)
101 101 self._savedict = {}
102 102 # If this flag is True, the .update() method will unconditionally
103 103 # remove a key named '_'. This is so that such a dict can be used as a
104 104 # namespace in doctests that call '_'.
105 105 self.protect_underscore = False
106 106
107 107 def clear(self):
108 108 dict.clear(self)
109 109 self.update(self._savedict)
110 110
111 111 def _checkpoint(self):
112 112 self._savedict.clear()
113 113 self._savedict.update(self)
114 114
115 115 def update(self,other):
116 116 self._checkpoint()
117 117 dict.update(self,other)
118 118
119 119 if self.protect_underscore:
120 120 # If '_' is in the namespace, python won't set it when executing
121 121 # code *in doctests*, and we have multiple doctests that use '_'.
122 122 # So we ensure that the namespace is always 'clean' of it before
123 123 # it's used for test code execution.
124 124 # This flag is only turned on by the doctest machinery, so that
125 125 # normal test code can assume the _ key is updated like any other
126 126 # key and can test for its presence after cell executions.
127 127 self.pop('_', None)
128 128
129 129 # The builtins namespace must *always* be the real __builtin__ module,
130 130 # else weird stuff happens. The main ipython code does have provisions
131 131 # to ensure this after %run, but since in this class we do some
132 132 # aggressive low-level cleaning of the execution namespace, we need to
133 133 # correct for that ourselves, to ensure consitency with the 'real'
134 134 # ipython.
135 135 self['__builtins__'] = builtin_mod
136 136
137 137 def __delitem__(self, key):
138 138 """Part of the test suite checks that we can release all
139 139 references to an object. So we need to make sure that we're not
140 140 keeping a reference in _savedict."""
141 141 dict.__delitem__(self, key)
142 142 try:
143 143 del self._savedict[key]
144 144 except KeyError:
145 145 pass
146 146
147 147
148 148 def get_ipython():
149 149 # This will get replaced by the real thing once we start IPython below
150 150 return start_ipython()
151 151
152 152
153 153 # A couple of methods to override those in the running IPython to interact
154 154 # better with doctest (doctest captures on raw stdout, so we need to direct
155 155 # various types of output there otherwise it will miss them).
156 156
157 157 def xsys(self, cmd):
158 158 """Replace the default system call with a capturing one for doctest.
159 159 """
160 160 # We use getoutput, but we need to strip it because pexpect captures
161 161 # the trailing newline differently from commands.getoutput
162 162 print(self.getoutput(cmd, split=False).rstrip(), end='', file=sys.stdout)
163 163 sys.stdout.flush()
164 164
165 165
166 166 def _showtraceback(self, etype, evalue, stb):
167 167 """Print the traceback purely on stdout for doctest to capture it.
168 168 """
169 169 print(self.InteractiveTB.stb2text(stb), file=sys.stdout)
170 170
171 171
172 172 def start_ipython():
173 173 """Start a global IPython shell, which we need for IPython-specific syntax.
174 174 """
175 175 global get_ipython
176 176
177 177 # This function should only ever run once!
178 178 if hasattr(start_ipython, 'already_called'):
179 179 return
180 180 start_ipython.already_called = True
181 181
182 182 # Store certain global objects that IPython modifies
183 183 _displayhook = sys.displayhook
184 184 _excepthook = sys.excepthook
185 185 _main = sys.modules.get('__main__')
186 186
187 187 # Create custom argv and namespaces for our IPython to be test-friendly
188 188 config = tools.default_config()
189 189
190 190 # Create and initialize our test-friendly IPython instance.
191 191 shell = TerminalInteractiveShell.instance(config=config,
192 192 user_ns=ipnsdict(),
193 193 user_global_ns={}
194 194 )
195 195
196 196 # A few more tweaks needed for playing nicely with doctests...
197 197
198 198 # remove history file
199 199 shell.tempfiles.append(config.HistoryManager.hist_file)
200 200
201 201 # These traps are normally only active for interactive use, set them
202 202 # permanently since we'll be mocking interactive sessions.
203 203 shell.builtin_trap.activate()
204 204
205 205 # Modify the IPython system call with one that uses getoutput, so that we
206 206 # can capture subcommands and print them to Python's stdout, otherwise the
207 207 # doctest machinery would miss them.
208 208 shell.system = py3compat.MethodType(xsys, shell)
209 209
210 210
211 211 shell._showtraceback = py3compat.MethodType(_showtraceback, shell)
212 212
213 213 # IPython is ready, now clean up some global state...
214 214
215 215 # Deactivate the various python system hooks added by ipython for
216 216 # interactive convenience so we don't confuse the doctest system
217 217 sys.modules['__main__'] = _main
218 218 sys.displayhook = _displayhook
219 219 sys.excepthook = _excepthook
220 220
221 221 # So that ipython magics and aliases can be doctested (they work by making
222 222 # a call into a global _ip object). Also make the top-level get_ipython
223 223 # now return this without recursively calling here again.
224 224 _ip = shell
225 225 get_ipython = _ip.get_ipython
226 226 builtin_mod._ip = _ip
227 227 builtin_mod.get_ipython = get_ipython
228 228
229 229 # To avoid extra IPython messages during testing, suppress io.stdout/stderr
230 230 io.stdout = StreamProxy('stdout')
231 231 io.stderr = StreamProxy('stderr')
232 232
233 233 # Override paging, so we don't require user interaction during the tests.
234 234 def nopage(strng, start=0, screen_lines=0, pager_cmd=None):
235 235 print(strng)
236 236
237 237 page.orig_page = page.page
238 238 page.page = nopage
239 239
240 240 return _ip
@@ -1,476 +1,476 b''
1 1 # -*- coding: utf-8 -*-
2 2 """IPython Test Suite Runner.
3 3
4 4 This module provides a main entry point to a user script to test IPython
5 5 itself from the command line. There are two ways of running this script:
6 6
7 7 1. With the syntax `iptest all`. This runs our entire test suite by
8 8 calling this script (with different arguments) recursively. This
9 9 causes modules and package to be tested in different processes, using nose
10 10 or trial where appropriate.
11 11 2. With the regular nose syntax, like `iptest -vvs IPython`. In this form
12 12 the script simply calls nose, but with special command line flags and
13 13 plugins loaded.
14 14
15 15 """
16 16
17 17 #-----------------------------------------------------------------------------
18 # Copyright (C) 2009 The IPython Development Team
18 # Copyright (C) 2009-2011 The IPython Development Team
19 19 #
20 20 # Distributed under the terms of the BSD License. The full license is in
21 21 # the file COPYING, distributed as part of this software.
22 22 #-----------------------------------------------------------------------------
23 23
24 24 #-----------------------------------------------------------------------------
25 25 # Imports
26 26 #-----------------------------------------------------------------------------
27 27
28 28 # Stdlib
29 29 import os
30 30 import os.path as path
31 31 import signal
32 32 import sys
33 33 import subprocess
34 34 import tempfile
35 35 import time
36 36 import warnings
37 37
38 38 # Note: monkeypatch!
39 39 # We need to monkeypatch a small problem in nose itself first, before importing
40 40 # it for actual use. This should get into nose upstream, but its release cycle
41 41 # is slow and we need it for our parametric tests to work correctly.
42 42 from IPython.testing import nosepatch
43 43 # Now, proceed to import nose itself
44 44 import nose.plugins.builtin
45 45 from nose.core import TestProgram
46 46
47 47 # Our own imports
48 48 from IPython.utils.importstring import import_item
49 49 from IPython.utils.path import get_ipython_module_path
50 50 from IPython.utils.process import find_cmd, pycmd2argv
51 51 from IPython.utils.sysinfo import sys_info
52 52
53 53 from IPython.testing import globalipapp
54 54 from IPython.testing.plugin.ipdoctest import IPythonDoctest
55 55 from IPython.external.decorators import KnownFailure
56 56
57 57 pjoin = path.join
58 58
59 59
60 60 #-----------------------------------------------------------------------------
61 61 # Globals
62 62 #-----------------------------------------------------------------------------
63 63
64 64
65 65 #-----------------------------------------------------------------------------
66 66 # Warnings control
67 67 #-----------------------------------------------------------------------------
68 68
69 69 # Twisted generates annoying warnings with Python 2.6, as will do other code
70 70 # that imports 'sets' as of today
71 71 warnings.filterwarnings('ignore', 'the sets module is deprecated',
72 72 DeprecationWarning )
73 73
74 74 # This one also comes from Twisted
75 75 warnings.filterwarnings('ignore', 'the sha module is deprecated',
76 76 DeprecationWarning)
77 77
78 78 # Wx on Fedora11 spits these out
79 79 warnings.filterwarnings('ignore', 'wxPython/wxWidgets release number mismatch',
80 80 UserWarning)
81 81
82 82 #-----------------------------------------------------------------------------
83 83 # Logic for skipping doctests
84 84 #-----------------------------------------------------------------------------
85 85 def extract_version(mod):
86 86 return mod.__version__
87 87
88 88 def test_for(item, min_version=None, callback=extract_version):
89 89 """Test to see if item is importable, and optionally check against a minimum
90 90 version.
91 91
92 92 If min_version is given, the default behavior is to check against the
93 93 `__version__` attribute of the item, but specifying `callback` allows you to
94 94 extract the value you are interested in. e.g::
95 95
96 96 In [1]: import sys
97 97
98 98 In [2]: from IPython.testing.iptest import test_for
99 99
100 100 In [3]: test_for('sys', (2,6), callback=lambda sys: sys.version_info)
101 101 Out[3]: True
102 102
103 103 """
104 104 try:
105 105 check = import_item(item)
106 106 except (ImportError, RuntimeError):
107 107 # GTK reports Runtime error if it can't be initialized even if it's
108 108 # importable.
109 109 return False
110 110 else:
111 111 if min_version:
112 112 if callback:
113 113 # extra processing step to get version to compare
114 114 check = callback(check)
115 115
116 116 return check >= min_version
117 117 else:
118 118 return True
119 119
120 120 # Global dict where we can store information on what we have and what we don't
121 121 # have available at test run time
122 122 have = {}
123 123
124 124 have['curses'] = test_for('_curses')
125 125 have['matplotlib'] = test_for('matplotlib')
126 126 have['pexpect'] = test_for('IPython.external.pexpect')
127 127 have['pymongo'] = test_for('pymongo')
128 128 have['wx'] = test_for('wx')
129 129 have['wx.aui'] = test_for('wx.aui')
130 130 have['qt'] = test_for('IPython.external.qt')
131 131 have['sqlite3'] = test_for('sqlite3')
132 132
133 133 have['tornado'] = test_for('tornado.version_info', (2,1,0), callback=None)
134 134
135 135 if os.name == 'nt':
136 136 min_zmq = (2,1,7)
137 137 else:
138 138 min_zmq = (2,1,4)
139 139
140 140 def version_tuple(mod):
141 141 "turn '2.1.9' into (2,1,9), and '2.1dev' into (2,1,999)"
142 142 # turn 'dev' into 999, because Python3 rejects str-int comparisons
143 143 vs = mod.__version__.replace('dev', '.999')
144 144 tup = tuple([int(v) for v in vs.split('.') ])
145 145 return tup
146 146
147 147 have['zmq'] = test_for('zmq', min_zmq, version_tuple)
148 148
149 149 #-----------------------------------------------------------------------------
150 150 # Functions and classes
151 151 #-----------------------------------------------------------------------------
152 152
153 153 def report():
154 154 """Return a string with a summary report of test-related variables."""
155 155
156 156 out = [ sys_info(), '\n']
157 157
158 158 avail = []
159 159 not_avail = []
160 160
161 161 for k, is_avail in have.items():
162 162 if is_avail:
163 163 avail.append(k)
164 164 else:
165 165 not_avail.append(k)
166 166
167 167 if avail:
168 168 out.append('\nTools and libraries available at test time:\n')
169 169 avail.sort()
170 170 out.append(' ' + ' '.join(avail)+'\n')
171 171
172 172 if not_avail:
173 173 out.append('\nTools and libraries NOT available at test time:\n')
174 174 not_avail.sort()
175 175 out.append(' ' + ' '.join(not_avail)+'\n')
176 176
177 177 return ''.join(out)
178 178
179 179
180 180 def make_exclude():
181 181 """Make patterns of modules and packages to exclude from testing.
182 182
183 183 For the IPythonDoctest plugin, we need to exclude certain patterns that
184 184 cause testing problems. We should strive to minimize the number of
185 185 skipped modules, since this means untested code.
186 186
187 187 These modules and packages will NOT get scanned by nose at all for tests.
188 188 """
189 189 # Simple utility to make IPython paths more readably, we need a lot of
190 190 # these below
191 191 ipjoin = lambda *paths: pjoin('IPython', *paths)
192 192
193 193 exclusions = [ipjoin('external'),
194 194 pjoin('IPython_doctest_plugin'),
195 195 ipjoin('quarantine'),
196 196 ipjoin('deathrow'),
197 197 ipjoin('testing', 'attic'),
198 198 # This guy is probably attic material
199 199 ipjoin('testing', 'mkdoctests'),
200 200 # Testing inputhook will need a lot of thought, to figure out
201 201 # how to have tests that don't lock up with the gui event
202 202 # loops in the picture
203 203 ipjoin('lib', 'inputhook'),
204 204 # Config files aren't really importable stand-alone
205 205 ipjoin('config', 'default'),
206 206 ipjoin('config', 'profile'),
207 207 ]
208 208 if not have['sqlite3']:
209 209 exclusions.append(ipjoin('core', 'tests', 'test_history'))
210 210 exclusions.append(ipjoin('core', 'history'))
211 211 if not have['wx']:
212 212 exclusions.append(ipjoin('lib', 'inputhookwx'))
213 213
214 214 # We do this unconditionally, so that the test suite doesn't import
215 215 # gtk, changing the default encoding and masking some unicode bugs.
216 216 exclusions.append(ipjoin('lib', 'inputhookgtk'))
217 217
218 218 # These have to be skipped on win32 because the use echo, rm, cd, etc.
219 219 # See ticket https://github.com/ipython/ipython/issues/87
220 220 if sys.platform == 'win32':
221 221 exclusions.append(ipjoin('testing', 'plugin', 'test_exampleip'))
222 222 exclusions.append(ipjoin('testing', 'plugin', 'dtexample'))
223 223
224 224 if not have['pexpect']:
225 225 exclusions.extend([ipjoin('scripts', 'irunner'),
226 226 ipjoin('lib', 'irunner'),
227 227 ipjoin('lib', 'tests', 'test_irunner')])
228 228
229 229 if not have['zmq']:
230 230 exclusions.append(ipjoin('zmq'))
231 231 exclusions.append(ipjoin('frontend', 'qt'))
232 232 exclusions.append(ipjoin('parallel'))
233 233 elif not have['qt']:
234 234 exclusions.append(ipjoin('frontend', 'qt'))
235 235
236 236 if not have['pymongo']:
237 237 exclusions.append(ipjoin('parallel', 'controller', 'mongodb'))
238 238 exclusions.append(ipjoin('parallel', 'tests', 'test_mongodb'))
239 239
240 240 if not have['matplotlib']:
241 241 exclusions.extend([ipjoin('lib', 'pylabtools'),
242 242 ipjoin('lib', 'tests', 'test_pylabtools')])
243 243
244 244 if not have['tornado']:
245 245 exclusions.append(ipjoin('frontend', 'html'))
246 246
247 247 # This is needed for the reg-exp to match on win32 in the ipdoctest plugin.
248 248 if sys.platform == 'win32':
249 249 exclusions = [s.replace('\\','\\\\') for s in exclusions]
250 250
251 251 return exclusions
252 252
253 253
254 254 class IPTester(object):
255 255 """Call that calls iptest or trial in a subprocess.
256 256 """
257 257 #: string, name of test runner that will be called
258 258 runner = None
259 259 #: list, parameters for test runner
260 260 params = None
261 261 #: list, arguments of system call to be made to call test runner
262 262 call_args = None
263 263 #: list, process ids of subprocesses we start (for cleanup)
264 264 pids = None
265 265
266 266 def __init__(self, runner='iptest', params=None):
267 267 """Create new test runner."""
268 268 p = os.path
269 269 if runner == 'iptest':
270 270 iptest_app = get_ipython_module_path('IPython.testing.iptest')
271 271 self.runner = pycmd2argv(iptest_app) + sys.argv[1:]
272 272 else:
273 273 raise Exception('Not a valid test runner: %s' % repr(runner))
274 274 if params is None:
275 275 params = []
276 276 if isinstance(params, str):
277 277 params = [params]
278 278 self.params = params
279 279
280 280 # Assemble call
281 281 self.call_args = self.runner+self.params
282 282
283 283 # Store pids of anything we start to clean up on deletion, if possible
284 284 # (on posix only, since win32 has no os.kill)
285 285 self.pids = []
286 286
287 287 if sys.platform == 'win32':
288 288 def _run_cmd(self):
289 289 # On Windows, use os.system instead of subprocess.call, because I
290 290 # was having problems with subprocess and I just don't know enough
291 291 # about win32 to debug this reliably. Os.system may be the 'old
292 292 # fashioned' way to do it, but it works just fine. If someone
293 293 # later can clean this up that's fine, as long as the tests run
294 294 # reliably in win32.
295 295 # What types of problems are you having. They may be related to
296 296 # running Python in unboffered mode. BG.
297 297 return os.system(' '.join(self.call_args))
298 298 else:
299 299 def _run_cmd(self):
300 300 # print >> sys.stderr, '*** CMD:', ' '.join(self.call_args) # dbg
301 301 subp = subprocess.Popen(self.call_args)
302 302 self.pids.append(subp.pid)
303 303 # If this fails, the pid will be left in self.pids and cleaned up
304 304 # later, but if the wait call succeeds, then we can clear the
305 305 # stored pid.
306 306 retcode = subp.wait()
307 307 self.pids.pop()
308 308 return retcode
309 309
310 310 def run(self):
311 311 """Run the stored commands"""
312 312 try:
313 313 return self._run_cmd()
314 314 except:
315 315 import traceback
316 316 traceback.print_exc()
317 317 return 1 # signal failure
318 318
319 319 def __del__(self):
320 320 """Cleanup on exit by killing any leftover processes."""
321 321
322 322 if not hasattr(os, 'kill'):
323 323 return
324 324
325 325 for pid in self.pids:
326 326 try:
327 327 print 'Cleaning stale PID:', pid
328 328 os.kill(pid, signal.SIGKILL)
329 329 except OSError:
330 330 # This is just a best effort, if we fail or the process was
331 331 # really gone, ignore it.
332 332 pass
333 333
334 334
335 335 def make_runners():
336 336 """Define the top-level packages that need to be tested.
337 337 """
338 338
339 339 # Packages to be tested via nose, that only depend on the stdlib
340 340 nose_pkg_names = ['config', 'core', 'extensions', 'frontend', 'lib',
341 341 'scripts', 'testing', 'utils', 'nbformat' ]
342 342
343 343 if have['zmq']:
344 344 nose_pkg_names.append('parallel')
345 345
346 346 # For debugging this code, only load quick stuff
347 347 #nose_pkg_names = ['core', 'extensions'] # dbg
348 348
349 349 # Make fully qualified package names prepending 'IPython.' to our name lists
350 350 nose_packages = ['IPython.%s' % m for m in nose_pkg_names ]
351 351
352 352 # Make runners
353 353 runners = [ (v, IPTester('iptest', params=v)) for v in nose_packages ]
354 354
355 355 return runners
356 356
357 357
358 358 def run_iptest():
359 359 """Run the IPython test suite using nose.
360 360
361 361 This function is called when this script is **not** called with the form
362 362 `iptest all`. It simply calls nose with appropriate command line flags
363 363 and accepts all of the standard nose arguments.
364 364 """
365 365
366 366 warnings.filterwarnings('ignore',
367 367 'This will be removed soon. Use IPython.testing.util instead')
368 368
369 369 argv = sys.argv + [ '--detailed-errors', # extra info in tracebacks
370 370
371 371 # Loading ipdoctest causes problems with Twisted, but
372 372 # our test suite runner now separates things and runs
373 373 # all Twisted tests with trial.
374 374 '--with-ipdoctest',
375 375 '--ipdoctest-tests','--ipdoctest-extension=txt',
376 376
377 377 # We add --exe because of setuptools' imbecility (it
378 378 # blindly does chmod +x on ALL files). Nose does the
379 379 # right thing and it tries to avoid executables,
380 380 # setuptools unfortunately forces our hand here. This
381 381 # has been discussed on the distutils list and the
382 382 # setuptools devs refuse to fix this problem!
383 383 '--exe',
384 384 ]
385 385
386 386 if nose.__version__ >= '0.11':
387 387 # I don't fully understand why we need this one, but depending on what
388 388 # directory the test suite is run from, if we don't give it, 0 tests
389 389 # get run. Specifically, if the test suite is run from the source dir
390 390 # with an argument (like 'iptest.py IPython.core', 0 tests are run,
391 391 # even if the same call done in this directory works fine). It appears
392 392 # that if the requested package is in the current dir, nose bails early
393 393 # by default. Since it's otherwise harmless, leave it in by default
394 394 # for nose >= 0.11, though unfortunately nose 0.10 doesn't support it.
395 395 argv.append('--traverse-namespace')
396 396
397 397 # use our plugin for doctesting. It will remove the standard doctest plugin
398 398 # if it finds it enabled
399 399 plugins = [IPythonDoctest(make_exclude()), KnownFailure()]
400 400 # We need a global ipython running in this process
401 401 globalipapp.start_ipython()
402 402 # Now nose can run
403 403 TestProgram(argv=argv, addplugins=plugins)
404 404
405 405
406 406 def run_iptestall():
407 407 """Run the entire IPython test suite by calling nose and trial.
408 408
409 409 This function constructs :class:`IPTester` instances for all IPython
410 410 modules and package and then runs each of them. This causes the modules
411 411 and packages of IPython to be tested each in their own subprocess using
412 412 nose or twisted.trial appropriately.
413 413 """
414 414
415 415 runners = make_runners()
416 416
417 417 # Run the test runners in a temporary dir so we can nuke it when finished
418 418 # to clean up any junk files left over by accident. This also makes it
419 419 # robust against being run in non-writeable directories by mistake, as the
420 420 # temp dir will always be user-writeable.
421 421 curdir = os.getcwdu()
422 422 testdir = tempfile.gettempdir()
423 423 os.chdir(testdir)
424 424
425 425 # Run all test runners, tracking execution time
426 426 failed = []
427 427 t_start = time.time()
428 428 try:
429 429 for (name, runner) in runners:
430 430 print '*'*70
431 431 print 'IPython test group:',name
432 432 res = runner.run()
433 433 if res:
434 434 failed.append( (name, runner) )
435 435 finally:
436 436 os.chdir(curdir)
437 437 t_end = time.time()
438 438 t_tests = t_end - t_start
439 439 nrunners = len(runners)
440 440 nfail = len(failed)
441 441 # summarize results
442 442 print
443 443 print '*'*70
444 444 print 'Test suite completed for system with the following information:'
445 445 print report()
446 446 print 'Ran %s test groups in %.3fs' % (nrunners, t_tests)
447 447 print
448 448 print 'Status:'
449 449 if not failed:
450 450 print 'OK'
451 451 else:
452 452 # If anything went wrong, point out what command to rerun manually to
453 453 # see the actual errors and individual summary
454 454 print 'ERROR - %s out of %s test groups failed.' % (nfail, nrunners)
455 455 for name, failed_runner in failed:
456 456 print '-'*40
457 457 print 'Runner failed:',name
458 458 print 'You may wish to rerun this one individually, with:'
459 459 print ' '.join(failed_runner.call_args)
460 460 print
461 461 # Ensure that our exit code indicates failure
462 462 sys.exit(1)
463 463
464 464
465 465 def main():
466 466 for arg in sys.argv[1:]:
467 467 if arg.startswith('IPython'):
468 468 # This is in-process
469 469 run_iptest()
470 470 else:
471 471 # This starts subprocesses
472 472 run_iptestall()
473 473
474 474
475 475 if __name__ == '__main__':
476 476 main()
@@ -1,184 +1,184 b''
1 1 """Experimental code for cleaner support of IPython syntax with unittest.
2 2
3 3 In IPython up until 0.10, we've used very hacked up nose machinery for running
4 4 tests with IPython special syntax, and this has proved to be extremely slow.
5 5 This module provides decorators to try a different approach, stemming from a
6 6 conversation Brian and I (FP) had about this problem Sept/09.
7 7
8 8 The goal is to be able to easily write simple functions that can be seen by
9 9 unittest as tests, and ultimately for these to support doctests with full
10 10 IPython syntax. Nose already offers this based on naming conventions and our
11 11 hackish plugins, but we are seeking to move away from nose dependencies if
12 12 possible.
13 13
14 14 This module follows a different approach, based on decorators.
15 15
16 16 - A decorator called @ipdoctest can mark any function as having a docstring
17 17 that should be viewed as a doctest, but after syntax conversion.
18 18
19 19 Authors
20 20 -------
21 21
22 22 - Fernando Perez <Fernando.Perez@berkeley.edu>
23 23 """
24 24
25 25 from __future__ import absolute_import
26 26
27 27 #-----------------------------------------------------------------------------
28 # Copyright (C) 2009 The IPython Development Team
28 # Copyright (C) 2009-2011 The IPython Development Team
29 29 #
30 30 # Distributed under the terms of the BSD License. The full license is in
31 31 # the file COPYING, distributed as part of this software.
32 32 #-----------------------------------------------------------------------------
33 33
34 34 #-----------------------------------------------------------------------------
35 35 # Imports
36 36 #-----------------------------------------------------------------------------
37 37
38 38 # Stdlib
39 39 import re
40 40 import sys
41 41 import unittest
42 42 from doctest import DocTestFinder, DocTestRunner, TestResults
43 43
44 44 # We already have python3-compliant code for parametric tests
45 45 if sys.version[0]=='2':
46 46 from ._paramtestpy2 import ParametricTestCase
47 47 else:
48 48 from ._paramtestpy3 import ParametricTestCase
49 49
50 50 #-----------------------------------------------------------------------------
51 51 # Classes and functions
52 52 #-----------------------------------------------------------------------------
53 53
54 54 def count_failures(runner):
55 55 """Count number of failures in a doctest runner.
56 56
57 57 Code modeled after the summarize() method in doctest.
58 58 """
59 59 return [TestResults(f, t) for f, t in runner._name2ft.values() if f > 0 ]
60 60
61 61
62 62 class IPython2PythonConverter(object):
63 63 """Convert IPython 'syntax' to valid Python.
64 64
65 65 Eventually this code may grow to be the full IPython syntax conversion
66 66 implementation, but for now it only does prompt convertion."""
67 67
68 68 def __init__(self):
69 69 self.rps1 = re.compile(r'In\ \[\d+\]: ')
70 70 self.rps2 = re.compile(r'\ \ \ \.\.\.+: ')
71 71 self.rout = re.compile(r'Out\[\d+\]: \s*?\n?')
72 72 self.pyps1 = '>>> '
73 73 self.pyps2 = '... '
74 74 self.rpyps1 = re.compile ('(\s*%s)(.*)$' % self.pyps1)
75 75 self.rpyps2 = re.compile ('(\s*%s)(.*)$' % self.pyps2)
76 76
77 77 def __call__(self, ds):
78 78 """Convert IPython prompts to python ones in a string."""
79 79 from . import globalipapp
80 80
81 81 pyps1 = '>>> '
82 82 pyps2 = '... '
83 83 pyout = ''
84 84
85 85 dnew = ds
86 86 dnew = self.rps1.sub(pyps1, dnew)
87 87 dnew = self.rps2.sub(pyps2, dnew)
88 88 dnew = self.rout.sub(pyout, dnew)
89 89 ip = globalipapp.get_ipython()
90 90
91 91 # Convert input IPython source into valid Python.
92 92 out = []
93 93 newline = out.append
94 94 for line in dnew.splitlines():
95 95
96 96 mps1 = self.rpyps1.match(line)
97 97 if mps1 is not None:
98 98 prompt, text = mps1.groups()
99 99 newline(prompt+ip.prefilter(text, False))
100 100 continue
101 101
102 102 mps2 = self.rpyps2.match(line)
103 103 if mps2 is not None:
104 104 prompt, text = mps2.groups()
105 105 newline(prompt+ip.prefilter(text, True))
106 106 continue
107 107
108 108 newline(line)
109 109 newline('') # ensure a closing newline, needed by doctest
110 110 #print "PYSRC:", '\n'.join(out) # dbg
111 111 return '\n'.join(out)
112 112
113 113 #return dnew
114 114
115 115
116 116 class Doc2UnitTester(object):
117 117 """Class whose instances act as a decorator for docstring testing.
118 118
119 119 In practice we're only likely to need one instance ever, made below (though
120 120 no attempt is made at turning it into a singleton, there is no need for
121 121 that).
122 122 """
123 123 def __init__(self, verbose=False):
124 124 """New decorator.
125 125
126 126 Parameters
127 127 ----------
128 128
129 129 verbose : boolean, optional (False)
130 130 Passed to the doctest finder and runner to control verbosity.
131 131 """
132 132 self.verbose = verbose
133 133 # We can reuse the same finder for all instances
134 134 self.finder = DocTestFinder(verbose=verbose, recurse=False)
135 135
136 136 def __call__(self, func):
137 137 """Use as a decorator: doctest a function's docstring as a unittest.
138 138
139 139 This version runs normal doctests, but the idea is to make it later run
140 140 ipython syntax instead."""
141 141
142 142 # Capture the enclosing instance with a different name, so the new
143 143 # class below can see it without confusion regarding its own 'self'
144 144 # that will point to the test instance at runtime
145 145 d2u = self
146 146
147 147 # Rewrite the function's docstring to have python syntax
148 148 if func.__doc__ is not None:
149 149 func.__doc__ = ip2py(func.__doc__)
150 150
151 151 # Now, create a tester object that is a real unittest instance, so
152 152 # normal unittest machinery (or Nose, or Trial) can find it.
153 153 class Tester(unittest.TestCase):
154 154 def test(self):
155 155 # Make a new runner per function to be tested
156 156 runner = DocTestRunner(verbose=d2u.verbose)
157 157 map(runner.run, d2u.finder.find(func, func.__name__))
158 158 failed = count_failures(runner)
159 159 if failed:
160 160 # Since we only looked at a single function's docstring,
161 161 # failed should contain at most one item. More than that
162 162 # is a case we can't handle and should error out on
163 163 if len(failed) > 1:
164 164 err = "Invalid number of test results:" % failed
165 165 raise ValueError(err)
166 166 # Report a normal failure.
167 167 self.fail('failed doctests: %s' % str(failed[0]))
168 168
169 169 # Rename it so test reports have the original signature.
170 170 Tester.__name__ = func.__name__
171 171 return Tester
172 172
173 173
174 174 def ipdocstring(func):
175 175 """Change the function docstring via ip2py.
176 176 """
177 177 if func.__doc__ is not None:
178 178 func.__doc__ = ip2py(func.__doc__)
179 179 return func
180 180
181 181
182 182 # Make an instance of the classes for public use
183 183 ipdoctest = Doc2UnitTester()
184 184 ip2py = IPython2PythonConverter()
@@ -1,71 +1,71 b''
1 1 """Monkeypatch nose to accept any callable as a method.
2 2
3 3 By default, nose's ismethod() fails for static methods.
4 4 Once this is fixed in upstream nose we can disable it.
5 5
6 6 Note: merely importing this module causes the monkeypatch to be applied."""
7 7
8 8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2009 The IPython Development Team
9 # Copyright (C) 2009-2011 The IPython Development Team
10 10 #
11 11 # Distributed under the terms of the BSD License. The full license is in
12 12 # the file COPYING, distributed as part of this software.
13 13 #-----------------------------------------------------------------------------
14 14
15 15 #-----------------------------------------------------------------------------
16 16 # Imports
17 17 #-----------------------------------------------------------------------------
18 18
19 19 import unittest
20 20 import sys
21 21 import nose.loader
22 22 from inspect import ismethod, isfunction
23 23
24 24 #-----------------------------------------------------------------------------
25 25 # Classes and functions
26 26 #-----------------------------------------------------------------------------
27 27
28 28 def getTestCaseNames(self, testCaseClass):
29 29 """Override to select with selector, unless
30 30 config.getTestCaseNamesCompat is True
31 31 """
32 32 if self.config.getTestCaseNamesCompat:
33 33 return unittest.TestLoader.getTestCaseNames(self, testCaseClass)
34 34
35 35 def wanted(attr, cls=testCaseClass, sel=self.selector):
36 36 item = getattr(cls, attr, None)
37 37 # MONKEYPATCH: replace this:
38 38 #if not ismethod(item):
39 39 # return False
40 40 # return sel.wantMethod(item)
41 41 # With:
42 42 if ismethod(item):
43 43 return sel.wantMethod(item)
44 44 # static method or something. If this is a static method, we
45 45 # can't get the class information, and we have to treat it
46 46 # as a function. Thus, we will miss things like class
47 47 # attributes for test selection
48 48 if isfunction(item):
49 49 return sel.wantFunction(item)
50 50 return False
51 51 # END MONKEYPATCH
52 52
53 53 cases = filter(wanted, dir(testCaseClass))
54 54 for base in testCaseClass.__bases__:
55 55 for case in self.getTestCaseNames(base):
56 56 if case not in cases:
57 57 cases.append(case)
58 58 # add runTest if nothing else picked
59 59 if not cases and hasattr(testCaseClass, 'runTest'):
60 60 cases = ['runTest']
61 61 if self.sortTestMethodsUsing:
62 62 cases.sort(self.sortTestMethodsUsing)
63 63 return cases
64 64
65 65
66 66 ##########################################################################
67 67 # Apply monkeypatch here
68 68 # Python 3 must be running with newer version of Nose, so don't touch anything.
69 69 if sys.version_info[0] < 3:
70 70 nose.loader.TestLoader.getTestCaseNames = getTestCaseNames
71 71 ##########################################################################
@@ -1,137 +1,137 b''
1 1 """Tests for IPython's test support utilities.
2 2
3 3 These are decorators that allow standalone functions and docstrings to be seen
4 4 as tests by unittest, replicating some of nose's functionality. Additionally,
5 5 IPython-syntax docstrings can be auto-converted to '>>>' so that ipython
6 6 sessions can be copy-pasted as tests.
7 7
8 8 This file can be run as a script, and it will call unittest.main(). We must
9 9 check that it works with unittest as well as with nose...
10 10
11 11
12 12 Notes:
13 13
14 14 - Using nosetests --with-doctest --doctest-tests testfile.py
15 15 will find docstrings as tests wherever they are, even in methods. But
16 16 if we use ipython syntax in the docstrings, they must be decorated with
17 17 @ipdocstring. This is OK for test-only code, but not for user-facing
18 18 docstrings where we want to keep the ipython syntax.
19 19
20 20 - Using nosetests --with-doctest file.py
21 21 also finds doctests if the file name doesn't have 'test' in it, because it is
22 22 treated like a normal module. But if nose treats the file like a test file,
23 23 then for normal classes to be doctested the extra --doctest-tests is
24 24 necessary.
25 25
26 26 - running this script with python (it has a __main__ section at the end) misses
27 27 one docstring test, the one embedded in the Foo object method. Since our
28 28 approach relies on using decorators that create standalone TestCase
29 29 instances, it can only be used for functions, not for methods of objects.
30 30 Authors
31 31 -------
32 32
33 33 - Fernando Perez <Fernando.Perez@berkeley.edu>
34 34 """
35 35
36 36 #-----------------------------------------------------------------------------
37 # Copyright (C) 2009 The IPython Development Team
37 # Copyright (C) 2009-2011 The IPython Development Team
38 38 #
39 39 # Distributed under the terms of the BSD License. The full license is in
40 40 # the file COPYING, distributed as part of this software.
41 41 #-----------------------------------------------------------------------------
42 42
43 43
44 44 #-----------------------------------------------------------------------------
45 45 # Imports
46 46 #-----------------------------------------------------------------------------
47 47
48 48 from IPython.testing.ipunittest import ipdoctest, ipdocstring
49 49 from IPython.utils.py3compat import doctest_refactor_print
50 50
51 51 #-----------------------------------------------------------------------------
52 52 # Test classes and functions
53 53 #-----------------------------------------------------------------------------
54 54 @ipdoctest
55 55 @doctest_refactor_print
56 56 def simple_dt():
57 57 """
58 58 >>> print 1+1
59 59 2
60 60 """
61 61
62 62
63 63 @ipdoctest
64 64 @doctest_refactor_print
65 65 def ipdt_flush():
66 66 """
67 67 In [20]: print 1
68 68 1
69 69
70 70 In [26]: for i in range(4):
71 71 ....: print i
72 72 ....:
73 73 ....:
74 74 0
75 75 1
76 76 2
77 77 3
78 78
79 79 In [27]: 3+4
80 80 Out[27]: 7
81 81 """
82 82
83 83
84 84 @ipdoctest
85 85 @doctest_refactor_print
86 86 def ipdt_indented_test():
87 87 """
88 88 In [20]: print 1
89 89 1
90 90
91 91 In [26]: for i in range(4):
92 92 ....: print i
93 93 ....:
94 94 ....:
95 95 0
96 96 1
97 97 2
98 98 3
99 99
100 100 In [27]: 3+4
101 101 Out[27]: 7
102 102 """
103 103
104 104
105 105 class Foo(object):
106 106 """For methods, the normal decorator doesn't work.
107 107
108 108 But rewriting the docstring with ip2py does, *but only if using nose
109 109 --with-doctest*. Do we want to have that as a dependency?
110 110 """
111 111
112 112 @ipdocstring
113 113 @doctest_refactor_print
114 114 def ipdt_method(self):
115 115 """
116 116 In [20]: print 1
117 117 1
118 118
119 119 In [26]: for i in range(4):
120 120 ....: print i
121 121 ....:
122 122 ....:
123 123 0
124 124 1
125 125 2
126 126 3
127 127
128 128 In [27]: 3+4
129 129 Out[27]: 7
130 130 """
131 131
132 132 @doctest_refactor_print
133 133 def normaldt_method(self):
134 134 """
135 135 >>> print 1+1
136 136 2
137 137 """
@@ -1,90 +1,90 b''
1 1 # encoding: utf-8
2 2 """
3 3 Tests for testing.tools
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2009 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16 from __future__ import with_statement
17 17
18 18 import os
19 19 import sys
20 20 import unittest
21 21
22 22 import nose.tools as nt
23 23
24 24 from IPython.testing import decorators as dec
25 25 from IPython.testing import tools as tt
26 26
27 27 #-----------------------------------------------------------------------------
28 28 # Tests
29 29 #-----------------------------------------------------------------------------
30 30
31 31 @dec.skip_win32
32 32 def test_full_path_posix():
33 33 spath = '/foo/bar.py'
34 34 result = tt.full_path(spath,['a.txt','b.txt'])
35 35 nt.assert_equal(result, ['/foo/a.txt', '/foo/b.txt'])
36 36 spath = '/foo'
37 37 result = tt.full_path(spath,['a.txt','b.txt'])
38 38 nt.assert_equal(result, ['/a.txt', '/b.txt'])
39 39 result = tt.full_path(spath,'a.txt')
40 40 nt.assert_equal(result, ['/a.txt'])
41 41
42 42
43 43 @dec.skip_if_not_win32
44 44 def test_full_path_win32():
45 45 spath = 'c:\\foo\\bar.py'
46 46 result = tt.full_path(spath,['a.txt','b.txt'])
47 47 nt.assert_equal(result, ['c:\\foo\\a.txt', 'c:\\foo\\b.txt'])
48 48 spath = 'c:\\foo'
49 49 result = tt.full_path(spath,['a.txt','b.txt'])
50 50 nt.assert_equal(result, ['c:\\a.txt', 'c:\\b.txt'])
51 51 result = tt.full_path(spath,'a.txt')
52 52 nt.assert_equal(result, ['c:\\a.txt'])
53 53
54 54
55 55 @dec.parametric
56 56 def test_parser():
57 57 err = ("FAILED (errors=1)", 1, 0)
58 58 fail = ("FAILED (failures=1)", 0, 1)
59 59 both = ("FAILED (errors=1, failures=1)", 1, 1)
60 60 for txt, nerr, nfail in [err, fail, both]:
61 61 nerr1, nfail1 = tt.parse_test_output(txt)
62 62 yield nt.assert_equal(nerr, nerr1)
63 63 yield nt.assert_equal(nfail, nfail1)
64 64
65 65
66 66 @dec.parametric
67 67 def test_temp_pyfile():
68 68 src = 'pass\n'
69 69 fname, fh = tt.temp_pyfile(src)
70 70 yield nt.assert_true(os.path.isfile(fname))
71 71 fh.close()
72 72 with open(fname) as fh2:
73 73 src2 = fh2.read()
74 74 yield nt.assert_equal(src2, src)
75 75
76 76 class TestAssertPrints(unittest.TestCase):
77 77 def test_passing(self):
78 78 with tt.AssertPrints("abc"):
79 79 print "abcd"
80 80 print "def"
81 81 print b"ghi"
82 82
83 83 def test_failing(self):
84 84 def func():
85 85 with tt.AssertPrints("abc"):
86 86 print "acd"
87 87 print "def"
88 88 print b"ghi"
89 89
90 90 self.assertRaises(AssertionError, func)
@@ -1,402 +1,402 b''
1 1 """Generic testing tools that do NOT depend on Twisted.
2 2
3 3 In particular, this module exposes a set of top-level assert* functions that
4 4 can be used in place of nose.tools.assert* in method generators (the ones in
5 5 nose can not, at least as of nose 0.10.4).
6 6
7 7 Note: our testing package contains testing.util, which does depend on Twisted
8 8 and provides utilities for tests that manage Deferreds. All testing support
9 9 tools that only depend on nose, IPython or the standard library should go here
10 10 instead.
11 11
12 12
13 13 Authors
14 14 -------
15 15 - Fernando Perez <Fernando.Perez@berkeley.edu>
16 16 """
17 17
18 18 from __future__ import absolute_import
19 19
20 20 #-----------------------------------------------------------------------------
21 # Copyright (C) 2009 The IPython Development Team
21 # Copyright (C) 2009-2011 The IPython Development Team
22 22 #
23 23 # Distributed under the terms of the BSD License. The full license is in
24 24 # the file COPYING, distributed as part of this software.
25 25 #-----------------------------------------------------------------------------
26 26
27 27 #-----------------------------------------------------------------------------
28 28 # Imports
29 29 #-----------------------------------------------------------------------------
30 30
31 31 import os
32 32 import re
33 33 import sys
34 34 import tempfile
35 35
36 36 from contextlib import contextmanager
37 37 from io import StringIO
38 38
39 39 try:
40 40 # These tools are used by parts of the runtime, so we make the nose
41 41 # dependency optional at this point. Nose is a hard dependency to run the
42 42 # test suite, but NOT to use ipython itself.
43 43 import nose.tools as nt
44 44 has_nose = True
45 45 except ImportError:
46 46 has_nose = False
47 47
48 48 from IPython.config.loader import Config
49 49 from IPython.utils.process import find_cmd, getoutputerror
50 50 from IPython.utils.text import list_strings, getdefaultencoding
51 51 from IPython.utils.io import temp_pyfile, Tee
52 52 from IPython.utils import py3compat
53 53
54 54 from . import decorators as dec
55 55 from . import skipdoctest
56 56
57 57 #-----------------------------------------------------------------------------
58 58 # Globals
59 59 #-----------------------------------------------------------------------------
60 60
61 61 # Make a bunch of nose.tools assert wrappers that can be used in test
62 62 # generators. This will expose an assert* function for each one in nose.tools.
63 63
64 64 _tpl = """
65 65 def %(name)s(*a,**kw):
66 66 return nt.%(name)s(*a,**kw)
67 67 """
68 68
69 69 if has_nose:
70 70 for _x in [a for a in dir(nt) if a.startswith('assert')]:
71 71 exec _tpl % dict(name=_x)
72 72
73 73 #-----------------------------------------------------------------------------
74 74 # Functions and classes
75 75 #-----------------------------------------------------------------------------
76 76
77 77 # The docstring for full_path doctests differently on win32 (different path
78 78 # separator) so just skip the doctest there. The example remains informative.
79 79 doctest_deco = skipdoctest.skip_doctest if sys.platform == 'win32' else dec.null_deco
80 80
81 81 @doctest_deco
82 82 def full_path(startPath,files):
83 83 """Make full paths for all the listed files, based on startPath.
84 84
85 85 Only the base part of startPath is kept, since this routine is typically
86 86 used with a script's __file__ variable as startPath. The base of startPath
87 87 is then prepended to all the listed files, forming the output list.
88 88
89 89 Parameters
90 90 ----------
91 91 startPath : string
92 92 Initial path to use as the base for the results. This path is split
93 93 using os.path.split() and only its first component is kept.
94 94
95 95 files : string or list
96 96 One or more files.
97 97
98 98 Examples
99 99 --------
100 100
101 101 >>> full_path('/foo/bar.py',['a.txt','b.txt'])
102 102 ['/foo/a.txt', '/foo/b.txt']
103 103
104 104 >>> full_path('/foo',['a.txt','b.txt'])
105 105 ['/a.txt', '/b.txt']
106 106
107 107 If a single file is given, the output is still a list:
108 108 >>> full_path('/foo','a.txt')
109 109 ['/a.txt']
110 110 """
111 111
112 112 files = list_strings(files)
113 113 base = os.path.split(startPath)[0]
114 114 return [ os.path.join(base,f) for f in files ]
115 115
116 116
117 117 def parse_test_output(txt):
118 118 """Parse the output of a test run and return errors, failures.
119 119
120 120 Parameters
121 121 ----------
122 122 txt : str
123 123 Text output of a test run, assumed to contain a line of one of the
124 124 following forms::
125 125 'FAILED (errors=1)'
126 126 'FAILED (failures=1)'
127 127 'FAILED (errors=1, failures=1)'
128 128
129 129 Returns
130 130 -------
131 131 nerr, nfail: number of errors and failures.
132 132 """
133 133
134 134 err_m = re.search(r'^FAILED \(errors=(\d+)\)', txt, re.MULTILINE)
135 135 if err_m:
136 136 nerr = int(err_m.group(1))
137 137 nfail = 0
138 138 return nerr, nfail
139 139
140 140 fail_m = re.search(r'^FAILED \(failures=(\d+)\)', txt, re.MULTILINE)
141 141 if fail_m:
142 142 nerr = 0
143 143 nfail = int(fail_m.group(1))
144 144 return nerr, nfail
145 145
146 146 both_m = re.search(r'^FAILED \(errors=(\d+), failures=(\d+)\)', txt,
147 147 re.MULTILINE)
148 148 if both_m:
149 149 nerr = int(both_m.group(1))
150 150 nfail = int(both_m.group(2))
151 151 return nerr, nfail
152 152
153 153 # If the input didn't match any of these forms, assume no error/failures
154 154 return 0, 0
155 155
156 156
157 157 # So nose doesn't think this is a test
158 158 parse_test_output.__test__ = False
159 159
160 160
161 161 def default_argv():
162 162 """Return a valid default argv for creating testing instances of ipython"""
163 163
164 164 return ['--quick', # so no config file is loaded
165 165 # Other defaults to minimize side effects on stdout
166 166 '--colors=NoColor', '--no-term-title','--no-banner',
167 167 '--autocall=0']
168 168
169 169
170 170 def default_config():
171 171 """Return a config object with good defaults for testing."""
172 172 config = Config()
173 173 config.TerminalInteractiveShell.colors = 'NoColor'
174 174 config.TerminalTerminalInteractiveShell.term_title = False,
175 175 config.TerminalInteractiveShell.autocall = 0
176 176 config.HistoryManager.hist_file = tempfile.mktemp(u'test_hist.sqlite')
177 177 config.HistoryManager.db_cache_size = 10000
178 178 return config
179 179
180 180
181 181 def ipexec(fname, options=None):
182 182 """Utility to call 'ipython filename'.
183 183
184 184 Starts IPython witha minimal and safe configuration to make startup as fast
185 185 as possible.
186 186
187 187 Note that this starts IPython in a subprocess!
188 188
189 189 Parameters
190 190 ----------
191 191 fname : str
192 192 Name of file to be executed (should have .py or .ipy extension).
193 193
194 194 options : optional, list
195 195 Extra command-line flags to be passed to IPython.
196 196
197 197 Returns
198 198 -------
199 199 (stdout, stderr) of ipython subprocess.
200 200 """
201 201 if options is None: options = []
202 202
203 203 # For these subprocess calls, eliminate all prompt printing so we only see
204 204 # output from script execution
205 205 prompt_opts = [ '--InteractiveShell.prompt_in1=""',
206 206 '--InteractiveShell.prompt_in2=""',
207 207 '--InteractiveShell.prompt_out=""'
208 208 ]
209 209 cmdargs = ' '.join(default_argv() + prompt_opts + options)
210 210
211 211 _ip = get_ipython()
212 212 test_dir = os.path.dirname(__file__)
213 213
214 214 ipython_cmd = find_cmd('ipython3' if py3compat.PY3 else 'ipython')
215 215 # Absolute path for filename
216 216 full_fname = os.path.join(test_dir, fname)
217 217 full_cmd = '%s %s %s' % (ipython_cmd, cmdargs, full_fname)
218 218 #print >> sys.stderr, 'FULL CMD:', full_cmd # dbg
219 219 out = getoutputerror(full_cmd)
220 220 # `import readline` causes 'ESC[?1034h' to be the first output sometimes,
221 221 # so strip that off the front of the first line if it is found
222 222 if out:
223 223 first = out[0]
224 224 m = re.match(r'\x1b\[[^h]+h', first)
225 225 if m:
226 226 # strip initial readline escape
227 227 out = list(out)
228 228 out[0] = first[len(m.group()):]
229 229 out = tuple(out)
230 230 return out
231 231
232 232
233 233 def ipexec_validate(fname, expected_out, expected_err='',
234 234 options=None):
235 235 """Utility to call 'ipython filename' and validate output/error.
236 236
237 237 This function raises an AssertionError if the validation fails.
238 238
239 239 Note that this starts IPython in a subprocess!
240 240
241 241 Parameters
242 242 ----------
243 243 fname : str
244 244 Name of the file to be executed (should have .py or .ipy extension).
245 245
246 246 expected_out : str
247 247 Expected stdout of the process.
248 248
249 249 expected_err : optional, str
250 250 Expected stderr of the process.
251 251
252 252 options : optional, list
253 253 Extra command-line flags to be passed to IPython.
254 254
255 255 Returns
256 256 -------
257 257 None
258 258 """
259 259
260 260 import nose.tools as nt
261 261
262 262 out, err = ipexec(fname, options)
263 263 #print 'OUT', out # dbg
264 264 #print 'ERR', err # dbg
265 265 # If there are any errors, we must check those befor stdout, as they may be
266 266 # more informative than simply having an empty stdout.
267 267 if err:
268 268 if expected_err:
269 269 nt.assert_equals(err.strip(), expected_err.strip())
270 270 else:
271 271 raise ValueError('Running file %r produced error: %r' %
272 272 (fname, err))
273 273 # If no errors or output on stderr was expected, match stdout
274 274 nt.assert_equals(out.strip(), expected_out.strip())
275 275
276 276
277 277 class TempFileMixin(object):
278 278 """Utility class to create temporary Python/IPython files.
279 279
280 280 Meant as a mixin class for test cases."""
281 281
282 282 def mktmp(self, src, ext='.py'):
283 283 """Make a valid python temp file."""
284 284 fname, f = temp_pyfile(src, ext)
285 285 self.tmpfile = f
286 286 self.fname = fname
287 287
288 288 def tearDown(self):
289 289 if hasattr(self, 'tmpfile'):
290 290 # If the tmpfile wasn't made because of skipped tests, like in
291 291 # win32, there's nothing to cleanup.
292 292 self.tmpfile.close()
293 293 try:
294 294 os.unlink(self.fname)
295 295 except:
296 296 # On Windows, even though we close the file, we still can't
297 297 # delete it. I have no clue why
298 298 pass
299 299
300 300 pair_fail_msg = ("Testing {0}\n\n"
301 301 "In:\n"
302 302 " {1!r}\n"
303 303 "Expected:\n"
304 304 " {2!r}\n"
305 305 "Got:\n"
306 306 " {3!r}\n")
307 307 def check_pairs(func, pairs):
308 308 """Utility function for the common case of checking a function with a
309 309 sequence of input/output pairs.
310 310
311 311 Parameters
312 312 ----------
313 313 func : callable
314 314 The function to be tested. Should accept a single argument.
315 315 pairs : iterable
316 316 A list of (input, expected_output) tuples.
317 317
318 318 Returns
319 319 -------
320 320 None. Raises an AssertionError if any output does not match the expected
321 321 value.
322 322 """
323 323 name = getattr(func, "func_name", getattr(func, "__name__", "<unknown>"))
324 324 for inp, expected in pairs:
325 325 out = func(inp)
326 326 assert out == expected, pair_fail_msg.format(name, inp, expected, out)
327 327
328 328
329 329 if py3compat.PY3:
330 330 MyStringIO = StringIO
331 331 else:
332 332 # In Python 2, stdout/stderr can have either bytes or unicode written to them,
333 333 # so we need a class that can handle both.
334 334 class MyStringIO(StringIO):
335 335 def write(self, s):
336 336 s = py3compat.cast_unicode(s, encoding=getdefaultencoding())
337 337 super(MyStringIO, self).write(s)
338 338
339 339 notprinted_msg = """Did not find {0!r} in printed output (on {1}):
340 340 {2!r}"""
341 341
342 342 class AssertPrints(object):
343 343 """Context manager for testing that code prints certain text.
344 344
345 345 Examples
346 346 --------
347 347 >>> with AssertPrints("abc", suppress=False):
348 348 ... print "abcd"
349 349 ... print "def"
350 350 ...
351 351 abcd
352 352 def
353 353 """
354 354 def __init__(self, s, channel='stdout', suppress=True):
355 355 self.s = s
356 356 self.channel = channel
357 357 self.suppress = suppress
358 358
359 359 def __enter__(self):
360 360 self.orig_stream = getattr(sys, self.channel)
361 361 self.buffer = MyStringIO()
362 362 self.tee = Tee(self.buffer, channel=self.channel)
363 363 setattr(sys, self.channel, self.buffer if self.suppress else self.tee)
364 364
365 365 def __exit__(self, etype, value, traceback):
366 366 self.tee.flush()
367 367 setattr(sys, self.channel, self.orig_stream)
368 368 printed = self.buffer.getvalue()
369 369 assert self.s in printed, notprinted_msg.format(self.s, self.channel, printed)
370 370 return False
371 371
372 372 class AssertNotPrints(AssertPrints):
373 373 """Context manager for checking that certain output *isn't* produced.
374 374
375 375 Counterpart of AssertPrints"""
376 376 def __exit__(self, etype, value, traceback):
377 377 self.tee.flush()
378 378 setattr(sys, self.channel, self.orig_stream)
379 379 printed = self.buffer.getvalue()
380 380 assert self.s not in printed, notprinted_msg.format(self.s, self.channel, printed)
381 381 return False
382 382
383 383 @contextmanager
384 384 def mute_warn():
385 385 from IPython.utils import warn
386 386 save_warn = warn.warn
387 387 warn.warn = lambda *a, **kw: None
388 388 try:
389 389 yield
390 390 finally:
391 391 warn.warn = save_warn
392 392
393 393 @contextmanager
394 394 def make_tempfile(name):
395 395 """ Create an empty, named, temporary file for the duration of the context.
396 396 """
397 397 f = open(name, 'w')
398 398 f.close()
399 399 try:
400 400 yield
401 401 finally:
402 402 os.unlink(name)
@@ -1,145 +1,145 b''
1 1 """Common utilities for the various process_* implementations.
2 2
3 3 This file is only meant to be imported by the platform-specific implementations
4 4 of subprocess utilities, and it contains tools that are common to all of them.
5 5 """
6 6
7 7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2010 The IPython Development Team
8 # Copyright (C) 2010-2011 The IPython Development Team
9 9 #
10 10 # Distributed under the terms of the BSD License. The full license is in
11 11 # the file COPYING, distributed as part of this software.
12 12 #-----------------------------------------------------------------------------
13 13
14 14 #-----------------------------------------------------------------------------
15 15 # Imports
16 16 #-----------------------------------------------------------------------------
17 17 import subprocess
18 18 import sys
19 19
20 20 from IPython.utils import py3compat
21 21
22 22 #-----------------------------------------------------------------------------
23 23 # Function definitions
24 24 #-----------------------------------------------------------------------------
25 25
26 26 def read_no_interrupt(p):
27 27 """Read from a pipe ignoring EINTR errors.
28 28
29 29 This is necessary because when reading from pipes with GUI event loops
30 30 running in the background, often interrupts are raised that stop the
31 31 command from completing."""
32 32 import errno
33 33
34 34 try:
35 35 return p.read()
36 36 except IOError, err:
37 37 if err.errno != errno.EINTR:
38 38 raise
39 39
40 40
41 41 def process_handler(cmd, callback, stderr=subprocess.PIPE):
42 42 """Open a command in a shell subprocess and execute a callback.
43 43
44 44 This function provides common scaffolding for creating subprocess.Popen()
45 45 calls. It creates a Popen object and then calls the callback with it.
46 46
47 47 Parameters
48 48 ----------
49 49 cmd : str
50 50 A string to be executed with the underlying system shell (by calling
51 51 :func:`Popen` with ``shell=True``.
52 52
53 53 callback : callable
54 54 A one-argument function that will be called with the Popen object.
55 55
56 56 stderr : file descriptor number, optional
57 57 By default this is set to ``subprocess.PIPE``, but you can also pass the
58 58 value ``subprocess.STDOUT`` to force the subprocess' stderr to go into
59 59 the same file descriptor as its stdout. This is useful to read stdout
60 60 and stderr combined in the order they are generated.
61 61
62 62 Returns
63 63 -------
64 64 The return value of the provided callback is returned.
65 65 """
66 66 sys.stdout.flush()
67 67 sys.stderr.flush()
68 68 # On win32, close_fds can't be true when using pipes for stdin/out/err
69 69 close_fds = sys.platform != 'win32'
70 70 p = subprocess.Popen(cmd, shell=True,
71 71 stdin=subprocess.PIPE,
72 72 stdout=subprocess.PIPE,
73 73 stderr=stderr,
74 74 close_fds=close_fds)
75 75
76 76 try:
77 77 out = callback(p)
78 78 except KeyboardInterrupt:
79 79 print('^C')
80 80 sys.stdout.flush()
81 81 sys.stderr.flush()
82 82 out = None
83 83 finally:
84 84 # Make really sure that we don't leave processes behind, in case the
85 85 # call above raises an exception
86 86 # We start by assuming the subprocess finished (to avoid NameErrors
87 87 # later depending on the path taken)
88 88 if p.returncode is None:
89 89 try:
90 90 p.terminate()
91 91 p.poll()
92 92 except OSError:
93 93 pass
94 94 # One last try on our way out
95 95 if p.returncode is None:
96 96 try:
97 97 p.kill()
98 98 except OSError:
99 99 pass
100 100
101 101 return out
102 102
103 103
104 104 def getoutput(cmd):
105 105 """Return standard output of executing cmd in a shell.
106 106
107 107 Accepts the same arguments as os.system().
108 108
109 109 Parameters
110 110 ----------
111 111 cmd : str
112 112 A command to be executed in the system shell.
113 113
114 114 Returns
115 115 -------
116 116 stdout : str
117 117 """
118 118
119 119 out = process_handler(cmd, lambda p: p.communicate()[0], subprocess.STDOUT)
120 120 if out is None:
121 121 return ''
122 122 return py3compat.bytes_to_str(out)
123 123
124 124
125 125 def getoutputerror(cmd):
126 126 """Return (standard output, standard error) of executing cmd in a shell.
127 127
128 128 Accepts the same arguments as os.system().
129 129
130 130 Parameters
131 131 ----------
132 132 cmd : str
133 133 A command to be executed in the system shell.
134 134
135 135 Returns
136 136 -------
137 137 stdout : str
138 138 stderr : str
139 139 """
140 140
141 141 out_err = process_handler(cmd, lambda p: p.communicate())
142 142 if out_err is None:
143 143 return '', ''
144 144 out, err = out_err
145 145 return py3compat.bytes_to_str(out), py3compat.bytes_to_str(err)
@@ -1,190 +1,190 b''
1 1 """Posix-specific implementation of process utilities.
2 2
3 3 This file is only meant to be imported by process.py, not by end-users.
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2010 The IPython Development Team
7 # Copyright (C) 2010-2011 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16 from __future__ import print_function
17 17
18 18 # Stdlib
19 19 import subprocess as sp
20 20 import sys
21 21
22 22 from IPython.external import pexpect
23 23
24 24 # Our own
25 25 from .autoattr import auto_attr
26 26 from ._process_common import getoutput
27 27 from IPython.utils import text
28 28 from IPython.utils import py3compat
29 29
30 30 #-----------------------------------------------------------------------------
31 31 # Function definitions
32 32 #-----------------------------------------------------------------------------
33 33
34 34 def _find_cmd(cmd):
35 35 """Find the full path to a command using which."""
36 36
37 37 path = sp.Popen(['/usr/bin/env', 'which', cmd],
38 38 stdout=sp.PIPE).communicate()[0]
39 39 return py3compat.bytes_to_str(path)
40 40
41 41
42 42 class ProcessHandler(object):
43 43 """Execute subprocesses under the control of pexpect.
44 44 """
45 45 # Timeout in seconds to wait on each reading of the subprocess' output.
46 46 # This should not be set too low to avoid cpu overusage from our side,
47 47 # since we read in a loop whose period is controlled by this timeout.
48 48 read_timeout = 0.05
49 49
50 50 # Timeout to give a process if we receive SIGINT, between sending the
51 51 # SIGINT to the process and forcefully terminating it.
52 52 terminate_timeout = 0.2
53 53
54 54 # File object where stdout and stderr of the subprocess will be written
55 55 logfile = None
56 56
57 57 # Shell to call for subprocesses to execute
58 58 sh = None
59 59
60 60 @auto_attr
61 61 def sh(self):
62 62 sh = pexpect.which('sh')
63 63 if sh is None:
64 64 raise OSError('"sh" shell not found')
65 65 return sh
66 66
67 67 def __init__(self, logfile=None, read_timeout=None, terminate_timeout=None):
68 68 """Arguments are used for pexpect calls."""
69 69 self.read_timeout = (ProcessHandler.read_timeout if read_timeout is
70 70 None else read_timeout)
71 71 self.terminate_timeout = (ProcessHandler.terminate_timeout if
72 72 terminate_timeout is None else
73 73 terminate_timeout)
74 74 self.logfile = sys.stdout if logfile is None else logfile
75 75
76 76 def getoutput(self, cmd):
77 77 """Run a command and return its stdout/stderr as a string.
78 78
79 79 Parameters
80 80 ----------
81 81 cmd : str
82 82 A command to be executed in the system shell.
83 83
84 84 Returns
85 85 -------
86 86 output : str
87 87 A string containing the combination of stdout and stderr from the
88 88 subprocess, in whatever order the subprocess originally wrote to its
89 89 file descriptors (so the order of the information in this string is the
90 90 correct order as would be seen if running the command in a terminal).
91 91 """
92 92 try:
93 93 return pexpect.run(self.sh, args=['-c', cmd]).replace('\r\n', '\n')
94 94 except KeyboardInterrupt:
95 95 print('^C', file=sys.stderr, end='')
96 96
97 97 def getoutput_pexpect(self, cmd):
98 98 """Run a command and return its stdout/stderr as a string.
99 99
100 100 Parameters
101 101 ----------
102 102 cmd : str
103 103 A command to be executed in the system shell.
104 104
105 105 Returns
106 106 -------
107 107 output : str
108 108 A string containing the combination of stdout and stderr from the
109 109 subprocess, in whatever order the subprocess originally wrote to its
110 110 file descriptors (so the order of the information in this string is the
111 111 correct order as would be seen if running the command in a terminal).
112 112 """
113 113 try:
114 114 return pexpect.run(self.sh, args=['-c', cmd]).replace('\r\n', '\n')
115 115 except KeyboardInterrupt:
116 116 print('^C', file=sys.stderr, end='')
117 117
118 118 def system(self, cmd):
119 119 """Execute a command in a subshell.
120 120
121 121 Parameters
122 122 ----------
123 123 cmd : str
124 124 A command to be executed in the system shell.
125 125
126 126 Returns
127 127 -------
128 128 int : child's exitstatus
129 129 """
130 130 # Get likely encoding for the output.
131 131 enc = text.getdefaultencoding()
132 132
133 133 # Patterns to match on the output, for pexpect. We read input and
134 134 # allow either a short timeout or EOF
135 135 patterns = [pexpect.TIMEOUT, pexpect.EOF]
136 136 # the index of the EOF pattern in the list.
137 137 # even though we know it's 1, this call means we don't have to worry if
138 138 # we change the above list, and forget to change this value:
139 139 EOF_index = patterns.index(pexpect.EOF)
140 140 # The size of the output stored so far in the process output buffer.
141 141 # Since pexpect only appends to this buffer, each time we print we
142 142 # record how far we've printed, so that next time we only print *new*
143 143 # content from the buffer.
144 144 out_size = 0
145 145 try:
146 146 # Since we're not really searching the buffer for text patterns, we
147 147 # can set pexpect's search window to be tiny and it won't matter.
148 148 # We only search for the 'patterns' timeout or EOF, which aren't in
149 149 # the text itself.
150 150 child = pexpect.spawn(self.sh, args=['-c', cmd])
151 151 flush = sys.stdout.flush
152 152 while True:
153 153 # res is the index of the pattern that caused the match, so we
154 154 # know whether we've finished (if we matched EOF) or not
155 155 res_idx = child.expect_list(patterns, self.read_timeout)
156 156 print(child.before[out_size:].decode(enc, 'replace'), end='')
157 157 flush()
158 158 if res_idx==EOF_index:
159 159 break
160 160 # Update the pointer to what we've already printed
161 161 out_size = len(child.before)
162 162 except KeyboardInterrupt:
163 163 # We need to send ^C to the process. The ascii code for '^C' is 3
164 164 # (the character is known as ETX for 'End of Text', see
165 165 # curses.ascii.ETX).
166 166 child.sendline(chr(3))
167 167 # Read and print any more output the program might produce on its
168 168 # way out.
169 169 try:
170 170 out_size = len(child.before)
171 171 child.expect_list(patterns, self.terminate_timeout)
172 172 print(child.before[out_size:].decode(enc, 'replace'), end='')
173 173 sys.stdout.flush()
174 174 except KeyboardInterrupt:
175 175 # Impatient users tend to type it multiple times
176 176 pass
177 177 finally:
178 178 # Ensure the subprocess really is terminated
179 179 child.terminate(force=True)
180 180 # add isalive check, to ensure exitstatus is set:
181 181 child.isalive()
182 182 return child.exitstatus
183 183
184 184
185 185 # Make system() with a functional interface for outside use. Note that we use
186 186 # getoutput() from the _common utils, which is built on top of popen(). Using
187 187 # pexpect to get subprocess output produces difficult to parse output, since
188 188 # programs think they are talking to a tty and produce highly formatted output
189 189 # (ls is a good example) that makes them hard.
190 190 system = ProcessHandler().system
@@ -1,148 +1,148 b''
1 1 """Windows-specific implementation of process utilities.
2 2
3 3 This file is only meant to be imported by process.py, not by end-users.
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2010 The IPython Development Team
7 # Copyright (C) 2010-2011 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16 from __future__ import print_function
17 17
18 18 # stdlib
19 19 import os
20 20 import sys
21 21
22 22 from subprocess import STDOUT
23 23
24 24 # our own imports
25 25 from ._process_common import read_no_interrupt, process_handler
26 26 from . import text
27 27
28 28 #-----------------------------------------------------------------------------
29 29 # Function definitions
30 30 #-----------------------------------------------------------------------------
31 31
32 32 class AvoidUNCPath(object):
33 33 """A context manager to protect command execution from UNC paths.
34 34
35 35 In the Win32 API, commands can't be invoked with the cwd being a UNC path.
36 36 This context manager temporarily changes directory to the 'C:' drive on
37 37 entering, and restores the original working directory on exit.
38 38
39 39 The context manager returns the starting working directory *if* it made a
40 40 change and None otherwise, so that users can apply the necessary adjustment
41 41 to their system calls in the event of a change.
42 42
43 43 Example
44 44 -------
45 45 ::
46 46 cmd = 'dir'
47 47 with AvoidUNCPath() as path:
48 48 if path is not None:
49 49 cmd = '"pushd %s &&"%s' % (path, cmd)
50 50 os.system(cmd)
51 51 """
52 52 def __enter__(self):
53 53 self.path = os.getcwdu()
54 54 self.is_unc_path = self.path.startswith(r"\\")
55 55 if self.is_unc_path:
56 56 # change to c drive (as cmd.exe cannot handle UNC addresses)
57 57 os.chdir("C:")
58 58 return self.path
59 59 else:
60 60 # We return None to signal that there was no change in the working
61 61 # directory
62 62 return None
63 63
64 64 def __exit__(self, exc_type, exc_value, traceback):
65 65 if self.is_unc_path:
66 66 os.chdir(self.path)
67 67
68 68
69 69 def _find_cmd(cmd):
70 70 """Find the full path to a .bat or .exe using the win32api module."""
71 71 try:
72 72 from win32api import SearchPath
73 73 except ImportError:
74 74 raise ImportError('you need to have pywin32 installed for this to work')
75 75 else:
76 76 PATH = os.environ['PATH']
77 77 extensions = ['.exe', '.com', '.bat', '.py']
78 78 path = None
79 79 for ext in extensions:
80 80 try:
81 81 path = SearchPath(PATH, cmd + ext)[0]
82 82 except:
83 83 pass
84 84 if path is None:
85 85 raise OSError("command %r not found" % cmd)
86 86 else:
87 87 return path
88 88
89 89
90 90 def _system_body(p):
91 91 """Callback for _system."""
92 92 enc = text.getdefaultencoding()
93 93 for line in read_no_interrupt(p.stdout).splitlines():
94 94 line = line.decode(enc, 'replace')
95 95 print(line, file=sys.stdout)
96 96 for line in read_no_interrupt(p.stderr).splitlines():
97 97 line = line.decode(enc, 'replace')
98 98 print(line, file=sys.stderr)
99 99
100 100 # Wait to finish for returncode
101 101 return p.wait()
102 102
103 103
104 104 def system(cmd):
105 105 """Win32 version of os.system() that works with network shares.
106 106
107 107 Note that this implementation returns None, as meant for use in IPython.
108 108
109 109 Parameters
110 110 ----------
111 111 cmd : str
112 112 A command to be executed in the system shell.
113 113
114 114 Returns
115 115 -------
116 116 None : we explicitly do NOT return the subprocess status code, as this
117 117 utility is meant to be used extensively in IPython, where any return value
118 118 would trigger :func:`sys.displayhook` calls.
119 119 """
120 120 with AvoidUNCPath() as path:
121 121 if path is not None:
122 122 cmd = '"pushd %s &&"%s' % (path, cmd)
123 123 return process_handler(cmd, _system_body)
124 124
125 125
126 126 def getoutput(cmd):
127 127 """Return standard output of executing cmd in a shell.
128 128
129 129 Accepts the same arguments as os.system().
130 130
131 131 Parameters
132 132 ----------
133 133 cmd : str
134 134 A command to be executed in the system shell.
135 135
136 136 Returns
137 137 -------
138 138 stdout : str
139 139 """
140 140
141 141 with AvoidUNCPath() as path:
142 142 if path is not None:
143 143 cmd = '"pushd %s &&"%s' % (path, cmd)
144 144 out = process_handler(cmd, lambda p: p.communicate()[0], STDOUT)
145 145
146 146 if out is None:
147 147 out = ''
148 148 return out
@@ -1,167 +1,167 b''
1 1 # encoding: utf-8
2 2 """
3 3 Older utilities that are not being used.
4 4
5 5 WARNING: IF YOU NEED TO USE ONE OF THESE FUNCTIONS, PLEASE FIRST MOVE IT
6 6 TO ANOTHER APPROPRIATE MODULE IN IPython.utils.
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 12 # Distributed under the terms of the BSD License. The full license is in
13 13 # the file COPYING, distributed as part of this software.
14 14 #-----------------------------------------------------------------------------
15 15
16 16 #-----------------------------------------------------------------------------
17 17 # Imports
18 18 #-----------------------------------------------------------------------------
19 19
20 20 import sys
21 21 import warnings
22 22
23 23 from IPython.utils.warn import warn
24 24
25 25 #-----------------------------------------------------------------------------
26 26 # Code
27 27 #-----------------------------------------------------------------------------
28 28
29 29
30 30 def mutex_opts(dict,ex_op):
31 31 """Check for presence of mutually exclusive keys in a dict.
32 32
33 33 Call: mutex_opts(dict,[[op1a,op1b],[op2a,op2b]...]"""
34 34 for op1,op2 in ex_op:
35 35 if op1 in dict and op2 in dict:
36 36 raise ValueError,'\n*** ERROR in Arguments *** '\
37 37 'Options '+op1+' and '+op2+' are mutually exclusive.'
38 38
39 39
40 40 class EvalDict:
41 41 """
42 42 Emulate a dict which evaluates its contents in the caller's frame.
43 43
44 44 Usage:
45 45 >>> number = 19
46 46
47 47 >>> text = "python"
48 48
49 49 >>> print "%(text.capitalize())s %(number/9.0).1f rules!" % EvalDict()
50 50 Python 2.1 rules!
51 51 """
52 52
53 53 # This version is due to sismex01@hebmex.com on c.l.py, and is basically a
54 54 # modified (shorter) version of:
55 55 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66018 by
56 56 # Skip Montanaro (skip@pobox.com).
57 57
58 58 def __getitem__(self, name):
59 59 frame = sys._getframe(1)
60 60 return eval(name, frame.f_globals, frame.f_locals)
61 61
62 62 EvalString = EvalDict # for backwards compatibility
63 63
64 64
65 65 def all_belong(candidates,checklist):
66 66 """Check whether a list of items ALL appear in a given list of options.
67 67
68 68 Returns a single 1 or 0 value."""
69 69
70 70 return 1-(0 in [x in checklist for x in candidates])
71 71
72 72
73 73 def belong(candidates,checklist):
74 74 """Check whether a list of items appear in a given list of options.
75 75
76 76 Returns a list of 1 and 0, one for each candidate given."""
77 77
78 78 return [x in checklist for x in candidates]
79 79
80 80
81 81 def with_obj(object, **args):
82 82 """Set multiple attributes for an object, similar to Pascal's with.
83 83
84 84 Example:
85 85 with_obj(jim,
86 86 born = 1960,
87 87 haircolour = 'Brown',
88 88 eyecolour = 'Green')
89 89
90 90 Credit: Greg Ewing, in
91 91 http://mail.python.org/pipermail/python-list/2001-May/040703.html.
92 92
93 93 NOTE: up until IPython 0.7.2, this was called simply 'with', but 'with'
94 94 has become a keyword for Python 2.5, so we had to rename it."""
95 95
96 96 object.__dict__.update(args)
97 97
98 98
99 99 def map_method(method,object_list,*argseq,**kw):
100 100 """map_method(method,object_list,*args,**kw) -> list
101 101
102 102 Return a list of the results of applying the methods to the items of the
103 103 argument sequence(s). If more than one sequence is given, the method is
104 104 called with an argument list consisting of the corresponding item of each
105 105 sequence. All sequences must be of the same length.
106 106
107 107 Keyword arguments are passed verbatim to all objects called.
108 108
109 109 This is Python code, so it's not nearly as fast as the builtin map()."""
110 110
111 111 out_list = []
112 112 idx = 0
113 113 for object in object_list:
114 114 try:
115 115 handler = getattr(object, method)
116 116 except AttributeError:
117 117 out_list.append(None)
118 118 else:
119 119 if argseq:
120 120 args = map(lambda lst:lst[idx],argseq)
121 121 #print 'ob',object,'hand',handler,'ar',args # dbg
122 122 out_list.append(handler(args,**kw))
123 123 else:
124 124 out_list.append(handler(**kw))
125 125 idx += 1
126 126 return out_list
127 127
128 128
129 129 def import_fail_info(mod_name,fns=None):
130 130 """Inform load failure for a module."""
131 131
132 132 if fns == None:
133 133 warn("Loading of %s failed.\n" % (mod_name,))
134 134 else:
135 135 warn("Loading of %s from %s failed.\n" % (fns,mod_name))
136 136
137 137
138 138 class NotGiven: pass
139 139
140 140 def popkey(dct,key,default=NotGiven):
141 141 """Return dct[key] and delete dct[key].
142 142
143 143 If default is given, return it if dct[key] doesn't exist, otherwise raise
144 144 KeyError. """
145 145
146 146 try:
147 147 val = dct[key]
148 148 except KeyError:
149 149 if default is NotGiven:
150 150 raise
151 151 else:
152 152 return default
153 153 else:
154 154 del dct[key]
155 155 return val
156 156
157 157
158 158 def wrap_deprecated(func, suggest = '<nothing>'):
159 159 def newFunc(*args, **kwargs):
160 160 warnings.warn("Call to deprecated function %s, use %s instead" %
161 161 ( func.__name__, suggest),
162 162 category=DeprecationWarning,
163 163 stacklevel = 2)
164 164 return func(*args, **kwargs)
165 165 return newFunc
166 166
167 167
@@ -1,43 +1,43 b''
1 1 # encoding: utf-8
2 2
3 3 """Utilities to enable code objects to be pickled.
4 4
5 5 Any process that import this module will be able to pickle code objects. This
6 6 includes the func_code attribute of any function. Once unpickled, new
7 7 functions can be built using new.function(code, globals()). Eventually
8 8 we need to automate all of this so that functions themselves can be pickled.
9 9
10 10 Reference: A. Tremols, P Cogolo, "Python Cookbook," p 302-305
11 11 """
12 12
13 13 __docformat__ = "restructuredtext en"
14 14
15 15 #-------------------------------------------------------------------------------
16 # Copyright (C) 2008 The IPython Development Team
16 # Copyright (C) 2008-2011 The IPython Development Team
17 17 #
18 18 # Distributed under the terms of the BSD License. The full license is in
19 19 # the file COPYING, distributed as part of this software.
20 20 #-------------------------------------------------------------------------------
21 21
22 22 #-------------------------------------------------------------------------------
23 23 # Imports
24 24 #-------------------------------------------------------------------------------
25 25
26 26 import sys
27 27 import types, copy_reg
28 28
29 29 def code_ctor(*args):
30 30 return types.CodeType(*args)
31 31
32 32 def reduce_code(co):
33 33 if co.co_freevars or co.co_cellvars:
34 34 raise ValueError("Sorry, cannot pickle code objects with closures")
35 35 args = [co.co_argcount, co.co_nlocals, co.co_stacksize,
36 36 co.co_flags, co.co_code, co.co_consts, co.co_names,
37 37 co.co_varnames, co.co_filename, co.co_name, co.co_firstlineno,
38 38 co.co_lnotab]
39 39 if sys.version_info[0] >= 3:
40 40 args.insert(1, co.co_kwonlyargcount)
41 41 return code_ctor, tuple(args)
42 42
43 43 copy_reg.pickle(types.CodeType, reduce_code) No newline at end of file
@@ -1,31 +1,31 b''
1 1 # encoding: utf-8
2 2 """
3 3 See if we have curses.
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2009 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 #-----------------------------------------------------------------------------
18 18 # Code
19 19 #-----------------------------------------------------------------------------
20 20
21 21 # Curses and termios are Unix-only modules
22 22 try:
23 23 import curses
24 24 # We need termios as well, so if its import happens to raise, we bail on
25 25 # using curses altogether.
26 26 import termios
27 27 except ImportError:
28 28 use_curses = False
29 29 else:
30 30 # Curses on Solaris may not be complete, so we can't use it there
31 31 use_curses = hasattr(curses,'initscr') No newline at end of file
@@ -1,106 +1,106 b''
1 1 # encoding: utf-8
2 2 """Utilities for working with data structures like lists, dicts and tuples.
3 3 """
4 4
5 5 #-----------------------------------------------------------------------------
6 # Copyright (C) 2008-2009 The IPython Development Team
6 # Copyright (C) 2008-2011 The IPython Development Team
7 7 #
8 8 # Distributed under the terms of the BSD License. The full license is in
9 9 # the file COPYING, distributed as part of this software.
10 10 #-----------------------------------------------------------------------------
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Imports
14 14 #-----------------------------------------------------------------------------
15 15
16 16 import types
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Code
20 20 #-----------------------------------------------------------------------------
21 21
22 22 def uniq_stable(elems):
23 23 """uniq_stable(elems) -> list
24 24
25 25 Return from an iterable, a list of all the unique elements in the input,
26 26 but maintaining the order in which they first appear.
27 27
28 28 A naive solution to this problem which just makes a dictionary with the
29 29 elements as keys fails to respect the stability condition, since
30 30 dictionaries are unsorted by nature.
31 31
32 32 Note: All elements in the input must be valid dictionary keys for this
33 33 routine to work, as it internally uses a dictionary for efficiency
34 34 reasons."""
35 35
36 36 unique = []
37 37 unique_dict = {}
38 38 for nn in elems:
39 39 if nn not in unique_dict:
40 40 unique.append(nn)
41 41 unique_dict[nn] = None
42 42 return unique
43 43
44 44
45 45 def sort_compare(lst1, lst2, inplace=1):
46 46 """Sort and compare two lists.
47 47
48 48 By default it does it in place, thus modifying the lists. Use inplace = 0
49 49 to avoid that (at the cost of temporary copy creation)."""
50 50 if not inplace:
51 51 lst1 = lst1[:]
52 52 lst2 = lst2[:]
53 53 lst1.sort(); lst2.sort()
54 54 return lst1 == lst2
55 55
56 56
57 57 def list2dict(lst):
58 58 """Takes a list of (key,value) pairs and turns it into a dict."""
59 59
60 60 dic = {}
61 61 for k,v in lst: dic[k] = v
62 62 return dic
63 63
64 64
65 65 def list2dict2(lst, default=''):
66 66 """Takes a list and turns it into a dict.
67 67 Much slower than list2dict, but more versatile. This version can take
68 68 lists with sublists of arbitrary length (including sclars)."""
69 69
70 70 dic = {}
71 71 for elem in lst:
72 72 if type(elem) in (types.ListType,types.TupleType):
73 73 size = len(elem)
74 74 if size == 0:
75 75 pass
76 76 elif size == 1:
77 77 dic[elem] = default
78 78 else:
79 79 k,v = elem[0], elem[1:]
80 80 if len(v) == 1: v = v[0]
81 81 dic[k] = v
82 82 else:
83 83 dic[elem] = default
84 84 return dic
85 85
86 86
87 87 def flatten(seq):
88 88 """Flatten a list of lists (NOT recursive, only works for 2d lists)."""
89 89
90 90 return [x for subseq in seq for x in subseq]
91 91
92 92
93 93 def get_slice(seq, start=0, stop=None, step=1):
94 94 """Get a slice of a sequence with variable step. Specify start,stop,step."""
95 95 if stop == None:
96 96 stop = len(seq)
97 97 item = lambda i: seq[i]
98 98 return map(item,xrange(start,stop,step))
99 99
100 100
101 101 def chop(seq, size):
102 102 """Chop a sequence into chunks of the given size."""
103 103 chunk = lambda i: seq[i:i+size]
104 104 return map(chunk,xrange(0,len(seq),size))
105 105
106 106
@@ -1,46 +1,46 b''
1 1 # encoding: utf-8
2 2 """Decorators that don't go anywhere else.
3 3
4 4 This module contains misc. decorators that don't really go with another module
5 5 in :mod:`IPython.utils`. Beore putting something here please see if it should
6 6 go into another topical module in :mod:`IPython.utils`.
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 12 # Distributed under the terms of the BSD License. The full license is in
13 13 # the file COPYING, distributed as part of this software.
14 14 #-----------------------------------------------------------------------------
15 15
16 16 #-----------------------------------------------------------------------------
17 17 # Imports
18 18 #-----------------------------------------------------------------------------
19 19
20 20 #-----------------------------------------------------------------------------
21 21 # Code
22 22 #-----------------------------------------------------------------------------
23 23
24 24 def flag_calls(func):
25 25 """Wrap a function to detect and flag when it gets called.
26 26
27 27 This is a decorator which takes a function and wraps it in a function with
28 28 a 'called' attribute. wrapper.called is initialized to False.
29 29
30 30 The wrapper.called attribute is set to False right before each call to the
31 31 wrapped function, so if the call fails it remains False. After the call
32 32 completes, wrapper.called is set to True and the output is returned.
33 33
34 34 Testing for truth in wrapper.called allows you to determine if a call to
35 35 func() was attempted and succeeded."""
36 36
37 37 def wrapper(*args,**kw):
38 38 wrapper.called = False
39 39 out = func(*args,**kw)
40 40 wrapper.called = True
41 41 return out
42 42
43 43 wrapper.called = False
44 44 wrapper.__doc__ = func.__doc__
45 45 return wrapper
46 46
@@ -1,94 +1,94 b''
1 1 # encoding: utf-8
2 2 """A fancy version of Python's builtin :func:`dir` function.
3 3 """
4 4
5 5 #-----------------------------------------------------------------------------
6 # Copyright (C) 2008-2009 The IPython Development Team
6 # Copyright (C) 2008-2011 The IPython Development Team
7 7 #
8 8 # Distributed under the terms of the BSD License. The full license is in
9 9 # the file COPYING, distributed as part of this software.
10 10 #-----------------------------------------------------------------------------
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Imports
14 14 #-----------------------------------------------------------------------------
15 15
16 16 #-----------------------------------------------------------------------------
17 17 # Code
18 18 #-----------------------------------------------------------------------------
19 19
20 20 def get_class_members(cls):
21 21 ret = dir(cls)
22 22 if hasattr(cls,'__bases__'):
23 23 try:
24 24 bases = cls.__bases__
25 25 except AttributeError:
26 26 # `obj` lied to hasattr (e.g. Pyro), ignore
27 27 pass
28 28 else:
29 29 for base in bases:
30 30 ret.extend(get_class_members(base))
31 31 return ret
32 32
33 33
34 34 def dir2(obj):
35 35 """dir2(obj) -> list of strings
36 36
37 37 Extended version of the Python builtin dir(), which does a few extra
38 38 checks, and supports common objects with unusual internals that confuse
39 39 dir(), such as Traits and PyCrust.
40 40
41 41 This version is guaranteed to return only a list of true strings, whereas
42 42 dir() returns anything that objects inject into themselves, even if they
43 43 are later not really valid for attribute access (many extension libraries
44 44 have such bugs).
45 45 """
46 46
47 47 # Start building the attribute list via dir(), and then complete it
48 48 # with a few extra special-purpose calls.
49 49 words = dir(obj)
50 50
51 51 if hasattr(obj,'__class__'):
52 52 words.append('__class__')
53 53 words.extend(get_class_members(obj.__class__))
54 54 #if '__base__' in words: 1/0
55 55
56 56 # Some libraries (such as traits) may introduce duplicates, we want to
57 57 # track and clean this up if it happens
58 58 may_have_dupes = False
59 59
60 60 # this is the 'dir' function for objects with Enthought's traits
61 61 if hasattr(obj, 'trait_names'):
62 62 try:
63 63 words.extend(obj.trait_names())
64 64 may_have_dupes = True
65 65 except TypeError:
66 66 # This will happen if `obj` is a class and not an instance.
67 67 pass
68 68 except AttributeError:
69 69 # `obj` lied to hasatter (e.g. Pyro), ignore
70 70 pass
71 71
72 72 # Support for PyCrust-style _getAttributeNames magic method.
73 73 if hasattr(obj, '_getAttributeNames'):
74 74 try:
75 75 words.extend(obj._getAttributeNames())
76 76 may_have_dupes = True
77 77 except TypeError:
78 78 # `obj` is a class and not an instance. Ignore
79 79 # this error.
80 80 pass
81 81 except AttributeError:
82 82 # `obj` lied to hasatter (e.g. Pyro), ignore
83 83 pass
84 84
85 85 if may_have_dupes:
86 86 # eliminate possible duplicates, as some traits may also
87 87 # appear as normal attributes in the dir() call.
88 88 words = list(set(words))
89 89 words.sort()
90 90
91 91 # filter out non-string attributes which may be stuffed by dir() calls
92 92 # and poor coding in third-party modules
93 93 return [w for w in words if isinstance(w, basestring)]
94 94
@@ -1,75 +1,75 b''
1 1 # encoding: utf-8
2 2 """
3 3 A utility for handling the reloading of doctest.
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2009 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 import sys
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Code
21 21 #-----------------------------------------------------------------------------
22 22
23 23 def dhook_wrap(func,*a,**k):
24 24 """Wrap a function call in a sys.displayhook controller.
25 25
26 26 Returns a wrapper around func which calls func, with all its arguments and
27 27 keywords unmodified, using the default sys.displayhook. Since IPython
28 28 modifies sys.displayhook, it breaks the behavior of certain systems that
29 29 rely on the default behavior, notably doctest.
30 30 """
31 31
32 32 def f(*a,**k):
33 33
34 34 dhook_s = sys.displayhook
35 35 sys.displayhook = sys.__displayhook__
36 36 try:
37 37 out = func(*a,**k)
38 38 finally:
39 39 sys.displayhook = dhook_s
40 40
41 41 return out
42 42
43 43 f.__doc__ = func.__doc__
44 44 return f
45 45
46 46
47 47 def doctest_reload():
48 48 """Properly reload doctest to reuse it interactively.
49 49
50 50 This routine:
51 51
52 52 - imports doctest but does NOT reload it (see below).
53 53
54 54 - resets its global 'master' attribute to None, so that multiple uses of
55 55 the module interactively don't produce cumulative reports.
56 56
57 57 - Monkeypatches its core test runner method to protect it from IPython's
58 58 modified displayhook. Doctest expects the default displayhook behavior
59 59 deep down, so our modification breaks it completely. For this reason, a
60 60 hard monkeypatch seems like a reasonable solution rather than asking
61 61 users to manually use a different doctest runner when under IPython.
62 62
63 63 Notes
64 64 -----
65 65
66 66 This function *used to* reload doctest, but this has been disabled because
67 67 reloading doctest unconditionally can cause massive breakage of other
68 68 doctest-dependent modules already in memory, such as those for IPython's
69 69 own testing system. The name wasn't changed to avoid breaking people's
70 70 code, but the reload call isn't actually made anymore."""
71 71
72 72 import doctest
73 73 doctest.master = None
74 74 doctest.DocTestRunner.run = dhook_wrap(doctest.DocTestRunner.run)
75 75
@@ -1,87 +1,87 b''
1 1 # encoding: utf-8
2 2 """
3 3 Utilities for working with stack frames.
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2009 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 import sys
18 18 from IPython.utils import py3compat
19 19
20 20 #-----------------------------------------------------------------------------
21 21 # Code
22 22 #-----------------------------------------------------------------------------
23 23
24 24 @py3compat.doctest_refactor_print
25 25 def extract_vars(*names,**kw):
26 26 """Extract a set of variables by name from another frame.
27 27
28 28 :Parameters:
29 29 - `*names`: strings
30 30 One or more variable names which will be extracted from the caller's
31 31 frame.
32 32
33 33 :Keywords:
34 34 - `depth`: integer (0)
35 35 How many frames in the stack to walk when looking for your variables.
36 36
37 37
38 38 Examples:
39 39
40 40 In [2]: def func(x):
41 41 ...: y = 1
42 42 ...: print extract_vars('x','y')
43 43 ...:
44 44
45 45 In [3]: func('hello')
46 46 {'y': 1, 'x': 'hello'}
47 47 """
48 48
49 49 depth = kw.get('depth',0)
50 50
51 51 callerNS = sys._getframe(depth+1).f_locals
52 52 return dict((k,callerNS[k]) for k in names)
53 53
54 54
55 55 def extract_vars_above(*names):
56 56 """Extract a set of variables by name from another frame.
57 57
58 58 Similar to extractVars(), but with a specified depth of 1, so that names
59 59 are exctracted exactly from above the caller.
60 60
61 61 This is simply a convenience function so that the very common case (for us)
62 62 of skipping exactly 1 frame doesn't have to construct a special dict for
63 63 keyword passing."""
64 64
65 65 callerNS = sys._getframe(2).f_locals
66 66 return dict((k,callerNS[k]) for k in names)
67 67
68 68
69 69 def debugx(expr,pre_msg=''):
70 70 """Print the value of an expression from the caller's frame.
71 71
72 72 Takes an expression, evaluates it in the caller's frame and prints both
73 73 the given expression and the resulting value (as well as a debug mark
74 74 indicating the name of the calling function. The input must be of a form
75 75 suitable for eval().
76 76
77 77 An optional message can be passed, which will be prepended to the printed
78 78 expr->value pair."""
79 79
80 80 cf = sys._getframe(1)
81 81 print '[DBG:%s] %s%s -> %r' % (cf.f_code.co_name,pre_msg,expr,
82 82 eval(expr,cf.f_globals,cf.f_locals))
83 83
84 84
85 85 # deactivate it by uncommenting the following line, which makes it a no-op
86 86 #def debugx(expr,pre_msg=''): pass
87 87
@@ -1,49 +1,49 b''
1 1 # encoding: utf-8
2 2 """Generic functions for extending IPython.
3 3
4 4 See http://cheeseshop.python.org/pypi/simplegeneric.
5 5 """
6 6
7 7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2008-2009 The IPython Development Team
8 # Copyright (C) 2008-2011 The IPython Development Team
9 9 #
10 10 # Distributed under the terms of the BSD License. The full license is in
11 11 # the file COPYING, distributed as part of this software.
12 12 #-----------------------------------------------------------------------------
13 13
14 14 #-----------------------------------------------------------------------------
15 15 # Imports
16 16 #-----------------------------------------------------------------------------
17 17
18 18 from IPython.core.error import TryNext
19 19 from IPython.external.simplegeneric import generic
20 20
21 21 #-----------------------------------------------------------------------------
22 22 # Imports
23 23 #-----------------------------------------------------------------------------
24 24
25 25
26 26 @generic
27 27 def inspect_object(obj):
28 28 """Called when you do obj?"""
29 29 raise TryNext
30 30
31 31
32 32 @generic
33 33 def complete_object(obj, prev_completions):
34 34 """Custom completer dispatching for python objects.
35 35
36 36 Parameters
37 37 ----------
38 38 obj : object
39 39 The object to complete.
40 40 prev_completions : list
41 41 List of attributes discovered so far.
42 42
43 43 This should return the list of attributes in obj. If you only wish to
44 44 add to the attributes already discovered normally, return
45 45 own_attrs + prev_completions.
46 46 """
47 47 raise TryNext
48 48
49 49
@@ -1,65 +1,65 b''
1 1 # encoding: utf-8
2 2 """
3 3 Utilities using Growl on OS X for notifications.
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2009 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 #-----------------------------------------------------------------------------
18 18 # Code
19 19 #-----------------------------------------------------------------------------
20 20
21 21 class IPythonGrowlError(Exception):
22 22 pass
23 23
24 24 class Notifier(object):
25 25
26 26 def __init__(self, app_name):
27 27 try:
28 28 import Growl
29 29 except ImportError:
30 30 self.g_notifier = None
31 31 else:
32 32 self.g_notifier = Growl.GrowlNotifier(app_name, ['kernel', 'core'])
33 33 self.g_notifier.register()
34 34
35 35 def _notify(self, title, msg):
36 36 if self.g_notifier is not None:
37 37 self.g_notifier.notify('core', title, msg)
38 38
39 39 def notify(self, title, msg):
40 40 self._notify(title, msg)
41 41
42 42 def notify_deferred(self, r, msg):
43 43 title = "Deferred Result"
44 44 msg = msg + '\n' + repr(r)
45 45 self._notify(title, msg)
46 46 return r
47 47
48 48 _notifier = None
49 49
50 50 def notify(title, msg):
51 51 pass
52 52
53 53 def notify_deferred(r, msg):
54 54 return r
55 55
56 56 def start(app_name):
57 57 global _notifier, notify, notify_deferred
58 58 if _notifier is not None:
59 59 raise IPythonGrowlError("this process is already registered with Growl")
60 60 else:
61 61 _notifier = Notifier(app_name)
62 62 notify = _notifier.notify
63 63 notify_deferred = _notifier.notify_deferred
64 64
65 65
@@ -1,43 +1,43 b''
1 1 # encoding: utf-8
2 2 """
3 3 A simple utility to import something by its string name.
4 4
5 5 Authors:
6 6
7 7 * Brian Granger
8 8 """
9 9
10 10 #-----------------------------------------------------------------------------
11 # Copyright (C) 2008-2009 The IPython Development Team
11 # Copyright (C) 2008-2011 The IPython Development Team
12 12 #
13 13 # Distributed under the terms of the BSD License. The full license is in
14 14 # the file COPYING, distributed as part of this software.
15 15 #-----------------------------------------------------------------------------
16 16
17 17 #-----------------------------------------------------------------------------
18 18 # Functions and classes
19 19 #-----------------------------------------------------------------------------
20 20
21 21 def import_item(name):
22 22 """Import and return bar given the string foo.bar."""
23 23 package = '.'.join(name.split('.')[0:-1])
24 24 obj = name.split('.')[-1]
25 25
26 26 # Note: the original code for this was the following. We've left it
27 27 # visible for now in case the new implementation shows any problems down
28 28 # the road, to make it easier on anyone looking for a problem. This code
29 29 # should be removed once we're comfortable we didn't break anything.
30 30
31 31 ## execString = 'from %s import %s' % (package, obj)
32 32 ## try:
33 33 ## exec execString
34 34 ## except SyntaxError:
35 35 ## raise ImportError("Invalid class specification: %s" % name)
36 36 ## exec 'temp = %s' % obj
37 37 ## return temp
38 38
39 39 if package:
40 40 module = __import__(package,fromlist=[obj])
41 41 return module.__dict__[obj]
42 42 else:
43 43 return __import__(obj)
@@ -1,321 +1,321 b''
1 1 # encoding: utf-8
2 2 """
3 3 IO related utilities.
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2009 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12 from __future__ import print_function
13 13
14 14 #-----------------------------------------------------------------------------
15 15 # Imports
16 16 #-----------------------------------------------------------------------------
17 17 import sys
18 18 import tempfile
19 19
20 20 #-----------------------------------------------------------------------------
21 21 # Code
22 22 #-----------------------------------------------------------------------------
23 23
24 24
25 25 class IOStream:
26 26
27 27 def __init__(self,stream, fallback=None):
28 28 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
29 29 if fallback is not None:
30 30 stream = fallback
31 31 else:
32 32 raise ValueError("fallback required, but not specified")
33 33 self.stream = stream
34 34 self._swrite = stream.write
35 35
36 36 # clone all methods not overridden:
37 37 def clone(meth):
38 38 return not hasattr(self, meth) and not meth.startswith('_')
39 39 for meth in filter(clone, dir(stream)):
40 40 setattr(self, meth, getattr(stream, meth))
41 41
42 42 def write(self,data):
43 43 try:
44 44 self._swrite(data)
45 45 except:
46 46 try:
47 47 # print handles some unicode issues which may trip a plain
48 48 # write() call. Emulate write() by using an empty end
49 49 # argument.
50 50 print(data, end='', file=self.stream)
51 51 except:
52 52 # if we get here, something is seriously broken.
53 53 print('ERROR - failed to write data to stream:', self.stream,
54 54 file=sys.stderr)
55 55
56 56 def writelines(self, lines):
57 57 if isinstance(lines, basestring):
58 58 lines = [lines]
59 59 for line in lines:
60 60 self.write(line)
61 61
62 62 # This class used to have a writeln method, but regular files and streams
63 63 # in Python don't have this method. We need to keep this completely
64 64 # compatible so we removed it.
65 65
66 66 @property
67 67 def closed(self):
68 68 return self.stream.closed
69 69
70 70 def close(self):
71 71 pass
72 72
73 73
74 74 class IOTerm:
75 75 """ Term holds the file or file-like objects for handling I/O operations.
76 76
77 77 These are normally just sys.stdin, sys.stdout and sys.stderr but for
78 78 Windows they can can replaced to allow editing the strings before they are
79 79 displayed."""
80 80
81 81 # In the future, having IPython channel all its I/O operations through
82 82 # this class will make it easier to embed it into other environments which
83 83 # are not a normal terminal (such as a GUI-based shell)
84 84 def __init__(self, stdin=None, stdout=None, stderr=None):
85 85 self.stdin = IOStream(stdin, sys.stdin)
86 86 self.stdout = IOStream(stdout, sys.stdout)
87 87 self.stderr = IOStream(stderr, sys.stderr)
88 88
89 89 # setup stdin/stdout/stderr to sys.stdin/sys.stdout/sys.stderr
90 90 stdin = IOStream(sys.stdin)
91 91 stdout = IOStream(sys.stdout)
92 92 stderr = IOStream(sys.stderr)
93 93
94 94
95 95 class Tee(object):
96 96 """A class to duplicate an output stream to stdout/err.
97 97
98 98 This works in a manner very similar to the Unix 'tee' command.
99 99
100 100 When the object is closed or deleted, it closes the original file given to
101 101 it for duplication.
102 102 """
103 103 # Inspired by:
104 104 # http://mail.python.org/pipermail/python-list/2007-May/442737.html
105 105
106 106 def __init__(self, file_or_name, mode="w", channel='stdout'):
107 107 """Construct a new Tee object.
108 108
109 109 Parameters
110 110 ----------
111 111 file_or_name : filename or open filehandle (writable)
112 112 File that will be duplicated
113 113
114 114 mode : optional, valid mode for open().
115 115 If a filename was give, open with this mode.
116 116
117 117 channel : str, one of ['stdout', 'stderr']
118 118 """
119 119 if channel not in ['stdout', 'stderr']:
120 120 raise ValueError('Invalid channel spec %s' % channel)
121 121
122 122 if hasattr(file_or_name, 'write') and hasattr(file_or_name, 'seek'):
123 123 self.file = file_or_name
124 124 else:
125 125 self.file = open(file_or_name, mode)
126 126 self.channel = channel
127 127 self.ostream = getattr(sys, channel)
128 128 setattr(sys, channel, self)
129 129 self._closed = False
130 130
131 131 def close(self):
132 132 """Close the file and restore the channel."""
133 133 self.flush()
134 134 setattr(sys, self.channel, self.ostream)
135 135 self.file.close()
136 136 self._closed = True
137 137
138 138 def write(self, data):
139 139 """Write data to both channels."""
140 140 self.file.write(data)
141 141 self.ostream.write(data)
142 142 self.ostream.flush()
143 143
144 144 def flush(self):
145 145 """Flush both channels."""
146 146 self.file.flush()
147 147 self.ostream.flush()
148 148
149 149 def __del__(self):
150 150 if not self._closed:
151 151 self.close()
152 152
153 153
154 154 def file_read(filename):
155 155 """Read a file and close it. Returns the file source."""
156 156 fobj = open(filename,'r');
157 157 source = fobj.read();
158 158 fobj.close()
159 159 return source
160 160
161 161
162 162 def file_readlines(filename):
163 163 """Read a file and close it. Returns the file source using readlines()."""
164 164 fobj = open(filename,'r');
165 165 lines = fobj.readlines();
166 166 fobj.close()
167 167 return lines
168 168
169 169
170 170 def raw_input_multi(header='', ps1='==> ', ps2='..> ',terminate_str = '.'):
171 171 """Take multiple lines of input.
172 172
173 173 A list with each line of input as a separate element is returned when a
174 174 termination string is entered (defaults to a single '.'). Input can also
175 175 terminate via EOF (^D in Unix, ^Z-RET in Windows).
176 176
177 177 Lines of input which end in \\ are joined into single entries (and a
178 178 secondary continuation prompt is issued as long as the user terminates
179 179 lines with \\). This allows entering very long strings which are still
180 180 meant to be treated as single entities.
181 181 """
182 182
183 183 try:
184 184 if header:
185 185 header += '\n'
186 186 lines = [raw_input(header + ps1)]
187 187 except EOFError:
188 188 return []
189 189 terminate = [terminate_str]
190 190 try:
191 191 while lines[-1:] != terminate:
192 192 new_line = raw_input(ps1)
193 193 while new_line.endswith('\\'):
194 194 new_line = new_line[:-1] + raw_input(ps2)
195 195 lines.append(new_line)
196 196
197 197 return lines[:-1] # don't return the termination command
198 198 except EOFError:
199 199 print()
200 200 return lines
201 201
202 202
203 203 def raw_input_ext(prompt='', ps2='... '):
204 204 """Similar to raw_input(), but accepts extended lines if input ends with \\."""
205 205
206 206 line = raw_input(prompt)
207 207 while line.endswith('\\'):
208 208 line = line[:-1] + raw_input(ps2)
209 209 return line
210 210
211 211
212 212 def ask_yes_no(prompt,default=None):
213 213 """Asks a question and returns a boolean (y/n) answer.
214 214
215 215 If default is given (one of 'y','n'), it is used if the user input is
216 216 empty. Otherwise the question is repeated until an answer is given.
217 217
218 218 An EOF is treated as the default answer. If there is no default, an
219 219 exception is raised to prevent infinite loops.
220 220
221 221 Valid answers are: y/yes/n/no (match is not case sensitive)."""
222 222
223 223 answers = {'y':True,'n':False,'yes':True,'no':False}
224 224 ans = None
225 225 while ans not in answers.keys():
226 226 try:
227 227 ans = raw_input(prompt+' ').lower()
228 228 if not ans: # response was an empty string
229 229 ans = default
230 230 except KeyboardInterrupt:
231 231 pass
232 232 except EOFError:
233 233 if default in answers.keys():
234 234 ans = default
235 235 print()
236 236 else:
237 237 raise
238 238
239 239 return answers[ans]
240 240
241 241
242 242 class NLprinter:
243 243 """Print an arbitrarily nested list, indicating index numbers.
244 244
245 245 An instance of this class called nlprint is available and callable as a
246 246 function.
247 247
248 248 nlprint(list,indent=' ',sep=': ') -> prints indenting each level by 'indent'
249 249 and using 'sep' to separate the index from the value. """
250 250
251 251 def __init__(self):
252 252 self.depth = 0
253 253
254 254 def __call__(self,lst,pos='',**kw):
255 255 """Prints the nested list numbering levels."""
256 256 kw.setdefault('indent',' ')
257 257 kw.setdefault('sep',': ')
258 258 kw.setdefault('start',0)
259 259 kw.setdefault('stop',len(lst))
260 260 # we need to remove start and stop from kw so they don't propagate
261 261 # into a recursive call for a nested list.
262 262 start = kw['start']; del kw['start']
263 263 stop = kw['stop']; del kw['stop']
264 264 if self.depth == 0 and 'header' in kw.keys():
265 265 print(kw['header'])
266 266
267 267 for idx in range(start,stop):
268 268 elem = lst[idx]
269 269 newpos = pos + str(idx)
270 270 if type(elem)==type([]):
271 271 self.depth += 1
272 272 self.__call__(elem, newpos+",", **kw)
273 273 self.depth -= 1
274 274 else:
275 275 print(kw['indent']*self.depth + newpos + kw["sep"] + repr(elem))
276 276
277 277 nlprint = NLprinter()
278 278
279 279
280 280 def temp_pyfile(src, ext='.py'):
281 281 """Make a temporary python file, return filename and filehandle.
282 282
283 283 Parameters
284 284 ----------
285 285 src : string or list of strings (no need for ending newlines if list)
286 286 Source code to be written to the file.
287 287
288 288 ext : optional, string
289 289 Extension for the generated file.
290 290
291 291 Returns
292 292 -------
293 293 (filename, open filehandle)
294 294 It is the caller's responsibility to close the open file and unlink it.
295 295 """
296 296 fname = tempfile.mkstemp(ext)[1]
297 297 f = open(fname,'w')
298 298 f.write(src)
299 299 f.flush()
300 300 return fname, f
301 301
302 302
303 303 def raw_print(*args, **kw):
304 304 """Raw print to sys.__stdout__, otherwise identical interface to print()."""
305 305
306 306 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
307 307 file=sys.__stdout__)
308 308 sys.__stdout__.flush()
309 309
310 310
311 311 def raw_print_err(*args, **kw):
312 312 """Raw print to sys.__stderr__, otherwise identical interface to print()."""
313 313
314 314 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
315 315 file=sys.__stderr__)
316 316 sys.__stderr__.flush()
317 317
318 318
319 319 # Short aliases for quick debugging, do NOT use these in production code.
320 320 rprint = raw_print
321 321 rprinte = raw_print_err
@@ -1,395 +1,395 b''
1 1 # encoding: utf-8
2 2 """A dict subclass that supports attribute style access.
3 3
4 4 Authors:
5 5
6 6 * Fernando Perez (original)
7 7 * Brian Granger (refactoring to a dict subclass)
8 8 """
9 9
10 10 #-----------------------------------------------------------------------------
11 # Copyright (C) 2008-2009 The IPython Development Team
11 # Copyright (C) 2008-2011 The IPython Development Team
12 12 #
13 13 # Distributed under the terms of the BSD License. The full license is in
14 14 # the file COPYING, distributed as part of this software.
15 15 #-----------------------------------------------------------------------------
16 16
17 17 #-----------------------------------------------------------------------------
18 18 # Imports
19 19 #-----------------------------------------------------------------------------
20 20
21 21 from IPython.utils.data import list2dict2
22 22
23 23 __all__ = ['Struct']
24 24
25 25 #-----------------------------------------------------------------------------
26 26 # Code
27 27 #-----------------------------------------------------------------------------
28 28
29 29
30 30 class Struct(dict):
31 31 """A dict subclass with attribute style access.
32 32
33 33 This dict subclass has a a few extra features:
34 34
35 35 * Attribute style access.
36 36 * Protection of class members (like keys, items) when using attribute
37 37 style access.
38 38 * The ability to restrict assignment to only existing keys.
39 39 * Intelligent merging.
40 40 * Overloaded operators.
41 41 """
42 42 _allownew = True
43 43 def __init__(self, *args, **kw):
44 44 """Initialize with a dictionary, another Struct, or data.
45 45
46 46 Parameters
47 47 ----------
48 48 args : dict, Struct
49 49 Initialize with one dict or Struct
50 50 kw : dict
51 51 Initialize with key, value pairs.
52 52
53 53 Examples
54 54 --------
55 55
56 56 >>> s = Struct(a=10,b=30)
57 57 >>> s.a
58 58 10
59 59 >>> s.b
60 60 30
61 61 >>> s2 = Struct(s,c=30)
62 62 >>> s2.keys()
63 63 ['a', 'c', 'b']
64 64 """
65 65 object.__setattr__(self, '_allownew', True)
66 66 dict.__init__(self, *args, **kw)
67 67
68 68 def __setitem__(self, key, value):
69 69 """Set an item with check for allownew.
70 70
71 71 Examples
72 72 --------
73 73
74 74 >>> s = Struct()
75 75 >>> s['a'] = 10
76 76 >>> s.allow_new_attr(False)
77 77 >>> s['a'] = 10
78 78 >>> s['a']
79 79 10
80 80 >>> try:
81 81 ... s['b'] = 20
82 82 ... except KeyError:
83 83 ... print 'this is not allowed'
84 84 ...
85 85 this is not allowed
86 86 """
87 87 if not self._allownew and not self.has_key(key):
88 88 raise KeyError(
89 89 "can't create new attribute %s when allow_new_attr(False)" % key)
90 90 dict.__setitem__(self, key, value)
91 91
92 92 def __setattr__(self, key, value):
93 93 """Set an attr with protection of class members.
94 94
95 95 This calls :meth:`self.__setitem__` but convert :exc:`KeyError` to
96 96 :exc:`AttributeError`.
97 97
98 98 Examples
99 99 --------
100 100
101 101 >>> s = Struct()
102 102 >>> s.a = 10
103 103 >>> s.a
104 104 10
105 105 >>> try:
106 106 ... s.get = 10
107 107 ... except AttributeError:
108 108 ... print "you can't set a class member"
109 109 ...
110 110 you can't set a class member
111 111 """
112 112 # If key is an str it might be a class member or instance var
113 113 if isinstance(key, str):
114 114 # I can't simply call hasattr here because it calls getattr, which
115 115 # calls self.__getattr__, which returns True for keys in
116 116 # self._data. But I only want keys in the class and in
117 117 # self.__dict__
118 118 if key in self.__dict__ or hasattr(Struct, key):
119 119 raise AttributeError(
120 120 'attr %s is a protected member of class Struct.' % key
121 121 )
122 122 try:
123 123 self.__setitem__(key, value)
124 124 except KeyError, e:
125 125 raise AttributeError(e)
126 126
127 127 def __getattr__(self, key):
128 128 """Get an attr by calling :meth:`dict.__getitem__`.
129 129
130 130 Like :meth:`__setattr__`, this method converts :exc:`KeyError` to
131 131 :exc:`AttributeError`.
132 132
133 133 Examples
134 134 --------
135 135
136 136 >>> s = Struct(a=10)
137 137 >>> s.a
138 138 10
139 139 >>> type(s.get)
140 140 <... 'builtin_function_or_method'>
141 141 >>> try:
142 142 ... s.b
143 143 ... except AttributeError:
144 144 ... print "I don't have that key"
145 145 ...
146 146 I don't have that key
147 147 """
148 148 try:
149 149 result = self[key]
150 150 except KeyError:
151 151 raise AttributeError(key)
152 152 else:
153 153 return result
154 154
155 155 def __iadd__(self, other):
156 156 """s += s2 is a shorthand for s.merge(s2).
157 157
158 158 Examples
159 159 --------
160 160
161 161 >>> s = Struct(a=10,b=30)
162 162 >>> s2 = Struct(a=20,c=40)
163 163 >>> s += s2
164 164 >>> s
165 165 {'a': 10, 'c': 40, 'b': 30}
166 166 """
167 167 self.merge(other)
168 168 return self
169 169
170 170 def __add__(self,other):
171 171 """s + s2 -> New Struct made from s.merge(s2).
172 172
173 173 Examples
174 174 --------
175 175
176 176 >>> s1 = Struct(a=10,b=30)
177 177 >>> s2 = Struct(a=20,c=40)
178 178 >>> s = s1 + s2
179 179 >>> s
180 180 {'a': 10, 'c': 40, 'b': 30}
181 181 """
182 182 sout = self.copy()
183 183 sout.merge(other)
184 184 return sout
185 185
186 186 def __sub__(self,other):
187 187 """s1 - s2 -> remove keys in s2 from s1.
188 188
189 189 Examples
190 190 --------
191 191
192 192 >>> s1 = Struct(a=10,b=30)
193 193 >>> s2 = Struct(a=40)
194 194 >>> s = s1 - s2
195 195 >>> s
196 196 {'b': 30}
197 197 """
198 198 sout = self.copy()
199 199 sout -= other
200 200 return sout
201 201
202 202 def __isub__(self,other):
203 203 """Inplace remove keys from self that are in other.
204 204
205 205 Examples
206 206 --------
207 207
208 208 >>> s1 = Struct(a=10,b=30)
209 209 >>> s2 = Struct(a=40)
210 210 >>> s1 -= s2
211 211 >>> s1
212 212 {'b': 30}
213 213 """
214 214 for k in other.keys():
215 215 if self.has_key(k):
216 216 del self[k]
217 217 return self
218 218
219 219 def __dict_invert(self, data):
220 220 """Helper function for merge.
221 221
222 222 Takes a dictionary whose values are lists and returns a dict with
223 223 the elements of each list as keys and the original keys as values.
224 224 """
225 225 outdict = {}
226 226 for k,lst in data.items():
227 227 if isinstance(lst, str):
228 228 lst = lst.split()
229 229 for entry in lst:
230 230 outdict[entry] = k
231 231 return outdict
232 232
233 233 def dict(self):
234 234 return self
235 235
236 236 def copy(self):
237 237 """Return a copy as a Struct.
238 238
239 239 Examples
240 240 --------
241 241
242 242 >>> s = Struct(a=10,b=30)
243 243 >>> s2 = s.copy()
244 244 >>> s2
245 245 {'a': 10, 'b': 30}
246 246 >>> type(s2).__name__
247 247 'Struct'
248 248 """
249 249 return Struct(dict.copy(self))
250 250
251 251 def hasattr(self, key):
252 252 """hasattr function available as a method.
253 253
254 254 Implemented like has_key.
255 255
256 256 Examples
257 257 --------
258 258
259 259 >>> s = Struct(a=10)
260 260 >>> s.hasattr('a')
261 261 True
262 262 >>> s.hasattr('b')
263 263 False
264 264 >>> s.hasattr('get')
265 265 False
266 266 """
267 267 return self.has_key(key)
268 268
269 269 def allow_new_attr(self, allow = True):
270 270 """Set whether new attributes can be created in this Struct.
271 271
272 272 This can be used to catch typos by verifying that the attribute user
273 273 tries to change already exists in this Struct.
274 274 """
275 275 object.__setattr__(self, '_allownew', allow)
276 276
277 277 def merge(self, __loc_data__=None, __conflict_solve=None, **kw):
278 278 """Merge two Structs with customizable conflict resolution.
279 279
280 280 This is similar to :meth:`update`, but much more flexible. First, a
281 281 dict is made from data+key=value pairs. When merging this dict with
282 282 the Struct S, the optional dictionary 'conflict' is used to decide
283 283 what to do.
284 284
285 285 If conflict is not given, the default behavior is to preserve any keys
286 286 with their current value (the opposite of the :meth:`update` method's
287 287 behavior).
288 288
289 289 Parameters
290 290 ----------
291 291 __loc_data : dict, Struct
292 292 The data to merge into self
293 293 __conflict_solve : dict
294 294 The conflict policy dict. The keys are binary functions used to
295 295 resolve the conflict and the values are lists of strings naming
296 296 the keys the conflict resolution function applies to. Instead of
297 297 a list of strings a space separated string can be used, like
298 298 'a b c'.
299 299 kw : dict
300 300 Additional key, value pairs to merge in
301 301
302 302 Notes
303 303 -----
304 304
305 305 The `__conflict_solve` dict is a dictionary of binary functions which will be used to
306 306 solve key conflicts. Here is an example::
307 307
308 308 __conflict_solve = dict(
309 309 func1=['a','b','c'],
310 310 func2=['d','e']
311 311 )
312 312
313 313 In this case, the function :func:`func1` will be used to resolve
314 314 keys 'a', 'b' and 'c' and the function :func:`func2` will be used for
315 315 keys 'd' and 'e'. This could also be written as::
316 316
317 317 __conflict_solve = dict(func1='a b c',func2='d e')
318 318
319 319 These functions will be called for each key they apply to with the
320 320 form::
321 321
322 322 func1(self['a'], other['a'])
323 323
324 324 The return value is used as the final merged value.
325 325
326 326 As a convenience, merge() provides five (the most commonly needed)
327 327 pre-defined policies: preserve, update, add, add_flip and add_s. The
328 328 easiest explanation is their implementation::
329 329
330 330 preserve = lambda old,new: old
331 331 update = lambda old,new: new
332 332 add = lambda old,new: old + new
333 333 add_flip = lambda old,new: new + old # note change of order!
334 334 add_s = lambda old,new: old + ' ' + new # only for str!
335 335
336 336 You can use those four words (as strings) as keys instead
337 337 of defining them as functions, and the merge method will substitute
338 338 the appropriate functions for you.
339 339
340 340 For more complicated conflict resolution policies, you still need to
341 341 construct your own functions.
342 342
343 343 Examples
344 344 --------
345 345
346 346 This show the default policy:
347 347
348 348 >>> s = Struct(a=10,b=30)
349 349 >>> s2 = Struct(a=20,c=40)
350 350 >>> s.merge(s2)
351 351 >>> s
352 352 {'a': 10, 'c': 40, 'b': 30}
353 353
354 354 Now, show how to specify a conflict dict:
355 355
356 356 >>> s = Struct(a=10,b=30)
357 357 >>> s2 = Struct(a=20,b=40)
358 358 >>> conflict = {'update':'a','add':'b'}
359 359 >>> s.merge(s2,conflict)
360 360 >>> s
361 361 {'a': 20, 'b': 70}
362 362 """
363 363
364 364 data_dict = dict(__loc_data__,**kw)
365 365
366 366 # policies for conflict resolution: two argument functions which return
367 367 # the value that will go in the new struct
368 368 preserve = lambda old,new: old
369 369 update = lambda old,new: new
370 370 add = lambda old,new: old + new
371 371 add_flip = lambda old,new: new + old # note change of order!
372 372 add_s = lambda old,new: old + ' ' + new
373 373
374 374 # default policy is to keep current keys when there's a conflict
375 375 conflict_solve = list2dict2(self.keys(), default = preserve)
376 376
377 377 # the conflict_solve dictionary is given by the user 'inverted': we
378 378 # need a name-function mapping, it comes as a function -> names
379 379 # dict. Make a local copy (b/c we'll make changes), replace user
380 380 # strings for the three builtin policies and invert it.
381 381 if __conflict_solve:
382 382 inv_conflict_solve_user = __conflict_solve.copy()
383 383 for name, func in [('preserve',preserve), ('update',update),
384 384 ('add',add), ('add_flip',add_flip),
385 385 ('add_s',add_s)]:
386 386 if name in inv_conflict_solve_user.keys():
387 387 inv_conflict_solve_user[func] = inv_conflict_solve_user[name]
388 388 del inv_conflict_solve_user[name]
389 389 conflict_solve.update(self.__dict_invert(inv_conflict_solve_user))
390 390 for key in data_dict:
391 391 if key not in self:
392 392 self[key] = data_dict[key]
393 393 else:
394 394 self[key] = conflict_solve[key](self[key],data_dict[key])
395 395
@@ -1,165 +1,165 b''
1 1 """Utilities to manipulate JSON objects.
2 2 """
3 3 #-----------------------------------------------------------------------------
4 # Copyright (C) 2010 The IPython Development Team
4 # Copyright (C) 2010-2011 The IPython Development Team
5 5 #
6 6 # Distributed under the terms of the BSD License. The full license is in
7 7 # the file COPYING.txt, distributed as part of this software.
8 8 #-----------------------------------------------------------------------------
9 9
10 10 #-----------------------------------------------------------------------------
11 11 # Imports
12 12 #-----------------------------------------------------------------------------
13 13 # stdlib
14 14 import re
15 15 import sys
16 16 import types
17 17 from datetime import datetime
18 18
19 19 from IPython.utils import py3compat
20 20 from IPython.utils import text
21 21 next_attr_name = '__next__' if py3compat.PY3 else 'next'
22 22
23 23 #-----------------------------------------------------------------------------
24 24 # Globals and constants
25 25 #-----------------------------------------------------------------------------
26 26
27 27 # timestamp formats
28 28 ISO8601="%Y-%m-%dT%H:%M:%S.%f"
29 29 ISO8601_PAT=re.compile(r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+$")
30 30
31 31 #-----------------------------------------------------------------------------
32 32 # Classes and functions
33 33 #-----------------------------------------------------------------------------
34 34
35 35 def rekey(dikt):
36 36 """Rekey a dict that has been forced to use str keys where there should be
37 37 ints by json."""
38 38 for k in dikt.iterkeys():
39 39 if isinstance(k, basestring):
40 40 ik=fk=None
41 41 try:
42 42 ik = int(k)
43 43 except ValueError:
44 44 try:
45 45 fk = float(k)
46 46 except ValueError:
47 47 continue
48 48 if ik is not None:
49 49 nk = ik
50 50 else:
51 51 nk = fk
52 52 if nk in dikt:
53 53 raise KeyError("already have key %r"%nk)
54 54 dikt[nk] = dikt.pop(k)
55 55 return dikt
56 56
57 57
58 58 def extract_dates(obj):
59 59 """extract ISO8601 dates from unpacked JSON"""
60 60 if isinstance(obj, dict):
61 61 obj = dict(obj) # don't clobber
62 62 for k,v in obj.iteritems():
63 63 obj[k] = extract_dates(v)
64 64 elif isinstance(obj, (list, tuple)):
65 65 obj = [ extract_dates(o) for o in obj ]
66 66 elif isinstance(obj, basestring):
67 67 if ISO8601_PAT.match(obj):
68 68 obj = datetime.strptime(obj, ISO8601)
69 69 return obj
70 70
71 71 def squash_dates(obj):
72 72 """squash datetime objects into ISO8601 strings"""
73 73 if isinstance(obj, dict):
74 74 obj = dict(obj) # don't clobber
75 75 for k,v in obj.iteritems():
76 76 obj[k] = squash_dates(v)
77 77 elif isinstance(obj, (list, tuple)):
78 78 obj = [ squash_dates(o) for o in obj ]
79 79 elif isinstance(obj, datetime):
80 80 obj = obj.strftime(ISO8601)
81 81 return obj
82 82
83 83 def date_default(obj):
84 84 """default function for packing datetime objects in JSON."""
85 85 if isinstance(obj, datetime):
86 86 return obj.strftime(ISO8601)
87 87 else:
88 88 raise TypeError("%r is not JSON serializable"%obj)
89 89
90 90
91 91
92 92 def json_clean(obj):
93 93 """Clean an object to ensure it's safe to encode in JSON.
94 94
95 95 Atomic, immutable objects are returned unmodified. Sets and tuples are
96 96 converted to lists, lists are copied and dicts are also copied.
97 97
98 98 Note: dicts whose keys could cause collisions upon encoding (such as a dict
99 99 with both the number 1 and the string '1' as keys) will cause a ValueError
100 100 to be raised.
101 101
102 102 Parameters
103 103 ----------
104 104 obj : any python object
105 105
106 106 Returns
107 107 -------
108 108 out : object
109 109
110 110 A version of the input which will not cause an encoding error when
111 111 encoded as JSON. Note that this function does not *encode* its inputs,
112 112 it simply sanitizes it so that there will be no encoding errors later.
113 113
114 114 Examples
115 115 --------
116 116 >>> json_clean(4)
117 117 4
118 118 >>> json_clean(range(10))
119 119 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
120 120 >>> json_clean(dict(x=1, y=2))
121 121 {'y': 2, 'x': 1}
122 122 >>> json_clean(dict(x=1, y=2, z=[1,2,3]))
123 123 {'y': 2, 'x': 1, 'z': [1, 2, 3]}
124 124 >>> json_clean(True)
125 125 True
126 126 """
127 127 # types that are 'atomic' and ok in json as-is. bool doesn't need to be
128 128 # listed explicitly because bools pass as int instances
129 129 atomic_ok = (unicode, int, float, types.NoneType)
130 130
131 131 # containers that we need to convert into lists
132 132 container_to_list = (tuple, set, types.GeneratorType)
133 133
134 134 if isinstance(obj, atomic_ok):
135 135 return obj
136 136
137 137 if isinstance(obj, bytes):
138 138 return obj.decode(text.getdefaultencoding(), 'replace')
139 139
140 140 if isinstance(obj, container_to_list) or (
141 141 hasattr(obj, '__iter__') and hasattr(obj, next_attr_name)):
142 142 obj = list(obj)
143 143
144 144 if isinstance(obj, list):
145 145 return [json_clean(x) for x in obj]
146 146
147 147 if isinstance(obj, dict):
148 148 # First, validate that the dict won't lose data in conversion due to
149 149 # key collisions after stringification. This can happen with keys like
150 150 # True and 'true' or 1 and '1', which collide in JSON.
151 151 nkeys = len(obj)
152 152 nkeys_collapsed = len(set(map(str, obj)))
153 153 if nkeys != nkeys_collapsed:
154 154 raise ValueError('dict can not be safely converted to JSON: '
155 155 'key collision would lead to dropped values')
156 156 # If all OK, proceed by making the new dict that will be json-safe
157 157 out = {}
158 158 for k,v in obj.iteritems():
159 159 out[str(k)] = json_clean(v)
160 160 return out
161 161
162 162 # If we get here, we don't know how to handle the object, so we just get
163 163 # its repr and return that. This will catch lambdas, open sockets, class
164 164 # objects, and any other complicated contraption that json can't encode
165 165 return repr(obj)
@@ -1,40 +1,40 b''
1 1 """Simple utility for building a list of local IPs using the socket module.
2 2 This module defines two constants:
3 3
4 4 LOCALHOST : The loopback interface, or the first interface that points to this
5 5 machine. It will *almost* always be '127.0.0.1'
6 6
7 7 LOCAL_IPS : A list of IP addresses, loopback first, that point to this machine.
8 8 """
9 9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2010 The IPython Development Team
10 # Copyright (C) 2010-2011 The IPython Development Team
11 11 #
12 12 # Distributed under the terms of the BSD License. The full license is in
13 13 # the file COPYING, distributed as part of this software.
14 14 #-----------------------------------------------------------------------------
15 15
16 16 #-----------------------------------------------------------------------------
17 17 # Imports
18 18 #-----------------------------------------------------------------------------
19 19
20 20 import socket
21 21
22 22 #-----------------------------------------------------------------------------
23 23 # Code
24 24 #-----------------------------------------------------------------------------
25 25
26 26 LOCAL_IPS = []
27 27 try:
28 28 LOCAL_IPS = socket.gethostbyname_ex('localhost')[2]
29 29 except socket.gaierror:
30 30 pass
31 31
32 32 try:
33 33 LOCAL_IPS.extend(socket.gethostbyname_ex(socket.gethostname())[2])
34 34 except socket.gaierror:
35 35 pass
36 36
37 37 # include all-interface aliases: 0.0.0.0 and ''
38 38 LOCAL_IPS.extend(['0.0.0.0', ''])
39 39
40 40 LOCALHOST = LOCAL_IPS[0]
@@ -1,177 +1,177 b''
1 1 # encoding: utf-8
2 2 # -*- test-case-name: IPython.kernel.test.test_newserialized -*-
3 3
4 4 """Refactored serialization classes and interfaces."""
5 5
6 6 __docformat__ = "restructuredtext en"
7 7
8 8 # Tell nose to skip this module
9 9 __test__ = {}
10 10
11 11 #-------------------------------------------------------------------------------
12 # Copyright (C) 2008 The IPython Development Team
12 # Copyright (C) 2008-2011 The IPython Development Team
13 13 #
14 14 # Distributed under the terms of the BSD License. The full license is in
15 15 # the file COPYING, distributed as part of this software.
16 16 #-------------------------------------------------------------------------------
17 17
18 18 #-------------------------------------------------------------------------------
19 19 # Imports
20 20 #-------------------------------------------------------------------------------
21 21
22 22 import sys
23 23 import cPickle as pickle
24 24
25 25 try:
26 26 import numpy
27 27 except ImportError:
28 28 numpy = None
29 29
30 30 class SerializationError(Exception):
31 31 pass
32 32
33 33 if sys.version_info[0] >= 3:
34 34 buffer = memoryview
35 35 py3k = True
36 36 else:
37 37 py3k = False
38 38 if sys.version_info[:2] <= (2,6):
39 39 memoryview = buffer
40 40
41 41 #-----------------------------------------------------------------------------
42 42 # Classes and functions
43 43 #-----------------------------------------------------------------------------
44 44
45 45 class ISerialized:
46 46
47 47 def getData():
48 48 """"""
49 49
50 50 def getDataSize(units=10.0**6):
51 51 """"""
52 52
53 53 def getTypeDescriptor():
54 54 """"""
55 55
56 56 def getMetadata():
57 57 """"""
58 58
59 59
60 60 class IUnSerialized:
61 61
62 62 def getObject():
63 63 """"""
64 64
65 65 class Serialized(object):
66 66
67 67 # implements(ISerialized)
68 68
69 69 def __init__(self, data, typeDescriptor, metadata={}):
70 70 self.data = data
71 71 self.typeDescriptor = typeDescriptor
72 72 self.metadata = metadata
73 73
74 74 def getData(self):
75 75 return self.data
76 76
77 77 def getDataSize(self, units=10.0**6):
78 78 return len(self.data)/units
79 79
80 80 def getTypeDescriptor(self):
81 81 return self.typeDescriptor
82 82
83 83 def getMetadata(self):
84 84 return self.metadata
85 85
86 86
87 87 class UnSerialized(object):
88 88
89 89 # implements(IUnSerialized)
90 90
91 91 def __init__(self, obj):
92 92 self.obj = obj
93 93
94 94 def getObject(self):
95 95 return self.obj
96 96
97 97
98 98 class SerializeIt(object):
99 99
100 100 # implements(ISerialized)
101 101
102 102 def __init__(self, unSerialized):
103 103 self.data = None
104 104 self.obj = unSerialized.getObject()
105 105 if numpy is not None and isinstance(self.obj, numpy.ndarray):
106 106 if len(self.obj.shape) == 0: # length 0 arrays are just pickled
107 107 self.typeDescriptor = 'pickle'
108 108 self.metadata = {}
109 109 else:
110 110 self.obj = numpy.ascontiguousarray(self.obj, dtype=None)
111 111 self.typeDescriptor = 'ndarray'
112 112 self.metadata = {'shape':self.obj.shape,
113 113 'dtype':self.obj.dtype.str}
114 114 elif isinstance(self.obj, bytes):
115 115 self.typeDescriptor = 'bytes'
116 116 self.metadata = {}
117 117 elif isinstance(self.obj, buffer):
118 118 self.typeDescriptor = 'buffer'
119 119 self.metadata = {}
120 120 else:
121 121 self.typeDescriptor = 'pickle'
122 122 self.metadata = {}
123 123 self._generateData()
124 124
125 125 def _generateData(self):
126 126 if self.typeDescriptor == 'ndarray':
127 127 self.data = buffer(self.obj)
128 128 elif self.typeDescriptor in ('bytes', 'buffer'):
129 129 self.data = self.obj
130 130 elif self.typeDescriptor == 'pickle':
131 131 self.data = pickle.dumps(self.obj, -1)
132 132 else:
133 133 raise SerializationError("Really wierd serialization error.")
134 134 del self.obj
135 135
136 136 def getData(self):
137 137 return self.data
138 138
139 139 def getDataSize(self, units=10.0**6):
140 140 return 1.0*len(self.data)/units
141 141
142 142 def getTypeDescriptor(self):
143 143 return self.typeDescriptor
144 144
145 145 def getMetadata(self):
146 146 return self.metadata
147 147
148 148
149 149 class UnSerializeIt(UnSerialized):
150 150
151 151 # implements(IUnSerialized)
152 152
153 153 def __init__(self, serialized):
154 154 self.serialized = serialized
155 155
156 156 def getObject(self):
157 157 typeDescriptor = self.serialized.getTypeDescriptor()
158 158 if numpy is not None and typeDescriptor == 'ndarray':
159 159 buf = self.serialized.getData()
160 160 if isinstance(buf, (bytes, buffer, memoryview)):
161 161 result = numpy.frombuffer(buf, dtype = self.serialized.metadata['dtype'])
162 162 else:
163 163 raise TypeError("Expected bytes or buffer/memoryview, but got %r"%type(buf))
164 164 result.shape = self.serialized.metadata['shape']
165 165 elif typeDescriptor == 'pickle':
166 166 result = pickle.loads(self.serialized.getData())
167 167 elif typeDescriptor in ('bytes', 'buffer'):
168 168 result = self.serialized.getData()
169 169 else:
170 170 raise SerializationError("Really wierd serialization error.")
171 171 return result
172 172
173 173 def serialize(obj):
174 174 return SerializeIt(UnSerialized(obj))
175 175
176 176 def unserialize(serialized):
177 177 return UnSerializeIt(serialized).getObject()
@@ -1,142 +1,142 b''
1 1 # encoding: utf-8
2 2 """
3 3 The IPython Core Notification Center.
4 4
5 5 See docs/source/development/notification_blueprint.txt for an overview of the
6 6 notification module.
7 7
8 8 Authors:
9 9
10 10 * Barry Wark
11 11 * Brian Granger
12 12 """
13 13
14 14 #-----------------------------------------------------------------------------
15 # Copyright (C) 2008-2009 The IPython Development Team
15 # Copyright (C) 2008-2011 The IPython Development Team
16 16 #
17 17 # Distributed under the terms of the BSD License. The full license is in
18 18 # the file COPYING, distributed as part of this software.
19 19 #-----------------------------------------------------------------------------
20 20
21 21 #-----------------------------------------------------------------------------
22 22 # Code
23 23 #-----------------------------------------------------------------------------
24 24
25 25
26 26 class NotificationError(Exception):
27 27 pass
28 28
29 29
30 30 class NotificationCenter(object):
31 31 """Synchronous notification center.
32 32
33 33 Examples
34 34 --------
35 35 Here is a simple example of how to use this::
36 36
37 37 import IPython.util.notification as notification
38 38 def callback(ntype, theSender, args={}):
39 39 print ntype,theSender,args
40 40
41 41 notification.sharedCenter.add_observer(callback, 'NOTIFICATION_TYPE', None)
42 42 notification.sharedCenter.post_notification('NOTIFICATION_TYPE', object()) # doctest:+ELLIPSIS
43 43 NOTIFICATION_TYPE ...
44 44 """
45 45 def __init__(self):
46 46 super(NotificationCenter, self).__init__()
47 47 self._init_observers()
48 48
49 49 def _init_observers(self):
50 50 """Initialize observer storage"""
51 51
52 52 self.registered_types = set() #set of types that are observed
53 53 self.registered_senders = set() #set of senders that are observed
54 54 self.observers = {} #map (type,sender) => callback (callable)
55 55
56 56 def post_notification(self, ntype, sender, *args, **kwargs):
57 57 """Post notification to all registered observers.
58 58
59 59 The registered callback will be called as::
60 60
61 61 callback(ntype, sender, *args, **kwargs)
62 62
63 63 Parameters
64 64 ----------
65 65 ntype : hashable
66 66 The notification type.
67 67 sender : hashable
68 68 The object sending the notification.
69 69 *args : tuple
70 70 The positional arguments to be passed to the callback.
71 71 **kwargs : dict
72 72 The keyword argument to be passed to the callback.
73 73
74 74 Notes
75 75 -----
76 76 * If no registered observers, performance is O(1).
77 77 * Notificaiton order is undefined.
78 78 * Notifications are posted synchronously.
79 79 """
80 80
81 81 if(ntype==None or sender==None):
82 82 raise NotificationError(
83 83 "Notification type and sender are required.")
84 84
85 85 # If there are no registered observers for the type/sender pair
86 86 if((ntype not in self.registered_types and
87 87 None not in self.registered_types) or
88 88 (sender not in self.registered_senders and
89 89 None not in self.registered_senders)):
90 90 return
91 91
92 92 for o in self._observers_for_notification(ntype, sender):
93 93 o(ntype, sender, *args, **kwargs)
94 94
95 95 def _observers_for_notification(self, ntype, sender):
96 96 """Find all registered observers that should recieve notification"""
97 97
98 98 keys = (
99 99 (ntype,sender),
100 100 (ntype, None),
101 101 (None, sender),
102 102 (None,None)
103 103 )
104 104
105 105 obs = set()
106 106 for k in keys:
107 107 obs.update(self.observers.get(k, set()))
108 108
109 109 return obs
110 110
111 111 def add_observer(self, callback, ntype, sender):
112 112 """Add an observer callback to this notification center.
113 113
114 114 The given callback will be called upon posting of notifications of
115 115 the given type/sender and will receive any additional arguments passed
116 116 to post_notification.
117 117
118 118 Parameters
119 119 ----------
120 120 callback : callable
121 121 The callable that will be called by :meth:`post_notification`
122 122 as ``callback(ntype, sender, *args, **kwargs)
123 123 ntype : hashable
124 124 The notification type. If None, all notifications from sender
125 125 will be posted.
126 126 sender : hashable
127 127 The notification sender. If None, all notifications of ntype
128 128 will be posted.
129 129 """
130 130 assert(callback != None)
131 131 self.registered_types.add(ntype)
132 132 self.registered_senders.add(sender)
133 133 self.observers.setdefault((ntype,sender), set()).add(callback)
134 134
135 135 def remove_all_observers(self):
136 136 """Removes all observers from this notification center"""
137 137
138 138 self._init_observers()
139 139
140 140
141 141
142 142 shared_center = NotificationCenter()
@@ -1,521 +1,521 b''
1 1 # encoding: utf-8
2 2 """
3 3 Utilities for path handling.
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2009 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 import os
18 18 import sys
19 19 import tempfile
20 20 import warnings
21 21 from hashlib import md5
22 22
23 23 import IPython
24 24 from IPython.utils.process import system
25 25 from IPython.utils.importstring import import_item
26 26 from IPython.utils import py3compat
27 27
28 28 #-----------------------------------------------------------------------------
29 29 # Code
30 30 #-----------------------------------------------------------------------------
31 31
32 32 fs_encoding = sys.getfilesystemencoding()
33 33
34 34 def _get_long_path_name(path):
35 35 """Dummy no-op."""
36 36 return path
37 37
38 38 def _writable_dir(path):
39 39 """Whether `path` is a directory, to which the user has write access."""
40 40 return os.path.isdir(path) and os.access(path, os.W_OK)
41 41
42 42 if sys.platform == 'win32':
43 43 def _get_long_path_name(path):
44 44 """Get a long path name (expand ~) on Windows using ctypes.
45 45
46 46 Examples
47 47 --------
48 48
49 49 >>> get_long_path_name('c:\\docume~1')
50 50 u'c:\\\\Documents and Settings'
51 51
52 52 """
53 53 try:
54 54 import ctypes
55 55 except ImportError:
56 56 raise ImportError('you need to have ctypes installed for this to work')
57 57 _GetLongPathName = ctypes.windll.kernel32.GetLongPathNameW
58 58 _GetLongPathName.argtypes = [ctypes.c_wchar_p, ctypes.c_wchar_p,
59 59 ctypes.c_uint ]
60 60
61 61 buf = ctypes.create_unicode_buffer(260)
62 62 rv = _GetLongPathName(path, buf, 260)
63 63 if rv == 0 or rv > 260:
64 64 return path
65 65 else:
66 66 return buf.value
67 67
68 68
69 69 def get_long_path_name(path):
70 70 """Expand a path into its long form.
71 71
72 72 On Windows this expands any ~ in the paths. On other platforms, it is
73 73 a null operation.
74 74 """
75 75 return _get_long_path_name(path)
76 76
77 77
78 78 def unquote_filename(name, win32=(sys.platform=='win32')):
79 79 """ On Windows, remove leading and trailing quotes from filenames.
80 80 """
81 81 if win32:
82 82 if name.startswith(("'", '"')) and name.endswith(("'", '"')):
83 83 name = name[1:-1]
84 84 return name
85 85
86 86
87 87 def get_py_filename(name, force_win32=None):
88 88 """Return a valid python filename in the current directory.
89 89
90 90 If the given name is not a file, it adds '.py' and searches again.
91 91 Raises IOError with an informative message if the file isn't found.
92 92
93 93 On Windows, apply Windows semantics to the filename. In particular, remove
94 94 any quoting that has been applied to it. This option can be forced for
95 95 testing purposes.
96 96 """
97 97
98 98 name = os.path.expanduser(name)
99 99 if force_win32 is None:
100 100 win32 = (sys.platform == 'win32')
101 101 else:
102 102 win32 = force_win32
103 103 name = unquote_filename(name, win32=win32)
104 104 if not os.path.isfile(name) and not name.endswith('.py'):
105 105 name += '.py'
106 106 if os.path.isfile(name):
107 107 return name
108 108 else:
109 109 raise IOError,'File `%s` not found.' % name
110 110
111 111
112 112 def filefind(filename, path_dirs=None):
113 113 """Find a file by looking through a sequence of paths.
114 114
115 115 This iterates through a sequence of paths looking for a file and returns
116 116 the full, absolute path of the first occurence of the file. If no set of
117 117 path dirs is given, the filename is tested as is, after running through
118 118 :func:`expandvars` and :func:`expanduser`. Thus a simple call::
119 119
120 120 filefind('myfile.txt')
121 121
122 122 will find the file in the current working dir, but::
123 123
124 124 filefind('~/myfile.txt')
125 125
126 126 Will find the file in the users home directory. This function does not
127 127 automatically try any paths, such as the cwd or the user's home directory.
128 128
129 129 Parameters
130 130 ----------
131 131 filename : str
132 132 The filename to look for.
133 133 path_dirs : str, None or sequence of str
134 134 The sequence of paths to look for the file in. If None, the filename
135 135 need to be absolute or be in the cwd. If a string, the string is
136 136 put into a sequence and the searched. If a sequence, walk through
137 137 each element and join with ``filename``, calling :func:`expandvars`
138 138 and :func:`expanduser` before testing for existence.
139 139
140 140 Returns
141 141 -------
142 142 Raises :exc:`IOError` or returns absolute path to file.
143 143 """
144 144
145 145 # If paths are quoted, abspath gets confused, strip them...
146 146 filename = filename.strip('"').strip("'")
147 147 # If the input is an absolute path, just check it exists
148 148 if os.path.isabs(filename) and os.path.isfile(filename):
149 149 return filename
150 150
151 151 if path_dirs is None:
152 152 path_dirs = ("",)
153 153 elif isinstance(path_dirs, basestring):
154 154 path_dirs = (path_dirs,)
155 155
156 156 for path in path_dirs:
157 157 if path == '.': path = os.getcwdu()
158 158 testname = expand_path(os.path.join(path, filename))
159 159 if os.path.isfile(testname):
160 160 return os.path.abspath(testname)
161 161
162 162 raise IOError("File %r does not exist in any of the search paths: %r" %
163 163 (filename, path_dirs) )
164 164
165 165
166 166 class HomeDirError(Exception):
167 167 pass
168 168
169 169
170 170 def get_home_dir():
171 171 """Return the closest possible equivalent to a 'home' directory.
172 172
173 173 * On POSIX, we try $HOME.
174 174 * On Windows we try:
175 175 - %HOMESHARE%
176 176 - %HOMEDRIVE\%HOMEPATH%
177 177 - %USERPROFILE%
178 178 - Registry hack for My Documents
179 179 - %HOME%: rare, but some people with unix-like setups may have defined it
180 180 * On Dos C:\
181 181
182 182 Currently only Posix and NT are implemented, a HomeDirError exception is
183 183 raised for all other OSes.
184 184 """
185 185
186 186 env = os.environ
187 187
188 188 # first, check py2exe distribution root directory for _ipython.
189 189 # This overrides all. Normally does not exist.
190 190
191 191 if hasattr(sys, "frozen"): #Is frozen by py2exe
192 192 if '\\library.zip\\' in IPython.__file__.lower():#libraries compressed to zip-file
193 193 root, rest = IPython.__file__.lower().split('library.zip')
194 194 else:
195 195 root=os.path.join(os.path.split(IPython.__file__)[0],"../../")
196 196 root=os.path.abspath(root).rstrip('\\')
197 197 if _writable_dir(os.path.join(root, '_ipython')):
198 198 os.environ["IPYKITROOT"] = root
199 199 return py3compat.cast_unicode(root, fs_encoding)
200 200
201 201 if os.name == 'posix':
202 202 # Linux, Unix, AIX, OS X
203 203 try:
204 204 homedir = env['HOME']
205 205 except KeyError:
206 206 # Last-ditch attempt at finding a suitable $HOME, on systems where
207 207 # it may not be defined in the environment but the system shell
208 208 # still knows it - reported once as:
209 209 # https://github.com/ipython/ipython/issues/154
210 210 from subprocess import Popen, PIPE
211 211 homedir = Popen('echo $HOME', shell=True,
212 212 stdout=PIPE).communicate()[0].strip()
213 213 if homedir:
214 214 return py3compat.cast_unicode(homedir, fs_encoding)
215 215 else:
216 216 raise HomeDirError('Undefined $HOME, IPython cannot proceed.')
217 217 else:
218 218 return py3compat.cast_unicode(homedir, fs_encoding)
219 219 elif os.name == 'nt':
220 220 # Now for win9x, XP, Vista, 7?
221 221 # For some strange reason all of these return 'nt' for os.name.
222 222 # First look for a network home directory. This will return the UNC
223 223 # path (\\server\\Users\%username%) not the mapped path (Z:\). This
224 224 # is needed when running IPython on cluster where all paths have to
225 225 # be UNC.
226 226 try:
227 227 homedir = env['HOMESHARE']
228 228 except KeyError:
229 229 pass
230 230 else:
231 231 if _writable_dir(homedir):
232 232 return py3compat.cast_unicode(homedir, fs_encoding)
233 233
234 234 # Now look for a local home directory
235 235 try:
236 236 homedir = os.path.join(env['HOMEDRIVE'],env['HOMEPATH'])
237 237 except KeyError:
238 238 pass
239 239 else:
240 240 if _writable_dir(homedir):
241 241 return py3compat.cast_unicode(homedir, fs_encoding)
242 242
243 243 # Now the users profile directory
244 244 try:
245 245 homedir = os.path.join(env['USERPROFILE'])
246 246 except KeyError:
247 247 pass
248 248 else:
249 249 if _writable_dir(homedir):
250 250 return py3compat.cast_unicode(homedir, fs_encoding)
251 251
252 252 # Use the registry to get the 'My Documents' folder.
253 253 try:
254 254 import _winreg as wreg
255 255 key = wreg.OpenKey(
256 256 wreg.HKEY_CURRENT_USER,
257 257 "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
258 258 )
259 259 homedir = wreg.QueryValueEx(key,'Personal')[0]
260 260 key.Close()
261 261 except:
262 262 pass
263 263 else:
264 264 if _writable_dir(homedir):
265 265 return py3compat.cast_unicode(homedir, fs_encoding)
266 266
267 267 # A user with a lot of unix tools in win32 may have defined $HOME.
268 268 # Try this as a last ditch option.
269 269 try:
270 270 homedir = env['HOME']
271 271 except KeyError:
272 272 pass
273 273 else:
274 274 if _writable_dir(homedir):
275 275 return py3compat.cast_unicode(homedir, fs_encoding)
276 276
277 277 # If all else fails, raise HomeDirError
278 278 raise HomeDirError('No valid home directory could be found')
279 279 elif os.name == 'dos':
280 280 # Desperate, may do absurd things in classic MacOS. May work under DOS.
281 281 return u'C:\\'
282 282 else:
283 283 raise HomeDirError('No valid home directory could be found for your OS')
284 284
285 285 def get_xdg_dir():
286 286 """Return the XDG_CONFIG_HOME, if it is defined and exists, else None.
287 287
288 288 This is only for posix (Linux,Unix,OS X, etc) systems.
289 289 """
290 290
291 291 env = os.environ
292 292
293 293 if os.name == 'posix':
294 294 # Linux, Unix, AIX, OS X
295 295 # use ~/.config if not set OR empty
296 296 xdg = env.get("XDG_CONFIG_HOME", None) or os.path.join(get_home_dir(), '.config')
297 297 if xdg and _writable_dir(xdg):
298 298 return py3compat.cast_unicode(xdg, fs_encoding)
299 299
300 300 return None
301 301
302 302
303 303 def get_ipython_dir():
304 304 """Get the IPython directory for this platform and user.
305 305
306 306 This uses the logic in `get_home_dir` to find the home directory
307 307 and then adds .ipython to the end of the path.
308 308 """
309 309
310 310 env = os.environ
311 311 pjoin = os.path.join
312 312
313 313
314 314 ipdir_def = '.ipython'
315 315 xdg_def = 'ipython'
316 316
317 317 home_dir = get_home_dir()
318 318 xdg_dir = get_xdg_dir()
319 319 # import pdb; pdb.set_trace() # dbg
320 320 ipdir = env.get('IPYTHON_DIR', env.get('IPYTHONDIR', None))
321 321 if ipdir is None:
322 322 # not set explicitly, use XDG_CONFIG_HOME or HOME
323 323 home_ipdir = pjoin(home_dir, ipdir_def)
324 324 if xdg_dir:
325 325 # use XDG, as long as the user isn't already
326 326 # using $HOME/.ipython and *not* XDG/ipython
327 327
328 328 xdg_ipdir = pjoin(xdg_dir, xdg_def)
329 329
330 330 if _writable_dir(xdg_ipdir) or not _writable_dir(home_ipdir):
331 331 ipdir = xdg_ipdir
332 332
333 333 if ipdir is None:
334 334 # not using XDG
335 335 ipdir = home_ipdir
336 336
337 337 ipdir = os.path.normpath(os.path.expanduser(ipdir))
338 338
339 339 if os.path.exists(ipdir) and not _writable_dir(ipdir):
340 340 # ipdir exists, but is not writable
341 341 warnings.warn("IPython dir '%s' is not a writable location,"
342 342 " using a temp directory."%ipdir)
343 343 ipdir = tempfile.mkdtemp()
344 344 elif not os.path.exists(ipdir):
345 345 parent = ipdir.rsplit(os.path.sep, 1)[0]
346 346 if not _writable_dir(parent):
347 347 # ipdir does not exist and parent isn't writable
348 348 warnings.warn("IPython parent '%s' is not a writable location,"
349 349 " using a temp directory."%parent)
350 350 ipdir = tempfile.mkdtemp()
351 351
352 352 return py3compat.cast_unicode(ipdir, fs_encoding)
353 353
354 354
355 355 def get_ipython_package_dir():
356 356 """Get the base directory where IPython itself is installed."""
357 357 ipdir = os.path.dirname(IPython.__file__)
358 358 return py3compat.cast_unicode(ipdir, fs_encoding)
359 359
360 360
361 361 def get_ipython_module_path(module_str):
362 362 """Find the path to an IPython module in this version of IPython.
363 363
364 364 This will always find the version of the module that is in this importable
365 365 IPython package. This will always return the path to the ``.py``
366 366 version of the module.
367 367 """
368 368 if module_str == 'IPython':
369 369 return os.path.join(get_ipython_package_dir(), '__init__.py')
370 370 mod = import_item(module_str)
371 371 the_path = mod.__file__.replace('.pyc', '.py')
372 372 the_path = the_path.replace('.pyo', '.py')
373 373 return py3compat.cast_unicode(the_path, fs_encoding)
374 374
375 375 def locate_profile(profile='default'):
376 376 """Find the path to the folder associated with a given profile.
377 377
378 378 I.e. find $IPYTHON_DIR/profile_whatever.
379 379 """
380 380 from IPython.core.profiledir import ProfileDir, ProfileDirError
381 381 try:
382 382 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
383 383 except ProfileDirError:
384 384 # IOError makes more sense when people are expecting a path
385 385 raise IOError("Couldn't find profile %r" % profile)
386 386 return pd.location
387 387
388 388 def expand_path(s):
389 389 """Expand $VARS and ~names in a string, like a shell
390 390
391 391 :Examples:
392 392
393 393 In [2]: os.environ['FOO']='test'
394 394
395 395 In [3]: expand_path('variable FOO is $FOO')
396 396 Out[3]: 'variable FOO is test'
397 397 """
398 398 # This is a pretty subtle hack. When expand user is given a UNC path
399 399 # on Windows (\\server\share$\%username%), os.path.expandvars, removes
400 400 # the $ to get (\\server\share\%username%). I think it considered $
401 401 # alone an empty var. But, we need the $ to remains there (it indicates
402 402 # a hidden share).
403 403 if os.name=='nt':
404 404 s = s.replace('$\\', 'IPYTHON_TEMP')
405 405 s = os.path.expandvars(os.path.expanduser(s))
406 406 if os.name=='nt':
407 407 s = s.replace('IPYTHON_TEMP', '$\\')
408 408 return s
409 409
410 410
411 411 def target_outdated(target,deps):
412 412 """Determine whether a target is out of date.
413 413
414 414 target_outdated(target,deps) -> 1/0
415 415
416 416 deps: list of filenames which MUST exist.
417 417 target: single filename which may or may not exist.
418 418
419 419 If target doesn't exist or is older than any file listed in deps, return
420 420 true, otherwise return false.
421 421 """
422 422 try:
423 423 target_time = os.path.getmtime(target)
424 424 except os.error:
425 425 return 1
426 426 for dep in deps:
427 427 dep_time = os.path.getmtime(dep)
428 428 if dep_time > target_time:
429 429 #print "For target",target,"Dep failed:",dep # dbg
430 430 #print "times (dep,tar):",dep_time,target_time # dbg
431 431 return 1
432 432 return 0
433 433
434 434
435 435 def target_update(target,deps,cmd):
436 436 """Update a target with a given command given a list of dependencies.
437 437
438 438 target_update(target,deps,cmd) -> runs cmd if target is outdated.
439 439
440 440 This is just a wrapper around target_outdated() which calls the given
441 441 command if target is outdated."""
442 442
443 443 if target_outdated(target,deps):
444 444 system(cmd)
445 445
446 446 def filehash(path):
447 447 """Make an MD5 hash of a file, ignoring any differences in line
448 448 ending characters."""
449 449 with open(path, "rU") as f:
450 450 return md5(py3compat.str_to_bytes(f.read())).hexdigest()
451 451
452 452 # If the config is unmodified from the default, we'll just delete it.
453 453 # These are consistent for 0.10.x, thankfully. We're not going to worry about
454 454 # older versions.
455 455 old_config_md5 = {'ipy_user_conf.py': 'fc108bedff4b9a00f91fa0a5999140d3',
456 456 'ipythonrc': '12a68954f3403eea2eec09dc8fe5a9b5'}
457 457
458 458 def check_for_old_config(ipython_dir=None):
459 459 """Check for old config files, and present a warning if they exist.
460 460
461 461 A link to the docs of the new config is included in the message.
462 462
463 463 This should mitigate confusion with the transition to the new
464 464 config system in 0.11.
465 465 """
466 466 if ipython_dir is None:
467 467 ipython_dir = get_ipython_dir()
468 468
469 469 old_configs = ['ipy_user_conf.py', 'ipythonrc', 'ipython_config.py']
470 470 warned = False
471 471 for cfg in old_configs:
472 472 f = os.path.join(ipython_dir, cfg)
473 473 if os.path.exists(f):
474 474 if filehash(f) == old_config_md5.get(cfg, ''):
475 475 os.unlink(f)
476 476 else:
477 477 warnings.warn("Found old IPython config file %r (modified by user)"%f)
478 478 warned = True
479 479
480 480 if warned:
481 481 warnings.warn("""
482 482 The IPython configuration system has changed as of 0.11, and these files will
483 483 be ignored. See http://ipython.github.com/ipython-doc/dev/config for details
484 484 of the new config system.
485 485 To start configuring IPython, do `ipython profile create`, and edit
486 486 `ipython_config.py` in <ipython_dir>/profile_default.
487 487 If you need to leave the old config files in place for an older version of
488 488 IPython and want to suppress this warning message, set
489 489 `c.InteractiveShellApp.ignore_old_config=True` in the new config.""")
490 490
491 491 def get_security_file(filename, profile='default'):
492 492 """Return the absolute path of a security file given by filename and profile
493 493
494 494 This allows users and developers to find security files without
495 495 knowledge of the IPython directory structure. The search path
496 496 will be ['.', profile.security_dir]
497 497
498 498 Parameters
499 499 ----------
500 500
501 501 filename : str
502 502 The file to be found. If it is passed as an absolute path, it will
503 503 simply be returned.
504 504 profile : str [default: 'default']
505 505 The name of the profile to search. Leaving this unspecified
506 506 The file to be found. If it is passed as an absolute path, fname will
507 507 simply be returned.
508 508
509 509 Returns
510 510 -------
511 511 Raises :exc:`IOError` if file not found or returns absolute path to file.
512 512 """
513 513 # import here, because profiledir also imports from utils.path
514 514 from IPython.core.profiledir import ProfileDir
515 515 try:
516 516 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
517 517 except Exception:
518 518 # will raise ProfileDirError if no such profile
519 519 raise IOError("Profile %r not found")
520 520 return filefind(filename, ['.', pd.security_dir])
521 521
@@ -1,153 +1,153 b''
1 1 # encoding: utf-8
2 2
3 3 """Pickle related utilities. Perhaps this should be called 'can'."""
4 4
5 5 __docformat__ = "restructuredtext en"
6 6
7 7 #-------------------------------------------------------------------------------
8 # Copyright (C) 2008 The IPython Development Team
8 # Copyright (C) 2008-2011 The IPython Development Team
9 9 #
10 10 # Distributed under the terms of the BSD License. The full license is in
11 11 # the file COPYING, distributed as part of this software.
12 12 #-------------------------------------------------------------------------------
13 13
14 14 #-------------------------------------------------------------------------------
15 15 # Imports
16 16 #-------------------------------------------------------------------------------
17 17
18 18 import copy
19 19 import sys
20 20 from types import FunctionType
21 21
22 22 import codeutil
23 23
24 24 #-------------------------------------------------------------------------------
25 25 # Classes
26 26 #-------------------------------------------------------------------------------
27 27
28 28
29 29 class CannedObject(object):
30 30 def __init__(self, obj, keys=[]):
31 31 self.keys = keys
32 32 self.obj = copy.copy(obj)
33 33 for key in keys:
34 34 setattr(self.obj, key, can(getattr(obj, key)))
35 35
36 36
37 37 def getObject(self, g=None):
38 38 if g is None:
39 39 g = globals()
40 40 for key in self.keys:
41 41 setattr(self.obj, key, uncan(getattr(self.obj, key), g))
42 42 return self.obj
43 43
44 44 class Reference(CannedObject):
45 45 """object for wrapping a remote reference by name."""
46 46 def __init__(self, name):
47 47 if not isinstance(name, basestring):
48 48 raise TypeError("illegal name: %r"%name)
49 49 self.name = name
50 50
51 51 def __repr__(self):
52 52 return "<Reference: %r>"%self.name
53 53
54 54 def getObject(self, g=None):
55 55 if g is None:
56 56 g = globals()
57 57 try:
58 58 return g[self.name]
59 59 except KeyError:
60 60 raise NameError("name %r is not defined"%self.name)
61 61
62 62
63 63 class CannedFunction(CannedObject):
64 64
65 65 def __init__(self, f):
66 66 self._checkType(f)
67 67 self.code = f.func_code
68 68 self.defaults = f.func_defaults
69 69 self.module = f.__module__ or '__main__'
70 70 self.__name__ = f.__name__
71 71
72 72 def _checkType(self, obj):
73 73 assert isinstance(obj, FunctionType), "Not a function type"
74 74
75 75 def getObject(self, g=None):
76 76 # try to load function back into its module:
77 77 if not self.module.startswith('__'):
78 78 try:
79 79 __import__(self.module)
80 80 except ImportError:
81 81 pass
82 82 else:
83 83 g = sys.modules[self.module].__dict__
84 84
85 85 if g is None:
86 86 g = globals()
87 87 newFunc = FunctionType(self.code, g, self.__name__, self.defaults)
88 88 return newFunc
89 89
90 90 #-------------------------------------------------------------------------------
91 91 # Functions
92 92 #-------------------------------------------------------------------------------
93 93
94 94 def can(obj):
95 95 # import here to prevent module-level circular imports
96 96 from IPython.parallel import dependent
97 97 if isinstance(obj, dependent):
98 98 keys = ('f','df')
99 99 return CannedObject(obj, keys=keys)
100 100 elif isinstance(obj, FunctionType):
101 101 return CannedFunction(obj)
102 102 elif isinstance(obj,dict):
103 103 return canDict(obj)
104 104 elif isinstance(obj, (list,tuple)):
105 105 return canSequence(obj)
106 106 else:
107 107 return obj
108 108
109 109 def canDict(obj):
110 110 if isinstance(obj, dict):
111 111 newobj = {}
112 112 for k, v in obj.iteritems():
113 113 newobj[k] = can(v)
114 114 return newobj
115 115 else:
116 116 return obj
117 117
118 118 def canSequence(obj):
119 119 if isinstance(obj, (list, tuple)):
120 120 t = type(obj)
121 121 return t([can(i) for i in obj])
122 122 else:
123 123 return obj
124 124
125 125 def uncan(obj, g=None):
126 126 if isinstance(obj, CannedObject):
127 127 return obj.getObject(g)
128 128 elif isinstance(obj,dict):
129 129 return uncanDict(obj, g)
130 130 elif isinstance(obj, (list,tuple)):
131 131 return uncanSequence(obj, g)
132 132 else:
133 133 return obj
134 134
135 135 def uncanDict(obj, g=None):
136 136 if isinstance(obj, dict):
137 137 newobj = {}
138 138 for k, v in obj.iteritems():
139 139 newobj[k] = uncan(v,g)
140 140 return newobj
141 141 else:
142 142 return obj
143 143
144 144 def uncanSequence(obj, g=None):
145 145 if isinstance(obj, (list, tuple)):
146 146 t = type(obj)
147 147 return t([uncan(i,g) for i in obj])
148 148 else:
149 149 return obj
150 150
151 151
152 152 def rebindFunctionGlobals(f, glbls):
153 153 return FunctionType(f.func_code, glbls)
@@ -1,147 +1,147 b''
1 1 # encoding: utf-8
2 2 """
3 3 Utilities for working with external processes.
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2009 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16 from __future__ import print_function
17 17
18 18 # Stdlib
19 19 import os
20 20 import sys
21 21 import shlex
22 22
23 23 # Our own
24 24 if sys.platform == 'win32':
25 25 from ._process_win32 import _find_cmd, system, getoutput, AvoidUNCPath
26 26 else:
27 27 from ._process_posix import _find_cmd, system, getoutput
28 28
29 29 from ._process_common import getoutputerror
30 30 from IPython.utils import py3compat
31 31
32 32 #-----------------------------------------------------------------------------
33 33 # Code
34 34 #-----------------------------------------------------------------------------
35 35
36 36
37 37 class FindCmdError(Exception):
38 38 pass
39 39
40 40
41 41 def find_cmd(cmd):
42 42 """Find absolute path to executable cmd in a cross platform manner.
43 43
44 44 This function tries to determine the full path to a command line program
45 45 using `which` on Unix/Linux/OS X and `win32api` on Windows. Most of the
46 46 time it will use the version that is first on the users `PATH`. If
47 47 cmd is `python` return `sys.executable`.
48 48
49 49 Warning, don't use this to find IPython command line programs as there
50 50 is a risk you will find the wrong one. Instead find those using the
51 51 following code and looking for the application itself::
52 52
53 53 from IPython.utils.path import get_ipython_module_path
54 54 from IPython.utils.process import pycmd2argv
55 55 argv = pycmd2argv(get_ipython_module_path('IPython.frontend.terminal.ipapp'))
56 56
57 57 Parameters
58 58 ----------
59 59 cmd : str
60 60 The command line program to look for.
61 61 """
62 62 if cmd == 'python':
63 63 return os.path.abspath(sys.executable)
64 64 try:
65 65 path = _find_cmd(cmd).rstrip()
66 66 except OSError:
67 67 raise FindCmdError('command could not be found: %s' % cmd)
68 68 # which returns empty if not found
69 69 if path == '':
70 70 raise FindCmdError('command could not be found: %s' % cmd)
71 71 return os.path.abspath(path)
72 72
73 73
74 74 def pycmd2argv(cmd):
75 75 r"""Take the path of a python command and return a list (argv-style).
76 76
77 77 This only works on Python based command line programs and will find the
78 78 location of the ``python`` executable using ``sys.executable`` to make
79 79 sure the right version is used.
80 80
81 81 For a given path ``cmd``, this returns [cmd] if cmd's extension is .exe,
82 82 .com or .bat, and [, cmd] otherwise.
83 83
84 84 Parameters
85 85 ----------
86 86 cmd : string
87 87 The path of the command.
88 88
89 89 Returns
90 90 -------
91 91 argv-style list.
92 92 """
93 93 ext = os.path.splitext(cmd)[1]
94 94 if ext in ['.exe', '.com', '.bat']:
95 95 return [cmd]
96 96 else:
97 97 if sys.platform == 'win32':
98 98 # The -u option here turns on unbuffered output, which is required
99 99 # on Win32 to prevent wierd conflict and problems with Twisted.
100 100 # Also, use sys.executable to make sure we are picking up the
101 101 # right python exe.
102 102 return [sys.executable, '-u', cmd]
103 103 else:
104 104 return [sys.executable, cmd]
105 105
106 106
107 107 def arg_split(s, posix=False):
108 108 """Split a command line's arguments in a shell-like manner.
109 109
110 110 This is a modified version of the standard library's shlex.split()
111 111 function, but with a default of posix=False for splitting, so that quotes
112 112 in inputs are respected."""
113 113
114 114 # Unfortunately, python's shlex module is buggy with unicode input:
115 115 # http://bugs.python.org/issue1170
116 116 # At least encoding the input when it's unicode seems to help, but there
117 117 # may be more problems lurking. Apparently this is fixed in python3.
118 118 is_unicode = False
119 119 if (not py3compat.PY3) and isinstance(s, unicode):
120 120 is_unicode = True
121 121 s = s.encode('utf-8')
122 122 lex = shlex.shlex(s, posix=posix)
123 123 lex.whitespace_split = True
124 124 tokens = list(lex)
125 125 if is_unicode:
126 126 # Convert the tokens back to unicode.
127 127 tokens = [x.decode('utf-8') for x in tokens]
128 128 return tokens
129 129
130 130
131 131 def abbrev_cwd():
132 132 """ Return abbreviated version of cwd, e.g. d:mydir """
133 133 cwd = os.getcwdu().replace('\\','/')
134 134 drivepart = ''
135 135 tail = cwd
136 136 if sys.platform == 'win32':
137 137 if len(cwd) < 4:
138 138 return cwd
139 139 drivepart,tail = os.path.splitdrive(cwd)
140 140
141 141
142 142 parts = tail.split('/')
143 143 if len(parts) > 2:
144 144 tail = '/'.join(parts[-2:])
145 145
146 146 return (drivepart + (
147 147 cwd == '/' and '/' or tail))
@@ -1,191 +1,191 b''
1 1 # encoding: utf-8
2 2 """
3 3 Utilities for getting information about IPython and the system it's running in.
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2009 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 import os
18 18 import platform
19 19 import pprint
20 20 import sys
21 21 import subprocess
22 22
23 23 from ConfigParser import ConfigParser
24 24
25 25 from IPython.core import release
26 26 from IPython.utils import py3compat
27 27
28 28 #-----------------------------------------------------------------------------
29 29 # Globals
30 30 #-----------------------------------------------------------------------------
31 31 COMMIT_INFO_FNAME = '.git_commit_info.ini'
32 32
33 33 #-----------------------------------------------------------------------------
34 34 # Code
35 35 #-----------------------------------------------------------------------------
36 36
37 37 def pkg_commit_hash(pkg_path):
38 38 """Get short form of commit hash given directory `pkg_path`
39 39
40 40 There should be a file called 'COMMIT_INFO.txt' in `pkg_path`. This is a
41 41 file in INI file format, with at least one section: ``commit hash``, and two
42 42 variables ``archive_subst_hash`` and ``install_hash``. The first has a
43 43 substitution pattern in it which may have been filled by the execution of
44 44 ``git archive`` if this is an archive generated that way. The second is
45 45 filled in by the installation, if the installation is from a git archive.
46 46
47 47 We get the commit hash from (in order of preference):
48 48
49 49 * A substituted value in ``archive_subst_hash``
50 50 * A written commit hash value in ``install_hash`
51 51 * git output, if we are in a git repository
52 52
53 53 If all these fail, we return a not-found placeholder tuple
54 54
55 55 Parameters
56 56 ----------
57 57 pkg_path : str
58 58 directory containing package
59 59
60 60 Returns
61 61 -------
62 62 hash_from : str
63 63 Where we got the hash from - description
64 64 hash_str : str
65 65 short form of hash
66 66 """
67 67 # Try and get commit from written commit text file
68 68 pth = os.path.join(pkg_path, COMMIT_INFO_FNAME)
69 69 if not os.path.isfile(pth):
70 70 raise IOError('Missing commit info file %s' % pth)
71 71 cfg_parser = ConfigParser()
72 72 cfg_parser.read(pth)
73 73 try:
74 74 archive_subst = cfg_parser.get('commit hash', 'archive_subst_hash')
75 75 except Exception:
76 76 pass
77 77 else:
78 78 if not archive_subst.startswith('$Format'): # it has been substituted
79 79 return 'archive substitution', archive_subst
80 80 install_subst = cfg_parser.get('commit hash', 'install_hash')
81 81 if install_subst != '':
82 82 return 'installation', install_subst
83 83 # maybe we are in a repository
84 84 proc = subprocess.Popen('git rev-parse --short HEAD',
85 85 stdout=subprocess.PIPE,
86 86 stderr=subprocess.PIPE,
87 87 cwd=pkg_path, shell=True)
88 88 repo_commit, _ = proc.communicate()
89 89 if repo_commit:
90 90 return 'repository', repo_commit.strip()
91 91 return '(none found)', '<not found>'
92 92
93 93
94 94 def pkg_info(pkg_path):
95 95 """Return dict describing the context of this package
96 96
97 97 Parameters
98 98 ----------
99 99 pkg_path : str
100 100 path containing __init__.py for package
101 101
102 102 Returns
103 103 -------
104 104 context : dict
105 105 with named parameters of interest
106 106 """
107 107 src, hsh = pkg_commit_hash(pkg_path)
108 108 return dict(
109 109 ipython_version=release.version,
110 110 ipython_path=pkg_path,
111 111 commit_source=src,
112 112 commit_hash=hsh,
113 113 sys_version=sys.version,
114 114 sys_executable=sys.executable,
115 115 sys_platform=sys.platform,
116 116 platform=platform.platform(),
117 117 os_name=os.name,
118 118 )
119 119
120 120
121 121 @py3compat.doctest_refactor_print
122 122 def sys_info():
123 123 """Return useful information about IPython and the system, as a string.
124 124
125 125 Example
126 126 -------
127 127 In [2]: print sys_info()
128 128 {'commit_hash': '144fdae', # random
129 129 'commit_source': 'repository',
130 130 'ipython_path': '/home/fperez/usr/lib/python2.6/site-packages/IPython',
131 131 'ipython_version': '0.11.dev',
132 132 'os_name': 'posix',
133 133 'platform': 'Linux-2.6.35-22-generic-i686-with-Ubuntu-10.10-maverick',
134 134 'sys_executable': '/usr/bin/python',
135 135 'sys_platform': 'linux2',
136 136 'sys_version': '2.6.6 (r266:84292, Sep 15 2010, 15:52:39) \\n[GCC 4.4.5]'}
137 137 """
138 138 p = os.path
139 139 path = p.dirname(p.abspath(p.join(__file__, '..')))
140 140 return pprint.pformat(pkg_info(path))
141 141
142 142
143 143 def _num_cpus_unix():
144 144 """Return the number of active CPUs on a Unix system."""
145 145 return os.sysconf("SC_NPROCESSORS_ONLN")
146 146
147 147
148 148 def _num_cpus_darwin():
149 149 """Return the number of active CPUs on a Darwin system."""
150 150 p = subprocess.Popen(['sysctl','-n','hw.ncpu'],stdout=subprocess.PIPE)
151 151 return p.stdout.read()
152 152
153 153
154 154 def _num_cpus_windows():
155 155 """Return the number of active CPUs on a Windows system."""
156 156 return os.environ.get("NUMBER_OF_PROCESSORS")
157 157
158 158
159 159 def num_cpus():
160 160 """Return the effective number of CPUs in the system as an integer.
161 161
162 162 This cross-platform function makes an attempt at finding the total number of
163 163 available CPUs in the system, as returned by various underlying system and
164 164 python calls.
165 165
166 166 If it can't find a sensible answer, it returns 1 (though an error *may* make
167 167 it return a large positive number that's actually incorrect).
168 168 """
169 169
170 170 # Many thanks to the Parallel Python project (http://www.parallelpython.com)
171 171 # for the names of the keys we needed to look up for this function. This
172 172 # code was inspired by their equivalent function.
173 173
174 174 ncpufuncs = {'Linux':_num_cpus_unix,
175 175 'Darwin':_num_cpus_darwin,
176 176 'Windows':_num_cpus_windows,
177 177 # On Vista, python < 2.5.2 has a bug and returns 'Microsoft'
178 178 # See http://bugs.python.org/issue1082 for details.
179 179 'Microsoft':_num_cpus_windows,
180 180 }
181 181
182 182 ncpufunc = ncpufuncs.get(platform.system(),
183 183 # default to unix version (Solaris, AIX, etc)
184 184 _num_cpus_unix)
185 185
186 186 try:
187 187 ncpus = max(1,int(ncpufunc()))
188 188 except:
189 189 ncpus = 1
190 190 return ncpus
191 191
@@ -1,69 +1,69 b''
1 1 # encoding: utf-8
2 2 """
3 3 Context managers for adding things to sys.path temporarily.
4 4
5 5 Authors:
6 6
7 7 * Brian Granger
8 8 """
9 9
10 10 #-----------------------------------------------------------------------------
11 # Copyright (C) 2008-2009 The IPython Development Team
11 # Copyright (C) 2008-2011 The IPython Development Team
12 12 #
13 13 # Distributed under the terms of the BSD License. The full license is in
14 14 # the file COPYING, distributed as part of this software.
15 15 #-----------------------------------------------------------------------------
16 16
17 17 #-----------------------------------------------------------------------------
18 18 # Imports
19 19 #-----------------------------------------------------------------------------
20 20
21 21 import sys
22 22
23 23 #-----------------------------------------------------------------------------
24 24 # Code
25 25 #-----------------------------------------------------------------------------
26 26
27 27 class appended_to_syspath(object):
28 28 """A context for appending a directory to sys.path for a second."""
29 29
30 30 def __init__(self, dir):
31 31 self.dir = dir
32 32
33 33 def __enter__(self):
34 34 if self.dir not in sys.path:
35 35 sys.path.append(self.dir)
36 36 self.added = True
37 37 else:
38 38 self.added = False
39 39
40 40 def __exit__(self, type, value, traceback):
41 41 if self.added:
42 42 try:
43 43 sys.path.remove(self.dir)
44 44 except ValueError:
45 45 pass
46 46 # Returning False causes any exceptions to be re-raised.
47 47 return False
48 48
49 49 class prepended_to_syspath(object):
50 50 """A context for prepending a directory to sys.path for a second."""
51 51
52 52 def __init__(self, dir):
53 53 self.dir = dir
54 54
55 55 def __enter__(self):
56 56 if self.dir not in sys.path:
57 57 sys.path.insert(0,self.dir)
58 58 self.added = True
59 59 else:
60 60 self.added = False
61 61
62 62 def __exit__(self, type, value, traceback):
63 63 if self.added:
64 64 try:
65 65 sys.path.remove(self.dir)
66 66 except ValueError:
67 67 pass
68 68 # Returning False causes any exceptions to be re-raised.
69 69 return False
@@ -1,162 +1,162 b''
1 1 # encoding: utf-8
2 2 """
3 3 Utilities for working with terminals.
4 4
5 5 Authors:
6 6
7 7 * Brian E. Granger
8 8 * Fernando Perez
9 9 * Alexander Belchenko (e-mail: bialix AT ukr.net)
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 15 # Distributed under the terms of the BSD License. The full license is in
16 16 # the file COPYING, distributed as part of this software.
17 17 #-----------------------------------------------------------------------------
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Imports
21 21 #-----------------------------------------------------------------------------
22 22
23 23 import os
24 24 import struct
25 25 import sys
26 26 import warnings
27 27
28 28 #-----------------------------------------------------------------------------
29 29 # Code
30 30 #-----------------------------------------------------------------------------
31 31
32 32 # This variable is part of the expected API of the module:
33 33 ignore_termtitle = True
34 34
35 35
36 36 def _term_clear():
37 37 pass
38 38
39 39
40 40 if os.name == 'posix':
41 41 def _term_clear():
42 42 os.system('clear')
43 43
44 44
45 45 if sys.platform == 'win32':
46 46 def _term_clear():
47 47 os.system('cls')
48 48
49 49
50 50 def term_clear():
51 51 _term_clear()
52 52
53 53
54 54 def toggle_set_term_title(val):
55 55 """Control whether set_term_title is active or not.
56 56
57 57 set_term_title() allows writing to the console titlebar. In embedded
58 58 widgets this can cause problems, so this call can be used to toggle it on
59 59 or off as needed.
60 60
61 61 The default state of the module is for the function to be disabled.
62 62
63 63 Parameters
64 64 ----------
65 65 val : bool
66 66 If True, set_term_title() actually writes to the terminal (using the
67 67 appropriate platform-specific module). If False, it is a no-op.
68 68 """
69 69 global ignore_termtitle
70 70 ignore_termtitle = not(val)
71 71
72 72
73 73 def _set_term_title(*args,**kw):
74 74 """Dummy no-op."""
75 75 pass
76 76
77 77
78 78 def _set_term_title_xterm(title):
79 79 """ Change virtual terminal title in xterm-workalikes """
80 80 sys.stdout.write('\033]0;%s\007' % title)
81 81
82 82 if os.name == 'posix':
83 83 TERM = os.environ.get('TERM','')
84 84 if (TERM == 'xterm') or (TERM == 'xterm-color'):
85 85 _set_term_title = _set_term_title_xterm
86 86
87 87
88 88 if sys.platform == 'win32':
89 89 try:
90 90 import ctypes
91 91
92 92 SetConsoleTitleW = ctypes.windll.kernel32.SetConsoleTitleW
93 93 SetConsoleTitleW.argtypes = [ctypes.c_wchar_p]
94 94
95 95 def _set_term_title(title):
96 96 """Set terminal title using ctypes to access the Win32 APIs."""
97 97 SetConsoleTitleW(title)
98 98 except ImportError:
99 99 def _set_term_title(title):
100 100 """Set terminal title using the 'title' command."""
101 101 global ignore_termtitle
102 102
103 103 try:
104 104 # Cannot be on network share when issuing system commands
105 105 curr = os.getcwdu()
106 106 os.chdir("C:")
107 107 ret = os.system("title " + title)
108 108 finally:
109 109 os.chdir(curr)
110 110 if ret:
111 111 # non-zero return code signals error, don't try again
112 112 ignore_termtitle = True
113 113
114 114
115 115 def set_term_title(title):
116 116 """Set terminal title using the necessary platform-dependent calls."""
117 117 if ignore_termtitle:
118 118 return
119 119 _set_term_title(title)
120 120
121 121
122 122 def freeze_term_title():
123 123 warnings.warn("This function is deprecated, use toggle_set_term_title()")
124 124 global ignore_termtitle
125 125 ignore_termtitle = True
126 126
127 127
128 128 def get_terminal_size(defaultx=80, defaulty=25):
129 129 return defaultx, defaulty
130 130
131 131
132 132 if sys.platform == 'win32':
133 133 def get_terminal_size(defaultx=80, defaulty=25):
134 134 """Return size of current terminal console.
135 135
136 136 This function try to determine actual size of current working
137 137 console window and return tuple (sizex, sizey) if success,
138 138 or default size (defaultx, defaulty) otherwise.
139 139
140 140 Dependencies: ctypes should be installed.
141 141
142 142 Author: Alexander Belchenko (e-mail: bialix AT ukr.net)
143 143 """
144 144 try:
145 145 import ctypes
146 146 except ImportError:
147 147 return defaultx, defaulty
148 148
149 149 h = ctypes.windll.kernel32.GetStdHandle(-11)
150 150 csbi = ctypes.create_string_buffer(22)
151 151 res = ctypes.windll.kernel32.GetConsoleScreenBufferInfo(h, csbi)
152 152
153 153 if res:
154 154 (bufx, bufy, curx, cury, wattr,
155 155 left, top, right, bottom, maxx, maxy) = struct.unpack(
156 156 "hhhhHhhhhhh", csbi.raw)
157 157 sizex = right - left + 1
158 158 sizey = bottom - top + 1
159 159 return (sizex, sizey)
160 160 else:
161 161 return (defaultx, defaulty)
162 162
@@ -1,75 +1,75 b''
1 1 # encoding: utf-8
2 2 """Tests for io.py"""
3 3
4 4 #-----------------------------------------------------------------------------
5 # Copyright (C) 2008 The IPython Development Team
5 # Copyright (C) 2008-2011 The IPython Development Team
6 6 #
7 7 # Distributed under the terms of the BSD License. The full license is in
8 8 # the file COPYING, distributed as part of this software.
9 9 #-----------------------------------------------------------------------------
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Imports
13 13 #-----------------------------------------------------------------------------
14 14
15 15 import sys
16 16
17 17 from StringIO import StringIO
18 18 from subprocess import Popen, PIPE
19 19
20 20 import nose.tools as nt
21 21
22 22 from IPython.testing import decorators as dec
23 23 from IPython.utils.io import Tee
24 24 from IPython.utils.py3compat import doctest_refactor_print
25 25
26 26 #-----------------------------------------------------------------------------
27 27 # Tests
28 28 #-----------------------------------------------------------------------------
29 29
30 30
31 31 def test_tee_simple():
32 32 "Very simple check with stdout only"
33 33 chan = StringIO()
34 34 text = 'Hello'
35 35 tee = Tee(chan, channel='stdout')
36 36 print >> chan, text
37 37 nt.assert_equal(chan.getvalue(), text+"\n")
38 38
39 39
40 40 class TeeTestCase(dec.ParametricTestCase):
41 41
42 42 def tchan(self, channel, check='close'):
43 43 trap = StringIO()
44 44 chan = StringIO()
45 45 text = 'Hello'
46 46
47 47 std_ori = getattr(sys, channel)
48 48 setattr(sys, channel, trap)
49 49
50 50 tee = Tee(chan, channel=channel)
51 51 print >> chan, text,
52 52 setattr(sys, channel, std_ori)
53 53 trap_val = trap.getvalue()
54 54 nt.assert_equals(chan.getvalue(), text)
55 55 if check=='close':
56 56 tee.close()
57 57 else:
58 58 del tee
59 59
60 60 def test(self):
61 61 for chan in ['stdout', 'stderr']:
62 62 for check in ['close', 'del']:
63 63 yield self.tchan(chan, check)
64 64
65 65 def test_io_init():
66 66 """Test that io.stdin/out/err exist at startup"""
67 67 for name in ('stdin', 'stdout', 'stderr'):
68 68 cmd = doctest_refactor_print("from IPython.utils import io;print io.%s.__class__"%name)
69 69 p = Popen([sys.executable, '-c', cmd],
70 70 stdout=PIPE)
71 71 p.wait()
72 72 classname = p.stdout.read().strip().decode('ascii')
73 73 # __class__ is a reference to the class object in Python 3, so we can't
74 74 # just test for string equality.
75 75 assert 'IPython.utils.io.IOStream' in classname, classname
@@ -1,71 +1,71 b''
1 1 """Test suite for our JSON utilities.
2 2 """
3 3 #-----------------------------------------------------------------------------
4 # Copyright (C) 2010 The IPython Development Team
4 # Copyright (C) 2010-2011 The IPython Development Team
5 5 #
6 6 # Distributed under the terms of the BSD License. The full license is in
7 7 # the file COPYING.txt, distributed as part of this software.
8 8 #-----------------------------------------------------------------------------
9 9
10 10 #-----------------------------------------------------------------------------
11 11 # Imports
12 12 #-----------------------------------------------------------------------------
13 13 # stdlib
14 14 import json
15 15
16 16 # third party
17 17 import nose.tools as nt
18 18
19 19 # our own
20 20 from ..jsonutil import json_clean
21 21
22 22 #-----------------------------------------------------------------------------
23 23 # Test functions
24 24 #-----------------------------------------------------------------------------
25 25
26 26 def test():
27 27 # list of input/expected output. Use None for the expected output if it
28 28 # can be the same as the input.
29 29 pairs = [(1, None), # start with scalars
30 30 (1.0, None),
31 31 ('a', None),
32 32 (True, None),
33 33 (False, None),
34 34 (None, None),
35 35 # complex numbers for now just go to strings, as otherwise they
36 36 # are unserializable
37 37 (1j, '1j'),
38 38 # Containers
39 39 ([1, 2], None),
40 40 ((1, 2), [1, 2]),
41 41 (set([1, 2]), [1, 2]),
42 42 (dict(x=1), None),
43 43 ({'x': 1, 'y':[1,2,3], '1':'int'}, None),
44 44 # More exotic objects
45 45 ((x for x in range(3)), [0, 1, 2]),
46 46 (iter([1, 2]), [1, 2]),
47 47 ]
48 48
49 49 for val, jval in pairs:
50 50 if jval is None:
51 51 jval = val
52 52 out = json_clean(val)
53 53 # validate our cleanup
54 54 nt.assert_equal(out, jval)
55 55 # and ensure that what we return, indeed encodes cleanly
56 56 json.loads(json.dumps(out))
57 57
58 58
59 59 def test_lambda():
60 60 jc = json_clean(lambda : 1)
61 61 nt.assert_true(jc.startswith('<function <lambda> at '))
62 62 json.dumps(jc)
63 63
64 64
65 65 def test_exception():
66 66 bad_dicts = [{1:'number', '1':'string'},
67 67 {True:'bool', 'True':'string'},
68 68 ]
69 69 for d in bad_dicts:
70 70 nt.assert_raises(ValueError, json_clean, d)
71 71
@@ -1,133 +1,133 b''
1 1 # encoding: utf-8
2 2 """Tests for IPython.utils.path.py"""
3 3
4 4 #-----------------------------------------------------------------------------
5 # Copyright (C) 2008 The IPython Development Team
5 # Copyright (C) 2008-2011 The IPython Development Team
6 6 #
7 7 # Distributed under the terms of the BSD License. The full license is in
8 8 # the file COPYING, distributed as part of this software.
9 9 #-----------------------------------------------------------------------------
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Imports
13 13 #-----------------------------------------------------------------------------
14 14
15 15 from __future__ import with_statement
16 16
17 17 import os
18 18 import shutil
19 19 import sys
20 20 import tempfile
21 21 import StringIO
22 22
23 23 from os.path import join, abspath, split
24 24
25 25 import nose.tools as nt
26 26
27 27 from nose import with_setup
28 28
29 29 import IPython
30 30 from IPython.testing import decorators as dec
31 31 from IPython.testing.decorators import skip_if_not_win32, skip_win32
32 32 from IPython.testing.tools import make_tempfile
33 33 from IPython.utils import path, io
34 34 from IPython.utils import py3compat
35 35
36 36 import IPython.utils.module_paths as mp
37 37
38 38 env = os.environ
39 39 TEST_FILE_PATH = split(abspath(__file__))[0]
40 40 TMP_TEST_DIR = tempfile.mkdtemp()
41 41 #
42 42 # Setup/teardown functions/decorators
43 43 #
44 44
45 45 old_syspath = sys.path
46 46 sys.path = [TMP_TEST_DIR]
47 47
48 48 def make_empty_file(fname):
49 49 f = open(fname, 'w')
50 50 f.close()
51 51
52 52
53 53 def setup():
54 54 """Setup testenvironment for the module:
55 55
56 56 """
57 57 # Do not mask exceptions here. In particular, catching WindowsError is a
58 58 # problem because that exception is only defined on Windows...
59 59 os.makedirs(join(TMP_TEST_DIR, "xmod"))
60 60 os.makedirs(join(TMP_TEST_DIR, "nomod"))
61 61 make_empty_file(join(TMP_TEST_DIR, "xmod/__init__.py"))
62 62 make_empty_file(join(TMP_TEST_DIR, "xmod/sub.py"))
63 63 make_empty_file(join(TMP_TEST_DIR, "pack.py"))
64 64 make_empty_file(join(TMP_TEST_DIR, "packpyc.pyc"))
65 65
66 66 def teardown():
67 67 """Teardown testenvironment for the module:
68 68
69 69 - Remove tempdir
70 70 """
71 71 # Note: we remove the parent test dir, which is the root of all test
72 72 # subdirs we may have created. Use shutil instead of os.removedirs, so
73 73 # that non-empty directories are all recursively removed.
74 74 shutil.rmtree(TMP_TEST_DIR)
75 75
76 76
77 77 def test_get_init_1():
78 78 """See if get_init can find __init__.py in this testdir"""
79 79 with make_tempfile(join(TMP_TEST_DIR, "__init__.py")):
80 80 assert mp.get_init(TMP_TEST_DIR)
81 81
82 82 def test_get_init_2():
83 83 """See if get_init can find __init__.pyw in this testdir"""
84 84 with make_tempfile(join(TMP_TEST_DIR, "__init__.pyw")):
85 85 assert mp.get_init(TMP_TEST_DIR)
86 86
87 87 def test_get_init_3():
88 88 """get_init can't find __init__.pyc in this testdir"""
89 89 with make_tempfile(join(TMP_TEST_DIR, "__init__.pyc")):
90 90 assert mp.get_init(TMP_TEST_DIR) is None
91 91
92 92 def test_get_init_3():
93 93 """get_init can't find __init__ in empty testdir"""
94 94 assert mp.get_init(TMP_TEST_DIR) is None
95 95
96 96
97 97 def test_find_mod_1():
98 98 modpath = join(TMP_TEST_DIR, "xmod", "__init__.py")
99 99 assert mp.find_mod("xmod") == modpath
100 100
101 101 def test_find_mod_2():
102 102 modpath = join(TMP_TEST_DIR, "xmod", "__init__.py")
103 103 assert mp.find_mod("xmod") == modpath
104 104
105 105 def test_find_mod_3():
106 106 modpath = join(TMP_TEST_DIR, "xmod", "sub.py")
107 107 assert mp.find_mod("xmod.sub") == modpath
108 108
109 109 def test_find_mod_4():
110 110 modpath = join(TMP_TEST_DIR, "pack.py")
111 111 assert mp.find_mod("pack") == modpath
112 112
113 113 def test_find_mod_5():
114 114 assert mp.find_mod("packpyc") is None
115 115
116 116 def test_find_module_1():
117 117 modpath = join(TMP_TEST_DIR, "xmod")
118 118 assert mp.find_module("xmod") == modpath
119 119
120 120 def test_find_module_2():
121 121 """Testing sys.path that is empty"""
122 122 assert mp.find_module("xmod", []) is None
123 123
124 124 def test_find_module_3():
125 125 """Testing sys.path that is empty"""
126 126 assert mp.find_module(None, None) is None
127 127
128 128 def test_find_module_4():
129 129 """Testing sys.path that is empty"""
130 130 assert mp.find_module(None) is None
131 131
132 132 def test_find_module_5():
133 133 assert mp.find_module("xmod.nopack") is None
@@ -1,150 +1,150 b''
1 1 # encoding: utf-8
2 2
3 3 """This file contains unittests for the notification.py module."""
4 4
5 5 #-----------------------------------------------------------------------------
6 # Copyright (C) 2008-2009 The IPython Development Team
6 # Copyright (C) 2008-2011 The IPython Development Team
7 7 #
8 8 # Distributed under the terms of the BSD License. The full license is
9 9 # in the file COPYING, distributed as part of this software.
10 10 #-----------------------------------------------------------------------------
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Imports
14 14 #-----------------------------------------------------------------------------
15 15
16 16 import unittest
17 17
18 18 from IPython.utils.notification import shared_center
19 19
20 20 #-----------------------------------------------------------------------------
21 21 # Support Classes
22 22 #-----------------------------------------------------------------------------
23 23
24 24
25 25 class Observer(object):
26 26
27 27 def __init__(self, expected_ntype, expected_sender,
28 28 center=shared_center, *args, **kwargs):
29 29 super(Observer, self).__init__()
30 30 self.expected_ntype = expected_ntype
31 31 self.expected_sender = expected_sender
32 32 self.expected_args = args
33 33 self.expected_kwargs = kwargs
34 34 self.recieved = False
35 35 center.add_observer(self.callback,
36 36 self.expected_ntype,
37 37 self.expected_sender)
38 38
39 39 def callback(self, ntype, sender, *args, **kwargs):
40 40 assert(ntype == self.expected_ntype or
41 41 self.expected_ntype == None)
42 42 assert(sender == self.expected_sender or
43 43 self.expected_sender == None)
44 44 assert(args == self.expected_args)
45 45 assert(kwargs == self.expected_kwargs)
46 46 self.recieved = True
47 47
48 48 def verify(self):
49 49 assert(self.recieved)
50 50
51 51 def reset(self):
52 52 self.recieved = False
53 53
54 54
55 55 class Notifier(object):
56 56
57 57 def __init__(self, ntype, **kwargs):
58 58 super(Notifier, self).__init__()
59 59 self.ntype = ntype
60 60 self.kwargs = kwargs
61 61
62 62 def post(self, center=shared_center):
63 63
64 64 center.post_notification(self.ntype, self,
65 65 **self.kwargs)
66 66
67 67
68 68 #-----------------------------------------------------------------------------
69 69 # Tests
70 70 #-----------------------------------------------------------------------------
71 71
72 72
73 73 class NotificationTests(unittest.TestCase):
74 74
75 75 def tearDown(self):
76 76 shared_center.remove_all_observers()
77 77
78 78 def test_notification_delivered(self):
79 79 """Test that notifications are delivered"""
80 80
81 81 expected_ntype = 'EXPECTED_TYPE'
82 82 sender = Notifier(expected_ntype)
83 83 observer = Observer(expected_ntype, sender)
84 84
85 85 sender.post()
86 86 observer.verify()
87 87
88 88 def test_type_specificity(self):
89 89 """Test that observers are registered by type"""
90 90
91 91 expected_ntype = 1
92 92 unexpected_ntype = "UNEXPECTED_TYPE"
93 93 sender = Notifier(expected_ntype)
94 94 unexpected_sender = Notifier(unexpected_ntype)
95 95 observer = Observer(expected_ntype, sender)
96 96
97 97 sender.post()
98 98 unexpected_sender.post()
99 99 observer.verify()
100 100
101 101 def test_sender_specificity(self):
102 102 """Test that observers are registered by sender"""
103 103
104 104 expected_ntype = "EXPECTED_TYPE"
105 105 sender1 = Notifier(expected_ntype)
106 106 sender2 = Notifier(expected_ntype)
107 107 observer = Observer(expected_ntype, sender1)
108 108
109 109 sender1.post()
110 110 sender2.post()
111 111
112 112 observer.verify()
113 113
114 114 def test_remove_all_observers(self):
115 115 """White-box test for remove_all_observers"""
116 116
117 117 for i in xrange(10):
118 118 Observer('TYPE', None, center=shared_center)
119 119
120 120 self.assert_(len(shared_center.observers[('TYPE',None)]) >= 10,
121 121 "observers registered")
122 122
123 123 shared_center.remove_all_observers()
124 124 self.assert_(len(shared_center.observers) == 0, "observers removed")
125 125
126 126 def test_any_sender(self):
127 127 expected_ntype = "EXPECTED_TYPE"
128 128 sender1 = Notifier(expected_ntype)
129 129 sender2 = Notifier(expected_ntype)
130 130 observer = Observer(expected_ntype, None)
131 131
132 132 sender1.post()
133 133 observer.verify()
134 134
135 135 observer.reset()
136 136 sender2.post()
137 137 observer.verify()
138 138
139 139 def test_post_performance(self):
140 140 """Test that post_notification, even with many registered irrelevant
141 141 observers is fast"""
142 142
143 143 for i in xrange(10):
144 144 Observer("UNRELATED_TYPE", None)
145 145
146 146 o = Observer('EXPECTED_TYPE', None)
147 147 shared_center.post_notification('EXPECTED_TYPE', self)
148 148 o.verify()
149 149
150 150
@@ -1,445 +1,445 b''
1 1 # encoding: utf-8
2 2 """Tests for IPython.utils.path.py"""
3 3
4 4 #-----------------------------------------------------------------------------
5 # Copyright (C) 2008 The IPython Development Team
5 # Copyright (C) 2008-2011 The IPython Development Team
6 6 #
7 7 # Distributed under the terms of the BSD License. The full license is in
8 8 # the file COPYING, distributed as part of this software.
9 9 #-----------------------------------------------------------------------------
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Imports
13 13 #-----------------------------------------------------------------------------
14 14
15 15 from __future__ import with_statement
16 16
17 17 import os
18 18 import shutil
19 19 import sys
20 20 import tempfile
21 21 from io import StringIO
22 22
23 23 from os.path import join, abspath, split
24 24
25 25 import nose.tools as nt
26 26
27 27 from nose import with_setup
28 28
29 29 import IPython
30 30 from IPython.testing import decorators as dec
31 31 from IPython.testing.decorators import skip_if_not_win32, skip_win32
32 32 from IPython.testing.tools import make_tempfile, AssertPrints
33 33 from IPython.utils import path, io
34 34 from IPython.utils import py3compat
35 35
36 36 # Platform-dependent imports
37 37 try:
38 38 import _winreg as wreg
39 39 except ImportError:
40 40 #Fake _winreg module on none windows platforms
41 41 import types
42 42 wr_name = "winreg" if py3compat.PY3 else "_winreg"
43 43 sys.modules[wr_name] = types.ModuleType(wr_name)
44 44 import _winreg as wreg
45 45 #Add entries that needs to be stubbed by the testing code
46 46 (wreg.OpenKey, wreg.QueryValueEx,) = (None, None)
47 47
48 48 try:
49 49 reload
50 50 except NameError: # Python 3
51 51 from imp import reload
52 52
53 53 #-----------------------------------------------------------------------------
54 54 # Globals
55 55 #-----------------------------------------------------------------------------
56 56 env = os.environ
57 57 TEST_FILE_PATH = split(abspath(__file__))[0]
58 58 TMP_TEST_DIR = tempfile.mkdtemp()
59 59 HOME_TEST_DIR = join(TMP_TEST_DIR, "home_test_dir")
60 60 XDG_TEST_DIR = join(HOME_TEST_DIR, "xdg_test_dir")
61 61 IP_TEST_DIR = join(HOME_TEST_DIR,'.ipython')
62 62 #
63 63 # Setup/teardown functions/decorators
64 64 #
65 65
66 66 def setup():
67 67 """Setup testenvironment for the module:
68 68
69 69 - Adds dummy home dir tree
70 70 """
71 71 # Do not mask exceptions here. In particular, catching WindowsError is a
72 72 # problem because that exception is only defined on Windows...
73 73 os.makedirs(IP_TEST_DIR)
74 74 os.makedirs(os.path.join(XDG_TEST_DIR, 'ipython'))
75 75
76 76
77 77 def teardown():
78 78 """Teardown testenvironment for the module:
79 79
80 80 - Remove dummy home dir tree
81 81 """
82 82 # Note: we remove the parent test dir, which is the root of all test
83 83 # subdirs we may have created. Use shutil instead of os.removedirs, so
84 84 # that non-empty directories are all recursively removed.
85 85 shutil.rmtree(TMP_TEST_DIR)
86 86
87 87
88 88 def setup_environment():
89 89 """Setup testenvironment for some functions that are tested
90 90 in this module. In particular this functions stores attributes
91 91 and other things that we need to stub in some test functions.
92 92 This needs to be done on a function level and not module level because
93 93 each testfunction needs a pristine environment.
94 94 """
95 95 global oldstuff, platformstuff
96 96 oldstuff = (env.copy(), os.name, path.get_home_dir, IPython.__file__, os.getcwd())
97 97
98 98 if os.name == 'nt':
99 99 platformstuff = (wreg.OpenKey, wreg.QueryValueEx,)
100 100
101 101
102 102 def teardown_environment():
103 103 """Restore things that were remebered by the setup_environment function
104 104 """
105 105 (oldenv, os.name, path.get_home_dir, IPython.__file__, old_wd) = oldstuff
106 106 os.chdir(old_wd)
107 107 reload(path)
108 108
109 109 for key in env.keys():
110 110 if key not in oldenv:
111 111 del env[key]
112 112 env.update(oldenv)
113 113 if hasattr(sys, 'frozen'):
114 114 del sys.frozen
115 115 if os.name == 'nt':
116 116 (wreg.OpenKey, wreg.QueryValueEx,) = platformstuff
117 117
118 118 # Build decorator that uses the setup_environment/setup_environment
119 119 with_environment = with_setup(setup_environment, teardown_environment)
120 120
121 121
122 122 @skip_if_not_win32
123 123 @with_environment
124 124 def test_get_home_dir_1():
125 125 """Testcase for py2exe logic, un-compressed lib
126 126 """
127 127 sys.frozen = True
128 128
129 129 #fake filename for IPython.__init__
130 130 IPython.__file__ = abspath(join(HOME_TEST_DIR, "Lib/IPython/__init__.py"))
131 131
132 132 home_dir = path.get_home_dir()
133 133 nt.assert_equal(home_dir, abspath(HOME_TEST_DIR))
134 134
135 135
136 136 @skip_if_not_win32
137 137 @with_environment
138 138 def test_get_home_dir_2():
139 139 """Testcase for py2exe logic, compressed lib
140 140 """
141 141 sys.frozen = True
142 142 #fake filename for IPython.__init__
143 143 IPython.__file__ = abspath(join(HOME_TEST_DIR, "Library.zip/IPython/__init__.py")).lower()
144 144
145 145 home_dir = path.get_home_dir()
146 146 nt.assert_equal(home_dir, abspath(HOME_TEST_DIR).lower())
147 147
148 148
149 149 @with_environment
150 150 @skip_win32
151 151 def test_get_home_dir_3():
152 152 """Testcase $HOME is set, then use its value as home directory."""
153 153 env["HOME"] = HOME_TEST_DIR
154 154 home_dir = path.get_home_dir()
155 155 nt.assert_equal(home_dir, env["HOME"])
156 156
157 157
158 158 @with_environment
159 159 @skip_win32
160 160 def test_get_home_dir_4():
161 161 """Testcase $HOME is not set, os=='posix'.
162 162 This should fail with HomeDirError"""
163 163
164 164 os.name = 'posix'
165 165 if 'HOME' in env: del env['HOME']
166 166 nt.assert_raises(path.HomeDirError, path.get_home_dir)
167 167
168 168
169 169 @skip_if_not_win32
170 170 @with_environment
171 171 def test_get_home_dir_5():
172 172 """Using HOMEDRIVE + HOMEPATH, os=='nt'.
173 173
174 174 HOMESHARE is missing.
175 175 """
176 176
177 177 os.name = 'nt'
178 178 env.pop('HOMESHARE', None)
179 179 env['HOMEDRIVE'], env['HOMEPATH'] = os.path.splitdrive(HOME_TEST_DIR)
180 180 home_dir = path.get_home_dir()
181 181 nt.assert_equal(home_dir, abspath(HOME_TEST_DIR))
182 182
183 183
184 184 @skip_if_not_win32
185 185 @with_environment
186 186 def test_get_home_dir_6():
187 187 """Using USERPROFILE, os=='nt'.
188 188
189 189 HOMESHARE, HOMEDRIVE, HOMEPATH are missing.
190 190 """
191 191
192 192 os.name = 'nt'
193 193 env.pop('HOMESHARE', None)
194 194 env.pop('HOMEDRIVE', None)
195 195 env.pop('HOMEPATH', None)
196 196 env["USERPROFILE"] = abspath(HOME_TEST_DIR)
197 197 home_dir = path.get_home_dir()
198 198 nt.assert_equal(home_dir, abspath(HOME_TEST_DIR))
199 199
200 200
201 201 @skip_if_not_win32
202 202 @with_environment
203 203 def test_get_home_dir_7():
204 204 """Using HOMESHARE, os=='nt'."""
205 205
206 206 os.name = 'nt'
207 207 env["HOMESHARE"] = abspath(HOME_TEST_DIR)
208 208 home_dir = path.get_home_dir()
209 209 nt.assert_equal(home_dir, abspath(HOME_TEST_DIR))
210 210
211 211
212 212 # Should we stub wreg fully so we can run the test on all platforms?
213 213 @skip_if_not_win32
214 214 @with_environment
215 215 def test_get_home_dir_8():
216 216 """Using registry hack for 'My Documents', os=='nt'
217 217
218 218 HOMESHARE, HOMEDRIVE, HOMEPATH, USERPROFILE and others are missing.
219 219 """
220 220 os.name = 'nt'
221 221 # Remove from stub environment all keys that may be set
222 222 for key in ['HOME', 'HOMESHARE', 'HOMEDRIVE', 'HOMEPATH', 'USERPROFILE']:
223 223 env.pop(key, None)
224 224
225 225 #Stub windows registry functions
226 226 def OpenKey(x, y):
227 227 class key:
228 228 def Close(self):
229 229 pass
230 230 return key()
231 231 def QueryValueEx(x, y):
232 232 return [abspath(HOME_TEST_DIR)]
233 233
234 234 wreg.OpenKey = OpenKey
235 235 wreg.QueryValueEx = QueryValueEx
236 236
237 237 home_dir = path.get_home_dir()
238 238 nt.assert_equal(home_dir, abspath(HOME_TEST_DIR))
239 239
240 240
241 241 @with_environment
242 242 def test_get_ipython_dir_1():
243 243 """test_get_ipython_dir_1, Testcase to see if we can call get_ipython_dir without Exceptions."""
244 244 env_ipdir = os.path.join("someplace", ".ipython")
245 245 path._writable_dir = lambda path: True
246 246 env['IPYTHON_DIR'] = env_ipdir
247 247 ipdir = path.get_ipython_dir()
248 248 nt.assert_equal(ipdir, env_ipdir)
249 249
250 250
251 251 @with_environment
252 252 def test_get_ipython_dir_2():
253 253 """test_get_ipython_dir_2, Testcase to see if we can call get_ipython_dir without Exceptions."""
254 254 path.get_home_dir = lambda : "someplace"
255 255 path.get_xdg_dir = lambda : None
256 256 path._writable_dir = lambda path: True
257 257 os.name = "posix"
258 258 env.pop('IPYTHON_DIR', None)
259 259 env.pop('IPYTHONDIR', None)
260 260 env.pop('XDG_CONFIG_HOME', None)
261 261 ipdir = path.get_ipython_dir()
262 262 nt.assert_equal(ipdir, os.path.join("someplace", ".ipython"))
263 263
264 264 @with_environment
265 265 def test_get_ipython_dir_3():
266 266 """test_get_ipython_dir_3, use XDG if defined, and .ipython doesn't exist."""
267 267 path.get_home_dir = lambda : "someplace"
268 268 path._writable_dir = lambda path: True
269 269 os.name = "posix"
270 270 env.pop('IPYTHON_DIR', None)
271 271 env.pop('IPYTHONDIR', None)
272 272 env['XDG_CONFIG_HOME'] = XDG_TEST_DIR
273 273 ipdir = path.get_ipython_dir()
274 274 nt.assert_equal(ipdir, os.path.join(XDG_TEST_DIR, "ipython"))
275 275
276 276 @with_environment
277 277 def test_get_ipython_dir_4():
278 278 """test_get_ipython_dir_4, use XDG if both exist."""
279 279 path.get_home_dir = lambda : HOME_TEST_DIR
280 280 os.name = "posix"
281 281 env.pop('IPYTHON_DIR', None)
282 282 env.pop('IPYTHONDIR', None)
283 283 env['XDG_CONFIG_HOME'] = XDG_TEST_DIR
284 284 xdg_ipdir = os.path.join(XDG_TEST_DIR, "ipython")
285 285 ipdir = path.get_ipython_dir()
286 286 nt.assert_equal(ipdir, xdg_ipdir)
287 287
288 288 @with_environment
289 289 def test_get_ipython_dir_5():
290 290 """test_get_ipython_dir_5, use .ipython if exists and XDG defined, but doesn't exist."""
291 291 path.get_home_dir = lambda : HOME_TEST_DIR
292 292 os.name = "posix"
293 293 env.pop('IPYTHON_DIR', None)
294 294 env.pop('IPYTHONDIR', None)
295 295 env['XDG_CONFIG_HOME'] = XDG_TEST_DIR
296 296 os.rmdir(os.path.join(XDG_TEST_DIR, 'ipython'))
297 297 ipdir = path.get_ipython_dir()
298 298 nt.assert_equal(ipdir, IP_TEST_DIR)
299 299
300 300 @with_environment
301 301 def test_get_ipython_dir_6():
302 302 """test_get_ipython_dir_6, use XDG if defined and neither exist."""
303 303 xdg = os.path.join(HOME_TEST_DIR, 'somexdg')
304 304 os.mkdir(xdg)
305 305 shutil.rmtree(os.path.join(HOME_TEST_DIR, '.ipython'))
306 306 path.get_home_dir = lambda : HOME_TEST_DIR
307 307 path.get_xdg_dir = lambda : xdg
308 308 os.name = "posix"
309 309 env.pop('IPYTHON_DIR', None)
310 310 env.pop('IPYTHONDIR', None)
311 311 env.pop('XDG_CONFIG_HOME', None)
312 312 xdg_ipdir = os.path.join(xdg, "ipython")
313 313 ipdir = path.get_ipython_dir()
314 314 nt.assert_equal(ipdir, xdg_ipdir)
315 315
316 316 @with_environment
317 317 def test_get_ipython_dir_7():
318 318 """test_get_ipython_dir_7, test home directory expansion on IPYTHON_DIR"""
319 319 path._writable_dir = lambda path: True
320 320 home_dir = os.path.expanduser('~')
321 321 env['IPYTHON_DIR'] = os.path.join('~', 'somewhere')
322 322 ipdir = path.get_ipython_dir()
323 323 nt.assert_equal(ipdir, os.path.join(home_dir, 'somewhere'))
324 324
325 325
326 326 @with_environment
327 327 def test_get_xdg_dir_1():
328 328 """test_get_xdg_dir_1, check xdg_dir"""
329 329 reload(path)
330 330 path._writable_dir = lambda path: True
331 331 path.get_home_dir = lambda : 'somewhere'
332 332 os.name = "posix"
333 333 env.pop('IPYTHON_DIR', None)
334 334 env.pop('IPYTHONDIR', None)
335 335 env.pop('XDG_CONFIG_HOME', None)
336 336
337 337 nt.assert_equal(path.get_xdg_dir(), os.path.join('somewhere', '.config'))
338 338
339 339
340 340 @with_environment
341 341 def test_get_xdg_dir_1():
342 342 """test_get_xdg_dir_1, check nonexistant xdg_dir"""
343 343 reload(path)
344 344 path.get_home_dir = lambda : HOME_TEST_DIR
345 345 os.name = "posix"
346 346 env.pop('IPYTHON_DIR', None)
347 347 env.pop('IPYTHONDIR', None)
348 348 env.pop('XDG_CONFIG_HOME', None)
349 349 nt.assert_equal(path.get_xdg_dir(), None)
350 350
351 351 @with_environment
352 352 def test_get_xdg_dir_2():
353 353 """test_get_xdg_dir_2, check xdg_dir default to ~/.config"""
354 354 reload(path)
355 355 path.get_home_dir = lambda : HOME_TEST_DIR
356 356 os.name = "posix"
357 357 env.pop('IPYTHON_DIR', None)
358 358 env.pop('IPYTHONDIR', None)
359 359 env.pop('XDG_CONFIG_HOME', None)
360 360 cfgdir=os.path.join(path.get_home_dir(), '.config')
361 361 os.makedirs(cfgdir)
362 362
363 363 nt.assert_equal(path.get_xdg_dir(), cfgdir)
364 364
365 365 def test_filefind():
366 366 """Various tests for filefind"""
367 367 f = tempfile.NamedTemporaryFile()
368 368 # print 'fname:',f.name
369 369 alt_dirs = path.get_ipython_dir()
370 370 t = path.filefind(f.name, alt_dirs)
371 371 # print 'found:',t
372 372
373 373
374 374 def test_get_ipython_package_dir():
375 375 ipdir = path.get_ipython_package_dir()
376 376 nt.assert_true(os.path.isdir(ipdir))
377 377
378 378
379 379 def test_get_ipython_module_path():
380 380 ipapp_path = path.get_ipython_module_path('IPython.frontend.terminal.ipapp')
381 381 nt.assert_true(os.path.isfile(ipapp_path))
382 382
383 383
384 384 @dec.skip_if_not_win32
385 385 def test_get_long_path_name_win32():
386 386 p = path.get_long_path_name('c:\\docume~1')
387 387 nt.assert_equals(p,u'c:\\Documents and Settings')
388 388
389 389
390 390 @dec.skip_win32
391 391 def test_get_long_path_name():
392 392 p = path.get_long_path_name('/usr/local')
393 393 nt.assert_equals(p,'/usr/local')
394 394
395 395 @dec.skip_win32 # can't create not-user-writable dir on win
396 396 @with_environment
397 397 def test_not_writable_ipdir():
398 398 tmpdir = tempfile.mkdtemp()
399 399 os.name = "posix"
400 400 env.pop('IPYTHON_DIR', None)
401 401 env.pop('IPYTHONDIR', None)
402 402 env.pop('XDG_CONFIG_HOME', None)
403 403 env['HOME'] = tmpdir
404 404 ipdir = os.path.join(tmpdir, '.ipython')
405 405 os.mkdir(ipdir)
406 406 os.chmod(ipdir, 600)
407 407 with AssertPrints('is not a writable location', channel='stderr'):
408 408 ipdir = path.get_ipython_dir()
409 409 env.pop('IPYTHON_DIR', None)
410 410
411 411 def test_unquote_filename():
412 412 for win32 in (True, False):
413 413 nt.assert_equals(path.unquote_filename('foo.py', win32=win32), 'foo.py')
414 414 nt.assert_equals(path.unquote_filename('foo bar.py', win32=win32), 'foo bar.py')
415 415 nt.assert_equals(path.unquote_filename('"foo.py"', win32=True), 'foo.py')
416 416 nt.assert_equals(path.unquote_filename('"foo bar.py"', win32=True), 'foo bar.py')
417 417 nt.assert_equals(path.unquote_filename("'foo.py'", win32=True), 'foo.py')
418 418 nt.assert_equals(path.unquote_filename("'foo bar.py'", win32=True), 'foo bar.py')
419 419 nt.assert_equals(path.unquote_filename('"foo.py"', win32=False), '"foo.py"')
420 420 nt.assert_equals(path.unquote_filename('"foo bar.py"', win32=False), '"foo bar.py"')
421 421 nt.assert_equals(path.unquote_filename("'foo.py'", win32=False), "'foo.py'")
422 422 nt.assert_equals(path.unquote_filename("'foo bar.py'", win32=False), "'foo bar.py'")
423 423
424 424 @with_environment
425 425 def test_get_py_filename():
426 426 os.chdir(TMP_TEST_DIR)
427 427 for win32 in (True, False):
428 428 with make_tempfile('foo.py'):
429 429 nt.assert_equals(path.get_py_filename('foo.py', force_win32=win32), 'foo.py')
430 430 nt.assert_equals(path.get_py_filename('foo', force_win32=win32), 'foo.py')
431 431 with make_tempfile('foo'):
432 432 nt.assert_equals(path.get_py_filename('foo', force_win32=win32), 'foo')
433 433 nt.assert_raises(IOError, path.get_py_filename, 'foo.py', force_win32=win32)
434 434 nt.assert_raises(IOError, path.get_py_filename, 'foo', force_win32=win32)
435 435 nt.assert_raises(IOError, path.get_py_filename, 'foo.py', force_win32=win32)
436 436 true_fn = 'foo with spaces.py'
437 437 with make_tempfile(true_fn):
438 438 nt.assert_equals(path.get_py_filename('foo with spaces', force_win32=win32), true_fn)
439 439 nt.assert_equals(path.get_py_filename('foo with spaces.py', force_win32=win32), true_fn)
440 440 if win32:
441 441 nt.assert_equals(path.get_py_filename('"foo with spaces.py"', force_win32=True), true_fn)
442 442 nt.assert_equals(path.get_py_filename("'foo with spaces.py'", force_win32=True), true_fn)
443 443 else:
444 444 nt.assert_raises(IOError, path.get_py_filename, '"foo with spaces.py"', force_win32=False)
445 445 nt.assert_raises(IOError, path.get_py_filename, "'foo with spaces.py'", force_win32=False)
@@ -1,111 +1,111 b''
1 1 # encoding: utf-8
2 2 """
3 3 Tests for platutils.py
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2009 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 import sys
18 18 from unittest import TestCase
19 19
20 20 import nose.tools as nt
21 21
22 22 from IPython.utils.process import (find_cmd, FindCmdError, arg_split,
23 23 system, getoutput, getoutputerror)
24 24 from IPython.testing import decorators as dec
25 25 from IPython.testing import tools as tt
26 26
27 27 #-----------------------------------------------------------------------------
28 28 # Tests
29 29 #-----------------------------------------------------------------------------
30 30
31 31 def test_find_cmd_python():
32 32 """Make sure we find sys.exectable for python."""
33 33 nt.assert_equals(find_cmd('python'), sys.executable)
34 34
35 35
36 36 @dec.skip_win32
37 37 def test_find_cmd_ls():
38 38 """Make sure we can find the full path to ls."""
39 39 path = find_cmd('ls')
40 40 nt.assert_true(path.endswith('ls'))
41 41
42 42
43 43 def has_pywin32():
44 44 try:
45 45 import win32api
46 46 except ImportError:
47 47 return False
48 48 return True
49 49
50 50
51 51 @dec.onlyif(has_pywin32, "This test requires win32api to run")
52 52 def test_find_cmd_pythonw():
53 53 """Try to find pythonw on Windows."""
54 54 path = find_cmd('pythonw')
55 55 nt.assert_true(path.endswith('pythonw.exe'))
56 56
57 57
58 58 @dec.onlyif(lambda : sys.platform != 'win32' or has_pywin32(),
59 59 "This test runs on posix or in win32 with win32api installed")
60 60 def test_find_cmd_fail():
61 61 """Make sure that FindCmdError is raised if we can't find the cmd."""
62 62 nt.assert_raises(FindCmdError,find_cmd,'asdfasdf')
63 63
64 64
65 65 def test_arg_split():
66 66 """Ensure that argument lines are correctly split like in a shell."""
67 67 tests = [['hi', ['hi']],
68 68 [u'hi', [u'hi']],
69 69 ['hello there', ['hello', 'there']],
70 70 [u'h\N{LATIN SMALL LETTER A WITH CARON}llo', [u'h\N{LATIN SMALL LETTER A WITH CARON}llo']],
71 71 ['something "with quotes"', ['something', '"with quotes"']],
72 72 ]
73 73 for argstr, argv in tests:
74 74 nt.assert_equal(arg_split(argstr), argv)
75 75
76 76
77 77 class SubProcessTestCase(TestCase, tt.TempFileMixin):
78 78 def setUp(self):
79 79 """Make a valid python temp file."""
80 80 lines = ["from __future__ import print_function",
81 81 "import sys",
82 82 "print('on stdout', end='', file=sys.stdout)",
83 83 "print('on stderr', end='', file=sys.stderr)",
84 84 "sys.stdout.flush()",
85 85 "sys.stderr.flush()"]
86 86 self.mktmp('\n'.join(lines))
87 87
88 88 def test_system(self):
89 89 status = system('python "%s"' % self.fname)
90 90 self.assertEquals(status, 0)
91 91
92 92 def test_system_quotes(self):
93 93 status = system('python -c "import sys"')
94 94 self.assertEquals(status, 0)
95 95
96 96 def test_getoutput(self):
97 97 out = getoutput('python "%s"' % self.fname)
98 98 self.assertEquals(out, 'on stdout')
99 99
100 100 def test_getoutput_quoted(self):
101 101 out = getoutput('python -c "print (1)"')
102 102 self.assertEquals(out.strip(), '1')
103 103 out = getoutput("python -c 'print (1)'")
104 104 self.assertEquals(out.strip(), '1')
105 105 out = getoutput("python -c 'print (\"1\")'")
106 106 self.assertEquals(out.strip(), '1')
107 107
108 108 def test_getoutput(self):
109 109 out, err = getoutputerror('python "%s"' % self.fname)
110 110 self.assertEquals(out, 'on stdout')
111 111 self.assertEquals(err, 'on stderr')
@@ -1,890 +1,890 b''
1 1 # encoding: utf-8
2 2 """
3 3 Tests for IPython.utils.traitlets.
4 4
5 5 Authors:
6 6
7 7 * Brian Granger
8 8 * Enthought, Inc. Some of the code in this file comes from enthought.traits
9 9 and is licensed under the BSD license. Also, many of the ideas also come
10 10 from enthought.traits even though our implementation is very different.
11 11 """
12 12
13 13 #-----------------------------------------------------------------------------
14 # Copyright (C) 2008-2009 The IPython Development Team
14 # Copyright (C) 2008-2011 The IPython Development Team
15 15 #
16 16 # Distributed under the terms of the BSD License. The full license is in
17 17 # the file COPYING, distributed as part of this software.
18 18 #-----------------------------------------------------------------------------
19 19
20 20 #-----------------------------------------------------------------------------
21 21 # Imports
22 22 #-----------------------------------------------------------------------------
23 23
24 24 import sys
25 25 from unittest import TestCase
26 26
27 27 from IPython.utils.traitlets import (
28 28 HasTraits, MetaHasTraits, TraitType, Any, CBytes,
29 29 Int, Long, Integer, Float, Complex, Bytes, Unicode, TraitError,
30 30 Undefined, Type, This, Instance, TCPAddress, List, Tuple,
31 31 ObjectName, DottedObjectName
32 32 )
33 33 from IPython.utils import py3compat
34 34 from IPython.testing.decorators import skipif
35 35
36 36 #-----------------------------------------------------------------------------
37 37 # Helper classes for testing
38 38 #-----------------------------------------------------------------------------
39 39
40 40
41 41 class HasTraitsStub(HasTraits):
42 42
43 43 def _notify_trait(self, name, old, new):
44 44 self._notify_name = name
45 45 self._notify_old = old
46 46 self._notify_new = new
47 47
48 48
49 49 #-----------------------------------------------------------------------------
50 50 # Test classes
51 51 #-----------------------------------------------------------------------------
52 52
53 53
54 54 class TestTraitType(TestCase):
55 55
56 56 def test_get_undefined(self):
57 57 class A(HasTraits):
58 58 a = TraitType
59 59 a = A()
60 60 self.assertEquals(a.a, Undefined)
61 61
62 62 def test_set(self):
63 63 class A(HasTraitsStub):
64 64 a = TraitType
65 65
66 66 a = A()
67 67 a.a = 10
68 68 self.assertEquals(a.a, 10)
69 69 self.assertEquals(a._notify_name, 'a')
70 70 self.assertEquals(a._notify_old, Undefined)
71 71 self.assertEquals(a._notify_new, 10)
72 72
73 73 def test_validate(self):
74 74 class MyTT(TraitType):
75 75 def validate(self, inst, value):
76 76 return -1
77 77 class A(HasTraitsStub):
78 78 tt = MyTT
79 79
80 80 a = A()
81 81 a.tt = 10
82 82 self.assertEquals(a.tt, -1)
83 83
84 84 def test_default_validate(self):
85 85 class MyIntTT(TraitType):
86 86 def validate(self, obj, value):
87 87 if isinstance(value, int):
88 88 return value
89 89 self.error(obj, value)
90 90 class A(HasTraits):
91 91 tt = MyIntTT(10)
92 92 a = A()
93 93 self.assertEquals(a.tt, 10)
94 94
95 95 # Defaults are validated when the HasTraits is instantiated
96 96 class B(HasTraits):
97 97 tt = MyIntTT('bad default')
98 98 self.assertRaises(TraitError, B)
99 99
100 100 def test_is_valid_for(self):
101 101 class MyTT(TraitType):
102 102 def is_valid_for(self, value):
103 103 return True
104 104 class A(HasTraits):
105 105 tt = MyTT
106 106
107 107 a = A()
108 108 a.tt = 10
109 109 self.assertEquals(a.tt, 10)
110 110
111 111 def test_value_for(self):
112 112 class MyTT(TraitType):
113 113 def value_for(self, value):
114 114 return 20
115 115 class A(HasTraits):
116 116 tt = MyTT
117 117
118 118 a = A()
119 119 a.tt = 10
120 120 self.assertEquals(a.tt, 20)
121 121
122 122 def test_info(self):
123 123 class A(HasTraits):
124 124 tt = TraitType
125 125 a = A()
126 126 self.assertEquals(A.tt.info(), 'any value')
127 127
128 128 def test_error(self):
129 129 class A(HasTraits):
130 130 tt = TraitType
131 131 a = A()
132 132 self.assertRaises(TraitError, A.tt.error, a, 10)
133 133
134 134 def test_dynamic_initializer(self):
135 135 class A(HasTraits):
136 136 x = Int(10)
137 137 def _x_default(self):
138 138 return 11
139 139 class B(A):
140 140 x = Int(20)
141 141 class C(A):
142 142 def _x_default(self):
143 143 return 21
144 144
145 145 a = A()
146 146 self.assertEquals(a._trait_values, {})
147 147 self.assertEquals(a._trait_dyn_inits.keys(), ['x'])
148 148 self.assertEquals(a.x, 11)
149 149 self.assertEquals(a._trait_values, {'x': 11})
150 150 b = B()
151 151 self.assertEquals(b._trait_values, {'x': 20})
152 152 self.assertEquals(a._trait_dyn_inits.keys(), ['x'])
153 153 self.assertEquals(b.x, 20)
154 154 c = C()
155 155 self.assertEquals(c._trait_values, {})
156 156 self.assertEquals(a._trait_dyn_inits.keys(), ['x'])
157 157 self.assertEquals(c.x, 21)
158 158 self.assertEquals(c._trait_values, {'x': 21})
159 159 # Ensure that the base class remains unmolested when the _default
160 160 # initializer gets overridden in a subclass.
161 161 a = A()
162 162 c = C()
163 163 self.assertEquals(a._trait_values, {})
164 164 self.assertEquals(a._trait_dyn_inits.keys(), ['x'])
165 165 self.assertEquals(a.x, 11)
166 166 self.assertEquals(a._trait_values, {'x': 11})
167 167
168 168
169 169
170 170 class TestHasTraitsMeta(TestCase):
171 171
172 172 def test_metaclass(self):
173 173 self.assertEquals(type(HasTraits), MetaHasTraits)
174 174
175 175 class A(HasTraits):
176 176 a = Int
177 177
178 178 a = A()
179 179 self.assertEquals(type(a.__class__), MetaHasTraits)
180 180 self.assertEquals(a.a,0)
181 181 a.a = 10
182 182 self.assertEquals(a.a,10)
183 183
184 184 class B(HasTraits):
185 185 b = Int()
186 186
187 187 b = B()
188 188 self.assertEquals(b.b,0)
189 189 b.b = 10
190 190 self.assertEquals(b.b,10)
191 191
192 192 class C(HasTraits):
193 193 c = Int(30)
194 194
195 195 c = C()
196 196 self.assertEquals(c.c,30)
197 197 c.c = 10
198 198 self.assertEquals(c.c,10)
199 199
200 200 def test_this_class(self):
201 201 class A(HasTraits):
202 202 t = This()
203 203 tt = This()
204 204 class B(A):
205 205 tt = This()
206 206 ttt = This()
207 207 self.assertEquals(A.t.this_class, A)
208 208 self.assertEquals(B.t.this_class, A)
209 209 self.assertEquals(B.tt.this_class, B)
210 210 self.assertEquals(B.ttt.this_class, B)
211 211
212 212 class TestHasTraitsNotify(TestCase):
213 213
214 214 def setUp(self):
215 215 self._notify1 = []
216 216 self._notify2 = []
217 217
218 218 def notify1(self, name, old, new):
219 219 self._notify1.append((name, old, new))
220 220
221 221 def notify2(self, name, old, new):
222 222 self._notify2.append((name, old, new))
223 223
224 224 def test_notify_all(self):
225 225
226 226 class A(HasTraits):
227 227 a = Int
228 228 b = Float
229 229
230 230 a = A()
231 231 a.on_trait_change(self.notify1)
232 232 a.a = 0
233 233 self.assertEquals(len(self._notify1),0)
234 234 a.b = 0.0
235 235 self.assertEquals(len(self._notify1),0)
236 236 a.a = 10
237 237 self.assert_(('a',0,10) in self._notify1)
238 238 a.b = 10.0
239 239 self.assert_(('b',0.0,10.0) in self._notify1)
240 240 self.assertRaises(TraitError,setattr,a,'a','bad string')
241 241 self.assertRaises(TraitError,setattr,a,'b','bad string')
242 242 self._notify1 = []
243 243 a.on_trait_change(self.notify1,remove=True)
244 244 a.a = 20
245 245 a.b = 20.0
246 246 self.assertEquals(len(self._notify1),0)
247 247
248 248 def test_notify_one(self):
249 249
250 250 class A(HasTraits):
251 251 a = Int
252 252 b = Float
253 253
254 254 a = A()
255 255 a.on_trait_change(self.notify1, 'a')
256 256 a.a = 0
257 257 self.assertEquals(len(self._notify1),0)
258 258 a.a = 10
259 259 self.assert_(('a',0,10) in self._notify1)
260 260 self.assertRaises(TraitError,setattr,a,'a','bad string')
261 261
262 262 def test_subclass(self):
263 263
264 264 class A(HasTraits):
265 265 a = Int
266 266
267 267 class B(A):
268 268 b = Float
269 269
270 270 b = B()
271 271 self.assertEquals(b.a,0)
272 272 self.assertEquals(b.b,0.0)
273 273 b.a = 100
274 274 b.b = 100.0
275 275 self.assertEquals(b.a,100)
276 276 self.assertEquals(b.b,100.0)
277 277
278 278 def test_notify_subclass(self):
279 279
280 280 class A(HasTraits):
281 281 a = Int
282 282
283 283 class B(A):
284 284 b = Float
285 285
286 286 b = B()
287 287 b.on_trait_change(self.notify1, 'a')
288 288 b.on_trait_change(self.notify2, 'b')
289 289 b.a = 0
290 290 b.b = 0.0
291 291 self.assertEquals(len(self._notify1),0)
292 292 self.assertEquals(len(self._notify2),0)
293 293 b.a = 10
294 294 b.b = 10.0
295 295 self.assert_(('a',0,10) in self._notify1)
296 296 self.assert_(('b',0.0,10.0) in self._notify2)
297 297
298 298 def test_static_notify(self):
299 299
300 300 class A(HasTraits):
301 301 a = Int
302 302 _notify1 = []
303 303 def _a_changed(self, name, old, new):
304 304 self._notify1.append((name, old, new))
305 305
306 306 a = A()
307 307 a.a = 0
308 308 # This is broken!!!
309 309 self.assertEquals(len(a._notify1),0)
310 310 a.a = 10
311 311 self.assert_(('a',0,10) in a._notify1)
312 312
313 313 class B(A):
314 314 b = Float
315 315 _notify2 = []
316 316 def _b_changed(self, name, old, new):
317 317 self._notify2.append((name, old, new))
318 318
319 319 b = B()
320 320 b.a = 10
321 321 b.b = 10.0
322 322 self.assert_(('a',0,10) in b._notify1)
323 323 self.assert_(('b',0.0,10.0) in b._notify2)
324 324
325 325 def test_notify_args(self):
326 326
327 327 def callback0():
328 328 self.cb = ()
329 329 def callback1(name):
330 330 self.cb = (name,)
331 331 def callback2(name, new):
332 332 self.cb = (name, new)
333 333 def callback3(name, old, new):
334 334 self.cb = (name, old, new)
335 335
336 336 class A(HasTraits):
337 337 a = Int
338 338
339 339 a = A()
340 340 a.on_trait_change(callback0, 'a')
341 341 a.a = 10
342 342 self.assertEquals(self.cb,())
343 343 a.on_trait_change(callback0, 'a', remove=True)
344 344
345 345 a.on_trait_change(callback1, 'a')
346 346 a.a = 100
347 347 self.assertEquals(self.cb,('a',))
348 348 a.on_trait_change(callback1, 'a', remove=True)
349 349
350 350 a.on_trait_change(callback2, 'a')
351 351 a.a = 1000
352 352 self.assertEquals(self.cb,('a',1000))
353 353 a.on_trait_change(callback2, 'a', remove=True)
354 354
355 355 a.on_trait_change(callback3, 'a')
356 356 a.a = 10000
357 357 self.assertEquals(self.cb,('a',1000,10000))
358 358 a.on_trait_change(callback3, 'a', remove=True)
359 359
360 360 self.assertEquals(len(a._trait_notifiers['a']),0)
361 361
362 362
363 363 class TestHasTraits(TestCase):
364 364
365 365 def test_trait_names(self):
366 366 class A(HasTraits):
367 367 i = Int
368 368 f = Float
369 369 a = A()
370 370 self.assertEquals(a.trait_names(),['i','f'])
371 371 self.assertEquals(A.class_trait_names(),['i','f'])
372 372
373 373 def test_trait_metadata(self):
374 374 class A(HasTraits):
375 375 i = Int(config_key='MY_VALUE')
376 376 a = A()
377 377 self.assertEquals(a.trait_metadata('i','config_key'), 'MY_VALUE')
378 378
379 379 def test_traits(self):
380 380 class A(HasTraits):
381 381 i = Int
382 382 f = Float
383 383 a = A()
384 384 self.assertEquals(a.traits(), dict(i=A.i, f=A.f))
385 385 self.assertEquals(A.class_traits(), dict(i=A.i, f=A.f))
386 386
387 387 def test_traits_metadata(self):
388 388 class A(HasTraits):
389 389 i = Int(config_key='VALUE1', other_thing='VALUE2')
390 390 f = Float(config_key='VALUE3', other_thing='VALUE2')
391 391 j = Int(0)
392 392 a = A()
393 393 self.assertEquals(a.traits(), dict(i=A.i, f=A.f, j=A.j))
394 394 traits = a.traits(config_key='VALUE1', other_thing='VALUE2')
395 395 self.assertEquals(traits, dict(i=A.i))
396 396
397 397 # This passes, but it shouldn't because I am replicating a bug in
398 398 # traits.
399 399 traits = a.traits(config_key=lambda v: True)
400 400 self.assertEquals(traits, dict(i=A.i, f=A.f, j=A.j))
401 401
402 402 def test_init(self):
403 403 class A(HasTraits):
404 404 i = Int()
405 405 x = Float()
406 406 a = A(i=1, x=10.0)
407 407 self.assertEquals(a.i, 1)
408 408 self.assertEquals(a.x, 10.0)
409 409
410 410 #-----------------------------------------------------------------------------
411 411 # Tests for specific trait types
412 412 #-----------------------------------------------------------------------------
413 413
414 414
415 415 class TestType(TestCase):
416 416
417 417 def test_default(self):
418 418
419 419 class B(object): pass
420 420 class A(HasTraits):
421 421 klass = Type
422 422
423 423 a = A()
424 424 self.assertEquals(a.klass, None)
425 425
426 426 a.klass = B
427 427 self.assertEquals(a.klass, B)
428 428 self.assertRaises(TraitError, setattr, a, 'klass', 10)
429 429
430 430 def test_value(self):
431 431
432 432 class B(object): pass
433 433 class C(object): pass
434 434 class A(HasTraits):
435 435 klass = Type(B)
436 436
437 437 a = A()
438 438 self.assertEquals(a.klass, B)
439 439 self.assertRaises(TraitError, setattr, a, 'klass', C)
440 440 self.assertRaises(TraitError, setattr, a, 'klass', object)
441 441 a.klass = B
442 442
443 443 def test_allow_none(self):
444 444
445 445 class B(object): pass
446 446 class C(B): pass
447 447 class A(HasTraits):
448 448 klass = Type(B, allow_none=False)
449 449
450 450 a = A()
451 451 self.assertEquals(a.klass, B)
452 452 self.assertRaises(TraitError, setattr, a, 'klass', None)
453 453 a.klass = C
454 454 self.assertEquals(a.klass, C)
455 455
456 456 def test_validate_klass(self):
457 457
458 458 class A(HasTraits):
459 459 klass = Type('no strings allowed')
460 460
461 461 self.assertRaises(ImportError, A)
462 462
463 463 class A(HasTraits):
464 464 klass = Type('rub.adub.Duck')
465 465
466 466 self.assertRaises(ImportError, A)
467 467
468 468 def test_validate_default(self):
469 469
470 470 class B(object): pass
471 471 class A(HasTraits):
472 472 klass = Type('bad default', B)
473 473
474 474 self.assertRaises(ImportError, A)
475 475
476 476 class C(HasTraits):
477 477 klass = Type(None, B, allow_none=False)
478 478
479 479 self.assertRaises(TraitError, C)
480 480
481 481 def test_str_klass(self):
482 482
483 483 class A(HasTraits):
484 484 klass = Type('IPython.utils.ipstruct.Struct')
485 485
486 486 from IPython.utils.ipstruct import Struct
487 487 a = A()
488 488 a.klass = Struct
489 489 self.assertEquals(a.klass, Struct)
490 490
491 491 self.assertRaises(TraitError, setattr, a, 'klass', 10)
492 492
493 493 class TestInstance(TestCase):
494 494
495 495 def test_basic(self):
496 496 class Foo(object): pass
497 497 class Bar(Foo): pass
498 498 class Bah(object): pass
499 499
500 500 class A(HasTraits):
501 501 inst = Instance(Foo)
502 502
503 503 a = A()
504 504 self.assert_(a.inst is None)
505 505 a.inst = Foo()
506 506 self.assert_(isinstance(a.inst, Foo))
507 507 a.inst = Bar()
508 508 self.assert_(isinstance(a.inst, Foo))
509 509 self.assertRaises(TraitError, setattr, a, 'inst', Foo)
510 510 self.assertRaises(TraitError, setattr, a, 'inst', Bar)
511 511 self.assertRaises(TraitError, setattr, a, 'inst', Bah())
512 512
513 513 def test_unique_default_value(self):
514 514 class Foo(object): pass
515 515 class A(HasTraits):
516 516 inst = Instance(Foo,(),{})
517 517
518 518 a = A()
519 519 b = A()
520 520 self.assert_(a.inst is not b.inst)
521 521
522 522 def test_args_kw(self):
523 523 class Foo(object):
524 524 def __init__(self, c): self.c = c
525 525 class Bar(object): pass
526 526 class Bah(object):
527 527 def __init__(self, c, d):
528 528 self.c = c; self.d = d
529 529
530 530 class A(HasTraits):
531 531 inst = Instance(Foo, (10,))
532 532 a = A()
533 533 self.assertEquals(a.inst.c, 10)
534 534
535 535 class B(HasTraits):
536 536 inst = Instance(Bah, args=(10,), kw=dict(d=20))
537 537 b = B()
538 538 self.assertEquals(b.inst.c, 10)
539 539 self.assertEquals(b.inst.d, 20)
540 540
541 541 class C(HasTraits):
542 542 inst = Instance(Foo)
543 543 c = C()
544 544 self.assert_(c.inst is None)
545 545
546 546 def test_bad_default(self):
547 547 class Foo(object): pass
548 548
549 549 class A(HasTraits):
550 550 inst = Instance(Foo, allow_none=False)
551 551
552 552 self.assertRaises(TraitError, A)
553 553
554 554 def test_instance(self):
555 555 class Foo(object): pass
556 556
557 557 def inner():
558 558 class A(HasTraits):
559 559 inst = Instance(Foo())
560 560
561 561 self.assertRaises(TraitError, inner)
562 562
563 563
564 564 class TestThis(TestCase):
565 565
566 566 def test_this_class(self):
567 567 class Foo(HasTraits):
568 568 this = This
569 569
570 570 f = Foo()
571 571 self.assertEquals(f.this, None)
572 572 g = Foo()
573 573 f.this = g
574 574 self.assertEquals(f.this, g)
575 575 self.assertRaises(TraitError, setattr, f, 'this', 10)
576 576
577 577 def test_this_inst(self):
578 578 class Foo(HasTraits):
579 579 this = This()
580 580
581 581 f = Foo()
582 582 f.this = Foo()
583 583 self.assert_(isinstance(f.this, Foo))
584 584
585 585 def test_subclass(self):
586 586 class Foo(HasTraits):
587 587 t = This()
588 588 class Bar(Foo):
589 589 pass
590 590 f = Foo()
591 591 b = Bar()
592 592 f.t = b
593 593 b.t = f
594 594 self.assertEquals(f.t, b)
595 595 self.assertEquals(b.t, f)
596 596
597 597 def test_subclass_override(self):
598 598 class Foo(HasTraits):
599 599 t = This()
600 600 class Bar(Foo):
601 601 t = This()
602 602 f = Foo()
603 603 b = Bar()
604 604 f.t = b
605 605 self.assertEquals(f.t, b)
606 606 self.assertRaises(TraitError, setattr, b, 't', f)
607 607
608 608 class TraitTestBase(TestCase):
609 609 """A best testing class for basic trait types."""
610 610
611 611 def assign(self, value):
612 612 self.obj.value = value
613 613
614 614 def coerce(self, value):
615 615 return value
616 616
617 617 def test_good_values(self):
618 618 if hasattr(self, '_good_values'):
619 619 for value in self._good_values:
620 620 self.assign(value)
621 621 self.assertEquals(self.obj.value, self.coerce(value))
622 622
623 623 def test_bad_values(self):
624 624 if hasattr(self, '_bad_values'):
625 625 for value in self._bad_values:
626 626 try:
627 627 self.assertRaises(TraitError, self.assign, value)
628 628 except AssertionError:
629 629 assert False, value
630 630
631 631 def test_default_value(self):
632 632 if hasattr(self, '_default_value'):
633 633 self.assertEquals(self._default_value, self.obj.value)
634 634
635 635 def tearDown(self):
636 636 # restore default value after tests, if set
637 637 if hasattr(self, '_default_value'):
638 638 self.obj.value = self._default_value
639 639
640 640
641 641 class AnyTrait(HasTraits):
642 642
643 643 value = Any
644 644
645 645 class AnyTraitTest(TraitTestBase):
646 646
647 647 obj = AnyTrait()
648 648
649 649 _default_value = None
650 650 _good_values = [10.0, 'ten', u'ten', [10], {'ten': 10},(10,), None, 1j]
651 651 _bad_values = []
652 652
653 653
654 654 class IntTrait(HasTraits):
655 655
656 656 value = Int(99)
657 657
658 658 class TestInt(TraitTestBase):
659 659
660 660 obj = IntTrait()
661 661 _default_value = 99
662 662 _good_values = [10, -10]
663 663 _bad_values = ['ten', u'ten', [10], {'ten': 10},(10,), None, 1j,
664 664 10.1, -10.1, '10L', '-10L', '10.1', '-10.1', u'10L',
665 665 u'-10L', u'10.1', u'-10.1', '10', '-10', u'10', u'-10']
666 666 if not py3compat.PY3:
667 667 _bad_values.extend([10L, -10L, 10*sys.maxint, -10*sys.maxint])
668 668
669 669
670 670 class LongTrait(HasTraits):
671 671
672 672 value = Long(99L)
673 673
674 674 class TestLong(TraitTestBase):
675 675
676 676 obj = LongTrait()
677 677
678 678 _default_value = 99L
679 679 _good_values = [10, -10, 10L, -10L]
680 680 _bad_values = ['ten', u'ten', [10], [10l], {'ten': 10},(10,),(10L,),
681 681 None, 1j, 10.1, -10.1, '10', '-10', '10L', '-10L', '10.1',
682 682 '-10.1', u'10', u'-10', u'10L', u'-10L', u'10.1',
683 683 u'-10.1']
684 684 if not py3compat.PY3:
685 685 # maxint undefined on py3, because int == long
686 686 _good_values.extend([10*sys.maxint, -10*sys.maxint])
687 687
688 688 @skipif(py3compat.PY3, "not relevant on py3")
689 689 def test_cast_small(self):
690 690 """Long casts ints to long"""
691 691 self.obj.value = 10
692 692 self.assertEquals(type(self.obj.value), long)
693 693
694 694
695 695 class IntegerTrait(HasTraits):
696 696 value = Integer(1)
697 697
698 698 class TestInteger(TestLong):
699 699 obj = IntegerTrait()
700 700 _default_value = 1
701 701
702 702 def coerce(self, n):
703 703 return int(n)
704 704
705 705 @skipif(py3compat.PY3, "not relevant on py3")
706 706 def test_cast_small(self):
707 707 """Integer casts small longs to int"""
708 708 if py3compat.PY3:
709 709 raise SkipTest("not relevant on py3")
710 710
711 711 self.obj.value = 100L
712 712 self.assertEquals(type(self.obj.value), int)
713 713
714 714
715 715 class FloatTrait(HasTraits):
716 716
717 717 value = Float(99.0)
718 718
719 719 class TestFloat(TraitTestBase):
720 720
721 721 obj = FloatTrait()
722 722
723 723 _default_value = 99.0
724 724 _good_values = [10, -10, 10.1, -10.1]
725 725 _bad_values = ['ten', u'ten', [10], {'ten': 10},(10,), None,
726 726 1j, '10', '-10', '10L', '-10L', '10.1', '-10.1', u'10',
727 727 u'-10', u'10L', u'-10L', u'10.1', u'-10.1']
728 728 if not py3compat.PY3:
729 729 _bad_values.extend([10L, -10L])
730 730
731 731
732 732 class ComplexTrait(HasTraits):
733 733
734 734 value = Complex(99.0-99.0j)
735 735
736 736 class TestComplex(TraitTestBase):
737 737
738 738 obj = ComplexTrait()
739 739
740 740 _default_value = 99.0-99.0j
741 741 _good_values = [10, -10, 10.1, -10.1, 10j, 10+10j, 10-10j,
742 742 10.1j, 10.1+10.1j, 10.1-10.1j]
743 743 _bad_values = [u'10L', u'-10L', 'ten', [10], {'ten': 10},(10,), None]
744 744 if not py3compat.PY3:
745 745 _bad_values.extend([10L, -10L])
746 746
747 747
748 748 class BytesTrait(HasTraits):
749 749
750 750 value = Bytes(b'string')
751 751
752 752 class TestBytes(TraitTestBase):
753 753
754 754 obj = BytesTrait()
755 755
756 756 _default_value = b'string'
757 757 _good_values = [b'10', b'-10', b'10L',
758 758 b'-10L', b'10.1', b'-10.1', b'string']
759 759 _bad_values = [10, -10, 10L, -10L, 10.1, -10.1, 1j, [10],
760 760 ['ten'],{'ten': 10},(10,), None, u'string']
761 761
762 762
763 763 class UnicodeTrait(HasTraits):
764 764
765 765 value = Unicode(u'unicode')
766 766
767 767 class TestUnicode(TraitTestBase):
768 768
769 769 obj = UnicodeTrait()
770 770
771 771 _default_value = u'unicode'
772 772 _good_values = ['10', '-10', '10L', '-10L', '10.1',
773 773 '-10.1', '', u'', 'string', u'string', u"€"]
774 774 _bad_values = [10, -10, 10L, -10L, 10.1, -10.1, 1j,
775 775 [10], ['ten'], [u'ten'], {'ten': 10},(10,), None]
776 776
777 777
778 778 class ObjectNameTrait(HasTraits):
779 779 value = ObjectName("abc")
780 780
781 781 class TestObjectName(TraitTestBase):
782 782 obj = ObjectNameTrait()
783 783
784 784 _default_value = "abc"
785 785 _good_values = ["a", "gh", "g9", "g_", "_G", u"a345_"]
786 786 _bad_values = [1, "", u"€", "9g", "!", "#abc", "aj@", "a.b", "a()", "a[0]",
787 787 object(), object]
788 788 if sys.version_info[0] < 3:
789 789 _bad_values.append(u"þ")
790 790 else:
791 791 _good_values.append(u"þ") # þ=1 is valid in Python 3 (PEP 3131).
792 792
793 793
794 794 class DottedObjectNameTrait(HasTraits):
795 795 value = DottedObjectName("a.b")
796 796
797 797 class TestDottedObjectName(TraitTestBase):
798 798 obj = DottedObjectNameTrait()
799 799
800 800 _default_value = "a.b"
801 801 _good_values = ["A", "y.t", "y765.__repr__", "os.path.join", u"os.path.join"]
802 802 _bad_values = [1, u"abc.€", "_.@", ".", ".abc", "abc.", ".abc."]
803 803 if sys.version_info[0] < 3:
804 804 _bad_values.append(u"t.þ")
805 805 else:
806 806 _good_values.append(u"t.þ")
807 807
808 808
809 809 class TCPAddressTrait(HasTraits):
810 810
811 811 value = TCPAddress()
812 812
813 813 class TestTCPAddress(TraitTestBase):
814 814
815 815 obj = TCPAddressTrait()
816 816
817 817 _default_value = ('127.0.0.1',0)
818 818 _good_values = [('localhost',0),('192.168.0.1',1000),('www.google.com',80)]
819 819 _bad_values = [(0,0),('localhost',10.0),('localhost',-1)]
820 820
821 821 class ListTrait(HasTraits):
822 822
823 823 value = List(Int)
824 824
825 825 class TestList(TraitTestBase):
826 826
827 827 obj = ListTrait()
828 828
829 829 _default_value = []
830 830 _good_values = [[], [1], range(10)]
831 831 _bad_values = [10, [1,'a'], 'a', (1,2)]
832 832
833 833 class LenListTrait(HasTraits):
834 834
835 835 value = List(Int, [0], minlen=1, maxlen=2)
836 836
837 837 class TestLenList(TraitTestBase):
838 838
839 839 obj = LenListTrait()
840 840
841 841 _default_value = [0]
842 842 _good_values = [[1], range(2)]
843 843 _bad_values = [10, [1,'a'], 'a', (1,2), [], range(3)]
844 844
845 845 class TupleTrait(HasTraits):
846 846
847 847 value = Tuple(Int)
848 848
849 849 class TestTupleTrait(TraitTestBase):
850 850
851 851 obj = TupleTrait()
852 852
853 853 _default_value = None
854 854 _good_values = [(1,), None,(0,)]
855 855 _bad_values = [10, (1,2), [1],('a'), ()]
856 856
857 857 def test_invalid_args(self):
858 858 self.assertRaises(TypeError, Tuple, 5)
859 859 self.assertRaises(TypeError, Tuple, default_value='hello')
860 860 t = Tuple(Int, CBytes, default_value=(1,5))
861 861
862 862 class LooseTupleTrait(HasTraits):
863 863
864 864 value = Tuple((1,2,3))
865 865
866 866 class TestLooseTupleTrait(TraitTestBase):
867 867
868 868 obj = LooseTupleTrait()
869 869
870 870 _default_value = (1,2,3)
871 871 _good_values = [(1,), None, (0,), tuple(range(5)), tuple('hello'), ('a',5), ()]
872 872 _bad_values = [10, 'hello', [1], []]
873 873
874 874 def test_invalid_args(self):
875 875 self.assertRaises(TypeError, Tuple, 5)
876 876 self.assertRaises(TypeError, Tuple, default_value='hello')
877 877 t = Tuple(Int, CBytes, default_value=(1,5))
878 878
879 879
880 880 class MultiTupleTrait(HasTraits):
881 881
882 882 value = Tuple(Int, Bytes, default_value=[99,b'bottles'])
883 883
884 884 class TestMultiTuple(TraitTestBase):
885 885
886 886 obj = MultiTupleTrait()
887 887
888 888 _default_value = (99,b'bottles')
889 889 _good_values = [(1,b'a'), (2,b'b')]
890 890 _bad_values = ((),10, b'a', (1,b'a',3), (b'a',1), (1, u'a'))
@@ -1,760 +1,760 b''
1 1 # encoding: utf-8
2 2 """
3 3 Utilities for working with strings and text.
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2009 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 import __main__
18 18
19 19 import locale
20 20 import os
21 21 import re
22 22 import shutil
23 23 import sys
24 24 import textwrap
25 25 from string import Formatter
26 26
27 27 from IPython.external.path import path
28 28 from IPython.testing.skipdoctest import skip_doctest_py3
29 29 from IPython.utils import py3compat
30 30 from IPython.utils.io import nlprint
31 31 from IPython.utils.data import flatten
32 32
33 33 #-----------------------------------------------------------------------------
34 34 # Code
35 35 #-----------------------------------------------------------------------------
36 36
37 37 # Less conservative replacement for sys.getdefaultencoding, that will try
38 38 # to match the environment.
39 39 # Defined here as central function, so if we find better choices, we
40 40 # won't need to make changes all over IPython.
41 41 def getdefaultencoding():
42 42 """Return IPython's guess for the default encoding for bytes as text.
43 43
44 44 Asks for stdin.encoding first, to match the calling Terminal, but that
45 45 is often None for subprocesses. Fall back on locale.getpreferredencoding()
46 46 which should be a sensible platform default (that respects LANG environment),
47 47 and finally to sys.getdefaultencoding() which is the most conservative option,
48 48 and usually ASCII.
49 49 """
50 50 enc = sys.stdin.encoding
51 51 if not enc or enc=='ascii':
52 52 try:
53 53 # There are reports of getpreferredencoding raising errors
54 54 # in some cases, which may well be fixed, but let's be conservative here.
55 55 enc = locale.getpreferredencoding()
56 56 except Exception:
57 57 pass
58 58 return enc or sys.getdefaultencoding()
59 59
60 60 def unquote_ends(istr):
61 61 """Remove a single pair of quotes from the endpoints of a string."""
62 62
63 63 if not istr:
64 64 return istr
65 65 if (istr[0]=="'" and istr[-1]=="'") or \
66 66 (istr[0]=='"' and istr[-1]=='"'):
67 67 return istr[1:-1]
68 68 else:
69 69 return istr
70 70
71 71
72 72 class LSString(str):
73 73 """String derivative with a special access attributes.
74 74
75 75 These are normal strings, but with the special attributes:
76 76
77 77 .l (or .list) : value as list (split on newlines).
78 78 .n (or .nlstr): original value (the string itself).
79 79 .s (or .spstr): value as whitespace-separated string.
80 80 .p (or .paths): list of path objects
81 81
82 82 Any values which require transformations are computed only once and
83 83 cached.
84 84
85 85 Such strings are very useful to efficiently interact with the shell, which
86 86 typically only understands whitespace-separated options for commands."""
87 87
88 88 def get_list(self):
89 89 try:
90 90 return self.__list
91 91 except AttributeError:
92 92 self.__list = self.split('\n')
93 93 return self.__list
94 94
95 95 l = list = property(get_list)
96 96
97 97 def get_spstr(self):
98 98 try:
99 99 return self.__spstr
100 100 except AttributeError:
101 101 self.__spstr = self.replace('\n',' ')
102 102 return self.__spstr
103 103
104 104 s = spstr = property(get_spstr)
105 105
106 106 def get_nlstr(self):
107 107 return self
108 108
109 109 n = nlstr = property(get_nlstr)
110 110
111 111 def get_paths(self):
112 112 try:
113 113 return self.__paths
114 114 except AttributeError:
115 115 self.__paths = [path(p) for p in self.split('\n') if os.path.exists(p)]
116 116 return self.__paths
117 117
118 118 p = paths = property(get_paths)
119 119
120 120 # FIXME: We need to reimplement type specific displayhook and then add this
121 121 # back as a custom printer. This should also be moved outside utils into the
122 122 # core.
123 123
124 124 # def print_lsstring(arg):
125 125 # """ Prettier (non-repr-like) and more informative printer for LSString """
126 126 # print "LSString (.p, .n, .l, .s available). Value:"
127 127 # print arg
128 128 #
129 129 #
130 130 # print_lsstring = result_display.when_type(LSString)(print_lsstring)
131 131
132 132
133 133 class SList(list):
134 134 """List derivative with a special access attributes.
135 135
136 136 These are normal lists, but with the special attributes:
137 137
138 138 .l (or .list) : value as list (the list itself).
139 139 .n (or .nlstr): value as a string, joined on newlines.
140 140 .s (or .spstr): value as a string, joined on spaces.
141 141 .p (or .paths): list of path objects
142 142
143 143 Any values which require transformations are computed only once and
144 144 cached."""
145 145
146 146 def get_list(self):
147 147 return self
148 148
149 149 l = list = property(get_list)
150 150
151 151 def get_spstr(self):
152 152 try:
153 153 return self.__spstr
154 154 except AttributeError:
155 155 self.__spstr = ' '.join(self)
156 156 return self.__spstr
157 157
158 158 s = spstr = property(get_spstr)
159 159
160 160 def get_nlstr(self):
161 161 try:
162 162 return self.__nlstr
163 163 except AttributeError:
164 164 self.__nlstr = '\n'.join(self)
165 165 return self.__nlstr
166 166
167 167 n = nlstr = property(get_nlstr)
168 168
169 169 def get_paths(self):
170 170 try:
171 171 return self.__paths
172 172 except AttributeError:
173 173 self.__paths = [path(p) for p in self if os.path.exists(p)]
174 174 return self.__paths
175 175
176 176 p = paths = property(get_paths)
177 177
178 178 def grep(self, pattern, prune = False, field = None):
179 179 """ Return all strings matching 'pattern' (a regex or callable)
180 180
181 181 This is case-insensitive. If prune is true, return all items
182 182 NOT matching the pattern.
183 183
184 184 If field is specified, the match must occur in the specified
185 185 whitespace-separated field.
186 186
187 187 Examples::
188 188
189 189 a.grep( lambda x: x.startswith('C') )
190 190 a.grep('Cha.*log', prune=1)
191 191 a.grep('chm', field=-1)
192 192 """
193 193
194 194 def match_target(s):
195 195 if field is None:
196 196 return s
197 197 parts = s.split()
198 198 try:
199 199 tgt = parts[field]
200 200 return tgt
201 201 except IndexError:
202 202 return ""
203 203
204 204 if isinstance(pattern, basestring):
205 205 pred = lambda x : re.search(pattern, x, re.IGNORECASE)
206 206 else:
207 207 pred = pattern
208 208 if not prune:
209 209 return SList([el for el in self if pred(match_target(el))])
210 210 else:
211 211 return SList([el for el in self if not pred(match_target(el))])
212 212
213 213 def fields(self, *fields):
214 214 """ Collect whitespace-separated fields from string list
215 215
216 216 Allows quick awk-like usage of string lists.
217 217
218 218 Example data (in var a, created by 'a = !ls -l')::
219 219 -rwxrwxrwx 1 ville None 18 Dec 14 2006 ChangeLog
220 220 drwxrwxrwx+ 6 ville None 0 Oct 24 18:05 IPython
221 221
222 222 a.fields(0) is ['-rwxrwxrwx', 'drwxrwxrwx+']
223 223 a.fields(1,0) is ['1 -rwxrwxrwx', '6 drwxrwxrwx+']
224 224 (note the joining by space).
225 225 a.fields(-1) is ['ChangeLog', 'IPython']
226 226
227 227 IndexErrors are ignored.
228 228
229 229 Without args, fields() just split()'s the strings.
230 230 """
231 231 if len(fields) == 0:
232 232 return [el.split() for el in self]
233 233
234 234 res = SList()
235 235 for el in [f.split() for f in self]:
236 236 lineparts = []
237 237
238 238 for fd in fields:
239 239 try:
240 240 lineparts.append(el[fd])
241 241 except IndexError:
242 242 pass
243 243 if lineparts:
244 244 res.append(" ".join(lineparts))
245 245
246 246 return res
247 247
248 248 def sort(self,field= None, nums = False):
249 249 """ sort by specified fields (see fields())
250 250
251 251 Example::
252 252 a.sort(1, nums = True)
253 253
254 254 Sorts a by second field, in numerical order (so that 21 > 3)
255 255
256 256 """
257 257
258 258 #decorate, sort, undecorate
259 259 if field is not None:
260 260 dsu = [[SList([line]).fields(field), line] for line in self]
261 261 else:
262 262 dsu = [[line, line] for line in self]
263 263 if nums:
264 264 for i in range(len(dsu)):
265 265 numstr = "".join([ch for ch in dsu[i][0] if ch.isdigit()])
266 266 try:
267 267 n = int(numstr)
268 268 except ValueError:
269 269 n = 0;
270 270 dsu[i][0] = n
271 271
272 272
273 273 dsu.sort()
274 274 return SList([t[1] for t in dsu])
275 275
276 276
277 277 # FIXME: We need to reimplement type specific displayhook and then add this
278 278 # back as a custom printer. This should also be moved outside utils into the
279 279 # core.
280 280
281 281 # def print_slist(arg):
282 282 # """ Prettier (non-repr-like) and more informative printer for SList """
283 283 # print "SList (.p, .n, .l, .s, .grep(), .fields(), sort() available):"
284 284 # if hasattr(arg, 'hideonce') and arg.hideonce:
285 285 # arg.hideonce = False
286 286 # return
287 287 #
288 288 # nlprint(arg)
289 289 #
290 290 # print_slist = result_display.when_type(SList)(print_slist)
291 291
292 292
293 293 def esc_quotes(strng):
294 294 """Return the input string with single and double quotes escaped out"""
295 295
296 296 return strng.replace('"','\\"').replace("'","\\'")
297 297
298 298
299 299 def qw(words,flat=0,sep=None,maxsplit=-1):
300 300 """Similar to Perl's qw() operator, but with some more options.
301 301
302 302 qw(words,flat=0,sep=' ',maxsplit=-1) -> words.split(sep,maxsplit)
303 303
304 304 words can also be a list itself, and with flat=1, the output will be
305 305 recursively flattened.
306 306
307 307 Examples:
308 308
309 309 >>> qw('1 2')
310 310 ['1', '2']
311 311
312 312 >>> qw(['a b','1 2',['m n','p q']])
313 313 [['a', 'b'], ['1', '2'], [['m', 'n'], ['p', 'q']]]
314 314
315 315 >>> qw(['a b','1 2',['m n','p q']],flat=1)
316 316 ['a', 'b', '1', '2', 'm', 'n', 'p', 'q']
317 317 """
318 318
319 319 if isinstance(words, basestring):
320 320 return [word.strip() for word in words.split(sep,maxsplit)
321 321 if word and not word.isspace() ]
322 322 if flat:
323 323 return flatten(map(qw,words,[1]*len(words)))
324 324 return map(qw,words)
325 325
326 326
327 327 def qwflat(words,sep=None,maxsplit=-1):
328 328 """Calls qw(words) in flat mode. It's just a convenient shorthand."""
329 329 return qw(words,1,sep,maxsplit)
330 330
331 331
332 332 def qw_lol(indata):
333 333 """qw_lol('a b') -> [['a','b']],
334 334 otherwise it's just a call to qw().
335 335
336 336 We need this to make sure the modules_some keys *always* end up as a
337 337 list of lists."""
338 338
339 339 if isinstance(indata, basestring):
340 340 return [qw(indata)]
341 341 else:
342 342 return qw(indata)
343 343
344 344
345 345 def grep(pat,list,case=1):
346 346 """Simple minded grep-like function.
347 347 grep(pat,list) returns occurrences of pat in list, None on failure.
348 348
349 349 It only does simple string matching, with no support for regexps. Use the
350 350 option case=0 for case-insensitive matching."""
351 351
352 352 # This is pretty crude. At least it should implement copying only references
353 353 # to the original data in case it's big. Now it copies the data for output.
354 354 out=[]
355 355 if case:
356 356 for term in list:
357 357 if term.find(pat)>-1: out.append(term)
358 358 else:
359 359 lpat=pat.lower()
360 360 for term in list:
361 361 if term.lower().find(lpat)>-1: out.append(term)
362 362
363 363 if len(out): return out
364 364 else: return None
365 365
366 366
367 367 def dgrep(pat,*opts):
368 368 """Return grep() on dir()+dir(__builtins__).
369 369
370 370 A very common use of grep() when working interactively."""
371 371
372 372 return grep(pat,dir(__main__)+dir(__main__.__builtins__),*opts)
373 373
374 374
375 375 def idgrep(pat):
376 376 """Case-insensitive dgrep()"""
377 377
378 378 return dgrep(pat,0)
379 379
380 380
381 381 def igrep(pat,list):
382 382 """Synonym for case-insensitive grep."""
383 383
384 384 return grep(pat,list,case=0)
385 385
386 386
387 387 def indent(instr,nspaces=4, ntabs=0, flatten=False):
388 388 """Indent a string a given number of spaces or tabstops.
389 389
390 390 indent(str,nspaces=4,ntabs=0) -> indent str by ntabs+nspaces.
391 391
392 392 Parameters
393 393 ----------
394 394
395 395 instr : basestring
396 396 The string to be indented.
397 397 nspaces : int (default: 4)
398 398 The number of spaces to be indented.
399 399 ntabs : int (default: 0)
400 400 The number of tabs to be indented.
401 401 flatten : bool (default: False)
402 402 Whether to scrub existing indentation. If True, all lines will be
403 403 aligned to the same indentation. If False, existing indentation will
404 404 be strictly increased.
405 405
406 406 Returns
407 407 -------
408 408
409 409 str|unicode : string indented by ntabs and nspaces.
410 410
411 411 """
412 412 if instr is None:
413 413 return
414 414 ind = '\t'*ntabs+' '*nspaces
415 415 if flatten:
416 416 pat = re.compile(r'^\s*', re.MULTILINE)
417 417 else:
418 418 pat = re.compile(r'^', re.MULTILINE)
419 419 outstr = re.sub(pat, ind, instr)
420 420 if outstr.endswith(os.linesep+ind):
421 421 return outstr[:-len(ind)]
422 422 else:
423 423 return outstr
424 424
425 425 def native_line_ends(filename,backup=1):
426 426 """Convert (in-place) a file to line-ends native to the current OS.
427 427
428 428 If the optional backup argument is given as false, no backup of the
429 429 original file is left. """
430 430
431 431 backup_suffixes = {'posix':'~','dos':'.bak','nt':'.bak','mac':'.bak'}
432 432
433 433 bak_filename = filename + backup_suffixes[os.name]
434 434
435 435 original = open(filename).read()
436 436 shutil.copy2(filename,bak_filename)
437 437 try:
438 438 new = open(filename,'wb')
439 439 new.write(os.linesep.join(original.splitlines()))
440 440 new.write(os.linesep) # ALWAYS put an eol at the end of the file
441 441 new.close()
442 442 except:
443 443 os.rename(bak_filename,filename)
444 444 if not backup:
445 445 try:
446 446 os.remove(bak_filename)
447 447 except:
448 448 pass
449 449
450 450
451 451 def list_strings(arg):
452 452 """Always return a list of strings, given a string or list of strings
453 453 as input.
454 454
455 455 :Examples:
456 456
457 457 In [7]: list_strings('A single string')
458 458 Out[7]: ['A single string']
459 459
460 460 In [8]: list_strings(['A single string in a list'])
461 461 Out[8]: ['A single string in a list']
462 462
463 463 In [9]: list_strings(['A','list','of','strings'])
464 464 Out[9]: ['A', 'list', 'of', 'strings']
465 465 """
466 466
467 467 if isinstance(arg,basestring): return [arg]
468 468 else: return arg
469 469
470 470
471 471 def marquee(txt='',width=78,mark='*'):
472 472 """Return the input string centered in a 'marquee'.
473 473
474 474 :Examples:
475 475
476 476 In [16]: marquee('A test',40)
477 477 Out[16]: '**************** A test ****************'
478 478
479 479 In [17]: marquee('A test',40,'-')
480 480 Out[17]: '---------------- A test ----------------'
481 481
482 482 In [18]: marquee('A test',40,' ')
483 483 Out[18]: ' A test '
484 484
485 485 """
486 486 if not txt:
487 487 return (mark*width)[:width]
488 488 nmark = (width-len(txt)-2)//len(mark)//2
489 489 if nmark < 0: nmark =0
490 490 marks = mark*nmark
491 491 return '%s %s %s' % (marks,txt,marks)
492 492
493 493
494 494 ini_spaces_re = re.compile(r'^(\s+)')
495 495
496 496 def num_ini_spaces(strng):
497 497 """Return the number of initial spaces in a string"""
498 498
499 499 ini_spaces = ini_spaces_re.match(strng)
500 500 if ini_spaces:
501 501 return ini_spaces.end()
502 502 else:
503 503 return 0
504 504
505 505
506 506 def format_screen(strng):
507 507 """Format a string for screen printing.
508 508
509 509 This removes some latex-type format codes."""
510 510 # Paragraph continue
511 511 par_re = re.compile(r'\\$',re.MULTILINE)
512 512 strng = par_re.sub('',strng)
513 513 return strng
514 514
515 515 def dedent(text):
516 516 """Equivalent of textwrap.dedent that ignores unindented first line.
517 517
518 518 This means it will still dedent strings like:
519 519 '''foo
520 520 is a bar
521 521 '''
522 522
523 523 For use in wrap_paragraphs.
524 524 """
525 525
526 526 if text.startswith('\n'):
527 527 # text starts with blank line, don't ignore the first line
528 528 return textwrap.dedent(text)
529 529
530 530 # split first line
531 531 splits = text.split('\n',1)
532 532 if len(splits) == 1:
533 533 # only one line
534 534 return textwrap.dedent(text)
535 535
536 536 first, rest = splits
537 537 # dedent everything but the first line
538 538 rest = textwrap.dedent(rest)
539 539 return '\n'.join([first, rest])
540 540
541 541 def wrap_paragraphs(text, ncols=80):
542 542 """Wrap multiple paragraphs to fit a specified width.
543 543
544 544 This is equivalent to textwrap.wrap, but with support for multiple
545 545 paragraphs, as separated by empty lines.
546 546
547 547 Returns
548 548 -------
549 549
550 550 list of complete paragraphs, wrapped to fill `ncols` columns.
551 551 """
552 552 paragraph_re = re.compile(r'\n(\s*\n)+', re.MULTILINE)
553 553 text = dedent(text).strip()
554 554 paragraphs = paragraph_re.split(text)[::2] # every other entry is space
555 555 out_ps = []
556 556 indent_re = re.compile(r'\n\s+', re.MULTILINE)
557 557 for p in paragraphs:
558 558 # presume indentation that survives dedent is meaningful formatting,
559 559 # so don't fill unless text is flush.
560 560 if indent_re.search(p) is None:
561 561 # wrap paragraph
562 562 p = textwrap.fill(p, ncols)
563 563 out_ps.append(p)
564 564 return out_ps
565 565
566 566
567 567 class EvalFormatter(Formatter):
568 568 """A String Formatter that allows evaluation of simple expressions.
569 569
570 570 Note that this version interprets a : as specifying a format string (as per
571 571 standard string formatting), so if slicing is required, you must explicitly
572 572 create a slice.
573 573
574 574 This is to be used in templating cases, such as the parallel batch
575 575 script templates, where simple arithmetic on arguments is useful.
576 576
577 577 Examples
578 578 --------
579 579
580 580 In [1]: f = EvalFormatter()
581 581 In [2]: f.format('{n//4}', n=8)
582 582 Out [2]: '2'
583 583
584 584 In [3]: f.format("{greeting[slice(2,4)]}", greeting="Hello")
585 585 Out [3]: 'll'
586 586 """
587 587 def get_field(self, name, args, kwargs):
588 588 v = eval(name, kwargs)
589 589 return v, name
590 590
591 591 @skip_doctest_py3
592 592 class FullEvalFormatter(Formatter):
593 593 """A String Formatter that allows evaluation of simple expressions.
594 594
595 595 Any time a format key is not found in the kwargs,
596 596 it will be tried as an expression in the kwargs namespace.
597 597
598 598 Note that this version allows slicing using [1:2], so you cannot specify
599 599 a format string. Use :class:`EvalFormatter` to permit format strings.
600 600
601 601 Examples
602 602 --------
603 603
604 604 In [1]: f = FullEvalFormatter()
605 605 In [2]: f.format('{n//4}', n=8)
606 606 Out[2]: u'2'
607 607
608 608 In [3]: f.format('{list(range(5))[2:4]}')
609 609 Out[3]: u'[2, 3]'
610 610
611 611 In [4]: f.format('{3*2}')
612 612 Out[4]: u'6'
613 613 """
614 614 # copied from Formatter._vformat with minor changes to allow eval
615 615 # and replace the format_spec code with slicing
616 616 def _vformat(self, format_string, args, kwargs, used_args, recursion_depth):
617 617 if recursion_depth < 0:
618 618 raise ValueError('Max string recursion exceeded')
619 619 result = []
620 620 for literal_text, field_name, format_spec, conversion in \
621 621 self.parse(format_string):
622 622
623 623 # output the literal text
624 624 if literal_text:
625 625 result.append(literal_text)
626 626
627 627 # if there's a field, output it
628 628 if field_name is not None:
629 629 # this is some markup, find the object and do
630 630 # the formatting
631 631
632 632 if format_spec:
633 633 # override format spec, to allow slicing:
634 634 field_name = ':'.join([field_name, format_spec])
635 635
636 636 # eval the contents of the field for the object
637 637 # to be formatted
638 638 obj = eval(field_name, kwargs)
639 639
640 640 # do any conversion on the resulting object
641 641 obj = self.convert_field(obj, conversion)
642 642
643 643 # format the object and append to the result
644 644 result.append(self.format_field(obj, ''))
645 645
646 646 return u''.join(py3compat.cast_unicode(s) for s in result)
647 647
648 648 @skip_doctest_py3
649 649 class DollarFormatter(FullEvalFormatter):
650 650 """Formatter allowing Itpl style $foo replacement, for names and attribute
651 651 access only. Standard {foo} replacement also works, and allows full
652 652 evaluation of its arguments.
653 653
654 654 Examples
655 655 --------
656 656 In [1]: f = DollarFormatter()
657 657 In [2]: f.format('{n//4}', n=8)
658 658 Out[2]: u'2'
659 659
660 660 In [3]: f.format('23 * 76 is $result', result=23*76)
661 661 Out[3]: u'23 * 76 is 1748'
662 662
663 663 In [4]: f.format('$a or {b}', a=1, b=2)
664 664 Out[4]: u'1 or 2'
665 665 """
666 666 _dollar_pattern = re.compile("(.*?)\$(\$?[\w\.]+)")
667 667 def parse(self, fmt_string):
668 668 for literal_txt, field_name, format_spec, conversion \
669 669 in Formatter.parse(self, fmt_string):
670 670
671 671 # Find $foo patterns in the literal text.
672 672 continue_from = 0
673 673 txt = ""
674 674 for m in self._dollar_pattern.finditer(literal_txt):
675 675 new_txt, new_field = m.group(1,2)
676 676 # $$foo --> $foo
677 677 if new_field.startswith("$"):
678 678 txt += new_txt + new_field
679 679 else:
680 680 yield (txt + new_txt, new_field, "", None)
681 681 txt = ""
682 682 continue_from = m.end()
683 683
684 684 # Re-yield the {foo} style pattern
685 685 yield (txt + literal_txt[continue_from:], field_name, format_spec, conversion)
686 686
687 687
688 688 def columnize(items, separator=' ', displaywidth=80):
689 689 """ Transform a list of strings into a single string with columns.
690 690
691 691 Parameters
692 692 ----------
693 693 items : sequence of strings
694 694 The strings to process.
695 695
696 696 separator : str, optional [default is two spaces]
697 697 The string that separates columns.
698 698
699 699 displaywidth : int, optional [default is 80]
700 700 Width of the display in number of characters.
701 701
702 702 Returns
703 703 -------
704 704 The formatted string.
705 705 """
706 706 # Note: this code is adapted from columnize 0.3.2.
707 707 # See http://code.google.com/p/pycolumnize/
708 708
709 709 # Some degenerate cases.
710 710 size = len(items)
711 711 if size == 0:
712 712 return '\n'
713 713 elif size == 1:
714 714 return '%s\n' % items[0]
715 715
716 716 # Special case: if any item is longer than the maximum width, there's no
717 717 # point in triggering the logic below...
718 718 item_len = map(len, items) # save these, we can reuse them below
719 719 longest = max(item_len)
720 720 if longest >= displaywidth:
721 721 return '\n'.join(items+[''])
722 722
723 723 # Try every row count from 1 upwards
724 724 array_index = lambda nrows, row, col: nrows*col + row
725 725 for nrows in range(1, size):
726 726 ncols = (size + nrows - 1) // nrows
727 727 colwidths = []
728 728 totwidth = -len(separator)
729 729 for col in range(ncols):
730 730 # Get max column width for this column
731 731 colwidth = 0
732 732 for row in range(nrows):
733 733 i = array_index(nrows, row, col)
734 734 if i >= size: break
735 735 x, len_x = items[i], item_len[i]
736 736 colwidth = max(colwidth, len_x)
737 737 colwidths.append(colwidth)
738 738 totwidth += colwidth + len(separator)
739 739 if totwidth > displaywidth:
740 740 break
741 741 if totwidth <= displaywidth:
742 742 break
743 743
744 744 # The smallest number of rows computed and the max widths for each
745 745 # column has been obtained. Now we just have to format each of the rows.
746 746 string = ''
747 747 for row in range(nrows):
748 748 texts = []
749 749 for col in range(ncols):
750 750 i = row + nrows*col
751 751 if i >= size:
752 752 texts.append('')
753 753 else:
754 754 texts.append(items[i])
755 755 while texts and not texts[-1]:
756 756 del texts[-1]
757 757 for col in range(len(texts)):
758 758 texts[col] = texts[col].ljust(colwidths[col])
759 759 string += '%s\n' % separator.join(texts)
760 760 return string
@@ -1,116 +1,116 b''
1 1 # encoding: utf-8
2 2 """
3 3 Utilities for timing code execution.
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2009 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 import time
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Code
21 21 #-----------------------------------------------------------------------------
22 22
23 23 # If possible (Unix), use the resource module instead of time.clock()
24 24 try:
25 25 import resource
26 26 def clocku():
27 27 """clocku() -> floating point number
28 28
29 29 Return the *USER* CPU time in seconds since the start of the process.
30 30 This is done via a call to resource.getrusage, so it avoids the
31 31 wraparound problems in time.clock()."""
32 32
33 33 return resource.getrusage(resource.RUSAGE_SELF)[0]
34 34
35 35 def clocks():
36 36 """clocks() -> floating point number
37 37
38 38 Return the *SYSTEM* CPU time in seconds since the start of the process.
39 39 This is done via a call to resource.getrusage, so it avoids the
40 40 wraparound problems in time.clock()."""
41 41
42 42 return resource.getrusage(resource.RUSAGE_SELF)[1]
43 43
44 44 def clock():
45 45 """clock() -> floating point number
46 46
47 47 Return the *TOTAL USER+SYSTEM* CPU time in seconds since the start of
48 48 the process. This is done via a call to resource.getrusage, so it
49 49 avoids the wraparound problems in time.clock()."""
50 50
51 51 u,s = resource.getrusage(resource.RUSAGE_SELF)[:2]
52 52 return u+s
53 53
54 54 def clock2():
55 55 """clock2() -> (t_user,t_system)
56 56
57 57 Similar to clock(), but return a tuple of user/system times."""
58 58 return resource.getrusage(resource.RUSAGE_SELF)[:2]
59 59 except ImportError:
60 60 # There is no distinction of user/system time under windows, so we just use
61 61 # time.clock() for everything...
62 62 clocku = clocks = clock = time.clock
63 63 def clock2():
64 64 """Under windows, system CPU time can't be measured.
65 65
66 66 This just returns clock() and zero."""
67 67 return time.clock(),0.0
68 68
69 69
70 70 def timings_out(reps,func,*args,**kw):
71 71 """timings_out(reps,func,*args,**kw) -> (t_total,t_per_call,output)
72 72
73 73 Execute a function reps times, return a tuple with the elapsed total
74 74 CPU time in seconds, the time per call and the function's output.
75 75
76 76 Under Unix, the return value is the sum of user+system time consumed by
77 77 the process, computed via the resource module. This prevents problems
78 78 related to the wraparound effect which the time.clock() function has.
79 79
80 80 Under Windows the return value is in wall clock seconds. See the
81 81 documentation for the time module for more details."""
82 82
83 83 reps = int(reps)
84 84 assert reps >=1, 'reps must be >= 1'
85 85 if reps==1:
86 86 start = clock()
87 87 out = func(*args,**kw)
88 88 tot_time = clock()-start
89 89 else:
90 90 rng = xrange(reps-1) # the last time is executed separately to store output
91 91 start = clock()
92 92 for dummy in rng: func(*args,**kw)
93 93 out = func(*args,**kw) # one last time
94 94 tot_time = clock()-start
95 95 av_time = tot_time / reps
96 96 return tot_time,av_time,out
97 97
98 98
99 99 def timings(reps,func,*args,**kw):
100 100 """timings(reps,func,*args,**kw) -> (t_total,t_per_call)
101 101
102 102 Execute a function reps times, return a tuple with the elapsed total CPU
103 103 time in seconds and the time per call. These are just the first two values
104 104 in timings_out()."""
105 105
106 106 return timings_out(reps,func,*args,**kw)[0:2]
107 107
108 108
109 109 def timing(func,*args,**kw):
110 110 """timing(func,*args,**kw) -> t_total
111 111
112 112 Execute a function once, return the elapsed total CPU time in
113 113 seconds. This is just the first value in timings_out()."""
114 114
115 115 return timings_out(1,func,*args,**kw)[0]
116 116
@@ -1,1413 +1,1413 b''
1 1 # encoding: utf-8
2 2 """
3 3 A lightweight Traits like module.
4 4
5 5 This is designed to provide a lightweight, simple, pure Python version of
6 6 many of the capabilities of enthought.traits. This includes:
7 7
8 8 * Validation
9 9 * Type specification with defaults
10 10 * Static and dynamic notification
11 11 * Basic predefined types
12 12 * An API that is similar to enthought.traits
13 13
14 14 We don't support:
15 15
16 16 * Delegation
17 17 * Automatic GUI generation
18 18 * A full set of trait types. Most importantly, we don't provide container
19 19 traits (list, dict, tuple) that can trigger notifications if their
20 20 contents change.
21 21 * API compatibility with enthought.traits
22 22
23 23 There are also some important difference in our design:
24 24
25 25 * enthought.traits does not validate default values. We do.
26 26
27 27 We choose to create this module because we need these capabilities, but
28 28 we need them to be pure Python so they work in all Python implementations,
29 29 including Jython and IronPython.
30 30
31 31 Authors:
32 32
33 33 * Brian Granger
34 34 * Enthought, Inc. Some of the code in this file comes from enthought.traits
35 35 and is licensed under the BSD license. Also, many of the ideas also come
36 36 from enthought.traits even though our implementation is very different.
37 37 """
38 38
39 39 #-----------------------------------------------------------------------------
40 # Copyright (C) 2008-2009 The IPython Development Team
40 # Copyright (C) 2008-2011 The IPython Development Team
41 41 #
42 42 # Distributed under the terms of the BSD License. The full license is in
43 43 # the file COPYING, distributed as part of this software.
44 44 #-----------------------------------------------------------------------------
45 45
46 46 #-----------------------------------------------------------------------------
47 47 # Imports
48 48 #-----------------------------------------------------------------------------
49 49
50 50
51 51 import inspect
52 52 import re
53 53 import sys
54 54 import types
55 55 from types import FunctionType
56 56 try:
57 57 from types import ClassType, InstanceType
58 58 ClassTypes = (ClassType, type)
59 59 except:
60 60 ClassTypes = (type,)
61 61
62 62 from .importstring import import_item
63 63 from IPython.utils import py3compat
64 64
65 65 SequenceTypes = (list, tuple, set, frozenset)
66 66
67 67 #-----------------------------------------------------------------------------
68 68 # Basic classes
69 69 #-----------------------------------------------------------------------------
70 70
71 71
72 72 class NoDefaultSpecified ( object ): pass
73 73 NoDefaultSpecified = NoDefaultSpecified()
74 74
75 75
76 76 class Undefined ( object ): pass
77 77 Undefined = Undefined()
78 78
79 79 class TraitError(Exception):
80 80 pass
81 81
82 82 #-----------------------------------------------------------------------------
83 83 # Utilities
84 84 #-----------------------------------------------------------------------------
85 85
86 86
87 87 def class_of ( object ):
88 88 """ Returns a string containing the class name of an object with the
89 89 correct indefinite article ('a' or 'an') preceding it (e.g., 'an Image',
90 90 'a PlotValue').
91 91 """
92 92 if isinstance( object, basestring ):
93 93 return add_article( object )
94 94
95 95 return add_article( object.__class__.__name__ )
96 96
97 97
98 98 def add_article ( name ):
99 99 """ Returns a string containing the correct indefinite article ('a' or 'an')
100 100 prefixed to the specified string.
101 101 """
102 102 if name[:1].lower() in 'aeiou':
103 103 return 'an ' + name
104 104
105 105 return 'a ' + name
106 106
107 107
108 108 def repr_type(obj):
109 109 """ Return a string representation of a value and its type for readable
110 110 error messages.
111 111 """
112 112 the_type = type(obj)
113 113 if (not py3compat.PY3) and the_type is InstanceType:
114 114 # Old-style class.
115 115 the_type = obj.__class__
116 116 msg = '%r %r' % (obj, the_type)
117 117 return msg
118 118
119 119
120 120 def parse_notifier_name(name):
121 121 """Convert the name argument to a list of names.
122 122
123 123 Examples
124 124 --------
125 125
126 126 >>> parse_notifier_name('a')
127 127 ['a']
128 128 >>> parse_notifier_name(['a','b'])
129 129 ['a', 'b']
130 130 >>> parse_notifier_name(None)
131 131 ['anytrait']
132 132 """
133 133 if isinstance(name, str):
134 134 return [name]
135 135 elif name is None:
136 136 return ['anytrait']
137 137 elif isinstance(name, (list, tuple)):
138 138 for n in name:
139 139 assert isinstance(n, str), "names must be strings"
140 140 return name
141 141
142 142
143 143 class _SimpleTest:
144 144 def __init__ ( self, value ): self.value = value
145 145 def __call__ ( self, test ):
146 146 return test == self.value
147 147 def __repr__(self):
148 148 return "<SimpleTest(%r)" % self.value
149 149 def __str__(self):
150 150 return self.__repr__()
151 151
152 152
153 153 def getmembers(object, predicate=None):
154 154 """A safe version of inspect.getmembers that handles missing attributes.
155 155
156 156 This is useful when there are descriptor based attributes that for
157 157 some reason raise AttributeError even though they exist. This happens
158 158 in zope.inteface with the __provides__ attribute.
159 159 """
160 160 results = []
161 161 for key in dir(object):
162 162 try:
163 163 value = getattr(object, key)
164 164 except AttributeError:
165 165 pass
166 166 else:
167 167 if not predicate or predicate(value):
168 168 results.append((key, value))
169 169 results.sort()
170 170 return results
171 171
172 172
173 173 #-----------------------------------------------------------------------------
174 174 # Base TraitType for all traits
175 175 #-----------------------------------------------------------------------------
176 176
177 177
178 178 class TraitType(object):
179 179 """A base class for all trait descriptors.
180 180
181 181 Notes
182 182 -----
183 183 Our implementation of traits is based on Python's descriptor
184 184 prototol. This class is the base class for all such descriptors. The
185 185 only magic we use is a custom metaclass for the main :class:`HasTraits`
186 186 class that does the following:
187 187
188 188 1. Sets the :attr:`name` attribute of every :class:`TraitType`
189 189 instance in the class dict to the name of the attribute.
190 190 2. Sets the :attr:`this_class` attribute of every :class:`TraitType`
191 191 instance in the class dict to the *class* that declared the trait.
192 192 This is used by the :class:`This` trait to allow subclasses to
193 193 accept superclasses for :class:`This` values.
194 194 """
195 195
196 196
197 197 metadata = {}
198 198 default_value = Undefined
199 199 info_text = 'any value'
200 200
201 201 def __init__(self, default_value=NoDefaultSpecified, **metadata):
202 202 """Create a TraitType.
203 203 """
204 204 if default_value is not NoDefaultSpecified:
205 205 self.default_value = default_value
206 206
207 207 if len(metadata) > 0:
208 208 if len(self.metadata) > 0:
209 209 self._metadata = self.metadata.copy()
210 210 self._metadata.update(metadata)
211 211 else:
212 212 self._metadata = metadata
213 213 else:
214 214 self._metadata = self.metadata
215 215
216 216 self.init()
217 217
218 218 def init(self):
219 219 pass
220 220
221 221 def get_default_value(self):
222 222 """Create a new instance of the default value."""
223 223 return self.default_value
224 224
225 225 def instance_init(self, obj):
226 226 """This is called by :meth:`HasTraits.__new__` to finish init'ing.
227 227
228 228 Some stages of initialization must be delayed until the parent
229 229 :class:`HasTraits` instance has been created. This method is
230 230 called in :meth:`HasTraits.__new__` after the instance has been
231 231 created.
232 232
233 233 This method trigger the creation and validation of default values
234 234 and also things like the resolution of str given class names in
235 235 :class:`Type` and :class`Instance`.
236 236
237 237 Parameters
238 238 ----------
239 239 obj : :class:`HasTraits` instance
240 240 The parent :class:`HasTraits` instance that has just been
241 241 created.
242 242 """
243 243 self.set_default_value(obj)
244 244
245 245 def set_default_value(self, obj):
246 246 """Set the default value on a per instance basis.
247 247
248 248 This method is called by :meth:`instance_init` to create and
249 249 validate the default value. The creation and validation of
250 250 default values must be delayed until the parent :class:`HasTraits`
251 251 class has been instantiated.
252 252 """
253 253 # Check for a deferred initializer defined in the same class as the
254 254 # trait declaration or above.
255 255 mro = type(obj).mro()
256 256 meth_name = '_%s_default' % self.name
257 257 for cls in mro[:mro.index(self.this_class)+1]:
258 258 if meth_name in cls.__dict__:
259 259 break
260 260 else:
261 261 # We didn't find one. Do static initialization.
262 262 dv = self.get_default_value()
263 263 newdv = self._validate(obj, dv)
264 264 obj._trait_values[self.name] = newdv
265 265 return
266 266 # Complete the dynamic initialization.
267 267 obj._trait_dyn_inits[self.name] = cls.__dict__[meth_name]
268 268
269 269 def __get__(self, obj, cls=None):
270 270 """Get the value of the trait by self.name for the instance.
271 271
272 272 Default values are instantiated when :meth:`HasTraits.__new__`
273 273 is called. Thus by the time this method gets called either the
274 274 default value or a user defined value (they called :meth:`__set__`)
275 275 is in the :class:`HasTraits` instance.
276 276 """
277 277 if obj is None:
278 278 return self
279 279 else:
280 280 try:
281 281 value = obj._trait_values[self.name]
282 282 except KeyError:
283 283 # Check for a dynamic initializer.
284 284 if self.name in obj._trait_dyn_inits:
285 285 value = obj._trait_dyn_inits[self.name](obj)
286 286 # FIXME: Do we really validate here?
287 287 value = self._validate(obj, value)
288 288 obj._trait_values[self.name] = value
289 289 return value
290 290 else:
291 291 raise TraitError('Unexpected error in TraitType: '
292 292 'both default value and dynamic initializer are '
293 293 'absent.')
294 294 except Exception:
295 295 # HasTraits should call set_default_value to populate
296 296 # this. So this should never be reached.
297 297 raise TraitError('Unexpected error in TraitType: '
298 298 'default value not set properly')
299 299 else:
300 300 return value
301 301
302 302 def __set__(self, obj, value):
303 303 new_value = self._validate(obj, value)
304 304 old_value = self.__get__(obj)
305 305 if old_value != new_value:
306 306 obj._trait_values[self.name] = new_value
307 307 obj._notify_trait(self.name, old_value, new_value)
308 308
309 309 def _validate(self, obj, value):
310 310 if hasattr(self, 'validate'):
311 311 return self.validate(obj, value)
312 312 elif hasattr(self, 'is_valid_for'):
313 313 valid = self.is_valid_for(value)
314 314 if valid:
315 315 return value
316 316 else:
317 317 raise TraitError('invalid value for type: %r' % value)
318 318 elif hasattr(self, 'value_for'):
319 319 return self.value_for(value)
320 320 else:
321 321 return value
322 322
323 323 def info(self):
324 324 return self.info_text
325 325
326 326 def error(self, obj, value):
327 327 if obj is not None:
328 328 e = "The '%s' trait of %s instance must be %s, but a value of %s was specified." \
329 329 % (self.name, class_of(obj),
330 330 self.info(), repr_type(value))
331 331 else:
332 332 e = "The '%s' trait must be %s, but a value of %r was specified." \
333 333 % (self.name, self.info(), repr_type(value))
334 334 raise TraitError(e)
335 335
336 336 def get_metadata(self, key):
337 337 return getattr(self, '_metadata', {}).get(key, None)
338 338
339 339 def set_metadata(self, key, value):
340 340 getattr(self, '_metadata', {})[key] = value
341 341
342 342
343 343 #-----------------------------------------------------------------------------
344 344 # The HasTraits implementation
345 345 #-----------------------------------------------------------------------------
346 346
347 347
348 348 class MetaHasTraits(type):
349 349 """A metaclass for HasTraits.
350 350
351 351 This metaclass makes sure that any TraitType class attributes are
352 352 instantiated and sets their name attribute.
353 353 """
354 354
355 355 def __new__(mcls, name, bases, classdict):
356 356 """Create the HasTraits class.
357 357
358 358 This instantiates all TraitTypes in the class dict and sets their
359 359 :attr:`name` attribute.
360 360 """
361 361 # print "MetaHasTraitlets (mcls, name): ", mcls, name
362 362 # print "MetaHasTraitlets (bases): ", bases
363 363 # print "MetaHasTraitlets (classdict): ", classdict
364 364 for k,v in classdict.iteritems():
365 365 if isinstance(v, TraitType):
366 366 v.name = k
367 367 elif inspect.isclass(v):
368 368 if issubclass(v, TraitType):
369 369 vinst = v()
370 370 vinst.name = k
371 371 classdict[k] = vinst
372 372 return super(MetaHasTraits, mcls).__new__(mcls, name, bases, classdict)
373 373
374 374 def __init__(cls, name, bases, classdict):
375 375 """Finish initializing the HasTraits class.
376 376
377 377 This sets the :attr:`this_class` attribute of each TraitType in the
378 378 class dict to the newly created class ``cls``.
379 379 """
380 380 for k, v in classdict.iteritems():
381 381 if isinstance(v, TraitType):
382 382 v.this_class = cls
383 383 super(MetaHasTraits, cls).__init__(name, bases, classdict)
384 384
385 385 class HasTraits(object):
386 386
387 387 __metaclass__ = MetaHasTraits
388 388
389 389 def __new__(cls, **kw):
390 390 # This is needed because in Python 2.6 object.__new__ only accepts
391 391 # the cls argument.
392 392 new_meth = super(HasTraits, cls).__new__
393 393 if new_meth is object.__new__:
394 394 inst = new_meth(cls)
395 395 else:
396 396 inst = new_meth(cls, **kw)
397 397 inst._trait_values = {}
398 398 inst._trait_notifiers = {}
399 399 inst._trait_dyn_inits = {}
400 400 # Here we tell all the TraitType instances to set their default
401 401 # values on the instance.
402 402 for key in dir(cls):
403 403 # Some descriptors raise AttributeError like zope.interface's
404 404 # __provides__ attributes even though they exist. This causes
405 405 # AttributeErrors even though they are listed in dir(cls).
406 406 try:
407 407 value = getattr(cls, key)
408 408 except AttributeError:
409 409 pass
410 410 else:
411 411 if isinstance(value, TraitType):
412 412 value.instance_init(inst)
413 413
414 414 return inst
415 415
416 416 def __init__(self, **kw):
417 417 # Allow trait values to be set using keyword arguments.
418 418 # We need to use setattr for this to trigger validation and
419 419 # notifications.
420 420 for key, value in kw.iteritems():
421 421 setattr(self, key, value)
422 422
423 423 def _notify_trait(self, name, old_value, new_value):
424 424
425 425 # First dynamic ones
426 426 callables = self._trait_notifiers.get(name,[])
427 427 more_callables = self._trait_notifiers.get('anytrait',[])
428 428 callables.extend(more_callables)
429 429
430 430 # Now static ones
431 431 try:
432 432 cb = getattr(self, '_%s_changed' % name)
433 433 except:
434 434 pass
435 435 else:
436 436 callables.append(cb)
437 437
438 438 # Call them all now
439 439 for c in callables:
440 440 # Traits catches and logs errors here. I allow them to raise
441 441 if callable(c):
442 442 argspec = inspect.getargspec(c)
443 443 nargs = len(argspec[0])
444 444 # Bound methods have an additional 'self' argument
445 445 # I don't know how to treat unbound methods, but they
446 446 # can't really be used for callbacks.
447 447 if isinstance(c, types.MethodType):
448 448 offset = -1
449 449 else:
450 450 offset = 0
451 451 if nargs + offset == 0:
452 452 c()
453 453 elif nargs + offset == 1:
454 454 c(name)
455 455 elif nargs + offset == 2:
456 456 c(name, new_value)
457 457 elif nargs + offset == 3:
458 458 c(name, old_value, new_value)
459 459 else:
460 460 raise TraitError('a trait changed callback '
461 461 'must have 0-3 arguments.')
462 462 else:
463 463 raise TraitError('a trait changed callback '
464 464 'must be callable.')
465 465
466 466
467 467 def _add_notifiers(self, handler, name):
468 468 if not self._trait_notifiers.has_key(name):
469 469 nlist = []
470 470 self._trait_notifiers[name] = nlist
471 471 else:
472 472 nlist = self._trait_notifiers[name]
473 473 if handler not in nlist:
474 474 nlist.append(handler)
475 475
476 476 def _remove_notifiers(self, handler, name):
477 477 if self._trait_notifiers.has_key(name):
478 478 nlist = self._trait_notifiers[name]
479 479 try:
480 480 index = nlist.index(handler)
481 481 except ValueError:
482 482 pass
483 483 else:
484 484 del nlist[index]
485 485
486 486 def on_trait_change(self, handler, name=None, remove=False):
487 487 """Setup a handler to be called when a trait changes.
488 488
489 489 This is used to setup dynamic notifications of trait changes.
490 490
491 491 Static handlers can be created by creating methods on a HasTraits
492 492 subclass with the naming convention '_[traitname]_changed'. Thus,
493 493 to create static handler for the trait 'a', create the method
494 494 _a_changed(self, name, old, new) (fewer arguments can be used, see
495 495 below).
496 496
497 497 Parameters
498 498 ----------
499 499 handler : callable
500 500 A callable that is called when a trait changes. Its
501 501 signature can be handler(), handler(name), handler(name, new)
502 502 or handler(name, old, new).
503 503 name : list, str, None
504 504 If None, the handler will apply to all traits. If a list
505 505 of str, handler will apply to all names in the list. If a
506 506 str, the handler will apply just to that name.
507 507 remove : bool
508 508 If False (the default), then install the handler. If True
509 509 then unintall it.
510 510 """
511 511 if remove:
512 512 names = parse_notifier_name(name)
513 513 for n in names:
514 514 self._remove_notifiers(handler, n)
515 515 else:
516 516 names = parse_notifier_name(name)
517 517 for n in names:
518 518 self._add_notifiers(handler, n)
519 519
520 520 @classmethod
521 521 def class_trait_names(cls, **metadata):
522 522 """Get a list of all the names of this classes traits.
523 523
524 524 This method is just like the :meth:`trait_names` method, but is unbound.
525 525 """
526 526 return cls.class_traits(**metadata).keys()
527 527
528 528 @classmethod
529 529 def class_traits(cls, **metadata):
530 530 """Get a list of all the traits of this class.
531 531
532 532 This method is just like the :meth:`traits` method, but is unbound.
533 533
534 534 The TraitTypes returned don't know anything about the values
535 535 that the various HasTrait's instances are holding.
536 536
537 537 This follows the same algorithm as traits does and does not allow
538 538 for any simple way of specifying merely that a metadata name
539 539 exists, but has any value. This is because get_metadata returns
540 540 None if a metadata key doesn't exist.
541 541 """
542 542 traits = dict([memb for memb in getmembers(cls) if \
543 543 isinstance(memb[1], TraitType)])
544 544
545 545 if len(metadata) == 0:
546 546 return traits
547 547
548 548 for meta_name, meta_eval in metadata.items():
549 549 if type(meta_eval) is not FunctionType:
550 550 metadata[meta_name] = _SimpleTest(meta_eval)
551 551
552 552 result = {}
553 553 for name, trait in traits.items():
554 554 for meta_name, meta_eval in metadata.items():
555 555 if not meta_eval(trait.get_metadata(meta_name)):
556 556 break
557 557 else:
558 558 result[name] = trait
559 559
560 560 return result
561 561
562 562 def trait_names(self, **metadata):
563 563 """Get a list of all the names of this classes traits."""
564 564 return self.traits(**metadata).keys()
565 565
566 566 def traits(self, **metadata):
567 567 """Get a list of all the traits of this class.
568 568
569 569 The TraitTypes returned don't know anything about the values
570 570 that the various HasTrait's instances are holding.
571 571
572 572 This follows the same algorithm as traits does and does not allow
573 573 for any simple way of specifying merely that a metadata name
574 574 exists, but has any value. This is because get_metadata returns
575 575 None if a metadata key doesn't exist.
576 576 """
577 577 traits = dict([memb for memb in getmembers(self.__class__) if \
578 578 isinstance(memb[1], TraitType)])
579 579
580 580 if len(metadata) == 0:
581 581 return traits
582 582
583 583 for meta_name, meta_eval in metadata.items():
584 584 if type(meta_eval) is not FunctionType:
585 585 metadata[meta_name] = _SimpleTest(meta_eval)
586 586
587 587 result = {}
588 588 for name, trait in traits.items():
589 589 for meta_name, meta_eval in metadata.items():
590 590 if not meta_eval(trait.get_metadata(meta_name)):
591 591 break
592 592 else:
593 593 result[name] = trait
594 594
595 595 return result
596 596
597 597 def trait_metadata(self, traitname, key):
598 598 """Get metadata values for trait by key."""
599 599 try:
600 600 trait = getattr(self.__class__, traitname)
601 601 except AttributeError:
602 602 raise TraitError("Class %s does not have a trait named %s" %
603 603 (self.__class__.__name__, traitname))
604 604 else:
605 605 return trait.get_metadata(key)
606 606
607 607 #-----------------------------------------------------------------------------
608 608 # Actual TraitTypes implementations/subclasses
609 609 #-----------------------------------------------------------------------------
610 610
611 611 #-----------------------------------------------------------------------------
612 612 # TraitTypes subclasses for handling classes and instances of classes
613 613 #-----------------------------------------------------------------------------
614 614
615 615
616 616 class ClassBasedTraitType(TraitType):
617 617 """A trait with error reporting for Type, Instance and This."""
618 618
619 619 def error(self, obj, value):
620 620 kind = type(value)
621 621 if (not py3compat.PY3) and kind is InstanceType:
622 622 msg = 'class %s' % value.__class__.__name__
623 623 else:
624 624 msg = '%s (i.e. %s)' % ( str( kind )[1:-1], repr( value ) )
625 625
626 626 if obj is not None:
627 627 e = "The '%s' trait of %s instance must be %s, but a value of %s was specified." \
628 628 % (self.name, class_of(obj),
629 629 self.info(), msg)
630 630 else:
631 631 e = "The '%s' trait must be %s, but a value of %r was specified." \
632 632 % (self.name, self.info(), msg)
633 633
634 634 raise TraitError(e)
635 635
636 636
637 637 class Type(ClassBasedTraitType):
638 638 """A trait whose value must be a subclass of a specified class."""
639 639
640 640 def __init__ (self, default_value=None, klass=None, allow_none=True, **metadata ):
641 641 """Construct a Type trait
642 642
643 643 A Type trait specifies that its values must be subclasses of
644 644 a particular class.
645 645
646 646 If only ``default_value`` is given, it is used for the ``klass`` as
647 647 well.
648 648
649 649 Parameters
650 650 ----------
651 651 default_value : class, str or None
652 652 The default value must be a subclass of klass. If an str,
653 653 the str must be a fully specified class name, like 'foo.bar.Bah'.
654 654 The string is resolved into real class, when the parent
655 655 :class:`HasTraits` class is instantiated.
656 656 klass : class, str, None
657 657 Values of this trait must be a subclass of klass. The klass
658 658 may be specified in a string like: 'foo.bar.MyClass'.
659 659 The string is resolved into real class, when the parent
660 660 :class:`HasTraits` class is instantiated.
661 661 allow_none : boolean
662 662 Indicates whether None is allowed as an assignable value. Even if
663 663 ``False``, the default value may be ``None``.
664 664 """
665 665 if default_value is None:
666 666 if klass is None:
667 667 klass = object
668 668 elif klass is None:
669 669 klass = default_value
670 670
671 671 if not (inspect.isclass(klass) or isinstance(klass, basestring)):
672 672 raise TraitError("A Type trait must specify a class.")
673 673
674 674 self.klass = klass
675 675 self._allow_none = allow_none
676 676
677 677 super(Type, self).__init__(default_value, **metadata)
678 678
679 679 def validate(self, obj, value):
680 680 """Validates that the value is a valid object instance."""
681 681 try:
682 682 if issubclass(value, self.klass):
683 683 return value
684 684 except:
685 685 if (value is None) and (self._allow_none):
686 686 return value
687 687
688 688 self.error(obj, value)
689 689
690 690 def info(self):
691 691 """ Returns a description of the trait."""
692 692 if isinstance(self.klass, basestring):
693 693 klass = self.klass
694 694 else:
695 695 klass = self.klass.__name__
696 696 result = 'a subclass of ' + klass
697 697 if self._allow_none:
698 698 return result + ' or None'
699 699 return result
700 700
701 701 def instance_init(self, obj):
702 702 self._resolve_classes()
703 703 super(Type, self).instance_init(obj)
704 704
705 705 def _resolve_classes(self):
706 706 if isinstance(self.klass, basestring):
707 707 self.klass = import_item(self.klass)
708 708 if isinstance(self.default_value, basestring):
709 709 self.default_value = import_item(self.default_value)
710 710
711 711 def get_default_value(self):
712 712 return self.default_value
713 713
714 714
715 715 class DefaultValueGenerator(object):
716 716 """A class for generating new default value instances."""
717 717
718 718 def __init__(self, *args, **kw):
719 719 self.args = args
720 720 self.kw = kw
721 721
722 722 def generate(self, klass):
723 723 return klass(*self.args, **self.kw)
724 724
725 725
726 726 class Instance(ClassBasedTraitType):
727 727 """A trait whose value must be an instance of a specified class.
728 728
729 729 The value can also be an instance of a subclass of the specified class.
730 730 """
731 731
732 732 def __init__(self, klass=None, args=None, kw=None,
733 733 allow_none=True, **metadata ):
734 734 """Construct an Instance trait.
735 735
736 736 This trait allows values that are instances of a particular
737 737 class or its sublclasses. Our implementation is quite different
738 738 from that of enthough.traits as we don't allow instances to be used
739 739 for klass and we handle the ``args`` and ``kw`` arguments differently.
740 740
741 741 Parameters
742 742 ----------
743 743 klass : class, str
744 744 The class that forms the basis for the trait. Class names
745 745 can also be specified as strings, like 'foo.bar.Bar'.
746 746 args : tuple
747 747 Positional arguments for generating the default value.
748 748 kw : dict
749 749 Keyword arguments for generating the default value.
750 750 allow_none : bool
751 751 Indicates whether None is allowed as a value.
752 752
753 753 Default Value
754 754 -------------
755 755 If both ``args`` and ``kw`` are None, then the default value is None.
756 756 If ``args`` is a tuple and ``kw`` is a dict, then the default is
757 757 created as ``klass(*args, **kw)``. If either ``args`` or ``kw`` is
758 758 not (but not both), None is replace by ``()`` or ``{}``.
759 759 """
760 760
761 761 self._allow_none = allow_none
762 762
763 763 if (klass is None) or (not (inspect.isclass(klass) or isinstance(klass, basestring))):
764 764 raise TraitError('The klass argument must be a class'
765 765 ' you gave: %r' % klass)
766 766 self.klass = klass
767 767
768 768 # self.klass is a class, so handle default_value
769 769 if args is None and kw is None:
770 770 default_value = None
771 771 else:
772 772 if args is None:
773 773 # kw is not None
774 774 args = ()
775 775 elif kw is None:
776 776 # args is not None
777 777 kw = {}
778 778
779 779 if not isinstance(kw, dict):
780 780 raise TraitError("The 'kw' argument must be a dict or None.")
781 781 if not isinstance(args, tuple):
782 782 raise TraitError("The 'args' argument must be a tuple or None.")
783 783
784 784 default_value = DefaultValueGenerator(*args, **kw)
785 785
786 786 super(Instance, self).__init__(default_value, **metadata)
787 787
788 788 def validate(self, obj, value):
789 789 if value is None:
790 790 if self._allow_none:
791 791 return value
792 792 self.error(obj, value)
793 793
794 794 if isinstance(value, self.klass):
795 795 return value
796 796 else:
797 797 self.error(obj, value)
798 798
799 799 def info(self):
800 800 if isinstance(self.klass, basestring):
801 801 klass = self.klass
802 802 else:
803 803 klass = self.klass.__name__
804 804 result = class_of(klass)
805 805 if self._allow_none:
806 806 return result + ' or None'
807 807
808 808 return result
809 809
810 810 def instance_init(self, obj):
811 811 self._resolve_classes()
812 812 super(Instance, self).instance_init(obj)
813 813
814 814 def _resolve_classes(self):
815 815 if isinstance(self.klass, basestring):
816 816 self.klass = import_item(self.klass)
817 817
818 818 def get_default_value(self):
819 819 """Instantiate a default value instance.
820 820
821 821 This is called when the containing HasTraits classes'
822 822 :meth:`__new__` method is called to ensure that a unique instance
823 823 is created for each HasTraits instance.
824 824 """
825 825 dv = self.default_value
826 826 if isinstance(dv, DefaultValueGenerator):
827 827 return dv.generate(self.klass)
828 828 else:
829 829 return dv
830 830
831 831
832 832 class This(ClassBasedTraitType):
833 833 """A trait for instances of the class containing this trait.
834 834
835 835 Because how how and when class bodies are executed, the ``This``
836 836 trait can only have a default value of None. This, and because we
837 837 always validate default values, ``allow_none`` is *always* true.
838 838 """
839 839
840 840 info_text = 'an instance of the same type as the receiver or None'
841 841
842 842 def __init__(self, **metadata):
843 843 super(This, self).__init__(None, **metadata)
844 844
845 845 def validate(self, obj, value):
846 846 # What if value is a superclass of obj.__class__? This is
847 847 # complicated if it was the superclass that defined the This
848 848 # trait.
849 849 if isinstance(value, self.this_class) or (value is None):
850 850 return value
851 851 else:
852 852 self.error(obj, value)
853 853
854 854
855 855 #-----------------------------------------------------------------------------
856 856 # Basic TraitTypes implementations/subclasses
857 857 #-----------------------------------------------------------------------------
858 858
859 859
860 860 class Any(TraitType):
861 861 default_value = None
862 862 info_text = 'any value'
863 863
864 864
865 865 class Int(TraitType):
866 866 """An int trait."""
867 867
868 868 default_value = 0
869 869 info_text = 'an int'
870 870
871 871 def validate(self, obj, value):
872 872 if isinstance(value, int):
873 873 return value
874 874 self.error(obj, value)
875 875
876 876 class CInt(Int):
877 877 """A casting version of the int trait."""
878 878
879 879 def validate(self, obj, value):
880 880 try:
881 881 return int(value)
882 882 except:
883 883 self.error(obj, value)
884 884
885 885 if py3compat.PY3:
886 886 Long, CLong = Int, CInt
887 887 Integer = Int
888 888 else:
889 889 class Long(TraitType):
890 890 """A long integer trait."""
891 891
892 892 default_value = 0L
893 893 info_text = 'a long'
894 894
895 895 def validate(self, obj, value):
896 896 if isinstance(value, long):
897 897 return value
898 898 if isinstance(value, int):
899 899 return long(value)
900 900 self.error(obj, value)
901 901
902 902
903 903 class CLong(Long):
904 904 """A casting version of the long integer trait."""
905 905
906 906 def validate(self, obj, value):
907 907 try:
908 908 return long(value)
909 909 except:
910 910 self.error(obj, value)
911 911
912 912 class Integer(TraitType):
913 913 """An integer trait.
914 914
915 915 Longs that are unnecessary (<= sys.maxint) are cast to ints."""
916 916
917 917 default_value = 0
918 918 info_text = 'an integer'
919 919
920 920 def validate(self, obj, value):
921 921 if isinstance(value, int):
922 922 return value
923 923 elif isinstance(value, long):
924 924 # downcast longs that fit in int:
925 925 # note that int(n > sys.maxint) returns a long, so
926 926 # we don't need a condition on this cast
927 927 return int(value)
928 928 self.error(obj, value)
929 929
930 930
931 931 class Float(TraitType):
932 932 """A float trait."""
933 933
934 934 default_value = 0.0
935 935 info_text = 'a float'
936 936
937 937 def validate(self, obj, value):
938 938 if isinstance(value, float):
939 939 return value
940 940 if isinstance(value, int):
941 941 return float(value)
942 942 self.error(obj, value)
943 943
944 944
945 945 class CFloat(Float):
946 946 """A casting version of the float trait."""
947 947
948 948 def validate(self, obj, value):
949 949 try:
950 950 return float(value)
951 951 except:
952 952 self.error(obj, value)
953 953
954 954 class Complex(TraitType):
955 955 """A trait for complex numbers."""
956 956
957 957 default_value = 0.0 + 0.0j
958 958 info_text = 'a complex number'
959 959
960 960 def validate(self, obj, value):
961 961 if isinstance(value, complex):
962 962 return value
963 963 if isinstance(value, (float, int)):
964 964 return complex(value)
965 965 self.error(obj, value)
966 966
967 967
968 968 class CComplex(Complex):
969 969 """A casting version of the complex number trait."""
970 970
971 971 def validate (self, obj, value):
972 972 try:
973 973 return complex(value)
974 974 except:
975 975 self.error(obj, value)
976 976
977 977 # We should always be explicit about whether we're using bytes or unicode, both
978 978 # for Python 3 conversion and for reliable unicode behaviour on Python 2. So
979 979 # we don't have a Str type.
980 980 class Bytes(TraitType):
981 981 """A trait for byte strings."""
982 982
983 983 default_value = b''
984 984 info_text = 'a string'
985 985
986 986 def validate(self, obj, value):
987 987 if isinstance(value, bytes):
988 988 return value
989 989 self.error(obj, value)
990 990
991 991
992 992 class CBytes(Bytes):
993 993 """A casting version of the byte string trait."""
994 994
995 995 def validate(self, obj, value):
996 996 try:
997 997 return bytes(value)
998 998 except:
999 999 self.error(obj, value)
1000 1000
1001 1001
1002 1002 class Unicode(TraitType):
1003 1003 """A trait for unicode strings."""
1004 1004
1005 1005 default_value = u''
1006 1006 info_text = 'a unicode string'
1007 1007
1008 1008 def validate(self, obj, value):
1009 1009 if isinstance(value, unicode):
1010 1010 return value
1011 1011 if isinstance(value, bytes):
1012 1012 return unicode(value)
1013 1013 self.error(obj, value)
1014 1014
1015 1015
1016 1016 class CUnicode(Unicode):
1017 1017 """A casting version of the unicode trait."""
1018 1018
1019 1019 def validate(self, obj, value):
1020 1020 try:
1021 1021 return unicode(value)
1022 1022 except:
1023 1023 self.error(obj, value)
1024 1024
1025 1025
1026 1026 class ObjectName(TraitType):
1027 1027 """A string holding a valid object name in this version of Python.
1028 1028
1029 1029 This does not check that the name exists in any scope."""
1030 1030 info_text = "a valid object identifier in Python"
1031 1031
1032 1032 if py3compat.PY3:
1033 1033 # Python 3:
1034 1034 coerce_str = staticmethod(lambda _,s: s)
1035 1035
1036 1036 else:
1037 1037 # Python 2:
1038 1038 def coerce_str(self, obj, value):
1039 1039 "In Python 2, coerce ascii-only unicode to str"
1040 1040 if isinstance(value, unicode):
1041 1041 try:
1042 1042 return str(value)
1043 1043 except UnicodeEncodeError:
1044 1044 self.error(obj, value)
1045 1045 return value
1046 1046
1047 1047 def validate(self, obj, value):
1048 1048 value = self.coerce_str(obj, value)
1049 1049
1050 1050 if isinstance(value, str) and py3compat.isidentifier(value):
1051 1051 return value
1052 1052 self.error(obj, value)
1053 1053
1054 1054 class DottedObjectName(ObjectName):
1055 1055 """A string holding a valid dotted object name in Python, such as A.b3._c"""
1056 1056 def validate(self, obj, value):
1057 1057 value = self.coerce_str(obj, value)
1058 1058
1059 1059 if isinstance(value, str) and py3compat.isidentifier(value, dotted=True):
1060 1060 return value
1061 1061 self.error(obj, value)
1062 1062
1063 1063
1064 1064 class Bool(TraitType):
1065 1065 """A boolean (True, False) trait."""
1066 1066
1067 1067 default_value = False
1068 1068 info_text = 'a boolean'
1069 1069
1070 1070 def validate(self, obj, value):
1071 1071 if isinstance(value, bool):
1072 1072 return value
1073 1073 self.error(obj, value)
1074 1074
1075 1075
1076 1076 class CBool(Bool):
1077 1077 """A casting version of the boolean trait."""
1078 1078
1079 1079 def validate(self, obj, value):
1080 1080 try:
1081 1081 return bool(value)
1082 1082 except:
1083 1083 self.error(obj, value)
1084 1084
1085 1085
1086 1086 class Enum(TraitType):
1087 1087 """An enum that whose value must be in a given sequence."""
1088 1088
1089 1089 def __init__(self, values, default_value=None, allow_none=True, **metadata):
1090 1090 self.values = values
1091 1091 self._allow_none = allow_none
1092 1092 super(Enum, self).__init__(default_value, **metadata)
1093 1093
1094 1094 def validate(self, obj, value):
1095 1095 if value is None:
1096 1096 if self._allow_none:
1097 1097 return value
1098 1098
1099 1099 if value in self.values:
1100 1100 return value
1101 1101 self.error(obj, value)
1102 1102
1103 1103 def info(self):
1104 1104 """ Returns a description of the trait."""
1105 1105 result = 'any of ' + repr(self.values)
1106 1106 if self._allow_none:
1107 1107 return result + ' or None'
1108 1108 return result
1109 1109
1110 1110 class CaselessStrEnum(Enum):
1111 1111 """An enum of strings that are caseless in validate."""
1112 1112
1113 1113 def validate(self, obj, value):
1114 1114 if value is None:
1115 1115 if self._allow_none:
1116 1116 return value
1117 1117
1118 1118 if not isinstance(value, basestring):
1119 1119 self.error(obj, value)
1120 1120
1121 1121 for v in self.values:
1122 1122 if v.lower() == value.lower():
1123 1123 return v
1124 1124 self.error(obj, value)
1125 1125
1126 1126 class Container(Instance):
1127 1127 """An instance of a container (list, set, etc.)
1128 1128
1129 1129 To be subclassed by overriding klass.
1130 1130 """
1131 1131 klass = None
1132 1132 _valid_defaults = SequenceTypes
1133 1133 _trait = None
1134 1134
1135 1135 def __init__(self, trait=None, default_value=None, allow_none=True,
1136 1136 **metadata):
1137 1137 """Create a container trait type from a list, set, or tuple.
1138 1138
1139 1139 The default value is created by doing ``List(default_value)``,
1140 1140 which creates a copy of the ``default_value``.
1141 1141
1142 1142 ``trait`` can be specified, which restricts the type of elements
1143 1143 in the container to that TraitType.
1144 1144
1145 1145 If only one arg is given and it is not a Trait, it is taken as
1146 1146 ``default_value``:
1147 1147
1148 1148 ``c = List([1,2,3])``
1149 1149
1150 1150 Parameters
1151 1151 ----------
1152 1152
1153 1153 trait : TraitType [ optional ]
1154 1154 the type for restricting the contents of the Container. If unspecified,
1155 1155 types are not checked.
1156 1156
1157 1157 default_value : SequenceType [ optional ]
1158 1158 The default value for the Trait. Must be list/tuple/set, and
1159 1159 will be cast to the container type.
1160 1160
1161 1161 allow_none : Bool [ default True ]
1162 1162 Whether to allow the value to be None
1163 1163
1164 1164 **metadata : any
1165 1165 further keys for extensions to the Trait (e.g. config)
1166 1166
1167 1167 """
1168 1168 istrait = lambda t: isinstance(t, type) and issubclass(t, TraitType)
1169 1169
1170 1170 # allow List([values]):
1171 1171 if default_value is None and not istrait(trait):
1172 1172 default_value = trait
1173 1173 trait = None
1174 1174
1175 1175 if default_value is None:
1176 1176 args = ()
1177 1177 elif isinstance(default_value, self._valid_defaults):
1178 1178 args = (default_value,)
1179 1179 else:
1180 1180 raise TypeError('default value of %s was %s' %(self.__class__.__name__, default_value))
1181 1181
1182 1182 if istrait(trait):
1183 1183 self._trait = trait()
1184 1184 self._trait.name = 'element'
1185 1185 elif trait is not None:
1186 1186 raise TypeError("`trait` must be a Trait or None, got %s"%repr_type(trait))
1187 1187
1188 1188 super(Container,self).__init__(klass=self.klass, args=args,
1189 1189 allow_none=allow_none, **metadata)
1190 1190
1191 1191 def element_error(self, obj, element, validator):
1192 1192 e = "Element of the '%s' trait of %s instance must be %s, but a value of %s was specified." \
1193 1193 % (self.name, class_of(obj), validator.info(), repr_type(element))
1194 1194 raise TraitError(e)
1195 1195
1196 1196 def validate(self, obj, value):
1197 1197 value = super(Container, self).validate(obj, value)
1198 1198 if value is None:
1199 1199 return value
1200 1200
1201 1201 value = self.validate_elements(obj, value)
1202 1202
1203 1203 return value
1204 1204
1205 1205 def validate_elements(self, obj, value):
1206 1206 validated = []
1207 1207 if self._trait is None or isinstance(self._trait, Any):
1208 1208 return value
1209 1209 for v in value:
1210 1210 try:
1211 1211 v = self._trait.validate(obj, v)
1212 1212 except TraitError:
1213 1213 self.element_error(obj, v, self._trait)
1214 1214 else:
1215 1215 validated.append(v)
1216 1216 return self.klass(validated)
1217 1217
1218 1218
1219 1219 class List(Container):
1220 1220 """An instance of a Python list."""
1221 1221 klass = list
1222 1222
1223 1223 def __init__(self, trait=None, default_value=None, minlen=0, maxlen=sys.maxint,
1224 1224 allow_none=True, **metadata):
1225 1225 """Create a List trait type from a list, set, or tuple.
1226 1226
1227 1227 The default value is created by doing ``List(default_value)``,
1228 1228 which creates a copy of the ``default_value``.
1229 1229
1230 1230 ``trait`` can be specified, which restricts the type of elements
1231 1231 in the container to that TraitType.
1232 1232
1233 1233 If only one arg is given and it is not a Trait, it is taken as
1234 1234 ``default_value``:
1235 1235
1236 1236 ``c = List([1,2,3])``
1237 1237
1238 1238 Parameters
1239 1239 ----------
1240 1240
1241 1241 trait : TraitType [ optional ]
1242 1242 the type for restricting the contents of the Container. If unspecified,
1243 1243 types are not checked.
1244 1244
1245 1245 default_value : SequenceType [ optional ]
1246 1246 The default value for the Trait. Must be list/tuple/set, and
1247 1247 will be cast to the container type.
1248 1248
1249 1249 minlen : Int [ default 0 ]
1250 1250 The minimum length of the input list
1251 1251
1252 1252 maxlen : Int [ default sys.maxint ]
1253 1253 The maximum length of the input list
1254 1254
1255 1255 allow_none : Bool [ default True ]
1256 1256 Whether to allow the value to be None
1257 1257
1258 1258 **metadata : any
1259 1259 further keys for extensions to the Trait (e.g. config)
1260 1260
1261 1261 """
1262 1262 self._minlen = minlen
1263 1263 self._maxlen = maxlen
1264 1264 super(List, self).__init__(trait=trait, default_value=default_value,
1265 1265 allow_none=allow_none, **metadata)
1266 1266
1267 1267 def length_error(self, obj, value):
1268 1268 e = "The '%s' trait of %s instance must be of length %i <= L <= %i, but a value of %s was specified." \
1269 1269 % (self.name, class_of(obj), self._minlen, self._maxlen, value)
1270 1270 raise TraitError(e)
1271 1271
1272 1272 def validate_elements(self, obj, value):
1273 1273 length = len(value)
1274 1274 if length < self._minlen or length > self._maxlen:
1275 1275 self.length_error(obj, value)
1276 1276
1277 1277 return super(List, self).validate_elements(obj, value)
1278 1278
1279 1279
1280 1280 class Set(Container):
1281 1281 """An instance of a Python set."""
1282 1282 klass = set
1283 1283
1284 1284 class Tuple(Container):
1285 1285 """An instance of a Python tuple."""
1286 1286 klass = tuple
1287 1287
1288 1288 def __init__(self, *traits, **metadata):
1289 1289 """Tuple(*traits, default_value=None, allow_none=True, **medatata)
1290 1290
1291 1291 Create a tuple from a list, set, or tuple.
1292 1292
1293 1293 Create a fixed-type tuple with Traits:
1294 1294
1295 1295 ``t = Tuple(Int, Str, CStr)``
1296 1296
1297 1297 would be length 3, with Int,Str,CStr for each element.
1298 1298
1299 1299 If only one arg is given and it is not a Trait, it is taken as
1300 1300 default_value:
1301 1301
1302 1302 ``t = Tuple((1,2,3))``
1303 1303
1304 1304 Otherwise, ``default_value`` *must* be specified by keyword.
1305 1305
1306 1306 Parameters
1307 1307 ----------
1308 1308
1309 1309 *traits : TraitTypes [ optional ]
1310 1310 the tsype for restricting the contents of the Tuple. If unspecified,
1311 1311 types are not checked. If specified, then each positional argument
1312 1312 corresponds to an element of the tuple. Tuples defined with traits
1313 1313 are of fixed length.
1314 1314
1315 1315 default_value : SequenceType [ optional ]
1316 1316 The default value for the Tuple. Must be list/tuple/set, and
1317 1317 will be cast to a tuple. If `traits` are specified, the
1318 1318 `default_value` must conform to the shape and type they specify.
1319 1319
1320 1320 allow_none : Bool [ default True ]
1321 1321 Whether to allow the value to be None
1322 1322
1323 1323 **metadata : any
1324 1324 further keys for extensions to the Trait (e.g. config)
1325 1325
1326 1326 """
1327 1327 default_value = metadata.pop('default_value', None)
1328 1328 allow_none = metadata.pop('allow_none', True)
1329 1329
1330 1330 istrait = lambda t: isinstance(t, type) and issubclass(t, TraitType)
1331 1331
1332 1332 # allow Tuple((values,)):
1333 1333 if len(traits) == 1 and default_value is None and not istrait(traits[0]):
1334 1334 default_value = traits[0]
1335 1335 traits = ()
1336 1336
1337 1337 if default_value is None:
1338 1338 args = ()
1339 1339 elif isinstance(default_value, self._valid_defaults):
1340 1340 args = (default_value,)
1341 1341 else:
1342 1342 raise TypeError('default value of %s was %s' %(self.__class__.__name__, default_value))
1343 1343
1344 1344 self._traits = []
1345 1345 for trait in traits:
1346 1346 t = trait()
1347 1347 t.name = 'element'
1348 1348 self._traits.append(t)
1349 1349
1350 1350 if self._traits and default_value is None:
1351 1351 # don't allow default to be an empty container if length is specified
1352 1352 args = None
1353 1353 super(Container,self).__init__(klass=self.klass, args=args,
1354 1354 allow_none=allow_none, **metadata)
1355 1355
1356 1356 def validate_elements(self, obj, value):
1357 1357 if not self._traits:
1358 1358 # nothing to validate
1359 1359 return value
1360 1360 if len(value) != len(self._traits):
1361 1361 e = "The '%s' trait of %s instance requires %i elements, but a value of %s was specified." \
1362 1362 % (self.name, class_of(obj), len(self._traits), repr_type(value))
1363 1363 raise TraitError(e)
1364 1364
1365 1365 validated = []
1366 1366 for t,v in zip(self._traits, value):
1367 1367 try:
1368 1368 v = t.validate(obj, v)
1369 1369 except TraitError:
1370 1370 self.element_error(obj, v, t)
1371 1371 else:
1372 1372 validated.append(v)
1373 1373 return tuple(validated)
1374 1374
1375 1375
1376 1376 class Dict(Instance):
1377 1377 """An instance of a Python dict."""
1378 1378
1379 1379 def __init__(self, default_value=None, allow_none=True, **metadata):
1380 1380 """Create a dict trait type from a dict.
1381 1381
1382 1382 The default value is created by doing ``dict(default_value)``,
1383 1383 which creates a copy of the ``default_value``.
1384 1384 """
1385 1385 if default_value is None:
1386 1386 args = ((),)
1387 1387 elif isinstance(default_value, dict):
1388 1388 args = (default_value,)
1389 1389 elif isinstance(default_value, SequenceTypes):
1390 1390 args = (default_value,)
1391 1391 else:
1392 1392 raise TypeError('default value of Dict was %s' % default_value)
1393 1393
1394 1394 super(Dict,self).__init__(klass=dict, args=args,
1395 1395 allow_none=allow_none, **metadata)
1396 1396
1397 1397 class TCPAddress(TraitType):
1398 1398 """A trait for an (ip, port) tuple.
1399 1399
1400 1400 This allows for both IPv4 IP addresses as well as hostnames.
1401 1401 """
1402 1402
1403 1403 default_value = ('127.0.0.1', 0)
1404 1404 info_text = 'an (ip, port) tuple'
1405 1405
1406 1406 def validate(self, obj, value):
1407 1407 if isinstance(value, tuple):
1408 1408 if len(value) == 2:
1409 1409 if isinstance(value[0], basestring) and isinstance(value[1], int):
1410 1410 port = value[1]
1411 1411 if port >= 0 and port <= 65535:
1412 1412 return value
1413 1413 self.error(obj, value)
@@ -1,66 +1,66 b''
1 1 # encoding: utf-8
2 2 """
3 3 Utilities for warnings. Shoudn't we just use the built in warnings module.
4 4 """
5 5
6 6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2009 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 8 #
9 9 # Distributed under the terms of the BSD License. The full license is in
10 10 # the file COPYING, distributed as part of this software.
11 11 #-----------------------------------------------------------------------------
12 12
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16
17 17 import sys
18 18
19 19 from IPython.utils import io
20 20
21 21 #-----------------------------------------------------------------------------
22 22 # Code
23 23 #-----------------------------------------------------------------------------
24 24
25 25 def warn(msg,level=2,exit_val=1):
26 26 """Standard warning printer. Gives formatting consistency.
27 27
28 28 Output is sent to io.stderr (sys.stderr by default).
29 29
30 30 Options:
31 31
32 32 -level(2): allows finer control:
33 33 0 -> Do nothing, dummy function.
34 34 1 -> Print message.
35 35 2 -> Print 'WARNING:' + message. (Default level).
36 36 3 -> Print 'ERROR:' + message.
37 37 4 -> Print 'FATAL ERROR:' + message and trigger a sys.exit(exit_val).
38 38
39 39 -exit_val (1): exit value returned by sys.exit() for a level 4
40 40 warning. Ignored for all other levels."""
41 41
42 42 if level>0:
43 43 header = ['','','WARNING: ','ERROR: ','FATAL ERROR: ']
44 44 io.stderr.write('%s%s' % (header[level],msg))
45 45 if level == 4:
46 46 print >> io.stderr,'Exiting.\n'
47 47 sys.exit(exit_val)
48 48
49 49
50 50 def info(msg):
51 51 """Equivalent to warn(msg,level=1)."""
52 52
53 53 warn(msg,level=1)
54 54
55 55
56 56 def error(msg):
57 57 """Equivalent to warn(msg,level=3)."""
58 58
59 59 warn(msg,level=3)
60 60
61 61
62 62 def fatal(msg,exit_val=1):
63 63 """Equivalent to warn(msg,exit_val=exit_val,level=4)."""
64 64
65 65 warn(msg,exit_val=exit_val,level=4)
66 66
@@ -1,42 +1,42 b''
1 1 #-----------------------------------------------------------------------------
2 # Copyright (C) 2010 The IPython Development Team
2 # Copyright (C) 2010-2011 The IPython Development Team
3 3 #
4 4 # Distributed under the terms of the BSD License. The full license is in
5 5 # the file COPYING.txt, distributed as part of this software.
6 6 #-----------------------------------------------------------------------------
7 7
8 8 #-----------------------------------------------------------------------------
9 9 # Verify zmq version dependency >= 2.1.4
10 10 #-----------------------------------------------------------------------------
11 11
12 12 import re
13 13 import warnings
14 14
15 15 def check_for_zmq(minimum_version, module='IPython.zmq'):
16 16 min_vlist = [int(n) for n in minimum_version.split('.')]
17 17
18 18 try:
19 19 import zmq
20 20 except ImportError:
21 21 raise ImportError("%s requires pyzmq >= %s"%(module, minimum_version))
22 22
23 23 pyzmq_version = zmq.__version__
24 24 vlist = [int(n) for n in re.findall(r'\d+', pyzmq_version)]
25 25
26 26 if 'dev' not in pyzmq_version and vlist < min_vlist:
27 27 raise ImportError("%s requires pyzmq >= %s, but you have %s"%(
28 28 module, minimum_version, pyzmq_version))
29 29
30 30 # fix missing DEALER/ROUTER aliases in pyzmq < 2.1.9
31 31 if not hasattr(zmq, 'DEALER'):
32 32 zmq.DEALER = zmq.XREQ
33 33 if not hasattr(zmq, 'ROUTER'):
34 34 zmq.ROUTER = zmq.XREP
35 35
36 36 if zmq.zmq_version() >= '4.0.0':
37 37 warnings.warn("""libzmq 4 detected.
38 38 It is unlikely that IPython's zmq code will work properly.
39 39 Please install libzmq stable, which is 2.1.x or 2.2.x""",
40 40 RuntimeWarning)
41 41
42 42 check_for_zmq('2.1.4')
@@ -1,129 +1,129 b''
1 1 """Implement a fully blocking kernel manager.
2 2
3 3 Useful for test suites and blocking terminal interfaces.
4 4 """
5 5 #-----------------------------------------------------------------------------
6 # Copyright (C) 2010 The IPython Development Team
6 # Copyright (C) 2010-2011 The IPython Development Team
7 7 #
8 8 # Distributed under the terms of the BSD License. The full license is in
9 9 # the file COPYING.txt, distributed as part of this software.
10 10 #-----------------------------------------------------------------------------
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Imports
14 14 #-----------------------------------------------------------------------------
15 15 from __future__ import print_function
16 16
17 17 # Stdlib
18 18 from Queue import Queue, Empty
19 19
20 20 # Our own
21 21 from IPython.utils import io
22 22 from IPython.utils.traitlets import Type
23 23
24 24 from .kernelmanager import (KernelManager, SubSocketChannel, HBSocketChannel,
25 25 ShellSocketChannel, StdInSocketChannel)
26 26
27 27 #-----------------------------------------------------------------------------
28 28 # Functions and classes
29 29 #-----------------------------------------------------------------------------
30 30
31 31 class BlockingSubSocketChannel(SubSocketChannel):
32 32
33 33 def __init__(self, context, session, address=None):
34 34 super(BlockingSubSocketChannel, self).__init__(context, session,
35 35 address)
36 36 self._in_queue = Queue()
37 37
38 38 def call_handlers(self, msg):
39 39 #io.rprint('[[Sub]]', msg) # dbg
40 40 self._in_queue.put(msg)
41 41
42 42 def msg_ready(self):
43 43 """Is there a message that has been received?"""
44 44 if self._in_queue.qsize() == 0:
45 45 return False
46 46 else:
47 47 return True
48 48
49 49 def get_msg(self, block=True, timeout=None):
50 50 """Get a message if there is one that is ready."""
51 51 if block and timeout is None:
52 52 # never use timeout=None, because get
53 53 # becomes uninterruptible
54 54 timeout = 1e6
55 55 return self._in_queue.get(block, timeout)
56 56
57 57 def get_msgs(self):
58 58 """Get all messages that are currently ready."""
59 59 msgs = []
60 60 while True:
61 61 try:
62 62 msgs.append(self.get_msg(block=False))
63 63 except Empty:
64 64 break
65 65 return msgs
66 66
67 67
68 68 class BlockingShellSocketChannel(ShellSocketChannel):
69 69
70 70 def __init__(self, context, session, address=None):
71 71 super(BlockingShellSocketChannel, self).__init__(context, session,
72 72 address)
73 73 self._in_queue = Queue()
74 74
75 75 def call_handlers(self, msg):
76 76 #io.rprint('[[Shell]]', msg) # dbg
77 77 self._in_queue.put(msg)
78 78
79 79 def msg_ready(self):
80 80 """Is there a message that has been received?"""
81 81 if self._in_queue.qsize() == 0:
82 82 return False
83 83 else:
84 84 return True
85 85
86 86 def get_msg(self, block=True, timeout=None):
87 87 """Get a message if there is one that is ready."""
88 88 if block and timeout is None:
89 89 # never use timeout=None, because get
90 90 # becomes uninterruptible
91 91 timeout = 1e6
92 92 return self._in_queue.get(block, timeout)
93 93
94 94 def get_msgs(self):
95 95 """Get all messages that are currently ready."""
96 96 msgs = []
97 97 while True:
98 98 try:
99 99 msgs.append(self.get_msg(block=False))
100 100 except Empty:
101 101 break
102 102 return msgs
103 103
104 104
105 105 class BlockingStdInSocketChannel(StdInSocketChannel):
106 106
107 107 def call_handlers(self, msg):
108 108 #io.rprint('[[Rep]]', msg) # dbg
109 109 pass
110 110
111 111
112 112 class BlockingHBSocketChannel(HBSocketChannel):
113 113
114 114 # This kernel needs rapid monitoring capabilities
115 115 time_to_dead = 0.2
116 116
117 117 def call_handlers(self, since_last_heartbeat):
118 118 #io.rprint('[[Heart]]', since_last_heartbeat) # dbg
119 119 pass
120 120
121 121
122 122 class BlockingKernelManager(KernelManager):
123 123
124 124 # The classes to use for the various channels.
125 125 shell_channel_class = Type(BlockingShellSocketChannel)
126 126 sub_channel_class = Type(BlockingSubSocketChannel)
127 127 stdin_channel_class = Type(BlockingStdInSocketChannel)
128 128 hb_channel_class = Type(BlockingHBSocketChannel)
129 129
@@ -1,15 +1,15 b''
1 1 """GUI support for the IPython ZeroMQ kernel.
2 2
3 3 This package contains the various toolkit-dependent utilities we use to enable
4 4 coordination between the IPython kernel and the event loops of the various GUI
5 5 toolkits.
6 6 """
7 7
8 8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2010 The IPython Development Team.
9 # Copyright (C) 2010-2011 The IPython Development Team.
10 10 #
11 11 # Distributed under the terms of the BSD License.
12 12 #
13 13 # The full license is in the file COPYING.txt, distributed as part of this
14 14 # software.
15 15 #-----------------------------------------------------------------------------
@@ -1,86 +1,86 b''
1 1 """GUI support for the IPython ZeroMQ kernel - GTK toolkit support.
2 2 """
3 3 #-----------------------------------------------------------------------------
4 # Copyright (C) 2010 The IPython Development Team
4 # Copyright (C) 2010-2011 The IPython Development Team
5 5 #
6 6 # Distributed under the terms of the BSD License. The full license is in
7 7 # the file COPYING.txt, distributed as part of this software.
8 8 #-----------------------------------------------------------------------------
9 9
10 10 #-----------------------------------------------------------------------------
11 11 # Imports
12 12 #-----------------------------------------------------------------------------
13 13 # stdlib
14 14 import sys
15 15
16 16 # Third-party
17 17 import gobject
18 18 import gtk
19 19
20 20 #-----------------------------------------------------------------------------
21 21 # Classes and functions
22 22 #-----------------------------------------------------------------------------
23 23
24 24 class GTKEmbed(object):
25 25 """A class to embed a kernel into the GTK main event loop.
26 26 """
27 27 def __init__(self, kernel):
28 28 self.kernel = kernel
29 29 # These two will later store the real gtk functions when we hijack them
30 30 self.gtk_main = None
31 31 self.gtk_main_quit = None
32 32
33 33 def start(self):
34 34 """Starts the GTK main event loop and sets our kernel startup routine.
35 35 """
36 36 # Register our function to initiate the kernel and start gtk
37 37 gobject.idle_add(self._wire_kernel)
38 38 gtk.main()
39 39
40 40 def _wire_kernel(self):
41 41 """Initializes the kernel inside GTK.
42 42
43 43 This is meant to run only once at startup, so it does its job and
44 44 returns False to ensure it doesn't get run again by GTK.
45 45 """
46 46 self.gtk_main, self.gtk_main_quit = self._hijack_gtk()
47 47 gobject.timeout_add(int(1000*self.kernel._poll_interval),
48 48 self.iterate_kernel)
49 49 return False
50 50
51 51 def iterate_kernel(self):
52 52 """Run one iteration of the kernel and return True.
53 53
54 54 GTK timer functions must return True to be called again, so we make the
55 55 call to :meth:`do_one_iteration` and then return True for GTK.
56 56 """
57 57 self.kernel.do_one_iteration()
58 58 return True
59 59
60 60 def stop(self):
61 61 # FIXME: this one isn't getting called because we have no reliable
62 62 # kernel shutdown. We need to fix that: once the kernel has a
63 63 # shutdown mechanism, it can call this.
64 64 self.gtk_main_quit()
65 65 sys.exit()
66 66
67 67 def _hijack_gtk(self):
68 68 """Hijack a few key functions in GTK for IPython integration.
69 69
70 70 Modifies pyGTK's main and main_quit with a dummy so user code does not
71 71 block IPython. This allows us to use %run to run arbitrary pygtk
72 72 scripts from a long-lived IPython session, and when they attempt to
73 73 start or stop
74 74
75 75 Returns
76 76 -------
77 77 The original functions that have been hijacked:
78 78 - gtk.main
79 79 - gtk.main_quit
80 80 """
81 81 def dummy(*args, **kw):
82 82 pass
83 83 # save and trap main and main_quit from gtk
84 84 orig_main, gtk.main = gtk.main, dummy
85 85 orig_main_quit, gtk.main_quit = gtk.main_quit, dummy
86 86 return orig_main, orig_main_quit
@@ -1,48 +1,48 b''
1 1 """The client and server for a basic ping-pong style heartbeat.
2 2 """
3 3
4 4 #-----------------------------------------------------------------------------
5 # Copyright (C) 2008-2010 The IPython Development Team
5 # Copyright (C) 2008-2011 The IPython Development Team
6 6 #
7 7 # Distributed under the terms of the BSD License. The full license is in
8 8 # the file COPYING, distributed as part of this software.
9 9 #-----------------------------------------------------------------------------
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Imports
13 13 #-----------------------------------------------------------------------------
14 14
15 15 import socket
16 16 import sys
17 17 from threading import Thread
18 18
19 19 import zmq
20 20
21 21 from IPython.utils.localinterfaces import LOCALHOST
22 22
23 23 #-----------------------------------------------------------------------------
24 24 # Code
25 25 #-----------------------------------------------------------------------------
26 26
27 27
28 28 class Heartbeat(Thread):
29 29 "A simple ping-pong style heartbeat that runs in a thread."
30 30
31 31 def __init__(self, context, addr=(LOCALHOST, 0)):
32 32 Thread.__init__(self)
33 33 self.context = context
34 34 self.ip, self.port = addr
35 35 if self.port == 0:
36 36 s = socket.socket()
37 37 # '*' means all interfaces to 0MQ, which is '' to socket.socket
38 38 s.bind(('' if self.ip == '*' else self.ip, 0))
39 39 self.port = s.getsockname()[1]
40 40 s.close()
41 41 self.addr = (self.ip, self.port)
42 42 self.daemon = True
43 43
44 44 def run(self):
45 45 self.socket = self.context.socket(zmq.REP)
46 46 self.socket.bind('tcp://%s:%i' % self.addr)
47 47 zmq.device(zmq.FORWARDER, self.socket, self.socket)
48 48
@@ -1,947 +1,947 b''
1 1 """Base classes to manage the interaction with a running kernel.
2 2
3 3 TODO
4 4 * Create logger to handle debugging and console messages.
5 5 """
6 6
7 7 #-----------------------------------------------------------------------------
8 # Copyright (C) 2008-2010 The IPython Development Team
8 # Copyright (C) 2008-2011 The IPython Development Team
9 9 #
10 10 # Distributed under the terms of the BSD License. The full license is in
11 11 # the file COPYING, distributed as part of this software.
12 12 #-----------------------------------------------------------------------------
13 13
14 14 #-----------------------------------------------------------------------------
15 15 # Imports
16 16 #-----------------------------------------------------------------------------
17 17
18 18 # Standard library imports.
19 19 import errno
20 20 import json
21 21 from subprocess import Popen
22 22 import os
23 23 import signal
24 24 import sys
25 25 from threading import Thread
26 26 import time
27 27
28 28 # System library imports.
29 29 import zmq
30 30 from zmq.eventloop import ioloop, zmqstream
31 31
32 32 # Local imports.
33 33 from IPython.config.loader import Config
34 34 from IPython.utils.localinterfaces import LOCALHOST, LOCAL_IPS
35 35 from IPython.utils.traitlets import (
36 36 HasTraits, Any, Instance, Type, Unicode, Integer, Bool
37 37 )
38 38 from IPython.utils.py3compat import str_to_bytes
39 39 from IPython.zmq.entry_point import write_connection_file
40 40 from session import Session
41 41
42 42 #-----------------------------------------------------------------------------
43 43 # Constants and exceptions
44 44 #-----------------------------------------------------------------------------
45 45
46 46 class InvalidPortNumber(Exception):
47 47 pass
48 48
49 49 #-----------------------------------------------------------------------------
50 50 # Utility functions
51 51 #-----------------------------------------------------------------------------
52 52
53 53 # some utilities to validate message structure, these might get moved elsewhere
54 54 # if they prove to have more generic utility
55 55
56 56 def validate_string_list(lst):
57 57 """Validate that the input is a list of strings.
58 58
59 59 Raises ValueError if not."""
60 60 if not isinstance(lst, list):
61 61 raise ValueError('input %r must be a list' % lst)
62 62 for x in lst:
63 63 if not isinstance(x, basestring):
64 64 raise ValueError('element %r in list must be a string' % x)
65 65
66 66
67 67 def validate_string_dict(dct):
68 68 """Validate that the input is a dict with string keys and values.
69 69
70 70 Raises ValueError if not."""
71 71 for k,v in dct.iteritems():
72 72 if not isinstance(k, basestring):
73 73 raise ValueError('key %r in dict must be a string' % k)
74 74 if not isinstance(v, basestring):
75 75 raise ValueError('value %r in dict must be a string' % v)
76 76
77 77
78 78 #-----------------------------------------------------------------------------
79 79 # ZMQ Socket Channel classes
80 80 #-----------------------------------------------------------------------------
81 81
82 82 class ZMQSocketChannel(Thread):
83 83 """The base class for the channels that use ZMQ sockets.
84 84 """
85 85 context = None
86 86 session = None
87 87 socket = None
88 88 ioloop = None
89 89 stream = None
90 90 _address = None
91 91
92 92 def __init__(self, context, session, address):
93 93 """Create a channel
94 94
95 95 Parameters
96 96 ----------
97 97 context : :class:`zmq.Context`
98 98 The ZMQ context to use.
99 99 session : :class:`session.Session`
100 100 The session to use.
101 101 address : tuple
102 102 Standard (ip, port) tuple that the kernel is listening on.
103 103 """
104 104 super(ZMQSocketChannel, self).__init__()
105 105 self.daemon = True
106 106
107 107 self.context = context
108 108 self.session = session
109 109 if address[1] == 0:
110 110 message = 'The port number for a channel cannot be 0.'
111 111 raise InvalidPortNumber(message)
112 112 self._address = address
113 113
114 114 def _run_loop(self):
115 115 """Run my loop, ignoring EINTR events in the poller"""
116 116 while True:
117 117 try:
118 118 self.ioloop.start()
119 119 except zmq.ZMQError as e:
120 120 if e.errno == errno.EINTR:
121 121 continue
122 122 else:
123 123 raise
124 124 else:
125 125 break
126 126
127 127 def stop(self):
128 128 """Stop the channel's activity.
129 129
130 130 This calls :method:`Thread.join` and returns when the thread
131 131 terminates. :class:`RuntimeError` will be raised if
132 132 :method:`self.start` is called again.
133 133 """
134 134 self.join()
135 135
136 136 @property
137 137 def address(self):
138 138 """Get the channel's address as an (ip, port) tuple.
139 139
140 140 By the default, the address is (localhost, 0), where 0 means a random
141 141 port.
142 142 """
143 143 return self._address
144 144
145 145 def _queue_send(self, msg):
146 146 """Queue a message to be sent from the IOLoop's thread.
147 147
148 148 Parameters
149 149 ----------
150 150 msg : message to send
151 151
152 152 This is threadsafe, as it uses IOLoop.add_callback to give the loop's
153 153 thread control of the action.
154 154 """
155 155 def thread_send():
156 156 self.session.send(self.stream, msg)
157 157 self.ioloop.add_callback(thread_send)
158 158
159 159 def _handle_recv(self, msg):
160 160 """callback for stream.on_recv
161 161
162 162 unpacks message, and calls handlers with it.
163 163 """
164 164 ident,smsg = self.session.feed_identities(msg)
165 165 self.call_handlers(self.session.unserialize(smsg))
166 166
167 167
168 168
169 169 class ShellSocketChannel(ZMQSocketChannel):
170 170 """The XREQ channel for issues request/replies to the kernel.
171 171 """
172 172
173 173 command_queue = None
174 174 # flag for whether execute requests should be allowed to call raw_input:
175 175 allow_stdin = True
176 176
177 177 def __init__(self, context, session, address):
178 178 super(ShellSocketChannel, self).__init__(context, session, address)
179 179 self.ioloop = ioloop.IOLoop()
180 180
181 181 def run(self):
182 182 """The thread's main activity. Call start() instead."""
183 183 self.socket = self.context.socket(zmq.DEALER)
184 184 self.socket.setsockopt(zmq.IDENTITY, self.session.bsession)
185 185 self.socket.connect('tcp://%s:%i' % self.address)
186 186 self.stream = zmqstream.ZMQStream(self.socket, self.ioloop)
187 187 self.stream.on_recv(self._handle_recv)
188 188 self._run_loop()
189 189
190 190 def stop(self):
191 191 self.ioloop.stop()
192 192 super(ShellSocketChannel, self).stop()
193 193
194 194 def call_handlers(self, msg):
195 195 """This method is called in the ioloop thread when a message arrives.
196 196
197 197 Subclasses should override this method to handle incoming messages.
198 198 It is important to remember that this method is called in the thread
199 199 so that some logic must be done to ensure that the application leve
200 200 handlers are called in the application thread.
201 201 """
202 202 raise NotImplementedError('call_handlers must be defined in a subclass.')
203 203
204 204 def execute(self, code, silent=False,
205 205 user_variables=None, user_expressions=None, allow_stdin=None):
206 206 """Execute code in the kernel.
207 207
208 208 Parameters
209 209 ----------
210 210 code : str
211 211 A string of Python code.
212 212
213 213 silent : bool, optional (default False)
214 214 If set, the kernel will execute the code as quietly possible.
215 215
216 216 user_variables : list, optional
217 217 A list of variable names to pull from the user's namespace. They
218 218 will come back as a dict with these names as keys and their
219 219 :func:`repr` as values.
220 220
221 221 user_expressions : dict, optional
222 222 A dict with string keys and to pull from the user's
223 223 namespace. They will come back as a dict with these names as keys
224 224 and their :func:`repr` as values.
225 225
226 226 allow_stdin : bool, optional
227 227 Flag for
228 228 A dict with string keys and to pull from the user's
229 229 namespace. They will come back as a dict with these names as keys
230 230 and their :func:`repr` as values.
231 231
232 232 Returns
233 233 -------
234 234 The msg_id of the message sent.
235 235 """
236 236 if user_variables is None:
237 237 user_variables = []
238 238 if user_expressions is None:
239 239 user_expressions = {}
240 240 if allow_stdin is None:
241 241 allow_stdin = self.allow_stdin
242 242
243 243
244 244 # Don't waste network traffic if inputs are invalid
245 245 if not isinstance(code, basestring):
246 246 raise ValueError('code %r must be a string' % code)
247 247 validate_string_list(user_variables)
248 248 validate_string_dict(user_expressions)
249 249
250 250 # Create class for content/msg creation. Related to, but possibly
251 251 # not in Session.
252 252 content = dict(code=code, silent=silent,
253 253 user_variables=user_variables,
254 254 user_expressions=user_expressions,
255 255 allow_stdin=allow_stdin,
256 256 )
257 257 msg = self.session.msg('execute_request', content)
258 258 self._queue_send(msg)
259 259 return msg['header']['msg_id']
260 260
261 261 def complete(self, text, line, cursor_pos, block=None):
262 262 """Tab complete text in the kernel's namespace.
263 263
264 264 Parameters
265 265 ----------
266 266 text : str
267 267 The text to complete.
268 268 line : str
269 269 The full line of text that is the surrounding context for the
270 270 text to complete.
271 271 cursor_pos : int
272 272 The position of the cursor in the line where the completion was
273 273 requested.
274 274 block : str, optional
275 275 The full block of code in which the completion is being requested.
276 276
277 277 Returns
278 278 -------
279 279 The msg_id of the message sent.
280 280 """
281 281 content = dict(text=text, line=line, block=block, cursor_pos=cursor_pos)
282 282 msg = self.session.msg('complete_request', content)
283 283 self._queue_send(msg)
284 284 return msg['header']['msg_id']
285 285
286 286 def object_info(self, oname):
287 287 """Get metadata information about an object.
288 288
289 289 Parameters
290 290 ----------
291 291 oname : str
292 292 A string specifying the object name.
293 293
294 294 Returns
295 295 -------
296 296 The msg_id of the message sent.
297 297 """
298 298 content = dict(oname=oname)
299 299 msg = self.session.msg('object_info_request', content)
300 300 self._queue_send(msg)
301 301 return msg['header']['msg_id']
302 302
303 303 def history(self, raw=True, output=False, hist_access_type='range', **kwargs):
304 304 """Get entries from the history list.
305 305
306 306 Parameters
307 307 ----------
308 308 raw : bool
309 309 If True, return the raw input.
310 310 output : bool
311 311 If True, then return the output as well.
312 312 hist_access_type : str
313 313 'range' (fill in session, start and stop params), 'tail' (fill in n)
314 314 or 'search' (fill in pattern param).
315 315
316 316 session : int
317 317 For a range request, the session from which to get lines. Session
318 318 numbers are positive integers; negative ones count back from the
319 319 current session.
320 320 start : int
321 321 The first line number of a history range.
322 322 stop : int
323 323 The final (excluded) line number of a history range.
324 324
325 325 n : int
326 326 The number of lines of history to get for a tail request.
327 327
328 328 pattern : str
329 329 The glob-syntax pattern for a search request.
330 330
331 331 Returns
332 332 -------
333 333 The msg_id of the message sent.
334 334 """
335 335 content = dict(raw=raw, output=output, hist_access_type=hist_access_type,
336 336 **kwargs)
337 337 msg = self.session.msg('history_request', content)
338 338 self._queue_send(msg)
339 339 return msg['header']['msg_id']
340 340
341 341 def shutdown(self, restart=False):
342 342 """Request an immediate kernel shutdown.
343 343
344 344 Upon receipt of the (empty) reply, client code can safely assume that
345 345 the kernel has shut down and it's safe to forcefully terminate it if
346 346 it's still alive.
347 347
348 348 The kernel will send the reply via a function registered with Python's
349 349 atexit module, ensuring it's truly done as the kernel is done with all
350 350 normal operation.
351 351 """
352 352 # Send quit message to kernel. Once we implement kernel-side setattr,
353 353 # this should probably be done that way, but for now this will do.
354 354 msg = self.session.msg('shutdown_request', {'restart':restart})
355 355 self._queue_send(msg)
356 356 return msg['header']['msg_id']
357 357
358 358
359 359
360 360 class SubSocketChannel(ZMQSocketChannel):
361 361 """The SUB channel which listens for messages that the kernel publishes.
362 362 """
363 363
364 364 def __init__(self, context, session, address):
365 365 super(SubSocketChannel, self).__init__(context, session, address)
366 366 self.ioloop = ioloop.IOLoop()
367 367
368 368 def run(self):
369 369 """The thread's main activity. Call start() instead."""
370 370 self.socket = self.context.socket(zmq.SUB)
371 371 self.socket.setsockopt(zmq.SUBSCRIBE,b'')
372 372 self.socket.setsockopt(zmq.IDENTITY, self.session.bsession)
373 373 self.socket.connect('tcp://%s:%i' % self.address)
374 374 self.stream = zmqstream.ZMQStream(self.socket, self.ioloop)
375 375 self.stream.on_recv(self._handle_recv)
376 376 self._run_loop()
377 377
378 378 def stop(self):
379 379 self.ioloop.stop()
380 380 super(SubSocketChannel, self).stop()
381 381
382 382 def call_handlers(self, msg):
383 383 """This method is called in the ioloop thread when a message arrives.
384 384
385 385 Subclasses should override this method to handle incoming messages.
386 386 It is important to remember that this method is called in the thread
387 387 so that some logic must be done to ensure that the application leve
388 388 handlers are called in the application thread.
389 389 """
390 390 raise NotImplementedError('call_handlers must be defined in a subclass.')
391 391
392 392 def flush(self, timeout=1.0):
393 393 """Immediately processes all pending messages on the SUB channel.
394 394
395 395 Callers should use this method to ensure that :method:`call_handlers`
396 396 has been called for all messages that have been received on the
397 397 0MQ SUB socket of this channel.
398 398
399 399 This method is thread safe.
400 400
401 401 Parameters
402 402 ----------
403 403 timeout : float, optional
404 404 The maximum amount of time to spend flushing, in seconds. The
405 405 default is one second.
406 406 """
407 407 # We do the IOLoop callback process twice to ensure that the IOLoop
408 408 # gets to perform at least one full poll.
409 409 stop_time = time.time() + timeout
410 410 for i in xrange(2):
411 411 self._flushed = False
412 412 self.ioloop.add_callback(self._flush)
413 413 while not self._flushed and time.time() < stop_time:
414 414 time.sleep(0.01)
415 415
416 416 def _flush(self):
417 417 """Callback for :method:`self.flush`."""
418 418 self.stream.flush()
419 419 self._flushed = True
420 420
421 421
422 422 class StdInSocketChannel(ZMQSocketChannel):
423 423 """A reply channel to handle raw_input requests that the kernel makes."""
424 424
425 425 msg_queue = None
426 426
427 427 def __init__(self, context, session, address):
428 428 super(StdInSocketChannel, self).__init__(context, session, address)
429 429 self.ioloop = ioloop.IOLoop()
430 430
431 431 def run(self):
432 432 """The thread's main activity. Call start() instead."""
433 433 self.socket = self.context.socket(zmq.DEALER)
434 434 self.socket.setsockopt(zmq.IDENTITY, self.session.bsession)
435 435 self.socket.connect('tcp://%s:%i' % self.address)
436 436 self.stream = zmqstream.ZMQStream(self.socket, self.ioloop)
437 437 self.stream.on_recv(self._handle_recv)
438 438 self._run_loop()
439 439
440 440 def stop(self):
441 441 self.ioloop.stop()
442 442 super(StdInSocketChannel, self).stop()
443 443
444 444 def call_handlers(self, msg):
445 445 """This method is called in the ioloop thread when a message arrives.
446 446
447 447 Subclasses should override this method to handle incoming messages.
448 448 It is important to remember that this method is called in the thread
449 449 so that some logic must be done to ensure that the application leve
450 450 handlers are called in the application thread.
451 451 """
452 452 raise NotImplementedError('call_handlers must be defined in a subclass.')
453 453
454 454 def input(self, string):
455 455 """Send a string of raw input to the kernel."""
456 456 content = dict(value=string)
457 457 msg = self.session.msg('input_reply', content)
458 458 self._queue_send(msg)
459 459
460 460
461 461 class HBSocketChannel(ZMQSocketChannel):
462 462 """The heartbeat channel which monitors the kernel heartbeat.
463 463
464 464 Note that the heartbeat channel is paused by default. As long as you start
465 465 this channel, the kernel manager will ensure that it is paused and un-paused
466 466 as appropriate.
467 467 """
468 468
469 469 time_to_dead = 3.0
470 470 socket = None
471 471 poller = None
472 472 _running = None
473 473 _pause = None
474 474
475 475 def __init__(self, context, session, address):
476 476 super(HBSocketChannel, self).__init__(context, session, address)
477 477 self._running = False
478 478 self._pause = True
479 479
480 480 def _create_socket(self):
481 481 self.socket = self.context.socket(zmq.REQ)
482 482 self.socket.setsockopt(zmq.IDENTITY, self.session.bsession)
483 483 self.socket.connect('tcp://%s:%i' % self.address)
484 484 self.poller = zmq.Poller()
485 485 self.poller.register(self.socket, zmq.POLLIN)
486 486
487 487 def run(self):
488 488 """The thread's main activity. Call start() instead."""
489 489 self._create_socket()
490 490 self._running = True
491 491 while self._running:
492 492 if self._pause:
493 493 time.sleep(self.time_to_dead)
494 494 else:
495 495 since_last_heartbeat = 0.0
496 496 request_time = time.time()
497 497 try:
498 498 #io.rprint('Ping from HB channel') # dbg
499 499 self.socket.send(b'ping')
500 500 except zmq.ZMQError, e:
501 501 #io.rprint('*** HB Error:', e) # dbg
502 502 if e.errno == zmq.EFSM:
503 503 #io.rprint('sleep...', self.time_to_dead) # dbg
504 504 time.sleep(self.time_to_dead)
505 505 self._create_socket()
506 506 else:
507 507 raise
508 508 else:
509 509 while True:
510 510 try:
511 511 self.socket.recv(zmq.NOBLOCK)
512 512 except zmq.ZMQError, e:
513 513 #io.rprint('*** HB Error 2:', e) # dbg
514 514 if e.errno == zmq.EAGAIN:
515 515 before_poll = time.time()
516 516 until_dead = self.time_to_dead - (before_poll -
517 517 request_time)
518 518
519 519 # When the return value of poll() is an empty
520 520 # list, that is when things have gone wrong
521 521 # (zeromq bug). As long as it is not an empty
522 522 # list, poll is working correctly even if it
523 523 # returns quickly. Note: poll timeout is in
524 524 # milliseconds.
525 525 if until_dead > 0.0:
526 526 while True:
527 527 try:
528 528 self.poller.poll(1000 * until_dead)
529 529 except zmq.ZMQError as e:
530 530 if e.errno == errno.EINTR:
531 531 continue
532 532 else:
533 533 raise
534 534 else:
535 535 break
536 536
537 537 since_last_heartbeat = time.time()-request_time
538 538 if since_last_heartbeat > self.time_to_dead:
539 539 self.call_handlers(since_last_heartbeat)
540 540 break
541 541 else:
542 542 # FIXME: We should probably log this instead.
543 543 raise
544 544 else:
545 545 until_dead = self.time_to_dead - (time.time() -
546 546 request_time)
547 547 if until_dead > 0.0:
548 548 #io.rprint('sleep...', self.time_to_dead) # dbg
549 549 time.sleep(until_dead)
550 550 break
551 551
552 552 def pause(self):
553 553 """Pause the heartbeat."""
554 554 self._pause = True
555 555
556 556 def unpause(self):
557 557 """Unpause the heartbeat."""
558 558 self._pause = False
559 559
560 560 def is_beating(self):
561 561 """Is the heartbeat running and not paused."""
562 562 if self.is_alive() and not self._pause:
563 563 return True
564 564 else:
565 565 return False
566 566
567 567 def stop(self):
568 568 self._running = False
569 569 super(HBSocketChannel, self).stop()
570 570
571 571 def call_handlers(self, since_last_heartbeat):
572 572 """This method is called in the ioloop thread when a message arrives.
573 573
574 574 Subclasses should override this method to handle incoming messages.
575 575 It is important to remember that this method is called in the thread
576 576 so that some logic must be done to ensure that the application leve
577 577 handlers are called in the application thread.
578 578 """
579 579 raise NotImplementedError('call_handlers must be defined in a subclass.')
580 580
581 581
582 582 #-----------------------------------------------------------------------------
583 583 # Main kernel manager class
584 584 #-----------------------------------------------------------------------------
585 585
586 586 class KernelManager(HasTraits):
587 587 """ Manages a kernel for a frontend.
588 588
589 589 The SUB channel is for the frontend to receive messages published by the
590 590 kernel.
591 591
592 592 The REQ channel is for the frontend to make requests of the kernel.
593 593
594 594 The REP channel is for the kernel to request stdin (raw_input) from the
595 595 frontend.
596 596 """
597 597 # config object for passing to child configurables
598 598 config = Instance(Config)
599 599
600 600 # The PyZMQ Context to use for communication with the kernel.
601 601 context = Instance(zmq.Context)
602 602 def _context_default(self):
603 603 return zmq.Context.instance()
604 604
605 605 # The Session to use for communication with the kernel.
606 606 session = Instance(Session)
607 607
608 608 # The kernel process with which the KernelManager is communicating.
609 609 kernel = Instance(Popen)
610 610
611 611 # The addresses for the communication channels.
612 612 connection_file = Unicode('')
613 613 ip = Unicode(LOCALHOST)
614 614 def _ip_changed(self, name, old, new):
615 615 if new == '*':
616 616 self.ip = '0.0.0.0'
617 617 shell_port = Integer(0)
618 618 iopub_port = Integer(0)
619 619 stdin_port = Integer(0)
620 620 hb_port = Integer(0)
621 621
622 622 # The classes to use for the various channels.
623 623 shell_channel_class = Type(ShellSocketChannel)
624 624 sub_channel_class = Type(SubSocketChannel)
625 625 stdin_channel_class = Type(StdInSocketChannel)
626 626 hb_channel_class = Type(HBSocketChannel)
627 627
628 628 # Protected traits.
629 629 _launch_args = Any
630 630 _shell_channel = Any
631 631 _sub_channel = Any
632 632 _stdin_channel = Any
633 633 _hb_channel = Any
634 634 _connection_file_written=Bool(False)
635 635
636 636 def __init__(self, **kwargs):
637 637 super(KernelManager, self).__init__(**kwargs)
638 638 if self.session is None:
639 639 self.session = Session(config=self.config)
640 640
641 641 def __del__(self):
642 642 if self._connection_file_written:
643 643 # cleanup connection files on full shutdown of kernel we started
644 644 self._connection_file_written = False
645 645 try:
646 646 os.remove(self.connection_file)
647 647 except IOError:
648 648 pass
649 649
650 650
651 651 #--------------------------------------------------------------------------
652 652 # Channel management methods:
653 653 #--------------------------------------------------------------------------
654 654
655 655 def start_channels(self, shell=True, sub=True, stdin=True, hb=True):
656 656 """Starts the channels for this kernel.
657 657
658 658 This will create the channels if they do not exist and then start
659 659 them. If port numbers of 0 are being used (random ports) then you
660 660 must first call :method:`start_kernel`. If the channels have been
661 661 stopped and you call this, :class:`RuntimeError` will be raised.
662 662 """
663 663 if shell:
664 664 self.shell_channel.start()
665 665 if sub:
666 666 self.sub_channel.start()
667 667 if stdin:
668 668 self.stdin_channel.start()
669 669 self.shell_channel.allow_stdin = True
670 670 else:
671 671 self.shell_channel.allow_stdin = False
672 672 if hb:
673 673 self.hb_channel.start()
674 674
675 675 def stop_channels(self):
676 676 """Stops all the running channels for this kernel.
677 677 """
678 678 if self.shell_channel.is_alive():
679 679 self.shell_channel.stop()
680 680 if self.sub_channel.is_alive():
681 681 self.sub_channel.stop()
682 682 if self.stdin_channel.is_alive():
683 683 self.stdin_channel.stop()
684 684 if self.hb_channel.is_alive():
685 685 self.hb_channel.stop()
686 686
687 687 @property
688 688 def channels_running(self):
689 689 """Are any of the channels created and running?"""
690 690 return (self.shell_channel.is_alive() or self.sub_channel.is_alive() or
691 691 self.stdin_channel.is_alive() or self.hb_channel.is_alive())
692 692
693 693 #--------------------------------------------------------------------------
694 694 # Kernel process management methods:
695 695 #--------------------------------------------------------------------------
696 696
697 697 def load_connection_file(self):
698 698 """load connection info from JSON dict in self.connection_file"""
699 699 with open(self.connection_file) as f:
700 700 cfg = json.loads(f.read())
701 701
702 702 self.ip = cfg['ip']
703 703 self.shell_port = cfg['shell_port']
704 704 self.stdin_port = cfg['stdin_port']
705 705 self.iopub_port = cfg['iopub_port']
706 706 self.hb_port = cfg['hb_port']
707 707 self.session.key = str_to_bytes(cfg['key'])
708 708
709 709 def write_connection_file(self):
710 710 """write connection info to JSON dict in self.connection_file"""
711 711 if self._connection_file_written:
712 712 return
713 713 self.connection_file,cfg = write_connection_file(self.connection_file,
714 714 ip=self.ip, key=self.session.key,
715 715 stdin_port=self.stdin_port, iopub_port=self.iopub_port,
716 716 shell_port=self.shell_port, hb_port=self.hb_port)
717 717 # write_connection_file also sets default ports:
718 718 self.shell_port = cfg['shell_port']
719 719 self.stdin_port = cfg['stdin_port']
720 720 self.iopub_port = cfg['iopub_port']
721 721 self.hb_port = cfg['hb_port']
722 722
723 723 self._connection_file_written = True
724 724
725 725 def start_kernel(self, **kw):
726 726 """Starts a kernel process and configures the manager to use it.
727 727
728 728 If random ports (port=0) are being used, this method must be called
729 729 before the channels are created.
730 730
731 731 Parameters:
732 732 -----------
733 733 ipython : bool, optional (default True)
734 734 Whether to use an IPython kernel instead of a plain Python kernel.
735 735
736 736 launcher : callable, optional (default None)
737 737 A custom function for launching the kernel process (generally a
738 738 wrapper around ``entry_point.base_launch_kernel``). In most cases,
739 739 it should not be necessary to use this parameter.
740 740
741 741 **kw : optional
742 742 See respective options for IPython and Python kernels.
743 743 """
744 744 if self.ip not in LOCAL_IPS:
745 745 raise RuntimeError("Can only launch a kernel on a local interface. "
746 746 "Make sure that the '*_address' attributes are "
747 747 "configured properly. "
748 748 "Currently valid addresses are: %s"%LOCAL_IPS
749 749 )
750 750
751 751 # write connection file / get default ports
752 752 self.write_connection_file()
753 753
754 754 self._launch_args = kw.copy()
755 755 launch_kernel = kw.pop('launcher', None)
756 756 if launch_kernel is None:
757 757 if kw.pop('ipython', True):
758 758 from ipkernel import launch_kernel
759 759 else:
760 760 from pykernel import launch_kernel
761 761 self.kernel = launch_kernel(fname=self.connection_file, **kw)
762 762
763 763 def shutdown_kernel(self, restart=False):
764 764 """ Attempts to the stop the kernel process cleanly. If the kernel
765 765 cannot be stopped, it is killed, if possible.
766 766 """
767 767 # FIXME: Shutdown does not work on Windows due to ZMQ errors!
768 768 if sys.platform == 'win32':
769 769 self.kill_kernel()
770 770 return
771 771
772 772 # Pause the heart beat channel if it exists.
773 773 if self._hb_channel is not None:
774 774 self._hb_channel.pause()
775 775
776 776 # Don't send any additional kernel kill messages immediately, to give
777 777 # the kernel a chance to properly execute shutdown actions. Wait for at
778 778 # most 1s, checking every 0.1s.
779 779 self.shell_channel.shutdown(restart=restart)
780 780 for i in range(10):
781 781 if self.is_alive:
782 782 time.sleep(0.1)
783 783 else:
784 784 break
785 785 else:
786 786 # OK, we've waited long enough.
787 787 if self.has_kernel:
788 788 self.kill_kernel()
789 789
790 790 if not restart and self._connection_file_written:
791 791 # cleanup connection files on full shutdown of kernel we started
792 792 self._connection_file_written = False
793 793 try:
794 794 os.remove(self.connection_file)
795 795 except IOError:
796 796 pass
797 797
798 798 def restart_kernel(self, now=False, **kw):
799 799 """Restarts a kernel with the arguments that were used to launch it.
800 800
801 801 If the old kernel was launched with random ports, the same ports will be
802 802 used for the new kernel.
803 803
804 804 Parameters
805 805 ----------
806 806 now : bool, optional
807 807 If True, the kernel is forcefully restarted *immediately*, without
808 808 having a chance to do any cleanup action. Otherwise the kernel is
809 809 given 1s to clean up before a forceful restart is issued.
810 810
811 811 In all cases the kernel is restarted, the only difference is whether
812 812 it is given a chance to perform a clean shutdown or not.
813 813
814 814 **kw : optional
815 815 Any options specified here will replace those used to launch the
816 816 kernel.
817 817 """
818 818 if self._launch_args is None:
819 819 raise RuntimeError("Cannot restart the kernel. "
820 820 "No previous call to 'start_kernel'.")
821 821 else:
822 822 # Stop currently running kernel.
823 823 if self.has_kernel:
824 824 if now:
825 825 self.kill_kernel()
826 826 else:
827 827 self.shutdown_kernel(restart=True)
828 828
829 829 # Start new kernel.
830 830 self._launch_args.update(kw)
831 831 self.start_kernel(**self._launch_args)
832 832
833 833 # FIXME: Messages get dropped in Windows due to probable ZMQ bug
834 834 # unless there is some delay here.
835 835 if sys.platform == 'win32':
836 836 time.sleep(0.2)
837 837
838 838 @property
839 839 def has_kernel(self):
840 840 """Returns whether a kernel process has been specified for the kernel
841 841 manager.
842 842 """
843 843 return self.kernel is not None
844 844
845 845 def kill_kernel(self):
846 846 """ Kill the running kernel. """
847 847 if self.has_kernel:
848 848 # Pause the heart beat channel if it exists.
849 849 if self._hb_channel is not None:
850 850 self._hb_channel.pause()
851 851
852 852 # Attempt to kill the kernel.
853 853 try:
854 854 self.kernel.kill()
855 855 except OSError, e:
856 856 # In Windows, we will get an Access Denied error if the process
857 857 # has already terminated. Ignore it.
858 858 if sys.platform == 'win32':
859 859 if e.winerror != 5:
860 860 raise
861 861 # On Unix, we may get an ESRCH error if the process has already
862 862 # terminated. Ignore it.
863 863 else:
864 864 from errno import ESRCH
865 865 if e.errno != ESRCH:
866 866 raise
867 867 self.kernel = None
868 868 else:
869 869 raise RuntimeError("Cannot kill kernel. No kernel is running!")
870 870
871 871 def interrupt_kernel(self):
872 872 """ Interrupts the kernel. Unlike ``signal_kernel``, this operation is
873 873 well supported on all platforms.
874 874 """
875 875 if self.has_kernel:
876 876 if sys.platform == 'win32':
877 877 from parentpoller import ParentPollerWindows as Poller
878 878 Poller.send_interrupt(self.kernel.win32_interrupt_event)
879 879 else:
880 880 self.kernel.send_signal(signal.SIGINT)
881 881 else:
882 882 raise RuntimeError("Cannot interrupt kernel. No kernel is running!")
883 883
884 884 def signal_kernel(self, signum):
885 885 """ Sends a signal to the kernel. Note that since only SIGTERM is
886 886 supported on Windows, this function is only useful on Unix systems.
887 887 """
888 888 if self.has_kernel:
889 889 self.kernel.send_signal(signum)
890 890 else:
891 891 raise RuntimeError("Cannot signal kernel. No kernel is running!")
892 892
893 893 @property
894 894 def is_alive(self):
895 895 """Is the kernel process still running?"""
896 896 # FIXME: not using a heartbeat means this method is broken for any
897 897 # remote kernel, it's only capable of handling local kernels.
898 898 if self.has_kernel:
899 899 if self.kernel.poll() is None:
900 900 return True
901 901 else:
902 902 return False
903 903 else:
904 904 # We didn't start the kernel with this KernelManager so we don't
905 905 # know if it is running. We should use a heartbeat for this case.
906 906 return True
907 907
908 908 #--------------------------------------------------------------------------
909 909 # Channels used for communication with the kernel:
910 910 #--------------------------------------------------------------------------
911 911
912 912 @property
913 913 def shell_channel(self):
914 914 """Get the REQ socket channel object to make requests of the kernel."""
915 915 if self._shell_channel is None:
916 916 self._shell_channel = self.shell_channel_class(self.context,
917 917 self.session,
918 918 (self.ip, self.shell_port))
919 919 return self._shell_channel
920 920
921 921 @property
922 922 def sub_channel(self):
923 923 """Get the SUB socket channel object."""
924 924 if self._sub_channel is None:
925 925 self._sub_channel = self.sub_channel_class(self.context,
926 926 self.session,
927 927 (self.ip, self.iopub_port))
928 928 return self._sub_channel
929 929
930 930 @property
931 931 def stdin_channel(self):
932 932 """Get the REP socket channel object to handle stdin (raw_input)."""
933 933 if self._stdin_channel is None:
934 934 self._stdin_channel = self.stdin_channel_class(self.context,
935 935 self.session,
936 936 (self.ip, self.stdin_port))
937 937 return self._stdin_channel
938 938
939 939 @property
940 940 def hb_channel(self):
941 941 """Get the heartbeat socket channel object to check that the
942 942 kernel is alive."""
943 943 if self._hb_channel is None:
944 944 self._hb_channel = self.hb_channel_class(self.context,
945 945 self.session,
946 946 (self.ip, self.hb_port))
947 947 return self._hb_channel
@@ -1,40 +1,40 b''
1 1 """Test suite for our zeromq-based messaging specification.
2 2 """
3 3 #-----------------------------------------------------------------------------
4 # Copyright (C) 2010 The IPython Development Team
4 # Copyright (C) 2010-2011 The IPython Development Team
5 5 #
6 6 # Distributed under the terms of the BSD License. The full license is in
7 7 # the file COPYING.txt, distributed as part of this software.
8 8 #-----------------------------------------------------------------------------
9 9
10 10 import sys
11 11 import time
12 12
13 13 import nose.tools as nt
14 14
15 15 from ..blockingkernelmanager import BlockingKernelManager
16 16
17 17 from IPython.utils import io
18 18
19 19 def setup():
20 20 global KM
21 21 KM = BlockingKernelManager()
22 22
23 23 KM.start_kernel()
24 24 KM.start_channels()
25 25 # Give the kernel a chance to come up.
26 26 time.sleep(1)
27 27
28 28 def teardown():
29 29 io.rprint('Entering teardown...') # dbg
30 30 io.rprint('Stopping channels and kernel...') # dbg
31 31 KM.stop_channels()
32 32 KM.kill_kernel()
33 33
34 34
35 35 # Actual tests
36 36
37 37 def test_execute():
38 38 KM.shell_channel.execute(code='x=1')
39 39 KM.shell_channel.execute(code='print 1')
40 40
General Comments 0
You need to be logged in to leave comments. Login now