##// END OF EJS Templates
hardcode builtins extensions
Matthias Bussonnier -
Show More
@@ -1,150 +1,167 b''
1 1 # encoding: utf-8
2 2 """A class for managing IPython extensions."""
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7 import os
8 8 import os.path
9 9 import sys
10 10 from importlib import import_module, reload
11 11
12 12 from traitlets.config.configurable import Configurable
13 13 from IPython.utils.path import ensure_dir_exists, compress_user
14 14 from IPython.utils.decorators import undoc
15 15 from traitlets import Instance
16 16
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Main class
20 20 #-----------------------------------------------------------------------------
21 21
22 BUILTINS_EXTS = {"storemagic": False, "autoreload": False}
23
24
22 25 class ExtensionManager(Configurable):
23 26 """A class to manage IPython extensions.
24 27
25 28 An IPython extension is an importable Python module that has
26 29 a function with the signature::
27 30
28 31 def load_ipython_extension(ipython):
29 32 # Do things with ipython
30 33
31 34 This function is called after your extension is imported and the
32 35 currently active :class:`InteractiveShell` instance is passed as
33 36 the only argument. You can do anything you want with IPython at
34 37 that point, including defining new magic and aliases, adding new
35 38 components, etc.
36 39
37 40 You can also optionally define an :func:`unload_ipython_extension(ipython)`
38 41 function, which will be called if the user unloads or reloads the extension.
39 42 The extension manager will only call :func:`load_ipython_extension` again
40 43 if the extension is reloaded.
41 44
42 45 You can put your extension modules anywhere you want, as long as
43 46 they can be imported by Python's standard import mechanism. However,
44 47 to make it easy to write extensions, you can also put your extensions
45 48 in ``os.path.join(self.ipython_dir, 'extensions')``. This directory
46 49 is added to ``sys.path`` automatically.
47 50 """
48 51
49 52 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
50 53
51 54 def __init__(self, shell=None, **kwargs):
52 55 super(ExtensionManager, self).__init__(shell=shell, **kwargs)
53 56 self.shell.observe(
54 57 self._on_ipython_dir_changed, names=('ipython_dir',)
55 58 )
56 59 self.loaded = set()
57 60
58 61 @property
59 62 def ipython_extension_dir(self):
60 63 return os.path.join(self.shell.ipython_dir, u'extensions')
61 64
62 65 def _on_ipython_dir_changed(self, change):
63 66 ensure_dir_exists(self.ipython_extension_dir)
64 67
65 def load_extension(self, module_str):
68 def load_extension(self, module_str: str):
66 69 """Load an IPython extension by its module name.
67 70
68 71 Returns the string "already loaded" if the extension is already loaded,
69 72 "no load function" if the module doesn't have a load_ipython_extension
70 73 function, or None if it succeeded.
71 74 """
75 try:
76 return self._load_extension(module_str)
77 except ModuleNotFoundError:
78 if module_str in BUILTINS_EXTS:
79 BUILTINS_EXTS[module_str] = True
80 return self._load_extension("IPython.extensions." + module_str)
81 raise
82
83 def _load_extension(self, module_str: str):
72 84 if module_str in self.loaded:
73 85 return "already loaded"
74 86
75 87 from IPython.utils.syspathcontext import prepended_to_syspath
76 88
77 89 with self.shell.builtin_trap:
78 90 if module_str not in sys.modules:
79 91 with prepended_to_syspath(self.ipython_extension_dir):
80 92 mod = import_module(module_str)
81 93 if mod.__file__.startswith(self.ipython_extension_dir):
82 94 print(("Loading extensions from {dir} is deprecated. "
83 95 "We recommend managing extensions like any "
84 96 "other Python packages, in site-packages.").format(
85 97 dir=compress_user(self.ipython_extension_dir)))
86 98 mod = sys.modules[module_str]
87 99 if self._call_load_ipython_extension(mod):
88 100 self.loaded.add(module_str)
89 101 else:
90 102 return "no load function"
91 103
92 def unload_extension(self, module_str):
104 def unload_extension(self, module_str: str):
93 105 """Unload an IPython extension by its module name.
94 106
95 107 This function looks up the extension's name in ``sys.modules`` and
96 108 simply calls ``mod.unload_ipython_extension(self)``.
97 109
98 110 Returns the string "no unload function" if the extension doesn't define
99 111 a function to unload itself, "not loaded" if the extension isn't loaded,
100 112 otherwise None.
101 113 """
114 if BUILTINS_EXTS.get(module_str, False) is True:
115 module_str = "IPython.extensions." + module_str
102 116 if module_str not in self.loaded:
103 117 return "not loaded"
104
118
105 119 if module_str in sys.modules:
106 120 mod = sys.modules[module_str]
107 121 if self._call_unload_ipython_extension(mod):
108 122 self.loaded.discard(module_str)
109 123 else:
110 124 return "no unload function"
111 125
112 def reload_extension(self, module_str):
126 def reload_extension(self, module_str: str):
113 127 """Reload an IPython extension by calling reload.
114 128
115 129 If the module has not been loaded before,
116 130 :meth:`InteractiveShell.load_extension` is called. Otherwise
117 131 :func:`reload` is called and then the :func:`load_ipython_extension`
118 132 function of the module, if it exists is called.
119 133 """
120 134 from IPython.utils.syspathcontext import prepended_to_syspath
121 135
136 if BUILTINS_EXTS.get(module_str, False) is True:
137 module_str = "IPython.extensions." + module_str
138
122 139 if (module_str in self.loaded) and (module_str in sys.modules):
123 140 self.unload_extension(module_str)
124 141 mod = sys.modules[module_str]
125 142 with prepended_to_syspath(self.ipython_extension_dir):
126 143 reload(mod)
127 144 if self._call_load_ipython_extension(mod):
128 145 self.loaded.add(module_str)
129 146 else:
130 147 self.load_extension(module_str)
131 148
132 149 def _call_load_ipython_extension(self, mod):
133 150 if hasattr(mod, 'load_ipython_extension'):
134 151 mod.load_ipython_extension(self.shell)
135 152 return True
136 153
137 154 def _call_unload_ipython_extension(self, mod):
138 155 if hasattr(mod, 'unload_ipython_extension'):
139 156 mod.unload_ipython_extension(self.shell)
140 157 return True
141 158
142 159 @undoc
143 160 def install_extension(self, url, filename=None):
144 161 """
145 162 Deprecated.
146 163 """
147 164 # Ensure the extension directory exists
148 165 raise DeprecationWarning(
149 166 '`install_extension` and the `install_ext` magic have been deprecated since IPython 4.0'
150 167 'Use pip or other package managers to manage ipython extensions.')
General Comments 0
You need to be logged in to leave comments. Login now