##// END OF EJS Templates
Fix reload_extension on Python 3
Thomas Kluyver -
Show More
@@ -1,178 +1,181 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """A class for managing IPython extensions.
2 """A class for managing IPython extensions.
3
3
4 Authors:
4 Authors:
5
5
6 * Brian Granger
6 * Brian Granger
7 """
7 """
8
8
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2010-2011 The IPython Development Team
10 # Copyright (C) 2010-2011 The IPython Development Team
11 #
11 #
12 # Distributed under the terms of the BSD License. The full license is in
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
13 # the file COPYING, distributed as part of this software.
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 # Imports
17 # Imports
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 import os
20 import os
21 from shutil import copyfile
21 from shutil import copyfile
22 import sys
22 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.core.error import UsageError
27 from IPython.config.configurable import Configurable
27 from IPython.config.configurable import Configurable
28 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
29
32
30 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
31 # Main class
34 # Main class
32 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
33
36
34 class ExtensionManager(Configurable):
37 class ExtensionManager(Configurable):
35 """A class to manage IPython extensions.
38 """A class to manage IPython extensions.
36
39
37 An IPython extension is an importable Python module that has
40 An IPython extension is an importable Python module that has
38 a function with the signature::
41 a function with the signature::
39
42
40 def load_ipython_extension(ipython):
43 def load_ipython_extension(ipython):
41 # Do things with ipython
44 # Do things with ipython
42
45
43 This function is called after your extension is imported and the
46 This function is called after your extension is imported and the
44 currently active :class:`InteractiveShell` instance is passed as
47 currently active :class:`InteractiveShell` instance is passed as
45 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
46 that point, including defining new magic and aliases, adding new
49 that point, including defining new magic and aliases, adding new
47 components, etc.
50 components, etc.
48
51
49 You can also optionaly define an :func:`unload_ipython_extension(ipython)`
52 You can also optionaly define an :func:`unload_ipython_extension(ipython)`
50 function, which will be called if the user unloads or reloads the extension.
53 function, which will be called if the user unloads or reloads the extension.
51 The extension manager will only call :func:`load_ipython_extension` again
54 The extension manager will only call :func:`load_ipython_extension` again
52 if the extension is reloaded.
55 if the extension is reloaded.
53
56
54 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
55 they can be imported by Python's standard import mechanism. However,
58 they can be imported by Python's standard import mechanism. However,
56 to make it easy to write extensions, you can also put your extensions
59 to make it easy to write extensions, you can also put your extensions
57 in ``os.path.join(self.ipython_dir, 'extensions')``. This directory
60 in ``os.path.join(self.ipython_dir, 'extensions')``. This directory
58 is added to ``sys.path`` automatically.
61 is added to ``sys.path`` automatically.
59 """
62 """
60
63
61 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
64 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
62
65
63 def __init__(self, shell=None, config=None):
66 def __init__(self, shell=None, config=None):
64 super(ExtensionManager, self).__init__(shell=shell, config=config)
67 super(ExtensionManager, self).__init__(shell=shell, config=config)
65 self.shell.on_trait_change(
68 self.shell.on_trait_change(
66 self._on_ipython_dir_changed, 'ipython_dir'
69 self._on_ipython_dir_changed, 'ipython_dir'
67 )
70 )
68 self.loaded = set()
71 self.loaded = set()
69
72
70 def __del__(self):
73 def __del__(self):
71 self.shell.on_trait_change(
74 self.shell.on_trait_change(
72 self._on_ipython_dir_changed, 'ipython_dir', remove=True
75 self._on_ipython_dir_changed, 'ipython_dir', remove=True
73 )
76 )
74
77
75 @property
78 @property
76 def ipython_extension_dir(self):
79 def ipython_extension_dir(self):
77 return os.path.join(self.shell.ipython_dir, u'extensions')
80 return os.path.join(self.shell.ipython_dir, u'extensions')
78
81
79 def _on_ipython_dir_changed(self):
82 def _on_ipython_dir_changed(self):
80 if not os.path.isdir(self.ipython_extension_dir):
83 if not os.path.isdir(self.ipython_extension_dir):
81 os.makedirs(self.ipython_extension_dir, mode = 0o777)
84 os.makedirs(self.ipython_extension_dir, mode = 0o777)
82
85
83 def load_extension(self, module_str):
86 def load_extension(self, module_str):
84 """Load an IPython extension by its module name.
87 """Load an IPython extension by its module name.
85
88
86 Returns the string "already loaded" if the extension is already loaded,
89 Returns the string "already loaded" if the extension is already loaded,
87 otherwise None.
90 otherwise None.
88 """
91 """
89 if module_str in self.loaded:
92 if module_str in self.loaded:
90 return "already loaded"
93 return "already loaded"
91
94
92 from IPython.utils.syspathcontext import prepended_to_syspath
95 from IPython.utils.syspathcontext import prepended_to_syspath
93
96
94 if module_str not in sys.modules:
97 if module_str not in sys.modules:
95 with prepended_to_syspath(self.ipython_extension_dir):
98 with prepended_to_syspath(self.ipython_extension_dir):
96 __import__(module_str)
99 __import__(module_str)
97 mod = sys.modules[module_str]
100 mod = sys.modules[module_str]
98 if self._call_load_ipython_extension(mod):
101 if self._call_load_ipython_extension(mod):
99 self.loaded.add(module_str)
102 self.loaded.add(module_str)
100
103
101 def unload_extension(self, module_str):
104 def unload_extension(self, module_str):
102 """Unload an IPython extension by its module name.
105 """Unload an IPython extension by its module name.
103
106
104 This function looks up the extension's name in ``sys.modules`` and
107 This function looks up the extension's name in ``sys.modules`` and
105 simply calls ``mod.unload_ipython_extension(self)``.
108 simply calls ``mod.unload_ipython_extension(self)``.
106
109
107 Returns the string "no unload function" if the extension doesn't define
110 Returns the string "no unload function" if the extension doesn't define
108 a function to unload itself, "not loaded" if the extension isn't loaded,
111 a function to unload itself, "not loaded" if the extension isn't loaded,
109 otherwise None.
112 otherwise None.
110 """
113 """
111 if module_str not in self.loaded:
114 if module_str not in self.loaded:
112 return "not loaded"
115 return "not loaded"
113
116
114 if module_str in sys.modules:
117 if module_str in sys.modules:
115 mod = sys.modules[module_str]
118 mod = sys.modules[module_str]
116 if self._call_unload_ipython_extension(mod):
119 if self._call_unload_ipython_extension(mod):
117 self.loaded.discard(module_str)
120 self.loaded.discard(module_str)
118 else:
121 else:
119 return "no unload function"
122 return "no unload function"
120
123
121 def reload_extension(self, module_str):
124 def reload_extension(self, module_str):
122 """Reload an IPython extension by calling reload.
125 """Reload an IPython extension by calling reload.
123
126
124 If the module has not been loaded before,
127 If the module has not been loaded before,
125 :meth:`InteractiveShell.load_extension` is called. Otherwise
128 :meth:`InteractiveShell.load_extension` is called. Otherwise
126 :func:`reload` is called and then the :func:`load_ipython_extension`
129 :func:`reload` is called and then the :func:`load_ipython_extension`
127 function of the module, if it exists is called.
130 function of the module, if it exists is called.
128 """
131 """
129 from IPython.utils.syspathcontext import prepended_to_syspath
132 from IPython.utils.syspathcontext import prepended_to_syspath
130
133
131 if (module_str in self.loaded) and (module_str in sys.modules):
134 if (module_str in self.loaded) and (module_str in sys.modules):
132 self.unload_extension(module_str)
135 self.unload_extension(module_str)
133 mod = sys.modules[module_str]
136 mod = sys.modules[module_str]
134 with prepended_to_syspath(self.ipython_extension_dir):
137 with prepended_to_syspath(self.ipython_extension_dir):
135 reload(mod)
138 reload(mod)
136 if self._call_load_ipython_extension(mod):
139 if self._call_load_ipython_extension(mod):
137 self.loaded.add(module_str)
140 self.loaded.add(module_str)
138 else:
141 else:
139 self.load_extension(module_str)
142 self.load_extension(module_str)
140
143
141 def _call_load_ipython_extension(self, mod):
144 def _call_load_ipython_extension(self, mod):
142 if hasattr(mod, 'load_ipython_extension'):
145 if hasattr(mod, 'load_ipython_extension'):
143 mod.load_ipython_extension(self.shell)
146 mod.load_ipython_extension(self.shell)
144 return True
147 return True
145
148
146 def _call_unload_ipython_extension(self, mod):
149 def _call_unload_ipython_extension(self, mod):
147 if hasattr(mod, 'unload_ipython_extension'):
150 if hasattr(mod, 'unload_ipython_extension'):
148 mod.unload_ipython_extension(self.shell)
151 mod.unload_ipython_extension(self.shell)
149 return True
152 return True
150
153
151 def install_extension(self, url, filename=None):
154 def install_extension(self, url, filename=None):
152 """Download and install an IPython extension.
155 """Download and install an IPython extension.
153
156
154 If filename is given, the file will be so named (inside the extension
157 If filename is given, the file will be so named (inside the extension
155 directory). Otherwise, the name from the URL will be used. The file must
158 directory). Otherwise, the name from the URL will be used. The file must
156 have a .py or .zip extension; otherwise, a ValueError will be raised.
159 have a .py or .zip extension; otherwise, a ValueError will be raised.
157
160
158 Returns the full path to the installed file.
161 Returns the full path to the installed file.
159 """
162 """
160 # Ensure the extension directory exists
163 # Ensure the extension directory exists
161 if not os.path.isdir(self.ipython_extension_dir):
164 if not os.path.isdir(self.ipython_extension_dir):
162 os.makedirs(self.ipython_extension_dir, mode = 0o777)
165 os.makedirs(self.ipython_extension_dir, mode = 0o777)
163
166
164 if os.path.isfile(url):
167 if os.path.isfile(url):
165 src_filename = os.path.basename(url)
168 src_filename = os.path.basename(url)
166 copy = copyfile
169 copy = copyfile
167 else:
170 else:
168 src_filename = urlparse(url).path.split('/')[-1]
171 src_filename = urlparse(url).path.split('/')[-1]
169 copy = urlretrieve
172 copy = urlretrieve
170
173
171 if filename is None:
174 if filename is None:
172 filename = src_filename
175 filename = src_filename
173 if os.path.splitext(filename)[1] not in ('.py', '.zip'):
176 if os.path.splitext(filename)[1] not in ('.py', '.zip'):
174 raise ValueError("The file must have a .py or .zip extension", filename)
177 raise ValueError("The file must have a .py or .zip extension", filename)
175
178
176 filename = os.path.join(self.ipython_extension_dir, filename)
179 filename = os.path.join(self.ipython_extension_dir, filename)
177 copy(url, filename)
180 copy(url, filename)
178 return filename
181 return filename
General Comments 0
You need to be logged in to leave comments. Login now