##// END OF EJS Templates
Merge pull request #2462 from takluyver/extensions-loaded...
Bradley M. Froehle -
r8658:ddeb9bb3 merge
parent child Browse files
Show More
@@ -0,0 +1,73 b''
1 import os.path
2
3 import nose.tools as nt
4
5 import IPython.testing.tools as tt
6 from IPython.utils.syspathcontext import prepended_to_syspath
7 from IPython.utils.tempdir import TemporaryDirectory
8
9 ext1_content = """
10 def load_ipython_extension(ip):
11 print("Running ext1 load")
12
13 def unload_ipython_extension(ip):
14 print("Running ext1 unload")
15 """
16
17 ext2_content = """
18 def load_ipython_extension(ip):
19 print("Running ext2 load")
20 """
21
22 def test_extension_loading():
23 em = get_ipython().extension_manager
24 with TemporaryDirectory() as td:
25 ext1 = os.path.join(td, 'ext1.py')
26 with open(ext1, 'w') as f:
27 f.write(ext1_content)
28
29 ext2 = os.path.join(td, 'ext2.py')
30 with open(ext2, 'w') as f:
31 f.write(ext2_content)
32
33 with prepended_to_syspath(td):
34 assert 'ext1' not in em.loaded
35 assert 'ext2' not in em.loaded
36
37 # Load extension
38 with tt.AssertPrints("Running ext1 load"):
39 assert em.load_extension('ext1') is None
40 assert 'ext1' in em.loaded
41
42 # Should refuse to load it again
43 with tt.AssertNotPrints("Running ext1 load"):
44 assert em.load_extension('ext1') == 'already loaded'
45
46 # Reload
47 with tt.AssertPrints("Running ext1 unload"):
48 with tt.AssertPrints("Running ext1 load", suppress=False):
49 em.reload_extension('ext1')
50
51 # Unload
52 with tt.AssertPrints("Running ext1 unload"):
53 assert em.unload_extension('ext1') is None
54
55 # Can't unload again
56 with tt.AssertNotPrints("Running ext1 unload"):
57 assert em.unload_extension('ext1') == 'not loaded'
58 assert em.unload_extension('ext2') == 'not loaded'
59
60 # Load extension 2
61 with tt.AssertPrints("Running ext2 load"):
62 assert em.load_extension('ext2') is None
63
64 # Can't unload this
65 assert em.unload_extension('ext2') == 'no unload function'
66
67 # But can reload it
68 with tt.AssertPrints("Running ext2 load"):
69 em.reload_extension('ext2')
70
71 def test_non_extension():
72 em = get_ipython().extension_manager
73 nt.assert_equal(em.load_extension('sys'), "no load function")
@@ -23,8 +23,12 b' import sys'
23 from urllib import urlretrieve
23 from urllib import urlretrieve
24 from urlparse import urlparse
24 from urlparse import urlparse
25
25
26 from IPython.core.error import UsageError
26 from IPython.config.configurable import Configurable
27 from IPython.config.configurable import Configurable
27 from IPython.utils.traitlets import Instance
28 from IPython.utils.traitlets import Instance
29 from IPython.utils.py3compat import PY3
30 if PY3:
31 from imp import reload
28
32
29 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
30 # Main class
34 # Main class
@@ -44,10 +48,11 b' class ExtensionManager(Configurable):'
44 the only argument. You can do anything you want with IPython at
48 the only argument. You can do anything you want with IPython at
45 that point, including defining new magic and aliases, adding new
49 that point, including defining new magic and aliases, adding new
46 components, etc.
50 components, etc.
47
51
48 The :func:`load_ipython_extension` will be called again is you
52 You can also optionaly define an :func:`unload_ipython_extension(ipython)`
49 load or reload the extension again. It is up to the extension
53 function, which will be called if the user unloads or reloads the extension.
50 author to add code to manage that.
54 The extension manager will only call :func:`load_ipython_extension` again
55 if the extension is reloaded.
51
56
52 You can put your extension modules anywhere you want, as long as
57 You can put your extension modules anywhere you want, as long as
53 they can be imported by Python's standard import mechanism. However,
58 they can be imported by Python's standard import mechanism. However,
@@ -63,6 +68,7 b' class ExtensionManager(Configurable):'
63 self.shell.on_trait_change(
68 self.shell.on_trait_change(
64 self._on_ipython_dir_changed, 'ipython_dir'
69 self._on_ipython_dir_changed, 'ipython_dir'
65 )
70 )
71 self.loaded = set()
66
72
67 def __del__(self):
73 def __del__(self):
68 self.shell.on_trait_change(
74 self.shell.on_trait_change(
@@ -80,26 +86,43 b' class ExtensionManager(Configurable):'
80 def load_extension(self, module_str):
86 def load_extension(self, module_str):
81 """Load an IPython extension by its module name.
87 """Load an IPython extension by its module name.
82
88
83 If :func:`load_ipython_extension` returns anything, this function
89 Returns the string "already loaded" if the extension is already loaded,
84 will return that object.
90 "no load function" if the module doesn't have a load_ipython_extension
91 function, or None if it succeeded.
85 """
92 """
93 if module_str in self.loaded:
94 return "already loaded"
95
86 from IPython.utils.syspathcontext import prepended_to_syspath
96 from IPython.utils.syspathcontext import prepended_to_syspath
87
97
88 if module_str not in sys.modules:
98 if module_str not in sys.modules:
89 with prepended_to_syspath(self.ipython_extension_dir):
99 with prepended_to_syspath(self.ipython_extension_dir):
90 __import__(module_str)
100 __import__(module_str)
91 mod = sys.modules[module_str]
101 mod = sys.modules[module_str]
92 return self._call_load_ipython_extension(mod)
102 if self._call_load_ipython_extension(mod):
103 self.loaded.add(module_str)
104 else:
105 return "no load function"
93
106
94 def unload_extension(self, module_str):
107 def unload_extension(self, module_str):
95 """Unload an IPython extension by its module name.
108 """Unload an IPython extension by its module name.
96
109
97 This function looks up the extension's name in ``sys.modules`` and
110 This function looks up the extension's name in ``sys.modules`` and
98 simply calls ``mod.unload_ipython_extension(self)``.
111 simply calls ``mod.unload_ipython_extension(self)``.
112
113 Returns the string "no unload function" if the extension doesn't define
114 a function to unload itself, "not loaded" if the extension isn't loaded,
115 otherwise None.
99 """
116 """
117 if module_str not in self.loaded:
118 return "not loaded"
119
100 if module_str in sys.modules:
120 if module_str in sys.modules:
101 mod = sys.modules[module_str]
121 mod = sys.modules[module_str]
102 self._call_unload_ipython_extension(mod)
122 if self._call_unload_ipython_extension(mod):
123 self.loaded.discard(module_str)
124 else:
125 return "no unload function"
103
126
104 def reload_extension(self, module_str):
127 def reload_extension(self, module_str):
105 """Reload an IPython extension by calling reload.
128 """Reload an IPython extension by calling reload.
@@ -111,21 +134,25 b' class ExtensionManager(Configurable):'
111 """
134 """
112 from IPython.utils.syspathcontext import prepended_to_syspath
135 from IPython.utils.syspathcontext import prepended_to_syspath
113
136
114 with prepended_to_syspath(self.ipython_extension_dir):
137 if (module_str in self.loaded) and (module_str in sys.modules):
115 if module_str in sys.modules:
138 self.unload_extension(module_str)
116 mod = sys.modules[module_str]
139 mod = sys.modules[module_str]
140 with prepended_to_syspath(self.ipython_extension_dir):
117 reload(mod)
141 reload(mod)
118 self._call_load_ipython_extension(mod)
142 if self._call_load_ipython_extension(mod):
119 else:
143 self.loaded.add(module_str)
120 self.load_extension(module_str)
144 else:
145 self.load_extension(module_str)
121
146
122 def _call_load_ipython_extension(self, mod):
147 def _call_load_ipython_extension(self, mod):
123 if hasattr(mod, 'load_ipython_extension'):
148 if hasattr(mod, 'load_ipython_extension'):
124 return mod.load_ipython_extension(self.shell)
149 mod.load_ipython_extension(self.shell)
150 return True
125
151
126 def _call_unload_ipython_extension(self, mod):
152 def _call_unload_ipython_extension(self, mod):
127 if hasattr(mod, 'unload_ipython_extension'):
153 if hasattr(mod, 'unload_ipython_extension'):
128 return mod.unload_ipython_extension(self.shell)
154 mod.unload_ipython_extension(self.shell)
155 return True
129
156
130 def install_extension(self, url, filename=None):
157 def install_extension(self, url, filename=None):
131 """Download and install an IPython extension.
158 """Download and install an IPython extension.
@@ -59,14 +59,30 b' class ExtensionMagics(Magics):'
59 """Load an IPython extension by its module name."""
59 """Load an IPython extension by its module name."""
60 if not module_str:
60 if not module_str:
61 raise UsageError('Missing module name.')
61 raise UsageError('Missing module name.')
62 return self.shell.extension_manager.load_extension(module_str)
62 res = self.shell.extension_manager.load_extension(module_str)
63
64 if res == 'already loaded':
65 print "The %s extension is already loaded. To reload it, use:" % module_str
66 print " %reload_ext", module_str
67 elif res == 'no load function':
68 print "The %s module is not an IPython extension." % module_str
63
69
64 @line_magic
70 @line_magic
65 def unload_ext(self, module_str):
71 def unload_ext(self, module_str):
66 """Unload an IPython extension by its module name."""
72 """Unload an IPython extension by its module name.
73
74 Not all extensions can be unloaded, only those which define an
75 ``unload_ipython_extension`` function.
76 """
67 if not module_str:
77 if not module_str:
68 raise UsageError('Missing module name.')
78 raise UsageError('Missing module name.')
69 self.shell.extension_manager.unload_extension(module_str)
79
80 res = self.shell.extension_manager.unload_extension(module_str)
81
82 if res == 'no unload function':
83 print "The %s extension doesn't define how to unload it." % module_str
84 elif res == "not loaded":
85 print "The %s extension is not loaded." % module_str
70
86
71 @line_magic
87 @line_magic
72 def reload_ext(self, module_str):
88 def reload_ext(self, module_str):
@@ -514,14 +514,8 b' class AutoreloadMagics(Magics):'
514 pass
514 pass
515
515
516
516
517 _loaded = False
518
519
520 def load_ipython_extension(ip):
517 def load_ipython_extension(ip):
521 """Load the extension in IPython."""
518 """Load the extension in IPython."""
522 global _loaded
519 auto_reload = AutoreloadMagics(ip)
523 if not _loaded:
520 ip.register_magics(auto_reload)
524 auto_reload = AutoreloadMagics(ip)
521 ip.set_hook('pre_run_code_hook', auto_reload.pre_run_code_hook)
525 ip.register_magics(auto_reload)
526 ip.set_hook('pre_run_code_hook', auto_reload.pre_run_code_hook)
527 _loaded = True
@@ -273,11 +273,7 b' class CythonMagics(Magics):'
273 html = '\n'.join(l for l in html.splitlines() if not r.match(l))
273 html = '\n'.join(l for l in html.splitlines() if not r.match(l))
274 return html
274 return html
275
275
276 _loaded = False
277
276
278 def load_ipython_extension(ip):
277 def load_ipython_extension(ip):
279 """Load the extension in IPython."""
278 """Load the extension in IPython."""
280 global _loaded
279 ip.register_magics(CythonMagics)
281 if not _loaded:
282 ip.register_magics(CythonMagics)
283 _loaded = True
@@ -362,10 +362,6 b' __doc__ = __doc__.format('
362 )
362 )
363
363
364
364
365 _loaded = False
366 def load_ipython_extension(ip):
365 def load_ipython_extension(ip):
367 """Load the extension in IPython."""
366 """Load the extension in IPython."""
368 global _loaded
367 ip.register_magics(OctaveMagics)
369 if not _loaded:
370 ip.register_magics(OctaveMagics)
371 _loaded = True
@@ -588,10 +588,6 b' __doc__ = __doc__.format('
588 )
588 )
589
589
590
590
591 _loaded = False
592 def load_ipython_extension(ip):
591 def load_ipython_extension(ip):
593 """Load the extension in IPython."""
592 """Load the extension in IPython."""
594 global _loaded
593 ip.register_magics(RMagics)
595 if not _loaded:
596 ip.register_magics(RMagics)
597 _loaded = True
@@ -209,12 +209,6 b' class StoreMagics(Magics):'
209 print "Stored '%s' (%s)" % (args[0], obj.__class__.__name__)
209 print "Stored '%s' (%s)" % (args[0], obj.__class__.__name__)
210
210
211
211
212 _loaded = False
213
214
215 def load_ipython_extension(ip):
212 def load_ipython_extension(ip):
216 """Load the extension in IPython."""
213 """Load the extension in IPython."""
217 global _loaded
214 ip.register_magics(StoreMagics)
218 if not _loaded:
219 ip.register_magics(StoreMagics)
220 _loaded = True
General Comments 0
You need to be logged in to leave comments. Login now