23 """A 2.3-compatible implementation of `sorted`.""" |
22 """A 2.3-compatible implementation of `sorted`.""" |
24 lst = list(iterable) |
23 lst = list(iterable) |
25 lst.sort() |
24 lst.sort() |
26 return lst |
25 return lst |
27 |
26 |
|
27 # Python 2.3 doesn't have `reversed`. |
|
28 try: |
|
29 reversed = reversed |
|
30 except NameError: |
|
31 def reversed(iterable): |
|
32 """A 2.3-compatible implementation of `reversed`.""" |
|
33 lst = list(iterable) |
|
34 return lst[::-1] |
|
35 |
|
36 # rpartition is new in 2.5 |
|
37 try: |
|
38 "".rpartition |
|
39 except AttributeError: |
|
40 def rpartition(s, sep): |
|
41 """Implement s.rpartition(sep) for old Pythons.""" |
|
42 i = s.rfind(sep) |
|
43 if i == -1: |
|
44 return ('', '', s) |
|
45 else: |
|
46 return (s[:i], sep, s[i+len(sep):]) |
|
47 else: |
|
48 def rpartition(s, sep): |
|
49 """A common interface for new Pythons.""" |
|
50 return s.rpartition(sep) |
|
51 |
28 # Pythons 2 and 3 differ on where to get StringIO |
52 # Pythons 2 and 3 differ on where to get StringIO |
29 |
|
30 try: |
53 try: |
31 from cStringIO import StringIO |
54 from cStringIO import StringIO |
32 BytesIO = StringIO |
55 BytesIO = StringIO |
33 except ImportError: |
56 except ImportError: |
34 from io import StringIO, BytesIO |
57 from io import StringIO, BytesIO |
35 |
58 |
36 # What's a string called? |
59 # What's a string called? |
37 |
|
38 try: |
60 try: |
39 string_class = basestring |
61 string_class = basestring |
40 except NameError: |
62 except NameError: |
41 string_class = str |
63 string_class = str |
42 |
64 |
43 # Where do pickles come from? |
65 # Where do pickles come from? |
44 |
|
45 try: |
66 try: |
46 import cPickle as pickle |
67 import cPickle as pickle |
47 except ImportError: |
68 except ImportError: |
48 import pickle |
69 import pickle |
49 |
70 |
50 # range or xrange? |
71 # range or xrange? |
51 |
|
52 try: |
72 try: |
53 range = xrange |
73 range = xrange |
54 except NameError: |
74 except NameError: |
55 range = range |
75 range = range |
56 |
76 |
|
77 # A function to iterate listlessly over a dict's items. |
|
78 try: |
|
79 {}.iteritems |
|
80 except AttributeError: |
|
81 def iitems(d): |
|
82 """Produce the items from dict `d`.""" |
|
83 return d.items() |
|
84 else: |
|
85 def iitems(d): |
|
86 """Produce the items from dict `d`.""" |
|
87 return d.iteritems() |
|
88 |
57 # Exec is a statement in Py2, a function in Py3 |
89 # Exec is a statement in Py2, a function in Py3 |
58 |
90 if sys.version_info >= (3, 0): |
59 if sys.hexversion > 0x03000000: |
91 def exec_code_object(code, global_map): |
60 def exec_function(source, filename, global_map): |
|
61 """A wrapper around exec().""" |
92 """A wrapper around exec().""" |
62 exec(compile(source, filename, "exec"), global_map) |
93 exec(code, global_map) |
63 else: |
94 else: |
64 # OK, this is pretty gross. In Py2, exec was a statement, but that will |
95 # OK, this is pretty gross. In Py2, exec was a statement, but that will |
65 # be a syntax error if we try to put it in a Py3 file, even if it is never |
96 # be a syntax error if we try to put it in a Py3 file, even if it is never |
66 # executed. So hide it inside an evaluated string literal instead. |
97 # executed. So hide it inside an evaluated string literal instead. |
67 eval(compile("""\ |
98 eval( |
68 def exec_function(source, filename, global_map): |
99 compile( |
69 exec compile(source, filename, "exec") in global_map |
100 "def exec_code_object(code, global_map):\n" |
70 """, |
101 " exec code in global_map\n", |
71 "<exec_function>", "exec" |
102 "<exec_function>", "exec" |
72 )) |
103 ) |
|
104 ) |
73 |
105 |
74 # |
106 # Reading Python source and interpreting the coding comment is a big deal. |
75 # eflag: FileType = Python2 |
107 if sys.version_info >= (3, 0): |
|
108 # Python 3.2 provides `tokenize.open`, the best way to open source files. |
|
109 import tokenize |
|
110 try: |
|
111 open_source = tokenize.open # pylint: disable=E1101 |
|
112 except AttributeError: |
|
113 from io import TextIOWrapper |
|
114 detect_encoding = tokenize.detect_encoding # pylint: disable=E1101 |
|
115 # Copied from the 3.2 stdlib: |
|
116 def open_source(fname): |
|
117 """Open a file in read only mode using the encoding detected by |
|
118 detect_encoding(). |
|
119 """ |
|
120 buffer = open(fname, 'rb') |
|
121 encoding, _ = detect_encoding(buffer.readline) |
|
122 buffer.seek(0) |
|
123 text = TextIOWrapper(buffer, encoding, line_buffering=True) |
|
124 text.mode = 'r' |
|
125 return text |
|
126 else: |
|
127 def open_source(fname): |
|
128 """Open a source file the best way.""" |
|
129 return open(fname, "rU") |
|
130 |
|
131 |
|
132 # Python 3.x is picky about bytes and strings, so provide methods to |
|
133 # get them right, and make them no-ops in 2.x |
|
134 if sys.version_info >= (3, 0): |
|
135 def to_bytes(s): |
|
136 """Convert string `s` to bytes.""" |
|
137 return s.encode('utf8') |
|
138 |
|
139 def to_string(b): |
|
140 """Convert bytes `b` to a string.""" |
|
141 return b.decode('utf8') |
|
142 |
|
143 def binary_bytes(byte_values): |
|
144 """Produce a byte string with the ints from `byte_values`.""" |
|
145 return bytes(byte_values) |
|
146 |
|
147 def byte_to_int(byte_value): |
|
148 """Turn an element of a bytes object into an int.""" |
|
149 return byte_value |
|
150 |
|
151 def bytes_to_ints(bytes_value): |
|
152 """Turn a bytes object into a sequence of ints.""" |
|
153 # In Py3, iterating bytes gives ints. |
|
154 return bytes_value |
|
155 |
|
156 else: |
|
157 def to_bytes(s): |
|
158 """Convert string `s` to bytes (no-op in 2.x).""" |
|
159 return s |
|
160 |
|
161 def to_string(b): |
|
162 """Convert bytes `b` to a string (no-op in 2.x).""" |
|
163 return b |
|
164 |
|
165 def binary_bytes(byte_values): |
|
166 """Produce a byte string with the ints from `byte_values`.""" |
|
167 return "".join([chr(b) for b in byte_values]) |
|
168 |
|
169 def byte_to_int(byte_value): |
|
170 """Turn an element of a bytes object into an int.""" |
|
171 return ord(byte_value) |
|
172 |
|
173 def bytes_to_ints(bytes_value): |
|
174 """Turn a bytes object into a sequence of ints.""" |
|
175 for byte in bytes_value: |
|
176 yield ord(byte) |
|
177 |
|
178 # Md5 is available in different places. |
|
179 try: |
|
180 import hashlib |
|
181 md5 = hashlib.md5 |
|
182 except ImportError: |
|
183 import md5 |
|
184 md5 = md5.new |