Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/cherrypy/_cpcompat.py
blob: 216ddddce89b66d1ff13e460ac03b3aef4b703cf (plain)
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
"""Compatibility code for using CherryPy with various versions of Python.

CherryPy 3.2 is compatible with Python versions 2.3+. This module provides a
useful abstraction over the differences between Python versions, sometimes by
preferring a newer idiom, sometimes an older one, and sometimes a custom one.

In particular, Python 2 uses str and '' for byte strings, while Python 3
uses str and '' for unicode strings. We will call each of these the 'native
string' type for each version. Because of this major difference, this module
provides new 'bytestr', 'unicodestr', and 'nativestr' attributes, as well as
two functions: 'ntob', which translates native strings (of type 'str') into
byte strings regardless of Python version, and 'ntou', which translates native
strings to unicode strings. This also provides a 'BytesIO' name for dealing
specifically with bytes, and a 'StringIO' name for dealing with native strings.
It also provides a 'base64_decode' function with native strings as input and
output.
"""
import os
import sys

if sys.version_info >= (3, 0):
    bytestr = bytes
    unicodestr = str
    nativestr = unicodestr
    basestring = (bytes, str)
    def ntob(n, encoding='ISO-8859-1'):
        """Return the given native string as a byte string in the given encoding."""
        # In Python 3, the native string type is unicode
        return n.encode(encoding)
    def ntou(n, encoding='ISO-8859-1'):
        """Return the given native string as a unicode string with the given encoding."""
        # In Python 3, the native string type is unicode
        return n
    # type("")
    from io import StringIO
    # bytes:
    from io import BytesIO as BytesIO
else:
    # Python 2
    bytestr = str
    unicodestr = unicode
    nativestr = bytestr
    basestring = basestring
    def ntob(n, encoding='ISO-8859-1'):
        """Return the given native string as a byte string in the given encoding."""
        # 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.
        return n
    def ntou(n, encoding='ISO-8859-1'):
        """Return the given native string as a unicode string with the given encoding."""
        # 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.
        return n.decode(encoding)
    try:
        # type("")
        from cStringIO import StringIO
    except ImportError:
        # type("")
        from StringIO import StringIO
    # bytes:
    BytesIO = StringIO

try:
    set = set
except NameError:
    from sets import Set as set

try:
    # Python 3.1+
    from base64 import decodebytes as _base64_decodebytes
except ImportError:
    # Python 3.0-
    # since CherryPy claims compability with Python 2.3, we must use
    # the legacy API of base64
    from base64 import decodestring as _base64_decodebytes

def base64_decode(n, encoding='ISO-8859-1'):
    """Return the native string base64-decoded (as a native string)."""
    if isinstance(n, unicodestr):
        b = n.encode(encoding)
    else:
        b = n
    b = _base64_decodebytes(b)
    if nativestr is unicodestr:
        return b.decode(encoding)
    else:
        return b

try:
    # Python 2.5+
    from hashlib import md5
except ImportError:
    from md5 import new as md5

try:
    # Python 2.5+
    from hashlib import sha1 as sha
except ImportError:
    from sha import new as sha

try:
    sorted = sorted
except NameError:
    def sorted(i):
        i = i[:]
        i.sort()
        return i

try:
    reversed = reversed
except NameError:
    def reversed(x):
        i = len(x)
        while i > 0:
            i -= 1
            yield x[i]

try:
    # Python 3
    from urllib.parse import urljoin, urlencode
    from urllib.parse import quote, quote_plus
    from urllib.request import unquote, urlopen
    from urllib.request import parse_http_list, parse_keqv_list
except ImportError:
    # Python 2
    from urlparse import urljoin
    from urllib import urlencode, urlopen
    from urllib import quote, quote_plus
    from urllib import unquote
    from urllib2 import parse_http_list, parse_keqv_list

try:
    from threading import local as threadlocal
except ImportError:
    from cherrypy._cpthreadinglocal import local as threadlocal

try:
    dict.iteritems
    # Python 2
    iteritems = lambda d: d.iteritems()
    copyitems = lambda d: d.items()
