##// END OF EJS Templates
Merge pull request #2088 from bfroehle/_2083_py32_test_failures...
Thomas Kluyver -
r7811:d6009ff2 merge
parent child Browse files
Show More
@@ -1,743 +1,744
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tests for various magic functions.
2 """Tests for various magic functions.
3
3
4 Needs to be run by nose (to make ipython session available).
4 Needs to be run by nose (to make ipython session available).
5 """
5 """
6 from __future__ import absolute_import
6 from __future__ import absolute_import
7
7
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Imports
9 # Imports
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11
11
12 import io
12 import io
13 import os
13 import os
14 import sys
14 import sys
15 from StringIO import StringIO
15 from StringIO import StringIO
16 from unittest import TestCase
16 from unittest import TestCase
17
17
18 try:
18 try:
19 from importlib import invalidate_caches # Required from Python 3.3
19 from importlib import invalidate_caches # Required from Python 3.3
20 except ImportError:
20 except ImportError:
21 def invalidate_caches():
21 def invalidate_caches():
22 pass
22 pass
23
23
24 import nose.tools as nt
24 import nose.tools as nt
25
25
26 from IPython.core import magic
26 from IPython.core import magic
27 from IPython.core.magic import (Magics, magics_class, line_magic,
27 from IPython.core.magic import (Magics, magics_class, line_magic,
28 cell_magic, line_cell_magic,
28 cell_magic, line_cell_magic,
29 register_line_magic, register_cell_magic,
29 register_line_magic, register_cell_magic,
30 register_line_cell_magic)
30 register_line_cell_magic)
31 from IPython.core.magics import execution, script
31 from IPython.core.magics import execution, script
32 from IPython.nbformat.v3.tests.nbexamples import nb0
32 from IPython.nbformat.v3.tests.nbexamples import nb0
33 from IPython.nbformat import current
33 from IPython.nbformat import current
34 from IPython.testing import decorators as dec
34 from IPython.testing import decorators as dec
35 from IPython.testing import tools as tt
35 from IPython.testing import tools as tt
36 from IPython.utils import py3compat
36 from IPython.utils import py3compat
37 from IPython.utils.tempdir import TemporaryDirectory
37 from IPython.utils.tempdir import TemporaryDirectory
38 from IPython.utils.process import find_cmd
38 from IPython.utils.process import find_cmd
39
39
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41 # Test functions begin
41 # Test functions begin
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43
43
44 @magic.magics_class
44 @magic.magics_class
45 class DummyMagics(magic.Magics): pass
45 class DummyMagics(magic.Magics): pass
46
46
47 def test_rehashx():
47 def test_rehashx():
48 # clear up everything
48 # clear up everything
49 _ip = get_ipython()
49 _ip = get_ipython()
50 _ip.alias_manager.alias_table.clear()
50 _ip.alias_manager.alias_table.clear()
51 del _ip.db['syscmdlist']
51 del _ip.db['syscmdlist']
52
52
53 _ip.magic('rehashx')
53 _ip.magic('rehashx')
54 # Practically ALL ipython development systems will have more than 10 aliases
54 # Practically ALL ipython development systems will have more than 10 aliases
55
55
56 yield (nt.assert_true, len(_ip.alias_manager.alias_table) > 10)
56 yield (nt.assert_true, len(_ip.alias_manager.alias_table) > 10)
57 for key, val in _ip.alias_manager.alias_table.iteritems():
57 for key, val in _ip.alias_manager.alias_table.iteritems():
58 # we must strip dots from alias names
58 # we must strip dots from alias names
59 nt.assert_true('.' not in key)
59 nt.assert_true('.' not in key)
60
60
61 # rehashx must fill up syscmdlist
61 # rehashx must fill up syscmdlist
62 scoms = _ip.db['syscmdlist']
62 scoms = _ip.db['syscmdlist']
63 yield (nt.assert_true, len(scoms) > 10)
63 yield (nt.assert_true, len(scoms) > 10)
64
64
65
65
66 def test_magic_parse_options():
66 def test_magic_parse_options():
67 """Test that we don't mangle paths when parsing magic options."""
67 """Test that we don't mangle paths when parsing magic options."""
68 ip = get_ipython()
68 ip = get_ipython()
69 path = 'c:\\x'
69 path = 'c:\\x'
70 m = DummyMagics(ip)
70 m = DummyMagics(ip)
71 opts = m.parse_options('-f %s' % path,'f:')[0]
71 opts = m.parse_options('-f %s' % path,'f:')[0]
72 # argv splitting is os-dependent
72 # argv splitting is os-dependent
73 if os.name == 'posix':
73 if os.name == 'posix':
74 expected = 'c:x'
74 expected = 'c:x'
75 else:
75 else:
76 expected = path
76 expected = path
77 nt.assert_equals(opts['f'], expected)
77 nt.assert_equals(opts['f'], expected)
78
78
79 def test_magic_parse_long_options():
79 def test_magic_parse_long_options():
80 """Magic.parse_options can handle --foo=bar long options"""
80 """Magic.parse_options can handle --foo=bar long options"""
81 ip = get_ipython()
81 ip = get_ipython()
82 m = DummyMagics(ip)
82 m = DummyMagics(ip)
83 opts, _ = m.parse_options('--foo --bar=bubble', 'a', 'foo', 'bar=')
83 opts, _ = m.parse_options('--foo --bar=bubble', 'a', 'foo', 'bar=')
84 nt.assert_true('foo' in opts)
84 nt.assert_true('foo' in opts)
85 nt.assert_true('bar' in opts)
85 nt.assert_true('bar' in opts)
86 nt.assert_true(opts['bar'], "bubble")
86 nt.assert_true(opts['bar'], "bubble")
87
87
88
88
89 @dec.skip_without('sqlite3')
89 @dec.skip_without('sqlite3')
90 def doctest_hist_f():
90 def doctest_hist_f():
91 """Test %hist -f with temporary filename.
91 """Test %hist -f with temporary filename.
92
92
93 In [9]: import tempfile
93 In [9]: import tempfile
94
94
95 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
95 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
96
96
97 In [11]: %hist -nl -f $tfile 3
97 In [11]: %hist -nl -f $tfile 3
98
98
99 In [13]: import os; os.unlink(tfile)
99 In [13]: import os; os.unlink(tfile)
100 """
100 """
101
101
102
102
103 @dec.skip_without('sqlite3')
103 @dec.skip_without('sqlite3')
104 def doctest_hist_r():
104 def doctest_hist_r():
105 """Test %hist -r
105 """Test %hist -r
106
106
107 XXX - This test is not recording the output correctly. For some reason, in
107 XXX - This test is not recording the output correctly. For some reason, in
108 testing mode the raw history isn't getting populated. No idea why.
108 testing mode the raw history isn't getting populated. No idea why.
109 Disabling the output checking for now, though at least we do run it.
109 Disabling the output checking for now, though at least we do run it.
110
110
111 In [1]: 'hist' in _ip.lsmagic()
111 In [1]: 'hist' in _ip.lsmagic()
112 Out[1]: True
112 Out[1]: True
113
113
114 In [2]: x=1
114 In [2]: x=1
115
115
116 In [3]: %hist -rl 2
116 In [3]: %hist -rl 2
117 x=1 # random
117 x=1 # random
118 %hist -r 2
118 %hist -r 2
119 """
119 """
120
120
121
121
122 @dec.skip_without('sqlite3')
122 @dec.skip_without('sqlite3')
123 def doctest_hist_op():
123 def doctest_hist_op():
124 """Test %hist -op
124 """Test %hist -op
125
125
126 In [1]: class b(float):
126 In [1]: class b(float):
127 ...: pass
127 ...: pass
128 ...:
128 ...:
129
129
130 In [2]: class s(object):
130 In [2]: class s(object):
131 ...: def __str__(self):
131 ...: def __str__(self):
132 ...: return 's'
132 ...: return 's'
133 ...:
133 ...:
134
134
135 In [3]:
135 In [3]:
136
136
137 In [4]: class r(b):
137 In [4]: class r(b):
138 ...: def __repr__(self):
138 ...: def __repr__(self):
139 ...: return 'r'
139 ...: return 'r'
140 ...:
140 ...:
141
141
142 In [5]: class sr(s,r): pass
142 In [5]: class sr(s,r): pass
143 ...:
143 ...:
144
144
145 In [6]:
145 In [6]:
146
146
147 In [7]: bb=b()
147 In [7]: bb=b()
148
148
149 In [8]: ss=s()
149 In [8]: ss=s()
150
150
151 In [9]: rr=r()
151 In [9]: rr=r()
152
152
153 In [10]: ssrr=sr()
153 In [10]: ssrr=sr()
154
154
155 In [11]: 4.5
155 In [11]: 4.5
156 Out[11]: 4.5
156 Out[11]: 4.5
157
157
158 In [12]: str(ss)
158 In [12]: str(ss)
159 Out[12]: 's'
159 Out[12]: 's'
160
160
161 In [13]:
161 In [13]:
162
162
163 In [14]: %hist -op
163 In [14]: %hist -op
164 >>> class b:
164 >>> class b:
165 ... pass
165 ... pass
166 ...
166 ...
167 >>> class s(b):
167 >>> class s(b):
168 ... def __str__(self):
168 ... def __str__(self):
169 ... return 's'
169 ... return 's'
170 ...
170 ...
171 >>>
171 >>>
172 >>> class r(b):
172 >>> class r(b):
173 ... def __repr__(self):
173 ... def __repr__(self):
174 ... return 'r'
174 ... return 'r'
175 ...
175 ...
176 >>> class sr(s,r): pass
176 >>> class sr(s,r): pass
177 >>>
177 >>>
178 >>> bb=b()
178 >>> bb=b()
179 >>> ss=s()
179 >>> ss=s()
180 >>> rr=r()
180 >>> rr=r()
181 >>> ssrr=sr()
181 >>> ssrr=sr()
182 >>> 4.5
182 >>> 4.5
183 4.5
183 4.5
184 >>> str(ss)
184 >>> str(ss)
185 's'
185 's'
186 >>>
186 >>>
187 """
187 """
188
188
189
189
190 @dec.skip_without('sqlite3')
190 @dec.skip_without('sqlite3')
191 def test_macro():
191 def test_macro():
192 ip = get_ipython()
192 ip = get_ipython()
193 ip.history_manager.reset() # Clear any existing history.
193 ip.history_manager.reset() # Clear any existing history.
194 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
194 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
195 for i, cmd in enumerate(cmds, start=1):
195 for i, cmd in enumerate(cmds, start=1):
196 ip.history_manager.store_inputs(i, cmd)
196 ip.history_manager.store_inputs(i, cmd)
197 ip.magic("macro test 1-3")
197 ip.magic("macro test 1-3")
198 nt.assert_equal(ip.user_ns["test"].value, "\n".join(cmds)+"\n")
198 nt.assert_equal(ip.user_ns["test"].value, "\n".join(cmds)+"\n")
199
199
200 # List macros.
200 # List macros.
201 assert "test" in ip.magic("macro")
201 assert "test" in ip.magic("macro")
202
202
203
203
204 @dec.skip_without('sqlite3')
204 @dec.skip_without('sqlite3')
205 def test_macro_run():
205 def test_macro_run():
206 """Test that we can run a multi-line macro successfully."""
206 """Test that we can run a multi-line macro successfully."""
207 ip = get_ipython()
207 ip = get_ipython()
208 ip.history_manager.reset()
208 ip.history_manager.reset()
209 cmds = ["a=10", "a+=1", py3compat.doctest_refactor_print("print a"),
209 cmds = ["a=10", "a+=1", py3compat.doctest_refactor_print("print a"),
210 "%macro test 2-3"]
210 "%macro test 2-3"]
211 for cmd in cmds:
211 for cmd in cmds:
212 ip.run_cell(cmd, store_history=True)
212 ip.run_cell(cmd, store_history=True)
213 nt.assert_equal(ip.user_ns["test"].value,
213 nt.assert_equal(ip.user_ns["test"].value,
214 py3compat.doctest_refactor_print("a+=1\nprint a\n"))
214 py3compat.doctest_refactor_print("a+=1\nprint a\n"))
215 with tt.AssertPrints("12"):
215 with tt.AssertPrints("12"):
216 ip.run_cell("test")
216 ip.run_cell("test")
217 with tt.AssertPrints("13"):
217 with tt.AssertPrints("13"):
218 ip.run_cell("test")
218 ip.run_cell("test")
219
219
220
220
221 @dec.skipif_not_numpy
221 @dec.skipif_not_numpy
222 def test_numpy_reset_array_undec():
222 def test_numpy_reset_array_undec():
223 "Test '%reset array' functionality"
223 "Test '%reset array' functionality"
224 _ip.ex('import numpy as np')
224 _ip.ex('import numpy as np')
225 _ip.ex('a = np.empty(2)')
225 _ip.ex('a = np.empty(2)')
226 yield (nt.assert_true, 'a' in _ip.user_ns)
226 yield (nt.assert_true, 'a' in _ip.user_ns)
227 _ip.magic('reset -f array')
227 _ip.magic('reset -f array')
228 yield (nt.assert_false, 'a' in _ip.user_ns)
228 yield (nt.assert_false, 'a' in _ip.user_ns)
229
229
230 def test_reset_out():
230 def test_reset_out():
231 "Test '%reset out' magic"
231 "Test '%reset out' magic"
232 _ip.run_cell("parrot = 'dead'", store_history=True)
232 _ip.run_cell("parrot = 'dead'", store_history=True)
233 # test '%reset -f out', make an Out prompt
233 # test '%reset -f out', make an Out prompt
234 _ip.run_cell("parrot", store_history=True)
234 _ip.run_cell("parrot", store_history=True)
235 nt.assert_true('dead' in [_ip.user_ns[x] for x in '_','__','___'])
235 nt.assert_true('dead' in [_ip.user_ns[x] for x in '_','__','___'])
236 _ip.magic('reset -f out')
236 _ip.magic('reset -f out')
237 nt.assert_false('dead' in [_ip.user_ns[x] for x in '_','__','___'])
237 nt.assert_false('dead' in [_ip.user_ns[x] for x in '_','__','___'])
238 nt.assert_true(len(_ip.user_ns['Out']) == 0)
238 nt.assert_true(len(_ip.user_ns['Out']) == 0)
239
239
240 def test_reset_in():
240 def test_reset_in():
241 "Test '%reset in' magic"
241 "Test '%reset in' magic"
242 # test '%reset -f in'
242 # test '%reset -f in'
243 _ip.run_cell("parrot", store_history=True)
243 _ip.run_cell("parrot", store_history=True)
244 nt.assert_true('parrot' in [_ip.user_ns[x] for x in '_i','_ii','_iii'])
244 nt.assert_true('parrot' in [_ip.user_ns[x] for x in '_i','_ii','_iii'])
245 _ip.magic('%reset -f in')
245 _ip.magic('%reset -f in')
246 nt.assert_false('parrot' in [_ip.user_ns[x] for x in '_i','_ii','_iii'])
246 nt.assert_false('parrot' in [_ip.user_ns[x] for x in '_i','_ii','_iii'])
247 nt.assert_true(len(set(_ip.user_ns['In'])) == 1)
247 nt.assert_true(len(set(_ip.user_ns['In'])) == 1)
248
248
249 def test_reset_dhist():
249 def test_reset_dhist():
250 "Test '%reset dhist' magic"
250 "Test '%reset dhist' magic"
251 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
251 _ip.run_cell("tmp = [d for d in _dh]") # copy before clearing
252 _ip.magic('cd ' + os.path.dirname(nt.__file__))
252 _ip.magic('cd ' + os.path.dirname(nt.__file__))
253 _ip.magic('cd -')
253 _ip.magic('cd -')
254 nt.assert_true(len(_ip.user_ns['_dh']) > 0)
254 nt.assert_true(len(_ip.user_ns['_dh']) > 0)
255 _ip.magic('reset -f dhist')
255 _ip.magic('reset -f dhist')
256 nt.assert_true(len(_ip.user_ns['_dh']) == 0)
256 nt.assert_true(len(_ip.user_ns['_dh']) == 0)
257 _ip.run_cell("_dh = [d for d in tmp]") #restore
257 _ip.run_cell("_dh = [d for d in tmp]") #restore
258
258
259 def test_reset_in_length():
259 def test_reset_in_length():
260 "Test that '%reset in' preserves In[] length"
260 "Test that '%reset in' preserves In[] length"
261 _ip.run_cell("print 'foo'")
261 _ip.run_cell("print 'foo'")
262 _ip.run_cell("reset -f in")
262 _ip.run_cell("reset -f in")
263 nt.assert_true(len(_ip.user_ns['In']) == _ip.displayhook.prompt_count+1)
263 nt.assert_true(len(_ip.user_ns['In']) == _ip.displayhook.prompt_count+1)
264
264
265 def test_time():
265 def test_time():
266 _ip.magic('time None')
266 _ip.magic('time None')
267
267
268 def test_tb_syntaxerror():
268 def test_tb_syntaxerror():
269 """test %tb after a SyntaxError"""
269 """test %tb after a SyntaxError"""
270 ip = get_ipython()
270 ip = get_ipython()
271 ip.run_cell("for")
271 ip.run_cell("for")
272
272
273 # trap and validate stdout
273 # trap and validate stdout
274 save_stdout = sys.stdout
274 save_stdout = sys.stdout
275 try:
275 try:
276 sys.stdout = StringIO()
276 sys.stdout = StringIO()
277 ip.run_cell("%tb")
277 ip.run_cell("%tb")
278 out = sys.stdout.getvalue()
278 out = sys.stdout.getvalue()
279 finally:
279 finally:
280 sys.stdout = save_stdout
280 sys.stdout = save_stdout
281 # trim output, and only check the last line
281 # trim output, and only check the last line
282 last_line = out.rstrip().splitlines()[-1].strip()
282 last_line = out.rstrip().splitlines()[-1].strip()
283 nt.assert_equals(last_line, "SyntaxError: invalid syntax")
283 nt.assert_equals(last_line, "SyntaxError: invalid syntax")
284
284
285
285
286 @py3compat.doctest_refactor_print
286 @py3compat.doctest_refactor_print
287 def doctest_time():
287 def doctest_time():
288 """
288 """
289 In [10]: %time None
289 In [10]: %time None
290 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
290 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
291 Wall time: 0.00 s
291 Wall time: 0.00 s
292
292
293 In [11]: def f(kmjy):
293 In [11]: def f(kmjy):
294 ....: %time print 2*kmjy
294 ....: %time print 2*kmjy
295
295
296 In [12]: f(3)
296 In [12]: f(3)
297 6
297 6
298 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
298 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
299 Wall time: 0.00 s
299 Wall time: 0.00 s
300 """
300 """
301
301
302
302
303 def test_doctest_mode():
303 def test_doctest_mode():
304 "Toggle doctest_mode twice, it should be a no-op and run without error"
304 "Toggle doctest_mode twice, it should be a no-op and run without error"
305 _ip.magic('doctest_mode')
305 _ip.magic('doctest_mode')
306 _ip.magic('doctest_mode')
306 _ip.magic('doctest_mode')
307
307
308
308
309 def test_parse_options():
309 def test_parse_options():
310 """Tests for basic options parsing in magics."""
310 """Tests for basic options parsing in magics."""
311 # These are only the most minimal of tests, more should be added later. At
311 # These are only the most minimal of tests, more should be added later. At
312 # the very least we check that basic text/unicode calls work OK.
312 # the very least we check that basic text/unicode calls work OK.
313 m = DummyMagics(_ip)
313 m = DummyMagics(_ip)
314 nt.assert_equal(m.parse_options('foo', '')[1], 'foo')
314 nt.assert_equal(m.parse_options('foo', '')[1], 'foo')
315 nt.assert_equal(m.parse_options(u'foo', '')[1], u'foo')
315 nt.assert_equal(m.parse_options(u'foo', '')[1], u'foo')
316
316
317
317
318 def test_dirops():
318 def test_dirops():
319 """Test various directory handling operations."""
319 """Test various directory handling operations."""
320 # curpath = lambda :os.path.splitdrive(os.getcwdu())[1].replace('\\','/')
320 # curpath = lambda :os.path.splitdrive(os.getcwdu())[1].replace('\\','/')
321 curpath = os.getcwdu
321 curpath = os.getcwdu
322 startdir = os.getcwdu()
322 startdir = os.getcwdu()
323 ipdir = os.path.realpath(_ip.ipython_dir)
323 ipdir = os.path.realpath(_ip.ipython_dir)
324 try:
324 try:
325 _ip.magic('cd "%s"' % ipdir)
325 _ip.magic('cd "%s"' % ipdir)
326 nt.assert_equal(curpath(), ipdir)
326 nt.assert_equal(curpath(), ipdir)
327 _ip.magic('cd -')
327 _ip.magic('cd -')
328 nt.assert_equal(curpath(), startdir)
328 nt.assert_equal(curpath(), startdir)
329 _ip.magic('pushd "%s"' % ipdir)
329 _ip.magic('pushd "%s"' % ipdir)
330 nt.assert_equal(curpath(), ipdir)
330 nt.assert_equal(curpath(), ipdir)
331 _ip.magic('popd')
331 _ip.magic('popd')
332 nt.assert_equal(curpath(), startdir)
332 nt.assert_equal(curpath(), startdir)
333 finally:
333 finally:
334 os.chdir(startdir)
334 os.chdir(startdir)
335
335
336
336
337 def test_xmode():
337 def test_xmode():
338 # Calling xmode three times should be a no-op
338 # Calling xmode three times should be a no-op
339 xmode = _ip.InteractiveTB.mode
339 xmode = _ip.InteractiveTB.mode
340 for i in range(3):
340 for i in range(3):
341 _ip.magic("xmode")
341 _ip.magic("xmode")
342 nt.assert_equal(_ip.InteractiveTB.mode, xmode)
342 nt.assert_equal(_ip.InteractiveTB.mode, xmode)
343
343
344 def test_reset_hard():
344 def test_reset_hard():
345 monitor = []
345 monitor = []
346 class A(object):
346 class A(object):
347 def __del__(self):
347 def __del__(self):
348 monitor.append(1)
348 monitor.append(1)
349 def __repr__(self):
349 def __repr__(self):
350 return "<A instance>"
350 return "<A instance>"
351
351
352 _ip.user_ns["a"] = A()
352 _ip.user_ns["a"] = A()
353 _ip.run_cell("a")
353 _ip.run_cell("a")
354
354
355 nt.assert_equal(monitor, [])
355 nt.assert_equal(monitor, [])
356 _ip.magic("reset -f")
356 _ip.magic("reset -f")
357 nt.assert_equal(monitor, [1])
357 nt.assert_equal(monitor, [1])
358
358
359 class TestXdel(tt.TempFileMixin):
359 class TestXdel(tt.TempFileMixin):
360 def test_xdel(self):
360 def test_xdel(self):
361 """Test that references from %run are cleared by xdel."""
361 """Test that references from %run are cleared by xdel."""
362 src = ("class A(object):\n"
362 src = ("class A(object):\n"
363 " monitor = []\n"
363 " monitor = []\n"
364 " def __del__(self):\n"
364 " def __del__(self):\n"
365 " self.monitor.append(1)\n"
365 " self.monitor.append(1)\n"
366 "a = A()\n")
366 "a = A()\n")
367 self.mktmp(src)
367 self.mktmp(src)
368 # %run creates some hidden references...
368 # %run creates some hidden references...
369 _ip.magic("run %s" % self.fname)
369 _ip.magic("run %s" % self.fname)
370 # ... as does the displayhook.
370 # ... as does the displayhook.
371 _ip.run_cell("a")
371 _ip.run_cell("a")
372
372
373 monitor = _ip.user_ns["A"].monitor
373 monitor = _ip.user_ns["A"].monitor
374 nt.assert_equal(monitor, [])
374 nt.assert_equal(monitor, [])
375
375
376 _ip.magic("xdel a")
376 _ip.magic("xdel a")
377
377
378 # Check that a's __del__ method has been called.
378 # Check that a's __del__ method has been called.
379 nt.assert_equal(monitor, [1])
379 nt.assert_equal(monitor, [1])
380
380
381 def doctest_who():
381 def doctest_who():
382 """doctest for %who
382 """doctest for %who
383
383
384 In [1]: %reset -f
384 In [1]: %reset -f
385
385
386 In [2]: alpha = 123
386 In [2]: alpha = 123
387
387
388 In [3]: beta = 'beta'
388 In [3]: beta = 'beta'
389
389
390 In [4]: %who int
390 In [4]: %who int
391 alpha
391 alpha
392
392
393 In [5]: %who str
393 In [5]: %who str
394 beta
394 beta
395
395
396 In [6]: %whos
396 In [6]: %whos
397 Variable Type Data/Info
397 Variable Type Data/Info
398 ----------------------------
398 ----------------------------
399 alpha int 123
399 alpha int 123
400 beta str beta
400 beta str beta
401
401
402 In [7]: %who_ls
402 In [7]: %who_ls
403 Out[7]: ['alpha', 'beta']
403 Out[7]: ['alpha', 'beta']
404 """
404 """
405
405
406 def test_whos():
406 def test_whos():
407 """Check that whos is protected against objects where repr() fails."""
407 """Check that whos is protected against objects where repr() fails."""
408 class A(object):
408 class A(object):
409 def __repr__(self):
409 def __repr__(self):
410 raise Exception()
410 raise Exception()
411 _ip.user_ns['a'] = A()
411 _ip.user_ns['a'] = A()
412 _ip.magic("whos")
412 _ip.magic("whos")
413
413
414 @py3compat.u_format
414 @py3compat.u_format
415 def doctest_precision():
415 def doctest_precision():
416 """doctest for %precision
416 """doctest for %precision
417
417
418 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
418 In [1]: f = get_ipython().display_formatter.formatters['text/plain']
419
419
420 In [2]: %precision 5
420 In [2]: %precision 5
421 Out[2]: {u}'%.5f'
421 Out[2]: {u}'%.5f'
422
422
423 In [3]: f.float_format
423 In [3]: f.float_format
424 Out[3]: {u}'%.5f'
424 Out[3]: {u}'%.5f'
425
425
426 In [4]: %precision %e
426 In [4]: %precision %e
427 Out[4]: {u}'%e'
427 Out[4]: {u}'%e'
428
428
429 In [5]: f(3.1415927)
429 In [5]: f(3.1415927)
430 Out[5]: {u}'3.141593e+00'
430 Out[5]: {u}'3.141593e+00'
431 """
431 """
432
432
433 def test_psearch():
433 def test_psearch():
434 with tt.AssertPrints("dict.fromkeys"):
434 with tt.AssertPrints("dict.fromkeys"):
435 _ip.run_cell("dict.fr*?")
435 _ip.run_cell("dict.fr*?")
436
436
437 def test_timeit_shlex():
437 def test_timeit_shlex():
438 """test shlex issues with timeit (#1109)"""
438 """test shlex issues with timeit (#1109)"""
439 _ip.ex("def f(*a,**kw): pass")
439 _ip.ex("def f(*a,**kw): pass")
440 _ip.magic('timeit -n1 "this is a bug".count(" ")')
440 _ip.magic('timeit -n1 "this is a bug".count(" ")')
441 _ip.magic('timeit -r1 -n1 f(" ", 1)')
441 _ip.magic('timeit -r1 -n1 f(" ", 1)')
442 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
442 _ip.magic('timeit -r1 -n1 f(" ", 1, " ", 2, " ")')
443 _ip.magic('timeit -r1 -n1 ("a " + "b")')
443 _ip.magic('timeit -r1 -n1 ("a " + "b")')
444 _ip.magic('timeit -r1 -n1 f("a " + "b")')
444 _ip.magic('timeit -r1 -n1 f("a " + "b")')
445 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
445 _ip.magic('timeit -r1 -n1 f("a " + "b ")')
446
446
447
447
448 def test_timeit_arguments():
448 def test_timeit_arguments():
449 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
449 "Test valid timeit arguments, should not cause SyntaxError (GH #1269)"
450 _ip.magic("timeit ('#')")
450 _ip.magic("timeit ('#')")
451
451
452
452
453 def test_timeit_special_syntax():
453 def test_timeit_special_syntax():
454 "Test %%timeit with IPython special syntax"
454 "Test %%timeit with IPython special syntax"
455 from IPython.core.magic import register_line_magic
455 from IPython.core.magic import register_line_magic
456
456
457 @register_line_magic
457 @register_line_magic
458 def lmagic(line):
458 def lmagic(line):
459 ip = get_ipython()
459 ip = get_ipython()
460 ip.user_ns['lmagic_out'] = line
460 ip.user_ns['lmagic_out'] = line
461
461
462 # line mode test
462 # line mode test
463 _ip.run_line_magic('timeit', '-n1 -r1 %lmagic my line')
463 _ip.run_line_magic('timeit', '-n1 -r1 %lmagic my line')
464 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
464 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line')
465 # cell mode test
465 # cell mode test
466 _ip.run_cell_magic('timeit', '-n1 -r1', '%lmagic my line2')
466 _ip.run_cell_magic('timeit', '-n1 -r1', '%lmagic my line2')
467 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
467 nt.assert_equal(_ip.user_ns['lmagic_out'], 'my line2')
468
468
469
469
470 @dec.skipif(execution.profile is None)
470 @dec.skipif(execution.profile is None)
471 def test_prun_quotes():
471 def test_prun_quotes():
472 "Test that prun does not clobber string escapes (GH #1302)"
472 "Test that prun does not clobber string escapes (GH #1302)"
473 _ip.magic(r"prun -q x = '\t'")
473 _ip.magic(r"prun -q x = '\t'")
474 nt.assert_equal(_ip.user_ns['x'], '\t')
474 nt.assert_equal(_ip.user_ns['x'], '\t')
475
475
476 def test_extension():
476 def test_extension():
477 tmpdir = TemporaryDirectory()
477 tmpdir = TemporaryDirectory()
478 orig_ipython_dir = _ip.ipython_dir
478 orig_ipython_dir = _ip.ipython_dir
479 try:
479 try:
480 _ip.ipython_dir = tmpdir.name
480 _ip.ipython_dir = tmpdir.name
481 nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension")
481 nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension")
482 url = os.path.join(os.path.dirname(__file__), "daft_extension.py")
482 url = os.path.join(os.path.dirname(__file__), "daft_extension.py")
483 _ip.magic("install_ext %s" % url)
483 _ip.magic("install_ext %s" % url)
484 _ip.user_ns.pop('arq', None)
484 _ip.user_ns.pop('arq', None)
485 invalidate_caches() # Clear import caches
485 invalidate_caches() # Clear import caches
486 _ip.magic("load_ext daft_extension")
486 _ip.magic("load_ext daft_extension")
487 tt.assert_equal(_ip.user_ns['arq'], 185)
487 tt.assert_equal(_ip.user_ns['arq'], 185)
488 _ip.magic("unload_ext daft_extension")
488 _ip.magic("unload_ext daft_extension")
489 assert 'arq' not in _ip.user_ns
489 assert 'arq' not in _ip.user_ns
490 finally:
490 finally:
491 _ip.ipython_dir = orig_ipython_dir
491 _ip.ipython_dir = orig_ipython_dir
492 tmpdir.cleanup()
492
493
493 def test_notebook_export_json():
494 def test_notebook_export_json():
494 with TemporaryDirectory() as td:
495 with TemporaryDirectory() as td:
495 outfile = os.path.join(td, "nb.ipynb")
496 outfile = os.path.join(td, "nb.ipynb")
496 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
497 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
497 _ip.magic("notebook -e %s" % outfile)
498 _ip.magic("notebook -e %s" % outfile)
498
499
499 def test_notebook_export_py():
500 def test_notebook_export_py():
500 with TemporaryDirectory() as td:
501 with TemporaryDirectory() as td:
501 outfile = os.path.join(td, "nb.py")
502 outfile = os.path.join(td, "nb.py")
502 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
503 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
503 _ip.magic("notebook -e %s" % outfile)
504 _ip.magic("notebook -e %s" % outfile)
504
505
505 def test_notebook_reformat_py():
506 def test_notebook_reformat_py():
506 with TemporaryDirectory() as td:
507 with TemporaryDirectory() as td:
507 infile = os.path.join(td, "nb.ipynb")
508 infile = os.path.join(td, "nb.ipynb")
508 with io.open(infile, 'w', encoding='utf-8') as f:
509 with io.open(infile, 'w', encoding='utf-8') as f:
509 current.write(nb0, f, 'json')
510 current.write(nb0, f, 'json')
510
511
511 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
512 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
512 _ip.magic("notebook -f py %s" % infile)
513 _ip.magic("notebook -f py %s" % infile)
513
514
514 def test_notebook_reformat_json():
515 def test_notebook_reformat_json():
515 with TemporaryDirectory() as td:
516 with TemporaryDirectory() as td:
516 infile = os.path.join(td, "nb.py")
517 infile = os.path.join(td, "nb.py")
517 with io.open(infile, 'w', encoding='utf-8') as f:
518 with io.open(infile, 'w', encoding='utf-8') as f:
518 current.write(nb0, f, 'py')
519 current.write(nb0, f, 'py')
519
520
520 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
521 _ip.ex(py3compat.u_format(u"u = {u}'hΓ©llo'"))
521 _ip.magic("notebook -f ipynb %s" % infile)
522 _ip.magic("notebook -f ipynb %s" % infile)
522 _ip.magic("notebook -f json %s" % infile)
523 _ip.magic("notebook -f json %s" % infile)
523
524
524 def test_env():
525 def test_env():
525 env = _ip.magic("env")
526 env = _ip.magic("env")
526 assert isinstance(env, dict), type(env)
527 assert isinstance(env, dict), type(env)
527
528
528
529
529 class CellMagicTestCase(TestCase):
530 class CellMagicTestCase(TestCase):
530
531
531 def check_ident(self, magic):
532 def check_ident(self, magic):
532 # Manually called, we get the result
533 # Manually called, we get the result
533 out = _ip.run_cell_magic(magic, 'a', 'b')
534 out = _ip.run_cell_magic(magic, 'a', 'b')
534 nt.assert_equals(out, ('a','b'))
535 nt.assert_equals(out, ('a','b'))
535 # Via run_cell, it goes into the user's namespace via displayhook
536 # Via run_cell, it goes into the user's namespace via displayhook
536 _ip.run_cell('%%' + magic +' c\nd')
537 _ip.run_cell('%%' + magic +' c\nd')
537 nt.assert_equals(_ip.user_ns['_'], ('c','d'))
538 nt.assert_equals(_ip.user_ns['_'], ('c','d'))
538
539
539 def test_cell_magic_func_deco(self):
540 def test_cell_magic_func_deco(self):
540 "Cell magic using simple decorator"
541 "Cell magic using simple decorator"
541 @register_cell_magic
542 @register_cell_magic
542 def cellm(line, cell):
543 def cellm(line, cell):
543 return line, cell
544 return line, cell
544
545
545 self.check_ident('cellm')
546 self.check_ident('cellm')
546
547
547 def test_cell_magic_reg(self):
548 def test_cell_magic_reg(self):
548 "Cell magic manually registered"
549 "Cell magic manually registered"
549 def cellm(line, cell):
550 def cellm(line, cell):
550 return line, cell
551 return line, cell
551
552
552 _ip.register_magic_function(cellm, 'cell', 'cellm2')
553 _ip.register_magic_function(cellm, 'cell', 'cellm2')
553 self.check_ident('cellm2')
554 self.check_ident('cellm2')
554
555
555 def test_cell_magic_class(self):
556 def test_cell_magic_class(self):
556 "Cell magics declared via a class"
557 "Cell magics declared via a class"
557 @magics_class
558 @magics_class
558 class MyMagics(Magics):
559 class MyMagics(Magics):
559
560
560 @cell_magic
561 @cell_magic
561 def cellm3(self, line, cell):
562 def cellm3(self, line, cell):
562 return line, cell
563 return line, cell
563
564
564 _ip.register_magics(MyMagics)
565 _ip.register_magics(MyMagics)
565 self.check_ident('cellm3')
566 self.check_ident('cellm3')
566
567
567 def test_cell_magic_class2(self):
568 def test_cell_magic_class2(self):
568 "Cell magics declared via a class, #2"
569 "Cell magics declared via a class, #2"
569 @magics_class
570 @magics_class
570 class MyMagics2(Magics):
571 class MyMagics2(Magics):
571
572
572 @cell_magic('cellm4')
573 @cell_magic('cellm4')
573 def cellm33(self, line, cell):
574 def cellm33(self, line, cell):
574 return line, cell
575 return line, cell
575
576
576 _ip.register_magics(MyMagics2)
577 _ip.register_magics(MyMagics2)
577 self.check_ident('cellm4')
578 self.check_ident('cellm4')
578 # Check that nothing is registered as 'cellm33'
579 # Check that nothing is registered as 'cellm33'
579 c33 = _ip.find_cell_magic('cellm33')
580 c33 = _ip.find_cell_magic('cellm33')
580 nt.assert_equals(c33, None)
581 nt.assert_equals(c33, None)
581
582
582 def test_file():
583 def test_file():
583 """Basic %%file"""
584 """Basic %%file"""
584 ip = get_ipython()
585 ip = get_ipython()
585 with TemporaryDirectory() as td:
586 with TemporaryDirectory() as td:
586 fname = os.path.join(td, 'file1')
587 fname = os.path.join(td, 'file1')
587 ip.run_cell_magic("file", fname, u'\n'.join([
588 ip.run_cell_magic("file", fname, u'\n'.join([
588 'line1',
589 'line1',
589 'line2',
590 'line2',
590 ]))
591 ]))
591 with open(fname) as f:
592 with open(fname) as f:
592 s = f.read()
593 s = f.read()
593 nt.assert_in('line1\n', s)
594 nt.assert_in('line1\n', s)
594 nt.assert_in('line2', s)
595 nt.assert_in('line2', s)
595
596
596 def test_file_unicode():
597 def test_file_unicode():
597 """%%file with unicode cell"""
598 """%%file with unicode cell"""
598 ip = get_ipython()
599 ip = get_ipython()
599 with TemporaryDirectory() as td:
600 with TemporaryDirectory() as td:
600 fname = os.path.join(td, 'file1')
601 fname = os.path.join(td, 'file1')
601 ip.run_cell_magic("file", fname, u'\n'.join([
602 ip.run_cell_magic("file", fname, u'\n'.join([
602 u'linΓ©1',
603 u'linΓ©1',
603 u'linΓ©2',
604 u'linΓ©2',
604 ]))
605 ]))
605 with io.open(fname, encoding='utf-8') as f:
606 with io.open(fname, encoding='utf-8') as f:
606 s = f.read()
607 s = f.read()
607 nt.assert_in(u'linΓ©1\n', s)
608 nt.assert_in(u'linΓ©1\n', s)
608 nt.assert_in(u'linΓ©2', s)
609 nt.assert_in(u'linΓ©2', s)
609
610
610 def test_file_amend():
611 def test_file_amend():
611 """%%file -a amends files"""
612 """%%file -a amends files"""
612 ip = get_ipython()
613 ip = get_ipython()
613 with TemporaryDirectory() as td:
614 with TemporaryDirectory() as td:
614 fname = os.path.join(td, 'file2')
615 fname = os.path.join(td, 'file2')
615 ip.run_cell_magic("file", fname, u'\n'.join([
616 ip.run_cell_magic("file", fname, u'\n'.join([
616 'line1',
617 'line1',
617 'line2',
618 'line2',
618 ]))
619 ]))
619 ip.run_cell_magic("file", "-a %s" % fname, u'\n'.join([
620 ip.run_cell_magic("file", "-a %s" % fname, u'\n'.join([
620 'line3',
621 'line3',
621 'line4',
622 'line4',
622 ]))
623 ]))
623 with open(fname) as f:
624 with open(fname) as f:
624 s = f.read()
625 s = f.read()
625 nt.assert_in('line1\n', s)
626 nt.assert_in('line1\n', s)
626 nt.assert_in('line3\n', s)
627 nt.assert_in('line3\n', s)
627
628
628
629
629 def test_script_config():
630 def test_script_config():
630 ip = get_ipython()
631 ip = get_ipython()
631 ip.config.ScriptMagics.script_magics = ['whoda']
632 ip.config.ScriptMagics.script_magics = ['whoda']
632 sm = script.ScriptMagics(shell=ip)
633 sm = script.ScriptMagics(shell=ip)
633 nt.assert_in('whoda', sm.magics['cell'])
634 nt.assert_in('whoda', sm.magics['cell'])
634
635
635 @dec.skip_win32
636 @dec.skip_win32
636 def test_script_out():
637 def test_script_out():
637 ip = get_ipython()
638 ip = get_ipython()
638 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
639 ip.run_cell_magic("script", "--out output sh", "echo 'hi'")
639 nt.assert_equals(ip.user_ns['output'], 'hi\n')
640 nt.assert_equals(ip.user_ns['output'], 'hi\n')
640
641
641 @dec.skip_win32
642 @dec.skip_win32
642 def test_script_err():
643 def test_script_err():
643 ip = get_ipython()
644 ip = get_ipython()
644 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
645 ip.run_cell_magic("script", "--err error sh", "echo 'hello' >&2")
645 nt.assert_equals(ip.user_ns['error'], 'hello\n')
646 nt.assert_equals(ip.user_ns['error'], 'hello\n')
646
647
647 @dec.skip_win32
648 @dec.skip_win32
648 def test_script_out_err():
649 def test_script_out_err():
649 ip = get_ipython()
650 ip = get_ipython()
650 ip.run_cell_magic("script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2")
651 ip.run_cell_magic("script", "--out output --err error sh", "echo 'hi'\necho 'hello' >&2")
651 nt.assert_equals(ip.user_ns['output'], 'hi\n')
652 nt.assert_equals(ip.user_ns['output'], 'hi\n')
652 nt.assert_equals(ip.user_ns['error'], 'hello\n')
653 nt.assert_equals(ip.user_ns['error'], 'hello\n')
653
654
654 @dec.skip_win32
655 @dec.skip_win32
655 def test_script_bg_out():
656 def test_script_bg_out():
656 ip = get_ipython()
657 ip = get_ipython()
657 ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
658 ip.run_cell_magic("script", "--bg --out output sh", "echo 'hi'")
658 nt.assert_equals(ip.user_ns['output'].read(), b'hi\n')
659 nt.assert_equals(ip.user_ns['output'].read(), b'hi\n')
659
660
660 @dec.skip_win32
661 @dec.skip_win32
661 def test_script_bg_err():
662 def test_script_bg_err():
662 ip = get_ipython()
663 ip = get_ipython()
663 ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2")
664 ip.run_cell_magic("script", "--bg --err error sh", "echo 'hello' >&2")
664 nt.assert_equals(ip.user_ns['error'].read(), b'hello\n')
665 nt.assert_equals(ip.user_ns['error'].read(), b'hello\n')
665
666
666 @dec.skip_win32
667 @dec.skip_win32
667 def test_script_bg_out_err():
668 def test_script_bg_out_err():
668 ip = get_ipython()
669 ip = get_ipython()
669 ip.run_cell_magic("script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2")
670 ip.run_cell_magic("script", "--bg --out output --err error sh", "echo 'hi'\necho 'hello' >&2")
670 nt.assert_equals(ip.user_ns['output'].read(), b'hi\n')
671 nt.assert_equals(ip.user_ns['output'].read(), b'hi\n')
671 nt.assert_equals(ip.user_ns['error'].read(), b'hello\n')
672 nt.assert_equals(ip.user_ns['error'].read(), b'hello\n')
672
673
673 def test_script_defaults():
674 def test_script_defaults():
674 ip = get_ipython()
675 ip = get_ipython()
675 for cmd in ['sh', 'bash', 'perl', 'ruby']:
676 for cmd in ['sh', 'bash', 'perl', 'ruby']:
676 try:
677 try:
677 find_cmd(cmd)
678 find_cmd(cmd)
678 except Exception:
679 except Exception:
679 pass
680 pass
680 else:
681 else:
681 nt.assert_in(cmd, ip.magics_manager.magics['cell'])
682 nt.assert_in(cmd, ip.magics_manager.magics['cell'])
682
683
683
684
684 @magics_class
685 @magics_class
685 class FooFoo(Magics):
686 class FooFoo(Magics):
686 """class with both %foo and %%foo magics"""
687 """class with both %foo and %%foo magics"""
687 @line_magic('foo')
688 @line_magic('foo')
688 def line_foo(self, line):
689 def line_foo(self, line):
689 "I am line foo"
690 "I am line foo"
690 pass
691 pass
691
692
692 @cell_magic("foo")
693 @cell_magic("foo")
693 def cell_foo(self, line, cell):
694 def cell_foo(self, line, cell):
694 "I am cell foo, not line foo"
695 "I am cell foo, not line foo"
695 pass
696 pass
696
697
697 def test_line_cell_info():
698 def test_line_cell_info():
698 """%%foo and %foo magics are distinguishable to inspect"""
699 """%%foo and %foo magics are distinguishable to inspect"""
699 ip = get_ipython()
700 ip = get_ipython()
700 ip.magics_manager.register(FooFoo)
701 ip.magics_manager.register(FooFoo)
701 oinfo = ip.object_inspect('foo')
702 oinfo = ip.object_inspect('foo')
702 nt.assert_true(oinfo['found'])
703 nt.assert_true(oinfo['found'])
703 nt.assert_true(oinfo['ismagic'])
704 nt.assert_true(oinfo['ismagic'])
704
705
705 oinfo = ip.object_inspect('%%foo')
706 oinfo = ip.object_inspect('%%foo')
706 nt.assert_true(oinfo['found'])
707 nt.assert_true(oinfo['found'])
707 nt.assert_true(oinfo['ismagic'])
708 nt.assert_true(oinfo['ismagic'])
708 nt.assert_equals(oinfo['docstring'], FooFoo.cell_foo.__doc__)
709 nt.assert_equals(oinfo['docstring'], FooFoo.cell_foo.__doc__)
709
710
710 oinfo = ip.object_inspect('%foo')
711 oinfo = ip.object_inspect('%foo')
711 nt.assert_true(oinfo['found'])
712 nt.assert_true(oinfo['found'])
712 nt.assert_true(oinfo['ismagic'])
713 nt.assert_true(oinfo['ismagic'])
713 nt.assert_equals(oinfo['docstring'], FooFoo.line_foo.__doc__)
714 nt.assert_equals(oinfo['docstring'], FooFoo.line_foo.__doc__)
714
715
715 def test_multiple_magics():
716 def test_multiple_magics():
716 ip = get_ipython()
717 ip = get_ipython()
717 foo1 = FooFoo(ip)
718 foo1 = FooFoo(ip)
718 foo2 = FooFoo(ip)
719 foo2 = FooFoo(ip)
719 mm = ip.magics_manager
720 mm = ip.magics_manager
720 mm.register(foo1)
721 mm.register(foo1)
721 nt.assert_true(mm.magics['line']['foo'].im_self is foo1)
722 nt.assert_true(mm.magics['line']['foo'].im_self is foo1)
722 mm.register(foo2)
723 mm.register(foo2)
723 nt.assert_true(mm.magics['line']['foo'].im_self is foo2)
724 nt.assert_true(mm.magics['line']['foo'].im_self is foo2)
724
725
725 def test_alias_magic():
726 def test_alias_magic():
726 """Test %alias_magic."""
727 """Test %alias_magic."""
727 ip = get_ipython()
728 ip = get_ipython()
728 mm = ip.magics_manager
729 mm = ip.magics_manager
729
730
730 # Basic operation: both cell and line magics are created, if possible.
731 # Basic operation: both cell and line magics are created, if possible.
731 ip.run_line_magic('alias_magic', 'timeit_alias timeit')
732 ip.run_line_magic('alias_magic', 'timeit_alias timeit')
732 nt.assert_true('timeit_alias' in mm.magics['line'])
733 nt.assert_true('timeit_alias' in mm.magics['line'])
733 nt.assert_true('timeit_alias' in mm.magics['cell'])
734 nt.assert_true('timeit_alias' in mm.magics['cell'])
734
735
735 # --cell is specified, line magic not created.
736 # --cell is specified, line magic not created.
736 ip.run_line_magic('alias_magic', '--cell timeit_cell_alias timeit')
737 ip.run_line_magic('alias_magic', '--cell timeit_cell_alias timeit')
737 nt.assert_false('timeit_cell_alias' in mm.magics['line'])
738 nt.assert_false('timeit_cell_alias' in mm.magics['line'])
738 nt.assert_true('timeit_cell_alias' in mm.magics['cell'])
739 nt.assert_true('timeit_cell_alias' in mm.magics['cell'])
739
740
740 # Test that line alias is created successfully.
741 # Test that line alias is created successfully.
741 ip.run_line_magic('alias_magic', '--line env_alias env')
742 ip.run_line_magic('alias_magic', '--line env_alias env')
742 nt.assert_equal(ip.run_line_magic('env', ''),
743 nt.assert_equal(ip.run_line_magic('env', ''),
743 ip.run_line_magic('env_alias', ''))
744 ip.run_line_magic('env_alias', ''))
@@ -1,364 +1,366
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2
2
3 """ PickleShare - a small 'shelve' like datastore with concurrency support
3 """ PickleShare - a small 'shelve' like datastore with concurrency support
4
4
5 Like shelve, a PickleShareDB object acts like a normal dictionary. Unlike
5 Like shelve, a PickleShareDB object acts like a normal dictionary. Unlike
6 shelve, many processes can access the database simultaneously. Changing a
6 shelve, many processes can access the database simultaneously. Changing a
7 value in database is immediately visible to other processes accessing the
7 value in database is immediately visible to other processes accessing the
8 same database.
8 same database.
9
9
10 Concurrency is possible because the values are stored in separate files. Hence
10 Concurrency is possible because the values are stored in separate files. Hence
11 the "database" is a directory where *all* files are governed by PickleShare.
11 the "database" is a directory where *all* files are governed by PickleShare.
12
12
13 Example usage::
13 Example usage::
14
14
15 from pickleshare import *
15 from pickleshare import *
16 db = PickleShareDB('~/testpickleshare')
16 db = PickleShareDB('~/testpickleshare')
17 db.clear()
17 db.clear()
18 print "Should be empty:",db.items()
18 print "Should be empty:",db.items()
19 db['hello'] = 15
19 db['hello'] = 15
20 db['aku ankka'] = [1,2,313]
20 db['aku ankka'] = [1,2,313]
21 db['paths/are/ok/key'] = [1,(5,46)]
21 db['paths/are/ok/key'] = [1,(5,46)]
22 print db.keys()
22 print db.keys()
23 del db['aku ankka']
23 del db['aku ankka']
24
24
25 This module is certainly not ZODB, but can be used for low-load
25 This module is certainly not ZODB, but can be used for low-load
26 (non-mission-critical) situations where tiny code size trumps the
26 (non-mission-critical) situations where tiny code size trumps the
27 advanced features of a "real" object database.
27 advanced features of a "real" object database.
28
28
29 Installation guide: easy_install pickleshare
29 Installation guide: easy_install pickleshare
30
30
31 Author: Ville Vainio <vivainio@gmail.com>
31 Author: Ville Vainio <vivainio@gmail.com>
32 License: MIT open source license.
32 License: MIT open source license.
33
33
34 """
34 """
35
35
36 from IPython.external.path import path as Path
36 from IPython.external.path import path as Path
37 import os,stat,time
37 import os,stat,time
38 import collections
38 import collections
39 import cPickle as pickle
39 import cPickle as pickle
40 import glob
40 import glob
41
41
42 def gethashfile(key):
42 def gethashfile(key):
43 return ("%02x" % abs(hash(key) % 256))[-2:]
43 return ("%02x" % abs(hash(key) % 256))[-2:]
44
44
45 _sentinel = object()
45 _sentinel = object()
46
46
47 class PickleShareDB(collections.MutableMapping):
47 class PickleShareDB(collections.MutableMapping):
48 """ The main 'connection' object for PickleShare database """
48 """ The main 'connection' object for PickleShare database """
49 def __init__(self,root):
49 def __init__(self,root):
50 """ Return a db object that will manage the specied directory"""
50 """ Return a db object that will manage the specied directory"""
51 self.root = Path(root).expanduser().abspath()
51 self.root = Path(root).expanduser().abspath()
52 if not self.root.isdir():
52 if not self.root.isdir():
53 self.root.makedirs()
53 self.root.makedirs()
54 # cache has { 'key' : (obj, orig_mod_time) }
54 # cache has { 'key' : (obj, orig_mod_time) }
55 self.cache = {}
55 self.cache = {}
56
56
57
57
58 def __getitem__(self,key):
58 def __getitem__(self,key):
59 """ db['key'] reading """
59 """ db['key'] reading """
60 fil = self.root / key
60 fil = self.root / key
61 try:
61 try:
62 mtime = (fil.stat()[stat.ST_MTIME])
62 mtime = (fil.stat()[stat.ST_MTIME])
63 except OSError:
63 except OSError:
64 raise KeyError(key)
64 raise KeyError(key)
65
65
66 if fil in self.cache and mtime == self.cache[fil][1]:
66 if fil in self.cache and mtime == self.cache[fil][1]:
67 return self.cache[fil][0]
67 return self.cache[fil][0]
68 try:
68 try:
69 # The cached item has expired, need to read
69 # The cached item has expired, need to read
70 obj = pickle.loads(fil.open("rb").read())
70 with fil.open("rb") as f:
71 obj = pickle.loads(f.read())
71 except:
72 except:
72 raise KeyError(key)
73 raise KeyError(key)
73
74
74 self.cache[fil] = (obj,mtime)
75 self.cache[fil] = (obj,mtime)
75 return obj
76 return obj
76
77
77 def __setitem__(self,key,value):
78 def __setitem__(self,key,value):
78 """ db['key'] = 5 """
79 """ db['key'] = 5 """
79 fil = self.root / key
80 fil = self.root / key
80 parent = fil.parent
81 parent = fil.parent
81 if parent and not parent.isdir():
82 if parent and not parent.isdir():
82 parent.makedirs()
83 parent.makedirs()
83 # We specify protocol 2, so that we can mostly go between Python 2
84 # We specify protocol 2, so that we can mostly go between Python 2
84 # and Python 3. We can upgrade to protocol 3 when Python 2 is obsolete.
85 # and Python 3. We can upgrade to protocol 3 when Python 2 is obsolete.
85 pickled = pickle.dump(value,fil.open('wb'), protocol=2)
86 with fil.open('wb') as f:
87 pickled = pickle.dump(value, f, protocol=2)
86 try:
88 try:
87 self.cache[fil] = (value,fil.mtime)
89 self.cache[fil] = (value,fil.mtime)
88 except OSError as e:
90 except OSError as e:
89 if e.errno != 2:
91 if e.errno != 2:
90 raise
92 raise
91
93
92 def hset(self, hashroot, key, value):
94 def hset(self, hashroot, key, value):
93 """ hashed set """
95 """ hashed set """
94 hroot = self.root / hashroot
96 hroot = self.root / hashroot
95 if not hroot.isdir():
97 if not hroot.isdir():
96 hroot.makedirs()
98 hroot.makedirs()
97 hfile = hroot / gethashfile(key)
99 hfile = hroot / gethashfile(key)
98 d = self.get(hfile, {})
100 d = self.get(hfile, {})
99 d.update( {key : value})
101 d.update( {key : value})
100 self[hfile] = d
102 self[hfile] = d
101
103
102
104
103
105
104 def hget(self, hashroot, key, default = _sentinel, fast_only = True):
106 def hget(self, hashroot, key, default = _sentinel, fast_only = True):
105 """ hashed get """
107 """ hashed get """
106 hroot = self.root / hashroot
108 hroot = self.root / hashroot
107 hfile = hroot / gethashfile(key)
109 hfile = hroot / gethashfile(key)
108
110
109 d = self.get(hfile, _sentinel )
111 d = self.get(hfile, _sentinel )
110 #print "got dict",d,"from",hfile
112 #print "got dict",d,"from",hfile
111 if d is _sentinel:
113 if d is _sentinel:
112 if fast_only:
114 if fast_only:
113 if default is _sentinel:
115 if default is _sentinel:
114 raise KeyError(key)
116 raise KeyError(key)
115
117
116 return default
118 return default
117
119
118 # slow mode ok, works even after hcompress()
120 # slow mode ok, works even after hcompress()
119 d = self.hdict(hashroot)
121 d = self.hdict(hashroot)
120
122
121 return d.get(key, default)
123 return d.get(key, default)
122
124
123 def hdict(self, hashroot):
125 def hdict(self, hashroot):
124 """ Get all data contained in hashed category 'hashroot' as dict """
126 """ Get all data contained in hashed category 'hashroot' as dict """
125 hfiles = self.keys(hashroot + "/*")
127 hfiles = self.keys(hashroot + "/*")
126 hfiles.sort()
128 hfiles.sort()
127 last = len(hfiles) and hfiles[-1] or ''
129 last = len(hfiles) and hfiles[-1] or ''
128 if last.endswith('xx'):
130 if last.endswith('xx'):
129 # print "using xx"
131 # print "using xx"
130 hfiles = [last] + hfiles[:-1]
132 hfiles = [last] + hfiles[:-1]
131
133
132 all = {}
134 all = {}
133
135
134 for f in hfiles:
136 for f in hfiles:
135 # print "using",f
137 # print "using",f
136 try:
138 try:
137 all.update(self[f])
139 all.update(self[f])
138 except KeyError:
140 except KeyError:
139 print "Corrupt",f,"deleted - hset is not threadsafe!"
141 print "Corrupt",f,"deleted - hset is not threadsafe!"
140 del self[f]
142 del self[f]
141
143
142 self.uncache(f)
144 self.uncache(f)
143
145
144 return all
146 return all
145
147
146 def hcompress(self, hashroot):
148 def hcompress(self, hashroot):
147 """ Compress category 'hashroot', so hset is fast again
149 """ Compress category 'hashroot', so hset is fast again
148
150
149 hget will fail if fast_only is True for compressed items (that were
151 hget will fail if fast_only is True for compressed items (that were
150 hset before hcompress).
152 hset before hcompress).
151
153
152 """
154 """
153 hfiles = self.keys(hashroot + "/*")
155 hfiles = self.keys(hashroot + "/*")
154 all = {}
156 all = {}
155 for f in hfiles:
157 for f in hfiles:
156 # print "using",f
158 # print "using",f
157 all.update(self[f])
159 all.update(self[f])
158 self.uncache(f)
160 self.uncache(f)
159
161
160 self[hashroot + '/xx'] = all
162 self[hashroot + '/xx'] = all
161 for f in hfiles:
163 for f in hfiles:
162 p = self.root / f
164 p = self.root / f
163 if p.basename() == 'xx':
165 if p.basename() == 'xx':
164 continue
166 continue
165 p.remove()
167 p.remove()
166
168
167
169
168
170
169 def __delitem__(self,key):
171 def __delitem__(self,key):
170 """ del db["key"] """
172 """ del db["key"] """
171 fil = self.root / key
173 fil = self.root / key
172 self.cache.pop(fil,None)
174 self.cache.pop(fil,None)
173 try:
175 try:
174 fil.remove()
176 fil.remove()
175 except OSError:
177 except OSError:
176 # notfound and permission denied are ok - we
178 # notfound and permission denied are ok - we
177 # lost, the other process wins the conflict
179 # lost, the other process wins the conflict
178 pass
180 pass
179
181
180 def _normalized(self, p):
182 def _normalized(self, p):
181 """ Make a key suitable for user's eyes """
183 """ Make a key suitable for user's eyes """
182 return str(self.root.relpathto(p)).replace('\\','/')
184 return str(self.root.relpathto(p)).replace('\\','/')
183
185
184 def keys(self, globpat = None):
186 def keys(self, globpat = None):
185 """ All keys in DB, or all keys matching a glob"""
187 """ All keys in DB, or all keys matching a glob"""
186
188
187 if globpat is None:
189 if globpat is None:
188 files = self.root.walkfiles()
190 files = self.root.walkfiles()
189 else:
191 else:
190 files = [Path(p) for p in glob.glob(self.root/globpat)]
192 files = [Path(p) for p in glob.glob(self.root/globpat)]
191 return [self._normalized(p) for p in files if p.isfile()]
193 return [self._normalized(p) for p in files if p.isfile()]
192
194
193 def __iter__(self):
195 def __iter__(self):
194 return iter(self.keys())
196 return iter(self.keys())
195
197
196 def __len__(self):
198 def __len__(self):
197 return len(self.keys())
199 return len(self.keys())
198
200
199 def uncache(self,*items):
201 def uncache(self,*items):
200 """ Removes all, or specified items from cache
202 """ Removes all, or specified items from cache
201
203
202 Use this after reading a large amount of large objects
204 Use this after reading a large amount of large objects
203 to free up memory, when you won't be needing the objects
205 to free up memory, when you won't be needing the objects
204 for a while.
206 for a while.
205
207
206 """
208 """
207 if not items:
209 if not items:
208 self.cache = {}
210 self.cache = {}
209 for it in items:
211 for it in items:
210 self.cache.pop(it,None)
212 self.cache.pop(it,None)
211
213
212 def waitget(self,key, maxwaittime = 60 ):
214 def waitget(self,key, maxwaittime = 60 ):
213 """ Wait (poll) for a key to get a value
215 """ Wait (poll) for a key to get a value
214
216
215 Will wait for `maxwaittime` seconds before raising a KeyError.
217 Will wait for `maxwaittime` seconds before raising a KeyError.
216 The call exits normally if the `key` field in db gets a value
218 The call exits normally if the `key` field in db gets a value
217 within the timeout period.
219 within the timeout period.
218
220
219 Use this for synchronizing different processes or for ensuring
221 Use this for synchronizing different processes or for ensuring
220 that an unfortunately timed "db['key'] = newvalue" operation
222 that an unfortunately timed "db['key'] = newvalue" operation
221 in another process (which causes all 'get' operation to cause a
223 in another process (which causes all 'get' operation to cause a
222 KeyError for the duration of pickling) won't screw up your program
224 KeyError for the duration of pickling) won't screw up your program
223 logic.
225 logic.
224 """
226 """
225
227
226 wtimes = [0.2] * 3 + [0.5] * 2 + [1]
228 wtimes = [0.2] * 3 + [0.5] * 2 + [1]
227 tries = 0
229 tries = 0
228 waited = 0
230 waited = 0
229 while 1:
231 while 1:
230 try:
232 try:
231 val = self[key]
233 val = self[key]
232 return val
234 return val
233 except KeyError:
235 except KeyError:
234 pass
236 pass
235
237
236 if waited > maxwaittime:
238 if waited > maxwaittime:
237 raise KeyError(key)
239 raise KeyError(key)
238
240
239 time.sleep(wtimes[tries])
241 time.sleep(wtimes[tries])
240 waited+=wtimes[tries]
242 waited+=wtimes[tries]
241 if tries < len(wtimes) -1:
243 if tries < len(wtimes) -1:
242 tries+=1
244 tries+=1
243
245
244 def getlink(self,folder):
246 def getlink(self,folder):
245 """ Get a convenient link for accessing items """
247 """ Get a convenient link for accessing items """
246 return PickleShareLink(self, folder)
248 return PickleShareLink(self, folder)
247
249
248 def __repr__(self):
250 def __repr__(self):
249 return "PickleShareDB('%s')" % self.root
251 return "PickleShareDB('%s')" % self.root
250
252
251
253
252
254
253 class PickleShareLink:
255 class PickleShareLink:
254 """ A shortdand for accessing nested PickleShare data conveniently.
256 """ A shortdand for accessing nested PickleShare data conveniently.
255
257
256 Created through PickleShareDB.getlink(), example::
258 Created through PickleShareDB.getlink(), example::
257
259
258 lnk = db.getlink('myobjects/test')
260 lnk = db.getlink('myobjects/test')
259 lnk.foo = 2
261 lnk.foo = 2
260 lnk.bar = lnk.foo + 5
262 lnk.bar = lnk.foo + 5
261
263
262 """
264 """
263 def __init__(self, db, keydir ):
265 def __init__(self, db, keydir ):
264 self.__dict__.update(locals())
266 self.__dict__.update(locals())
265
267
266 def __getattr__(self,key):
268 def __getattr__(self,key):
267 return self.__dict__['db'][self.__dict__['keydir']+'/' + key]
269 return self.__dict__['db'][self.__dict__['keydir']+'/' + key]
268 def __setattr__(self,key,val):
270 def __setattr__(self,key,val):
269 self.db[self.keydir+'/' + key] = val
271 self.db[self.keydir+'/' + key] = val
270 def __repr__(self):
272 def __repr__(self):
271 db = self.__dict__['db']
273 db = self.__dict__['db']
272 keys = db.keys( self.__dict__['keydir'] +"/*")
274 keys = db.keys( self.__dict__['keydir'] +"/*")
273 return "<PickleShareLink '%s': %s>" % (
275 return "<PickleShareLink '%s': %s>" % (
274 self.__dict__['keydir'],
276 self.__dict__['keydir'],
275 ";".join([Path(k).basename() for k in keys]))
277 ";".join([Path(k).basename() for k in keys]))
276
278
277
279
278 def test():
280 def test():
279 db = PickleShareDB('~/testpickleshare')
281 db = PickleShareDB('~/testpickleshare')
280 db.clear()
282 db.clear()
281 print "Should be empty:",db.items()
283 print "Should be empty:",db.items()
282 db['hello'] = 15
284 db['hello'] = 15
283 db['aku ankka'] = [1,2,313]
285 db['aku ankka'] = [1,2,313]
284 db['paths/nest/ok/keyname'] = [1,(5,46)]
286 db['paths/nest/ok/keyname'] = [1,(5,46)]
285 db.hset('hash', 'aku', 12)
287 db.hset('hash', 'aku', 12)
286 db.hset('hash', 'ankka', 313)
288 db.hset('hash', 'ankka', 313)
287 print "12 =",db.hget('hash','aku')
289 print "12 =",db.hget('hash','aku')
288 print "313 =",db.hget('hash','ankka')
290 print "313 =",db.hget('hash','ankka')
289 print "all hashed",db.hdict('hash')
291 print "all hashed",db.hdict('hash')
290 print db.keys()
292 print db.keys()
291 print db.keys('paths/nest/ok/k*')
293 print db.keys('paths/nest/ok/k*')
292 print dict(db) # snapsot of whole db
294 print dict(db) # snapsot of whole db
293 db.uncache() # frees memory, causes re-reads later
295 db.uncache() # frees memory, causes re-reads later
294
296
295 # shorthand for accessing deeply nested files
297 # shorthand for accessing deeply nested files
296 lnk = db.getlink('myobjects/test')
298 lnk = db.getlink('myobjects/test')
297 lnk.foo = 2
299 lnk.foo = 2
298 lnk.bar = lnk.foo + 5
300 lnk.bar = lnk.foo + 5
299 print lnk.bar # 7
301 print lnk.bar # 7
300
302
301 def stress():
303 def stress():
302 db = PickleShareDB('~/fsdbtest')
304 db = PickleShareDB('~/fsdbtest')
303 import time,sys
305 import time,sys
304 for i in range(1000):
306 for i in range(1000):
305 for j in range(1000):
307 for j in range(1000):
306 if i % 15 == 0 and i < 200:
308 if i % 15 == 0 and i < 200:
307 if str(j) in db:
309 if str(j) in db:
308 del db[str(j)]
310 del db[str(j)]
309 continue
311 continue
310
312
311 if j%33 == 0:
313 if j%33 == 0:
312 time.sleep(0.02)
314 time.sleep(0.02)
313
315
314 db[str(j)] = db.get(str(j), []) + [(i,j,"proc %d" % os.getpid())]
316 db[str(j)] = db.get(str(j), []) + [(i,j,"proc %d" % os.getpid())]
315 db.hset('hash',j, db.hget('hash',j,15) + 1 )
317 db.hset('hash',j, db.hget('hash',j,15) + 1 )
316
318
317 print i,
319 print i,
318 sys.stdout.flush()
320 sys.stdout.flush()
319 if i % 10 == 0:
321 if i % 10 == 0:
320 db.uncache()
322 db.uncache()
321
323
322 def main():
324 def main():
323 import textwrap
325 import textwrap
324 usage = textwrap.dedent("""\
326 usage = textwrap.dedent("""\
325 pickleshare - manage PickleShare databases
327 pickleshare - manage PickleShare databases
326
328
327 Usage:
329 Usage:
328
330
329 pickleshare dump /path/to/db > dump.txt
331 pickleshare dump /path/to/db > dump.txt
330 pickleshare load /path/to/db < dump.txt
332 pickleshare load /path/to/db < dump.txt
331 pickleshare test /path/to/db
333 pickleshare test /path/to/db
332 """)
334 """)
333 DB = PickleShareDB
335 DB = PickleShareDB
334 import sys
336 import sys
335 if len(sys.argv) < 2:
337 if len(sys.argv) < 2:
336 print usage
338 print usage
337 return
339 return
338
340
339 cmd = sys.argv[1]
341 cmd = sys.argv[1]
340 args = sys.argv[2:]
342 args = sys.argv[2:]
341 if cmd == 'dump':
343 if cmd == 'dump':
342 if not args: args= ['.']
344 if not args: args= ['.']
343 db = DB(args[0])
345 db = DB(args[0])
344 import pprint
346 import pprint
345 pprint.pprint(db.items())
347 pprint.pprint(db.items())
346 elif cmd == 'load':
348 elif cmd == 'load':
347 cont = sys.stdin.read()
349 cont = sys.stdin.read()
348 db = DB(args[0])
350 db = DB(args[0])
349 data = eval(cont)
351 data = eval(cont)
350 db.clear()
352 db.clear()
351 for k,v in db.items():
353 for k,v in db.items():
352 db[k] = v
354 db[k] = v
353 elif cmd == 'testwait':
355 elif cmd == 'testwait':
354 db = DB(args[0])
356 db = DB(args[0])
355 db.clear()
357 db.clear()
356 print db.waitget('250')
358 print db.waitget('250')
357 elif cmd == 'test':
359 elif cmd == 'test':
358 test()
360 test()
359 stress()
361 stress()
360
362
361 if __name__== "__main__":
363 if __name__== "__main__":
362 main()
364 main()
363
365
364
366
@@ -1,178 +1,179
1 # coding: utf-8
1 # coding: utf-8
2 """Compatibility tricks for Python 3. Mainly to do with unicode."""
2 """Compatibility tricks for Python 3. Mainly to do with unicode."""
3 import __builtin__
3 import __builtin__
4 import functools
4 import functools
5 import sys
5 import sys
6 import re
6 import re
7 import types
7 import types
8
8
9 from .encoding import DEFAULT_ENCODING
9 from .encoding import DEFAULT_ENCODING
10
10
11 orig_open = open
11 orig_open = open
12
12
13 def no_code(x, encoding=None):
13 def no_code(x, encoding=None):
14 return x
14 return x
15
15
16 def decode(s, encoding=None):
16 def decode(s, encoding=None):
17 encoding = encoding or DEFAULT_ENCODING
17 encoding = encoding or DEFAULT_ENCODING
18 return s.decode(encoding, "replace")
18 return s.decode(encoding, "replace")
19
19
20 def encode(u, encoding=None):
20 def encode(u, encoding=None):
21 encoding = encoding or DEFAULT_ENCODING
21 encoding = encoding or DEFAULT_ENCODING
22 return u.encode(encoding, "replace")
22 return u.encode(encoding, "replace")
23
23
24
24
25 def cast_unicode(s, encoding=None):
25 def cast_unicode(s, encoding=None):
26 if isinstance(s, bytes):
26 if isinstance(s, bytes):
27 return decode(s, encoding)
27 return decode(s, encoding)
28 return s
28 return s
29
29
30 def cast_bytes(s, encoding=None):
30 def cast_bytes(s, encoding=None):
31 if not isinstance(s, bytes):
31 if not isinstance(s, bytes):
32 return encode(s, encoding)
32 return encode(s, encoding)
33 return s
33 return s
34
34
35 def _modify_str_or_docstring(str_change_func):
35 def _modify_str_or_docstring(str_change_func):
36 @functools.wraps(str_change_func)
36 @functools.wraps(str_change_func)
37 def wrapper(func_or_str):
37 def wrapper(func_or_str):
38 if isinstance(func_or_str, basestring):
38 if isinstance(func_or_str, basestring):
39 func = None
39 func = None
40 doc = func_or_str
40 doc = func_or_str
41 else:
41 else:
42 func = func_or_str
42 func = func_or_str
43 doc = func.__doc__
43 doc = func.__doc__
44
44
45 doc = str_change_func(doc)
45 doc = str_change_func(doc)
46
46
47 if func:
47 if func:
48 func.__doc__ = doc
48 func.__doc__ = doc
49 return func
49 return func
50 return doc
50 return doc
51 return wrapper
51 return wrapper
52
52
53 if sys.version_info[0] >= 3:
53 if sys.version_info[0] >= 3:
54 PY3 = True
54 PY3 = True
55
55
56 input = input
56 input = input
57 builtin_mod_name = "builtins"
57 builtin_mod_name = "builtins"
58
58
59 str_to_unicode = no_code
59 str_to_unicode = no_code
60 unicode_to_str = no_code
60 unicode_to_str = no_code
61 str_to_bytes = encode
61 str_to_bytes = encode
62 bytes_to_str = decode
62 bytes_to_str = decode
63 cast_bytes_py2 = no_code
63 cast_bytes_py2 = no_code
64
64
65 def isidentifier(s, dotted=False):
65 def isidentifier(s, dotted=False):
66 if dotted:
66 if dotted:
67 return all(isidentifier(a) for a in s.split("."))
67 return all(isidentifier(a) for a in s.split("."))
68 return s.isidentifier()
68 return s.isidentifier()
69
69
70 open = orig_open
70 open = orig_open
71
71
72 MethodType = types.MethodType
72 MethodType = types.MethodType
73
73
74 def execfile(fname, glob, loc=None):
74 def execfile(fname, glob, loc=None):
75 loc = loc if (loc is not None) else glob
75 loc = loc if (loc is not None) else glob
76 exec compile(open(fname, 'rb').read(), fname, 'exec') in glob, loc
76 with open(fname, 'rb') as f:
77 exec compile(f.read(), fname, 'exec') in glob, loc
77
78
78 # Refactor print statements in doctests.
79 # Refactor print statements in doctests.
79 _print_statement_re = re.compile(r"\bprint (?P<expr>.*)$", re.MULTILINE)
80 _print_statement_re = re.compile(r"\bprint (?P<expr>.*)$", re.MULTILINE)
80 def _print_statement_sub(match):
81 def _print_statement_sub(match):
81 expr = match.groups('expr')
82 expr = match.groups('expr')
82 return "print(%s)" % expr
83 return "print(%s)" % expr
83
84
84 @_modify_str_or_docstring
85 @_modify_str_or_docstring
85 def doctest_refactor_print(doc):
86 def doctest_refactor_print(doc):
86 """Refactor 'print x' statements in a doctest to print(x) style. 2to3
87 """Refactor 'print x' statements in a doctest to print(x) style. 2to3
87 unfortunately doesn't pick up on our doctests.
88 unfortunately doesn't pick up on our doctests.
88
89
89 Can accept a string or a function, so it can be used as a decorator."""
90 Can accept a string or a function, so it can be used as a decorator."""
90 return _print_statement_re.sub(_print_statement_sub, doc)
91 return _print_statement_re.sub(_print_statement_sub, doc)
91
92
92 # Abstract u'abc' syntax:
93 # Abstract u'abc' syntax:
93 @_modify_str_or_docstring
94 @_modify_str_or_docstring
94 def u_format(s):
95 def u_format(s):
95 """"{u}'abc'" --> "'abc'" (Python 3)
96 """"{u}'abc'" --> "'abc'" (Python 3)
96
97
97 Accepts a string or a function, so it can be used as a decorator."""
98 Accepts a string or a function, so it can be used as a decorator."""
98 return s.format(u='')
99 return s.format(u='')
99
100
100 else:
101 else:
101 PY3 = False
102 PY3 = False
102
103
103 input = raw_input
104 input = raw_input
104 builtin_mod_name = "__builtin__"
105 builtin_mod_name = "__builtin__"
105
106
106 str_to_unicode = decode
107 str_to_unicode = decode
107 unicode_to_str = encode
108 unicode_to_str = encode
108 str_to_bytes = no_code
109 str_to_bytes = no_code
109 bytes_to_str = no_code
110 bytes_to_str = no_code
110 cast_bytes_py2 = cast_bytes
111 cast_bytes_py2 = cast_bytes
111
112
112 import re
113 import re
113 _name_re = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*$")
114 _name_re = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*$")
114 def isidentifier(s, dotted=False):
115 def isidentifier(s, dotted=False):
115 if dotted:
116 if dotted:
116 return all(isidentifier(a) for a in s.split("."))
117 return all(isidentifier(a) for a in s.split("."))
117 return bool(_name_re.match(s))
118 return bool(_name_re.match(s))
118
119
119 class open(object):
120 class open(object):
120 """Wrapper providing key part of Python 3 open() interface."""
121 """Wrapper providing key part of Python 3 open() interface."""
121 def __init__(self, fname, mode="r", encoding="utf-8"):
122 def __init__(self, fname, mode="r", encoding="utf-8"):
122 self.f = orig_open(fname, mode)
123 self.f = orig_open(fname, mode)
123 self.enc = encoding
124 self.enc = encoding
124
125
125 def write(self, s):
126 def write(self, s):
126 return self.f.write(s.encode(self.enc))
127 return self.f.write(s.encode(self.enc))
127
128
128 def read(self, size=-1):
129 def read(self, size=-1):
129 return self.f.read(size).decode(self.enc)
130 return self.f.read(size).decode(self.enc)
130
131
131 def close(self):
132 def close(self):
132 return self.f.close()
133 return self.f.close()
133
134
134 def __enter__(self):
135 def __enter__(self):
135 return self
136 return self
136
137
137 def __exit__(self, etype, value, traceback):
138 def __exit__(self, etype, value, traceback):
138 self.f.close()
139 self.f.close()
139
140
140 def MethodType(func, instance):
141 def MethodType(func, instance):
141 return types.MethodType(func, instance, type(instance))
142 return types.MethodType(func, instance, type(instance))
142
143
143 # don't override system execfile on 2.x:
144 # don't override system execfile on 2.x:
144 execfile = execfile
145 execfile = execfile
145
146
146 def doctest_refactor_print(func_or_str):
147 def doctest_refactor_print(func_or_str):
147 return func_or_str
148 return func_or_str
148
149
149
150
150 # Abstract u'abc' syntax:
151 # Abstract u'abc' syntax:
151 @_modify_str_or_docstring
152 @_modify_str_or_docstring
152 def u_format(s):
153 def u_format(s):
153 """"{u}'abc'" --> "u'abc'" (Python 2)
154 """"{u}'abc'" --> "u'abc'" (Python 2)
154
155
155 Accepts a string or a function, so it can be used as a decorator."""
156 Accepts a string or a function, so it can be used as a decorator."""
156 return s.format(u='u')
157 return s.format(u='u')
157
158
158 if sys.platform == 'win32':
159 if sys.platform == 'win32':
159 def execfile(fname, glob=None, loc=None):
160 def execfile(fname, glob=None, loc=None):
160 loc = loc if (loc is not None) else glob
161 loc = loc if (loc is not None) else glob
161 # The rstrip() is necessary b/c trailing whitespace in files will
162 # The rstrip() is necessary b/c trailing whitespace in files will
162 # cause an IndentationError in Python 2.6 (this was fixed in 2.7,
163 # cause an IndentationError in Python 2.6 (this was fixed in 2.7,
163 # but we still support 2.6). See issue 1027.
164 # but we still support 2.6). See issue 1027.
164 scripttext = __builtin__.open(fname).read().rstrip() + '\n'
165 scripttext = __builtin__.open(fname).read().rstrip() + '\n'
165 # compile converts unicode filename to str assuming
166 # compile converts unicode filename to str assuming
166 # ascii. Let's do the conversion before calling compile
167 # ascii. Let's do the conversion before calling compile
167 if isinstance(fname, unicode):
168 if isinstance(fname, unicode):
168 filename = unicode_to_str(fname)
169 filename = unicode_to_str(fname)
169 else:
170 else:
170 filename = fname
171 filename = fname
171 exec compile(scripttext, filename, 'exec') in glob, loc
172 exec compile(scripttext, filename, 'exec') in glob, loc
172 else:
173 else:
173 def execfile(fname, *where):
174 def execfile(fname, *where):
174 if isinstance(fname, unicode):
175 if isinstance(fname, unicode):
175 filename = fname.encode(sys.getfilesystemencoding())
176 filename = fname.encode(sys.getfilesystemencoding())
176 else:
177 else:
177 filename = fname
178 filename = fname
178 __builtin__.execfile(filename, *where)
179 __builtin__.execfile(filename, *where)
General Comments 0
You need to be logged in to leave comments. Login now