OLD | NEW |
| (Empty) |
1 """Add things to old Pythons so I can pretend they are newer.""" | |
2 | |
3 # This file does lots of tricky stuff, so disable a bunch of lintisms. | |
4 # pylint: disable=F0401,W0611,W0622 | |
5 # F0401: Unable to import blah | |
6 # W0611: Unused import blah | |
7 # W0622: Redefining built-in blah | |
8 | |
9 import os, sys | |
10 | |
11 # Python 2.3 doesn't have `set` | |
12 try: | |
13 set = set # new in 2.4 | |
14 except NameError: | |
15 from sets import Set as set | |
16 | |
17 # Python 2.3 doesn't have `sorted`. | |
18 try: | |
19 sorted = sorted | |
20 except NameError: | |
21 def sorted(iterable): | |
22 """A 2.3-compatible implementation of `sorted`.""" | |
23 lst = list(iterable) | |
24 lst.sort() | |
25 return lst | |
26 | |
27 # Pythons 2 and 3 differ on where to get StringIO | |
28 try: | |
29 from cStringIO import StringIO | |
30 BytesIO = StringIO | |
31 except ImportError: | |
32 from io import StringIO, BytesIO | |
33 | |
34 # What's a string called? | |
35 try: | |
36 string_class = basestring | |
37 except NameError: | |
38 string_class = str | |
39 | |
40 # Where do pickles come from? | |
41 try: | |
42 import cPickle as pickle | |
43 except ImportError: | |
44 import pickle | |
45 | |
46 # range or xrange? | |
47 try: | |
48 range = xrange | |
49 except NameError: | |
50 range = range | |
51 | |
52 # Exec is a statement in Py2, a function in Py3 | |
53 if sys.version_info >= (3, 0): | |
54 def exec_code_object(code, global_map): | |
55 """A wrapper around exec().""" | |
56 exec(code, global_map) | |
57 else: | |
58 # OK, this is pretty gross. In Py2, exec was a statement, but that will | |
59 # be a syntax error if we try to put it in a Py3 file, even if it is never | |
60 # executed. So hide it inside an evaluated string literal instead. | |
61 eval( | |
62 compile( | |
63 "def exec_code_object(code, global_map):\n" | |
64 " exec code in global_map\n", | |
65 "<exec_function>", "exec" | |
66 ) | |
67 ) | |
68 | |
69 # ConfigParser was renamed to the more-standard configparser | |
70 try: | |
71 import configparser | |
72 except ImportError: | |
73 import ConfigParser as configparser | |
74 | |
75 # Python 3.2 provides `tokenize.open`, the best way to open source files. | |
76 import tokenize | |
77 try: | |
78 open_source = tokenize.open # pylint: disable=E1101 | |
79 except AttributeError: | |
80 try: | |
81 detect_encoding = tokenize.detect_encoding # pylint: disable=E1101 | |
82 except AttributeError: | |
83 def open_source(fname): | |
84 """Open a source file the best way.""" | |
85 return open(fname, "rU") | |
86 else: | |
87 from io import TextIOWrapper | |
88 # Copied from the 3.2 stdlib: | |
89 def open_source(fname): | |
90 """Open a file in read only mode using the encoding detected by | |
91 detect_encoding(). | |
92 """ | |
93 buffer = open(fname, 'rb') | |
94 encoding, _ = detect_encoding(buffer.readline) | |
95 buffer.seek(0) | |
96 text = TextIOWrapper(buffer, encoding, line_buffering=True) | |
97 text.mode = 'r' | |
98 return text | |
99 | |
100 # Python 3.x is picky about bytes and strings, so provide methods to | |
101 # get them right, and make them no-ops in 2.x | |
102 if sys.version_info >= (3, 0): | |
103 def to_bytes(s): | |
104 """Convert string `s` to bytes.""" | |
105 return s.encode('utf8') | |
106 | |
107 def to_string(b): | |
108 """Convert bytes `b` to a string.""" | |
109 return b.decode('utf8') | |
110 | |
111 else: | |
112 def to_bytes(s): | |
113 """Convert string `s` to bytes (no-op in 2.x).""" | |
114 return s | |
115 | |
116 def to_string(b): | |
117 """Convert bytes `b` to a string (no-op in 2.x).""" | |
118 return b | |
119 | |
120 # A few details about writing encoded text are different in 2.x and 3.x. | |
121 if sys.version_info >= (3, 0): | |
122 def write_encoded(fname, text, encoding='utf8', errors='strict'): | |
123 '''Write string `text` to file names `fname`, with encoding.''' | |
124 # Don't use "with", so that this file is still good for old 2.x. | |
125 f = open(fname, 'w', encoding=encoding, errors=errors) | |
126 try: | |
127 f.write(text) | |
128 finally: | |
129 f.close() | |
130 else: | |
131 # It's not clear that using utf8 strings in 2.x is the right thing to do. | |
132 def write_encoded(fname, text, encoding='utf8', errors='strict'): | |
133 '''Write utf8 string `text` to file names `fname`, with encoding.''' | |
134 import codecs | |
135 f = codecs.open(fname, 'w', encoding=encoding, errors=errors) | |
136 try: | |
137 f.write(text.decode('utf8')) | |
138 finally: | |
139 f.close() | |
140 | |
141 # Md5 is available in different places. | |
142 try: | |
143 import hashlib | |
144 md5 = hashlib.md5 | |
145 except ImportError: | |
146 import md5 | |
147 md5 = md5.new | |
OLD | NEW |