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