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, re, 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 # 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 |
| 52 # Pythons 2 and 3 differ on where to get StringIO |
| 53 try: |
| 54 from cStringIO import StringIO |
| 55 BytesIO = StringIO |
| 56 except ImportError: |
| 57 from io import StringIO, BytesIO |
| 58 |
| 59 # What's a string called? |
| 60 try: |
| 61 string_class = basestring |
| 62 except NameError: |
| 63 string_class = str |
| 64 |
| 65 # Where do pickles come from? |
| 66 try: |
| 67 import cPickle as pickle |
| 68 except ImportError: |
| 69 import pickle |
| 70 |
| 71 # range or xrange? |
| 72 try: |
| 73 range = xrange |
| 74 except NameError: |
| 75 range = range |
| 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 |
| 89 # Exec is a statement in Py2, a function in Py3 |
| 90 if sys.version_info >= (3, 0): |
| 91 def exec_code_object(code, global_map): |
| 92 """A wrapper around exec().""" |
| 93 exec(code, global_map) |
| 94 else: |
| 95 # OK, this is pretty gross. In Py2, exec was a statement, but that will |
| 96 # be a syntax error if we try to put it in a Py3 file, even if it is never |
| 97 # executed. So hide it inside an evaluated string literal instead. |
| 98 eval( |
| 99 compile( |
| 100 "def exec_code_object(code, global_map):\n" |
| 101 " exec code in global_map\n", |
| 102 "<exec_function>", "exec" |
| 103 ) |
| 104 ) |
| 105 |
| 106 # Reading Python source and interpreting the coding comment is a big deal. |
| 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 |
OLD | NEW |