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