##// END OF EJS Templates
imp module deprecated in 3.4...
Matthias Bussonnier -
Show More
@@ -1,176 +1,180 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 from shutil import copyfile
9 9 import sys
10 10
11 11 from traitlets.config.configurable import Configurable
12 12 from IPython.utils.path import ensure_dir_exists
13 13 from traitlets import Instance
14 14 from IPython.utils.py3compat import PY3
15 15 if PY3:
16 from imp import reload
16 try:
17 from importlib import reload
18 except ImportError :
19 ## deprecated since 3.4
20 from imp import reload
17 21
18 22 #-----------------------------------------------------------------------------
19 23 # Main class
20 24 #-----------------------------------------------------------------------------
21 25
22 26 class ExtensionManager(Configurable):
23 27 """A class to manage IPython extensions.
24 28
25 29 An IPython extension is an importable Python module that has
26 30 a function with the signature::
27 31
28 32 def load_ipython_extension(ipython):
29 33 # Do things with ipython
30 34
31 35 This function is called after your extension is imported and the
32 36 currently active :class:`InteractiveShell` instance is passed as
33 37 the only argument. You can do anything you want with IPython at
34 38 that point, including defining new magic and aliases, adding new
35 39 components, etc.
36 40
37 41 You can also optionally define an :func:`unload_ipython_extension(ipython)`
38 42 function, which will be called if the user unloads or reloads the extension.
39 43 The extension manager will only call :func:`load_ipython_extension` again
40 44 if the extension is reloaded.
41 45
42 46 You can put your extension modules anywhere you want, as long as
43 47 they can be imported by Python's standard import mechanism. However,
44 48 to make it easy to write extensions, you can also put your extensions
45 49 in ``os.path.join(self.ipython_dir, 'extensions')``. This directory
46 50 is added to ``sys.path`` automatically.
47 51 """
48 52
49 53 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC',
50 54 allow_none=True)
51 55
52 56 def __init__(self, shell=None, **kwargs):
53 57 super(ExtensionManager, self).__init__(shell=shell, **kwargs)
54 58 self.shell.on_trait_change(
55 59 self._on_ipython_dir_changed, 'ipython_dir'
56 60 )
57 61 self.loaded = set()
58 62
59 63 def __del__(self):
60 64 self.shell.on_trait_change(
61 65 self._on_ipython_dir_changed, 'ipython_dir', remove=True
62 66 )
63 67
64 68 @property
65 69 def ipython_extension_dir(self):
66 70 return os.path.join(self.shell.ipython_dir, u'extensions')
67 71
68 72 def _on_ipython_dir_changed(self):
69 73 ensure_dir_exists(self.ipython_extension_dir)
70 74
71 75 def load_extension(self, module_str):
72 76 """Load an IPython extension by its module name.
73 77
74 78 Returns the string "already loaded" if the extension is already loaded,
75 79 "no load function" if the module doesn't have a load_ipython_extension
76 80 function, or None if it succeeded.
77 81 """
78 82 if module_str in self.loaded:
79 83 return "already loaded"
80 84
81 85 from IPython.utils.syspathcontext import prepended_to_syspath
82 86
83 87 with self.shell.builtin_trap:
84 88 if module_str not in sys.modules:
85 89 with prepended_to_syspath(self.ipython_extension_dir):
86 90 __import__(module_str)
87 91 mod = sys.modules[module_str]
88 92 if self._call_load_ipython_extension(mod):
89 93 self.loaded.add(module_str)
90 94 else:
91 95 return "no load function"
92 96
93 97 def unload_extension(self, module_str):
94 98 """Unload an IPython extension by its module name.
95 99
96 100 This function looks up the extension's name in ``sys.modules`` and
97 101 simply calls ``mod.unload_ipython_extension(self)``.
98 102
99 103 Returns the string "no unload function" if the extension doesn't define
100 104 a function to unload itself, "not loaded" if the extension isn't loaded,
101 105 otherwise None.
102 106 """
103 107 if module_str not in self.loaded:
104 108 return "not loaded"
105 109
106 110 if module_str in sys.modules:
107 111 mod = sys.modules[module_str]
108 112 if self._call_unload_ipython_extension(mod):
109 113 self.loaded.discard(module_str)
110 114 else:
111 115 return "no unload function"
112 116
113 117 def reload_extension(self, module_str):
114 118 """Reload an IPython extension by calling reload.
115 119
116 120 If the module has not been loaded before,
117 121 :meth:`InteractiveShell.load_extension` is called. Otherwise
118 122 :func:`reload` is called and then the :func:`load_ipython_extension`
119 123 function of the module, if it exists is called.
120 124 """
121 125 from IPython.utils.syspathcontext import prepended_to_syspath
122 126
123 127 if (module_str in self.loaded) and (module_str in sys.modules):
124 128 self.unload_extension(module_str)
125 129 mod = sys.modules[module_str]
126 130 with prepended_to_syspath(self.ipython_extension_dir):
127 131 reload(mod)
128 132 if self._call_load_ipython_extension(mod):
129 133 self.loaded.add(module_str)
130 134 else:
131 135 self.load_extension(module_str)
132 136
133 137 def _call_load_ipython_extension(self, mod):
134 138 if hasattr(mod, 'load_ipython_extension'):
135 139 mod.load_ipython_extension(self.shell)
136 140 return True
137 141
138 142 def _call_unload_ipython_extension(self, mod):
139 143 if hasattr(mod, 'unload_ipython_extension'):
140 144 mod.unload_ipython_extension(self.shell)
141 145 return True
142 146
143 147 def install_extension(self, url, filename=None):
144 148 """Download and install an IPython extension.
145 149
146 150 If filename is given, the file will be so named (inside the extension
147 151 directory). Otherwise, the name from the URL will be used. The file must
148 152 have a .py or .zip extension; otherwise, a ValueError will be raised.
149 153
150 154 Returns the full path to the installed file.
151 155 """
152 156 # Ensure the extension directory exists
153 157 ensure_dir_exists(self.ipython_extension_dir)
154 158
155 159 if os.path.isfile(url):
156 160 src_filename = os.path.basename(url)
157 161 copy = copyfile
158 162 else:
159 163 # Deferred imports
160 164 try:
161 165 from urllib.parse import urlparse # Py3
162 166 from urllib.request import urlretrieve
163 167 except ImportError:
164 168 from urlparse import urlparse
165 169 from urllib import urlretrieve
166 170 src_filename = urlparse(url).path.split('/')[-1]
167 171 copy = urlretrieve
168 172
169 173 if filename is None:
170 174 filename = src_filename
171 175 if os.path.splitext(filename)[1] not in ('.py', '.zip'):
172 176 raise ValueError("The file must have a .py or .zip extension", filename)
173 177
174 178 filename = os.path.join(self.ipython_extension_dir, filename)
175 179 copy(url, filename)
176 180 return filename
@@ -1,245 +1,249 b''
1 1 """
2 2 Tools to open .py files as Unicode, using the encoding specified within the file,
3 3 as per PEP 263.
4 4
5 5 Much of the code is taken from the tokenize module in Python 3.2.
6 6 """
7 7 from __future__ import absolute_import
8 8
9 9 import io
10 10 from io import TextIOWrapper, BytesIO
11 11 import os.path
12 12 import re
13 13
14 14 from .py3compat import unicode_type
15 15
16 16 cookie_re = re.compile(r"coding[:=]\s*([-\w.]+)", re.UNICODE)
17 17 cookie_comment_re = re.compile(r"^\s*#.*coding[:=]\s*([-\w.]+)", re.UNICODE)
18 18
19 19 try:
20 20 # Available in Python 3
21 21 from tokenize import detect_encoding
22 22 except ImportError:
23 23 from codecs import lookup, BOM_UTF8
24 24
25 25 # Copied from Python 3.2 tokenize
26 26 def _get_normal_name(orig_enc):
27 27 """Imitates get_normal_name in tokenizer.c."""
28 28 # Only care about the first 12 characters.
29 29 enc = orig_enc[:12].lower().replace("_", "-")
30 30 if enc == "utf-8" or enc.startswith("utf-8-"):
31 31 return "utf-8"
32 32 if enc in ("latin-1", "iso-8859-1", "iso-latin-1") or \
33 33 enc.startswith(("latin-1-", "iso-8859-1-", "iso-latin-1-")):
34 34 return "iso-8859-1"
35 35 return orig_enc
36 36
37 37 # Copied from Python 3.2 tokenize
38 38 def detect_encoding(readline):
39 39 """
40 40 The detect_encoding() function is used to detect the encoding that should
41 41 be used to decode a Python source file. It requires one argment, readline,
42 42 in the same way as the tokenize() generator.
43 43
44 44 It will call readline a maximum of twice, and return the encoding used
45 45 (as a string) and a list of any lines (left as bytes) it has read in.
46 46
47 47 It detects the encoding from the presence of a utf-8 bom or an encoding
48 48 cookie as specified in pep-0263. If both a bom and a cookie are present,
49 49 but disagree, a SyntaxError will be raised. If the encoding cookie is an
50 50 invalid charset, raise a SyntaxError. Note that if a utf-8 bom is found,
51 51 'utf-8-sig' is returned.
52 52
53 53 If no encoding is specified, then the default of 'utf-8' will be returned.
54 54 """
55 55 bom_found = False
56 56 encoding = None
57 57 default = 'utf-8'
58 58 def read_or_stop():
59 59 try:
60 60 return readline()
61 61 except StopIteration:
62 62 return b''
63 63
64 64 def find_cookie(line):
65 65 try:
66 66 line_string = line.decode('ascii')
67 67 except UnicodeDecodeError:
68 68 return None
69 69
70 70 matches = cookie_re.findall(line_string)
71 71 if not matches:
72 72 return None
73 73 encoding = _get_normal_name(matches[0])
74 74 try:
75 75 codec = lookup(encoding)
76 76 except LookupError:
77 77 # This behaviour mimics the Python interpreter
78 78 raise SyntaxError("unknown encoding: " + encoding)
79 79
80 80 if bom_found:
81 81 if codec.name != 'utf-8':
82 82 # This behaviour mimics the Python interpreter
83 83 raise SyntaxError('encoding problem: utf-8')
84 84 encoding += '-sig'
85 85 return encoding
86 86
87 87 first = read_or_stop()
88 88 if first.startswith(BOM_UTF8):
89 89 bom_found = True
90 90 first = first[3:]
91 91 default = 'utf-8-sig'
92 92 if not first:
93 93 return default, []
94 94
95 95 encoding = find_cookie(first)
96 96 if encoding:
97 97 return encoding, [first]
98 98
99 99 second = read_or_stop()
100 100 if not second:
101 101 return default, [first]
102 102
103 103 encoding = find_cookie(second)
104 104 if encoding:
105 105 return encoding, [first, second]
106 106
107 107 return default, [first, second]
108 108
109 109 try:
110 110 # Available in Python 3.2 and above.
111 111 from tokenize import open
112 112 except ImportError:
113 113 # Copied from Python 3.2 tokenize
114 114 def open(filename):
115 115 """Open a file in read only mode using the encoding detected by
116 116 detect_encoding().
117 117 """
118 118 buffer = io.open(filename, 'rb') # Tweaked to use io.open for Python 2
119 119 encoding, lines = detect_encoding(buffer.readline)
120 120 buffer.seek(0)
121 121 text = TextIOWrapper(buffer, encoding, line_buffering=True)
122 122 text.mode = 'r'
123 123 return text
124 124
125 125 def source_to_unicode(txt, errors='replace', skip_encoding_cookie=True):
126 126 """Converts a bytes string with python source code to unicode.
127 127
128 128 Unicode strings are passed through unchanged. Byte strings are checked
129 129 for the python source file encoding cookie to determine encoding.
130 130 txt can be either a bytes buffer or a string containing the source
131 131 code.
132 132 """
133 133 if isinstance(txt, unicode_type):
134 134 return txt
135 135 if isinstance(txt, bytes):
136 136 buffer = BytesIO(txt)
137 137 else:
138 138 buffer = txt
139 139 try:
140 140 encoding, _ = detect_encoding(buffer.readline)
141 141 except SyntaxError:
142 142 encoding = "ascii"
143 143 buffer.seek(0)
144 144 text = TextIOWrapper(buffer, encoding, errors=errors, line_buffering=True)
145 145 text.mode = 'r'
146 146 if skip_encoding_cookie:
147 147 return u"".join(strip_encoding_cookie(text))
148 148 else:
149 149 return text.read()
150 150
151 151 def strip_encoding_cookie(filelike):
152 152 """Generator to pull lines from a text-mode file, skipping the encoding
153 153 cookie if it is found in the first two lines.
154 154 """
155 155 it = iter(filelike)
156 156 try:
157 157 first = next(it)
158 158 if not cookie_comment_re.match(first):
159 159 yield first
160 160 second = next(it)
161 161 if not cookie_comment_re.match(second):
162 162 yield second
163 163 except StopIteration:
164 164 return
165 165
166 166 for line in it:
167 167 yield line
168 168
169 169 def read_py_file(filename, skip_encoding_cookie=True):
170 170 """Read a Python file, using the encoding declared inside the file.
171 171
172 172 Parameters
173 173 ----------
174 174 filename : str
175 175 The path to the file to read.
176 176 skip_encoding_cookie : bool
177 177 If True (the default), and the encoding declaration is found in the first
178 178 two lines, that line will be excluded from the output - compiling a
179 179 unicode string with an encoding declaration is a SyntaxError in Python 2.
180 180
181 181 Returns
182 182 -------
183 183 A unicode string containing the contents of the file.
184 184 """
185 185 with open(filename) as f: # the open function defined in this module.
186 186 if skip_encoding_cookie:
187 187 return "".join(strip_encoding_cookie(f))
188 188 else:
189 189 return f.read()
190 190
191 191 def read_py_url(url, errors='replace', skip_encoding_cookie=True):
192 192 """Read a Python file from a URL, using the encoding declared inside the file.
193 193
194 194 Parameters
195 195 ----------
196 196 url : str
197 197 The URL from which to fetch the file.
198 198 errors : str
199 199 How to handle decoding errors in the file. Options are the same as for
200 200 bytes.decode(), but here 'replace' is the default.
201 201 skip_encoding_cookie : bool
202 202 If True (the default), and the encoding declaration is found in the first
203 203 two lines, that line will be excluded from the output - compiling a
204 204 unicode string with an encoding declaration is a SyntaxError in Python 2.
205 205
206 206 Returns
207 207 -------
208 208 A unicode string containing the contents of the file.
209 209 """
210 210 # Deferred import for faster start
211 211 try:
212 212 from urllib.request import urlopen # Py 3
213 213 except ImportError:
214 214 from urllib import urlopen
215 215 response = urlopen(url)
216 216 buffer = io.BytesIO(response.read())
217 217 return source_to_unicode(buffer, errors, skip_encoding_cookie)
218 218
219 219 def _list_readline(x):
220 220 """Given a list, returns a readline() function that returns the next element
221 221 with each call.
222 222 """
223 223 x = iter(x)
224 224 def readline():
225 225 return next(x)
226 226 return readline
227 227
228 228 # Code for going between .py files and cached .pyc files ----------------------
229 229
230 230 try: # Python 3.2, see PEP 3147
231 from imp import source_from_cache, cache_from_source
231 try:
232 from importlib.util import source_from_cache, cache_from_source
233 except ImportError :
234 ## deprecated since 3.4
235 from imp import source_from_cache, cache_from_source
232 236 except ImportError:
233 237 # Python <= 3.1: .pyc files go next to .py
234 238 def source_from_cache(path):
235 239 basename, ext = os.path.splitext(path)
236 240 if ext not in ('.pyc', '.pyo'):
237 241 raise ValueError('Not a cached Python file extension', ext)
238 242 # Should we look for .pyw files?
239 243 return basename + '.py'
240 244
241 245 def cache_from_source(path, debug_override=None):
242 246 if debug_override is None:
243 247 debug_override = __debug__
244 248 basename, ext = os.path.splitext(path)
245 249 return basename + '.pyc' if debug_override else '.pyo'
General Comments 0
You need to be logged in to leave comments. Login now