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