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