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