Package cherrypy :: Module _cpcompat
[hide private]
[frames] | no frames]

Source Code for Module cherrypy._cpcompat

  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 # In Python 3, the native string type is unicode 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 # In Python 3, the native string type is unicode 44 return n
45
46 - def tonative(n, encoding='ISO-8859-1'):
47 """Return the given string as a native string in the given encoding.""" 48 # In Python 3, the native string type is unicode 49 if isinstance(n, bytes): 50 return n.decode(encoding) 51 return n
52 # type("") 53 from io import StringIO 54 # bytes: 55 from io import BytesIO as BytesIO 56 else: 57 # Python 2 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 # In Python 2, the native string type is bytes. Assume it's already 70 # in the given encoding, which for ISO-8859-1 is almost always what 71 # was intended. 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 # In Python 2, the native string type is bytes. 80 # First, check for the special encoding 'escape'. The test suite uses 81 # this to signal that it wants to pass a string with embedded \uXXXX 82 # escapes, but without having to prefix it with u'' for Python 2, 83 # but no prefix for Python 3. 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 # Assume it's already in the given encoding, which for ISO-8859-1 90 # is almost always what was intended. 91 return n.decode(encoding)
92
93 - def tonative(n, encoding='ISO-8859-1'):
94 """Return the given string as a native string in the given encoding.""" 95 # In Python 2, the native string type is bytes. 96 if isinstance(n, unicode): 97 return n.encode(encoding) 98 return n
99 try: 100 # type("") 101 from cStringIO import StringIO 102 except ImportError: 103 # type("") 104 from StringIO import StringIO 105 # bytes: 106 BytesIO = StringIO 107 108
109 -def assert_native(n):
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 # Python 3.1+ 120 from base64 import decodebytes as _base64_decodebytes 121 except ImportError: 122 # Python 3.0- 123 # since CherryPy claims compability with Python 2.3, we must use 124 # the legacy API of base64 125 from base64 import decodestring as _base64_decodebytes 126 127
128 -def base64_decode(n, encoding='ISO-8859-1'):
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 # Python 2.5+ 142 from hashlib import md5 143 except ImportError: 144 from md5 import new as md5 145 146 try: 147 # Python 2.5+ 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:
155 - def sorted(i):
156 i = i[:] 157 i.sort() 158 return i
159 160 try: 161 reversed = reversed 162 except NameError:
163 - def reversed(x):
164 i = len(x) 165 while i > 0: 166 i -= 1 167 yield x[i]
168 169 try: 170 # Python 3 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 # Python 2 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 # Python 2 191 iteritems = lambda d: d.iteritems() 192 copyitems = lambda d: d.items() 193 except AttributeError: 194 # Python 3 195 iteritems = lambda d: d.items() 196 copyitems = lambda d: list(d.items()) 197 198 try: 199 dict.iterkeys 200 # Python 2 201 iterkeys = lambda d: d.iterkeys() 202 copykeys = lambda d: d.keys() 203 except AttributeError: 204 # Python 3 205 iterkeys = lambda d: d.keys() 206 copykeys = lambda d: list(d.keys()) 207 208 try: 209 dict.itervalues 210 # Python 2 211 itervalues = lambda d: d.itervalues() 212 copyvalues = lambda d: d.values() 213 except AttributeError: 214 # Python 3 215 itervalues = lambda d: d.values() 216 copyvalues = lambda d: list(d.values()) 217 218 try: 219 # Python 3 220 import builtins 221 except ImportError: 222 # Python 2 223 import __builtin__ as builtins 224 225 try: 226 # Python 2. We try Python 2 first clients on Python 2 227 # don't try to import the 'http' module from cherrypy.lib 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 # Python 3 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 # Some platforms don't expose HTTPSConnection, so handle it separately 240 if py3k: 241 try: 242 from http.client import HTTPSConnection 243 except ImportError: 244 # Some platforms which don't have SSL don't expose HTTPSConnection 245 HTTPSConnection = None 246 else: 247 try: 248 from httplib import HTTPSConnection 249 except ImportError: 250 HTTPSConnection = None 251 252 try: 253 # Python 2 254 xrange = xrange 255 except NameError: 256 # Python 3 257 xrange = range 258 259 import threading 260 if hasattr(threading.Thread, "daemon"): 261 # Python 2.6+
262 - def get_daemon(t):
263 return t.daemon
264
265 - def set_daemon(t, val):
266 t.daemon = val
267 else:
268 - def get_daemon(t):
269 return t.isDaemon()
270
271 - def set_daemon(t, val):
272 t.setDaemon(val)
273 274 try: 275 from email.utils import formatdate 276
277 - def HTTPDate(timeval=None):
278 return formatdate(timeval, usegmt=True)
279 except ImportError: 280 from rfc822 import formatdate as HTTPDate 281 282 try: 283 # Python 3 284 from urllib.parse import unquote as parse_unquote 285
286 - def unquote_qs(atom, encoding, errors='strict'):
287 return parse_unquote( 288 atom.replace('+', ' '), 289 encoding=encoding, 290 errors=errors)
291 except ImportError: 292 # Python 2 293 from urllib import unquote as parse_unquote 294
295 - def unquote_qs(atom, encoding, errors='strict'):
296 return parse_unquote(atom.replace('+', ' ')).decode(encoding, errors)
297 298 try: 299 # Prefer simplejson, which is usually more advanced than the builtin 300 # module. 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 # Python >=2.6 : json is part of the standard library 307 import json 308 json_decode = json.JSONDecoder().decode 309 _json_encode = json.JSONEncoder().iterencode 310 else: 311 json = None 312
313 - def json_decode(s):
314 raise ValueError('No JSON library is available')
315
316 - def _json_encode(s):
317 raise ValueError('No JSON library is available')
318 finally: 319 if json and py3k: 320 # The two Python 3 implementations (simplejson/json) 321 # outputs str. We need bytes.
322 - def json_encode(value):
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 # In Python 2, pickle is a Python version. 333 # In Python 3, pickle is the sped-up C version. 334 import pickle 335 336 try: 337 os.urandom(20) 338 import binascii 339
340 - def random20():
341 return binascii.hexlify(os.urandom(20)).decode('ascii')
342 except (AttributeError, NotImplementedError): 343 import random 344 # os.urandom not available until Python 2.4. Fall back to random.random. 345
346 - def random20():
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 # Python 3 356 next = next 357 except NameError: 358 # Python 2
359 - def next(i):
360 return i.next()
361 362 if sys.version_info >= (3, 3): 363 Timer = threading.Timer 364 Event = threading.Event 365 else: 366 # Python 3.2 and earlier 367 Timer = threading._Timer 368 Event = threading._Event 369 370 # Prior to Python 2.6, the Thread class did not have a .daemon property. 371 # This mix-in adds that property. 372 373
374 -class SetDaemonProperty:
375
376 - def __get_daemon(self):
377 return self.isDaemon()
378
379 - def __set_daemon(self, daemon):
380 self.setDaemon(daemon)
381 382 if sys.version_info < (2, 6): 383 daemon = property(__get_daemon, __set_daemon)
384