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
30 - def ntob(n, encoding='ISO-8859-1'):
31 """Return the given native string as a byte string in the given
32 encoding.
33 """
34 assert_native(n)
35
36 return n.encode(encoding)
37
38 - def ntou(n, encoding='ISO-8859-1'):
39 """Return the given native string as a unicode string with the given
40 encoding.
41 """
42 assert_native(n)
43
44 return n
45
47 """Return the given string as a native string in the given encoding."""
48
49 if isinstance(n, bytes):
50 return n.decode(encoding)
51 return n
52
53 from io import StringIO
54
55 from io import BytesIO as BytesIO
56 else:
57
58 py3k = False
59 bytestr = str
60 unicodestr = unicode
61 nativestr = bytestr
62 basestring = basestring
63
64 - def ntob(n, encoding='ISO-8859-1'):
65 """Return the given native string as a byte string in the given
66 encoding.
67 """
68 assert_native(n)
69
70
71
72 return n
73
74 - def ntou(n, encoding='ISO-8859-1'):
75 """Return the given native string as a unicode string with the given
76 encoding.
77 """
78 assert_native(n)
79
80
81
82
83
84 if encoding == 'escape':
85 return unicode(
86 re.sub(r'\\u([0-9a-zA-Z]{4})',
87 lambda m: unichr(int(m.group(1), 16)),
88 n.decode('ISO-8859-1')))
89
90
91 return n.decode(encoding)
92
94 """Return the given string as a native string in the given encoding."""
95
96 if isinstance(n, unicode):
97 return n.encode(encoding)
98 return n
99 try:
100
101 from cStringIO import StringIO
102 except ImportError:
103
104 from StringIO import StringIO
105
106 BytesIO = StringIO
107
108
110 if not isinstance(n, nativestr):
111 raise TypeError("n must be a native str (got %s)" % type(n).__name__)
112
113 try:
114 set = set
115 except NameError:
116 from sets import Set as set
117
118 try:
119
120 from base64 import decodebytes as _base64_decodebytes
121 except ImportError:
122
123
124
125 from base64 import decodestring as _base64_decodebytes
126
127
129 """Return the native string base64-decoded (as a native string)."""
130 if isinstance(n, unicodestr):
131 b = n.encode(encoding)
132 else:
133 b = n
134 b = _base64_decodebytes(b)
135 if nativestr is unicodestr:
136 return b.decode(encoding)
137 else:
138 return b
139
140 try:
141
142 from hashlib import md5
143 except ImportError:
144 from md5 import new as md5
145
146 try:
147
148 from hashlib import sha1 as sha
149 except ImportError:
150 from sha import new as sha
151
152 try:
153 sorted = sorted
154 except NameError:
156 i = i[:]
157 i.sort()
158 return i
159
160 try:
161 reversed = reversed
162 except NameError:
164 i = len(x)
165 while i > 0:
166 i -= 1
167 yield x[i]
168
169 try:
170
171 from urllib.parse import urljoin, urlencode
172 from urllib.parse import quote, quote_plus
173 from urllib.request import unquote, urlopen
174 from urllib.request import parse_http_list, parse_keqv_list
175 except ImportError:
176
177 from urlparse import urljoin
178 from urllib import urlencode, urlopen
179 from urllib import quote, quote_plus
180 from urllib import unquote
181 from urllib2 import parse_http_list, parse_keqv_list
182
183 try:
184 from threading import local as threadlocal
185 except ImportError:
186 from cherrypy._cpthreadinglocal import local as threadlocal
187
188 try:
189 dict.iteritems
190
191 iteritems = lambda d: d.iteritems()
192 copyitems = lambda d: d.items()
193 except AttributeError:
194
195 iteritems = lambda d: d.items()
196 copyitems = lambda d: list(d.items())
197
198 try:
199 dict.iterkeys
200
201 iterkeys = lambda d: d.iterkeys()
202 copykeys = lambda d: d.keys()
203 except AttributeError:
204
205 iterkeys = lambda d: d.keys()
206 copykeys = lambda d: list(d.keys())
207
208 try:
209 dict.itervalues
210
211 itervalues = lambda d: d.itervalues()
212 copyvalues = lambda d: d.values()
213 except AttributeError:
214
215 itervalues = lambda d: d.values()
216 copyvalues = lambda d: list(d.values())
217
218 try:
219
220 import builtins
221 except ImportError:
222
223 import __builtin__ as builtins
224
225 try:
226
227
228 from Cookie import SimpleCookie, CookieError
229 from httplib import BadStatusLine, HTTPConnection, IncompleteRead
230 from httplib import NotConnected
231 from BaseHTTPServer import BaseHTTPRequestHandler
232 except ImportError:
233
234 from http.cookies import SimpleCookie, CookieError
235 from http.client import BadStatusLine, HTTPConnection, IncompleteRead
236 from http.client import NotConnected
237 from http.server import BaseHTTPRequestHandler
238
239
240 if py3k:
241 try:
242 from http.client import HTTPSConnection
243 except ImportError:
244
245 HTTPSConnection = None
246 else:
247 try:
248 from httplib import HTTPSConnection
249 except ImportError:
250 HTTPSConnection = None
251
252 try:
253
254 xrange = xrange
255 except NameError:
256
257 xrange = range
258
259 import threading
260 if hasattr(threading.Thread, "daemon"):
261
264
267 else:
270
273
274 try:
275 from email.utils import formatdate
276
278 return formatdate(timeval, usegmt=True)
279 except ImportError:
280 from rfc822 import formatdate as HTTPDate
281
282 try:
283
284 from urllib.parse import unquote as parse_unquote
285
291 except ImportError:
292
293 from urllib import unquote as parse_unquote
294
297
298 try:
299
300
301 import simplejson as json
302 json_decode = json.JSONDecoder().decode
303 _json_encode = json.JSONEncoder().iterencode
304 except ImportError:
305 if sys.version_info >= (2, 6):
306
307 import json
308 json_decode = json.JSONDecoder().decode
309 _json_encode = json.JSONEncoder().iterencode
310 else:
311 json = None
312
314 raise ValueError('No JSON library is available')
315
317 raise ValueError('No JSON library is available')
318 finally:
319 if json and py3k:
320
321
323 for chunk in _json_encode(value):
324 yield chunk.encode('utf8')
325 else:
326 json_encode = _json_encode
327
328
329 try:
330 import cPickle as pickle
331 except ImportError:
332
333
334 import pickle
335
336 try:
337 os.urandom(20)
338 import binascii
339
341 return binascii.hexlify(os.urandom(20)).decode('ascii')
342 except (AttributeError, NotImplementedError):
343 import random
344
345
347 return sha('%s' % random.random()).hexdigest()
348
349 try:
350 from _thread import get_ident as get_thread_ident
351 except ImportError:
352 from thread import get_ident as get_thread_ident
353
354 try:
355
356 next = next
357 except NameError:
358
361
362 if sys.version_info >= (3, 3):
363 Timer = threading.Timer
364 Event = threading.Event
365 else:
366
367 Timer = threading._Timer
368 Event = threading._Event
369
370
371
372
373
384