##// END OF EJS Templates
cleanup
Srinivas Reddy Thatiparthy -
Show More
@@ -1,321 +1,316 b''
1 """Tests for autoreload extension.
1 """Tests for autoreload extension.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2012 IPython Development Team.
4 # Copyright (c) 2012 IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 import os
15 import os
16 import sys
16 import sys
17 import tempfile
17 import tempfile
18 import shutil
18 import shutil
19 import random
19 import random
20 import time
20 import time
21 from io import StringIO
21
22
22 import nose.tools as nt
23 import nose.tools as nt
23 import IPython.testing.tools as tt
24 import IPython.testing.tools as tt
24
25
25 from IPython.extensions.autoreload import AutoreloadMagics
26 from IPython.extensions.autoreload import AutoreloadMagics
26 from IPython.core.events import EventManager, pre_run_cell
27 from IPython.core.events import EventManager, pre_run_cell
27 from IPython.utils.py3compat import PY3
28
29 if PY3:
30 from io import StringIO
31 else:
32 from StringIO import StringIO
33
28
34 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
35 # Test fixture
30 # Test fixture
36 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
37
32
38 noop = lambda *a, **kw: None
33 noop = lambda *a, **kw: None
39
34
40 class FakeShell(object):
35 class FakeShell(object):
41
36
42 def __init__(self):
37 def __init__(self):
43 self.ns = {}
38 self.ns = {}
44 self.events = EventManager(self, {'pre_run_cell', pre_run_cell})
39 self.events = EventManager(self, {'pre_run_cell', pre_run_cell})
45 self.auto_magics = AutoreloadMagics(shell=self)
40 self.auto_magics = AutoreloadMagics(shell=self)
46 self.events.register('pre_run_cell', self.auto_magics.pre_run_cell)
41 self.events.register('pre_run_cell', self.auto_magics.pre_run_cell)
47
42
48 register_magics = set_hook = noop
43 register_magics = set_hook = noop
49
44
50 def run_code(self, code):
45 def run_code(self, code):
51 self.events.trigger('pre_run_cell')
46 self.events.trigger('pre_run_cell')
52 exec(code, self.ns)
47 exec(code, self.ns)
53 self.auto_magics.post_execute_hook()
48 self.auto_magics.post_execute_hook()
54
49
55 def push(self, items):
50 def push(self, items):
56 self.ns.update(items)
51 self.ns.update(items)
57
52
58 def magic_autoreload(self, parameter):
53 def magic_autoreload(self, parameter):
59 self.auto_magics.autoreload(parameter)
54 self.auto_magics.autoreload(parameter)
60
55
61 def magic_aimport(self, parameter, stream=None):
56 def magic_aimport(self, parameter, stream=None):
62 self.auto_magics.aimport(parameter, stream=stream)
57 self.auto_magics.aimport(parameter, stream=stream)
63 self.auto_magics.post_execute_hook()
58 self.auto_magics.post_execute_hook()
64
59
65
60
66 class Fixture(object):
61 class Fixture(object):
67 """Fixture for creating test module files"""
62 """Fixture for creating test module files"""
68
63
69 test_dir = None
64 test_dir = None
70 old_sys_path = None
65 old_sys_path = None
71 filename_chars = "abcdefghijklmopqrstuvwxyz0123456789"
66 filename_chars = "abcdefghijklmopqrstuvwxyz0123456789"
72
67
73 def setUp(self):
68 def setUp(self):
74 self.test_dir = tempfile.mkdtemp()
69 self.test_dir = tempfile.mkdtemp()
75 self.old_sys_path = list(sys.path)
70 self.old_sys_path = list(sys.path)
76 sys.path.insert(0, self.test_dir)
71 sys.path.insert(0, self.test_dir)
77 self.shell = FakeShell()
72 self.shell = FakeShell()
78
73
79 def tearDown(self):
74 def tearDown(self):
80 shutil.rmtree(self.test_dir)
75 shutil.rmtree(self.test_dir)
81 sys.path = self.old_sys_path
76 sys.path = self.old_sys_path
82
77
83 self.test_dir = None
78 self.test_dir = None
84 self.old_sys_path = None
79 self.old_sys_path = None
85 self.shell = None
80 self.shell = None
86
81
87 def get_module(self):
82 def get_module(self):
88 module_name = "tmpmod_" + "".join(random.sample(self.filename_chars,20))
83 module_name = "tmpmod_" + "".join(random.sample(self.filename_chars,20))
89 if module_name in sys.modules:
84 if module_name in sys.modules:
90 del sys.modules[module_name]
85 del sys.modules[module_name]
91 file_name = os.path.join(self.test_dir, module_name + ".py")
86 file_name = os.path.join(self.test_dir, module_name + ".py")
92 return module_name, file_name
87 return module_name, file_name
93
88
94 def write_file(self, filename, content):
89 def write_file(self, filename, content):
95 """
90 """
96 Write a file, and force a timestamp difference of at least one second
91 Write a file, and force a timestamp difference of at least one second
97
92
98 Notes
93 Notes
99 -----
94 -----
100 Python's .pyc files record the timestamp of their compilation
95 Python's .pyc files record the timestamp of their compilation
101 with a time resolution of one second.
96 with a time resolution of one second.
102
97
103 Therefore, we need to force a timestamp difference between .py
98 Therefore, we need to force a timestamp difference between .py
104 and .pyc, without having the .py file be timestamped in the
99 and .pyc, without having the .py file be timestamped in the
105 future, and without changing the timestamp of the .pyc file
100 future, and without changing the timestamp of the .pyc file
106 (because that is stored in the file). The only reliable way
101 (because that is stored in the file). The only reliable way
107 to achieve this seems to be to sleep.
102 to achieve this seems to be to sleep.
108 """
103 """
109
104
110 # Sleep one second + eps
105 # Sleep one second + eps
111 time.sleep(1.05)
106 time.sleep(1.05)
112
107
113 # Write
108 # Write
114 f = open(filename, 'w')
109 f = open(filename, 'w')
115 try:
110 try:
116 f.write(content)
111 f.write(content)
117 finally:
112 finally:
118 f.close()
113 f.close()
119
114
120 def new_module(self, code):
115 def new_module(self, code):
121 mod_name, mod_fn = self.get_module()
116 mod_name, mod_fn = self.get_module()
122 f = open(mod_fn, 'w')
117 f = open(mod_fn, 'w')
123 try:
118 try:
124 f.write(code)
119 f.write(code)
125 finally:
120 finally:
126 f.close()
121 f.close()
127 return mod_name, mod_fn
122 return mod_name, mod_fn
128
123
129 #-----------------------------------------------------------------------------
124 #-----------------------------------------------------------------------------
130 # Test automatic reloading
125 # Test automatic reloading
131 #-----------------------------------------------------------------------------
126 #-----------------------------------------------------------------------------
132
127
133 class TestAutoreload(Fixture):
128 class TestAutoreload(Fixture):
134 def _check_smoketest(self, use_aimport=True):
129 def _check_smoketest(self, use_aimport=True):
135 """
130 """
136 Functional test for the automatic reloader using either
131 Functional test for the automatic reloader using either
137 '%autoreload 1' or '%autoreload 2'
132 '%autoreload 1' or '%autoreload 2'
138 """
133 """
139
134
140 mod_name, mod_fn = self.new_module("""
135 mod_name, mod_fn = self.new_module("""
141 x = 9
136 x = 9
142
137
143 z = 123 # this item will be deleted
138 z = 123 # this item will be deleted
144
139
145 def foo(y):
140 def foo(y):
146 return y + 3
141 return y + 3
147
142
148 class Baz(object):
143 class Baz(object):
149 def __init__(self, x):
144 def __init__(self, x):
150 self.x = x
145 self.x = x
151 def bar(self, y):
146 def bar(self, y):
152 return self.x + y
147 return self.x + y
153 @property
148 @property
154 def quux(self):
149 def quux(self):
155 return 42
150 return 42
156 def zzz(self):
151 def zzz(self):
157 '''This method will be deleted below'''
152 '''This method will be deleted below'''
158 return 99
153 return 99
159
154
160 class Bar: # old-style class: weakref doesn't work for it on Python < 2.7
155 class Bar: # old-style class: weakref doesn't work for it on Python < 2.7
161 def foo(self):
156 def foo(self):
162 return 1
157 return 1
163 """)
158 """)
164
159
165 #
160 #
166 # Import module, and mark for reloading
161 # Import module, and mark for reloading
167 #
162 #
168 if use_aimport:
163 if use_aimport:
169 self.shell.magic_autoreload("1")
164 self.shell.magic_autoreload("1")
170 self.shell.magic_aimport(mod_name)
165 self.shell.magic_aimport(mod_name)
171 stream = StringIO()
166 stream = StringIO()
172 self.shell.magic_aimport("", stream=stream)
167 self.shell.magic_aimport("", stream=stream)
173 nt.assert_in(("Modules to reload:\n%s" % mod_name), stream.getvalue())
168 nt.assert_in(("Modules to reload:\n%s" % mod_name), stream.getvalue())
174
169
175 with nt.assert_raises(ImportError):
170 with nt.assert_raises(ImportError):
176 self.shell.magic_aimport("tmpmod_as318989e89ds")
171 self.shell.magic_aimport("tmpmod_as318989e89ds")
177 else:
172 else:
178 self.shell.magic_autoreload("2")
173 self.shell.magic_autoreload("2")
179 self.shell.run_code("import %s" % mod_name)
174 self.shell.run_code("import %s" % mod_name)
180 stream = StringIO()
175 stream = StringIO()
181 self.shell.magic_aimport("", stream=stream)
176 self.shell.magic_aimport("", stream=stream)
182 nt.assert_true("Modules to reload:\nall-except-skipped" in
177 nt.assert_true("Modules to reload:\nall-except-skipped" in
183 stream.getvalue())
178 stream.getvalue())
184 nt.assert_in(mod_name, self.shell.ns)
179 nt.assert_in(mod_name, self.shell.ns)
185
180
186 mod = sys.modules[mod_name]
181 mod = sys.modules[mod_name]
187
182
188 #
183 #
189 # Test module contents
184 # Test module contents
190 #
185 #
191 old_foo = mod.foo
186 old_foo = mod.foo
192 old_obj = mod.Baz(9)
187 old_obj = mod.Baz(9)
193 old_obj2 = mod.Bar()
188 old_obj2 = mod.Bar()
194
189
195 def check_module_contents():
190 def check_module_contents():
196 nt.assert_equal(mod.x, 9)
191 nt.assert_equal(mod.x, 9)
197 nt.assert_equal(mod.z, 123)
192 nt.assert_equal(mod.z, 123)
198
193
199 nt.assert_equal(old_foo(0), 3)
194 nt.assert_equal(old_foo(0), 3)
200 nt.assert_equal(mod.foo(0), 3)
195 nt.assert_equal(mod.foo(0), 3)
201
196
202 obj = mod.Baz(9)
197 obj = mod.Baz(9)
203 nt.assert_equal(old_obj.bar(1), 10)
198 nt.assert_equal(old_obj.bar(1), 10)
204 nt.assert_equal(obj.bar(1), 10)
199 nt.assert_equal(obj.bar(1), 10)
205 nt.assert_equal(obj.quux, 42)
200 nt.assert_equal(obj.quux, 42)
206 nt.assert_equal(obj.zzz(), 99)
201 nt.assert_equal(obj.zzz(), 99)
207
202
208 obj2 = mod.Bar()
203 obj2 = mod.Bar()
209 nt.assert_equal(old_obj2.foo(), 1)
204 nt.assert_equal(old_obj2.foo(), 1)
210 nt.assert_equal(obj2.foo(), 1)
205 nt.assert_equal(obj2.foo(), 1)
211
206
212 check_module_contents()
207 check_module_contents()
213
208
214 #
209 #
215 # Simulate a failed reload: no reload should occur and exactly
210 # Simulate a failed reload: no reload should occur and exactly
216 # one error message should be printed
211 # one error message should be printed
217 #
212 #
218 self.write_file(mod_fn, """
213 self.write_file(mod_fn, """
219 a syntax error
214 a syntax error
220 """)
215 """)
221
216
222 with tt.AssertPrints(('[autoreload of %s failed:' % mod_name), channel='stderr'):
217 with tt.AssertPrints(('[autoreload of %s failed:' % mod_name), channel='stderr'):
223 self.shell.run_code("pass") # trigger reload
218 self.shell.run_code("pass") # trigger reload
224 with tt.AssertNotPrints(('[autoreload of %s failed:' % mod_name), channel='stderr'):
219 with tt.AssertNotPrints(('[autoreload of %s failed:' % mod_name), channel='stderr'):
225 self.shell.run_code("pass") # trigger another reload
220 self.shell.run_code("pass") # trigger another reload
226 check_module_contents()
221 check_module_contents()
227
222
228 #
223 #
229 # Rewrite module (this time reload should succeed)
224 # Rewrite module (this time reload should succeed)
230 #
225 #
231 self.write_file(mod_fn, """
226 self.write_file(mod_fn, """
232 x = 10
227 x = 10
233
228
234 def foo(y):
229 def foo(y):
235 return y + 4
230 return y + 4
236
231
237 class Baz(object):
232 class Baz(object):
238 def __init__(self, x):
233 def __init__(self, x):
239 self.x = x
234 self.x = x
240 def bar(self, y):
235 def bar(self, y):
241 return self.x + y + 1
236 return self.x + y + 1
242 @property
237 @property
243 def quux(self):
238 def quux(self):
244 return 43
239 return 43
245
240
246 class Bar: # old-style class
241 class Bar: # old-style class
247 def foo(self):
242 def foo(self):
248 return 2
243 return 2
249 """)
244 """)
250
245
251 def check_module_contents():
246 def check_module_contents():
252 nt.assert_equal(mod.x, 10)
247 nt.assert_equal(mod.x, 10)
253 nt.assert_false(hasattr(mod, 'z'))
248 nt.assert_false(hasattr(mod, 'z'))
254
249
255 nt.assert_equal(old_foo(0), 4) # superreload magic!
250 nt.assert_equal(old_foo(0), 4) # superreload magic!
256 nt.assert_equal(mod.foo(0), 4)
251 nt.assert_equal(mod.foo(0), 4)
257
252
258 obj = mod.Baz(9)
253 obj = mod.Baz(9)
259 nt.assert_equal(old_obj.bar(1), 11) # superreload magic!
254 nt.assert_equal(old_obj.bar(1), 11) # superreload magic!
260 nt.assert_equal(obj.bar(1), 11)
255 nt.assert_equal(obj.bar(1), 11)
261
256
262 nt.assert_equal(old_obj.quux, 43)
257 nt.assert_equal(old_obj.quux, 43)
263 nt.assert_equal(obj.quux, 43)
258 nt.assert_equal(obj.quux, 43)
264
259
265 nt.assert_false(hasattr(old_obj, 'zzz'))
260 nt.assert_false(hasattr(old_obj, 'zzz'))
266 nt.assert_false(hasattr(obj, 'zzz'))
261 nt.assert_false(hasattr(obj, 'zzz'))
267
262
268 obj2 = mod.Bar()
263 obj2 = mod.Bar()
269 nt.assert_equal(old_obj2.foo(), 2)
264 nt.assert_equal(old_obj2.foo(), 2)
270 nt.assert_equal(obj2.foo(), 2)
265 nt.assert_equal(obj2.foo(), 2)
271
266
272 self.shell.run_code("pass") # trigger reload
267 self.shell.run_code("pass") # trigger reload
273 check_module_contents()
268 check_module_contents()
274
269
275 #
270 #
276 # Another failure case: deleted file (shouldn't reload)
271 # Another failure case: deleted file (shouldn't reload)
277 #
272 #
278 os.unlink(mod_fn)
273 os.unlink(mod_fn)
279
274
280 self.shell.run_code("pass") # trigger reload
275 self.shell.run_code("pass") # trigger reload
281 check_module_contents()
276 check_module_contents()
282
277
283 #
278 #
284 # Disable autoreload and rewrite module: no reload should occur
279 # Disable autoreload and rewrite module: no reload should occur
285 #
280 #
286 if use_aimport:
281 if use_aimport:
287 self.shell.magic_aimport("-" + mod_name)
282 self.shell.magic_aimport("-" + mod_name)
288 stream = StringIO()
283 stream = StringIO()
289 self.shell.magic_aimport("", stream=stream)
284 self.shell.magic_aimport("", stream=stream)
290 nt.assert_true(("Modules to skip:\n%s" % mod_name) in
285 nt.assert_true(("Modules to skip:\n%s" % mod_name) in
291 stream.getvalue())
286 stream.getvalue())
292
287
293 # This should succeed, although no such module exists
288 # This should succeed, although no such module exists
294 self.shell.magic_aimport("-tmpmod_as318989e89ds")
289 self.shell.magic_aimport("-tmpmod_as318989e89ds")
295 else:
290 else:
296 self.shell.magic_autoreload("0")
291 self.shell.magic_autoreload("0")
297
292
298 self.write_file(mod_fn, """
293 self.write_file(mod_fn, """
299 x = -99
294 x = -99
300 """)
295 """)
301
296
302 self.shell.run_code("pass") # trigger reload
297 self.shell.run_code("pass") # trigger reload
303 self.shell.run_code("pass")
298 self.shell.run_code("pass")
304 check_module_contents()
299 check_module_contents()
305
300
306 #
301 #
307 # Re-enable autoreload: reload should now occur
302 # Re-enable autoreload: reload should now occur
308 #
303 #
309 if use_aimport:
304 if use_aimport:
310 self.shell.magic_aimport(mod_name)
305 self.shell.magic_aimport(mod_name)
311 else:
306 else:
312 self.shell.magic_autoreload("")
307 self.shell.magic_autoreload("")
313
308
314 self.shell.run_code("pass") # trigger reload
309 self.shell.run_code("pass") # trigger reload
315 nt.assert_equal(mod.x, -99)
310 nt.assert_equal(mod.x, -99)
316
311
317 def test_smoketest_aimport(self):
312 def test_smoketest_aimport(self):
318 self._check_smoketest(use_aimport=True)
313 self._check_smoketest(use_aimport=True)
319
314
320 def test_smoketest_autoreload(self):
315 def test_smoketest_autoreload(self):
321 self._check_smoketest(use_aimport=False)
316 self._check_smoketest(use_aimport=False)
General Comments 0
You need to be logged in to leave comments. Login now