qs_codec package¶
Subpackages¶
- qs_codec.enums package
- qs_codec.models package- Submodules
- qs_codec.models.decode_options module- DecodeOptions- DecodeOptions.allow_dots
- DecodeOptions.allow_empty_lists
- DecodeOptions.charset
- DecodeOptions.charset_sentinel
- DecodeOptions.comma
- DecodeOptions.decode()
- DecodeOptions.decode_dot_in_keys
- DecodeOptions.decode_key()
- DecodeOptions.decode_value()
- DecodeOptions.decoder()
- DecodeOptions.delimiter
- DecodeOptions.depth
- DecodeOptions.duplicates
- DecodeOptions.ignore_query_prefix
- DecodeOptions.interpret_numeric_entities
- DecodeOptions.legacy_decoder
- DecodeOptions.list_limit
- DecodeOptions.parameter_limit
- DecodeOptions.parse_lists
- DecodeOptions.raise_on_limit_exceeded
- DecodeOptions.strict_depth
- DecodeOptions.strict_null_handling
 
 
- qs_codec.models.encode_options module- EncodeOptions- EncodeOptions.add_query_prefix
- EncodeOptions.allow_dots
- EncodeOptions.allow_empty_lists
- EncodeOptions.charset
- EncodeOptions.charset_sentinel
- EncodeOptions.comma_compact_nulls
- EncodeOptions.comma_round_trip
- EncodeOptions.delimiter
- EncodeOptions.encode
- EncodeOptions.encode_dot_in_keys
- EncodeOptions.encode_values_only
- EncodeOptions.encoder
- EncodeOptions.filter
- EncodeOptions.format
- EncodeOptions.indices
- EncodeOptions.list_format
- EncodeOptions.serialize_date()
- EncodeOptions.skip_nulls
- EncodeOptions.sort
- EncodeOptions.strict_null_handling
 
 
- qs_codec.models.undefined module
- qs_codec.models.weak_wrapper module
- Module contents
 
- qs_codec.utils package
Submodules¶
qs_codec.decode module¶
Query string decoder (a.k.a. parser) with feature parity to the Node.js qs package.
Highlights¶
- Accepts either a raw query string or a pre-tokenized mapping (mirrors qs.parse). 
- Supports RFC 3986 / 1738 percent-decoding via DecodeOptions.decoder. 
- Handles bracket notation, indices, dotted keys (opt-in), and duplicate keys strategies. 
- Respects list parsing limits, depth limits, and charset sentinels (utf8=%E2%9C%93 / utf8=%26%2310003%3B). 
- Returns plain dict / list containers and never mutates the caller’s input. 
This module intentionally keeps the control flow close to the original reference implementation so that behavior across ports stays predictable and easy to verify with shared test vectors.
- qs_codec.decode.decode(value: str | Mapping[str, Any] | None, options: DecodeOptions | None = None) Dict[str, Any][source]¶
- Decode a query string (or a pre-tokenized mapping) into a nested - Dict[str, Any].- Parameters:
- value – Either a raw query string ( - str) or an already-parsed mapping (- Mapping[str, Any]). Passing a mapping is useful in tests or when a custom tokenizer is used upstream.
- options – - DecodeOptionscontrolling delimiter, duplicates policy, list & depth limits, dot-notation, decoding charset, and more.
 
- Returns:
- A freshly-allocated mapping containing nested dicts/lists/values. 
- Return type:
- Dict[str, Any] 
- Raises:
- ValueError – If - valueis neither- strnor- Mapping, or when limits are violated under- raise_on_limit_exceeded=True.
 - Notes - Empty/falsey - valuereturns an empty dict.
- When the number of top-level tokens exceeds - list_limitand- parse_listsis enabled, the parser temporarily disables list parsing for this invocation to avoid quadratic work. This mirrors the behavior of other ports and keeps large flat query strings efficient.
 
