build_query and parse_query round-trip
Python
"""Build and parse query strings with merged defaults and repeated keys."""
from typing import Any
from urllib.parse import parse_qs, urlencode
def build_query(params: dict[str, Any], defaults: dict[str, Any] | None = None) -> str:
"""Encode params over defaults; list values repeat the key."""
merged = {**(defaults or {}), **params}
pairs = [
(key, item)
for key, value in merged.items()
if value is not None
for item in (value if isinstance(value, (list, tuple)) else [value])
]
return urlencode(pairs, doseq=True)
def parse_query(query: str, *, keep_blank: bool = False) -> dict[str, Any]:
"""Read '?a=1&a=2' into {'a': ['1', '2']}; single values unwrap to strings."""
parsed = parse_qs(query.lstrip("?"), keep_blank_values=keep_blank)
return {key: values[0] if len(values) == 1 else values for key, values in parsed.items()}
if __name__ == "__main__":
query = build_query({"page": 2, "tag": ["py", "api"]}, {"page": 1, "sort": "new"})
print(query) # page=2&sort=new&tag=py&tag=api
print(parse_query(query)) # {'page': '2', 'sort': 'new', 'tag': ['py', 'api']}