"""Compatibility code for using CherryPy with various versions of Python.CherryPy 3.2 is compatible with Python versions 2.3+. This module provides auseful abstraction over the differences between Python versions, sometimes bypreferring a newer idiom, sometimes an older one, and sometimes a custom one.In particular, Python 2 uses str and '' for byte strings, while Python 3uses str and '' for unicode strings. We will call each of these the 'nativestring' type for each version. Because of this major difference, this moduleprovides new 'bytestr', 'unicodestr', and 'nativestr' attributes, as well astwo functions: 'ntob', which translates native strings (of type 'str') intobyte strings regardless of Python version, and 'ntou', which translates nativestrings to unicode strings. This also provides a 'BytesIO' name for dealingspecifically with bytes, and a 'StringIO' name for dealing with native strings.It also provides a 'base64_decode' function with native strings as input andoutput."""importosimportreimportsysifsys.version_info>=(3,0):py3k=Truebytestr=bytesunicodestr=strnativestr=unicodestrbasestring=(bytes,str)defntob(n,encoding='ISO-8859-1'):"""Return the given native string as a byte string in the given encoding."""assert_native(n)# In Python 3, the native string type is unicodereturnn.encode(encoding)defntou(n,encoding='ISO-8859-1'):"""Return the given native string as a unicode string with the given encoding."""assert_native(n)# In Python 3, the native string type is unicodereturnndeftonative(n,encoding='ISO-8859-1'):"""Return the given string as a native string in the given encoding."""# In Python 3, the native string type is unicodeifisinstance(n,bytes):returnn.decode(encoding)returnn# type("")fromioimportStringIO# bytes:fromioimportBytesIOasBytesIOelse:# Python 2py3k=Falsebytestr=strunicodestr=unicodenativestr=bytestrbasestring=basestringdefntob(n,encoding='ISO-8859-1'):"""Return the given native string as a byte string in the given encoding."""assert_native(n)# In Python 2, the native string type is bytes. Assume it's already# in the given encoding, which for ISO-8859-1 is almost always what# was intended.returnndefntou(n,encoding='ISO-8859-1'):"""Return the given native string as a unicode string with the given encoding."""assert_native(n)# In Python 2, the native string type is bytes.# First, check for the special encoding 'escape'. The test suite uses this# to signal that it wants to pass a string with embedded \uXXXX escapes,# but without having to prefix it with u'' for Python 2, but no prefix# for Python 3.ifencoding=='escape':returnunicode(re.sub(r'\\u([0-9a-zA-Z]{4})',lambdam:unichr(int(m.group(1),16)),n.decode('ISO-8859-1')))# Assume it's already in the given encoding, which for ISO-8859-1 is almost# always what was intended.returnn.decode(encoding)deftonative(n,encoding='ISO-8859-1'):"""Return the given string as a native string in the given encoding."""# In Python 2, the native string type is bytes.ifisinstance(n,unicode):returnn.encode(encoding)returnntry:# type("")fromcStringIOimportStringIOexceptImportError:# type("")fromStringIOimportStringIO# bytes:BytesIO=StringIOdefassert_native(n):ifnotisinstance(n,nativestr):raiseTypeError("n must be a native str (got %s)"%type(n).__name__)defalways_bytes(str,encoding='utf-8'):ifisinstance(str,unicodestr):str=str.encode(encoding)returnstrtry:set=setexceptNameError:fromsetsimportSetassettry:# Python 3.1+frombase64importdecodebytesas_base64_decodebytesexceptImportError:# Python 3.0-# since CherryPy claims compability with Python 2.3, we must use# the legacy API of base64frombase64importdecodestringas_base64_decodebytesdefbase64_decode(n,encoding='ISO-8859-1'):"""Return the native string base64-decoded (as a native string)."""ifisinstance(n,unicodestr):b=n.encode(encoding)else:b=nb=_base64_decodebytes(b)ifnativestrisunicodestr:returnb.decode(encoding)else:returnbtry:# Python 2.5+fromhashlibimportmd5exceptImportError:frommd5importnewasmd5try:# Python 2.5+fromhashlibimportsha1asshaexceptImportError:fromshaimportnewasshatry:sorted=sortedexceptNameError:defsorted(i):i=i[:]i.sort()returnitry:reversed=reversedexceptNameError:defreversed(x):i=len(x)whilei>0:i-=1yieldx[i]try:# Python 3fromurllib.parseimporturljoin,urlencodefromurllib.parseimportquote,quote_plusfromurllib.requestimportunquote,urlopenfromurllib.requestimportparse_http_list,parse_keqv_listexceptImportError:# Python 2fromurlparseimporturljoinfromurllibimporturlencode,urlopenfromurllibimportquote,quote_plusfromurllibimportunquotefromurllib2importparse_http_list,parse_keqv_listtry:fromthreadingimportlocalasthreadlocalexceptImportError:fromcherrypy._cpthreadinglocalimportlocalasthreadlocaltry:dict.iteritems# Python 2iteritems=lambdad:d.iteritems()copyitems=lambdad:d.items()exceptAttributeError:# Python 3iteritems=lambdad:d.items()copyitems=lambdad:list(d.items())try:dict.iterkeys# Python 2iterkeys=lambdad:d.iterkeys()copykeys=lambdad:d.keys()exceptAttributeError:# Python 3iterkeys=lambdad:d.keys()copykeys=lambdad:list(d.keys())try:dict.itervalues# Python 2itervalues=lambdad:d.itervalues()copyvalues=lambdad:d.values()exceptAttributeError:# Python 3itervalues=lambdad:d.values()copyvalues=lambdad:list(d.values())try:# Python 3importbuiltinsexceptImportError:# Python 2import__builtin__asbuiltinstry:# Python 2. We try Python 2 first clients on Python 2# don't try to import the 'http' module from cherrypy.libfromCookieimportSimpleCookie,CookieErrorfromhttplibimportBadStatusLine,HTTPConnection,IncompleteRead,NotConnectedfromBaseHTTPServerimportBaseHTTPRequestHandlerexceptImportError:# Python 3fromhttp.cookiesimportSimpleCookie,CookieErrorfromhttp.clientimportBadStatusLine,HTTPConnection,IncompleteRead,NotConnectedfromhttp.serverimportBaseHTTPRequestHandler# Some platforms don't expose HTTPSConnection, so handle it separatelyifpy3k:try:fromhttp.clientimportHTTPSConnectionexceptImportError:# Some platforms which don't have SSL don't expose HTTPSConnectionHTTPSConnection=Noneelse:try:fromhttplibimportHTTPSConnectionexceptImportError:HTTPSConnection=Nonetry:# Python 2xrange=xrangeexceptNameError:# Python 3xrange=rangeimportthreadingifhasattr(threading.Thread,"daemon"):# Python 2.6+defget_daemon(t):returnt.daemondefset_daemon(t,val):t.daemon=valelse:defget_daemon(t):returnt.isDaemon()defset_daemon(t,val):t.setDaemon(val)try:fromemail.utilsimportformatdatedefHTTPDate(timeval=None):returnformatdate(timeval,usegmt=True)exceptImportError:fromrfc822importformatdateasHTTPDatetry:# Python 3fromurllib.parseimportunquoteasparse_unquotedefunquote_qs(atom,encoding,errors='strict'):returnparse_unquote(atom.replace('+',' '),encoding=encoding,errors=errors)exceptImportError:# Python 2fromurllibimportunquoteasparse_unquotedefunquote_qs(atom,encoding,errors='strict'):returnparse_unquote(atom.replace('+',' ')).decode(encoding,errors)try:# Prefer simplejson, which is usually more advanced than the builtin module.importsimplejsonasjsonjson_decode=json.JSONDecoder().decodejson_encode=json.JSONEncoder().iterencodeexceptImportError:ifpy3k:# Python 3.0: json is part of the standard library,# but outputs unicode. We need bytes.importjsonjson_decode=json.JSONDecoder().decode_json_encode=json.JSONEncoder().iterencodedefjson_encode(value):forchunkin_json_encode(value):yieldchunk.encode('utf8')elifsys.version_info>=(2,6):# Python 2.6: json is part of the standard libraryimportjsonjson_decode=json.JSONDecoder().decodejson_encode=json.JSONEncoder().iterencodeelse:json=Nonedefjson_decode(s):raiseValueError('No JSON library is available')defjson_encode(s):raiseValueError('No JSON library is available')try:importcPickleaspickleexceptImportError:# In Python 2, pickle is a Python version.# In Python 3, pickle is the sped-up C version.importpickletry:os.urandom(20)importbinasciidefrandom20():returnbinascii.hexlify(os.urandom(20)).decode('ascii')except(AttributeError,NotImplementedError):importrandom# os.urandom not available until Python 2.4. Fall back to random.random.defrandom20():returnsha('%s'%random.random()).hexdigest()try:from_threadimportget_identasget_thread_identexceptImportError:fromthreadimportget_identasget_thread_identtry:# Python 3next=nextexceptNameError:# Python 2defnext(i):returni.next()