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