- qs_codec.decode.load(value: str | Mapping[str, Any] | None, options: DecodeOptions | None = None) Dict[str, Any]¶
- Decode a query string (or a pre-tokenized mapping) into a nested - Dict[str, Any].- Parameters:
- value – Either a raw query string ( - str) or an already-parsed mapping (- Mapping[str, Any]). Passing a mapping is useful in tests or when a custom tokenizer is used upstream.
- options – - DecodeOptionscontrolling delimiter, duplicates policy, list & depth limits, dot-notation, decoding charset, and more.
 
- Returns:
- A freshly-allocated mapping containing nested dicts/lists/values. 
- Return type:
- Dict[str, Any] 
- Raises:
- ValueError – If - valueis neither- strnor- Mapping, or when limits are violated under- raise_on_limit_exceeded=True.
 - Notes - Empty/falsey - valuereturns an empty dict.
- When the number of top-level tokens exceeds - list_limitand- parse_listsis enabled, the parser temporarily disables list parsing for this invocation to avoid quadratic work. This mirrors the behavior of other ports and keeps large flat query strings efficient.
 
- qs_codec.decode.loads(value: str | None, options: DecodeOptions | None = None) Dict[str, Any][source]¶
- Alias for - decode. Decodes a query string into a- Dict[str, Any].- Use - decodeif you want to pass a- Dict[str, Any].
qs_codec.encode module¶
Query‑string encoder (stringifier).
This module converts Python mappings and sequences into a percent‑encoded query string with feature parity to the Node.js qs package where it makes sense for Python. It supports:
- Stable, deterministic key ordering with an optional custom comparator. 
- Multiple list encodings (indices, brackets, repeat key, comma) including the “comma round‑trip” behavior to preserve single‑element lists. 
- Custom per‑scalar encoder and datetime serializer hooks. 
- RFC 3986 vs RFC 1738 formatting and optional charset sentinels. 
- Dots vs brackets in key paths (allow_dots, encode_dot_in_keys). 
- Strict/null handling, empty‑list emission, and cycle detection. 
Nothing in this module mutates caller objects: inputs are shallow‑normalized and deep‑copied only where safe/necessary to honor options.
- qs_codec.encode.dumps(value: ~typing.Any, options: ~qs_codec.models.encode_options.EncodeOptions = EncodeOptions(allow_dots=False, add_query_prefix=False, allow_empty_lists=False, indices=None, list_format=<ListFormat.INDICES: list_format_name='INDICES', generator=<function ListFormatGenerator.indices>>, charset=<Charset.UTF8: encoding='utf-8'>, charset_sentinel=False, delimiter='&', encode=True, encode_dot_in_keys=False, encode_values_only=False, format=<Format.RFC3986: format_name='RFC3986', formatter=<function Formatter.rfc3986>>, filter=None, skip_nulls=False, serialize_date=<function EncodeUtils.serialize_date>, encoder=<function EncodeOptions.encoder.<locals>.<lambda>>, strict_null_handling=False, comma_round_trip=None, comma_compact_nulls=False, sort=None)) str¶
- Stringify a Python value into a query string. - Parameters:
- value – The object to encode. Accepted shapes: * Mapping -> encoded as-is. * Sequence (list/tuple) -> treated as an object with string indices. * Other/None -> treated as empty input. 
- options – Encoding behavior (parity with the Node.js qs API). 
 
- Returns:
- The encoded query string (possibly prefixed with “?” if requested), or an empty string when there is nothing to encode. 
 - Notes - Caller input is not mutated. When a mapping is provided it is deep-copied; sequences are projected to a temporary mapping. 
- If a callable filter is provided, it can transform the root object. 
- If an iterable filter is provided, it selects which root keys to emit. 
 
