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