except AttributeError:
    # Python 3
    iteritems = lambda d: d.items()
    copyitems = lambda d: list(d.items())

try:
    dict.iterkeys
    # Python 2
    iterkeys = lambda d: d.iterkeys()
    copykeys = lambda d: d.keys()
except AttributeError:
    # Python 3
    iterkeys = lambda d: d.keys()
    copykeys = lambda d: list(d.keys())

try:
    dict.itervalues
    # Python 2
    itervalues = lambda d: d.itervalues()
    copyvalues = lambda d: d.values()
except AttributeError:
    # Python 3
    itervalues = lambda d: d.values()
    copyvalues = lambda d: list(d.values())

try:
    # Python 3
    import builtins
except ImportError:
    # Python 2
    import __builtin__ as builtins

try:
    # Python 2. We have to do it in this order so Python 2 builds
    # don't try to import the 'http' module from cherrypy.lib
    from Cookie import SimpleCookie, CookieError
    from httplib import BadStatusLine, HTTPConnection, HTTPSConnection, IncompleteRead, NotConnected
    from BaseHTTPServer import BaseHTTPRequestHandler
except ImportError:
    # Python 3
    from http.cookies import SimpleCookie, CookieError
    from http.client import BadStatusLine, HTTPConnection, HTTPSConnection, IncompleteRead, NotConnected
    from http.server import BaseHTTPRequestHandler

try:
    # Python 2
    xrange = xrange
except NameError:
    # Python 3
    xrange = range

import threading
if hasattr(threading.Thread, "daemon"):
    # Python 2.6+
    def get_daemon(t):
        return t.daemon
    def set_daemon(t, val):
        t.daemon = val
else:
    def get_daemon(t):
        return t.isDaemon()
    def set_daemon(t, val):
        t.setDaemon(val)

try:
    from email.utils import formatdate
    def HTTPDate(timeval=None):
        return formatdate(timeval, usegmt=True)
except ImportError:
    from rfc822 import formatdate as HTTPDate

try:
    # Python 3
    from urllib.parse import unquote as parse_unquote
    def unquote_qs(atom, encoding, errors='strict'):
        return parse_unquote(atom.replace('+', ' '), encoding=encoding, errors=errors)
except ImportError:
    # Python 2
    from urllib import unquote as parse_unquote
    def unquote_qs(atom, encoding, errors='strict'):
        return parse_unquote(atom.replace('+', ' ')).decode(encoding, errors)

try:
    # Prefer simplejson, which is usually more advanced than the builtin module.
    import simplejson as json
    json_decode = json.JSONDecoder().decode
    json_encode = json.JSONEncoder().iterencode
except ImportError:
    if sys.version_info >= (3, 0):
        # Python 3.0: json is part of the standard library,
        # but outputs unicode. We need bytes.
        import json
        json_decode = json.JSONDecoder().decode
        _json_encode = json.JSONEncoder().iterencode
        def json_encode(value):
            for chunk in _json_encode(value):
                yield chunk.encode('utf8')
    elif sys.version_info >= (2, 6):
        # Python 2.6: json is part of the standard library
        import json
        json_decode = json.JSONDecoder().decode
        json_encode = json.JSONEncoder().iterencode
    else:
        json = None
        def json_decode(s):
            raise ValueError('No JSON library is available')
        def json_encode(s):
            raise ValueError('No JSON library is available')

try:
    import cPickle as pickle
except ImportError:
    # In Python 2, pickle is a Python version.
    # In Python 3, pickle is the sped-up C version.
    import pickle

try:
    os.urandom(20)
    import binascii
    def random20():
        return binascii.hexlify(os.urandom(20)).decode('ascii')
except (AttributeError, NotImplementedError):
    import random
    # os.urandom not available until Python 2.4. Fall back to random.random.
    def random20():
        return sha('%s' % random.random()).hexdigest()

try:
    from _thread import get_ident as get_thread_ident
except ImportError:
    from thread import get_ident as get_thread_ident

try:
    # Python 3
    next = next
except NameError:
    # Python 2
    def next(i):
        return i.next()