| 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 # rpartition is new in 2.5 | |
| 28 try: | |
| 29 "".rpartition | |
| 30 except AttributeError: | |
| 31 def rpartition(s, sep): | |
| 32 """Implement s.rpartition(sep) for old Pythons.""" | |
| 33 i = s.rfind(sep) | |
| 34 if i == -1: | |
| 35 return ('', '', s) | |
| 36 else: | |
| 37 return (s[:i], sep, s[i+len(sep):]) | |
| 38 else: | |
| 39 def rpartition(s, sep): | |
| 40 """A common interface for new Pythons.""" | |
| 41 return s.rpartition(sep) | |
| 42 | |
| 43 # Pythons 2 and 3 differ on where to get StringIO | |
| 44 try: | |
| 45 from cStringIO import StringIO | |
| 46 BytesIO = StringIO | |
| 47 except ImportError: | |
| 48 from io import StringIO, BytesIO | |
| 49 | |
| 50 # What's a string called? | |
| 51 try: | |
| 52 string_class = basestring | |
| 53 except NameError: | |
| 54 string_class = str | |
| 55 | |
| 56 # Where do pickles come from? | |
| 57 try: | |
| 58 import cPickle as pickle | |
| 59 except ImportError: | |
| 60 import pickle | |
| 61 | |
| 62 # range or xrange? | |
| 63 try: | |
| 64 range = xrange | |
| 65 except NameError: | |
| 66 range = range | |
| 67 | |
| 68 # A function to iterate listlessly over a dict's items. | |
| 69 if "iteritems" in dir({}): | |
| 70 def iitems(d): | |
| 71 """Produce the items from dict `d`.""" | |
| 72 return d.iteritems() | |
| 73 else: | |
| 74 def iitems(d): | |
| 75 """Produce the items from dict `d`.""" | |
| 76 return d.items() | |
| 77 | |
| 78 # Exec is a statement in Py2, a function in Py3 | |
| 79 if sys.version_info >= (3, 0): | |
| 80 def exec_code_object(code, global_map): | |
| 81 """A wrapper around exec().""" | |
| 82 exec(code, global_map) | |
| 83 else: | |
| 84 # OK, this is pretty gross. In Py2, exec was a statement, but that will | |
| 85 # be a syntax error if we try to put it in a Py3 file, even if it is never | |
| 86 # executed. So hide it inside an evaluated string literal instead. | |
| 87 eval( | |
| 88 compile( | |
| 89 "def exec_code_object(code, global_map):\n" | |
| 90 " exec code in global_map\n", | |
| 91 "<exec_function>", "exec" | |
| 92 ) | |
| 93 ) | |
| 94 | |
| 95 # Reading Python source and interpreting the coding comment is a big deal. | |
| 96 if sys.version_info >= (3, 0): | |
| 97 # Python 3.2 provides `tokenize.open`, the best way to open source files. | |
| 98 import tokenize | |
| 99 try: | |
| 100 open_source = tokenize.open # pylint: disable=E1101 | |
| 101 except AttributeError: | |
| 102 from io import TextIOWrapper | |
| 103 detect_encoding = tokenize.detect_encoding # pylint: disable=E1101 | |
| 104 # Copied from the 3.2 stdlib: | |
| 105 def open_source(fname): | |
| 106 """Open a file in read only mode using the encoding detected by | |
| 107 detect_encoding(). | |
| 108 """ | |
| 109 buffer = open(fname, 'rb') | |
| 110 encoding, _ = detect_encoding(buffer.readline) | |
| 111 buffer.seek(0) | |
| 112 text = TextIOWrapper(buffer, encoding, line_buffering=True) | |
| 113 text.mode = 'r' | |
| 114 return text | |
| 115 else: | |
| 116 def open_source(fname): | |
| 117 """Open a source file the best way.""" | |
| 118 return open(fname, "rU") | |
| 119 | |
| 120 | |
| 121 # Python 3.x is picky about bytes and strings, so provide methods to | |
| 122 # get them right, and make them no-ops in 2.x | |
| 123 if sys.version_info >= (3, 0): | |
| 124 def to_bytes(s): | |
| 125 """Convert string `s` to bytes.""" | |
| 126 return s.encode('utf8') | |
| 127 | |
| 128 def to_string(b): | |
| 129 """Convert bytes `b` to a string.""" | |
| 130 return b.decode('utf8') | |
| 131 | |
| 132 else: | |
| 133 def to_bytes(s): | |
| 134 """Convert string `s` to bytes (no-op in 2.x).""" | |
| 135 return s | |
| 136 | |
| 137 def to_string(b): | |
| 138 """Convert bytes `b` to a string (no-op in 2.x).""" | |
| 139 return b | |
| 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 |