##// END OF EJS Templates
Update IPython/core/extensions.py to the new traitlets API
Matthias Bussonnier -
Show More
@@ -1,174 +1,174 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',
52 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC').tag(
53 allow_none=True)
53 allow_none=True)
54
54
55 def __init__(self, shell=None, **kwargs):
55 def __init__(self, shell=None, **kwargs):
56 super(ExtensionManager, self).__init__(shell=shell, **kwargs)
56 super(ExtensionManager, self).__init__(shell=shell, **kwargs)
57 self.shell.on_trait_change(
57 self.shell.observe(
58 self._on_ipython_dir_changed, 'ipython_dir'
58 self._on_ipython_dir_changed, names=('ipython_dir',)
59 )
59 )
60 self.loaded = set()
60 self.loaded = set()
61
61
62 @property
62 @property
63 def ipython_extension_dir(self):
63 def ipython_extension_dir(self):
64 return os.path.join(self.shell.ipython_dir, u'extensions')
64 return os.path.join(self.shell.ipython_dir, u'extensions')
65
65
66 def _on_ipython_dir_changed(self):
66 def _on_ipython_dir_changed(self, change):
67 ensure_dir_exists(self.ipython_extension_dir)
67 ensure_dir_exists(self.ipython_extension_dir)
68
68
69 def load_extension(self, module_str):
69 def load_extension(self, module_str):
70 """Load an IPython extension by its module name.
70 """Load an IPython extension by its module name.
71
71
72 Returns the string "already loaded" if the extension is already loaded,
72 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
73 "no load function" if the module doesn't have a load_ipython_extension
74 function, or None if it succeeded.
74 function, or None if it succeeded.
75 """
75 """
76 if module_str in self.loaded:
76 if module_str in self.loaded:
77 return "already loaded"
77 return "already loaded"
78
78
79 from IPython.utils.syspathcontext import prepended_to_syspath
79 from IPython.utils.syspathcontext import prepended_to_syspath
80
80
81 with self.shell.builtin_trap:
81 with self.shell.builtin_trap:
82 if module_str not in sys.modules:
82 if module_str not in sys.modules:
83 with prepended_to_syspath(self.ipython_extension_dir):
83 with prepended_to_syspath(self.ipython_extension_dir):
84 __import__(module_str)
84 __import__(module_str)
85 mod = sys.modules[module_str]
85 mod = sys.modules[module_str]
86 if self._call_load_ipython_extension(mod):
86 if self._call_load_ipython_extension(mod):
87 self.loaded.add(module_str)
87 self.loaded.add(module_str)
88 else:
88 else:
89 return "no load function"
89 return "no load function"
90
90
91 def unload_extension(self, module_str):
91 def unload_extension(self, module_str):
92 """Unload an IPython extension by its module name.
92 """Unload an IPython extension by its module name.
93
93
94 This function looks up the extension's name in ``sys.modules`` and
94 This function looks up the extension's name in ``sys.modules`` and
95 simply calls ``mod.unload_ipython_extension(self)``.
95 simply calls ``mod.unload_ipython_extension(self)``.
96
96
97 Returns the string "no unload function" if the extension doesn't define
97 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,
98 a function to unload itself, "not loaded" if the extension isn't loaded,
99 otherwise None.
99 otherwise None.
100 """
100 """
101 if module_str not in self.loaded:
101 if module_str not in self.loaded:
102 return "not loaded"
102 return "not loaded"
103
103
104 if module_str in sys.modules:
104 if module_str in sys.modules:
105 mod = sys.modules[module_str]
105 mod = sys.modules[module_str]
106 if self._call_unload_ipython_extension(mod):
106 if self._call_unload_ipython_extension(mod):
107 self.loaded.discard(module_str)
107 self.loaded.discard(module_str)
108 else:
108 else:
109 return "no unload function"
109 return "no unload function"
110
110
111 def reload_extension(self, module_str):
111 def reload_extension(self, module_str):
112 """Reload an IPython extension by calling reload.
112 """Reload an IPython extension by calling reload.
113
113
114 If the module has not been loaded before,
114 If the module has not been loaded before,
115 :meth:`InteractiveShell.load_extension` is called. Otherwise
115 :meth:`InteractiveShell.load_extension` is called. Otherwise
116 :func:`reload` is called and then the :func:`load_ipython_extension`
116 :func:`reload` is called and then the :func:`load_ipython_extension`
117 function of the module, if it exists is called.
117 function of the module, if it exists is called.
118 """
118 """
119 from IPython.utils.syspathcontext import prepended_to_syspath
119 from IPython.utils.syspathcontext import prepended_to_syspath
120
120
121 if (module_str in self.loaded) and (module_str in sys.modules):
121 if (module_str in self.loaded) and (module_str in sys.modules):
122 self.unload_extension(module_str)
122 self.unload_extension(module_str)
123 mod = sys.modules[module_str]
123 mod = sys.modules[module_str]
124 with prepended_to_syspath(self.ipython_extension_dir):
124 with prepended_to_syspath(self.ipython_extension_dir):
125 reload(mod)
125 reload(mod)
126 if self._call_load_ipython_extension(mod):
126 if self._call_load_ipython_extension(mod):
127 self.loaded.add(module_str)
127 self.loaded.add(module_str)
128 else:
128 else:
129 self.load_extension(module_str)
129 self.load_extension(module_str)
130
130
131 def _call_load_ipython_extension(self, mod):
131 def _call_load_ipython_extension(self, mod):
132 if hasattr(mod, 'load_ipython_extension'):
132 if hasattr(mod, 'load_ipython_extension'):
133 mod.load_ipython_extension(self.shell)
133 mod.load_ipython_extension(self.shell)
134 return True
134 return True
135
135
136 def _call_unload_ipython_extension(self, mod):
136 def _call_unload_ipython_extension(self, mod):
137 if hasattr(mod, 'unload_ipython_extension'):
137 if hasattr(mod, 'unload_ipython_extension'):
138 mod.unload_ipython_extension(self.shell)
138 mod.unload_ipython_extension(self.shell)
139 return True
139 return True
140
140
141 def install_extension(self, url, filename=None):
141 def install_extension(self, url, filename=None):
142 """Download and install an IPython extension.
142 """Download and install an IPython extension.
143
143
144 If filename is given, the file will be so named (inside the extension
144 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
145 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.
146 have a .py or .zip extension; otherwise, a ValueError will be raised.
147
147
148 Returns the full path to the installed file.
148 Returns the full path to the installed file.
149 """
149 """
150 # Ensure the extension directory exists
150 # Ensure the extension directory exists
151 ensure_dir_exists(self.ipython_extension_dir)
151 ensure_dir_exists(self.ipython_extension_dir)
152
152
153 if os.path.isfile(url):
153 if os.path.isfile(url):
154 src_filename = os.path.basename(url)
154 src_filename = os.path.basename(url)
155 copy = copyfile
155 copy = copyfile
156 else:
156 else:
157 # Deferred imports
157 # Deferred imports
158 try:
158 try:
159 from urllib.parse import urlparse # Py3
159 from urllib.parse import urlparse # Py3
160 from urllib.request import urlretrieve
160 from urllib.request import urlretrieve
161 except ImportError:
161 except ImportError:
162 from urlparse import urlparse
162 from urlparse import urlparse
163 from urllib import urlretrieve
163 from urllib import urlretrieve
164 src_filename = urlparse(url).path.split('/')[-1]
164 src_filename = urlparse(url).path.split('/')[-1]
165 copy = urlretrieve
165 copy = urlretrieve
166
166
167 if filename is None:
167 if filename is None:
168 filename = src_filename
168 filename = src_filename
169 if os.path.splitext(filename)[1] not in ('.py', '.zip'):
169 if os.path.splitext(filename)[1] not in ('.py', '.zip'):
170 raise ValueError("The file must have a .py or .zip extension", filename)
170 raise ValueError("The file must have a .py or .zip extension", filename)
171
171
172 filename = os.path.join(self.ipython_extension_dir, filename)
172 filename = os.path.join(self.ipython_extension_dir, filename)
173 copy(url, filename)
173 copy(url, filename)
174 return filename
174 return filename
General Comments 0
You need to be logged in to leave comments. Login now