forked from cherrypy/cherrypy
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path_cpcompat.py
More file actions
156 lines (124 loc) · 4.91 KB
/
_cpcompat.py
File metadata and controls
156 lines (124 loc) · 4.91 KB
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
"""Compatibility code for using CherryPy with various versions of Python.
To retain compatibility with older Python versions, 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
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.
"""
import re
import sys
import threading
import base64
import six
from six.moves import urllib
if six.PY3:
def ntob(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 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.
"""
assert_native(n)
# In Python 3, the native string type is unicode
return n
def tonative(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 unicode
if isinstance(n, bytes):
return n.decode(encoding)
return n
else:
# Python 2
def ntob(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.
return n
def ntou(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.
if encoding == 'escape':
return six.text_type( # unicode for Python 2
re.sub(r'\\u([0-9a-zA-Z]{4})',
lambda m: six.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.
return n.decode(encoding)
def tonative(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.
if isinstance(n, six.text_type): # unicode for Python 2
return n.encode(encoding)
return n
def assert_native(n):
if not isinstance(n, str):
raise TypeError('n must be a native str (got %s)' % type(n).__name__)
def base64_decode(n, encoding='ISO-8859-1'):
"""Return the native string base64-decoded (as a native string)."""
decoded = base64.decodestring(n.encode('ascii'))
return tonative(decoded, encoding)
# Some platforms don't expose HTTPSConnection, so handle it separately
HTTPSConnection = getattr(six.moves.http_client, 'HTTPSConnection', None)
def unquote_qs(atom, encoding, errors='strict'):
atom_spc = atom.replace('+', ' ')
return (
urllib.parse.unquote(atom_spc, encoding=encoding, errors=errors)
if six.PY3 else
urllib.parse.unquote(atom_spc).decode(encoding, errors)
)
try:
# Prefer simplejson
import simplejson as json
except ImportError:
import json
json_decode = json.JSONDecoder().decode
_json_encode = json.JSONEncoder().iterencode
if six.PY3:
# Encode to bytes on Python 3
def json_encode(value):
for chunk in _json_encode(value):
yield chunk.encode('utf-8')
else:
json_encode = _json_encode
text_or_bytes = six.text_type, six.binary_type
if sys.version_info >= (3, 3):
Timer = threading.Timer
Event = threading.Event
else:
# Python 3.2 and earlier
Timer = threading._Timer
Event = threading._Event
# html module come in 3.2 version
try:
from html import escape
except ImportError:
from cgi import escape
# html module needed the argument quote=False because in cgi the default
# is False. With quote=True the results differ.
def escape_html(s, escape_quote=False):
"""Replace special characters "&", "<" and ">" to HTML-safe sequences.
When escape_quote=True, escape (') and (") chars.
"""
return escape(s, quote=escape_quote)