##// END OF EJS Templates
Much shorter deprecation message
Thomas Kluyver -
Show More
@@ -1,196 +1,179
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 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7 import os
7 import os
8 import os.path
8 import os.path
9 import warnings
9 import warnings
10 import textwrap
11 from shutil import copyfile
10 from shutil import copyfile
12 import sys
11 import sys
13 from importlib import import_module
12 from importlib import import_module
14
13
15 from traitlets.config.configurable import Configurable
14 from traitlets.config.configurable import Configurable
16 from IPython.utils.path import ensure_dir_exists
15 from IPython.utils.path import ensure_dir_exists, compress_user
17 from traitlets import Instance
16 from traitlets import Instance
18
17
19 try:
18 try:
20 from importlib import reload
19 from importlib import reload
21 except ImportError :
20 except ImportError :
22 ## deprecated since 3.4
21 ## deprecated since 3.4
23 from imp import reload
22 from imp import reload
24
23
25 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
26 # Main class
25 # Main class
27 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
28
27
29 class ExtensionManager(Configurable):
28 class ExtensionManager(Configurable):
30 """A class to manage IPython extensions.
29 """A class to manage IPython extensions.
31
30
32 An IPython extension is an importable Python module that has
31 An IPython extension is an importable Python module that has
33 a function with the signature::
32 a function with the signature::
34
33
35 def load_ipython_extension(ipython):
34 def load_ipython_extension(ipython):
36 # Do things with ipython
35 # Do things with ipython
37
36
38 This function is called after your extension is imported and the
37 This function is called after your extension is imported and the
39 currently active :class:`InteractiveShell` instance is passed as
38 currently active :class:`InteractiveShell` instance is passed as
40 the only argument. You can do anything you want with IPython at
39 the only argument. You can do anything you want with IPython at
41 that point, including defining new magic and aliases, adding new
40 that point, including defining new magic and aliases, adding new
42 components, etc.
41 components, etc.
43
42
44 You can also optionally define an :func:`unload_ipython_extension(ipython)`
43 You can also optionally define an :func:`unload_ipython_extension(ipython)`
45 function, which will be called if the user unloads or reloads the extension.
44 function, which will be called if the user unloads or reloads the extension.
46 The extension manager will only call :func:`load_ipython_extension` again
45 The extension manager will only call :func:`load_ipython_extension` again
47 if the extension is reloaded.
46 if the extension is reloaded.
48
47
49 You can put your extension modules anywhere you want, as long as
48 You can put your extension modules anywhere you want, as long as
50 they can be imported by Python's standard import mechanism. However,
49 they can be imported by Python's standard import mechanism. However,
51 to make it easy to write extensions, you can also put your extensions
50 to make it easy to write extensions, you can also put your extensions
52 in ``os.path.join(self.ipython_dir, 'extensions')``. This directory
51 in ``os.path.join(self.ipython_dir, 'extensions')``. This directory
53 is added to ``sys.path`` automatically.
52 is added to ``sys.path`` automatically.
54 """
53 """
55
54
56 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
55 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
57
56
58 def __init__(self, shell=None, **kwargs):
57 def __init__(self, shell=None, **kwargs):
59 super(ExtensionManager, self).__init__(shell=shell, **kwargs)
58 super(ExtensionManager, self).__init__(shell=shell, **kwargs)
60 self.shell.observe(
59 self.shell.observe(
61 self._on_ipython_dir_changed, names=('ipython_dir',)
60 self._on_ipython_dir_changed, names=('ipython_dir',)
62 )
61 )
63 self.loaded = set()
62 self.loaded = set()
64
63
65 @property
64 @property
66 def ipython_extension_dir(self):
65 def ipython_extension_dir(self):
67 return os.path.join(self.shell.ipython_dir, u'extensions')
66 return os.path.join(self.shell.ipython_dir, u'extensions')
68
67
69 def _on_ipython_dir_changed(self, change):
68 def _on_ipython_dir_changed(self, change):
70 ensure_dir_exists(self.ipython_extension_dir)
69 ensure_dir_exists(self.ipython_extension_dir)
71
70
72 def load_extension(self, module_str):
71 def load_extension(self, module_str):
73 """Load an IPython extension by its module name.
72 """Load an IPython extension by its module name.
74
73
75 Returns the string "already loaded" if the extension is already loaded,
74 Returns the string "already loaded" if the extension is already loaded,
76 "no load function" if the module doesn't have a load_ipython_extension
75 "no load function" if the module doesn't have a load_ipython_extension
77 function, or None if it succeeded.
76 function, or None if it succeeded.
78 """
77 """
79 if module_str in self.loaded:
78 if module_str in self.loaded:
80 return "already loaded"
79 return "already loaded"
81
80
82 from IPython.utils.syspathcontext import prepended_to_syspath
81 from IPython.utils.syspathcontext import prepended_to_syspath
83
82
84 with self.shell.builtin_trap:
83 with self.shell.builtin_trap:
85 if module_str not in sys.modules:
84 if module_str not in sys.modules:
86 with prepended_to_syspath(self.ipython_extension_dir):
85 with prepended_to_syspath(self.ipython_extension_dir):
87 mod = import_module(module_str)
86 mod = import_module(module_str)
88 if mod.__file__.startswith(self.ipython_extension_dir):
87 if mod.__file__.startswith(self.ipython_extension_dir):
89 print(textwrap.dedent(
88 print(("Loading extensions from {dir} is deprecated. "
90 """
89 "We recommend managing extensions like any "
91 Warning, you are attempting to load and IPython extensions from legacy
90 "other Python packages, in site-packages.").format(
92 location.
91 dir=compress_user(self.ipython_extension_dir)))
93
94 IPythonhas been requested to load extension `{ext}` which has been found in
95 `ipython_extension_dir` (`{dir}`).
96
97 It is likely you previously installed an extension using the `%install_ext`
98 mechanism which has been deprecated since IPython 4.0. Loading extensions
99 from the above directory is still supported but will be deprecated in a
100 future version of IPython.
101
102 Extensions should now be installed and managed as Python packages. We
103 recommend you update your extensions accordingly.
104
105 Old extensions files present in `ipython_extension_dir` may cause newly
106 installed extensions to not be recognized. Thus you may need to clean
107 the content of above mentioned directory.
108 """.format(dir=self.ipython_extension_dir, ext=module_str)))
109 mod = sys.modules[module_str]
92 mod = sys.modules[module_str]
110 if self._call_load_ipython_extension(mod):
93 if self._call_load_ipython_extension(mod):
111 self.loaded.add(module_str)
94 self.loaded.add(module_str)
112 else:
95 else:
113 return "no load function"
96 return "no load function"
114
97
115 def unload_extension(self, module_str):
98 def unload_extension(self, module_str):
116 """Unload an IPython extension by its module name.
99 """Unload an IPython extension by its module name.
117
100
118 This function looks up the extension's name in ``sys.modules`` and
101 This function looks up the extension's name in ``sys.modules`` and
119 simply calls ``mod.unload_ipython_extension(self)``.
102 simply calls ``mod.unload_ipython_extension(self)``.
120
103
121 Returns the string "no unload function" if the extension doesn't define
104 Returns the string "no unload function" if the extension doesn't define
122 a function to unload itself, "not loaded" if the extension isn't loaded,
105 a function to unload itself, "not loaded" if the extension isn't loaded,
123 otherwise None.
106 otherwise None.
124 """
107 """
125 if module_str not in self.loaded:
108 if module_str not in self.loaded:
126 return "not loaded"
109 return "not loaded"
127
110
128 if module_str in sys.modules:
111 if module_str in sys.modules:
129 mod = sys.modules[module_str]
112 mod = sys.modules[module_str]
130 if self._call_unload_ipython_extension(mod):
113 if self._call_unload_ipython_extension(mod):
131 self.loaded.discard(module_str)
114 self.loaded.discard(module_str)
132 else:
115 else:
133 return "no unload function"
116 return "no unload function"
134
117
135 def reload_extension(self, module_str):
118 def reload_extension(self, module_str):
136 """Reload an IPython extension by calling reload.
119 """Reload an IPython extension by calling reload.
137
120
138 If the module has not been loaded before,
121 If the module has not been loaded before,
139 :meth:`InteractiveShell.load_extension` is called. Otherwise
122 :meth:`InteractiveShell.load_extension` is called. Otherwise
140 :func:`reload` is called and then the :func:`load_ipython_extension`
123 :func:`reload` is called and then the :func:`load_ipython_extension`
141 function of the module, if it exists is called.
124 function of the module, if it exists is called.
142 """
125 """
143 from IPython.utils.syspathcontext import prepended_to_syspath
126 from IPython.utils.syspathcontext import prepended_to_syspath
144
127
145 if (module_str in self.loaded) and (module_str in sys.modules):
128 if (module_str in self.loaded) and (module_str in sys.modules):
146 self.unload_extension(module_str)
129 self.unload_extension(module_str)
147 mod = sys.modules[module_str]
130 mod = sys.modules[module_str]
148 with prepended_to_syspath(self.ipython_extension_dir):
131 with prepended_to_syspath(self.ipython_extension_dir):
149 reload(mod)
132 reload(mod)
150 if self._call_load_ipython_extension(mod):
133 if self._call_load_ipython_extension(mod):
151 self.loaded.add(module_str)
134 self.loaded.add(module_str)
152 else:
135 else:
153 self.load_extension(module_str)
136 self.load_extension(module_str)
154
137
155 def _call_load_ipython_extension(self, mod):
138 def _call_load_ipython_extension(self, mod):
156 if hasattr(mod, 'load_ipython_extension'):
139 if hasattr(mod, 'load_ipython_extension'):
157 mod.load_ipython_extension(self.shell)
140 mod.load_ipython_extension(self.shell)
158 return True
141 return True
159
142
160 def _call_unload_ipython_extension(self, mod):
143 def _call_unload_ipython_extension(self, mod):
161 if hasattr(mod, 'unload_ipython_extension'):
144 if hasattr(mod, 'unload_ipython_extension'):
162 mod.unload_ipython_extension(self.shell)
145 mod.unload_ipython_extension(self.shell)
163 return True
146 return True
164
147
165 def install_extension(self, url, filename=None):
148 def install_extension(self, url, filename=None):
166 """Download and install an IPython extension.
149 """Download and install an IPython extension.
167
150
168 If filename is given, the file will be so named (inside the extension
151 If filename is given, the file will be so named (inside the extension
169 directory). Otherwise, the name from the URL will be used. The file must
152 directory). Otherwise, the name from the URL will be used. The file must
170 have a .py or .zip extension; otherwise, a ValueError will be raised.
153 have a .py or .zip extension; otherwise, a ValueError will be raised.
171
154
172 Returns the full path to the installed file.
155 Returns the full path to the installed file.
173 """
156 """
174 # Ensure the extension directory exists
157 # Ensure the extension directory exists
175 ensure_dir_exists(self.ipython_extension_dir)
158 ensure_dir_exists(self.ipython_extension_dir)
176
159
177 if os.path.isfile(url):
160 if os.path.isfile(url):
178 src_filename = os.path.basename(url)
161 src_filename = os.path.basename(url)
179 copy = copyfile
162 copy = copyfile
180 else:
163 else:
181 # Deferred imports
164 # Deferred imports
182 from urllib.parse import urlparse
165 from urllib.parse import urlparse
183 from urllib.request import urlretrieve
166 from urllib.request import urlretrieve
184 src_filename = urlparse(url).path.split('/')[-1]
167 src_filename = urlparse(url).path.split('/')[-1]
185 copy = urlretrieve
168 copy = urlretrieve
186
169
187 if filename is None:
170 if filename is None:
188 filename = src_filename
171 filename = src_filename
189 if os.path.splitext(filename)[1] not in ('.py', '.zip'):
172 if os.path.splitext(filename)[1] not in ('.py', '.zip'):
190 raise ValueError("The file must have a .py or .zip extension", filename)
173 raise ValueError("The file must have a .py or .zip extension", filename)
191
174
192 filename = os.path.join(self.ipython_extension_dir, filename)
175 filename = os.path.join(self.ipython_extension_dir, filename)
193 copy(url, filename)
176 copy(url, filename)
194 return filename
177 return filename
195
178
196
179
General Comments 0
You need to be logged in to leave comments. Login now