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