- qs_codec.encode.encode(value: ~typing.Any, options: ~qs_codec.models.encode_options.EncodeOptions = EncodeOptions(allow_dots=False, add_query_prefix=False, allow_empty_lists=False, indices=None, list_format=<ListFormat.INDICES: list_format_name='INDICES', generator=<function ListFormatGenerator.indices>>, charset=<Charset.UTF8: encoding='utf-8'>, charset_sentinel=False, delimiter='&', encode=True, encode_dot_in_keys=False, encode_values_only=False, format=<Format.RFC3986: format_name='RFC3986', formatter=<function Formatter.rfc3986>>, filter=None, skip_nulls=False, serialize_date=<function EncodeUtils.serialize_date>, encoder=<function EncodeOptions.encoder.<locals>.<lambda>>, strict_null_handling=False, comma_round_trip=None, comma_compact_nulls=False, sort=None)) str[source]¶
- Stringify a Python value into a query string. - Parameters:
- value – The object to encode. Accepted shapes: * Mapping -> encoded as-is. * Sequence (list/tuple) -> treated as an object with string indices. * Other/None -> treated as empty input. 
- options – Encoding behavior (parity with the Node.js qs API). 
 
- Returns:
- The encoded query string (possibly prefixed with “?” if requested), or an empty string when there is nothing to encode. 
 - Notes - Caller input is not mutated. When a mapping is provided it is deep-copied; sequences are projected to a temporary mapping. 
- If a callable filter is provided, it can transform the root object. 
- If an iterable filter is provided, it selects which root keys to emit. 
 
Module contents¶
Query string encoding/decoding for Python.
This package is a Python port of the popular qs library for JavaScript/Node.js. It strives to match qs semantics and edge cases — including list/array formats, duplicate key handling, RFC 3986 vs RFC 1738 formatting, character set sentinels, and other interoperability details.
The package root re-exports the most commonly used functions and enums so you can:
>>> from qs_codec import encode, decode, ListFormat, EncodeOptions
>>> encode({"a": [1, 2, 3]}, options=EncodeOptions(list_format=ListFormat.brackets))
'a[]=1&a[]=2&a[]=3'
- class qs_codec.Charset(*values)[source]
- Bases: - _CharsetDataMixin,- Enum- Supported character sets for query-string processing. - Each enum member’s value is the codec string understood by Python’s encoding APIs. Prefer accessing - encodinginstead of hard-coding literals.- LATIN1 = _CharsetDataMixin(encoding='iso-8859-1')
- ISO-8859-1 (Latin-1) character encoding. 
 - UTF8 = _CharsetDataMixin(encoding='utf-8')
- UTF-8 character encoding. 
 
- class qs_codec.DecodeKind(*values)[source]
- Bases: - str,- Enum- Decoding context for query string tokens. - KEY
- Decode a key (or key segment). Note that the default scalar decoder ( - qs_codec.utils.decode_utils.decode) ignores kind and fully decodes percent-encoded dots (- %2E/- %2e). Dot-splitting behavior is applied later by higher-level parser options.
 - VALUE
- Decode a value. Implementations typically perform full percent decoding. 
 - KEY = 'key'
 - VALUE = 'value'
 
- class qs_codec.DecodeOptions(allow_dots: bool | None = None, decode_dot_in_keys: bool | None = None, allow_empty_lists: bool = False, list_limit: int = 20, charset: ~qs_codec.enums.charset.Charset = Charset.UTF8, charset_sentinel: bool = False, comma: bool = False, delimiter: str | ~typing.Pattern[str] = '&', depth: int = 5, parameter_limit: int | float = 1000, duplicates: ~qs_codec.enums.duplicates.Duplicates = Duplicates.COMBINE, ignore_query_prefix: bool = False, interpret_numeric_entities: bool = False, parse_lists: bool = True, strict_depth: bool = False, strict_null_handling: bool = False, raise_on_limit_exceeded: bool = False, decoder: ~typing.Callable[[...], str | None] | None = <bound method DecodeUtils.decode of <class 'qs_codec.utils.decode_utils.DecodeUtils'>>, legacy_decoder: ~typing.Callable[[...], str | None] | None = None)[source]
- Bases: - object- Options that configure the output of - decode.- allow_dots: bool | None = None
- Set to - Trueto decode dot- dictnotation in the encoded input. When- None(default), it inherits the value of- decode_dot_in_keys.
 - allow_empty_lists: bool = False
- Set to - Trueto allow empty- listvalues inside- dicts in the encoded input.
 - charset: Charset = _CharsetDataMixin(encoding='utf-8')
