##// END OF EJS Templates
Fix some more tests for Python 3.
Thomas Kluyver -
Show More
@@ -1,483 +1,487 b''
1 """
1 """
2 ``autoreload`` is an IPython extension that reloads modules
2 ``autoreload`` is an IPython extension that reloads modules
3 automatically before executing the line of code typed.
3 automatically before executing the line of code typed.
4
4
5 This makes for example the following workflow possible:
5 This makes for example the following workflow possible:
6
6
7 .. sourcecode:: ipython
7 .. sourcecode:: ipython
8
8
9 In [1]: %load_ext autoreload
9 In [1]: %load_ext autoreload
10
10
11 In [2]: %autoreload 2
11 In [2]: %autoreload 2
12
12
13 In [3]: from foo import some_function
13 In [3]: from foo import some_function
14
14
15 In [4]: some_function()
15 In [4]: some_function()
16 Out[4]: 42
16 Out[4]: 42
17
17
18 In [5]: # open foo.py in an editor and change some_function to return 43
18 In [5]: # open foo.py in an editor and change some_function to return 43
19
19
20 In [6]: some_function()
20 In [6]: some_function()
21 Out[6]: 43
21 Out[6]: 43
22
22
23 The module was reloaded without reloading it explicitly, and the
23 The module was reloaded without reloading it explicitly, and the
24 object imported with ``from foo import ...`` was also updated.
24 object imported with ``from foo import ...`` was also updated.
25
25
26 Usage
26 Usage
27 =====
27 =====
28
28
29 The following magic commands are provided:
29 The following magic commands are provided:
30
30
31 ``%autoreload``
31 ``%autoreload``
32
32
33 Reload all modules (except those excluded by ``%aimport``)
33 Reload all modules (except those excluded by ``%aimport``)
34 automatically now.
34 automatically now.
35
35
36 ``%autoreload 0``
36 ``%autoreload 0``
37
37
38 Disable automatic reloading.
38 Disable automatic reloading.
39
39
40 ``%autoreload 1``
40 ``%autoreload 1``
41
41
42 Reload all modules imported with ``%aimport`` every time before
42 Reload all modules imported with ``%aimport`` every time before
43 executing the Python code typed.
43 executing the Python code typed.
44
44
45 ``%autoreload 2``
45 ``%autoreload 2``
46
46
47 Reload all modules (except those excluded by ``%aimport``) every
47 Reload all modules (except those excluded by ``%aimport``) every
48 time before executing the Python code typed.
48 time before executing the Python code typed.
49
49
50 ``%aimport``
50 ``%aimport``
51
51
52 List modules which are to be automatically imported or not to be imported.
52 List modules which are to be automatically imported or not to be imported.
53
53
54 ``%aimport foo``
54 ``%aimport foo``
55
55
56 Import module 'foo' and mark it to be autoreloaded for ``%autoreload 1``
56 Import module 'foo' and mark it to be autoreloaded for ``%autoreload 1``
57
57
58 ``%aimport -foo``
58 ``%aimport -foo``
59
59
60 Mark module 'foo' to not be autoreloaded.
60 Mark module 'foo' to not be autoreloaded.
61
61
62 Caveats
62 Caveats
63 =======
63 =======
64
64
65 Reloading Python modules in a reliable way is in general difficult,
65 Reloading Python modules in a reliable way is in general difficult,
66 and unexpected things may occur. ``%autoreload`` tries to work around
66 and unexpected things may occur. ``%autoreload`` tries to work around
67 common pitfalls by replacing function code objects and parts of
67 common pitfalls by replacing function code objects and parts of
68 classes previously in the module with new versions. This makes the
68 classes previously in the module with new versions. This makes the
69 following things to work:
69 following things to work:
70
70
71 - Functions and classes imported via 'from xxx import foo' are upgraded
71 - Functions and classes imported via 'from xxx import foo' are upgraded
72 to new versions when 'xxx' is reloaded.
72 to new versions when 'xxx' is reloaded.
73
73
74 - Methods and properties of classes are upgraded on reload, so that
74 - Methods and properties of classes are upgraded on reload, so that
75 calling 'c.foo()' on an object 'c' created before the reload causes
75 calling 'c.foo()' on an object 'c' created before the reload causes
76 the new code for 'foo' to be executed.
76 the new code for 'foo' to be executed.
77
77
78 Some of the known remaining caveats are:
78 Some of the known remaining caveats are:
79
79
80 - Replacing code objects does not always succeed: changing a @property
80 - Replacing code objects does not always succeed: changing a @property
81 in a class to an ordinary method or a method to a member variable
81 in a class to an ordinary method or a method to a member variable
82 can cause problems (but in old objects only).
82 can cause problems (but in old objects only).
83
83
84 - Functions that are removed (eg. via monkey-patching) from a module
84 - Functions that are removed (eg. via monkey-patching) from a module
85 before it is reloaded are not upgraded.
85 before it is reloaded are not upgraded.
86
86
87 - C extension modules cannot be reloaded, and so cannot be
87 - C extension modules cannot be reloaded, and so cannot be
88 autoreloaded.
88 autoreloaded.
89
89
90 """
90 """
91
91
92 skip_doctest = True
92 skip_doctest = True
93
93
94 # Pauli Virtanen <pav@iki.fi>, 2008.
94 # Pauli Virtanen <pav@iki.fi>, 2008.
95 # Thomas Heller, 2000.
95 # Thomas Heller, 2000.
96 #
96 #
97 # This IPython module is written by Pauli Virtanen, based on the autoreload
97 # This IPython module is written by Pauli Virtanen, based on the autoreload
98 # code by Thomas Heller.
98 # code by Thomas Heller.
99
99
100 #------------------------------------------------------------------------------
100 #------------------------------------------------------------------------------
101 # Autoreload functionality
101 # Autoreload functionality
102 #------------------------------------------------------------------------------
102 #------------------------------------------------------------------------------
103
103
104 import time, os, threading, sys, types, imp, inspect, traceback, atexit
104 import time, os, threading, sys, types, imp, inspect, traceback, atexit
105 import weakref
105 import weakref
106 try:
107 reload
108 except NameError:
109 from imp import reload
106
110
107 def _get_compiled_ext():
111 def _get_compiled_ext():
108 """Official way to get the extension of compiled files (.pyc or .pyo)"""
112 """Official way to get the extension of compiled files (.pyc or .pyo)"""
109 for ext, mode, typ in imp.get_suffixes():
113 for ext, mode, typ in imp.get_suffixes():
110 if typ == imp.PY_COMPILED:
114 if typ == imp.PY_COMPILED:
111 return ext
115 return ext
112
116
113 PY_COMPILED_EXT = _get_compiled_ext()
117 PY_COMPILED_EXT = _get_compiled_ext()
114
118
115 class ModuleReloader(object):
119 class ModuleReloader(object):
116 enabled = False
120 enabled = False
117 """Whether this reloader is enabled"""
121 """Whether this reloader is enabled"""
118
122
119 failed = {}
123 failed = {}
120 """Modules that failed to reload: {module: mtime-on-failed-reload, ...}"""
124 """Modules that failed to reload: {module: mtime-on-failed-reload, ...}"""
121
125
122 modules = {}
126 modules = {}
123 """Modules specially marked as autoreloadable."""
127 """Modules specially marked as autoreloadable."""
124
128
125 skip_modules = {}
129 skip_modules = {}
126 """Modules specially marked as not autoreloadable."""
130 """Modules specially marked as not autoreloadable."""
127
131
128 check_all = True
132 check_all = True
129 """Autoreload all modules, not just those listed in 'modules'"""
133 """Autoreload all modules, not just those listed in 'modules'"""
130
134
131 old_objects = {}
135 old_objects = {}
132 """(module-name, name) -> weakref, for replacing old code objects"""
136 """(module-name, name) -> weakref, for replacing old code objects"""
133
137
134 def mark_module_skipped(self, module_name):
138 def mark_module_skipped(self, module_name):
135 """Skip reloading the named module in the future"""
139 """Skip reloading the named module in the future"""
136 try:
140 try:
137 del self.modules[module_name]
141 del self.modules[module_name]
138 except KeyError:
142 except KeyError:
139 pass
143 pass
140 self.skip_modules[module_name] = True
144 self.skip_modules[module_name] = True
141
145
142 def mark_module_reloadable(self, module_name):
146 def mark_module_reloadable(self, module_name):
143 """Reload the named module in the future (if it is imported)"""
147 """Reload the named module in the future (if it is imported)"""
144 try:
148 try:
145 del self.skip_modules[module_name]
149 del self.skip_modules[module_name]
146 except KeyError:
150 except KeyError:
147 pass
151 pass
148 self.modules[module_name] = True
152 self.modules[module_name] = True
149
153
150 def aimport_module(self, module_name):
154 def aimport_module(self, module_name):
151 """Import a module, and mark it reloadable
155 """Import a module, and mark it reloadable
152
156
153 Returns
157 Returns
154 -------
158 -------
155 top_module : module
159 top_module : module
156 The imported module if it is top-level, or the top-level
160 The imported module if it is top-level, or the top-level
157 top_name : module
161 top_name : module
158 Name of top_module
162 Name of top_module
159
163
160 """
164 """
161 self.mark_module_reloadable(module_name)
165 self.mark_module_reloadable(module_name)
162
166
163 __import__(module_name)
167 __import__(module_name)
164 top_name = module_name.split('.')[0]
168 top_name = module_name.split('.')[0]
165 top_module = sys.modules[top_name]
169 top_module = sys.modules[top_name]
166 return top_module, top_name
170 return top_module, top_name
167
171
168 def check(self, check_all=False):
172 def check(self, check_all=False):
169 """Check whether some modules need to be reloaded."""
173 """Check whether some modules need to be reloaded."""
170
174
171 if not self.enabled and not check_all:
175 if not self.enabled and not check_all:
172 return
176 return
173
177
174 if check_all or self.check_all:
178 if check_all or self.check_all:
175 modules = sys.modules.keys()
179 modules = sys.modules.keys()
176 else:
180 else:
177 modules = self.modules.keys()
181 modules = self.modules.keys()
178
182
179 for modname in modules:
183 for modname in modules:
180 m = sys.modules.get(modname, None)
184 m = sys.modules.get(modname, None)
181
185
182 if modname in self.skip_modules:
186 if modname in self.skip_modules:
183 continue
187 continue
184
188
185 if not hasattr(m, '__file__'):
189 if not hasattr(m, '__file__'):
186 continue
190 continue
187
191
188 if m.__name__ == '__main__':
192 if m.__name__ == '__main__':
189 # we cannot reload(__main__)
193 # we cannot reload(__main__)
190 continue
194 continue
191
195
192 filename = m.__file__
196 filename = m.__file__
193 path, ext = os.path.splitext(filename)
197 path, ext = os.path.splitext(filename)
194
198
195 if ext.lower() == '.py':
199 if ext.lower() == '.py':
196 ext = PY_COMPILED_EXT
200 ext = PY_COMPILED_EXT
197 pyc_filename = path + PY_COMPILED_EXT
201 pyc_filename = path + PY_COMPILED_EXT
198 py_filename = filename
202 py_filename = filename
199 else:
203 else:
200 pyc_filename = filename
204 pyc_filename = filename
201 py_filename = filename[:-1]
205 py_filename = filename[:-1]
202
206
203 if ext != PY_COMPILED_EXT:
207 if ext != PY_COMPILED_EXT:
204 continue
208 continue
205
209
206 try:
210 try:
207 pymtime = os.stat(py_filename).st_mtime
211 pymtime = os.stat(py_filename).st_mtime
208 if pymtime <= os.stat(pyc_filename).st_mtime:
212 if pymtime <= os.stat(pyc_filename).st_mtime:
209 continue
213 continue
210 if self.failed.get(py_filename, None) == pymtime:
214 if self.failed.get(py_filename, None) == pymtime:
211 continue
215 continue
212 except OSError:
216 except OSError:
213 continue
217 continue
214
218
215 try:
219 try:
216 superreload(m, reload, self.old_objects)
220 superreload(m, reload, self.old_objects)
217 if py_filename in self.failed:
221 if py_filename in self.failed:
218 del self.failed[py_filename]
222 del self.failed[py_filename]
219 except:
223 except:
220 print >> sys.stderr, "[autoreload of %s failed: %s]" % (
224 print >> sys.stderr, "[autoreload of %s failed: %s]" % (
221 modname, traceback.format_exc(1))
225 modname, traceback.format_exc(1))
222 self.failed[py_filename] = pymtime
226 self.failed[py_filename] = pymtime
223
227
224 #------------------------------------------------------------------------------
228 #------------------------------------------------------------------------------
225 # superreload
229 # superreload
226 #------------------------------------------------------------------------------
230 #------------------------------------------------------------------------------
227
231
228 def update_function(old, new):
232 def update_function(old, new):
229 """Upgrade the code object of a function"""
233 """Upgrade the code object of a function"""
230 for name in ['func_code', 'func_defaults', 'func_doc',
234 for name in ['func_code', 'func_defaults', 'func_doc',
231 'func_closure', 'func_globals', 'func_dict']:
235 'func_closure', 'func_globals', 'func_dict']:
232 try:
236 try:
233 setattr(old, name, getattr(new, name))
237 setattr(old, name, getattr(new, name))
234 except (AttributeError, TypeError):
238 except (AttributeError, TypeError):
235 pass
239 pass
236
240
237 def update_class(old, new):
241 def update_class(old, new):
238 """Replace stuff in the __dict__ of a class, and upgrade
242 """Replace stuff in the __dict__ of a class, and upgrade
239 method code objects"""
243 method code objects"""
240 for key in old.__dict__.keys():
244 for key in old.__dict__.keys():
241 old_obj = getattr(old, key)
245 old_obj = getattr(old, key)
242
246
243 try:
247 try:
244 new_obj = getattr(new, key)
248 new_obj = getattr(new, key)
245 except AttributeError:
249 except AttributeError:
246 # obsolete attribute: remove it
250 # obsolete attribute: remove it
247 try:
251 try:
248 delattr(old, key)
252 delattr(old, key)
249 except (AttributeError, TypeError):
253 except (AttributeError, TypeError):
250 pass
254 pass
251 continue
255 continue
252
256
253 if update_generic(old_obj, new_obj): continue
257 if update_generic(old_obj, new_obj): continue
254
258
255 try:
259 try:
256 setattr(old, key, getattr(new, key))
260 setattr(old, key, getattr(new, key))
257 except (AttributeError, TypeError):
261 except (AttributeError, TypeError):
258 pass # skip non-writable attributes
262 pass # skip non-writable attributes
259
263
260 def update_property(old, new):
264 def update_property(old, new):
261 """Replace get/set/del functions of a property"""
265 """Replace get/set/del functions of a property"""
262 update_generic(old.fdel, new.fdel)
266 update_generic(old.fdel, new.fdel)
263 update_generic(old.fget, new.fget)
267 update_generic(old.fget, new.fget)
264 update_generic(old.fset, new.fset)
268 update_generic(old.fset, new.fset)
265
269
266 def isinstance2(a, b, typ):
270 def isinstance2(a, b, typ):
267 return isinstance(a, typ) and isinstance(b, typ)
271 return isinstance(a, typ) and isinstance(b, typ)
268
272
269 UPDATE_RULES = [
273 UPDATE_RULES = [
270 (lambda a, b: isinstance2(a, b, types.ClassType),
274 (lambda a, b: isinstance2(a, b, types.ClassType),
271 update_class),
275 update_class),
272 (lambda a, b: isinstance2(a, b, types.TypeType),
276 (lambda a, b: isinstance2(a, b, types.TypeType),
273 update_class),
277 update_class),
274 (lambda a, b: isinstance2(a, b, types.FunctionType),
278 (lambda a, b: isinstance2(a, b, types.FunctionType),
275 update_function),
279 update_function),
276 (lambda a, b: isinstance2(a, b, property),
280 (lambda a, b: isinstance2(a, b, property),
277 update_property),
281 update_property),
278 (lambda a, b: isinstance2(a, b, types.MethodType),
282 (lambda a, b: isinstance2(a, b, types.MethodType),
279 lambda a, b: update_function(a.im_func, b.im_func)),
283 lambda a, b: update_function(a.im_func, b.im_func)),
280 ]
284 ]
281
285
282 def update_generic(a, b):
286 def update_generic(a, b):
283 for type_check, update in UPDATE_RULES:
287 for type_check, update in UPDATE_RULES:
284 if type_check(a, b):
288 if type_check(a, b):
285 update(a, b)
289 update(a, b)
286 return True
290 return True
287 return False
291 return False
288
292
289 class StrongRef(object):
293 class StrongRef(object):
290 def __init__(self, obj):
294 def __init__(self, obj):
291 self.obj = obj
295 self.obj = obj
292 def __call__(self):
296 def __call__(self):
293 return self.obj
297 return self.obj
294
298
295 def superreload(module, reload=reload, old_objects={}):
299 def superreload(module, reload=reload, old_objects={}):
296 """Enhanced version of the builtin reload function.
300 """Enhanced version of the builtin reload function.
297
301
298 superreload remembers objects previously in the module, and
302 superreload remembers objects previously in the module, and
299
303
300 - upgrades the class dictionary of every old class in the module
304 - upgrades the class dictionary of every old class in the module
301 - upgrades the code object of every old function and method
305 - upgrades the code object of every old function and method
302 - clears the module's namespace before reloading
306 - clears the module's namespace before reloading
303
307
304 """
308 """
305
309
306 # collect old objects in the module
310 # collect old objects in the module
307 for name, obj in module.__dict__.items():
311 for name, obj in module.__dict__.items():
308 if not hasattr(obj, '__module__') or obj.__module__ != module.__name__:
312 if not hasattr(obj, '__module__') or obj.__module__ != module.__name__:
309 continue
313 continue
310 key = (module.__name__, name)
314 key = (module.__name__, name)
311 try:
315 try:
312 old_objects.setdefault(key, []).append(weakref.ref(obj))
316 old_objects.setdefault(key, []).append(weakref.ref(obj))
313 except TypeError:
317 except TypeError:
314 # weakref doesn't work for all types;
318 # weakref doesn't work for all types;
315 # create strong references for 'important' cases
319 # create strong references for 'important' cases
316 if isinstance(obj, types.ClassType):
320 if isinstance(obj, types.ClassType):
317 old_objects.setdefault(key, []).append(StrongRef(obj))
321 old_objects.setdefault(key, []).append(StrongRef(obj))
318
322
319 # reload module
323 # reload module
320 try:
324 try:
321 # clear namespace first from old cruft
325 # clear namespace first from old cruft
322 old_dict = module.__dict__.copy()
326 old_dict = module.__dict__.copy()
323 old_name = module.__name__
327 old_name = module.__name__
324 module.__dict__.clear()
328 module.__dict__.clear()
325 module.__dict__['__name__'] = old_name
329 module.__dict__['__name__'] = old_name
326 except (TypeError, AttributeError, KeyError):
330 except (TypeError, AttributeError, KeyError):
327 pass
331 pass
328
332
329 try:
333 try:
330 module = reload(module)
334 module = reload(module)
331 except:
335 except:
332 # restore module dictionary on failed reload
336 # restore module dictionary on failed reload
333 module.__dict__.update(old_dict)
337 module.__dict__.update(old_dict)
334 raise
338 raise
335
339
336 # iterate over all objects and update functions & classes
340 # iterate over all objects and update functions & classes
337 for name, new_obj in module.__dict__.items():
341 for name, new_obj in module.__dict__.items():
338 key = (module.__name__, name)
342 key = (module.__name__, name)
339 if key not in old_objects: continue
343 if key not in old_objects: continue
340
344
341 new_refs = []
345 new_refs = []
342 for old_ref in old_objects[key]:
346 for old_ref in old_objects[key]:
343 old_obj = old_ref()
347 old_obj = old_ref()
344 if old_obj is None: continue
348 if old_obj is None: continue
345 new_refs.append(old_ref)
349 new_refs.append(old_ref)
346 update_generic(old_obj, new_obj)
350 update_generic(old_obj, new_obj)
347
351
348 if new_refs:
352 if new_refs:
349 old_objects[key] = new_refs
353 old_objects[key] = new_refs
350 else:
354 else:
351 del old_objects[key]
355 del old_objects[key]
352
356
353 return module
357 return module
354
358
355 #------------------------------------------------------------------------------
359 #------------------------------------------------------------------------------
356 # IPython connectivity
360 # IPython connectivity
357 #------------------------------------------------------------------------------
361 #------------------------------------------------------------------------------
358
362
359 from IPython.core.plugin import Plugin
363 from IPython.core.plugin import Plugin
360 from IPython.core.hooks import TryNext
364 from IPython.core.hooks import TryNext
361
365
362 class AutoreloadInterface(object):
366 class AutoreloadInterface(object):
363 def __init__(self, *a, **kw):
367 def __init__(self, *a, **kw):
364 super(AutoreloadInterface, self).__init__(*a, **kw)
368 super(AutoreloadInterface, self).__init__(*a, **kw)
365 self._reloader = ModuleReloader()
369 self._reloader = ModuleReloader()
366 self._reloader.check_all = False
370 self._reloader.check_all = False
367
371
368 def magic_autoreload(self, ipself, parameter_s=''):
372 def magic_autoreload(self, ipself, parameter_s=''):
369 r"""%autoreload => Reload modules automatically
373 r"""%autoreload => Reload modules automatically
370
374
371 %autoreload
375 %autoreload
372 Reload all modules (except those excluded by %aimport) automatically
376 Reload all modules (except those excluded by %aimport) automatically
373 now.
377 now.
374
378
375 %autoreload 0
379 %autoreload 0
376 Disable automatic reloading.
380 Disable automatic reloading.
377
381
378 %autoreload 1
382 %autoreload 1
379 Reload all modules imported with %aimport every time before executing
383 Reload all modules imported with %aimport every time before executing
380 the Python code typed.
384 the Python code typed.
381
385
382 %autoreload 2
386 %autoreload 2
383 Reload all modules (except those excluded by %aimport) every time
387 Reload all modules (except those excluded by %aimport) every time
384 before executing the Python code typed.
388 before executing the Python code typed.
385
389
386 Reloading Python modules in a reliable way is in general
390 Reloading Python modules in a reliable way is in general
387 difficult, and unexpected things may occur. %autoreload tries to
391 difficult, and unexpected things may occur. %autoreload tries to
388 work around common pitfalls by replacing function code objects and
392 work around common pitfalls by replacing function code objects and
389 parts of classes previously in the module with new versions. This
393 parts of classes previously in the module with new versions. This
390 makes the following things to work:
394 makes the following things to work:
391
395
392 - Functions and classes imported via 'from xxx import foo' are upgraded
396 - Functions and classes imported via 'from xxx import foo' are upgraded
393 to new versions when 'xxx' is reloaded.
397 to new versions when 'xxx' is reloaded.
394
398
395 - Methods and properties of classes are upgraded on reload, so that
399 - Methods and properties of classes are upgraded on reload, so that
396 calling 'c.foo()' on an object 'c' created before the reload causes
400 calling 'c.foo()' on an object 'c' created before the reload causes
397 the new code for 'foo' to be executed.
401 the new code for 'foo' to be executed.
398
402
399 Some of the known remaining caveats are:
403 Some of the known remaining caveats are:
400
404
401 - Replacing code objects does not always succeed: changing a @property
405 - Replacing code objects does not always succeed: changing a @property
402 in a class to an ordinary method or a method to a member variable
406 in a class to an ordinary method or a method to a member variable
403 can cause problems (but in old objects only).
407 can cause problems (but in old objects only).
404
408
405 - Functions that are removed (eg. via monkey-patching) from a module
409 - Functions that are removed (eg. via monkey-patching) from a module
406 before it is reloaded are not upgraded.
410 before it is reloaded are not upgraded.
407
411
408 - C extension modules cannot be reloaded, and so cannot be
412 - C extension modules cannot be reloaded, and so cannot be
409 autoreloaded.
413 autoreloaded.
410
414
411 """
415 """
412 if parameter_s == '':
416 if parameter_s == '':
413 self._reloader.check(True)
417 self._reloader.check(True)
414 elif parameter_s == '0':
418 elif parameter_s == '0':
415 self._reloader.enabled = False
419 self._reloader.enabled = False
416 elif parameter_s == '1':
420 elif parameter_s == '1':
417 self._reloader.check_all = False
421 self._reloader.check_all = False
418 self._reloader.enabled = True
422 self._reloader.enabled = True
419 elif parameter_s == '2':
423 elif parameter_s == '2':
420 self._reloader.check_all = True
424 self._reloader.check_all = True
421 self._reloader.enabled = True
425 self._reloader.enabled = True
422
426
423 def magic_aimport(self, ipself, parameter_s='', stream=None):
427 def magic_aimport(self, ipself, parameter_s='', stream=None):
424 """%aimport => Import modules for automatic reloading.
428 """%aimport => Import modules for automatic reloading.
425
429
426 %aimport
430 %aimport
427 List modules to automatically import and not to import.
431 List modules to automatically import and not to import.
428
432
429 %aimport foo
433 %aimport foo
430 Import module 'foo' and mark it to be autoreloaded for %autoreload 1
434 Import module 'foo' and mark it to be autoreloaded for %autoreload 1
431
435
432 %aimport -foo
436 %aimport -foo
433 Mark module 'foo' to not be autoreloaded for %autoreload 1
437 Mark module 'foo' to not be autoreloaded for %autoreload 1
434
438
435 """
439 """
436
440
437 modname = parameter_s
441 modname = parameter_s
438 if not modname:
442 if not modname:
439 to_reload = self._reloader.modules.keys()
443 to_reload = self._reloader.modules.keys()
440 to_reload.sort()
444 to_reload.sort()
441 to_skip = self._reloader.skip_modules.keys()
445 to_skip = self._reloader.skip_modules.keys()
442 to_skip.sort()
446 to_skip.sort()
443 if stream is None:
447 if stream is None:
444 stream = sys.stdout
448 stream = sys.stdout
445 if self._reloader.check_all:
449 if self._reloader.check_all:
446 stream.write("Modules to reload:\nall-except-skipped\n")
450 stream.write("Modules to reload:\nall-except-skipped\n")
447 else:
451 else:
448 stream.write("Modules to reload:\n%s\n" % ' '.join(to_reload))
452 stream.write("Modules to reload:\n%s\n" % ' '.join(to_reload))
449 stream.write("\nModules to skip:\n%s\n" % ' '.join(to_skip))
453 stream.write("\nModules to skip:\n%s\n" % ' '.join(to_skip))
450 elif modname.startswith('-'):
454 elif modname.startswith('-'):
451 modname = modname[1:]
455 modname = modname[1:]
452 self._reloader.mark_module_skipped(modname)
456 self._reloader.mark_module_skipped(modname)
453 else:
457 else:
454 top_module, top_name = self._reloader.aimport_module(modname)
458 top_module, top_name = self._reloader.aimport_module(modname)
455
459
456 # Inject module to user namespace
460 # Inject module to user namespace
457 ipself.push({top_name: top_module})
461 ipself.push({top_name: top_module})
458
462
459 def pre_run_code_hook(self, ipself):
463 def pre_run_code_hook(self, ipself):
460 if not self._reloader.enabled:
464 if not self._reloader.enabled:
461 raise TryNext
465 raise TryNext
462 try:
466 try:
463 self._reloader.check()
467 self._reloader.check()
464 except:
468 except:
465 pass
469 pass
466
470
467 class AutoreloadPlugin(AutoreloadInterface, Plugin):
471 class AutoreloadPlugin(AutoreloadInterface, Plugin):
468 def __init__(self, shell=None, config=None):
472 def __init__(self, shell=None, config=None):
469 super(AutoreloadPlugin, self).__init__(shell=shell, config=config)
473 super(AutoreloadPlugin, self).__init__(shell=shell, config=config)
470
474
471 self.shell.define_magic('autoreload', self.magic_autoreload)
475 self.shell.define_magic('autoreload', self.magic_autoreload)
472 self.shell.define_magic('aimport', self.magic_aimport)
476 self.shell.define_magic('aimport', self.magic_aimport)
473 self.shell.set_hook('pre_run_code_hook', self.pre_run_code_hook)
477 self.shell.set_hook('pre_run_code_hook', self.pre_run_code_hook)
474
478
475 _loaded = False
479 _loaded = False
476
480
477 def load_ipython_extension(ip):
481 def load_ipython_extension(ip):
478 """Load the extension in IPython."""
482 """Load the extension in IPython."""
479 global _loaded
483 global _loaded
480 if not _loaded:
484 if not _loaded:
481 plugin = AutoreloadPlugin(shell=ip, config=ip.config)
485 plugin = AutoreloadPlugin(shell=ip, config=ip.config)
482 ip.plugin_manager.register_plugin('autoreload', plugin)
486 ip.plugin_manager.register_plugin('autoreload', plugin)
483 _loaded = True
487 _loaded = True
@@ -1,147 +1,147 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Utilities for working with external processes.
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-2009 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 from __future__ import print_function
16 from __future__ import print_function
17
17
18 # Stdlib
18 # Stdlib
19 import os
19 import os
20 import sys
20 import sys
21 import shlex
21 import shlex
22
22
23 # Our own
23 # Our own
24 if sys.platform == 'win32':
24 if sys.platform == 'win32':
25 from ._process_win32 import _find_cmd, system, getoutput, AvoidUNCPath
25 from ._process_win32 import _find_cmd, system, getoutput, AvoidUNCPath
26 else:
26 else:
27 from ._process_posix import _find_cmd, system, getoutput
27 from ._process_posix import _find_cmd, system, getoutput
28
28
29 from ._process_common import getoutputerror
29 from ._process_common import getoutputerror
30 from IPython.utils import py3compat
30 from IPython.utils import py3compat
31
31
32 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
33 # Code
33 # Code
34 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
35
35
36
36
37 class FindCmdError(Exception):
37 class FindCmdError(Exception):
38 pass
38 pass
39
39
40
40
41 def find_cmd(cmd):
41 def find_cmd(cmd):
42 """Find absolute path to executable cmd in a cross platform manner.
42 """Find absolute path to executable cmd in a cross platform manner.
43
43
44 This function tries to determine the full path to a command line program
44 This function tries to determine the full path to a command line program
45 using `which` on Unix/Linux/OS X and `win32api` on Windows. Most of the
45 using `which` on Unix/Linux/OS X and `win32api` on Windows. Most of the
46 time it will use the version that is first on the users `PATH`. If
46 time it will use the version that is first on the users `PATH`. If
47 cmd is `python` return `sys.executable`.
47 cmd is `python` return `sys.executable`.
48
48
49 Warning, don't use this to find IPython command line programs as there
49 Warning, don't use this to find IPython command line programs as there
50 is a risk you will find the wrong one. Instead find those using the
50 is a risk you will find the wrong one. Instead find those using the
51 following code and looking for the application itself::
51 following code and looking for the application itself::
52
52
53 from IPython.utils.path import get_ipython_module_path
53 from IPython.utils.path import get_ipython_module_path
54 from IPython.utils.process import pycmd2argv
54 from IPython.utils.process import pycmd2argv
55 argv = pycmd2argv(get_ipython_module_path('IPython.frontend.terminal.ipapp'))
55 argv = pycmd2argv(get_ipython_module_path('IPython.frontend.terminal.ipapp'))
56
56
57 Parameters
57 Parameters
58 ----------
58 ----------
59 cmd : str
59 cmd : str
60 The command line program to look for.
60 The command line program to look for.
61 """
61 """
62 if cmd == 'python':
62 if cmd == 'python':
63 return os.path.abspath(sys.executable)
63 return os.path.abspath(sys.executable)
64 try:
64 try:
65 path = _find_cmd(cmd).rstrip()
65 path = _find_cmd(cmd).rstrip()
66 except OSError:
66 except OSError:
67 raise FindCmdError('command could not be found: %s' % cmd)
67 raise FindCmdError('command could not be found: %s' % cmd)
68 # which returns empty if not found
68 # which returns empty if not found
69 if path == b'':
69 if path == '':
70 raise FindCmdError('command could not be found: %s' % cmd)
70 raise FindCmdError('command could not be found: %s' % cmd)
71 return os.path.abspath(path)
71 return os.path.abspath(path)
72
72
73
73
74 def pycmd2argv(cmd):
74 def pycmd2argv(cmd):
75 r"""Take the path of a python command and return a list (argv-style).
75 r"""Take the path of a python command and return a list (argv-style).
76
76
77 This only works on Python based command line programs and will find the
77 This only works on Python based command line programs and will find the
78 location of the ``python`` executable using ``sys.executable`` to make
78 location of the ``python`` executable using ``sys.executable`` to make
79 sure the right version is used.
79 sure the right version is used.
80
80
81 For a given path ``cmd``, this returns [cmd] if cmd's extension is .exe,
81 For a given path ``cmd``, this returns [cmd] if cmd's extension is .exe,
82 .com or .bat, and [, cmd] otherwise.
82 .com or .bat, and [, cmd] otherwise.
83
83
84 Parameters
84 Parameters
85 ----------
85 ----------
86 cmd : string
86 cmd : string
87 The path of the command.
87 The path of the command.
88
88
89 Returns
89 Returns
90 -------
90 -------
91 argv-style list.
91 argv-style list.
92 """
92 """
93 ext = os.path.splitext(cmd)[1]
93 ext = os.path.splitext(cmd)[1]
94 if ext in ['.exe', '.com', '.bat']:
94 if ext in ['.exe', '.com', '.bat']:
95 return [cmd]
95 return [cmd]
96 else:
96 else:
97 if sys.platform == 'win32':
97 if sys.platform == 'win32':
98 # The -u option here turns on unbuffered output, which is required
98 # The -u option here turns on unbuffered output, which is required
99 # on Win32 to prevent wierd conflict and problems with Twisted.
99 # on Win32 to prevent wierd conflict and problems with Twisted.
100 # Also, use sys.executable to make sure we are picking up the
100 # Also, use sys.executable to make sure we are picking up the
101 # right python exe.
101 # right python exe.
102 return [sys.executable, '-u', cmd]
102 return [sys.executable, '-u', cmd]
103 else:
103 else:
104 return [sys.executable, cmd]
104 return [sys.executable, cmd]
105
105
106
106
107 def arg_split(s, posix=False):
107 def arg_split(s, posix=False):
108 """Split a command line's arguments in a shell-like manner.
108 """Split a command line's arguments in a shell-like manner.
109
109
110 This is a modified version of the standard library's shlex.split()
110 This is a modified version of the standard library's shlex.split()
111 function, but with a default of posix=False for splitting, so that quotes
111 function, but with a default of posix=False for splitting, so that quotes
112 in inputs are respected."""
112 in inputs are respected."""
113
113
114 # Unfortunately, python's shlex module is buggy with unicode input:
114 # Unfortunately, python's shlex module is buggy with unicode input:
115 # http://bugs.python.org/issue1170
115 # http://bugs.python.org/issue1170
116 # At least encoding the input when it's unicode seems to help, but there
116 # At least encoding the input when it's unicode seems to help, but there
117 # may be more problems lurking. Apparently this is fixed in python3.
117 # may be more problems lurking. Apparently this is fixed in python3.
118 is_unicode = False
118 is_unicode = False
119 if (not py3compat.PY3) and isinstance(s, unicode):
119 if (not py3compat.PY3) and isinstance(s, unicode):
120 is_unicode = True
120 is_unicode = True
121 s = s.encode('utf-8')
121 s = s.encode('utf-8')
122 lex = shlex.shlex(s, posix=posix)
122 lex = shlex.shlex(s, posix=posix)
123 lex.whitespace_split = True
123 lex.whitespace_split = True
124 tokens = list(lex)
124 tokens = list(lex)
125 if is_unicode:
125 if is_unicode:
126 # Convert the tokens back to unicode.
126 # Convert the tokens back to unicode.
127 tokens = [x.decode('utf-8') for x in tokens]
127 tokens = [x.decode('utf-8') for x in tokens]
128 return tokens
128 return tokens
129
129
130
130
131 def abbrev_cwd():
131 def abbrev_cwd():
132 """ Return abbreviated version of cwd, e.g. d:mydir """
132 """ Return abbreviated version of cwd, e.g. d:mydir """
133 cwd = os.getcwdu().replace('\\','/')
133 cwd = os.getcwdu().replace('\\','/')
134 drivepart = ''
134 drivepart = ''
135 tail = cwd
135 tail = cwd
136 if sys.platform == 'win32':
136 if sys.platform == 'win32':
137 if len(cwd) < 4:
137 if len(cwd) < 4:
138 return cwd
138 return cwd
139 drivepart,tail = os.path.splitdrive(cwd)
139 drivepart,tail = os.path.splitdrive(cwd)
140
140
141
141
142 parts = tail.split('/')
142 parts = tail.split('/')
143 if len(parts) > 2:
143 if len(parts) > 2:
144 tail = '/'.join(parts[-2:])
144 tail = '/'.join(parts[-2:])
145
145
146 return (drivepart + (
146 return (drivepart + (
147 cwd == '/' and '/' or tail))
147 cwd == '/' and '/' or tail))
@@ -1,98 +1,98 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Tests for platutils.py
3 Tests for platutils.py
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2009 The IPython Development Team
7 # Copyright (C) 2008-2009 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 import sys
17 import sys
18 from unittest import TestCase
18 from unittest import TestCase
19
19
20 import nose.tools as nt
20 import nose.tools as nt
21
21
22 from IPython.utils.process import (find_cmd, FindCmdError, arg_split,
22 from IPython.utils.process import (find_cmd, FindCmdError, arg_split,
23 system, getoutput, getoutputerror)
23 system, getoutput, getoutputerror)
24 from IPython.testing import decorators as dec
24 from IPython.testing import decorators as dec
25 from IPython.testing import tools as tt
25 from IPython.testing import tools as tt
26
26
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28 # Tests
28 # Tests
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30
30
31 def test_find_cmd_python():
31 def test_find_cmd_python():
32 """Make sure we find sys.exectable for python."""
32 """Make sure we find sys.exectable for python."""
33 nt.assert_equals(find_cmd('python'), sys.executable)
33 nt.assert_equals(find_cmd('python'), sys.executable)
34
34
35
35
36 @dec.skip_win32
36 @dec.skip_win32
37 def test_find_cmd_ls():
37 def test_find_cmd_ls():
38 """Make sure we can find the full path to ls."""
38 """Make sure we can find the full path to ls."""
39 path = find_cmd('ls')
39 path = find_cmd('ls')
40 nt.assert_true(path.endswith(b'ls'))
40 nt.assert_true(path.endswith('ls'))
41
41
42
42
43 def has_pywin32():
43 def has_pywin32():
44 try:
44 try:
45 import win32api
45 import win32api
46 except ImportError:
46 except ImportError:
47 return False
47 return False
48 return True
48 return True
49
49
50
50
51 @dec.onlyif(has_pywin32, "This test requires win32api to run")
51 @dec.onlyif(has_pywin32, "This test requires win32api to run")
52 def test_find_cmd_pythonw():
52 def test_find_cmd_pythonw():
53 """Try to find pythonw on Windows."""
53 """Try to find pythonw on Windows."""
54 path = find_cmd('pythonw')
54 path = find_cmd('pythonw')
55 nt.assert_true(path.endswith('pythonw.exe'))
55 nt.assert_true(path.endswith('pythonw.exe'))
56
56
57
57
58 @dec.onlyif(lambda : sys.platform != 'win32' or has_pywin32(),
58 @dec.onlyif(lambda : sys.platform != 'win32' or has_pywin32(),
59 "This test runs on posix or in win32 with win32api installed")
59 "This test runs on posix or in win32 with win32api installed")
60 def test_find_cmd_fail():
60 def test_find_cmd_fail():
61 """Make sure that FindCmdError is raised if we can't find the cmd."""
61 """Make sure that FindCmdError is raised if we can't find the cmd."""
62 nt.assert_raises(FindCmdError,find_cmd,'asdfasdf')
62 nt.assert_raises(FindCmdError,find_cmd,'asdfasdf')
63
63
64
64
65 def test_arg_split():
65 def test_arg_split():
66 """Ensure that argument lines are correctly split like in a shell."""
66 """Ensure that argument lines are correctly split like in a shell."""
67 tests = [['hi', ['hi']],
67 tests = [['hi', ['hi']],
68 [u'hi', [u'hi']],
68 [u'hi', [u'hi']],
69 ['hello there', ['hello', 'there']],
69 ['hello there', ['hello', 'there']],
70 [u'h\N{LATIN SMALL LETTER A WITH CARON}llo', [u'h\N{LATIN SMALL LETTER A WITH CARON}llo']],
70 [u'h\N{LATIN SMALL LETTER A WITH CARON}llo', [u'h\N{LATIN SMALL LETTER A WITH CARON}llo']],
71 ['something "with quotes"', ['something', '"with quotes"']],
71 ['something "with quotes"', ['something', '"with quotes"']],
72 ]
72 ]
73 for argstr, argv in tests:
73 for argstr, argv in tests:
74 nt.assert_equal(arg_split(argstr), argv)
74 nt.assert_equal(arg_split(argstr), argv)
75
75
76
76
77 class SubProcessTestCase(TestCase, tt.TempFileMixin):
77 class SubProcessTestCase(TestCase, tt.TempFileMixin):
78 def setUp(self):
78 def setUp(self):
79 """Make a valid python temp file."""
79 """Make a valid python temp file."""
80 lines = ["from __future__ import print_function",
80 lines = ["from __future__ import print_function",
81 "import sys",
81 "import sys",
82 "print('on stdout', end='', file=sys.stdout)",
82 "print('on stdout', end='', file=sys.stdout)",
83 "print('on stderr', end='', file=sys.stderr)",
83 "print('on stderr', end='', file=sys.stderr)",
84 "sys.stdout.flush()",
84 "sys.stdout.flush()",
85 "sys.stderr.flush()"]
85 "sys.stderr.flush()"]
86 self.mktmp('\n'.join(lines))
86 self.mktmp('\n'.join(lines))
87
87
88 def test_system(self):
88 def test_system(self):
89 system('python "%s"' % self.fname)
89 system('python "%s"' % self.fname)
90
90
91 def test_getoutput(self):
91 def test_getoutput(self):
92 out = getoutput('python "%s"' % self.fname)
92 out = getoutput('python "%s"' % self.fname)
93 self.assertEquals(out, 'on stdout')
93 self.assertEquals(out, 'on stdout')
94
94
95 def test_getoutput(self):
95 def test_getoutput(self):
96 out, err = getoutputerror('python "%s"' % self.fname)
96 out, err = getoutputerror('python "%s"' % self.fname)
97 self.assertEquals(out, 'on stdout')
97 self.assertEquals(out, 'on stdout')
98 self.assertEquals(err, 'on stderr')
98 self.assertEquals(err, 'on stderr')
General Comments 0
You need to be logged in to leave comments. Login now