##// END OF EJS Templates
add py3compat.get_closure...
MinRK -
Show More
@@ -1,264 +1,271 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 types
8 8
9 9 from .encoding import DEFAULT_ENCODING
10 10
11 11 orig_open = open
12 12
13 13 def no_code(x, encoding=None):
14 14 return x
15 15
16 16 def decode(s, encoding=None):
17 17 encoding = encoding or DEFAULT_ENCODING
18 18 return s.decode(encoding, "replace")
19 19
20 20 def encode(u, encoding=None):
21 21 encoding = encoding or DEFAULT_ENCODING
22 22 return u.encode(encoding, "replace")
23 23
24 24
25 25 def cast_unicode(s, encoding=None):
26 26 if isinstance(s, bytes):
27 27 return decode(s, encoding)
28 28 return s
29 29
30 30 def cast_bytes(s, encoding=None):
31 31 if not isinstance(s, bytes):
32 32 return encode(s, encoding)
33 33 return s
34 34
35 35 def _modify_str_or_docstring(str_change_func):
36 36 @functools.wraps(str_change_func)
37 37 def wrapper(func_or_str):
38 38 if isinstance(func_or_str, string_types):
39 39 func = None
40 40 doc = func_or_str
41 41 else:
42 42 func = func_or_str
43 43 doc = func.__doc__
44 44
45 45 doc = str_change_func(doc)
46 46
47 47 if func:
48 48 func.__doc__ = doc
49 49 return func
50 50 return doc
51 51 return wrapper
52 52
53 53 def safe_unicode(e):
54 54 """unicode(e) with various fallbacks. Used for exceptions, which may not be
55 55 safe to call unicode() on.
56 56 """
57 57 try:
58 58 return unicode_type(e)
59 59 except UnicodeError:
60 60 pass
61 61
62 62 try:
63 63 return str_to_unicode(str(e))
64 64 except UnicodeError:
65 65 pass
66 66
67 67 try:
68 68 return str_to_unicode(repr(e))
69 69 except UnicodeError:
70 70 pass
71 71
72 72 return u'Unrecoverably corrupt evalue'
73 73
74 74 if sys.version_info[0] >= 3:
75 75 PY3 = True
76 76
77 77 # keep reference to builtin_mod because the kernel overrides that value
78 78 # to forward requests to a frontend.
79 79 def input(prompt=''):
80 80 return builtin_mod.input(prompt)
81 81
82 82 builtin_mod_name = "builtins"
83 83 import builtins as builtin_mod
84 84
85 85 str_to_unicode = no_code
86 86 unicode_to_str = no_code
87 87 str_to_bytes = encode
88 88 bytes_to_str = decode
89 89 cast_bytes_py2 = no_code
90 90 cast_unicode_py2 = no_code
91 91
92 92 string_types = (str,)
93 93 unicode_type = str
94 94
95 95 def isidentifier(s, dotted=False):
96 96 if dotted:
97 97 return all(isidentifier(a) for a in s.split("."))
98 98 return s.isidentifier()
99 99
100 100 open = orig_open
101 101 xrange = range
102 102 def iteritems(d): return iter(d.items())
103 103 def itervalues(d): return iter(d.values())
104 104 getcwd = os.getcwd
105 105
106 106 MethodType = types.MethodType
107 107
108 108 def execfile(fname, glob, loc=None):
109 109 loc = loc if (loc is not None) else glob
110 110 with open(fname, 'rb') as f:
111 111 exec(compile(f.read(), fname, 'exec'), glob, loc)
112 112
113 113 # Refactor print statements in doctests.
114 114 _print_statement_re = re.compile(r"\bprint (?P<expr>.*)$", re.MULTILINE)
115 115 def _print_statement_sub(match):
116 116 expr = match.groups('expr')
117 117 return "print(%s)" % expr
118 118
119 119 @_modify_str_or_docstring
120 120 def doctest_refactor_print(doc):
121 121 """Refactor 'print x' statements in a doctest to print(x) style. 2to3
122 122 unfortunately doesn't pick up on our doctests.
123 123
124 124 Can accept a string or a function, so it can be used as a decorator."""
125 125 return _print_statement_re.sub(_print_statement_sub, doc)
126 126
127 127 # Abstract u'abc' syntax:
128 128 @_modify_str_or_docstring
129 129 def u_format(s):
130 130 """"{u}'abc'" --> "'abc'" (Python 3)
131 131
132 132 Accepts a string or a function, so it can be used as a decorator."""
133 133 return s.format(u='')
134
135 def get_closure(f):
136 """Get a function's closure attribute"""
137 return f.__closure__
134 138
135 139 else:
136 140 PY3 = False
137 141
138 142 # keep reference to builtin_mod because the kernel overrides that value
139 143 # to forward requests to a frontend.
140 144 def input(prompt=''):
141 145 return builtin_mod.raw_input(prompt)
142 146
143 147 builtin_mod_name = "__builtin__"
144 148 import __builtin__ as builtin_mod
145 149
146 150 str_to_unicode = decode
147 151 unicode_to_str = encode
148 152 str_to_bytes = no_code
149 153 bytes_to_str = no_code
150 154 cast_bytes_py2 = cast_bytes
151 155 cast_unicode_py2 = cast_unicode
152 156
153 157 string_types = (str, unicode)
154 158 unicode_type = unicode
155 159
156 160 import re
157 161 _name_re = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*$")
158 162 def isidentifier(s, dotted=False):
159 163 if dotted:
160 164 return all(isidentifier(a) for a in s.split("."))
161 165 return bool(_name_re.match(s))
162 166
163 167 class open(object):
164 168 """Wrapper providing key part of Python 3 open() interface."""
165 169 def __init__(self, fname, mode="r", encoding="utf-8"):
166 170 self.f = orig_open(fname, mode)
167 171 self.enc = encoding
168 172
169 173 def write(self, s):
170 174 return self.f.write(s.encode(self.enc))
171 175
172 176 def read(self, size=-1):
173 177 return self.f.read(size).decode(self.enc)
174 178
175 179 def close(self):
176 180 return self.f.close()
177 181
178 182 def __enter__(self):
179 183 return self
180 184
181 185 def __exit__(self, etype, value, traceback):
182 186 self.f.close()
183 187
184 188 xrange = xrange
185 189 def iteritems(d): return d.iteritems()
186 190 def itervalues(d): return d.itervalues()
187 191 getcwd = os.getcwdu
188 192
189 193 def MethodType(func, instance):
190 194 return types.MethodType(func, instance, type(instance))
191 195
192 196 def doctest_refactor_print(func_or_str):
193 197 return func_or_str
194 198
199 def get_closure(f):
200 """Get a function's closure attribute"""
201 return f.func_closure
195 202
196 203 # Abstract u'abc' syntax:
197 204 @_modify_str_or_docstring
198 205 def u_format(s):
199 206 """"{u}'abc'" --> "u'abc'" (Python 2)
200 207
201 208 Accepts a string or a function, so it can be used as a decorator."""
202 209 return s.format(u='u')
203 210
204 211 if sys.platform == 'win32':
205 212 def execfile(fname, glob=None, loc=None):
206 213 loc = loc if (loc is not None) else glob
207 214 # The rstrip() is necessary b/c trailing whitespace in files will
208 215 # cause an IndentationError in Python 2.6 (this was fixed in 2.7,
209 216 # but we still support 2.6). See issue 1027.
210 217 scripttext = builtin_mod.open(fname).read().rstrip() + '\n'
211 218 # compile converts unicode filename to str assuming
212 219 # ascii. Let's do the conversion before calling compile
213 220 if isinstance(fname, unicode):
214 221 filename = unicode_to_str(fname)
215 222 else:
216 223 filename = fname
217 224 exec(compile(scripttext, filename, 'exec'), glob, loc)
218 225 else:
219 226 def execfile(fname, *where):
220 227 if isinstance(fname, unicode):
221 228 filename = fname.encode(sys.getfilesystemencoding())
222 229 else:
223 230 filename = fname
224 231 builtin_mod.execfile(filename, *where)
225 232
226 233
227 234 def annotate(**kwargs):
228 235 """Python 3 compatible function annotation for Python 2."""
229 236 if not kwargs:
230 237 raise ValueError('annotations must be provided as keyword arguments')
231 238 def dec(f):
232 239 if hasattr(f, '__annotations__'):
233 240 for k, v in kwargs.items():
234 241 f.__annotations__[k] = v
235 242 else:
236 243 f.__annotations__ = kwargs
237 244 return f
238 245 return dec
239 246
240 247
241 248 # Parts below taken from six:
242 249 # Copyright (c) 2010-2013 Benjamin Peterson
243 250 #
244 251 # Permission is hereby granted, free of charge, to any person obtaining a copy
245 252 # of this software and associated documentation files (the "Software"), to deal
246 253 # in the Software without restriction, including without limitation the rights
247 254 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
248 255 # copies of the Software, and to permit persons to whom the Software is
249 256 # furnished to do so, subject to the following conditions:
250 257 #
251 258 # The above copyright notice and this permission notice shall be included in all
252 259 # copies or substantial portions of the Software.
253 260 #
254 261 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
255 262 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
256 263 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
257 264 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
258 265 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
259 266 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
260 267 # SOFTWARE.
261 268
262 269 def with_metaclass(meta, *bases):
263 270 """Create a base class with a metaclass."""
264 271 return meta("_NewBase", bases, {})
General Comments 0
You need to be logged in to leave comments. Login now