Parsing a query into pairs preserves duplicate names long enough to reject them.
Make this comfortable
Python query strings: retain blank fields and reject repeated keys
Operation contract
An owned pair list encodes a slash in the receipt identifier before transmission. The decoder retains blank values, requires exactly one receipt and one amount, and rejects repeated fields. It also caps the field count before building an application mapping.
Failure boundary
parse_qsl is a field parser, not a complete request validator. Percent escapes, Unicode normalization, numeric ranges, and authorization need separate rules. A query field limit does not cap the total request-line bytes; impose a byte limit at the receiving layer too.
Working program
from urllib.parse import parse_qsl, urlencode
def parse_receipt_query(query):
pairs = parse_qsl(query, keep_blank_values=True, strict_parsing=True,
errors="strict", max_num_fields=2)
if len(pairs) != 2 or {name for name, _ in pairs} != {"receipt", "amount"}:
raise ValueError("wrong or repeated fields")
fields = dict(pairs)
if not fields["receipt"] or not fields["amount"].isascii() or not fields["amount"].isdecimal():
raise ValueError("invalid field")
return fields["receipt"], int(fields["amount"])
wire_query = urlencode([("receipt", "R/47"), ("amount", "73")])
print("wire", wire_query)
print("parsed", parse_receipt_query(wire_query))
for rejected_query in ("receipt=R-47&receipt=R-73", "receipt=&amount=73",
"receipt=R-47&amount=73&mode=paid"):
try:
parse_receipt_query(rejected_query)
except ValueError:
print("rejected", rejected_query.split("&")[0])Output
wire receipt=R%2F47&amount=73
parsed ('R/47', 73)
rejected receipt=R-47
rejected receipt=
rejected receipt=R-47Costs and limits
Parsing scans the query and allocates decoded field strings. The two-field ceiling bounds field count only; the caller must also cap query bytes before parsing.
Common Mistakes
- Converting to a dict first silently discards the fact that a key repeated.
- The default parser may discard blank values unless asked to retain them.
- Field count is not a request-byte budget.
Connected lessons
python
query-field-duplicates
