1 """Compatibility code for using CherryPy with various versions of Python.
2
3 CherryPy 3.2 is compatible with Python versions 2.3+. This module provides a
4 useful abstraction over the differences between Python versions, sometimes by
5 preferring a newer idiom, sometimes an older one, and sometimes a custom one.
6
7 In particular, Python 2 uses str and '' for byte strings, while Python 3
8 uses str and '' for unicode strings. We will call each of these the 'native
9 string' type for each version. Because of this major difference, this module
10 provides new 'bytestr', 'unicodestr', and 'nativestr' attributes, as well as
11 two functions: 'ntob', which translates native strings (of type 'str') into
12 byte strings regardless of Python version, and 'ntou', which translates native
13 strings to unicode strings. This also provides a 'BytesIO' name for dealing
14 specifically with bytes, and a 'StringIO' name for dealing with native strings.
15 It also provides a 'base64_decode' function with native strings as input and
16 output.
17 """
18 import os
19 import re
20 import sys
21 import threading
22
23 if sys.version_info >= (3, 0):
24 py3k = True
25 bytestr = bytes
26 unicodestr = str
27 nativestr = unicodestr
28 basestring = (bytes, str)
29 - def ntob(n, encoding='ISO-8859-1'):
30 """Return the given native string as a byte string in the given encoding."""
31
32 return n.encode(encoding)
33 - def ntou(n, encoding='ISO-8859-1'):
34 """Return the given native string as a unicode string with the given encoding."""
35
36 return n
38 """Return the given string as a native string in the given encoding."""
39
40 if isinstance(n, bytes):
41 return n.decode(encoding)
42 return n
43
44 from io import StringIO
45
46 from io import BytesIO as BytesIO
47 else:
48
49 py3k = False
50 bytestr = str
51 unicodestr = unicode
52 nativestr = bytestr
53 basestring = basestring
54 - def ntob(n, encoding='ISO-8859-1'):
55 """Return the given native string as a byte string in the given encoding."""
56
57
58
59 return n
60 - def ntou(n, encoding='ISO-8859-1'):
61 """Return the given native string as a unicode string with the given encoding."""
62
63
64
65
66
67 if encoding == 'escape':
68 return unicode(
69 re.sub(r'\\u([0-9a-zA-Z]{4})',
70 lambda m: unichr(int(m.group(1), 16)),
71 n.decode('ISO-8859-1')))
72
73
74 return n.decode(encoding)
76 """Return the given string as a native string in the given encoding."""
77
78 if isinstance(n, unicode):
79 return n.encode(encoding)
80 return n
81 try:
82
83 from cStringIO import StringIO
84 except ImportError:
85
86 from StringIO import StringIO
87
88 BytesIO = StringIO
89
90 try:
91 set = set
92 except NameError:
93 from sets import Set as set
94
95 try:
96
97 from base64 import decodebytes as _base64_decodebytes
98 except ImportError:
99
100
101
102 from base64 import decodestring as _base64_decodebytes
103
105 """Return the native string base64-decoded (as a native string)."""
106 if isinstance(n, unicodestr):
107 b = n.encode(encoding)
108 else:
109 b = n
110 b = _base64_decodebytes(b)
111 if nativestr is unicodestr:
112 return b.decode(encoding)
113 else:
114 return b
115
116 try:
117
118 from hashlib import md5
119 except ImportError:
120 from md5 import new as md5
121
122 try:
123
124 from hashlib import sha1 as sha
125 except ImportError:
126 from sha import new as sha
127
128 try:
129 sorted = sorted
130 except NameError:
132 i = i[:]
133 i.sort()
134 return i
135
136 try:
137 reversed = reversed
138 except NameError:
140 i = len(x)
141 while i > 0:
142 i -= 1
143 yield x[i]
144
145 try:
146
147 from urllib.parse import urljoin, urlencode
148 from urllib.parse import quote, quote_plus
149 from urllib.request import unquote, urlopen
150 from urllib.request import parse_http_list, parse_keqv_list
151 except ImportError:
152
153 from urlparse import urljoin
154 from urllib import urlencode, urlopen
155 from urllib import quote, quote_plus
156 from urllib import unquote
157 from urllib2 import parse_http_list, parse_keqv_list
158
159 try:
160 from threading import local as threadlocal
161 except ImportError:
162 from cherrypy._cpthreadinglocal import local as threadlocal
163
164 try:
165 dict.iteritems
166
167 iteritems = lambda d: d.iteritems()
168 copyitems = lambda d: d.items()
169 except AttributeError:
170
171 iteritems = lambda d: d.items()
172 copyitems = lambda d: list(d.items())
173
174 try:
175 dict.iterkeys
176
177 iterkeys = lambda d: d.iterkeys()
178 copykeys = lambda d: d.keys()
179 except AttributeError:
180
181 iterkeys = lambda d: d.keys()
182 copykeys = lambda d: list(d.keys())
183
184 try:
185 dict.itervalues
186
187 itervalues = lambda d: d.itervalues()
188 copyvalues = lambda d: d.values()
189 except AttributeError:
190
191 itervalues = lambda d: d.values()
192 copyvalues = lambda d: list(d.values())
193
194 try:
195
196 import builtins
197 except ImportError:
198
199 import __builtin__ as builtins
200
201 try:
202
203
204 from Cookie import SimpleCookie, CookieError
205 from httplib import BadStatusLine, HTTPConnection, HTTPSConnection, IncompleteRead, NotConnected
206 from BaseHTTPServer import BaseHTTPRequestHandler
207 except ImportError:
208
209 from http.cookies import SimpleCookie, CookieError
210 from http.client import BadStatusLine, HTTPConnection, HTTPSConnection, IncompleteRead, NotConnected
211 from http.server import BaseHTTPRequestHandler
212
213 try:
214
215
216 from httplib import HTTPSConnection
217 except ImportError:
218 try:
219
220 from http.client import HTTPSConnection
221 except ImportError:
222
223 HTTPSConnection = None
224
225 try:
226
227 xrange = xrange
228 except NameError:
229
230 xrange = range
231
232 import threading
233 if hasattr(threading.Thread, "daemon"):
234
239 else:
244
245 try:
246 from email.utils import formatdate
248 return formatdate(timeval, usegmt=True)
249 except ImportError:
250 from rfc822 import formatdate as HTTPDate
251
252 try:
253
254 from urllib.parse import unquote as parse_unquote
257 except ImportError:
258
259 from urllib import unquote as parse_unquote
262
263 try:
264
265 import simplejson as json
266 json_decode = json.JSONDecoder().decode
267 json_encode = json.JSONEncoder().iterencode
268 except ImportError:
269 if py3k:
270
271
272 import json
273 json_decode = json.JSONDecoder().decode
274 _json_encode = json.JSONEncoder().iterencode
278 elif sys.version_info >= (2, 6):
279
280 import json
281 json_decode = json.JSONDecoder().decode
282 json_encode = json.JSONEncoder().iterencode
283 else:
284 json = None
286 raise ValueError('No JSON library is available')
288 raise ValueError('No JSON library is available')
289
290 try:
291 import cPickle as pickle
292 except ImportError:
293
294
295 import pickle
296
297 try:
298 os.urandom(20)
299 import binascii
301 return binascii.hexlify(os.urandom(20)).decode('ascii')
302 except (AttributeError, NotImplementedError):
303 import random
304
306 return sha('%s' % random.random()).hexdigest()
307
308 try:
309 from _thread import get_ident as get_thread_ident
310 except ImportError:
311 from thread import get_ident as get_thread_ident
312
313 try:
314
315 next = next
316 except NameError:
317
320
321 if sys.version_info >= (3,3):
322 Timer = threading.Timer
323 else:
324
325 Timer = threading._Timer
326