##// END OF EJS Templates
Add a set to track what extensions are loaded.
Thomas Kluyver -
Show More
@@ -1,157 +1,162 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 Authors:
4 Authors:
5
5
6 * Brian Granger
6 * Brian Granger
7 """
7 """
8
8
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10 # Copyright (C) 2010-2011 The IPython Development Team
10 # Copyright (C) 2010-2011 The IPython Development Team
11 #
11 #
12 # Distributed under the terms of the BSD License. The full license is in
12 # Distributed under the terms of the BSD License. The full license is in
13 # the file COPYING, distributed as part of this software.
13 # the file COPYING, distributed as part of this software.
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 #-----------------------------------------------------------------------------
16 #-----------------------------------------------------------------------------
17 # Imports
17 # Imports
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 import os
20 import os
21 from shutil import copyfile
21 from shutil import copyfile
22 import sys
22 import sys
23 from urllib import urlretrieve
23 from urllib import urlretrieve
24 from urlparse import urlparse
24 from urlparse import urlparse
25
25
26 from IPython.config.configurable import Configurable
26 from IPython.config.configurable import Configurable
27 from IPython.utils.traitlets import Instance
27 from IPython.utils.traitlets import Instance
28
28
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30 # Main class
30 # Main class
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32
32
33 class ExtensionManager(Configurable):
33 class ExtensionManager(Configurable):
34 """A class to manage IPython extensions.
34 """A class to manage IPython extensions.
35
35
36 An IPython extension is an importable Python module that has
36 An IPython extension is an importable Python module that has
37 a function with the signature::
37 a function with the signature::
38
38
39 def load_ipython_extension(ipython):
39 def load_ipython_extension(ipython):
40 # Do things with ipython
40 # Do things with ipython
41
41
42 This function is called after your extension is imported and the
42 This function is called after your extension is imported and the
43 currently active :class:`InteractiveShell` instance is passed as
43 currently active :class:`InteractiveShell` instance is passed as
44 the only argument. You can do anything you want with IPython at
44 the only argument. You can do anything you want with IPython at
45 that point, including defining new magic and aliases, adding new
45 that point, including defining new magic and aliases, adding new
46 components, etc.
46 components, etc.
47
47
48 The :func:`load_ipython_extension` will be called again is you
48 The :func:`load_ipython_extension` will be called again is you
49 load or reload the extension again. It is up to the extension
49 load or reload the extension again. It is up to the extension
50 author to add code to manage that.
50 author to add code to manage that.
51
51
52 You can put your extension modules anywhere you want, as long as
52 You can put your extension modules anywhere you want, as long as
53 they can be imported by Python's standard import mechanism. However,
53 they can be imported by Python's standard import mechanism. However,
54 to make it easy to write extensions, you can also put your extensions
54 to make it easy to write extensions, you can also put your extensions
55 in ``os.path.join(self.ipython_dir, 'extensions')``. This directory
55 in ``os.path.join(self.ipython_dir, 'extensions')``. This directory
56 is added to ``sys.path`` automatically.
56 is added to ``sys.path`` automatically.
57 """
57 """
58
58
59 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
59 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
60
60
61 def __init__(self, shell=None, config=None):
61 def __init__(self, shell=None, config=None):
62 super(ExtensionManager, self).__init__(shell=shell, config=config)
62 super(ExtensionManager, self).__init__(shell=shell, config=config)
63 self.shell.on_trait_change(
63 self.shell.on_trait_change(
64 self._on_ipython_dir_changed, 'ipython_dir'
64 self._on_ipython_dir_changed, 'ipython_dir'
65 )
65 )
66 self.loaded = set()
66
67
67 def __del__(self):
68 def __del__(self):
68 self.shell.on_trait_change(
69 self.shell.on_trait_change(
69 self._on_ipython_dir_changed, 'ipython_dir', remove=True
70 self._on_ipython_dir_changed, 'ipython_dir', remove=True
70 )
71 )
71
72
72 @property
73 @property
73 def ipython_extension_dir(self):
74 def ipython_extension_dir(self):
74 return os.path.join(self.shell.ipython_dir, u'extensions')
75 return os.path.join(self.shell.ipython_dir, u'extensions')
75
76
76 def _on_ipython_dir_changed(self):
77 def _on_ipython_dir_changed(self):
77 if not os.path.isdir(self.ipython_extension_dir):
78 if not os.path.isdir(self.ipython_extension_dir):
78 os.makedirs(self.ipython_extension_dir, mode = 0o777)
79 os.makedirs(self.ipython_extension_dir, mode = 0o777)
79
80
80 def load_extension(self, module_str):
81 def load_extension(self, module_str):
81 """Load an IPython extension by its module name.
82 """Load an IPython extension by its module name.
82
83
83 If :func:`load_ipython_extension` returns anything, this function
84 If :func:`load_ipython_extension` returns anything, this function
84 will return that object.
85 will return that object.
85 """
86 """
86 from IPython.utils.syspathcontext import prepended_to_syspath
87 from IPython.utils.syspathcontext import prepended_to_syspath
87
88
88 if module_str not in sys.modules:
89 if module_str not in sys.modules:
89 with prepended_to_syspath(self.ipython_extension_dir):
90 with prepended_to_syspath(self.ipython_extension_dir):
90 __import__(module_str)
91 __import__(module_str)
91 mod = sys.modules[module_str]
92 mod = sys.modules[module_str]
92 return self._call_load_ipython_extension(mod)
93 if self._call_load_ipython_extension(mod):
94 self.loaded.add(module_str)
93
95
94 def unload_extension(self, module_str):
96 def unload_extension(self, module_str):
95 """Unload an IPython extension by its module name.
97 """Unload an IPython extension by its module name.
96
98
97 This function looks up the extension's name in ``sys.modules`` and
99 This function looks up the extension's name in ``sys.modules`` and
98 simply calls ``mod.unload_ipython_extension(self)``.
100 simply calls ``mod.unload_ipython_extension(self)``.
99 """
101 """
100 if module_str in sys.modules:
102 if module_str in sys.modules:
101 mod = sys.modules[module_str]
103 mod = sys.modules[module_str]
102 self._call_unload_ipython_extension(mod)
104 if self._call_unload_ipython_extension(mod):
105 self.loaded.discard(module_str)
103
106
104 def reload_extension(self, module_str):
107 def reload_extension(self, module_str):
105 """Reload an IPython extension by calling reload.
108 """Reload an IPython extension by calling reload.
106
109
107 If the module has not been loaded before,
110 If the module has not been loaded before,
108 :meth:`InteractiveShell.load_extension` is called. Otherwise
111 :meth:`InteractiveShell.load_extension` is called. Otherwise
109 :func:`reload` is called and then the :func:`load_ipython_extension`
112 :func:`reload` is called and then the :func:`load_ipython_extension`
110 function of the module, if it exists is called.
113 function of the module, if it exists is called.
111 """
114 """
112 from IPython.utils.syspathcontext import prepended_to_syspath
115 from IPython.utils.syspathcontext import prepended_to_syspath
113
116
114 with prepended_to_syspath(self.ipython_extension_dir):
117 with prepended_to_syspath(self.ipython_extension_dir):
115 if module_str in sys.modules:
118 if module_str in sys.modules:
116 mod = sys.modules[module_str]
119 mod = sys.modules[module_str]
117 reload(mod)
120 reload(mod)
118 self._call_load_ipython_extension(mod)
121 self._call_load_ipython_extension(mod)
119 else:
122 else:
120 self.load_extension(module_str)
123 self.load_extension(module_str)
121
124
122 def _call_load_ipython_extension(self, mod):
125 def _call_load_ipython_extension(self, mod):
123 if hasattr(mod, 'load_ipython_extension'):
126 if hasattr(mod, 'load_ipython_extension'):
124 return mod.load_ipython_extension(self.shell)
127 mod.load_ipython_extension(self.shell)
128 return True
125
129
126 def _call_unload_ipython_extension(self, mod):
130 def _call_unload_ipython_extension(self, mod):
127 if hasattr(mod, 'unload_ipython_extension'):
131 if hasattr(mod, 'unload_ipython_extension'):
128 return mod.unload_ipython_extension(self.shell)
132 mod.unload_ipython_extension(self.shell)
133 return True
129
134
130 def install_extension(self, url, filename=None):
135 def install_extension(self, url, filename=None):
131 """Download and install an IPython extension.
136 """Download and install an IPython extension.
132
137
133 If filename is given, the file will be so named (inside the extension
138 If filename is given, the file will be so named (inside the extension
134 directory). Otherwise, the name from the URL will be used. The file must
139 directory). Otherwise, the name from the URL will be used. The file must
135 have a .py or .zip extension; otherwise, a ValueError will be raised.
140 have a .py or .zip extension; otherwise, a ValueError will be raised.
136
141
137 Returns the full path to the installed file.
142 Returns the full path to the installed file.
138 """
143 """
139 # Ensure the extension directory exists
144 # Ensure the extension directory exists
140 if not os.path.isdir(self.ipython_extension_dir):
145 if not os.path.isdir(self.ipython_extension_dir):
141 os.makedirs(self.ipython_extension_dir, mode = 0o777)
146 os.makedirs(self.ipython_extension_dir, mode = 0o777)
142
147
143 if os.path.isfile(url):
148 if os.path.isfile(url):
144 src_filename = os.path.basename(url)
149 src_filename = os.path.basename(url)
145 copy = copyfile
150 copy = copyfile
146 else:
151 else:
147 src_filename = urlparse(url).path.split('/')[-1]
152 src_filename = urlparse(url).path.split('/')[-1]
148 copy = urlretrieve
153 copy = urlretrieve
149
154
150 if filename is None:
155 if filename is None:
151 filename = src_filename
156 filename = src_filename
152 if os.path.splitext(filename)[1] not in ('.py', '.zip'):
157 if os.path.splitext(filename)[1] not in ('.py', '.zip'):
153 raise ValueError("The file must have a .py or .zip extension", filename)
158 raise ValueError("The file must have a .py or .zip extension", filename)
154
159
155 filename = os.path.join(self.ipython_extension_dir, filename)
160 filename = os.path.join(self.ipython_extension_dir, filename)
156 copy(url, filename)
161 copy(url, filename)
157 return filename
162 return filename
@@ -1,76 +1,76 b''
1 """Implementation of magic functions for the extension machinery.
1 """Implementation of magic functions for the extension machinery.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2012 The IPython Development Team.
4 # Copyright (c) 2012 The IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 # Stdlib
15 # Stdlib
16 import os
16 import os
17
17
18 # Our own packages
18 # Our own packages
19 from IPython.core.error import UsageError
19 from IPython.core.error import UsageError
20 from IPython.core.magic import Magics, magics_class, line_magic
20 from IPython.core.magic import Magics, magics_class, line_magic
21
21
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 # Magic implementation classes
23 # Magic implementation classes
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26 @magics_class
26 @magics_class
27 class ExtensionMagics(Magics):
27 class ExtensionMagics(Magics):
28 """Magics to manage the IPython extensions system."""
28 """Magics to manage the IPython extensions system."""
29
29
30 @line_magic
30 @line_magic
31 def install_ext(self, parameter_s=''):
31 def install_ext(self, parameter_s=''):
32 """Download and install an extension from a URL, e.g.::
32 """Download and install an extension from a URL, e.g.::
33
33
34 %install_ext https://bitbucket.org/birkenfeld/ipython-physics/raw/d1310a2ab15d/physics.py
34 %install_ext https://bitbucket.org/birkenfeld/ipython-physics/raw/d1310a2ab15d/physics.py
35
35
36 The URL should point to an importable Python module - either a .py file
36 The URL should point to an importable Python module - either a .py file
37 or a .zip file.
37 or a .zip file.
38
38
39 Parameters:
39 Parameters:
40
40
41 -n filename : Specify a name for the file, rather than taking it from
41 -n filename : Specify a name for the file, rather than taking it from
42 the URL.
42 the URL.
43 """
43 """
44 opts, args = self.parse_options(parameter_s, 'n:')
44 opts, args = self.parse_options(parameter_s, 'n:')
45 try:
45 try:
46 filename = self.shell.extension_manager.install_extension(args,
46 filename = self.shell.extension_manager.install_extension(args,
47 opts.get('n'))
47 opts.get('n'))
48 except ValueError as e:
48 except ValueError as e:
49 print e
49 print e
50 return
50 return
51
51
52 filename = os.path.basename(filename)
52 filename = os.path.basename(filename)
53 print "Installed %s. To use it, type:" % filename
53 print "Installed %s. To use it, type:" % filename
54 print " %%load_ext %s" % os.path.splitext(filename)[0]
54 print " %%load_ext %s" % os.path.splitext(filename)[0]
55
55
56
56
57 @line_magic
57 @line_magic
58 def load_ext(self, module_str):
58 def load_ext(self, module_str):
59 """Load an IPython extension by its module name."""
59 """Load an IPython extension by its module name."""
60 if not module_str:
60 if not module_str:
61 raise UsageError('Missing module name.')
61 raise UsageError('Missing module name.')
62 return self.shell.extension_manager.load_extension(module_str)
62 self.shell.extension_manager.load_extension(module_str)
63
63
64 @line_magic
64 @line_magic
65 def unload_ext(self, module_str):
65 def unload_ext(self, module_str):
66 """Unload an IPython extension by its module name."""
66 """Unload an IPython extension by its module name."""
67 if not module_str:
67 if not module_str:
68 raise UsageError('Missing module name.')
68 raise UsageError('Missing module name.')
69 self.shell.extension_manager.unload_extension(module_str)
69 self.shell.extension_manager.unload_extension(module_str)
70
70
71 @line_magic
71 @line_magic
72 def reload_ext(self, module_str):
72 def reload_ext(self, module_str):
73 """Reload an IPython extension by its module name."""
73 """Reload an IPython extension by its module name."""
74 if not module_str:
74 if not module_str:
75 raise UsageError('Missing module name.')
75 raise UsageError('Missing module name.')
76 self.shell.extension_manager.reload_extension(module_str)
76 self.shell.extension_manager.reload_extension(module_str)
General Comments 0
You need to be logged in to leave comments. Login now