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