File: query_string.py

package info (click to toggle)
python-urlobject 2.3.4-1
  • links: PTS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 276 kB
  • ctags: 474
  • sloc: python: 1,256; makefile: 135
file content (150 lines) | stat: -rw-r--r-- 4,330 bytes parent folder | download
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