Skip to content

Commit 3e1b19a

Browse files
committed
📝 update readme
1 parent 2b685c6 commit 3e1b19a

2 files changed

Lines changed: 102 additions & 0 deletions

File tree

README.rst

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,96 @@ A simple usage example:
4949
# Decoding
5050
assert qs.decode('a=b') == {'a': 'b'}
5151
52+
Compared with ``urllib.parse``
53+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
54+
55+
The standard library's
56+
`urlencode <https://docs.python.org/3/library/urllib.parse.html#urllib.parse.urlencode>`__,
57+
`parse_qs <https://docs.python.org/3/library/urllib.parse.html#urllib.parse.parse_qs>`__,
58+
and
59+
`parse_qsl <https://docs.python.org/3/library/urllib.parse.html#urllib.parse.parse_qsl>`__
60+
are designed for conventional flat ``application/x-www-form-urlencoded``
61+
data. Use ``qs_codec`` when the query represents nested dictionaries or lists,
62+
must interoperate with Node ``qs``, or needs configurable list, duplicate, null,
63+
or resource-limit behavior.
64+
65+
``urlencode`` can expand a flat sequence into repeated keys with
66+
``doseq=True``, which corresponds to ``ListFormat.REPEAT``. It does not
67+
recursively encode nested mappings; ``qs.encode`` uses bracket or dot paths
68+
instead:
69+
70+
.. code:: python
71+
72+
from urllib.parse import urlencode
73+
74+
import qs_codec as qs
75+
76+
assert urlencode({'tags': ['a', 'b']}, doseq=True) == 'tags=a&tags=b'
77+
assert qs.encode(
78+
{'tags': ['a', 'b']},
79+
qs.EncodeOptions(list_format=qs.ListFormat.REPEAT),
80+
) == 'tags=a&tags=b'
81+
assert qs.encode(
82+
{'filter': {'name': 'Jane'}},
83+
) == 'filter%5Bname%5D=Jane'
84+
85+
The encoding defaults also differ: ``urlencode`` emits spaces as ``+`` and
86+
uses Python scalar spellings such as ``True`` and ``None``; ``qs.encode`` uses
87+
``%20``, lowercase booleans, and an empty value for ``None`` by default.
88+
89+
On decode, ``parse_qs`` returns a dictionary whose values are always lists,
90+
while ``parse_qsl`` returns an ordered list of name/value pairs and preserves
91+
interleaved duplicate keys. Both treat bracket expressions as literal key
92+
names, drop blank values unless ``keep_blank_values=True``, and collapse a
93+
name-only token and an explicit empty value to the same empty string.
94+
``qs.decode`` normally returns a scalar for one value, reconstructs bracket
95+
paths, and can preserve that null distinction:
96+
97+
.. code:: python
98+
99+
from urllib.parse import parse_qs, parse_qsl
100+
101+
import qs_codec as qs
102+
103+
query = 'a=1&b=2&a=3&filter%5Bname%5D=Jane&flag&empty='
104+
105+
assert parse_qs(query, keep_blank_values=True) == {
106+
'a': ['1', '3'],
107+
'b': ['2'],
108+
'filter[name]': ['Jane'],
109+
'flag': [''],
110+
'empty': [''],
111+
}
112+
assert parse_qsl(query, keep_blank_values=True) == [
113+
('a', '1'),
114+
('b', '2'),
115+
('a', '3'),
116+
('filter[name]', 'Jane'),
117+
('flag', ''),
118+
('empty', ''),
119+
]
120+
assert qs.decode(
121+
query,
122+
qs.DecodeOptions(strict_null_handling=True),
123+
) == {
124+
'a': ['1', '3'],
125+
'b': '2',
126+
'filter': {'name': 'Jane'},
127+
'flag': None,
128+
'empty': '',
129+
}
130+
131+
All three decoders leave primitive values as strings. ``parse_qs`` and
132+
``qs.decode`` combine repeated flat keys under their default behavior;
133+
``parse_qsl`` instead retains each pair in input order. The standard-library
134+
parsers offer ``max_num_fields``; ``qs.decode`` additionally provides default
135+
parameter, nesting-depth, and list limits plus configurable duplicate handling.
136+
137+
Use ``parse_qsl`` when flat pair order or duplicate interleaving matters, but
138+
not as a raw-query round-trip format: it percent-decodes names and values,
139+
normalizes ``+`` and ``%20`` to the same space, and cannot retain the distinction
140+
between a name-only token and an explicit empty value.
141+
52142
Working with URLs
53143
~~~~~~~~~~~~~~~~~
54144

docs/index.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,18 @@ A simple usage example:
5353
# Decoding
5454
assert qs.decode('a=b') == {'a': 'b'}
5555
56+
Compared with ``urllib.parse``
57+
-------------------------------
58+
59+
Use ``urllib.parse.urlencode``, ``parse_qs``, and ``parse_qsl`` for conventional
60+
flat form data. ``urlencode`` does not recursively encode nested mappings.
61+
``parse_qs`` groups values by name; ``parse_qsl`` instead preserves pair order
62+
and interleaved duplicates. Both parsers treat bracket expressions as literal
63+
keys and collapse a name-only token and an explicit empty value when blanks are
64+
retained. Use ``qs_codec`` for nested dictionaries and lists, Node ``qs``
65+
interoperability, configurable duplicate and null semantics, or matching
66+
``encode``/``decode`` support. See :doc:`README` for URL composition guidance.
67+
5668
.. toctree::
5769
:maxdepth: 2
5870
:caption: Contents:

0 commit comments

Comments
 (0)