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
|
import collections
import re
import urllib
from .compat import urlparse
from six import text_type, string_types, u
class QueryString(text_type):
def __repr__(self):
return u('QueryString(%r)') % (text_type(self),)
@property
def list(self):
result = []
if not self:
# Empty string => empty list.
return result
name_value_pairs = re.split(r'[\&\;]', self)
for name_value_pair in name_value_pairs:
# Split the pair string into a naive, encoded (name, value) pair.
name_value = name_value_pair.split('=', 1)
# 'param=' => ('param', None)
if len(name_value) == 1:
name, value = name_value + [None]
# 'param=value' => ('param', 'value')
# 'param=' => ('param', '')
else:
name, value = name_value
name = qs_decode(name)
if value is not None:
value = qs_decode(value)
result.append((name, value))
return result
@property
def dict(self):
return dict(self.list)
@property
def multi_dict(self):
result = collections.defaultdict(list)
for name, value in self.list:
result[name].append(value)
return dict(result)
def add_param(self, name, value):
if value is None:
parameter = qs_encode(name)
elif not isinstance(value, string_types) and hasattr(value, '__iter__'):
# value is a list or tuple
parameter = '&'.join([qs_encode(name) + '=' + qs_encode(val) for val in value])
else:
parameter = qs_encode(name) + '=' + qs_encode(value)
if self:
return type(self)(self + '&' + parameter)
return type(self)(parameter)
def add_params(self, *args, **kwargs):
params_list = get_params_list(*args, **kwargs)
new = self
for name, value in params_list:
new = new.add_param(name, value)
return new
def del_param(self, name):
params = [(n, v) for n, v in self.list if n != name]
qs = type(self)('')
for param in params:
qs = qs.add_param(*param)
return qs
def set_param(self, name, value):
return self.del_param(name).add_param(name, value)
def set_params(self, *args, **kwargs):
params_list = get_params_list(*args, **kwargs)
new = self
for name, value in params_list:
new = new.set_param(name, value)
return new
def del_params(self, params):
deleted = set(params)
params = [(name, value) for name, value in self.list
if name not in deleted]
qs = type(self)('')
for param in params:
qs = qs.add_param(*param)
return qs
def get_params_list(*args, **kwargs):
"""Turn dict-like arguments into an ordered list of pairs."""
params = []
if args:
if len(args) > 1:
raise TypeError("Expected at most 1 arguments, got 2")
arg = args[0]
if hasattr(arg, 'items'):
params.extend(arg.items())
else:
params.extend(list(arg))
if kwargs:
params.extend(kwargs.items())
return params
def _qs_encode_py2(s):
"""Quote unicode or str using query string rules."""
if isinstance(s, unicode):
s = s.encode('utf-8')
return urllib.quote_plus(s).decode('utf-8')
def _qs_encode_py3(s):
"""Quote str or bytes using query string rules."""
# s can be bytes or unicode, urllib.parse.quote() assumes
# utf-8 if encoding is necessary.
return urlparse.quote_plus(s)
def _qs_decode_py2(s):
"""Unquote unicode or str using query string rules."""
if isinstance(s, unicode):
s = s.encode('utf-8')
return urllib.unquote_plus(s).decode('utf-8')
def _qs_decode_py3(s):
"""Unquote str or bytes using query string rules."""
if isinstance(s, bytes):
s = s.decode('utf-8')
return urlparse.unquote_plus(s)
if hasattr(urllib, 'quote'):
qs_encode = _qs_encode_py2
qs_decode = _qs_decode_py2
del _qs_encode_py3
del _qs_decode_py3
else:
qs_encode = _qs_encode_py3
qs_decode = _qs_decode_py3
del _qs_encode_py2
del _qs_decode_py2
|