##// END OF EJS Templates
Add function to handle u'abc' (Python 2) vs. 'abc' (Python 3) in doctests and similar.
Thomas Kluyver -
Show More
@@ -1,127 +1,151 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 sys
4 import sys
4 import re
5 import re
5 import types
6 import types
6
7
7 orig_open = open
8 orig_open = open
8
9
9 def no_code(x, encoding=None):
10 def no_code(x, encoding=None):
10 return x
11 return x
11
12
12 def decode(s, encoding=None):
13 def decode(s, encoding=None):
13 encoding = encoding or sys.stdin.encoding or sys.getdefaultencoding()
14 encoding = encoding or sys.stdin.encoding or sys.getdefaultencoding()
14 return s.decode(encoding, "replace")
15 return s.decode(encoding, "replace")
15
16
16 def encode(u, encoding=None):
17 def encode(u, encoding=None):
17 encoding = encoding or sys.stdin.encoding or sys.getdefaultencoding()
18 encoding = encoding or sys.stdin.encoding or sys.getdefaultencoding()
18 return u.encode(encoding, "replace")
19 return u.encode(encoding, "replace")
19
20
20 def cast_unicode(s, encoding=None):
21 def cast_unicode(s, encoding=None):
21 if isinstance(s, bytes):
22 if isinstance(s, bytes):
22 return decode(s, encoding)
23 return decode(s, encoding)
23 return s
24 return s
24
25
25 def cast_bytes(s, encoding=None):
26 def cast_bytes(s, encoding=None):
26 if not isinstance(s, bytes):
27 if not isinstance(s, bytes):
27 return encode(s, encoding)
28 return encode(s, encoding)
28 return s
29 return s
29
30
31 def _modify_str_or_docstring(str_change_func):
32 @functools.wraps(str_change_func)
33 def wrapper(func_or_str):
34 if isinstance(func_or_str, str):
35 func = None
36 doc = func_or_str
37 else:
38 func = func_or_str
39 doc = func.__doc__
40
41 doc = str_change_func(doc)
42
43 if func:
44 func.__doc__ = doc
45 return func
46 return doc
47 return wrapper
48
30 if sys.version_info[0] >= 3:
49 if sys.version_info[0] >= 3:
31 PY3 = True
50 PY3 = True
32
51
33 input = input
52 input = input
34 builtin_mod_name = "builtins"
53 builtin_mod_name = "builtins"
35
54
36 str_to_unicode = no_code
55 str_to_unicode = no_code
37 unicode_to_str = no_code
56 unicode_to_str = no_code
38 str_to_bytes = encode
57 str_to_bytes = encode
39 bytes_to_str = decode
58 bytes_to_str = decode
40 cast_bytes_py2 = no_code
59 cast_bytes_py2 = no_code
41
60
42 def isidentifier(s, dotted=False):
61 def isidentifier(s, dotted=False):
43 if dotted:
62 if dotted:
44 return all(isidentifier(a) for a in s.split("."))
63 return all(isidentifier(a) for a in s.split("."))
45 return s.isidentifier()
64 return s.isidentifier()
46
65
47 open = orig_open
66 open = orig_open
48
67
49 MethodType = types.MethodType
68 MethodType = types.MethodType
50
69
51 def execfile(fname, glob, loc=None):
70 def execfile(fname, glob, loc=None):
52 loc = loc if (loc is not None) else glob
71 loc = loc if (loc is not None) else glob
53 exec compile(open(fname).read(), fname, 'exec') in glob, loc
72 exec compile(open(fname).read(), fname, 'exec') in glob, loc
54
73
55 # Refactor print statements in doctests.
74 # Refactor print statements in doctests.
56 _print_statement_re = re.compile(r"\bprint (?P<expr>.*)$", re.MULTILINE)
75 _print_statement_re = re.compile(r"\bprint (?P<expr>.*)$", re.MULTILINE)
57 def _print_statement_sub(match):
76 def _print_statement_sub(match):
58 expr = match.groups('expr')
77 expr = match.groups('expr')
59 return "print(%s)" % expr
78 return "print(%s)" % expr
60 def doctest_refactor_print(func_or_str):
79
80 @_modify_str_or_docstring
81 def doctest_refactor_print(doc):
61 """Refactor 'print x' statements in a doctest to print(x) style. 2to3
82 """Refactor 'print x' statements in a doctest to print(x) style. 2to3
62 unfortunately doesn't pick up on our doctests.
83 unfortunately doesn't pick up on our doctests.
63
84
64 Can accept a string or a function, so it can be used as a decorator."""
85 Can accept a string or a function, so it can be used as a decorator."""
65 if isinstance(func_or_str, str):
86 return _print_statement_re.sub(_print_statement_sub, doc)
66 func = None
87
67 doc = func_or_str
88 # Abstract u'abc' syntax:
68 else:
89 @_modify_str_or_docstring
69 func = func_or_str
90 def u_format(s):
70 doc = func.__doc__
91 """"{u}'abc'" --> "'abc'" (Python 3)
71 doc = _print_statement_re.sub(_print_statement_sub, doc)
72
73 if func:
74 func.__doc__ = doc
75 return func
76 return doc
77
92
93 Accepts a string or a function, so it can be used as a decorator."""
94 return s.format(u='')
78
95
79 else:
96 else:
80 PY3 = False
97 PY3 = False
81
98
82 input = raw_input
99 input = raw_input
83 builtin_mod_name = "__builtin__"
100 builtin_mod_name = "__builtin__"
84
101
85 str_to_unicode = decode
102 str_to_unicode = decode
86 unicode_to_str = encode
103 unicode_to_str = encode
87 str_to_bytes = no_code
104 str_to_bytes = no_code
88 bytes_to_str = no_code
105 bytes_to_str = no_code
89 cast_bytes_py2 = cast_bytes
106 cast_bytes_py2 = cast_bytes
90
107
91 import re
108 import re
92 _name_re = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*$")
109 _name_re = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*$")
93 def isidentifier(s, dotted=False):
110 def isidentifier(s, dotted=False):
94 if dotted:
111 if dotted:
95 return all(isidentifier(a) for a in s.split("."))
112 return all(isidentifier(a) for a in s.split("."))
96 return bool(_name_re.match(s))
113 return bool(_name_re.match(s))
97
114
98 class open(object):
115 class open(object):
99 """Wrapper providing key part of Python 3 open() interface."""
116 """Wrapper providing key part of Python 3 open() interface."""
100 def __init__(self, fname, mode="r", encoding="utf-8"):
117 def __init__(self, fname, mode="r", encoding="utf-8"):
101 self.f = orig_open(fname, mode)
118 self.f = orig_open(fname, mode)
102 self.enc = encoding
119 self.enc = encoding
103
120
104 def write(self, s):
121 def write(self, s):
105 return self.f.write(s.encode(self.enc))
122 return self.f.write(s.encode(self.enc))
106
123
107 def read(self, size=-1):
124 def read(self, size=-1):
108 return self.f.read(size).decode(self.enc)
125 return self.f.read(size).decode(self.enc)
109
126
110 def close(self):
127 def close(self):
111 return self.f.close()
128 return self.f.close()
112
129
113 def __enter__(self):
130 def __enter__(self):
114 return self
131 return self
115
132
116 def __exit__(self, etype, value, traceback):
133 def __exit__(self, etype, value, traceback):
117 self.f.close()
134 self.f.close()
118
135
119 def MethodType(func, instance):
136 def MethodType(func, instance):
120 return types.MethodType(func, instance, type(instance))
137 return types.MethodType(func, instance, type(instance))
121
138
122 # don't override system execfile on 2.x:
139 # don't override system execfile on 2.x:
123 execfile = execfile
140 execfile = execfile
124
141
125 def doctest_refactor_print(func_or_str):
142 def doctest_refactor_print(func_or_str):
126 return func_or_str
143 return func_or_str
127
144
145 # Abstract u'abc' syntax:
146 @_modify_str_or_docstring
147 def u_format(s):
148 """"{u}'abc'" --> "u'abc'" (Python 2)
149
150 Accepts a string or a function, so it can be used as a decorator."""
151 return s.format(u='u')
General Comments 0
You need to be logged in to leave comments. Login now