##// END OF EJS Templates
Allow IPython to start when PYTHONOPTIMIZE=2...
Thomas Kluyver -
Show More
@@ -1,332 +1,334 b''
1 1 # coding: utf-8
2 2 """Compatibility tricks for Python 3. Mainly to do with unicode."""
3 3 import functools
4 4 import os
5 5 import sys
6 6 import re
7 7 import shutil
8 8 import types
9 9
10 10 from .encoding import DEFAULT_ENCODING
11 11
12 12 def no_code(x, encoding=None):
13 13 return x
14 14
15 15 def decode(s, encoding=None):
16 16 encoding = encoding or DEFAULT_ENCODING
17 17 return s.decode(encoding, "replace")
18 18
19 19 def encode(u, encoding=None):
20 20 encoding = encoding or DEFAULT_ENCODING
21 21 return u.encode(encoding, "replace")
22 22
23 23
24 24 def cast_unicode(s, encoding=None):
25 25 if isinstance(s, bytes):
26 26 return decode(s, encoding)
27 27 return s
28 28
29 29 def cast_bytes(s, encoding=None):
30 30 if not isinstance(s, bytes):
31 31 return encode(s, encoding)
32 32 return s
33 33
34 34 def buffer_to_bytes(buf):
35 35 """Cast a buffer object to bytes"""
36 36 if not isinstance(buf, bytes):
37 37 buf = bytes(buf)
38 38 return buf
39 39
40 40 def _modify_str_or_docstring(str_change_func):
41 41 @functools.wraps(str_change_func)
42 42 def wrapper(func_or_str):
43 43 if isinstance(func_or_str, string_types):
44 44 func = None
45 45 doc = func_or_str
46 46 else:
47 47 func = func_or_str
48 48 doc = func.__doc__
49 49
50 doc = str_change_func(doc)
50 # PYTHONOPTIMIZE=2 strips docstrings, so they can disappear unexpectedly
51 if doc is not None:
52 doc = str_change_func(doc)
51 53
52 54 if func:
53 55 func.__doc__ = doc
54 56 return func
55 57 return doc
56 58 return wrapper
57 59
58 60 def safe_unicode(e):
59 61 """unicode(e) with various fallbacks. Used for exceptions, which may not be
60 62 safe to call unicode() on.
61 63 """
62 64 try:
63 65 return unicode_type(e)
64 66 except UnicodeError:
65 67 pass
66 68
67 69 try:
68 70 return str_to_unicode(str(e))
69 71 except UnicodeError:
70 72 pass
71 73
72 74 try:
73 75 return str_to_unicode(repr(e))
74 76 except UnicodeError:
75 77 pass
76 78
77 79 return u'Unrecoverably corrupt evalue'
78 80
79 81 # shutil.which from Python 3.4
80 82 def _shutil_which(cmd, mode=os.F_OK | os.X_OK, path=None):
81 83 """Given a command, mode, and a PATH string, return the path which
82 84 conforms to the given mode on the PATH, or None if there is no such
83 85 file.
84 86
85 87 `mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result
86 88 of os.environ.get("PATH"), or can be overridden with a custom search
87 89 path.
88 90
89 91 This is a backport of shutil.which from Python 3.4
90 92 """
91 93 # Check that a given file can be accessed with the correct mode.
92 94 # Additionally check that `file` is not a directory, as on Windows
93 95 # directories pass the os.access check.
94 96 def _access_check(fn, mode):
95 97 return (os.path.exists(fn) and os.access(fn, mode)
96 98 and not os.path.isdir(fn))
97 99
98 100 # If we're given a path with a directory part, look it up directly rather
99 101 # than referring to PATH directories. This includes checking relative to the
100 102 # current directory, e.g. ./script
101 103 if os.path.dirname(cmd):
102 104 if _access_check(cmd, mode):
103 105 return cmd
104 106 return None
105 107
106 108 if path is None:
107 109 path = os.environ.get("PATH", os.defpath)
108 110 if not path:
109 111 return None
110 112 path = path.split(os.pathsep)
111 113
112 114 if sys.platform == "win32":
113 115 # The current directory takes precedence on Windows.
114 116 if not os.curdir in path:
115 117 path.insert(0, os.curdir)
116 118
117 119 # PATHEXT is necessary to check on Windows.
118 120 pathext = os.environ.get("PATHEXT", "").split(os.pathsep)
119 121 # See if the given file matches any of the expected path extensions.
120 122 # This will allow us to short circuit when given "python.exe".
121 123 # If it does match, only test that one, otherwise we have to try
122 124 # others.
123 125 if any(cmd.lower().endswith(ext.lower()) for ext in pathext):
124 126 files = [cmd]
125 127 else:
126 128 files = [cmd + ext for ext in pathext]
127 129 else:
128 130 # On other platforms you don't have things like PATHEXT to tell you
129 131 # what file suffixes are executable, so just pass on cmd as-is.
130 132 files = [cmd]
131 133
132 134 seen = set()
133 135 for dir in path:
134 136 normdir = os.path.normcase(dir)
135 137 if not normdir in seen:
136 138 seen.add(normdir)
137 139 for thefile in files:
138 140 name = os.path.join(dir, thefile)
139 141 if _access_check(name, mode):
140 142 return name
141 143 return None
142 144
143 145 if sys.version_info[0] >= 3:
144 146 PY3 = True
145 147
146 148 # keep reference to builtin_mod because the kernel overrides that value
147 149 # to forward requests to a frontend.
148 150 def input(prompt=''):
149 151 return builtin_mod.input(prompt)
150 152
151 153 builtin_mod_name = "builtins"
152 154 import builtins as builtin_mod
153 155
154 156 str_to_unicode = no_code
155 157 unicode_to_str = no_code
156 158 str_to_bytes = encode
157 159 bytes_to_str = decode
158 160 cast_bytes_py2 = no_code
159 161 cast_unicode_py2 = no_code
160 162 buffer_to_bytes_py2 = no_code
161 163
162 164 string_types = (str,)
163 165 unicode_type = str
164 166
165 167 which = shutil.which
166 168
167 169 def isidentifier(s, dotted=False):
168 170 if dotted:
169 171 return all(isidentifier(a) for a in s.split("."))
170 172 return s.isidentifier()
171 173
172 174 xrange = range
173 175 def iteritems(d): return iter(d.items())
174 176 def itervalues(d): return iter(d.values())
175 177 getcwd = os.getcwd
176 178
177 179 MethodType = types.MethodType
178 180
179 181 def execfile(fname, glob, loc=None, compiler=None):
180 182 loc = loc if (loc is not None) else glob
181 183 with open(fname, 'rb') as f:
182 184 compiler = compiler or compile
183 185 exec(compiler(f.read(), fname, 'exec'), glob, loc)
184 186
185 187 # Refactor print statements in doctests.
186 188 _print_statement_re = re.compile(r"\bprint (?P<expr>.*)$", re.MULTILINE)
187 189 def _print_statement_sub(match):
188 190 expr = match.groups('expr')
189 191 return "print(%s)" % expr
190 192
191 193 @_modify_str_or_docstring
192 194 def doctest_refactor_print(doc):
193 195 """Refactor 'print x' statements in a doctest to print(x) style. 2to3
194 196 unfortunately doesn't pick up on our doctests.
195 197
196 198 Can accept a string or a function, so it can be used as a decorator."""
197 199 return _print_statement_re.sub(_print_statement_sub, doc)
198 200
199 201 # Abstract u'abc' syntax:
200 202 @_modify_str_or_docstring
201 203 def u_format(s):
202 204 """"{u}'abc'" --> "'abc'" (Python 3)
203 205
204 206 Accepts a string or a function, so it can be used as a decorator."""
205 207 return s.format(u='')
206 208
207 209 def get_closure(f):
208 210 """Get a function's closure attribute"""
209 211 return f.__closure__
210 212
211 213 else:
212 214 PY3 = False
213 215
214 216 # keep reference to builtin_mod because the kernel overrides that value
215 217 # to forward requests to a frontend.
216 218 def input(prompt=''):
217 219 return builtin_mod.raw_input(prompt)
218 220
219 221 builtin_mod_name = "__builtin__"
220 222 import __builtin__ as builtin_mod
221 223
222 224 str_to_unicode = decode
223 225 unicode_to_str = encode
224 226 str_to_bytes = no_code
225 227 bytes_to_str = no_code
226 228 cast_bytes_py2 = cast_bytes
227 229 cast_unicode_py2 = cast_unicode
228 230 buffer_to_bytes_py2 = buffer_to_bytes
229 231
230 232 string_types = (str, unicode)
231 233 unicode_type = unicode
232 234
233 235 import re
234 236 _name_re = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*$")
235 237 def isidentifier(s, dotted=False):
236 238 if dotted:
237 239 return all(isidentifier(a) for a in s.split("."))
238 240 return bool(_name_re.match(s))
239 241
240 242 xrange = xrange
241 243 def iteritems(d): return d.iteritems()
242 244 def itervalues(d): return d.itervalues()
243 245 getcwd = os.getcwdu
244 246
245 247 def MethodType(func, instance):
246 248 return types.MethodType(func, instance, type(instance))
247 249
248 250 def doctest_refactor_print(func_or_str):
249 251 return func_or_str
250 252
251 253 def get_closure(f):
252 254 """Get a function's closure attribute"""
253 255 return f.func_closure
254 256
255 257 which = _shutil_which
256 258
257 259 # Abstract u'abc' syntax:
258 260 @_modify_str_or_docstring
259 261 def u_format(s):
260 262 """"{u}'abc'" --> "u'abc'" (Python 2)
261 263
262 264 Accepts a string or a function, so it can be used as a decorator."""
263 265 return s.format(u='u')
264 266
265 267 if sys.platform == 'win32':
266 268 def execfile(fname, glob=None, loc=None, compiler=None):
267 269 loc = loc if (loc is not None) else glob
268 270 scripttext = builtin_mod.open(fname).read()+ '\n'
269 271 # compile converts unicode filename to str assuming
270 272 # ascii. Let's do the conversion before calling compile
271 273 if isinstance(fname, unicode):
272 274 filename = unicode_to_str(fname)
273 275 else:
274 276 filename = fname
275 277 compiler = compiler or compile
276 278 exec(compiler(scripttext, filename, 'exec'), glob, loc)
277 279
278 280 else:
279 281 def execfile(fname, glob=None, loc=None, compiler=None):
280 282 if isinstance(fname, unicode):
281 283 filename = fname.encode(sys.getfilesystemencoding())
282 284 else:
283 285 filename = fname
284 286 where = [ns for ns in [glob, loc] if ns is not None]
285 287 if compiler is None:
286 288 builtin_mod.execfile(filename, *where)
287 289 else:
288 290 scripttext = builtin_mod.open(fname).read().rstrip() + '\n'
289 291 exec(compiler(scripttext, filename, 'exec'), glob, loc)
290 292
291 293
292 294 PY2 = not PY3
293 295
294 296
295 297 def annotate(**kwargs):
296 298 """Python 3 compatible function annotation for Python 2."""
297 299 if not kwargs:
298 300 raise ValueError('annotations must be provided as keyword arguments')
299 301 def dec(f):
300 302 if hasattr(f, '__annotations__'):
301 303 for k, v in kwargs.items():
302 304 f.__annotations__[k] = v
303 305 else:
304 306 f.__annotations__ = kwargs
305 307 return f
306 308 return dec
307 309
308 310
309 311 # Parts below taken from six:
310 312 # Copyright (c) 2010-2013 Benjamin Peterson
311 313 #
312 314 # Permission is hereby granted, free of charge, to any person obtaining a copy
313 315 # of this software and associated documentation files (the "Software"), to deal
314 316 # in the Software without restriction, including without limitation the rights
315 317 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
316 318 # copies of the Software, and to permit persons to whom the Software is
317 319 # furnished to do so, subject to the following conditions:
318 320 #
319 321 # The above copyright notice and this permission notice shall be included in all
320 322 # copies or substantial portions of the Software.
321 323 #
322 324 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
323 325 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
324 326 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
325 327 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
326 328 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
327 329 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
328 330 # SOFTWARE.
329 331
330 332 def with_metaclass(meta, *bases):
331 333 """Create a base class with a metaclass."""
332 334 return meta("_NewBase", bases, {})
General Comments 0
You need to be logged in to leave comments. Login now