- The character encoding to use when decoding the input. 
 - charset_sentinel: bool = False
- Some services add an initial - utf8=✓value to forms so that old InternetExplorer versions are more likely to submit the form as- utf-8. Additionally, the server can check the value against wrong encodings of the checkmark character and detect that a query string or- application/x-www-form-urlencodedbody was not sent as- utf-8, e.g. if the form had an- accept-charsetparameter or the containing page had a different character set.- qs_codecsupports this mechanism via the- charset_sentineloption. If specified, the- utf-8parameter will be omitted from the returned- dict. It will be used to switch to- LATIN1or- UTF8mode depending on how the checkmark is encoded.- Important: When you specify both the - charsetoption and the- charset_sentineloption, the- charsetwill be overridden when the request contains a- utf-8parameter from which the actual charset can be deduced. In that sense the- charsetwill behave as the default charset rather than the authoritative charset.
 - comma: bool = False
- Set to - Trueto parse the input as a comma-separated value. Note: nested- dicts, such as- 'a={b:1},{c:d}'are not supported.
 - decode(value: str | None, charset: Charset | None = None, *, kind: DecodeKind = DecodeKind.VALUE) Any | None[source]
- Unified scalar decode with key/value context. - Uses the configured - decoder(or- legacy_decoder) when provided; otherwise falls back to- DecodeUtils.decode(). The default library behavior decodes keys identically to values; whether a- .participates in key splitting is decided later by the parser.
 - decode_dot_in_keys: bool | None = None
- Set to - Trueto decode percent‑encoded dots in keys (e.g.,- %2E→- .). Note: it implies- allow_dots, so- decodewill error if you set- decode_dot_in_keysto- True, and- allow_dotsto- False. When- None(default), it defaults to- False.- Inside bracket segments, percent-decoding naturally yields - .from- %2E/%2e. This option controls whether top‑level encoded dots are treated as additional split points; it does not affect the literal- .produced by percent-decoding inside bracket segments.
 - decode_key(value: str | None, charset: Charset | None = None) str | None[source]
- Decode a key (or key segment). Always returns a string or - None.- Note: custom decoders returning non-strings for keys are coerced via - str().
 - decode_value(value: str | None, charset: Charset | None = None) Any | None[source]
- Decode a value token. Returns any scalar or - None.
 - classmethod decoder(string: str | None, charset: Charset | None = Charset.UTF8, kind: DecodeKind = DecodeKind.VALUE) str | None
- Decode a URL‑encoded scalar. - Notes - The kind parameter is accepted for API compatibility but is currently ignored; keys and values are decoded identically. It may be removed in a future major release. - Behavior: - Replace - +with a literal space before decoding. - If- charsetis- LATIN1, decode only- %XXbyte sequences (no- %uXXXX).- %uXXXXsequences are left as‑is to mimic older browser/JS behavior. - Otherwise (UTF‑8), defer to- urllib.parse.unquote(). - Keys and values are decoded identically; whether a literal- .acts as a key separator is decided later by the key‑splitting logic.- Returns:
- Nonewhen the input is- None.
- Return type:
- Optional[str] 
 
 - delimiter: str | Pattern[str] = '&'
- The delimiter to use when splitting key-value pairs in the encoded input. Can be a - stror a- Pattern.
 - depth: int = 5
- By default, when nesting - dicts- qs_codecwill only decode up to 5 children deep. This depth can be overridden by setting the- depth. The depth limit helps mitigate abuse when- qs_codecis used to parse user input, and it is recommended to keep it a reasonably small number.
 - duplicates: Duplicates = 1
- Strategy for handling duplicate keys in the input. - COMBINE(default): merge values into a list (e.g.,- a=1&a=2→- {"a": [1, 2]}).
- FIRST: keep the first value and ignore subsequent ones (- {"a": 1}).
- LAST: keep only the last value seen (- {"a": 2}).
 
 - ignore_query_prefix: bool = False
- Set to - Trueto ignore the leading question mark query prefix in the encoded input.
 - interpret_numeric_entities: bool = False
- Set to - Trueto interpret HTML numeric entities (- &#...;) in the encoded input.
 - legacy_decoder: Callable[[...], str | None] | None = None
- Back‑compat adapter for legacy decoders of the form - decoder(value, charset). Prefer- decoderwhich may optionally accept a- kindargument. When both are supplied,- decodertakes precedence (mirroring Kotlin/C#/Swift/Dart behavior).
 - list_limit: int = 20
- 20).- During decoding, keys like - a[0],- a[1], … are treated as list indices. If an index exceeds this limit, the container is treated as a- dictinstead, with the numeric index kept as a string key (e.g.,- {"999": "x"}) to prevent creation of massive sparse lists (e.g.,- a[999999999]).- This limit also applies to comma–split lists when - comma=True. Set a larger value if you explicitly need more items, or set a smaller one to harden against abuse.- Type:
- Maximum number of indexed items allowed in a single list (default 
 
 - parameter_limit: int | float = 1000
- For similar reasons, by default - qs_codecwill only parse up to 1000 parameters. This can be overridden by passing a- parameter_limitoption.
 - parse_lists: bool = True
- To disable - listparsing entirely, set- parse_liststo- False.
 - raise_on_limit_exceeded: bool = False
- Raise instead of degrading gracefully when limits are exceeded. - When - True, the decoder raises: - a- DecodeErrorfor parameter and list limit violations; and - an- IndexErrorwhen nesting deeper than- depthand- strict_depth=True.- When - False(default), the decoder degrades gracefully: it slices the parameter list at- parameter_limit, stops adding items beyond- list_limit, and—if- strict_depth=True—stops descending once- depthis reached without raising.
 - strict_depth: bool = False
- Enforce the - depthlimit when decoding nested structures.- When - True, the decoder will not descend beyond- depthlevels. Combined with- raise_on_limit_exceeded:- if - raise_on_limit_exceeded=True, exceeding the depth raises an- IndexError;
- if - False, the decoder stops descending and treats deeper content as a terminal value, preserving the last valid container without raising.
 
 - strict_null_handling: bool = False
- Set to - Trueto decode values without- =to- None.
 
- class qs_codec.Duplicates(*values)[source]
- Bases: - Enum- Defines how to resolve duplicate keys produced during parsing. - This is consulted by the decoder when more than one value is encountered for the same key. It does not affect encoding. - Members¶- COMBINE
- Combine duplicate keys into a single list of values (preserves order). 
- FIRST
- Keep only the first occurrence and discard subsequent ones. 
- LAST
- Keep only the last occurrence, overwriting prior ones. 
 - COMBINE = 1
- Combine duplicate keys into a single list of values (preserves order). 
 - FIRST = 2
- Keep only the first value encountered for the key. 
 - LAST = 3
- Keep only the last value encountered for the key. 
 
- class qs_codec.EncodeOptions(allow_dots: bool = None, add_query_prefix: bool = False, allow_empty_lists: bool = False, indices: bool | None = None, list_format: ~qs_codec.enums.list_format.ListFormat = ListFormat.INDICES, charset: ~qs_codec.enums.charset.Charset = Charset.UTF8, charset_sentinel: bool = False, delimiter: str = '&', encode: bool = True, encode_dot_in_keys: bool = None, encode_values_only: bool = False, format: ~qs_codec.enums.format.Format = Format.RFC3986, filter: ~typing.Callable | ~typing.List[str | int] | None = None, skip_nulls: bool = False, serialize_date: ~typing.Callable[[~datetime.datetime], str | None] = <function EncodeUtils.serialize_date>, encoder: ~typing.Callable[[~typing.Any, ~qs_codec.enums.charset.Charset | None, ~qs_codec.enums.format.Format | None], str] = <property object>, strict_null_handling: bool = False, comma_round_trip: bool | None = None, comma_compact_nulls: bool = False, sort: ~typing.Callable[[~typing.Any, ~typing.Any], int] | None = None)[source]
- Bases: - object- Options that configure the output of encode. - Each field corresponds to a knob in the query-string encoder. Defaults aim to be unsurprising and compatible with other Techouse qs ports. See per-field docs below for details and caveats. - add_query_prefix: bool = False
- When True, prefix the output with a ? (useful when appending to a base URL). 
 - allow_dots: bool = None
- When True, interpret dotted keys as object paths during encoding (e.g. a.b=1). If None, mirrors encode_dot_in_keys (see __post_init__). 
 - allow_empty_lists: bool = False
- When True, include empty lists in the output (e.g. a[]= instead of omitting). 
 - charset: Charset = _CharsetDataMixin(encoding='utf-8')
- Character encoding used by the encoder (defaults to UTF‑8). 
 - charset_sentinel: bool = False
- When True, include a sentinel parameter announcing the charset (e.g. utf8=✓). 
 - comma_compact_nulls: bool = False
- Only with ListFormat.COMMA. When True, omit None entries inside lists instead of emitting empty positions (e.g. [True, False, None, True] -> true,false,true). 
 - comma_round_trip: bool | None = None
- Only used with ListFormat.COMMA. When True, single‑item lists append [] so they round‑trip back to a list on decode. 
 - delimiter: str = '&'
- Pair delimiter between tokens (typically &; ; and others are allowed). 
 - encode: bool = True
- Master switch. When False, values/keys are not percent‑encoded (joined as-is). 
 - encode_dot_in_keys: bool = None
- When True, encode dots in keys literally. With encode_values_only=True, only key dots are encoded while values remain untouched. 
 - encode_values_only: bool = False
- When True, the encoder is applied to values only; keys are left unencoded. 
 - property encoder: Callable[[Any, Charset | None, Format | None], str]
- Return a view of the encoder bound to the current charset and format. - The returned callable has signature (value) -> str and internally calls the underlying _encoder(value, self.charset, self.format). 
 - filter: Callable | List[str | int] | None = None
- Restrict which keys get included. - If a callable is provided, it is invoked for each key and should return the replacement value (or None to drop when skip_nulls applies). - If a list is provided, only those keys/indices are retained. 
 - format: Format = _FormatDataMixin(format_name='RFC3986', formatter=<function Formatter.rfc3986>)
- Space handling and percent‑encoding style. RFC3986 encodes spaces as %20, while RFC1738 uses +. 
 - indices: bool | None = None
- prefer list_format. If set, maps to ListFormat.INDICES when True or ListFormat.REPEAT when False. - Type:
- Deprecated 
 
 - list_format: ListFormat = _ListFormatDataMixin(list_format_name='INDICES', generator=<function ListFormatGenerator.indices>)
- Controls how lists are encoded (indices/brackets/repeat/comma). See ListFormat. 
 - serialize_date() str
- Serialize a datetime to ISO‑8601 using datetime.isoformat(). 
 - skip_nulls: bool = False
- When True, omit keys whose value is None entirely (no trailing =). 
 - sort: Callable[[Any, Any], int] | None = None
- Optional comparator for deterministic key ordering. Must return -1, 0, or +1. 
 - strict_null_handling: bool = False
- None → a (no =), empty string → a=. - Type:
- When True, distinguish empty strings from None 
 
 
- class qs_codec.Format(*values)[source]
- Bases: - _FormatDataMixin,- Enum- Supported URI component formatting profiles. - Each enum value packs a - (format_name, formatter)tuple. After raw percent-encoding is performed by the encoder, the selected profile’s- formatteris called to adjust the final textual representation (e.g., mapping- "%20"to- "+"for RFC 1738).- RFC1738 = _FormatDataMixin(format_name='RFC1738', formatter=<function Formatter.rfc1738>)
 - RFC3986 = _FormatDataMixin(format_name='RFC3986', formatter=<function Formatter.rfc3986>)
 
- class qs_codec.ListFormat(*values)[source]
- Bases: - _ListFormatDataMixin,- Enum- Available list formatting options for the encoder. - Each member pairs a stable name with a generator function from - ListFormatGenerator:- BRACKETS:- foo[]for each element.
- INDICES:- foo[0],- foo[1], …
- REPEAT: repeat the key per value (- foo=1&foo=2).
- COMMA: single key with comma‑joined values (- foo=1,2).
 - These options control only how keys are produced; value encoding and delimiter handling are governed by other options. - BRACKETS = _ListFormatDataMixin(list_format_name='BRACKETS', generator=<function ListFormatGenerator.brackets>)
- Use brackets to represent list items, for example - foo[]=123&foo[]=456&foo[]=789.
 - COMMA = _ListFormatDataMixin(list_format_name='COMMA', generator=<function ListFormatGenerator.comma>)
- Use commas to represent list items, for example - foo=123,456,789.
 - INDICES = _ListFormatDataMixin(list_format_name='INDICES', generator=<function ListFormatGenerator.indices>)
- Use indices to represent list items, for example - foo[0]=123&foo[1]=456&foo[2]=789.
 - REPEAT = _ListFormatDataMixin(list_format_name='REPEAT', generator=<function ListFormatGenerator.repeat>)
- Use a repeat key to represent list items, for example - foo=123&foo=456&foo=789.
 
- class qs_codec.Sentinel(*values)[source]
- Bases: - _SentinelDataMixin,- Enum- All supported - utf8sentinels.- Each enum member provides:
- raw: the source token a browser starts with, and
- encoded: the final, percent-encoded- utf8=…fragment.
 
 - CHARSET = _SentinelDataMixin(raw='✓', encoded='utf8=%E2%9C%93')
- UTF‑8 sentinel indicating the request is UTF‑8 encoded. - This is the percent‑encoded UTF‑8 sequence for ✓, yielding the fragment - utf8=%E2%9C%93.
 - ISO = _SentinelDataMixin(raw='✓', encoded='utf8=%26%2310003%3B')
- HTML‑entity sentinel used by non‑UTF‑8 submissions. - When a check mark (✓) appears but the page/form encoding is - iso-8859-1(or another charset that lacks ✓), browsers first HTML‑entity‑escape it as- "✓"and then URL‑encode it, producing- utf8=%26%2310003%3B.
 
- class qs_codec.Undefined[source]
- Bases: - object- Singleton sentinel object representing an “undefined” value. - Notes - This is not the same as None. Use None to represent a null value and Undefined() to represent “no value / omit”. 
- All calls to - Undefined()return the same instance. Prefer identity checks (- is) over equality checks.
 - Examples - >>> from qs_codec.models.undefined import Undefined >>> a = Undefined() >>> b = Undefined() >>> a is b True >>> # Use it to indicate a key should be omitted when encoding: >>> maybe_value = Undefined() >>> if maybe_value is Undefined(): ... pass # skip emitting the key 
- qs_codec.decode(value: str | Mapping[str, Any] | None, options: DecodeOptions | None = None) Dict[str, Any][source]
- Decode a query string (or a pre-tokenized mapping) into a nested - Dict[str, Any].- Parameters:
- value – Either a raw query string ( - str) or an already-parsed mapping (- Mapping[str, Any]). Passing a mapping is useful in tests or when a custom tokenizer is used upstream.
- options – - DecodeOptionscontrolling delimiter, duplicates policy, list & depth limits, dot-notation, decoding charset, and more.
 
- Returns:
- A freshly-allocated mapping containing nested dicts/lists/values. 
- Return type:
- Dict[str, Any] 
- Raises:
- ValueError – If - valueis neither- strnor- Mapping, or when limits are violated under- raise_on_limit_exceeded=True.
 - Notes - Empty/falsey - valuereturns an empty dict.
- When the number of top-level tokens exceeds - list_limitand- parse_listsis enabled, the parser temporarily disables list parsing for this invocation to avoid quadratic work. This mirrors the behavior of other ports and keeps large flat query strings efficient.
 
- qs_codec.dumps(value: ~typing.Any, options: ~qs_codec.models.encode_options.EncodeOptions = EncodeOptions(allow_dots=False, add_query_prefix=False, allow_empty_lists=False, indices=None, list_format=<ListFormat.INDICES: list_format_name='INDICES', generator=<function ListFormatGenerator.indices>>, charset=<Charset.UTF8: encoding='utf-8'>, charset_sentinel=False, delimiter='&', encode=True, encode_dot_in_keys=False, encode_values_only=False, format=<Format.RFC3986: format_name='RFC3986', formatter=<function Formatter.rfc3986>>, filter=None, skip_nulls=False, serialize_date=<function EncodeUtils.serialize_date>, encoder=<function EncodeOptions.encoder.<locals>.<lambda>>, strict_null_handling=False, comma_round_trip=None, comma_compact_nulls=False, sort=None)) str
- Stringify a Python value into a query string. - Parameters:
- value – The object to encode. Accepted shapes: * Mapping -> encoded as-is. * Sequence (list/tuple) -> treated as an object with string indices. * Other/None -> treated as empty input. 
- options – Encoding behavior (parity with the Node.js qs API). 
 
- Returns:
- The encoded query string (possibly prefixed with “?” if requested), or an empty string when there is nothing to encode. 
 - Notes - Caller input is not mutated. When a mapping is provided it is deep-copied; sequences are projected to a temporary mapping. 
- If a callable filter is provided, it can transform the root object. 
- If an iterable filter is provided, it selects which root keys to emit. 
 
- qs_codec.encode(value: ~typing.Any, options: ~qs_codec.models.encode_options.EncodeOptions = EncodeOptions(allow_dots=False, add_query_prefix=False, allow_empty_lists=False, indices=None, list_format=<ListFormat.INDICES: list_format_name='INDICES', generator=<function ListFormatGenerator.indices>>, charset=<Charset.UTF8: encoding='utf-8'>, charset_sentinel=False, delimiter='&', encode=True, encode_dot_in_keys=False, encode_values_only=False, format=<Format.RFC3986: format_name='RFC3986', formatter=<function Formatter.rfc3986>>, filter=None, skip_nulls=False, serialize_date=<function EncodeUtils.serialize_date>, encoder=<function EncodeOptions.encoder.<locals>.<lambda>>, strict_null_handling=False, comma_round_trip=None, comma_compact_nulls=False, sort=None)) str[source]
- Stringify a Python value into a query string. - Parameters:
- value – The object to encode. Accepted shapes: * Mapping -> encoded as-is. * Sequence (list/tuple) -> treated as an object with string indices. * Other/None -> treated as empty input. 
- options – Encoding behavior (parity with the Node.js qs API). 
 
- Returns:
- The encoded query string (possibly prefixed with “?” if requested), or an empty string when there is nothing to encode. 
 - Notes - Caller input is not mutated. When a mapping is provided it is deep-copied; sequences are projected to a temporary mapping. 
- If a callable filter is provided, it can transform the root object. 
- If an iterable filter is provided, it selects which root keys to emit. 
 
- qs_codec.load(value: str | Mapping[str, Any] | None, options: DecodeOptions | None = None) Dict[str, Any]
- Decode a query string (or a pre-tokenized mapping) into a nested - Dict[str, Any].- Parameters:
- value – Either a raw query string ( - str) or an already-parsed mapping (- Mapping[str, Any]). Passing a mapping is useful in tests or when a custom tokenizer is used upstream.
- options – - DecodeOptionscontrolling delimiter, duplicates policy, list & depth limits, dot-notation, decoding charset, and more.
 
- Returns:
- A freshly-allocated mapping containing nested dicts/lists/values. 
- Return type:
- Dict[str, Any] 
- Raises:
- ValueError – If - valueis neither- strnor- Mapping, or when limits are violated under- raise_on_limit_exceeded=True.
 - Notes - Empty/falsey - valuereturns an empty dict.
- When the number of top-level tokens exceeds - list_limitand- parse_listsis enabled, the parser temporarily disables list parsing for this invocation to avoid quadratic work. This mirrors the behavior of other ports and keeps large flat query strings efficient.
 
- qs_codec.loads(value: str | None, options: DecodeOptions | None = None) Dict[str, Any][source]
- Alias for - decode. Decodes a query string into a- Dict[str, Any].- Use - decodeif you want to pass a- Dict[str, Any].