From eff6b0e05aabf6999880ddefe7051f0df2bf9d57 Mon Sep 17 00:00:00 2001 From: techouse Date: Sat, 11 May 2024 09:15:23 +0000 Subject: [PATCH] deploy: d80fc9c9a399559ac31746328d7dfca740c123c9 --- .buildinfo | 4 + .doctrees/README.doctree | Bin 0 -> 110517 bytes .doctrees/environment.pickle | Bin 0 -> 727672 bytes .doctrees/index.doctree | Bin 0 -> 25163 bytes .doctrees/modules.doctree | Bin 0 -> 2761 bytes .doctrees/qs_codec.doctree | Bin 0 -> 23946 bytes .doctrees/qs_codec.enums.doctree | Bin 0 -> 84576 bytes .doctrees/qs_codec.models.doctree | Bin 0 -> 136641 bytes .doctrees/qs_codec.utils.doctree | Bin 0 -> 74563 bytes .nojekyll | 0 README.html | 942 ++++++++++++++++++ _modules/index.html | 118 +++ _modules/qs_codec/decode.html | 300 ++++++ _modules/qs_codec/encode.html | 404 ++++++++ _modules/qs_codec/enums/charset.html | 129 +++ _modules/qs_codec/enums/duplicates.html | 124 +++ _modules/qs_codec/enums/format.html | 154 +++ _modules/qs_codec/enums/list_format.html | 176 ++++ _modules/qs_codec/enums/sentinel.html | 134 +++ _modules/qs_codec/models/decode_options.html | 199 ++++ _modules/qs_codec/models/encode_options.html | 225 +++++ _modules/qs_codec/models/undefined.html | 121 +++ _modules/qs_codec/models/weak_wrapper.html | 147 +++ _modules/qs_codec/utils/decode_utils.html | 177 ++++ _modules/qs_codec/utils/encode_utils.html | 266 ++++++ _modules/qs_codec/utils/str_utils.html | 123 +++ _modules/qs_codec/utils/utils.html | 347 +++++++ _sources/README.rst.txt | 951 +++++++++++++++++++ _sources/index.rst.txt | 92 ++ _sources/modules.rst.txt | 7 + _sources/qs_codec.enums.rst.txt | 53 ++ _sources/qs_codec.models.rst.txt | 45 + _sources/qs_codec.rst.txt | 39 + _sources/qs_codec.utils.rst.txt | 45 + _static/alabaster.css | 708 ++++++++++++++ _static/basic.css | 925 ++++++++++++++++++ _static/custom.css | 1 + _static/doctools.js | 156 +++ _static/documentation_options.js | 13 + _static/file.png | Bin 0 -> 286 bytes _static/language_data.js | 199 ++++ _static/minus.png | Bin 0 -> 90 bytes _static/plus.png | Bin 0 -> 90 bytes _static/pygments.css | 84 ++ _static/searchtools.js | 619 ++++++++++++ _static/sphinx_highlight.js | 154 +++ genindex.html | 613 ++++++++++++ index.html | 161 ++++ modules.html | 164 ++++ objects.inv | Bin 0 -> 1180 bytes py-modindex.html | 213 +++++ qs_codec.enums.html | 313 ++++++ qs_codec.html | 315 ++++++ qs_codec.models.html | 421 ++++++++ qs_codec.utils.html | 240 +++++ search.html | 125 +++ searchindex.js | 1 + 57 files changed, 10747 insertions(+) create mode 100644 .buildinfo create mode 100644 .doctrees/README.doctree create mode 100644 .doctrees/environment.pickle create mode 100644 .doctrees/index.doctree create mode 100644 .doctrees/modules.doctree create mode 100644 .doctrees/qs_codec.doctree create mode 100644 .doctrees/qs_codec.enums.doctree create mode 100644 .doctrees/qs_codec.models.doctree create mode 100644 .doctrees/qs_codec.utils.doctree create mode 100644 .nojekyll create mode 100644 README.html create mode 100644 _modules/index.html create mode 100644 _modules/qs_codec/decode.html create mode 100644 _modules/qs_codec/encode.html create mode 100644 _modules/qs_codec/enums/charset.html create mode 100644 _modules/qs_codec/enums/duplicates.html create mode 100644 _modules/qs_codec/enums/format.html create mode 100644 _modules/qs_codec/enums/list_format.html create mode 100644 _modules/qs_codec/enums/sentinel.html create mode 100644 _modules/qs_codec/models/decode_options.html create mode 100644 _modules/qs_codec/models/encode_options.html create mode 100644 _modules/qs_codec/models/undefined.html create mode 100644 _modules/qs_codec/models/weak_wrapper.html create mode 100644 _modules/qs_codec/utils/decode_utils.html create mode 100644 _modules/qs_codec/utils/encode_utils.html create mode 100644 _modules/qs_codec/utils/str_utils.html create mode 100644 _modules/qs_codec/utils/utils.html create mode 100644 _sources/README.rst.txt create mode 100644 _sources/index.rst.txt create mode 100644 _sources/modules.rst.txt create mode 100644 _sources/qs_codec.enums.rst.txt create mode 100644 _sources/qs_codec.models.rst.txt create mode 100644 _sources/qs_codec.rst.txt create mode 100644 _sources/qs_codec.utils.rst.txt create mode 100644 _static/alabaster.css create mode 100644 _static/basic.css create mode 100644 _static/custom.css create mode 100644 _static/doctools.js create mode 100644 _static/documentation_options.js create mode 100644 _static/file.png create mode 100644 _static/language_data.js create mode 100644 _static/minus.png create mode 100644 _static/plus.png create mode 100644 _static/pygments.css create mode 100644 _static/searchtools.js create mode 100644 _static/sphinx_highlight.js create mode 100644 genindex.html create mode 100644 index.html create mode 100644 modules.html create mode 100644 objects.inv create mode 100644 py-modindex.html create mode 100644 qs_codec.enums.html create mode 100644 qs_codec.html create mode 100644 qs_codec.models.html create mode 100644 qs_codec.utils.html create mode 100644 search.html create mode 100644 searchindex.js diff --git a/.buildinfo b/.buildinfo new file mode 100644 index 0000000..15c4834 --- /dev/null +++ b/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: ccceffa458940e20969a232f6352bfc3 +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/.doctrees/README.doctree b/.doctrees/README.doctree new file mode 100644 index 0000000000000000000000000000000000000000..fbb49533ca1495b5399ea342ea20939f6400be31 GIT binary patch literal 110517 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 dV{ac7IL8b}g5V!+i_c4&%X|+u1{{xNbef0nU literal 0 HcmV?d00001 diff --git a/.doctrees/environment.pickle b/.doctrees/environment.pickle new file mode 100644 index 0000000000000000000000000000000000000000..d783c1061debc4b1f4ec92b3898cba8d25b50fe5 GIT binary patch literal 727672 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 @BR`# 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 DW&;Pd literal 0 HcmV?d00001 diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/README.html b/README.html new file mode 100644 index 0000000..7fb2dc5 --- /dev/null +++ b/README.html @@ -0,0 +1,942 @@ + + + + + + + + Decoding — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

Decoding

+
+

dictionaries

+
import qs_codec, typing as t
+
+def decode(
+    value: t.Optional[t.Union[str, t.Mapping]],
+    options: qs_codec.DecodeOptions = qs_codec.DecodeOptions(),
+) -> dict:
+    """Decodes a str or Mapping into a Dict.
+
+    Providing custom DecodeOptions will override the default behavior."""
+    pass
+
+
+

decode allows you to create nested dicts within your query +strings, by surrounding the name of sub-keys with square brackets +[]. For example, the string 'foo[bar]=baz' converts to:

+
import qs_codec
+
+assert qs_codec.decode('foo[bar]=baz') == {'foo': {'bar': 'baz'}}
+
+
+

URI encoded strings work too:

+
import qs_codec
+
+assert qs_codec.decode('a%5Bb%5D=c') == {'a': {'b': 'c'}}
+
+
+

You can also nest your dicts, like 'foo[bar][baz]=foobarbaz':

+
import qs_codec
+
+assert qs_codec.decode('foo[bar][baz]=foobarbaz') == {'foo': {'bar': {'baz': 'foobarbaz'}}}
+
+
+

By default, when nesting dicts qs will only decode up to 5 +children deep. This means if you attempt to decode a string like +'a[b][c][d][e][f][g][h][i]=j' your resulting dict will be:

+
import qs_codec
+
+assert qs_codec.decode("a[b][c][d][e][f][g][h][i]=j") == {
+    "a": {"b": {"c": {"d": {"e": {"f": {"[g][h][i]": "j"}}}}}}
+}
+
+
+

This depth can be overridden by setting the depth:

+
import qs_codec
+
+assert qs_codec.decode(
+    'a[b][c][d][e][f][g][h][i]=j',
+    qs_codec.DecodeOptions(depth=1),
+) == {'a': {'b': {'[c][d][e][f][g][h][i]': 'j'}}}
+
+
+

The depth limit helps mitigate abuse when decode is used to parse user +input, and it is recommended to keep it a reasonably small number.

+

For similar reasons, by default decode will only parse up to 1000 parameters. This can be overridden by passing a +parameter_limit option:

+
import qs_codec
+
+assert qs_codec.decode(
+    'a=b&c=d',
+    qs_codec.DecodeOptions(parameter_limit=1),
+) == {'a': 'b'}
+
+
+

To bypass the leading question mark, use +ignore_query_prefix:

+
import qs_codec
+
+assert qs_codec.decode(
+    '?a=b&c=d',
+    qs_codec.DecodeOptions(ignore_query_prefix=True),
+) == {'a': 'b', 'c': 'd'}
+
+
+

An optional delimiter can also be passed:

+
import qs_codec
+
+assert qs_codec.decode(
+    'a=b;c=d',
+    qs_codec.DecodeOptions(delimiter=';'),
+) == {'a': 'b', 'c': 'd'}
+
+
+

delimiter can be a regular expression too:

+
import re, qs_codec
+
+assert qs_codec.decode(
+    'a=b;c=d',
+    qs_codec.DecodeOptions(delimiter=re.compile(r'[;,]')),
+) == {'a': 'b', 'c': 'd'}
+
+
+

Option allow_dots +can be used to enable dot notation:

+
import qs_codec
+
+assert qs_codec.decode(
+    'a.b=c',
+    qs_codec.DecodeOptions(allow_dots=True),
+) == {'a': {'b': 'c'}}
+
+
+

Option decode_dot_in_keys +can be used to decode dots in keys.

+

Note: it implies allow_dots, so +decode will error if you set decode_dot_in_keys +to True, and allow_dots to False.

+
import qs_codec
+
+assert qs_codec.decode(
+    'name%252Eobj.first=John&name%252Eobj.last=Doe',
+    qs_codec.DecodeOptions(decode_dot_in_keys=True),
+) == {'name.obj': {'first': 'John', 'last': 'Doe'}}
+
+
+

Option allow_empty_lists can +be used to allowing empty list values in a dict

+
import qs_codec
+
+assert qs_codec.decode(
+    'foo[]&bar=baz',
+    qs_codec.DecodeOptions(allow_empty_lists=True),
+) == {'foo': [], 'bar': 'baz'}
+
+
+

Option duplicates can be used to +change the behavior when duplicate keys are encountered

+
import qs_codec
+
+assert qs_codec.decode('foo=bar&foo=baz') == {'foo': ['bar', 'baz']}
+
+assert qs_codec.decode(
+    'foo=bar&foo=baz',
+    qs_codec.DecodeOptions(duplicates=qs_codec.Duplicates.COMBINE),
+) == {'foo': ['bar', 'baz']}
+
+assert qs_codec.decode(
+    'foo=bar&foo=baz',
+    qs_codec.DecodeOptions(duplicates=qs_codec.Duplicates.FIRST),
+) == {'foo': 'bar'}
+
+assert qs_codec.decode(
+    'foo=bar&foo=baz',
+    qs_codec.DecodeOptions(duplicates=qs_codec.Duplicates.LAST),
+) == {'foo': 'baz'}
+
+
+

If you have to deal with legacy browsers or services, there’s also +support for decoding percent-encoded octets as LATIN1:

+
import qs_codec
+
+assert qs_codec.decode(
+    'a=%A7',
+    qs_codec.DecodeOptions(charset=qs_codec.Charset.LATIN1),
+) == {'a': '§'}
+
+
+

Some services add an initial utf8=✓ value to forms so that old +Internet Explorer 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-urlencoded body was not sent as utf-8, +e.g. if the form had an accept-charset parameter or the containing +page had a different character set.

+

decode supports this mechanism via the +charset_sentinel option. +If specified, the utf8 parameter will be omitted from the returned +dict. It will be used to switch to LATIN1 or +UTF8 mode depending on how the checkmark is encoded.

+

Important: When you specify both the charset +option and the charset_sentinel option, the +charset will be overridden when the request contains a +utf8 parameter from which the actual charset can be deduced. In that +sense the charset will behave as the default charset +rather than the authoritative charset.

+
import qs_codec
+
+assert qs_codec.decode(
+    'utf8=%E2%9C%93&a=%C3%B8',
+    qs_codec.DecodeOptions(
+        charset=qs_codec.Charset.LATIN1,
+        charset_sentinel=True,
+    ),
+) == {'a': 'ø'}
+
+assert qs_codec.decode(
+    'utf8=%26%2310003%3B&a=%F8',
+    qs_codec.DecodeOptions(
+        charset=qs_codec.Charset.UTF8,
+        charset_sentinel=True,
+    ),
+) == {'a': 'ø'}
+
+
+

If you want to decode the &#…; syntax to the actual character, you can specify the +interpret_numeric_entities +option as well:

+
import qs_codec
+
+assert qs_codec.decode(
+    'a=%26%239786%3B',
+    qs_codec.DecodeOptions(
+        charset=qs_codec.Charset.LATIN1,
+        interpret_numeric_entities=True,
+    ),
+) == {'a': '☺'}
+
+
+

It also works when the charset has been detected in +charset_sentinel mode.

+
+
+

lists

+

decode can also decode lists using a similar [] notation:

+
import qs_codec
+
+assert qs_codec.decode('a[]=b&a[]=c') == {'a': ['b', 'c']}
+
+
+

You may specify an index as well:

+
import qs_codec
+
+assert qs_codec.decode('a[1]=c&a[0]=b') == {'a': ['b', 'c']}
+
+
+

Note that the only difference between an index in a list and a key +in a dict is that the value between the brackets must be a number to +create a list. When creating lists with specific indices, +decode will compact a sparse list to +only the existing values preserving their order:

+
import qs_codec
+
+assert qs_codec.decode('a[1]=b&a[15]=c') == {'a': ['b', 'c']}
+
+
+

Note that an empty string is also a value, and will be preserved:

+
import qs_codec
+
+assert qs_codec.decode('a[]=&a[]=b') == {'a': ['', 'b']}
+
+assert qs_codec.decode('a[0]=b&a[1]=&a[2]=c') == {'a': ['b', '', 'c']}
+
+
+

decode will also limit specifying indices +in a list to a maximum index of 20. Any list members with an +index of greater than 20 will instead be converted to a dict with +the index as the key. This is needed to handle cases when someone sent, +for example, a[999999999] and it will take significant time to iterate +over this huge list.

+
import qs_codec
+
+assert qs_codec.decode('a[100]=b') == {'a': {100: 'b'}}
+
+
+

This limit can be overridden by passing an list_limit +option:

+
import qs_codec
+
+assert qs_codec.decode(
+    'a[1]=b',
+    qs_codec.DecodeOptions(list_limit=0),
+) == {'a': {1: 'b'}}
+
+
+

To disable list parsing entirely, set parse_lists +to False.

+
import qs_codec
+
+assert qs_codec.decode(
+    'a[]=b',
+    qs_codec.DecodeOptions(parse_lists=False),
+) == {'a': {0: 'b'}}
+
+
+

If you mix notations, decode will merge the two items into a dict:

+
import qs_codec
+
+assert qs_codec.decode('a[0]=b&a[b]=c') == {'a': {0: 'b', 'b': 'c'}}
+
+
+

You can also create lists of dicts:

+
import qs_codec
+
+assert qs_codec.decode('a[][b]=c') == {'a': [{'b': 'c'}]}
+
+
+

(decode cannot convert nested ``dict``s, such as ``’a={b:1},{c:d}’``)

+
+
+

primitive values (int, bool, None, etc.)

+

By default, all values are parsed as strings.

+
import qs_codec
+
+assert qs_codec.decode(
+    'a=15&b=true&c=null',
+) == {'a': '15', 'b': 'true', 'c': 'null'}
+
+
+
+
+
+

Encoding

+
import qs_codec, typing as t
+
+def encode(
+    value: t.Any,
+    options: qs_codec.EncodeOptions = qs_codec.EncodeOptions()
+) -> str:
+    """Encodes an object into a query string.
+
+    Providing custom EncodeOptions will override the default behavior."""
+    pass
+
+
+

When encoding, encode by default URI encodes output. dicts are +encoded as you would expect:

+
import qs_codec
+
+assert qs_codec.encode({'a': 'b'}) == 'a=b'
+assert qs_codec.encode({'a': {'b': 'c'}}) == 'a%5Bb%5D=c'
+
+
+

This encoding can be disabled by setting the encode +option to False:

+
import qs_codec
+
+assert qs_codec.encode(
+    {'a': {'b': 'c'}},
+    qs_codec.EncodeOptions(encode=False),
+) == 'a[b]=c'
+
+
+

Encoding can be disabled for keys by setting the +encode_values_only option to True:

+
import qs_codec
+
+assert qs_codec.encode(
+    {
+        'a': 'b',
+        'c': ['d', 'e=f'],
+        'f': [
+            ['g'],
+            ['h']
+        ]
+    },
+    qs_codec.EncodeOptions(encode_values_only=True)
+) == 'a=b&c[0]=d&c[1]=e%3Df&f[0][0]=g&f[1][0]=h'
+
+
+

This encoding can also be replaced by a custom Callable in the +encoder option:

+
import qs_codec, typing as t
+
+
+def custom_encoder(
+    value: str,
+    charset: t.Optional[qs_codec.Charset],
+    format: t.Optional[qs_codec.Format],
+) -> str:
+    if value == 'č':
+        return 'c'
+    return value
+
+
+assert qs_codec.encode(
+    {'a': {'b': 'č'}},
+    qs_codec.EncodeOptions(encoder=custom_encoder),
+) == 'a[b]=c'
+
+
+

(Note: the encoder option does not apply if +encode is False).

+

Similar to encoder there is a +decoder option for decode +to override decoding of properties and values:

+
import qs_codec, typing as t
+
+def custom_decoder(
+    value: t.Any,
+    charset: t.Optional[qs_codec.Charset],
+) -> t.Union[int, str]:
+    try:
+        return int(value)
+    except ValueError:
+        return value
+
+assert qs_codec.decode(
+    'foo=123',
+    qs_codec.DecodeOptions(decoder=custom_decoder),
+) == {'foo': 123}
+
+
+

Examples beyond this point will be shown as though the output is not URI +encoded for clarity. Please note that the return values in these cases +will be URI encoded during real usage.

+

When lists are encoded, they follow the +list_format option, which defaults to +INDICES:

+
import qs_codec
+
+assert qs_codec.encode(
+    {'a': ['b', 'c', 'd']},
+    qs_codec.EncodeOptions(encode=False)
+) == 'a[0]=b&a[1]=c&a[2]=d'
+
+
+

You may override this by setting the indices option to +False, or to be more explicit, the list_format +option to REPEAT:

+
import qs_codec
+
+assert qs_codec.encode(
+    {'a': ['b', 'c', 'd']},
+    qs_codec.EncodeOptions(
+        encode=False,
+        indices=False,
+    ),
+) == 'a=b&a=c&a=d'
+
+
+

You may use the list_format option to specify the +format of the output list:

+
import qs_codec
+
+# ListFormat.INDICES
+assert qs_codec.encode(
+    {'a': ['b', 'c']},
+    qs_codec.EncodeOptions(
+        encode=False,
+        list_format=qs_codec.ListFormat.INDICES,
+    ),
+) == 'a[0]=b&a[1]=c'
+
+# ListFormat.BRACKETS
+assert qs_codec.encode(
+    {'a': ['b', 'c']},
+    qs_codec.EncodeOptions(
+        encode=False,
+        list_format=qs_codec.ListFormat.BRACKETS,
+    ),
+) == 'a[]=b&a[]=c'
+
+# ListFormat.REPEAT
+assert qs_codec.encode(
+    {'a': ['b', 'c']},
+    qs_codec.EncodeOptions(
+        encode=False,
+        list_format=qs_codec.ListFormat.REPEAT,
+    ),
+) == 'a=b&a=c'
+
+# ListFormat.COMMA
+assert qs_codec.encode(
+    {'a': ['b', 'c']},
+    qs_codec.EncodeOptions(
+        encode=False,
+        list_format=qs_codec.ListFormat.COMMA,
+    ),
+) == 'a=b,c'
+
+
+

Note: When using list_format set to +COMMA, you can also pass the +comma_round_trip option set to True or +False, to append [] on single-item lists, so that they can round trip through a decoding.

+

BRACKETS notation is used for encoding dicts by default:

+
import qs_codec
+
+assert qs_codec.encode(
+    {'a': {'b': {'c': 'd', 'e': 'f'}}},
+    qs_codec.EncodeOptions(encode=False),
+) == 'a[b][c]=d&a[b][e]=f'
+
+
+

You may override this to use dot notation by setting the +allow_dots option to True:

+
import qs_codec
+
+assert qs_codec.encode(
+    {'a': {'b': {'c': 'd', 'e': 'f'}}},
+    qs_codec.EncodeOptions(encode=False, allow_dots=True),
+) == 'a.b.c=d&a.b.e=f'
+
+
+

You may encode dots in keys of dicts by setting +encode_dot_in_keys to True:

+
import qs_codec
+
+assert qs_codec.encode(
+    {'name.obj': {'first': 'John', 'last': 'Doe'}},
+    qs_codec.EncodeOptions(
+        allow_dots=True,
+        encode_dot_in_keys=True,
+    ),
+) == 'name%252Eobj.first=John&name%252Eobj.last=Doe'
+
+
+

Caveat: When both encode_values_only +and encode_dot_in_keys are set to +True, only dots in keys and nothing else will be encoded!

+

You may allow empty list values by setting the +allow_empty_lists option to True:

+
import qs_codec
+
+assert qs_codec.encode(
+    {'foo': [], 'bar': 'baz', },
+    qs_codec.EncodeOptions(
+        encode=False,
+        allow_empty_lists=True,
+    ),
+) == 'foo[]&bar=baz'
+
+
+

Empty strings and None values will be omitted, but the equals sign (=) remains in place:

+
import qs_codec
+
+assert qs_codec.encode({'a': ''}) == 'a='
+
+
+

Keys with no values (such as an empty dict or list) will return nothing:

+
import qs_codec
+
+assert qs_codec.encode({'a': []}) == ''
+
+assert qs_codec.encode({'a': {}}) == ''
+
+assert qs_codec.encode({'a': [{}]}) == ''
+
+assert qs_codec.encode({'a': {'b': []}}) == ''
+
+assert qs_codec.encode({'a': {'b': {}}}) == ''
+
+
+

Undefined properties will be omitted entirely:

+
import qs_codec
+
+assert qs_codec.encode({'a': None, 'b': qs_codec.Undefined()}) == 'a='
+
+
+

The query string may optionally be prepended with a question mark (?) by setting +add_query_prefix to True:

+
import qs_codec
+
+assert qs_codec.encode(
+    {'a': 'b', 'c': 'd'},
+    qs_codec.EncodeOptions(add_query_prefix=True),
+) == '?a=b&c=d'
+
+
+

The delimiter may be overridden as well:

+
import qs_codec
+
+assert qs_codec.encode(
+    {'a': 'b', 'c': 'd', },
+    qs_codec.EncodeOptions(delimiter=';')
+) == 'a=b;c=d'
+
+
+

If you only want to override the serialization of datetime +objects, you can provide a Callable in the +serialize_date option:

+
import qs_codec, datetime, sys
+
+# First case: encoding a datetime object to an ISO 8601 string
+assert (
+    qs_codec.encode(
+        {
+            "a": (
+                datetime.datetime.fromtimestamp(7, datetime.UTC)
+                if sys.version_info.major == 3 and sys.version_info.minor >= 11
+                else datetime.datetime.utcfromtimestamp(7)
+            )
+        },
+        qs_codec.EncodeOptions(encode=False),
+    )
+    == "a=1970-01-01T00:00:07+00:00"
+    if sys.version_info.major == 3 and sys.version_info.minor >= 11
+    else "a=1970-01-01T00:00:07"
+)
+
+# Second case: encoding a datetime object to a timestamp string
+assert (
+    qs_codec.encode(
+        {
+            "a": (
+                datetime.datetime.fromtimestamp(7, datetime.UTC)
+                if sys.version_info.major == 3 and sys.version_info.minor >= 11
+                else datetime.datetime.utcfromtimestamp(7)
+            )
+        },
+        qs_codec.EncodeOptions(encode=False, serialize_date=lambda date: str(int(date.timestamp()))),
+    )
+    == "a=7"
+)
+
+
+

To affect the order of parameter keys, you can set a Callable in the +sort option:

+
import qs_codec
+
+assert qs_codec.encode(
+    {'a': 'c', 'z': 'y', 'b': 'f'},
+    qs_codec.EncodeOptions(
+        encode=False,
+        sort=lambda a, b: (a > b) - (a < b)
+    )
+) == 'a=c&b=f&z=y'
+
+
+

Finally, you can use the filter option to restrict +which keys will be included in the encoded output. If you pass a Callable, it will be called for each key to obtain +the replacement value. Otherwise, if you pass a list, it will be used to select properties and list indices to +be encoded:

+
import qs_codec, datetime, sys
+
+# First case: using a Callable as filter
+assert (
+    qs_codec.encode(
+        {
+            "a": "b",
+            "c": "d",
+            "e": {
+                "f": (
+                    datetime.datetime.fromtimestamp(123, datetime.UTC)
+                    if sys.version_info.major == 3 and sys.version_info.minor >= 11
+                    else datetime.datetime.utcfromtimestamp(123)
+                ),
+                "g": [2],
+            },
+        },
+        qs_codec.EncodeOptions(
+            encode=False,
+            filter=lambda prefix, value: {
+                "b": None,
+                "e[f]": int(value.timestamp()) if isinstance(value, datetime.datetime) else value,
+                "e[g][0]": value * 2 if isinstance(value, int) else value,
+            }.get(prefix, value),
+        ),
+    )
+    == "a=b&c=d&e[f]=123&e[g][0]=4"
+)
+
+# Second case: using a list as filter
+assert qs_codec.encode(
+    {'a': 'b', 'c': 'd', 'e': 'f'},
+    qs_codec.EncodeOptions(
+        encode=False,
+        filter=['a', 'e']
+    )
+) == 'a=b&e=f'
+
+# Third case: using a list as filter with indices
+assert qs_codec.encode(
+    {
+        'a': ['b', 'c', 'd'],
+        'e': 'f',
+    },
+    qs_codec.EncodeOptions(
+        encode=False,
+        filter=['a', 0, 2]
+    )
+) == 'a[0]=b&a[2]=d'
+
+
+
+
+

Handling None values

+

By default, None values are treated like empty strings:

+
import qs_codec
+
+assert qs_codec.encode({'a': None, 'b': ''}) == 'a=&b='
+
+
+

To distinguish between None values and empty strs use the +strict_null_handling flag. +In the result string the None values have no = sign:

+
import qs_codec
+
+assert qs_codec.encode(
+    {'a': None, 'b': ''},
+    qs_codec.EncodeOptions(strict_null_handling=True),
+) == 'a&b='
+
+
+

To decode values without = back to None use the +strict_null_handling flag:

+
import qs_codec
+
+assert qs_codec.decode(
+    'a&b=',
+    qs_codec.DecodeOptions(strict_null_handling=True),
+) == {'a': None, 'b': ''}
+
+
+

To completely skip rendering keys with None values, use the +skip_nulls flag:

+
import qs_codec
+
+assert qs_codec.encode(
+    {'a': 'b', 'c': None},
+    qs_codec.EncodeOptions(skip_nulls=True),
+) == 'a=b'
+
+
+

If you’re communicating with legacy systems, you can switch to +LATIN1 using the +charset option:

+
import qs_codec
+
+assert qs_codec.encode(
+    {'æ': 'æ'},
+    qs_codec.EncodeOptions(charset=qs_codec.Charset.LATIN1)
+) == '%E6=%E6'
+
+
+

Characters that don’t exist in LATIN1 +will be converted to numeric entities, similar to what browsers do:

+
import qs_codec
+
+assert qs_codec.encode(
+    {'a': '☺'},
+    qs_codec.EncodeOptions(charset=qs_codec.Charset.LATIN1)
+) == 'a=%26%239786%3B'
+
+
+

You can use the charset_sentinel +option to announce the character by including an utf8=✓ parameter with the proper +encoding of the checkmark, similar to what Ruby on Rails and others do when submitting forms.

+
import qs_codec
+
+assert qs_codec.encode(
+    {'a': '☺'},
+    qs_codec.EncodeOptions(charset_sentinel=True)
+) == 'utf8=%E2%9C%93&a=%E2%98%BA'
+
+assert qs_codec.encode(
+    {'a': 'æ'},
+    qs_codec.EncodeOptions(charset=qs_codec.Charset.LATIN1, charset_sentinel=True)
+) == 'utf8=%26%2310003%3B&a=%E6'
+
+
+
+
+

Dealing with special character sets

+

By default, the encoding and decoding of characters is done in +UTF8, and +LATIN1 support is also built in via +the charset +and charset parameter, +respectively.

+

If you wish to encode query strings to a different character set (i.e. +Shift JIS)

+
import qs_codec, codecs, typing as t
+
+def custom_encoder(
+    string: str,
+    charset: t.Optional[qs_codec.Charset],
+    format: t.Optional[qs_codec.Format],
+) -> str:
+    if string:
+        buf: bytes = codecs.encode(string, 'shift_jis')
+        result: t.List[str] = ['{:02x}'.format(b) for b in buf]
+        return '%' + '%'.join(result)
+    return ''
+
+assert qs_codec.encode(
+    {'a': 'こんにちは!'},
+    qs_codec.EncodeOptions(encoder=custom_encoder)
+) == '%61=%82%b1%82%f1%82%c9%82%bf%82%cd%81%49'
+
+
+

This also works for decoding of query strings:

+
import qs_codec, re, codecs, typing as t
+
+def custom_decoder(
+    string: str,
+    charset: t.Optional[qs_codec.Charset],
+) -> t.Optional[str]:
+    if string:
+        result: t.List[int] = []
+        while string:
+            match: t.Optional[t.Match[str]] = re.search(r'%([0-9A-F]{2})', string, re.IGNORECASE)
+            if match:
+                result.append(int(match.group(1), 16))
+                string = string[match.end():]
+            else:
+                break
+        buf: bytes = bytes(result)
+        return codecs.decode(buf, 'shift_jis')
+    return None
+
+assert qs_codec.decode(
+    '%61=%82%b1%82%f1%82%c9%82%bf%82%cd%81%49',
+    qs_codec.DecodeOptions(decoder=custom_decoder)
+) == {'a': 'こんにちは!'}
+
+
+
+
+

RFC 3986 and RFC 1738 space encoding

+

The default format is +RFC3986 which encodes +' ' to %20 which is backward compatible. You can also set the +format to +RFC1738 which encodes ' ' to +.

+
import qs_codec
+
+assert qs_codec.encode(
+    {'a': 'b c'},
+    qs_codec.EncodeOptions(format=qs_codec.Format.RFC3986)
+) == 'a=b%20c'
+
+assert qs_codec.encode(
+    {'a': 'b c'},
+    qs_codec.EncodeOptions(format=qs_codec.Format.RFC3986)
+) == 'a=b%20c'
+
+assert qs_codec.encode(
+    {'a': 'b c'},
+    qs_codec.EncodeOptions(format=qs_codec.Format.RFC1738)
+) == 'a=b+c'
+
+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/_modules/index.html b/_modules/index.html new file mode 100644 index 0000000..bdb7ad5 --- /dev/null +++ b/_modules/index.html @@ -0,0 +1,118 @@ + + + + + + + Overview: module code — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/_modules/qs_codec/decode.html b/_modules/qs_codec/decode.html new file mode 100644 index 0000000..2b68b2e --- /dev/null +++ b/_modules/qs_codec/decode.html @@ -0,0 +1,300 @@ + + + + + + + qs_codec.decode — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for qs_codec.decode

+"""A query string decoder (parser)."""
+
+import re
+import typing as t
+from math import isinf
+
+from regex import regex
+
+from .enums.charset import Charset
+from .enums.duplicates import Duplicates
+from .enums.sentinel import Sentinel
+from .models.decode_options import DecodeOptions
+from .models.undefined import Undefined
+from .utils.utils import Utils
+
+
+
+[docs] +def decode(value: t.Optional[t.Union[str, t.Mapping]], options: DecodeOptions = DecodeOptions()) -> dict: + """ + Decodes a ``str`` or ``Mapping`` into a ``dict``. + + Providing custom ``DecodeOptions`` will override the default behavior. + """ + if not value: + return dict() + + if not isinstance(value, (str, t.Mapping)): + raise ValueError("The input must be a String or a Dict") + + temp_obj: t.Optional[t.Mapping] = _parse_query_string_values(value, options) if isinstance(value, str) else value + obj: t.Dict = dict() + + # Iterate over the keys and setup the new object + if temp_obj: + for key, val in temp_obj.items(): + new_obj: t.Any = _parse_keys(key, val, options, isinstance(value, str)) + obj = Utils.merge(obj, new_obj, options) # type: ignore [assignment] + + return Utils.compact(obj)
+ + + +def _interpret_numeric_entities(value: str) -> str: + return re.sub(r"&#(\d+);", lambda match: chr(int(match.group(1))), value) + + +def _parse_array_value(value: t.Any, options: DecodeOptions) -> t.Any: + if isinstance(value, str) and value and options.comma and "," in value: + return value.split(",") + + return value + + +def _parse_query_string_values(value: str, options: DecodeOptions) -> t.Dict: + obj: t.Dict = dict() + + clean_str: str = value.replace("?", "", 1) if options.ignore_query_prefix else value + limit: t.Optional[int] = None if isinf(options.parameter_limit) else options.parameter_limit # type: ignore [assignment] + parts: t.List[str] + if isinstance(options.delimiter, re.Pattern): + parts = re.split(options.delimiter, clean_str) if not limit else re.split(options.delimiter, clean_str)[:limit] + else: + parts = clean_str.split(options.delimiter) if not limit else clean_str.split(options.delimiter)[:limit] + + skip_index: int = -1 # Keep track of where the utf8 sentinel was found + i: int + + charset: Charset = options.charset + + if options.charset_sentinel: + for i, _part in enumerate(parts): + if _part.startswith("utf8="): + if _part == Sentinel.CHARSET.encoded: + charset = Charset.UTF8 + elif _part == Sentinel.ISO.encoded: + charset = Charset.LATIN1 + skip_index = i + break + + for i, _ in enumerate(parts): + if i == skip_index: + continue + + part: str = parts[i] + bracket_equals_pos: int = part.find("]=") + pos: int = part.find("=") if bracket_equals_pos == -1 else (bracket_equals_pos + 1) + + key: str + val: t.Union[t.List, t.Tuple, str, t.Any] + if pos == -1: + key = options.decoder(part, charset) + val = None if options.strict_null_handling else "" + else: + key = options.decoder(part[:pos], charset) + val = Utils.apply( + _parse_array_value(part[pos + 1 :], options), + lambda v: options.decoder(v, charset), + ) + + if val and options.interpret_numeric_entities and charset == Charset.LATIN1: + val = _interpret_numeric_entities(val) # type: ignore [arg-type] + + if "[]=" in part: + val = [val] if isinstance(val, (list, tuple)) else val + + existing: bool = key in obj + + if existing and options.duplicates == Duplicates.COMBINE: + obj[key] = Utils.combine(obj[key], val) + elif not existing or options.duplicates == Duplicates.LAST: + obj[key] = val + + return obj + + +def _parse_object( + chain: t.Union[t.List[str], t.Tuple[str, ...]], val: t.Any, options: DecodeOptions, values_parsed: bool +) -> t.Any: + leaf: t.Any = val if values_parsed else _parse_array_value(val, options) + + i: int + for i in reversed(range(len(chain))): + obj: t.Optional[t.Any] + root: str = chain[i] + + if root == "[]" and options.parse_lists: + if options.allow_empty_lists and leaf == "": + obj = [] + else: + obj = list(leaf) if isinstance(leaf, (list, tuple)) else [leaf] + else: + obj = dict() + + clean_root: str = root[1:-1] if root.startswith("[") and root.endswith("]") else root + + decoded_root: str = clean_root.replace(r"%2E", ".") if options.decode_dot_in_keys else clean_root + + index: t.Optional[int] + try: + index = int(decoded_root, 10) + except (ValueError, TypeError): + index = None + + if not options.parse_lists and decoded_root == "": + obj = {0: leaf} + elif ( + index is not None + and index >= 0 + and root != decoded_root + and str(index) == decoded_root + and options.parse_lists + and index <= options.list_limit + ): + obj = [Undefined() for _ in range(index + 1)] + obj[index] = leaf + else: + obj[index if index is not None else decoded_root] = leaf + + leaf = obj + + return leaf + + +def _parse_keys(given_key: t.Optional[str], val: t.Any, options: DecodeOptions, values_parsed: bool) -> t.Any: + if not given_key: + return + + # Transform dot notation to bracket notation + key: str = re.sub(r"\.([^.[]+)", r"[\1]", given_key) if options.allow_dots else given_key + + # The regex chunks + brackets: regex.Pattern[str] = regex.compile(r"\[(?:[^\[\]]|(?R))*\]") + + # Get the parent + segment: t.Optional[regex.Match] = brackets.search(key) if options.depth > 0 else None + parent: str = key[0 : segment.start()] if segment is not None else key + + # Stash the parent if it exists + keys: t.List[str] = [parent] if parent else [] + + # Loop through children appending to the array until we hit depth + i: int = 0 + while options.depth > 0 and (segment := brackets.search(key)) is not None and i < options.depth: + i += 1 + if segment is not None: + keys.append(segment.group()) + # Update the key to start searching from the next position + key = key[segment.end() :] + + # If there's a remainder, just add whatever is left + if segment is not None: + keys.append(f"[{key[segment.start():]}]") + + return _parse_object(keys, val, options, values_parsed) +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/_modules/qs_codec/encode.html b/_modules/qs_codec/encode.html new file mode 100644 index 0000000..2685925 --- /dev/null +++ b/_modules/qs_codec/encode.html @@ -0,0 +1,404 @@ + + + + + + + qs_codec.encode — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for qs_codec.encode

+"""A query string encoder (stringifier)."""
+
+import typing as t
+from copy import deepcopy
+from datetime import datetime
+from functools import cmp_to_key
+from weakref import WeakKeyDictionary
+
+from .enums.charset import Charset
+from .enums.format import Format
+from .enums.list_format import ListFormat
+from .enums.sentinel import Sentinel
+from .models.encode_options import EncodeOptions
+from .models.undefined import Undefined
+from .models.weak_wrapper import WeakWrapper
+from .utils.utils import Utils
+
+
+
+[docs] +def encode(value: t.Any, options: EncodeOptions = EncodeOptions()) -> str: + """ + Encodes ``Any`` object into a query ``str`` ing. + + Providing custom ``EncodeOptions`` will override the default behavior. + """ + if value is None: + return "" + + obj: t.Mapping[str, t.Any] + if isinstance(value, t.Mapping): + obj = deepcopy(value) + elif isinstance(value, (list, tuple)): + obj = {str(key): value for key, value in enumerate(value)} + else: + obj = {} + + keys: t.List[t.Any] = [] + + if not obj: + return "" + + obj_keys: t.Optional[t.List[t.Any]] = None + + if options.filter is not None: + if callable(options.filter): + obj = options.filter("", obj) + elif isinstance(options.filter, (list, tuple)): + obj_keys = list(options.filter) + + comma_round_trip: bool = options.list_format == ListFormat.COMMA and options.comma_round_trip is True + + if obj_keys is None: + obj_keys = list(obj.keys()) + + if options.sort is not None and callable(options.sort): + obj_keys = sorted(obj_keys, key=cmp_to_key(options.sort)) + + side_channel: WeakKeyDictionary = WeakKeyDictionary() + + for _key in obj_keys: + if not isinstance(_key, str): + continue + if _key in obj and obj.get(_key) is None and options.skip_nulls: + continue + + _encoded: t.Union[t.List[t.Any], t.Tuple[t.Any, ...], t.Any] = _encode( + value=obj.get(_key), + is_undefined=_key not in obj, + side_channel=side_channel, + prefix=_key, + generate_array_prefix=options.list_format.generator, + comma_round_trip=comma_round_trip, + encoder=options.encoder if options.encode else None, + serialize_date=options.serialize_date, + sort=options.sort, + filter=options.filter, + formatter=options.format.formatter, + allow_empty_lists=options.allow_empty_lists, + strict_null_handling=options.strict_null_handling, + skip_nulls=options.skip_nulls, + encode_dot_in_keys=options.encode_dot_in_keys, + allow_dots=options.allow_dots, + format=options.format, + encode_values_only=options.encode_values_only, + charset=options.charset, + add_query_prefix=options.add_query_prefix, + ) + + if isinstance(_encoded, (list, tuple)): + keys.extend(_encoded) + else: + keys.append(_encoded) + + joined: str = options.delimiter.join(keys) + prefix: str = "?" if options.add_query_prefix else "" + + if options.charset_sentinel: + if options.charset == Charset.LATIN1: + prefix += f"{Sentinel.ISO.encoded}&" + elif options.charset == Charset.UTF8: + prefix += f"{Sentinel.CHARSET.encoded}&" + else: + raise ValueError("Invalid charset") + + return prefix + joined if joined else ""
+ + + +_sentinel: WeakWrapper = WeakWrapper({}) + + +def _encode( + value: t.Any, + is_undefined: bool, + side_channel: WeakKeyDictionary, + prefix: t.Optional[str], + comma_round_trip: t.Optional[bool], + encoder: t.Optional[t.Callable[[t.Any, t.Optional[Charset], t.Optional[Format]], str]], + serialize_date: t.Callable[[datetime], t.Optional[str]], + sort: t.Optional[t.Callable[[t.Any, t.Any], int]], + filter: t.Optional[t.Union[t.Callable, t.List[t.Union[str, int]]]], + formatter: t.Optional[t.Callable[[str], str]], + format: Format = Format.RFC3986, + generate_array_prefix: t.Callable[[str, t.Optional[str]], str] = ListFormat.INDICES.generator, + allow_empty_lists: bool = False, + strict_null_handling: bool = False, + skip_nulls: bool = False, + encode_dot_in_keys: bool = False, + allow_dots: bool = False, + encode_values_only: bool = False, + charset: t.Optional[Charset] = Charset.UTF8, + add_query_prefix: bool = False, +) -> t.Union[t.List[t.Any], t.Tuple[t.Any, ...], t.Any]: + if prefix is None: + prefix = "?" if add_query_prefix else "" + + if comma_round_trip is None: + comma_round_trip = generate_array_prefix == ListFormat.COMMA.generator + + if formatter is None: + formatter = format.formatter + + obj: t.Any = deepcopy(value) + + tmp_sc: t.Optional[WeakKeyDictionary] = side_channel + step: int = 0 + find_flag: bool = False + + while (tmp_sc := tmp_sc.get(_sentinel)) and not find_flag: # type: ignore [union-attr] + # Where value last appeared in the ref tree + pos: t.Optional[int] = tmp_sc.get(WeakWrapper(value)) + step += 1 + if pos is not None: + if pos == step: + raise ValueError("Circular reference detected") + else: + find_flag = True # Break while + if tmp_sc.get(_sentinel) is None: + step = 0 + + if callable(filter): + obj = filter(prefix, obj) + elif isinstance(obj, datetime): + obj = serialize_date(obj) if callable(serialize_date) else obj.isoformat() + elif generate_array_prefix == ListFormat.COMMA.generator and isinstance(obj, (list, tuple)): + obj = Utils.apply( + obj, + lambda val: ( + (serialize_date(val) if callable(serialize_date) else val.isoformat()) + if isinstance(val, datetime) + else val + ), + ) + + if not is_undefined and obj is None: + if strict_null_handling: + return encoder(prefix, charset, format) if callable(encoder) and not encode_values_only else prefix + + obj = "" + + if Utils.is_non_nullish_primitive(obj, skip_nulls) or isinstance(obj, bytes): + if callable(encoder): + key_value = prefix if encode_values_only else encoder(prefix, charset, format) + return [f"{formatter(key_value)}={formatter(encoder(obj, charset, format))}"] + + return [f"{formatter(prefix)}={formatter(str(obj))}"] + + values: t.List = [] + + if is_undefined: + return values + + obj_keys: t.List + if generate_array_prefix == ListFormat.COMMA.generator and isinstance(obj, (list, tuple)): + # we need to join elements in + if encode_values_only and callable(encoder): + obj = Utils.apply(obj, encoder) + + if obj: + obj_keys_value = ",".join([str(e) if e is not None else "" for e in obj]) + obj_keys = [{"value": obj_keys_value if obj_keys_value else None}] + else: + obj_keys = [{"value": Undefined()}] + elif isinstance(filter, (list, tuple)): + obj_keys = list(filter) + else: + keys: t.List + if isinstance(obj, t.Mapping): + keys = list(obj.keys()) + elif isinstance(obj, (list, tuple)): + keys = [index for index in range(len(obj))] + else: + keys = [] + + obj_keys = sorted(keys, key=cmp_to_key(sort)) if sort is not None else list(keys) + + encoded_prefix: str = prefix.replace(".", "%2E") if encode_dot_in_keys else prefix + + adjusted_prefix: str = ( + f"{encoded_prefix}[]" + if comma_round_trip and isinstance(obj, (list, tuple)) and len(obj) == 1 + else encoded_prefix + ) + + if allow_empty_lists and isinstance(obj, (list, tuple)) and not obj: + return [f"{adjusted_prefix}[]"] + + for _key in obj_keys: + _value: t.Any + _value_undefined: bool + + if isinstance(_key, t.Mapping) and "value" in _key and not isinstance(_key.get("value"), Undefined): + _value = _key.get("value") + _value_undefined = False + else: + try: + if isinstance(obj, t.Mapping): + _value = obj.get(_key) + _value_undefined = _key not in obj + elif isinstance(obj, (list, tuple)): + _value = obj[_key] + _value_undefined = False + else: + _value = obj[_key] + _value_undefined = False + except Exception: # pylint: disable=W0718 + _value = None + _value_undefined = True + + if skip_nulls and _value is None: + continue + + encoded_key: str = str(_key).replace(".", "%2E") if allow_dots and encode_dot_in_keys else str(_key) + + key_prefix: str = ( + generate_array_prefix(adjusted_prefix, encoded_key) + if isinstance(obj, (list, tuple)) + else f"{adjusted_prefix}{f'.{encoded_key}' if allow_dots else f'[{encoded_key}]'}" + ) + + side_channel[WeakWrapper(value)] = step + value_side_channel: WeakKeyDictionary = WeakKeyDictionary() + value_side_channel[_sentinel] = side_channel + + encoded: t.Union[t.List[t.Any], t.Tuple[t.Any, ...], t.Any] = _encode( + value=_value, + is_undefined=_value_undefined, + side_channel=value_side_channel, + prefix=key_prefix, + comma_round_trip=comma_round_trip, + encoder=( + None + if generate_array_prefix == ListFormat.COMMA.generator + and encode_values_only + and isinstance(obj, (list, tuple)) + else encoder + ), + serialize_date=serialize_date, + sort=sort, + filter=filter, + formatter=formatter, + format=format, + generate_array_prefix=generate_array_prefix, + allow_empty_lists=allow_empty_lists, + strict_null_handling=strict_null_handling, + skip_nulls=skip_nulls, + encode_dot_in_keys=encode_dot_in_keys, + allow_dots=allow_dots, + encode_values_only=encode_values_only, + charset=charset, + ) + + if isinstance(encoded, (list, tuple)): + values.extend(encoded) + else: + values.append(encoded) + + return values +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/_modules/qs_codec/enums/charset.html b/_modules/qs_codec/enums/charset.html new file mode 100644 index 0000000..df05bee --- /dev/null +++ b/_modules/qs_codec/enums/charset.html @@ -0,0 +1,129 @@ + + + + + + + qs_codec.enums.charset — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for qs_codec.enums.charset

+"""Charset enum module."""
+
+from dataclasses import dataclass
+from enum import Enum
+
+
+@dataclass(frozen=True)
+class _CharsetDataMixin:
+    """Character set data mixin."""
+
+    encoding: str
+
+
+
+[docs] +class Charset(_CharsetDataMixin, Enum): + """Character set.""" + + UTF8 = "utf-8" + """UTF-8 character encoding.""" + + LATIN1 = "iso-8859-1" + """ISO-8859-1 (Latin-1) character encoding."""
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/_modules/qs_codec/enums/duplicates.html b/_modules/qs_codec/enums/duplicates.html new file mode 100644 index 0000000..9609a02 --- /dev/null +++ b/_modules/qs_codec/enums/duplicates.html @@ -0,0 +1,124 @@ + + + + + + + qs_codec.enums.duplicates — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for qs_codec.enums.duplicates

+"""This module contains an enum of all available duplicate key handling strategies."""
+
+from enum import Enum
+
+
+
+[docs] +class Duplicates(Enum): + """An enum of all available duplicate key handling strategies.""" + + COMBINE = 1 + """Combine duplicate keys into a single key with an array of values.""" + + FIRST = 2 + """Use the first value for duplicate keys.""" + + LAST = 3 + """Use the last value for duplicate keys."""
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/_modules/qs_codec/enums/format.html b/_modules/qs_codec/enums/format.html new file mode 100644 index 0000000..a3907bb --- /dev/null +++ b/_modules/qs_codec/enums/format.html @@ -0,0 +1,154 @@ + + + + + + + qs_codec.enums.format — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for qs_codec.enums.format

+"""An enum of all supported URI component encoding formats."""
+
+import typing as t
+from dataclasses import dataclass
+from enum import Enum
+
+
+
+[docs] +class Formatter: + """A class for formatting URI components.""" + +
+[docs] + @staticmethod + def rfc1738(value: str) -> str: + """Format a string according to `RFC 1738 <https://datatracker.ietf.org/doc/html/rfc1738>`_.""" + return value.replace("%20", "+")
+ + +
+[docs] + @staticmethod + def rfc3986(value: str) -> str: + """Format a string according to `RFC 3986 <https://datatracker.ietf.org/doc/html/rfc3986>`_.""" + return value
+
+ + + +@dataclass(frozen=True) +class _FormatDataMixin: + """Format data mixin.""" + + format_name: str + formatter: t.Callable[[str], str] + + +
+[docs] +class Format(_FormatDataMixin, Enum): + """An enum of all supported URI component encoding formats.""" + + RFC1738 = "RFC1738", Formatter.rfc1738 + """`RFC 1738 <https://datatracker.ietf.org/doc/html/rfc1738>`_.""" + + RFC3986 = "RFC3986", Formatter.rfc3986 + """`RFC 3986 <https://datatracker.ietf.org/doc/html/rfc3986>`_."""
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/_modules/qs_codec/enums/list_format.html b/_modules/qs_codec/enums/list_format.html new file mode 100644 index 0000000..e068e77 --- /dev/null +++ b/_modules/qs_codec/enums/list_format.html @@ -0,0 +1,176 @@ + + + + + + + qs_codec.enums.list_format — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for qs_codec.enums.list_format

+"""An enum for all available list format options."""
+
+import typing as t
+from dataclasses import dataclass
+from enum import Enum
+
+
+
+[docs] +class ListFormatGenerator: + """A class for formatting list items.""" + +
+[docs] + @staticmethod + def brackets(prefix: str, key: t.Optional[str] = None) -> str: # pylint: disable=W0613 + """Format a list item using brackets.""" + return f"{prefix}[]"
+ + +
+[docs] + @staticmethod + def comma(prefix: str, key: t.Optional[str] = None) -> str: # pylint: disable=W0613 + """Format a list item using commas.""" + return prefix
+ + +
+[docs] + @staticmethod + def indices(prefix: str, key: t.Optional[str] = None) -> str: + """Format a list item using indices.""" + return f"{prefix}[{key}]"
+ + +
+[docs] + @staticmethod + def repeat(prefix: str, key: t.Optional[str] = None) -> str: # pylint: disable=W0613 + """Format a list item using repeats.""" + return prefix
+
+ + + +@dataclass(frozen=True) +class _ListFormatDataMixin: + """List format data mixin.""" + + list_format_name: str + generator: t.Callable[[str, t.Optional[str]], str] + + +
+[docs] +class ListFormat(_ListFormatDataMixin, Enum): + """An enum of all available list format options.""" + + BRACKETS = "BRACKETS", ListFormatGenerator.brackets + """Use brackets to represent list items, for example ``foo[]=123&foo[]=456&foo[]=789``""" + + COMMA = "COMMA", ListFormatGenerator.comma + """Use commas to represent list items, for example ``foo=123,456,789``""" + + REPEAT = "REPEAT", ListFormatGenerator.repeat + """Use a repeat key to represent list items, for example ``foo=123&foo=456&foo=789``""" + + INDICES = "INDICES", ListFormatGenerator.indices + """Use indices to represent list items, for example ``foo[0]=123&foo[1]=456&foo[2]=789``"""
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/_modules/qs_codec/enums/sentinel.html b/_modules/qs_codec/enums/sentinel.html new file mode 100644 index 0000000..a5a82ed --- /dev/null +++ b/_modules/qs_codec/enums/sentinel.html @@ -0,0 +1,134 @@ + + + + + + + qs_codec.enums.sentinel — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for qs_codec.enums.sentinel

+"""This module defines the Sentinel enum, which contains all available sentinel values."""
+
+from dataclasses import dataclass
+from enum import Enum
+
+
+@dataclass(frozen=True)
+class _SentinelDataMixin:
+    """Sentinel data mixin."""
+
+    raw: str
+    encoded: str
+
+
+
+[docs] +class Sentinel(_SentinelDataMixin, Enum): + """An enum of all available sentinel values.""" + + ISO = r"&#10003;", r"utf8=%26%2310003%3B" + """This is what browsers will submit when the ``✓`` character occurs in an ``application/x-www-form-urlencoded`` + body and the encoding of the page containing the form is ``iso-8859-1``, or when the submitted form has an + ``accept-charset`` attribute of ``iso-8859-1``. Presumably also with other charsets that do not contain the ``✓`` + character, such as ``us-ascii``.""" + + CHARSET = r"✓", r"utf8=%E2%9C%93" + """These are the percent-encoded ``utf-8`` octets representing a checkmark, indicating that the request actually is + ``utf-8`` encoded."""
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/_modules/qs_codec/models/decode_options.html b/_modules/qs_codec/models/decode_options.html new file mode 100644 index 0000000..bb74bb3 --- /dev/null +++ b/_modules/qs_codec/models/decode_options.html @@ -0,0 +1,199 @@ + + + + + + + qs_codec.models.decode_options — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for qs_codec.models.decode_options

+"""This module contains the ``DecodeOptions`` class that configures the output of ``decode``."""
+
+import typing as t
+from dataclasses import dataclass, field
+
+from ..enums.charset import Charset
+from ..enums.duplicates import Duplicates
+from ..utils.decode_utils import DecodeUtils
+
+
+
+[docs] +@dataclass +class DecodeOptions: + """Options that configure the output of ``decode``.""" + + allow_dots: bool = field(default=None) # type: ignore [assignment] + """Set to ``True`` to decode dot ``dict`` notation in the encoded input.""" + + decode_dot_in_keys: bool = field(default=None) # type: ignore [assignment] + """Set to ``True`` to decode dots in keys. + Note: it implies ``allow_dots``, so ``decode`` will error if you set ``decode_dot_in_keys`` to ``True``, and + ``allow_dots`` to ``False``.""" + + allow_empty_lists: bool = False + """Set to ``True`` to allow empty ``list`` values inside ``dict``\\s in the encoded input.""" + + list_limit: int = 20 + """``qs_codec`` will limit specifying indices in a ``list`` to a maximum index of ``20``. + Any ``list`` members with an index of greater than ``20`` will instead be converted to a ``dict`` with the index as + the key. This is needed to handle cases when someone sent, for example, ``a[999999999]`` and it will take + significant time to iterate over this huge ``list``. + This limit can be overridden by passing a ``list_limit`` option.""" + + charset: Charset = Charset.UTF8 + """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-urlencoded`` body was *not* sent as ``utf-8``, + e.g. if the form had an ``accept-charset`` parameter or the containing page had a different character set. + + ``qs_codec`` supports this mechanism via the ``charset_sentinel`` option. + If specified, the ``utf-8`` parameter will be omitted from the returned ``dict``. + It will be used to switch to ``LATIN1`` or ``UTF8`` mode depending on how the checkmark is encoded. + + Important: When you specify both the ``charset`` option and the ``charset_sentinel`` option, + the ``charset`` will be overridden when the request contains a ``utf-8`` parameter from which the actual charset + can be deduced. In that sense the ``charset`` will behave as the default charset rather than the authoritative + charset.""" + + comma: bool = False + """Set to ``True`` to parse the input as a comma-separated value. + Note: nested ``dict`` s, such as ``'a={b:1},{c:d}'`` are not supported.""" + + delimiter: t.Union[str, t.Pattern[str]] = "&" + """The delimiter to use when splitting key-value pairs in the encoded input. Can be a ``str`` or a ``Pattern``.""" + + depth: int = 5 + """By default, when nesting ``dict``\\s ``qs_codec`` will only decode up to 5 children deep. + This depth can be overridden by setting the ``depth``. + The depth limit helps mitigate abuse when ``qs_codec`` is used to parse user input, + and it is recommended to keep it a reasonably small number.""" + + parameter_limit: t.Union[int, float] = 1000 + """For similar reasons, by default ``qs_codec`` will only parse up to 1000 parameters. This can be overridden by + passing a ``parameter_limit`` option.""" + + duplicates: Duplicates = Duplicates.COMBINE + """Change the duplicate key handling strategy.""" + + ignore_query_prefix: bool = False + """Set to ``True`` to ignore the leading question mark query prefix in the encoded input.""" + + interpret_numeric_entities: bool = False + """Set to ``True`` to interpret HTML numeric entities (``&#...;``) in the encoded input.""" + + parse_lists: bool = True + """To disable ``list`` parsing entirely, set ``parse_lists`` to ``False``.""" + + strict_null_handling: bool = False + """Set to true to decode values without ``=`` to ``None``.""" + + decoder: t.Callable[[t.Optional[str], t.Optional[Charset]], t.Any] = DecodeUtils.decode + """Set a ``Callable`` to affect the decoding of the input.""" + + def __post_init__(self): + """Post-initialization.""" + if self.allow_dots is None: + self.allow_dots = self.decode_dot_in_keys is True or False + if self.decode_dot_in_keys is None: + self.decode_dot_in_keys = False
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/_modules/qs_codec/models/encode_options.html b/_modules/qs_codec/models/encode_options.html new file mode 100644 index 0000000..3ca0ca8 --- /dev/null +++ b/_modules/qs_codec/models/encode_options.html @@ -0,0 +1,225 @@ + + + + + + + qs_codec.models.encode_options — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for qs_codec.models.encode_options

+"""This module contains the ``EncodeOptions`` class that configures the output of ``encode``."""
+
+import typing as t
+from dataclasses import asdict, dataclass, field
+from datetime import datetime
+
+from ..enums.charset import Charset
+from ..enums.format import Format
+from ..enums.list_format import ListFormat
+from ..utils.encode_utils import EncodeUtils
+
+
+
+[docs] +@dataclass +class EncodeOptions: + """Options that configure the output of ``encode``.""" + + allow_dots: bool = field(default=None) # type: ignore [assignment] + """Set to ``True`` to use dot ``dict`` notation in the encoded output.""" + + add_query_prefix: bool = False + """Set to ``True`` to add a question mark ``?`` prefix to the encoded output.""" + + allow_empty_lists: bool = False + """Set to ``True`` to allow empty ``list`` s in the encoded output.""" + + indices: t.Optional[bool] = None + """Deprecated: Use ``list_format`` instead.""" + + list_format: ListFormat = ListFormat.INDICES + """The ``list`` encoding format to use.""" + + charset: Charset = Charset.UTF8 + """The character encoding to use.""" + + charset_sentinel: bool = False + """Set to ``True`` to announce the character by including an ``utf8=✓`` parameter with the proper encoding of the + checkmark, similar to what Ruby on Rails and others do when submitting forms.""" + + delimiter: str = "&" + """The delimiter to use when joining key-value pairs in the encoded output.""" + + encode: bool = True + """Set to ``False`` to disable encoding.""" + + encode_dot_in_keys: bool = field(default=None) # type: ignore [assignment] + """Encode ``dict`` keys using dot notation by setting ``encode_dot_in_keys`` to ``True``. + Caveat: When ``encode_values_only`` is ``True`` as well as ``encode_dot_in_keys``, only dots in keys and nothing + else will be encoded.""" + + encode_values_only: bool = False + """Encoding can be disabled for keys by setting the ``encode_values_only`` to ``True``.""" + + format: Format = Format.RFC3986 + """The encoding format to use. + The default ``format`` is ``Format.RFC3986`` which encodes ``' '`` to ``%20`` which is backward compatible. + You can also set ``format`` to ``Format.RFC1738`` which encodes ``' '`` to ``+``.""" + + filter: t.Optional[t.Union[t.Callable, t.List[t.Union[str, int]]]] = field(default=None) + """Use the ``filter`` option to restrict which keys will be included in the encoded output. + If you pass a ``Callable``, it will be called for each key to obtain the replacement value. + If you pass a ``list``, it will be used to select properties and ``list`` indices to be encoded.""" + + skip_nulls: bool = False + """Set to ``True`` to completely skip encoding keys with ``None`` values.""" + + serialize_date: t.Callable[[datetime], t.Optional[str]] = EncodeUtils.serialize_date + """If you only want to override the serialization of ``datetime`` objects, you can provide a ``Callable``.""" + + encoder: t.Callable[[t.Any, t.Optional[Charset], t.Optional[Format]], str] = field( # type: ignore [assignment] + default_factory=EncodeUtils.encode # type: ignore [arg-type] + ) + """Set an ``Encoder`` to affect the encoding of values. + Note: the ``encoder`` option does not apply if ``encode`` is ``False``.""" + + _encoder: t.Callable[[t.Any, t.Optional[Charset], t.Optional[Format]], str] = field(init=False, repr=False) + + @property # type: ignore [no-redef] + def encoder(self) -> t.Callable[[t.Any, t.Optional[Charset], t.Optional[Format]], str]: # noqa: F811 + """Get the encoder function.""" + return lambda v, c=self.charset, f=self.format: self._encoder(v, c, f) # type: ignore [misc] + + @encoder.setter + def encoder(self, value: t.Optional[t.Callable[[t.Any, t.Optional[Charset], t.Optional[Format]], str]]) -> None: + self._encoder = value if callable(value) else EncodeUtils.encode # type: ignore [assignment] + + strict_null_handling: bool = False + """Set to ``True`` to distinguish between ``null`` values and empty ``str``\\ings. This way the encoded string + ``None`` values will have no ``=`` sign.""" + + comma_round_trip: t.Optional[bool] = None + """When ``list_format`` is set to ``ListFormat.COMMA``, you can also set ``comma_round_trip`` option to ``True`` or + ``False``, to append ``[]`` on single-item ``list``\\s, so that they can round trip through a parse.""" + + sort: t.Optional[t.Callable[[t.Any, t.Any], int]] = field(default=None) + """Set a ``Callable`` to affect the order of parameter keys.""" + + def __post_init__(self): + """Post-initialization.""" + if self.allow_dots is None: + self.allow_dots = self.encode_dot_in_keys is True or False + if self.encode_dot_in_keys is None: + self.encode_dot_in_keys = False + if self.indices is not None: + self.list_format = ListFormat.INDICES if self.indices else ListFormat.REPEAT + + def __eq__(self, other: object) -> bool: + """Compare two `EncodeOptions` objects.""" + if not isinstance(other, EncodeOptions): + return False + + self_dict = asdict(self) + other_dict = asdict(other) + + self_dict["encoder"] = self._encoder + other_dict["encoder"] = other._encoder + + return self_dict == other_dict
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/_modules/qs_codec/models/undefined.html b/_modules/qs_codec/models/undefined.html new file mode 100644 index 0000000..1ce1bdb --- /dev/null +++ b/_modules/qs_codec/models/undefined.html @@ -0,0 +1,121 @@ + + + + + + + qs_codec.models.undefined — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for qs_codec.models.undefined

+"""Undefined class definition."""
+
+
+
+[docs] +class Undefined: + """Singleton class to represent undefined values.""" + + _instance = None + + def __new__(cls): + """Create a new instance of the class.""" + if cls._instance is None: + cls._instance = super(Undefined, cls).__new__(cls) + return cls._instance
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/_modules/qs_codec/models/weak_wrapper.html b/_modules/qs_codec/models/weak_wrapper.html new file mode 100644 index 0000000..501b5c6 --- /dev/null +++ b/_modules/qs_codec/models/weak_wrapper.html @@ -0,0 +1,147 @@ + + + + + + + qs_codec.models.weak_wrapper — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for qs_codec.models.weak_wrapper

+"""A wrapper that allows weak references to be used as dictionary keys."""
+
+import typing as t
+from dataclasses import dataclass
+
+
+
+[docs] +@dataclass(frozen=True) +class WeakWrapper: + """A wrapper that allows weak references to be used as dictionary keys.""" + + value: t.Any + + def __hash__(self) -> int: + """Return the hash of the value.""" + return hash(self._hash_recursive(self.value, seen=set(), stack=set())) + + def _hash_recursive( + self, value: t.Any, seen: set, stack: set, depth: int = 0, max_depth: int = 1000 + ) -> t.Union[t.Tuple, t.Any]: + """Recursively hash a value.""" + if id(value) in stack: + raise ValueError("Circular reference detected") + + seen.add(id(value)) + stack.add(id(value)) + + if depth > max_depth: + raise ValueError("Maximum recursion depth exceeded") + + if isinstance(value, t.Mapping): + result = tuple((k, self._hash_recursive(v, seen, stack, depth + 1)) for k, v in sorted(value.items())) + elif isinstance(value, (t.List, t.Set)): + result = tuple(self._hash_recursive(v, seen, stack, depth + 1) for v in value) + else: + result = value + + stack.remove(id(value)) + + return result
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/_modules/qs_codec/utils/decode_utils.html b/_modules/qs_codec/utils/decode_utils.html new file mode 100644 index 0000000..d01322f --- /dev/null +++ b/_modules/qs_codec/utils/decode_utils.html @@ -0,0 +1,177 @@ + + + + + + + qs_codec.utils.decode_utils — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for qs_codec.utils.decode_utils

+"""Decode utility methods used by the library."""
+
+import re
+import typing as t
+from urllib.parse import unquote
+
+from ..enums.charset import Charset
+from .str_utils import code_unit_at
+
+
+
+[docs] +class DecodeUtils: + """A collection of decode utility methods used by the library.""" + +
+[docs] + @classmethod + def unescape(cls, string: str) -> str: + """A Python representation the deprecated JavaScript unescape function. + + https://developer.mozilla.org/en-US/docs/web/javascript/reference/global_objects/unescape + """ + buffer: t.List[str] = [] + + i: int = 0 + while i < len(string): + c: int = code_unit_at(string, i) + + if c == 0x25: + if string[i + 1] == "u": + buffer.append( + chr(int(string[i + 2 : i + 6], 16)), + ) + i += 6 + continue + + buffer.append(chr(int(string[i + 1 : i + 3], 16))) + i += 3 + continue + + buffer.append(string[i]) + i += 1 + + return "".join(buffer)
+ + +
+[docs] + @classmethod + def decode( + cls, + string: t.Optional[str], + charset: t.Optional[Charset] = Charset.UTF8, + ) -> t.Optional[str]: + """Decode a URL-encoded string.""" + if string is None: + return None + + string_without_plus: str = string.replace("+", " ") + + if charset == Charset.LATIN1: + return re.sub( + r"%[0-9a-f]{2}", + lambda match: cls.unescape(match.group(0)), + string_without_plus, + flags=re.IGNORECASE, + ) + + return unquote(string_without_plus)
+
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/_modules/qs_codec/utils/encode_utils.html b/_modules/qs_codec/utils/encode_utils.html new file mode 100644 index 0000000..9b56b56 --- /dev/null +++ b/_modules/qs_codec/utils/encode_utils.html @@ -0,0 +1,266 @@ + + + + + + + qs_codec.utils.encode_utils — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for qs_codec.utils.encode_utils

+"""A collection of encode utility methods used by the library."""
+
+import re
+import typing as t
+from datetime import datetime
+from decimal import Decimal
+from enum import Enum
+
+from ..enums.charset import Charset
+from ..enums.format import Format
+from .str_utils import code_unit_at
+
+
+
+[docs] +class EncodeUtils: + """A collection of encode utility methods used by the library.""" + + HEX_TABLE: t.Tuple[str, ...] = tuple(f"%{i.to_bytes(1, 'big').hex().upper().zfill(2)}" for i in range(256)) + """Hex table of all 256 characters""" + +
+[docs] + @classmethod + def escape( + cls, + string: str, + format: t.Optional[Format] = Format.RFC3986, + ) -> str: + """A Python representation the deprecated JavaScript escape function. + + https://developer.mozilla.org/en-US/docs/web/javascript/reference/global_objects/escape + """ + buffer: t.List[str] = [] + + i: int + for i, _ in enumerate(string): + c: int = code_unit_at(string, i) + + # These 69 characters are safe for escaping + # ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789@*_+-./ + if ( + (0x30 <= c <= 0x39) # 0-9 + or (0x41 <= c <= 0x5A) # A-Z + or (0x61 <= c <= 0x7A) # a-z + or c == 0x40 # @ + or c == 0x2A # * + or c == 0x5F # _ + or c == 0x2D # - + or c == 0x2B # + + or c == 0x2E # . + or c == 0x2F # / + or (format == Format.RFC1738 and (c == 0x28 or c == 0x29)) # ( ) + ): + buffer.append(string[i]) + continue + + if c < 256: + buffer.extend([f"%{c.to_bytes(1, 'big').hex().upper().zfill(2)}"]) + continue + + buffer.extend([f"%u{c.to_bytes(2, 'big').hex().upper().zfill(4)}"]) + + return "".join(buffer)
+ + +
+[docs] + @classmethod + def encode( + cls, + value: t.Any, + charset: t.Optional[Charset] = Charset.UTF8, + format: t.Optional[Format] = Format.RFC3986, + ) -> str: + """Encode a value to a URL-encoded string.""" + if value is None or not isinstance(value, (int, float, Decimal, Enum, str, bool, bytes)): + return "" + + string: str + if isinstance(value, bytes): + string = value.decode("utf-8") + elif isinstance(value, bool): + string = str(value).lower() + elif isinstance(value, str): + string = value + else: + string = str(value) + + if value == "": + return "" + + if charset == Charset.LATIN1: + return re.sub( + r"%u[0-9a-f]{4}", + lambda match: f"%26%23{int(match.group(0)[2:], 16)}%3B", + EncodeUtils.escape(string, format), + flags=re.IGNORECASE, + ) + + buffer: t.List[str] = [] + + i: int + for i, _ in enumerate(string): + c: int = code_unit_at(string, i) + + if ( + c == 0x2D # - + or c == 0x2E # . + or c == 0x5F # _ + or c == 0x7E # ~ + or (0x30 <= c <= 0x39) # 0-9 + or (0x41 <= c <= 0x5A) # a-z + or (0x61 <= c <= 0x7A) # A-Z + or (format == Format.RFC1738 and (c == 0x28 or c == 0x29)) # ( ) + ): + buffer.append(string[i]) + continue + elif c < 0x80: # ASCII + buffer.extend([cls.HEX_TABLE[c]]) + continue + elif c < 0x800: # 2 bytes + buffer.extend( + [ + cls.HEX_TABLE[0xC0 | (c >> 6)], + cls.HEX_TABLE[0x80 | (c & 0x3F)], + ], + ) + continue + elif c < 0xD800 or c >= 0xE000: # 3 bytes + buffer.extend( + [ + cls.HEX_TABLE[0xE0 | (c >> 12)], + cls.HEX_TABLE[0x80 | ((c >> 6) & 0x3F)], + cls.HEX_TABLE[0x80 | (c & 0x3F)], + ], + ) + continue + else: + i += 1 + c = 0x10000 + (((c & 0x3FF) << 10) | (code_unit_at(string, i) & 0x3FF)) + buffer.extend( + [ + cls.HEX_TABLE[0xF0 | (c >> 18)], + cls.HEX_TABLE[0x80 | ((c >> 12) & 0x3F)], + cls.HEX_TABLE[0x80 | ((c >> 6) & 0x3F)], + cls.HEX_TABLE[0x80 | (c & 0x3F)], + ], + ) + + return "".join(buffer)
+ + +
+[docs] + @staticmethod + def serialize_date(dt: datetime) -> str: + """Serialize a `datetime` object to an ISO 8601 string.""" + return dt.isoformat()
+
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/_modules/qs_codec/utils/str_utils.html b/_modules/qs_codec/utils/str_utils.html new file mode 100644 index 0000000..7662f53 --- /dev/null +++ b/_modules/qs_codec/utils/str_utils.html @@ -0,0 +1,123 @@ + + + + + + + qs_codec.utils.str_utils — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for qs_codec.utils.str_utils

+"""Utility functions for working with strings."""
+
+
+
+[docs] +def code_unit_at(string: str, index: int) -> int: + """Returns the 16-bit UTF-16 code unit at the given index. + + This function first encodes the string in UTF-16 little endian format, then calculates the code unit at the + given index. The code unit is calculated by taking the byte at the index and adding it to 256 times the next + byte. This is because UTF-16 represents each code unit with two bytes, and in little endian format, the least + significant byte comes first. + + Adapted from https://api.dart.dev/stable/3.3.3/dart-core/String/codeUnitAt.html + """ + encoded_string: bytes = string.encode("utf-16-le") + return encoded_string[index * 2] + 256 * encoded_string[index * 2 + 1]
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/_modules/qs_codec/utils/utils.html b/_modules/qs_codec/utils/utils.html new file mode 100644 index 0000000..da777c0 --- /dev/null +++ b/_modules/qs_codec/utils/utils.html @@ -0,0 +1,347 @@ + + + + + + + qs_codec.utils.utils — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Source code for qs_codec.utils.utils

+"""A collection of utility methods used by the library."""
+
+import copy
+import typing as t
+from datetime import datetime, timedelta
+from decimal import Decimal
+from enum import Enum
+
+from ..models.decode_options import DecodeOptions
+from ..models.undefined import Undefined
+
+
+
+[docs] +class Utils: + """A collection of utility methods used by the library.""" + +
+[docs] + @staticmethod + def merge( + target: t.Optional[t.Union[t.Mapping, t.List, t.Tuple]], + source: t.Optional[t.Union[t.Mapping, t.List, t.Tuple, t.Any]], + options: DecodeOptions = DecodeOptions(), + ) -> t.Union[t.Dict, t.List, t.Tuple, t.Any]: + """Merge two objects together.""" + if source is None: + return target + + if not isinstance(source, t.Mapping): + if isinstance(target, (list, tuple)): + if any(isinstance(el, Undefined) for el in target): + target_: t.Dict[int, t.Any] = dict(enumerate(target)) + + if isinstance(source, (list, tuple)): + for i, item in enumerate(source): + if not isinstance(item, Undefined): + target_[i] = item + else: + target_[len(target_)] = source + + target = list(filter(lambda el: not isinstance(el, Undefined), target_.values())) + else: + if isinstance(source, (list, tuple)): + if all((isinstance(el, t.Mapping) or isinstance(el, Undefined)) for el in target) and all( + (isinstance(el, t.Mapping) or isinstance(el, Undefined)) for el in source + ): + target__: t.Dict[int, t.Any] = dict(enumerate(target)) + target = list( + { + i: Utils.merge(target__[i], item, options) if i in target__ else item + for i, item in enumerate(source) + }.values() + ) + else: + if isinstance(target, tuple): + target = list(target) + target.extend(filter(lambda el: not isinstance(el, Undefined), source)) + elif source is not None: + if isinstance(target, tuple): + target = list(target) + target.append(source) + elif isinstance(target, t.Mapping): + if isinstance(source, (list, tuple)): + target = { + **target, + **{i: item for i, item in enumerate(source) if not isinstance(item, Undefined)}, + } + elif source is not None: + if not isinstance(target, (list, tuple)) and isinstance(source, (list, tuple)): + return [target, *filter(lambda el: not isinstance(el, Undefined), source)] + return [target, source] + + return target + + if target is None or not isinstance(target, t.Mapping): + if isinstance(target, (list, tuple)): + return { + **{i: item for i, item in enumerate(target) if not isinstance(item, Undefined)}, + **source, + } + + return [ + el + for el in (target if isinstance(target, (list, tuple)) else [target]) + if not isinstance(el, Undefined) + ] + [ + el + for el in (source if isinstance(source, (list, tuple)) else [source]) + if not isinstance(el, Undefined) + ] + + merge_target: t.Dict = ( + dict(enumerate(el for el in source if not isinstance(el, Undefined))) + if isinstance(target, (list, tuple)) and not isinstance(source, (list, tuple)) + else copy.deepcopy(dict(target) if not isinstance(target, dict) else target) + ) + + return { + **merge_target, + **{ + key: Utils.merge(merge_target[key], value, options) if key in merge_target else value + for key, value in source.items() + }, + }
+ + +
+[docs] + @staticmethod + def compact(value: t.Dict) -> t.Dict: + """Remove all `Undefined` values from a dictionary.""" + queue: t.List[t.Dict] = [{"obj": {"o": value}, "prop": "o"}] + refs: t.List = [] + + for i in range(len(queue)): # pylint: disable=C0200 + item: t.Mapping = queue[i] + obj: t.Mapping = item["obj"][item["prop"]] + + keys: t.List = list(obj.keys()) + for key in keys: + val = obj.get(key) + + if ( + val is not None + and not isinstance(val, Undefined) + and isinstance(val, t.Mapping) + and val not in refs + ): + queue.append({"obj": obj, "prop": key}) + refs.append(val) + + Utils._compact_queue(queue) + Utils._remove_undefined_from_map(value) + + return value
+ + + @staticmethod + def _compact_queue(queue: t.List[t.Dict]) -> None: + while len(queue) > 1: + item = queue.pop() + obj = item["obj"][item["prop"]] + + if isinstance(obj, (list, tuple)): + item["obj"][item["prop"]] = list(filter(lambda el: not isinstance(el, Undefined), obj)) + + @staticmethod + def _remove_undefined_from_list(value: t.List) -> None: + i: int = len(value) - 1 + while i >= 0: + item = value[i] + if isinstance(item, Undefined): + value.pop(i) + elif isinstance(item, dict): + Utils._remove_undefined_from_map(item) + elif isinstance(item, list): + Utils._remove_undefined_from_list(item) + elif isinstance(item, tuple): + value[i] = list(item) + Utils._remove_undefined_from_list(value[i]) + i -= 1 + + @staticmethod + def _remove_undefined_from_map(obj: t.Dict) -> None: + keys: t.List = list(obj.keys()) + for key in keys: + val = obj[key] + if isinstance(val, Undefined): + obj.pop(key) + elif isinstance(val, dict) and not Utils._dicts_are_equal(val, obj): + Utils._remove_undefined_from_map(val) + elif isinstance(val, list): + Utils._remove_undefined_from_list(val) + elif isinstance(val, tuple): + obj[key] = list(val) + Utils._remove_undefined_from_list(obj[key]) + + @staticmethod + def _dicts_are_equal(d1: t.Mapping, d2: t.Mapping, path=None) -> bool: + if path is None: + path = set() + + if id(d1) in path or id(d2) in path: + return True + + path.add(id(d1)) + path.add(id(d2)) + + if isinstance(d1, dict) and isinstance(d2, dict): + if len(d1) != len(d2): + return False + for k, v in d1.items(): + if k not in d2: + return False + if not Utils._dicts_are_equal(v, d2[k], path): + return False + return True + else: + return d1 == d2 + +
+[docs] + @staticmethod + def combine(a: t.Union[list, tuple, t.Any], b: t.Union[list, tuple, t.Any]) -> t.List: + """Combine two lists or values.""" + return [*(a if isinstance(a, (list, tuple)) else [a]), *(b if isinstance(b, (list, tuple)) else [b])]
+ + +
+[docs] + @staticmethod + def apply(val: t.Union[list, tuple, t.Any], fn: t.Callable) -> t.Union[t.List, t.Any]: + """Apply a function to a value or a list of values.""" + return [fn(item) for item in val] if isinstance(val, (list, tuple)) else fn(val)
+ + +
+[docs] + @staticmethod + def is_non_nullish_primitive(val: t.Any, skip_nulls: bool = False) -> bool: + """Check if a value is a non-nullish primitive.""" + if val is None: + return False + + if isinstance(val, str): + return val != "" if skip_nulls else True + + if isinstance(val, (int, float, Decimal, bool, Enum, datetime, timedelta)): + return True + + if isinstance(val, Undefined): + return False + + if isinstance(val, object): + if isinstance(val, (list, tuple, t.Mapping)): + return False + return True + + return False
+
+ +
+ +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/_sources/README.rst.txt b/_sources/README.rst.txt new file mode 100644 index 0000000..db8e9c8 --- /dev/null +++ b/_sources/README.rst.txt @@ -0,0 +1,951 @@ +Decoding +~~~~~~~~ + +dictionaries +^^^^^^^^^^^^ + +.. code:: python + + import qs_codec, typing as t + + def decode( + value: t.Optional[t.Union[str, t.Mapping]], + options: qs_codec.DecodeOptions = qs_codec.DecodeOptions(), + ) -> dict: + """Decodes a str or Mapping into a Dict. + + Providing custom DecodeOptions will override the default behavior.""" + pass + +:py:attr:`decode ` allows you to create nested ``dict``\ s within your query +strings, by surrounding the name of sub-keys with square brackets +``[]``. For example, the string ``'foo[bar]=baz'`` converts to: + +.. code:: python + + import qs_codec + + assert qs_codec.decode('foo[bar]=baz') == {'foo': {'bar': 'baz'}} + +URI encoded strings work too: + +.. code:: python + + import qs_codec + + assert qs_codec.decode('a%5Bb%5D=c') == {'a': {'b': 'c'}} + +You can also nest your ``dict``\ s, like ``'foo[bar][baz]=foobarbaz'``: + +.. code:: python + + import qs_codec + + assert qs_codec.decode('foo[bar][baz]=foobarbaz') == {'foo': {'bar': {'baz': 'foobarbaz'}}} + +By default, when nesting ``dict``\ s qs will only decode up to 5 +children deep. This means if you attempt to decode a string like +``'a[b][c][d][e][f][g][h][i]=j'`` your resulting ``dict`` will be: + +.. code:: python + + import qs_codec + + assert qs_codec.decode("a[b][c][d][e][f][g][h][i]=j") == { + "a": {"b": {"c": {"d": {"e": {"f": {"[g][h][i]": "j"}}}}}} + } + +This depth can be overridden by setting the :py:attr:`depth `: + +.. code:: python + + import qs_codec + + assert qs_codec.decode( + 'a[b][c][d][e][f][g][h][i]=j', + qs_codec.DecodeOptions(depth=1), + ) == {'a': {'b': {'[c][d][e][f][g][h][i]': 'j'}}} + +The depth limit helps mitigate abuse when :py:attr:`decode ` is used to parse user +input, and it is recommended to keep it a reasonably small number. + +For similar reasons, by default :py:attr:`decode ` will only parse up to 1000 parameters. This can be overridden by passing a +:py:attr:`parameter_limit ` option: + +.. code:: python + + import qs_codec + + assert qs_codec.decode( + 'a=b&c=d', + qs_codec.DecodeOptions(parameter_limit=1), + ) == {'a': 'b'} + +To bypass the leading question mark, use +:py:attr:`ignore_query_prefix `: + +.. code:: python + + import qs_codec + + assert qs_codec.decode( + '?a=b&c=d', + qs_codec.DecodeOptions(ignore_query_prefix=True), + ) == {'a': 'b', 'c': 'd'} + +An optional :py:attr:`delimiter ` can also be passed: + +.. code:: python + + import qs_codec + + assert qs_codec.decode( + 'a=b;c=d', + qs_codec.DecodeOptions(delimiter=';'), + ) == {'a': 'b', 'c': 'd'} + +:py:attr:`delimiter ` can be a regular expression too: + +.. code:: python + + import re, qs_codec + + assert qs_codec.decode( + 'a=b;c=d', + qs_codec.DecodeOptions(delimiter=re.compile(r'[;,]')), + ) == {'a': 'b', 'c': 'd'} + +Option :py:attr:`allow_dots ` +can be used to enable dot notation: + +.. code:: python + + import qs_codec + + assert qs_codec.decode( + 'a.b=c', + qs_codec.DecodeOptions(allow_dots=True), + ) == {'a': {'b': 'c'}} + +Option :py:attr:`decode_dot_in_keys ` +can be used to decode dots in keys. + +**Note:** it implies :py:attr:`allow_dots `, so +:py:attr:`decode ` will error if you set :py:attr:`decode_dot_in_keys ` +to ``True``, and :py:attr:`allow_dots ` to ``False``. + +.. code:: python + + import qs_codec + + assert qs_codec.decode( + 'name%252Eobj.first=John&name%252Eobj.last=Doe', + qs_codec.DecodeOptions(decode_dot_in_keys=True), + ) == {'name.obj': {'first': 'John', 'last': 'Doe'}} + +Option :py:attr:`allow_empty_lists ` can +be used to allowing empty ``list`` values in a ``dict`` + +.. code:: python + + import qs_codec + + assert qs_codec.decode( + 'foo[]&bar=baz', + qs_codec.DecodeOptions(allow_empty_lists=True), + ) == {'foo': [], 'bar': 'baz'} + +Option :py:attr:`duplicates ` can be used to +change the behavior when duplicate keys are encountered + +.. code:: python + + import qs_codec + + assert qs_codec.decode('foo=bar&foo=baz') == {'foo': ['bar', 'baz']} + + assert qs_codec.decode( + 'foo=bar&foo=baz', + qs_codec.DecodeOptions(duplicates=qs_codec.Duplicates.COMBINE), + ) == {'foo': ['bar', 'baz']} + + assert qs_codec.decode( + 'foo=bar&foo=baz', + qs_codec.DecodeOptions(duplicates=qs_codec.Duplicates.FIRST), + ) == {'foo': 'bar'} + + assert qs_codec.decode( + 'foo=bar&foo=baz', + qs_codec.DecodeOptions(duplicates=qs_codec.Duplicates.LAST), + ) == {'foo': 'baz'} + +If you have to deal with legacy browsers or services, there’s also +support for decoding percent-encoded octets as :py:attr:`LATIN1 `: + +.. code:: python + + import qs_codec + + assert qs_codec.decode( + 'a=%A7', + qs_codec.DecodeOptions(charset=qs_codec.Charset.LATIN1), + ) == {'a': '§'} + +Some services add an initial ``utf8=✓`` value to forms so that old +Internet Explorer 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-urlencoded`` body was *not* sent as ``utf-8``, +e.g. if the form had an ``accept-charset`` parameter or the containing +page had a different character set. + +:py:attr:`decode ` supports this mechanism via the +:py:attr:`charset_sentinel ` option. +If specified, the ``utf8`` parameter will be omitted from the returned +``dict``. It will be used to switch to :py:attr:`LATIN1 ` or +:py:attr:`UTF8 ` mode depending on how the checkmark is encoded. + +**Important**: When you specify both the :py:attr:`charset ` +option and the :py:attr:`charset_sentinel ` option, the +:py:attr:`charset ` will be overridden when the request contains a +``utf8`` parameter from which the actual charset can be deduced. In that +sense the :py:attr:`charset ` will behave as the default charset +rather than the authoritative charset. + +.. code:: python + + import qs_codec + + assert qs_codec.decode( + 'utf8=%E2%9C%93&a=%C3%B8', + qs_codec.DecodeOptions( + charset=qs_codec.Charset.LATIN1, + charset_sentinel=True, + ), + ) == {'a': 'ø'} + + assert qs_codec.decode( + 'utf8=%26%2310003%3B&a=%F8', + qs_codec.DecodeOptions( + charset=qs_codec.Charset.UTF8, + charset_sentinel=True, + ), + ) == {'a': 'ø'} + +If you want to decode the `&#...; `_ syntax to the actual character, you can specify the +:py:attr:`interpret_numeric_entities ` +option as well: + +.. code:: python + + import qs_codec + + assert qs_codec.decode( + 'a=%26%239786%3B', + qs_codec.DecodeOptions( + charset=qs_codec.Charset.LATIN1, + interpret_numeric_entities=True, + ), + ) == {'a': '☺'} + +It also works when the charset has been detected in +:py:attr:`charset_sentinel ` mode. + +lists +^^^^^ + +:py:attr:`decode ` can also decode ``list``\ s using a similar ``[]`` notation: + +.. code:: python + + import qs_codec + + assert qs_codec.decode('a[]=b&a[]=c') == {'a': ['b', 'c']} + +You may specify an index as well: + +.. code:: python + + import qs_codec + + assert qs_codec.decode('a[1]=c&a[0]=b') == {'a': ['b', 'c']} + +Note that the only difference between an index in a ``list`` and a key +in a ``dict`` is that the value between the brackets must be a number to +create a ``list``. When creating ``list``\ s with specific indices, +:py:attr:`decode ` will compact a sparse ``list`` to +only the existing values preserving their order: + +.. code:: python + + import qs_codec + + assert qs_codec.decode('a[1]=b&a[15]=c') == {'a': ['b', 'c']} + +Note that an empty ``str``\ing is also a value, and will be preserved: + +.. code:: python + + import qs_codec + + assert qs_codec.decode('a[]=&a[]=b') == {'a': ['', 'b']} + + assert qs_codec.decode('a[0]=b&a[1]=&a[2]=c') == {'a': ['b', '', 'c']} + +:py:attr:`decode ` will also limit specifying indices +in a ``list`` to a maximum index of ``20``. Any ``list`` members with an +index of greater than ``20`` will instead be converted to a ``dict`` with +the index as the key. This is needed to handle cases when someone sent, +for example, ``a[999999999]`` and it will take significant time to iterate +over this huge ``list``. + +.. code:: python + + import qs_codec + + assert qs_codec.decode('a[100]=b') == {'a': {100: 'b'}} + +This limit can be overridden by passing an :py:attr:`list_limit ` +option: + +.. code:: python + + import qs_codec + + assert qs_codec.decode( + 'a[1]=b', + qs_codec.DecodeOptions(list_limit=0), + ) == {'a': {1: 'b'}} + +To disable ``list`` parsing entirely, set :py:attr:`parse_lists ` +to ``False``. + +.. code:: python + + import qs_codec + + assert qs_codec.decode( + 'a[]=b', + qs_codec.DecodeOptions(parse_lists=False), + ) == {'a': {0: 'b'}} + +If you mix notations, :py:attr:`decode ` will merge the two items into a ``dict``: + +.. code:: python + + import qs_codec + + assert qs_codec.decode('a[0]=b&a[b]=c') == {'a': {0: 'b', 'b': 'c'}} + +You can also create ``list``\ s of ``dict``\ s: + +.. code:: python + + import qs_codec + + assert qs_codec.decode('a[][b]=c') == {'a': [{'b': 'c'}]} + +(:py:attr:`decode ` *cannot convert nested ``dict``\ s, such as ``'a={b:1},{c:d}'``*) + +primitive values (``int``, ``bool``, ``None``, etc.) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +By default, all values are parsed as ``str``\ings. + +.. code:: python + + import qs_codec + + assert qs_codec.decode( + 'a=15&b=true&c=null', + ) == {'a': '15', 'b': 'true', 'c': 'null'} + +Encoding +~~~~~~~~ + +.. code:: python + + import qs_codec, typing as t + + def encode( + value: t.Any, + options: qs_codec.EncodeOptions = qs_codec.EncodeOptions() + ) -> str: + """Encodes an object into a query string. + + Providing custom EncodeOptions will override the default behavior.""" + pass + +When encoding, :py:attr:`encode ` by default URI encodes output. ``dict``\ s are +encoded as you would expect: + +.. code:: python + + import qs_codec + + assert qs_codec.encode({'a': 'b'}) == 'a=b' + assert qs_codec.encode({'a': {'b': 'c'}}) == 'a%5Bb%5D=c' + +This encoding can be disabled by setting the :py:attr:`encode ` +option to ``False``: + +.. code:: python + + import qs_codec + + assert qs_codec.encode( + {'a': {'b': 'c'}}, + qs_codec.EncodeOptions(encode=False), + ) == 'a[b]=c' + +Encoding can be disabled for keys by setting the +:py:attr:`encode_values_only ` option to ``True``: + +.. code:: python + + import qs_codec + + assert qs_codec.encode( + { + 'a': 'b', + 'c': ['d', 'e=f'], + 'f': [ + ['g'], + ['h'] + ] + }, + qs_codec.EncodeOptions(encode_values_only=True) + ) == 'a=b&c[0]=d&c[1]=e%3Df&f[0][0]=g&f[1][0]=h' + +This encoding can also be replaced by a custom ``Callable`` in the +:py:attr:`encoder ` option: + +.. code:: python + + import qs_codec, typing as t + + + def custom_encoder( + value: str, + charset: t.Optional[qs_codec.Charset], + format: t.Optional[qs_codec.Format], + ) -> str: + if value == 'č': + return 'c' + return value + + + assert qs_codec.encode( + {'a': {'b': 'č'}}, + qs_codec.EncodeOptions(encoder=custom_encoder), + ) == 'a[b]=c' + +(Note: the :py:attr:`encoder ` option does not apply if +:py:attr:`encode ` is ``False``). + +Similar to :py:attr:`encoder ` there is a +:py:attr:`decoder ` option for :py:attr:`decode ` +to override decoding of properties and values: + +.. code:: python + + import qs_codec, typing as t + + def custom_decoder( + value: t.Any, + charset: t.Optional[qs_codec.Charset], + ) -> t.Union[int, str]: + try: + return int(value) + except ValueError: + return value + + assert qs_codec.decode( + 'foo=123', + qs_codec.DecodeOptions(decoder=custom_decoder), + ) == {'foo': 123} + +Examples beyond this point will be shown as though the output is not URI +encoded for clarity. Please note that the return values in these cases +*will* be URI encoded during real usage. + +When ``list``\s are encoded, they follow the +:py:attr:`list_format ` option, which defaults to +:py:attr:`INDICES `: + +.. code:: python + + import qs_codec + + assert qs_codec.encode( + {'a': ['b', 'c', 'd']}, + qs_codec.EncodeOptions(encode=False) + ) == 'a[0]=b&a[1]=c&a[2]=d' + +You may override this by setting the :py:attr:`indices ` option to +``False``, or to be more explicit, the :py:attr:`list_format ` +option to :py:attr:`REPEAT `: + +.. code:: python + + import qs_codec + + assert qs_codec.encode( + {'a': ['b', 'c', 'd']}, + qs_codec.EncodeOptions( + encode=False, + indices=False, + ), + ) == 'a=b&a=c&a=d' + +You may use the :py:attr:`list_format ` option to specify the +format of the output ``list``: + +.. code:: python + + import qs_codec + + # ListFormat.INDICES + assert qs_codec.encode( + {'a': ['b', 'c']}, + qs_codec.EncodeOptions( + encode=False, + list_format=qs_codec.ListFormat.INDICES, + ), + ) == 'a[0]=b&a[1]=c' + + # ListFormat.BRACKETS + assert qs_codec.encode( + {'a': ['b', 'c']}, + qs_codec.EncodeOptions( + encode=False, + list_format=qs_codec.ListFormat.BRACKETS, + ), + ) == 'a[]=b&a[]=c' + + # ListFormat.REPEAT + assert qs_codec.encode( + {'a': ['b', 'c']}, + qs_codec.EncodeOptions( + encode=False, + list_format=qs_codec.ListFormat.REPEAT, + ), + ) == 'a=b&a=c' + + # ListFormat.COMMA + assert qs_codec.encode( + {'a': ['b', 'c']}, + qs_codec.EncodeOptions( + encode=False, + list_format=qs_codec.ListFormat.COMMA, + ), + ) == 'a=b,c' + +**Note:** When using :py:attr:`list_format ` set to +:py:attr:`COMMA `, you can also pass the +:py:attr:`comma_round_trip ` option set to ``True`` or +``False``, to append ``[]`` on single-item ``list``\ s, so that they can round trip through a decoding. + +:py:attr:`BRACKETS ` notation is used for encoding ``dict``\s by default: + +.. code:: python + + import qs_codec + + assert qs_codec.encode( + {'a': {'b': {'c': 'd', 'e': 'f'}}}, + qs_codec.EncodeOptions(encode=False), + ) == 'a[b][c]=d&a[b][e]=f' + +You may override this to use dot notation by setting the +:py:attr:`allow_dots ` option to ``True``: + +.. code:: python + + import qs_codec + + assert qs_codec.encode( + {'a': {'b': {'c': 'd', 'e': 'f'}}}, + qs_codec.EncodeOptions(encode=False, allow_dots=True), + ) == 'a.b.c=d&a.b.e=f' + +You may encode dots in keys of ``dict``\s by setting +:py:attr:`encode_dot_in_keys ` to ``True``: + +.. code:: python + + import qs_codec + + assert qs_codec.encode( + {'name.obj': {'first': 'John', 'last': 'Doe'}}, + qs_codec.EncodeOptions( + allow_dots=True, + encode_dot_in_keys=True, + ), + ) == 'name%252Eobj.first=John&name%252Eobj.last=Doe' + +**Caveat:** When both :py:attr:`encode_values_only ` +and :py:attr:`encode_dot_in_keys ` are set to +``True``, only dots in keys and nothing else will be encoded! + +You may allow empty ``list`` values by setting the +:py:attr:`allow_empty_lists ` option to ``True``: + +.. code:: python + + import qs_codec + + assert qs_codec.encode( + {'foo': [], 'bar': 'baz', }, + qs_codec.EncodeOptions( + encode=False, + allow_empty_lists=True, + ), + ) == 'foo[]&bar=baz' + +Empty ``str``\ings and ``None`` values will be omitted, but the equals sign (``=``) remains in place: + +.. code:: python + + import qs_codec + + assert qs_codec.encode({'a': ''}) == 'a=' + +Keys with no values (such as an empty ``dict`` or ``list``) will return nothing: + +.. code:: python + + import qs_codec + + assert qs_codec.encode({'a': []}) == '' + + assert qs_codec.encode({'a': {}}) == '' + + assert qs_codec.encode({'a': [{}]}) == '' + + assert qs_codec.encode({'a': {'b': []}}) == '' + + assert qs_codec.encode({'a': {'b': {}}}) == '' + +:py:attr:`Undefined ` properties will be omitted entirely: + +.. code:: python + + import qs_codec + + assert qs_codec.encode({'a': None, 'b': qs_codec.Undefined()}) == 'a=' + +The query string may optionally be prepended with a question mark (``?``) by setting +:py:attr:`add_query_prefix ` to ``True``: + +.. code:: python + + import qs_codec + + assert qs_codec.encode( + {'a': 'b', 'c': 'd'}, + qs_codec.EncodeOptions(add_query_prefix=True), + ) == '?a=b&c=d' + +The :py:attr:`delimiter ` may be overridden as well: + +.. code:: python + + import qs_codec + + assert qs_codec.encode( + {'a': 'b', 'c': 'd', }, + qs_codec.EncodeOptions(delimiter=';') + ) == 'a=b;c=d' + +If you only want to override the serialization of `datetime `_ +objects, you can provide a ``Callable`` in the +:py:attr:`serialize_date ` option: + +.. code:: python + + import qs_codec, datetime, sys + + # First case: encoding a datetime object to an ISO 8601 string + assert ( + qs_codec.encode( + { + "a": ( + datetime.datetime.fromtimestamp(7, datetime.UTC) + if sys.version_info.major == 3 and sys.version_info.minor >= 11 + else datetime.datetime.utcfromtimestamp(7) + ) + }, + qs_codec.EncodeOptions(encode=False), + ) + == "a=1970-01-01T00:00:07+00:00" + if sys.version_info.major == 3 and sys.version_info.minor >= 11 + else "a=1970-01-01T00:00:07" + ) + + # Second case: encoding a datetime object to a timestamp string + assert ( + qs_codec.encode( + { + "a": ( + datetime.datetime.fromtimestamp(7, datetime.UTC) + if sys.version_info.major == 3 and sys.version_info.minor >= 11 + else datetime.datetime.utcfromtimestamp(7) + ) + }, + qs_codec.EncodeOptions(encode=False, serialize_date=lambda date: str(int(date.timestamp()))), + ) + == "a=7" + ) + +To affect the order of parameter keys, you can set a ``Callable`` in the +:py:attr:`sort ` option: + +.. code:: python + + import qs_codec + + assert qs_codec.encode( + {'a': 'c', 'z': 'y', 'b': 'f'}, + qs_codec.EncodeOptions( + encode=False, + sort=lambda a, b: (a > b) - (a < b) + ) + ) == 'a=c&b=f&z=y' + +Finally, you can use the :py:attr:`filter ` option to restrict +which keys will be included in the encoded output. If you pass a ``Callable``, it will be called for each key to obtain +the replacement value. Otherwise, if you pass a ``list``, it will be used to select properties and ``list`` indices to +be encoded: + +.. code:: python + + import qs_codec, datetime, sys + + # First case: using a Callable as filter + assert ( + qs_codec.encode( + { + "a": "b", + "c": "d", + "e": { + "f": ( + datetime.datetime.fromtimestamp(123, datetime.UTC) + if sys.version_info.major == 3 and sys.version_info.minor >= 11 + else datetime.datetime.utcfromtimestamp(123) + ), + "g": [2], + }, + }, + qs_codec.EncodeOptions( + encode=False, + filter=lambda prefix, value: { + "b": None, + "e[f]": int(value.timestamp()) if isinstance(value, datetime.datetime) else value, + "e[g][0]": value * 2 if isinstance(value, int) else value, + }.get(prefix, value), + ), + ) + == "a=b&c=d&e[f]=123&e[g][0]=4" + ) + + # Second case: using a list as filter + assert qs_codec.encode( + {'a': 'b', 'c': 'd', 'e': 'f'}, + qs_codec.EncodeOptions( + encode=False, + filter=['a', 'e'] + ) + ) == 'a=b&e=f' + + # Third case: using a list as filter with indices + assert qs_codec.encode( + { + 'a': ['b', 'c', 'd'], + 'e': 'f', + }, + qs_codec.EncodeOptions( + encode=False, + filter=['a', 0, 2] + ) + ) == 'a[0]=b&a[2]=d' + +Handling ``None`` values +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +By default, ``None`` values are treated like empty ``str``\ings: + +.. code:: python + + import qs_codec + + assert qs_codec.encode({'a': None, 'b': ''}) == 'a=&b=' + +To distinguish between ``None`` values and empty ``str``\s use the +:py:attr:`strict_null_handling ` flag. +In the result string the ``None`` values have no ``=`` sign: + +.. code:: python + + import qs_codec + + assert qs_codec.encode( + {'a': None, 'b': ''}, + qs_codec.EncodeOptions(strict_null_handling=True), + ) == 'a&b=' + +To decode values without ``=`` back to ``None`` use the +:py:attr:`strict_null_handling ` flag: + +.. code:: python + + import qs_codec + + assert qs_codec.decode( + 'a&b=', + qs_codec.DecodeOptions(strict_null_handling=True), + ) == {'a': None, 'b': ''} + +To completely skip rendering keys with ``None`` values, use the +:py:attr:`skip_nulls ` flag: + +.. code:: python + + import qs_codec + + assert qs_codec.encode( + {'a': 'b', 'c': None}, + qs_codec.EncodeOptions(skip_nulls=True), + ) == 'a=b' + +If you’re communicating with legacy systems, you can switch to +:py:attr:`LATIN1 ` using the +:py:attr:`charset ` option: + +.. code:: python + + import qs_codec + + assert qs_codec.encode( + {'æ': 'æ'}, + qs_codec.EncodeOptions(charset=qs_codec.Charset.LATIN1) + ) == '%E6=%E6' + +Characters that don’t exist in :py:attr:`LATIN1 ` +will be converted to numeric entities, similar to what browsers do: + +.. code:: python + + import qs_codec + + assert qs_codec.encode( + {'a': '☺'}, + qs_codec.EncodeOptions(charset=qs_codec.Charset.LATIN1) + ) == 'a=%26%239786%3B' + +You can use the :py:attr:`charset_sentinel ` +option to announce the character by including an ``utf8=✓`` parameter with the proper +encoding of the checkmark, similar to what Ruby on Rails and others do when submitting forms. + +.. code:: python + + import qs_codec + + assert qs_codec.encode( + {'a': '☺'}, + qs_codec.EncodeOptions(charset_sentinel=True) + ) == 'utf8=%E2%9C%93&a=%E2%98%BA' + + assert qs_codec.encode( + {'a': 'æ'}, + qs_codec.EncodeOptions(charset=qs_codec.Charset.LATIN1, charset_sentinel=True) + ) == 'utf8=%26%2310003%3B&a=%E6' + +Dealing with special character sets +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +By default, the encoding and decoding of characters is done in +:py:attr:`UTF8 `, and +:py:attr:`LATIN1 ` support is also built in via +the :py:attr:`charset ` +and :py:attr:`charset ` parameter, +respectively. + +If you wish to encode query strings to a different character set (i.e. +`Shift JIS `__) + +.. code:: python + + import qs_codec, codecs, typing as t + + def custom_encoder( + string: str, + charset: t.Optional[qs_codec.Charset], + format: t.Optional[qs_codec.Format], + ) -> str: + if string: + buf: bytes = codecs.encode(string, 'shift_jis') + result: t.List[str] = ['{:02x}'.format(b) for b in buf] + return '%' + '%'.join(result) + return '' + + assert qs_codec.encode( + {'a': 'こんにちは!'}, + qs_codec.EncodeOptions(encoder=custom_encoder) + ) == '%61=%82%b1%82%f1%82%c9%82%bf%82%cd%81%49' + +This also works for decoding of query strings: + +.. code:: python + + import qs_codec, re, codecs, typing as t + + def custom_decoder( + string: str, + charset: t.Optional[qs_codec.Charset], + ) -> t.Optional[str]: + if string: + result: t.List[int] = [] + while string: + match: t.Optional[t.Match[str]] = re.search(r'%([0-9A-F]{2})', string, re.IGNORECASE) + if match: + result.append(int(match.group(1), 16)) + string = string[match.end():] + else: + break + buf: bytes = bytes(result) + return codecs.decode(buf, 'shift_jis') + return None + + assert qs_codec.decode( + '%61=%82%b1%82%f1%82%c9%82%bf%82%cd%81%49', + qs_codec.DecodeOptions(decoder=custom_decoder) + ) == {'a': 'こんにちは!'} + +RFC 3986 and RFC 1738 space encoding +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The default :py:attr:`format ` is +:py:attr:`RFC3986 ` which encodes +``' '`` to ``%20`` which is backward compatible. You can also set the +:py:attr:`format ` to +:py:attr:`RFC1738 ` which encodes ``' '`` to ``+``. + +.. code:: python + + import qs_codec + + assert qs_codec.encode( + {'a': 'b c'}, + qs_codec.EncodeOptions(format=qs_codec.Format.RFC3986) + ) == 'a=b%20c' + + assert qs_codec.encode( + {'a': 'b c'}, + qs_codec.EncodeOptions(format=qs_codec.Format.RFC3986) + ) == 'a=b%20c' + + assert qs_codec.encode( + {'a': 'b c'}, + qs_codec.EncodeOptions(format=qs_codec.Format.RFC1738) + ) == 'a=b+c' diff --git a/_sources/index.rst.txt b/_sources/index.rst.txt new file mode 100644 index 0000000..3549686 --- /dev/null +++ b/_sources/index.rst.txt @@ -0,0 +1,92 @@ +.. qs-codec documentation master file, created by + sphinx-quickstart on Sun Apr 28 13:58:45 2024. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +qs-codec +======== + +A query string encoding and decoding library for Python. + +Ported from `qs `__ for JavaScript. + +|PyPI - Version| |PyPI - Downloads| |PyPI - Status| |PyPI - Python Version| |PyPI - Format| |Black| +|Test| |CodeQL| |Publish| |Docs| |codecov| |Codacy| |Black| |flake8| |mypy| |pylint| |isort| |bandit| +|License| |Contributor Covenant| |GitHub Sponsors| |GitHub Repo stars| + +Usage +----- + +A simple usage example: + +.. code:: python + + import qs_codec + + # Encoding + assert qs_codec.encode({'a': 'b'}) == 'a=b' + + # Decoding + assert qs_codec.decode('a=b') == {'a': 'b'} + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + README + modules + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + +-------------- + +Special thanks to the authors of +`qs `__ for JavaScript: - `Jordan +Harband `__ - `TJ +Holowaychuk `__ + +.. |PyPI - Version| image:: https://img.shields.io/pypi/v/qs_codec + :target: https://pypi.org/project/qs-codec/ +.. |PyPI - Downloads| image:: https://img.shields.io/pypi/dm/qs_codec + :target: https://pypistats.org/packages/qs-codec +.. |PyPI - Status| image:: https://img.shields.io/pypi/status/qs_codec +.. |PyPI - Python Version| image:: https://img.shields.io/pypi/pyversions/qs_codec +.. |PyPI - Format| image:: https://img.shields.io/pypi/format/qs_codec +.. |Test| image:: https://github.com/techouse/qs_codec/actions/workflows/test.yml/badge.svg + :target: https://github.com/techouse/qs_codec/actions/workflows/test.yml +.. |CodeQL| image:: https://github.com/techouse/qs_codec/actions/workflows/github-code-scanning/codeql/badge.svg + :target: https://github.com/techouse/qs_codec/actions/workflows/github-code-scanning/codeql +.. |Publish| image:: https://github.com/techouse/qs_codec/actions/workflows/publish.yml/badge.svg + :target: https://github.com/techouse/qs_codec/actions/workflows/publish.yml +.. |Docs| image:: https://github.com/techouse/qs_codec/actions/workflows/docs.yml/badge.svg + :target: https://github.com/techouse/qs_codec/actions/workflows/docs.yml +.. |Black| image:: https://img.shields.io/badge/code%20style-black-000000.svg + :target: https://github.com/psf/black +.. |codecov| image:: https://codecov.io/gh/techouse/qs_codec/graph/badge.svg?token=Vp0z05yj2l + :target: https://codecov.io/gh/techouse/qs_codec +.. |Codacy| image:: https://app.codacy.com/project/badge/Grade/7ead208221ae4f6785631043064647e4 + :target: https://app.codacy.com/gh/techouse/qs_codec/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade +.. |License| image:: https://img.shields.io/github/license/techouse/qs_codec + :target: LICENSE +.. |GitHub Sponsors| image:: https://img.shields.io/github/sponsors/techouse + :target: https://github.com/sponsors/techouse +.. |GitHub Repo stars| image:: https://img.shields.io/github/stars/techouse/qs_codec + :target: https://github.com/techouse/qs_codec/stargazers +.. |Contributor Covenant| image:: https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg + :target: CODE-OF-CONDUCT.md +.. |flake8| image:: https://img.shields.io/badge/flake8-checked-blueviolet.svg + :target: https://flake8.pycqa.org/en/latest/ +.. |mypy| image:: https://img.shields.io/badge/mypy-checked-blue.svg + :target: https://mypy.readthedocs.io/en/stable/ +.. |pylint| image:: https://img.shields.io/badge/linting-pylint-yellowgreen.svg + :target: https://github.com/pylint-dev/pylint +.. |isort| image:: https://img.shields.io/badge/imports-isort-blue.svg + :target: https://pycqa.github.io/isort/ +.. |bandit| image:: https://img.shields.io/badge/security-bandit-blue.svg + :target: https://github.com/PyCQA/bandit + :alt: Security Status \ No newline at end of file diff --git a/_sources/modules.rst.txt b/_sources/modules.rst.txt new file mode 100644 index 0000000..b3bb515 --- /dev/null +++ b/_sources/modules.rst.txt @@ -0,0 +1,7 @@ +qs_codec +======== + +.. toctree:: + :maxdepth: 4 + + qs_codec diff --git a/_sources/qs_codec.enums.rst.txt b/_sources/qs_codec.enums.rst.txt new file mode 100644 index 0000000..49e6cd6 --- /dev/null +++ b/_sources/qs_codec.enums.rst.txt @@ -0,0 +1,53 @@ +qs\_codec.enums package +======================= + +Submodules +---------- + +qs\_codec.enums.charset module +------------------------------ + +.. automodule:: qs_codec.enums.charset + :members: + :undoc-members: + :show-inheritance: + +qs\_codec.enums.duplicates module +--------------------------------- + +.. automodule:: qs_codec.enums.duplicates + :members: + :undoc-members: + :show-inheritance: + +qs\_codec.enums.format module +----------------------------- + +.. automodule:: qs_codec.enums.format + :members: + :undoc-members: + :show-inheritance: + +qs\_codec.enums.list\_format module +----------------------------------- + +.. automodule:: qs_codec.enums.list_format + :members: + :undoc-members: + :show-inheritance: + +qs\_codec.enums.sentinel module +------------------------------- + +.. automodule:: qs_codec.enums.sentinel + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: qs_codec.enums + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/qs_codec.models.rst.txt b/_sources/qs_codec.models.rst.txt new file mode 100644 index 0000000..0cc38fd --- /dev/null +++ b/_sources/qs_codec.models.rst.txt @@ -0,0 +1,45 @@ +qs\_codec.models package +======================== + +Submodules +---------- + +qs\_codec.models.decode\_options module +--------------------------------------- + +.. automodule:: qs_codec.models.decode_options + :members: + :undoc-members: + :show-inheritance: + +qs\_codec.models.encode\_options module +--------------------------------------- + +.. automodule:: qs_codec.models.encode_options + :members: + :undoc-members: + :show-inheritance: + +qs\_codec.models.undefined module +--------------------------------- + +.. automodule:: qs_codec.models.undefined + :members: + :undoc-members: + :show-inheritance: + +qs\_codec.models.weak\_wrapper module +------------------------------------- + +.. automodule:: qs_codec.models.weak_wrapper + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: qs_codec.models + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/qs_codec.rst.txt b/_sources/qs_codec.rst.txt new file mode 100644 index 0000000..a368826 --- /dev/null +++ b/_sources/qs_codec.rst.txt @@ -0,0 +1,39 @@ +qs\_codec package +================= + +Subpackages +----------- + +.. toctree:: + :maxdepth: 4 + + qs_codec.enums + qs_codec.models + qs_codec.utils + +Submodules +---------- + +qs\_codec.decode module +----------------------- + +.. automodule:: qs_codec.decode + :members: + :undoc-members: + :show-inheritance: + +qs\_codec.encode module +----------------------- + +.. automodule:: qs_codec.encode + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: qs_codec + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/qs_codec.utils.rst.txt b/_sources/qs_codec.utils.rst.txt new file mode 100644 index 0000000..40fdf1f --- /dev/null +++ b/_sources/qs_codec.utils.rst.txt @@ -0,0 +1,45 @@ +qs\_codec.utils package +======================= + +Submodules +---------- + +qs\_codec.utils.decode\_utils module +------------------------------------ + +.. automodule:: qs_codec.utils.decode_utils + :members: + :undoc-members: + :show-inheritance: + +qs\_codec.utils.encode\_utils module +------------------------------------ + +.. automodule:: qs_codec.utils.encode_utils + :members: + :undoc-members: + :show-inheritance: + +qs\_codec.utils.str\_utils module +--------------------------------- + +.. automodule:: qs_codec.utils.str_utils + :members: + :undoc-members: + :show-inheritance: + +qs\_codec.utils.utils module +---------------------------- + +.. automodule:: qs_codec.utils.utils + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: qs_codec.utils + :members: + :undoc-members: + :show-inheritance: diff --git a/_static/alabaster.css b/_static/alabaster.css new file mode 100644 index 0000000..e3174bf --- /dev/null +++ b/_static/alabaster.css @@ -0,0 +1,708 @@ +@import url("basic.css"); + +/* -- page layout ----------------------------------------------------------- */ + +body { + font-family: Georgia, serif; + font-size: 17px; + background-color: #fff; + color: #000; + margin: 0; + padding: 0; +} + + +div.document { + width: 940px; + margin: 30px auto 0 auto; +} + +div.documentwrapper { + float: left; + width: 100%; +} + +div.bodywrapper { + margin: 0 0 0 220px; +} + +div.sphinxsidebar { + width: 220px; + font-size: 14px; + line-height: 1.5; +} + +hr { + border: 1px solid #B1B4B6; +} + +div.body { + background-color: #fff; + color: #3E4349; + padding: 0 30px 0 30px; +} + +div.body > .section { + text-align: left; +} + +div.footer { + width: 940px; + margin: 20px auto 30px auto; + font-size: 14px; + color: #888; + text-align: right; +} + +div.footer a { + color: #888; +} + +p.caption { + font-family: inherit; + font-size: inherit; +} + + +div.relations { + display: none; +} + + +div.sphinxsidebar { + max-height: 100%; + overflow-y: auto; +} + +div.sphinxsidebar a { + color: #444; + text-decoration: none; + border-bottom: 1px dotted #999; +} + +div.sphinxsidebar a:hover { + border-bottom: 1px solid #999; +} + +div.sphinxsidebarwrapper { + padding: 18px 10px; +} + +div.sphinxsidebarwrapper p.logo { + padding: 0; + margin: -10px 0 0 0px; + text-align: center; +} + +div.sphinxsidebarwrapper h1.logo { + margin-top: -10px; + text-align: center; + margin-bottom: 5px; + text-align: left; +} + +div.sphinxsidebarwrapper h1.logo-name { + margin-top: 0px; +} + +div.sphinxsidebarwrapper p.blurb { + margin-top: 0; + font-style: normal; +} + +div.sphinxsidebar h3, +div.sphinxsidebar h4 { + font-family: Georgia, serif; + color: #444; + font-size: 24px; + font-weight: normal; + margin: 0 0 5px 0; + padding: 0; +} + +div.sphinxsidebar h4 { + font-size: 20px; +} + +div.sphinxsidebar h3 a { + color: #444; +} + +div.sphinxsidebar p.logo a, +div.sphinxsidebar h3 a, +div.sphinxsidebar p.logo a:hover, +div.sphinxsidebar h3 a:hover { + border: none; +} + +div.sphinxsidebar p { + color: #555; + margin: 10px 0; +} + +div.sphinxsidebar ul { + margin: 10px 0; + padding: 0; + color: #000; +} + +div.sphinxsidebar ul li.toctree-l1 > a { + font-size: 120%; +} + +div.sphinxsidebar ul li.toctree-l2 > a { + font-size: 110%; +} + +div.sphinxsidebar input { + border: 1px solid #CCC; + font-family: Georgia, serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox input[type="text"] { + width: 160px; +} + +div.sphinxsidebar .search > div { + display: table-cell; +} + +div.sphinxsidebar hr { + border: none; + height: 1px; + color: #AAA; + background: #AAA; + + text-align: left; + margin-left: 0; + width: 50%; +} + +div.sphinxsidebar .badge { + border-bottom: none; +} + +div.sphinxsidebar .badge:hover { + border-bottom: none; +} + +/* To address an issue with donation coming after search */ +div.sphinxsidebar h3.donation { + margin-top: 10px; +} + +/* -- body styles ----------------------------------------------------------- */ + +a { + color: #004B6B; + text-decoration: underline; +} + +a:hover { + color: #6D4100; + text-decoration: underline; +} + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + font-family: Georgia, serif; + font-weight: normal; + margin: 30px 0px 10px 0px; + padding: 0; +} + +div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; } +div.body h2 { font-size: 180%; } +div.body h3 { font-size: 150%; } +div.body h4 { font-size: 130%; } +div.body h5 { font-size: 100%; } +div.body h6 { font-size: 100%; } + +a.headerlink { + color: #DDD; + padding: 0 4px; + text-decoration: none; +} + +a.headerlink:hover { + color: #444; + background: #EAEAEA; +} + +div.body p, div.body dd, div.body li { + line-height: 1.4em; +} + +div.admonition { + margin: 20px 0px; + padding: 10px 30px; + background-color: #EEE; + border: 1px solid #CCC; +} + +div.admonition tt.xref, div.admonition code.xref, div.admonition a tt { + background-color: #FBFBFB; + border-bottom: 1px solid #fafafa; +} + +div.admonition p.admonition-title { + font-family: Georgia, serif; + font-weight: normal; + font-size: 24px; + margin: 0 0 10px 0; + padding: 0; + line-height: 1; +} + +div.admonition p.last { + margin-bottom: 0; +} + +div.highlight { + background-color: #fff; +} + +dt:target, .highlight { + background: #FAF3E8; +} + +div.warning { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.danger { + background-color: #FCC; + border: 1px solid #FAA; + -moz-box-shadow: 2px 2px 4px #D52C2C; + -webkit-box-shadow: 2px 2px 4px #D52C2C; + box-shadow: 2px 2px 4px #D52C2C; +} + +div.error { + background-color: #FCC; + border: 1px solid #FAA; + -moz-box-shadow: 2px 2px 4px #D52C2C; + -webkit-box-shadow: 2px 2px 4px #D52C2C; + box-shadow: 2px 2px 4px #D52C2C; +} + +div.caution { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.attention { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.important { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.note { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.tip { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.hint { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.seealso { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.topic { + background-color: #EEE; +} + +p.admonition-title { + display: inline; +} + +p.admonition-title:after { + content: ":"; +} + +pre, tt, code { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; + font-size: 0.9em; +} + +.hll { + background-color: #FFC; + margin: 0 -12px; + padding: 0 12px; + display: block; +} + +img.screenshot { +} + +tt.descname, tt.descclassname, code.descname, code.descclassname { + font-size: 0.95em; +} + +tt.descname, code.descname { + padding-right: 0.08em; +} + +img.screenshot { + -moz-box-shadow: 2px 2px 4px #EEE; + -webkit-box-shadow: 2px 2px 4px #EEE; + box-shadow: 2px 2px 4px #EEE; +} + +table.docutils { + border: 1px solid #888; + -moz-box-shadow: 2px 2px 4px #EEE; + -webkit-box-shadow: 2px 2px 4px #EEE; + box-shadow: 2px 2px 4px #EEE; +} + +table.docutils td, table.docutils th { + border: 1px solid #888; + padding: 0.25em 0.7em; +} + +table.field-list, table.footnote { + border: none; + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; +} + +table.footnote { + margin: 15px 0; + width: 100%; + border: 1px solid #EEE; + background: #FDFDFD; + font-size: 0.9em; +} + +table.footnote + table.footnote { + margin-top: -15px; + border-top: none; +} + +table.field-list th { + padding: 0 0.8em 0 0; +} + +table.field-list td { + padding: 0; +} + +table.field-list p { + margin-bottom: 0.8em; +} + +/* Cloned from + * https://github.com/sphinx-doc/sphinx/commit/ef60dbfce09286b20b7385333d63a60321784e68 + */ +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +table.footnote td.label { + width: .1px; + padding: 0.3em 0 0.3em 0.5em; +} + +table.footnote td { + padding: 0.3em 0.5em; +} + +dl { + margin-left: 0; + margin-right: 0; + margin-top: 0; + padding: 0; +} + +dl dd { + margin-left: 30px; +} + +blockquote { + margin: 0 0 0 30px; + padding: 0; +} + +ul, ol { + /* Matches the 30px from the narrow-screen "li > ul" selector below */ + margin: 10px 0 10px 30px; + padding: 0; +} + +pre { + background: #EEE; + padding: 7px 30px; + margin: 15px 0px; + line-height: 1.3em; +} + +div.viewcode-block:target { + background: #ffd; +} + +dl pre, blockquote pre, li pre { + margin-left: 0; + padding-left: 30px; +} + +tt, code { + background-color: #ecf0f3; + color: #222; + /* padding: 1px 2px; */ +} + +tt.xref, code.xref, a tt { + background-color: #FBFBFB; + border-bottom: 1px solid #fff; +} + +a.reference { + text-decoration: none; + border-bottom: 1px dotted #004B6B; +} + +/* Don't put an underline on images */ +a.image-reference, a.image-reference:hover { + border-bottom: none; +} + +a.reference:hover { + border-bottom: 1px solid #6D4100; +} + +a.footnote-reference { + text-decoration: none; + font-size: 0.7em; + vertical-align: top; + border-bottom: 1px dotted #004B6B; +} + +a.footnote-reference:hover { + border-bottom: 1px solid #6D4100; +} + +a:hover tt, a:hover code { + background: #EEE; +} + + +@media screen and (max-width: 870px) { + + div.sphinxsidebar { + display: none; + } + + div.document { + width: 100%; + + } + + div.documentwrapper { + margin-left: 0; + margin-top: 0; + margin-right: 0; + margin-bottom: 0; + } + + div.bodywrapper { + margin-top: 0; + margin-right: 0; + margin-bottom: 0; + margin-left: 0; + } + + ul { + margin-left: 0; + } + + li > ul { + /* Matches the 30px from the "ul, ol" selector above */ + margin-left: 30px; + } + + .document { + width: auto; + } + + .footer { + width: auto; + } + + .bodywrapper { + margin: 0; + } + + .footer { + width: auto; + } + + .github { + display: none; + } + + + +} + + + +@media screen and (max-width: 875px) { + + body { + margin: 0; + padding: 20px 30px; + } + + div.documentwrapper { + float: none; + background: #fff; + } + + div.sphinxsidebar { + display: block; + float: none; + width: 102.5%; + margin: 50px -30px -20px -30px; + padding: 10px 20px; + background: #333; + color: #FFF; + } + + div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, + div.sphinxsidebar h3 a { + color: #fff; + } + + div.sphinxsidebar a { + color: #AAA; + } + + div.sphinxsidebar p.logo { + display: none; + } + + div.document { + width: 100%; + margin: 0; + } + + div.footer { + display: none; + } + + div.bodywrapper { + margin: 0; + } + + div.body { + min-height: 0; + padding: 0; + } + + .rtd_doc_footer { + display: none; + } + + .document { + width: auto; + } + + .footer { + width: auto; + } + + .footer { + width: auto; + } + + .github { + display: none; + } +} + + +/* misc. */ + +.revsys-inline { + display: none!important; +} + +/* Hide ugly table cell borders in ..bibliography:: directive output */ +table.docutils.citation, table.docutils.citation td, table.docutils.citation th { + border: none; + /* Below needed in some edge cases; if not applied, bottom shadows appear */ + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; +} + + +/* relbar */ + +.related { + line-height: 30px; + width: 100%; + font-size: 0.9rem; +} + +.related.top { + border-bottom: 1px solid #EEE; + margin-bottom: 20px; +} + +.related.bottom { + border-top: 1px solid #EEE; +} + +.related ul { + padding: 0; + margin: 0; + list-style: none; +} + +.related li { + display: inline; +} + +nav#rellinks { + float: right; +} + +nav#rellinks li+li:before { + content: "|"; +} + +nav#breadcrumbs li+li:before { + content: "\00BB"; +} + +/* Hide certain items when printing */ +@media print { + div.related { + display: none; + } +} \ No newline at end of file diff --git a/_static/basic.css b/_static/basic.css new file mode 100644 index 0000000..e5179b7 --- /dev/null +++ b/_static/basic.css @@ -0,0 +1,925 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: inherit; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a:visited { + color: #551A8B; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +.sig dd { + margin-top: 0px; + margin-bottom: 0px; +} + +.sig dl { + margin-top: 0px; + margin-bottom: 0px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +.translated { + background-color: rgba(207, 255, 207, 0.2) +} + +.untranslated { + background-color: rgba(255, 207, 207, 0.2) +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/_static/custom.css b/_static/custom.css new file mode 100644 index 0000000..2a924f1 --- /dev/null +++ b/_static/custom.css @@ -0,0 +1 @@ +/* This file intentionally left blank. */ diff --git a/_static/doctools.js b/_static/doctools.js new file mode 100644 index 0000000..4d67807 --- /dev/null +++ b/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/_static/documentation_options.js b/_static/documentation_options.js new file mode 100644 index 0000000..add8e0c --- /dev/null +++ b/_static/documentation_options.js @@ -0,0 +1,13 @@ +const DOCUMENTATION_OPTIONS = { + VERSION: '0.2.1', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/_static/file.png b/_static/file.png new file mode 100644 index 0000000000000000000000000000000000000000..a858a410e4faa62ce324d814e4b816fff83a6fb3 GIT binary patch literal 286 zcmV+(0pb3MP)s`hMrGg#P~ix$^RISR_I47Y|r1 z_CyJOe}D1){SET-^Amu_i71Lt6eYfZjRyw@I6OQAIXXHDfiX^GbOlHe=Ae4>0m)d(f|Me07*qoM6N<$f}vM^LjV8( literal 0 HcmV?d00001 diff --git a/_static/language_data.js b/_static/language_data.js new file mode 100644 index 0000000..367b8ed --- /dev/null +++ b/_static/language_data.js @@ -0,0 +1,199 @@ +/* + * language_data.js + * ~~~~~~~~~~~~~~~~ + * + * This script contains the language-specific data used by searchtools.js, + * namely the list of stopwords, stemmer, scorer and splitter. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +var stopwords = ["a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "near", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"]; + + +/* Non-minified version is copied as a separate JS file, if available */ + +/** + * Porter Stemmer + */ +var Stemmer = function() { + + var step2list = { + ational: 'ate', + tional: 'tion', + enci: 'ence', + anci: 'ance', + izer: 'ize', + bli: 'ble', + alli: 'al', + entli: 'ent', + eli: 'e', + ousli: 'ous', + ization: 'ize', + ation: 'ate', + ator: 'ate', + alism: 'al', + iveness: 'ive', + fulness: 'ful', + ousness: 'ous', + aliti: 'al', + iviti: 'ive', + biliti: 'ble', + logi: 'log' + }; + + var step3list = { + icate: 'ic', + ative: '', + alize: 'al', + iciti: 'ic', + ical: 'ic', + ful: '', + ness: '' + }; + + var c = "[^aeiou]"; // consonant + var v = "[aeiouy]"; // vowel + var C = c + "[^aeiouy]*"; // consonant sequence + var V = v + "[aeiou]*"; // vowel sequence + + var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + diff --git a/_static/minus.png b/_static/minus.png new file mode 100644 index 0000000000000000000000000000000000000000..d96755fdaf8bb2214971e0db9c1fd3077d7c419d GIT binary patch literal 90 zcmeAS@N?(olHy`uVBq!ia0vp^+#t*WBp7;*Yy1LIik>cxAr*|t7R?Mi>2?kWtu=nj kDsEF_5m^0CR;1wuP-*O&G^0G}KYk!hp00i_>zopr08q^qX#fBK literal 0 HcmV?d00001 diff --git a/_static/plus.png b/_static/plus.png new file mode 100644 index 0000000000000000000000000000000000000000..7107cec93a979b9a5f64843235a16651d563ce2d GIT binary patch literal 90 zcmeAS@N?(olHy`uVBq!ia0vp^+#t*WBp7;*Yy1LIik>cxAr*|t7R?Mi>2?kWtu>-2 m3q%Vub%g%s<8sJhVPMczOq}xhg9DJoz~JfX=d#Wzp$Pyb1r*Kz literal 0 HcmV?d00001 diff --git a/_static/pygments.css b/_static/pygments.css new file mode 100644 index 0000000..04a4174 --- /dev/null +++ b/_static/pygments.css @@ -0,0 +1,84 @@ +pre { line-height: 125%; } +td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight .hll { background-color: #ffffcc } +.highlight { background: #f8f8f8; } +.highlight .c { color: #8f5902; font-style: italic } /* Comment */ +.highlight .err { color: #a40000; border: 1px solid #ef2929 } /* Error */ +.highlight .g { color: #000000 } /* Generic */ +.highlight .k { color: #004461; font-weight: bold } /* Keyword */ +.highlight .l { color: #000000 } /* Literal */ +.highlight .n { color: #000000 } /* Name */ +.highlight .o { color: #582800 } /* Operator */ +.highlight .x { color: #000000 } /* Other */ +.highlight .p { color: #000000; font-weight: bold } /* Punctuation */ +.highlight .ch { color: #8f5902; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #8f5902; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #8f5902 } /* Comment.Preproc */ +.highlight .cpf { color: #8f5902; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #8f5902; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #8f5902; font-style: italic } /* Comment.Special */ +.highlight .gd { color: #a40000 } /* Generic.Deleted */ +.highlight .ge { color: #000000; font-style: italic } /* Generic.Emph */ +.highlight .ges { color: #000000 } /* Generic.EmphStrong */ +.highlight .gr { color: #ef2929 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #888888 } /* Generic.Output */ +.highlight .gp { color: #745334 } /* Generic.Prompt */ +.highlight .gs { color: #000000; font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #a40000; font-weight: bold } /* Generic.Traceback */ +.highlight .kc { color: #004461; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #004461; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #004461; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #004461; font-weight: bold } /* Keyword.Pseudo */ +.highlight .kr { color: #004461; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #004461; font-weight: bold } /* Keyword.Type */ +.highlight .ld { color: #000000 } /* Literal.Date */ +.highlight .m { color: #990000 } /* Literal.Number */ +.highlight .s { color: #4e9a06 } /* Literal.String */ +.highlight .na { color: #c4a000 } /* Name.Attribute */ +.highlight .nb { color: #004461 } /* Name.Builtin */ +.highlight .nc { color: #000000 } /* Name.Class */ +.highlight .no { color: #000000 } /* Name.Constant */ +.highlight .nd { color: #888888 } /* Name.Decorator */ +.highlight .ni { color: #ce5c00 } /* Name.Entity */ +.highlight .ne { color: #cc0000; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #000000 } /* Name.Function */ +.highlight .nl { color: #f57900 } /* Name.Label */ +.highlight .nn { color: #000000 } /* Name.Namespace */ +.highlight .nx { color: #000000 } /* Name.Other */ +.highlight .py { color: #000000 } /* Name.Property */ +.highlight .nt { color: #004461; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #000000 } /* Name.Variable */ +.highlight .ow { color: #004461; font-weight: bold } /* Operator.Word */ +.highlight .pm { color: #000000; font-weight: bold } /* Punctuation.Marker */ +.highlight .w { color: #f8f8f8 } /* Text.Whitespace */ +.highlight .mb { color: #990000 } /* Literal.Number.Bin */ +.highlight .mf { color: #990000 } /* Literal.Number.Float */ +.highlight .mh { color: #990000 } /* Literal.Number.Hex */ +.highlight .mi { color: #990000 } /* Literal.Number.Integer */ +.highlight .mo { color: #990000 } /* Literal.Number.Oct */ +.highlight .sa { color: #4e9a06 } /* Literal.String.Affix */ +.highlight .sb { color: #4e9a06 } /* Literal.String.Backtick */ +.highlight .sc { color: #4e9a06 } /* Literal.String.Char */ +.highlight .dl { color: #4e9a06 } /* Literal.String.Delimiter */ +.highlight .sd { color: #8f5902; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #4e9a06 } /* Literal.String.Double */ +.highlight .se { color: #4e9a06 } /* Literal.String.Escape */ +.highlight .sh { color: #4e9a06 } /* Literal.String.Heredoc */ +.highlight .si { color: #4e9a06 } /* Literal.String.Interpol */ +.highlight .sx { color: #4e9a06 } /* Literal.String.Other */ +.highlight .sr { color: #4e9a06 } /* Literal.String.Regex */ +.highlight .s1 { color: #4e9a06 } /* Literal.String.Single */ +.highlight .ss { color: #4e9a06 } /* Literal.String.Symbol */ +.highlight .bp { color: #3465a4 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #000000 } /* Name.Function.Magic */ +.highlight .vc { color: #000000 } /* Name.Variable.Class */ +.highlight .vg { color: #000000 } /* Name.Variable.Global */ +.highlight .vi { color: #000000 } /* Name.Variable.Instance */ +.highlight .vm { color: #000000 } /* Name.Variable.Magic */ +.highlight .il { color: #990000 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/_static/searchtools.js b/_static/searchtools.js new file mode 100644 index 0000000..92da3f8 --- /dev/null +++ b/_static/searchtools.js @@ -0,0 +1,619 @@ +/* + * searchtools.js + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for the full-text search. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +/** + * Simple result scoring code. + */ +if (typeof Scorer === "undefined") { + var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [docname, title, anchor, descr, score, filename] + // and returns the new score. + /* + score: result => { + const [docname, title, anchor, descr, score, filename] = result + return score + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: { + 0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5, // used to be unimportantResults + }, + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + partialTitle: 7, + // query found in terms + term: 5, + partialTerm: 2, + }; +} + +const _removeChildren = (element) => { + while (element && element.lastChild) element.removeChild(element.lastChild); +}; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping + */ +const _escapeRegExp = (string) => + string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string + +const _displayItem = (item, searchTerms, highlightTerms) => { + const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; + const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; + const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; + const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; + const contentRoot = document.documentElement.dataset.content_root; + + const [docName, title, anchor, descr, score, _filename] = item; + + let listItem = document.createElement("li"); + let requestUrl; + let linkUrl; + if (docBuilder === "dirhtml") { + // dirhtml builder + let dirname = docName + "/"; + if (dirname.match(/\/index\/$/)) + dirname = dirname.substring(0, dirname.length - 6); + else if (dirname === "index/") dirname = ""; + requestUrl = contentRoot + dirname; + linkUrl = requestUrl; + } else { + // normal html builders + requestUrl = contentRoot + docName + docFileSuffix; + linkUrl = docName + docLinkSuffix; + } + let linkEl = listItem.appendChild(document.createElement("a")); + linkEl.href = linkUrl + anchor; + linkEl.dataset.score = score; + linkEl.innerHTML = title; + if (descr) { + listItem.appendChild(document.createElement("span")).innerHTML = + " (" + descr + ")"; + // highlight search terms in the description + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + } + else if (showSearchSummary) + fetch(requestUrl) + .then((responseData) => responseData.text()) + .then((data) => { + if (data) + listItem.appendChild( + Search.makeSearchSummary(data, searchTerms, anchor) + ); + // highlight search terms in the summary + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + }); + Search.output.appendChild(listItem); +}; +const _finishSearch = (resultCount) => { + Search.stopPulse(); + Search.title.innerText = _("Search Results"); + if (!resultCount) + Search.status.innerText = Documentation.gettext( + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." + ); + else + Search.status.innerText = _( + "Search finished, found ${resultCount} page(s) matching the search query." + ).replace('${resultCount}', resultCount); +}; +const _displayNextItem = ( + results, + resultCount, + searchTerms, + highlightTerms, +) => { + // results left, load the summary and display it + // this is intended to be dynamic (don't sub resultsCount) + if (results.length) { + _displayItem(results.pop(), searchTerms, highlightTerms); + setTimeout( + () => _displayNextItem(results, resultCount, searchTerms, highlightTerms), + 5 + ); + } + // search finished, update title and status message + else _finishSearch(resultCount); +}; +// Helper function used by query() to order search results. +// Each input is an array of [docname, title, anchor, descr, score, filename]. +// Order the results by score (in opposite order of appearance, since the +// `_displayNextItem` function uses pop() to retrieve items) and then alphabetically. +const _orderResultsByScoreThenName = (a, b) => { + const leftScore = a[4]; + const rightScore = b[4]; + if (leftScore === rightScore) { + // same score: sort alphabetically + const leftTitle = a[1].toLowerCase(); + const rightTitle = b[1].toLowerCase(); + if (leftTitle === rightTitle) return 0; + return leftTitle > rightTitle ? -1 : 1; // inverted is intentional + } + return leftScore > rightScore ? 1 : -1; +}; + +/** + * Default splitQuery function. Can be overridden in ``sphinx.search`` with a + * custom function per language. + * + * The regular expression works by splitting the string on consecutive characters + * that are not Unicode letters, numbers, underscores, or emoji characters. + * This is the same as ``\W+`` in Python, preserving the surrogate pair area. + */ +if (typeof splitQuery === "undefined") { + var splitQuery = (query) => query + .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) + .filter(term => term) // remove remaining empty strings +} + +/** + * Search Module + */ +const Search = { + _index: null, + _queued_query: null, + _pulse_status: -1, + + htmlToText: (htmlString, anchor) => { + const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); + for (const removalQuery of [".headerlinks", "script", "style"]) { + htmlElement.querySelectorAll(removalQuery).forEach((el) => { el.remove() }); + } + if (anchor) { + const anchorContent = htmlElement.querySelector(`[role="main"] ${anchor}`); + if (anchorContent) return anchorContent.textContent; + + console.warn( + `Anchored content block not found. Sphinx search tries to obtain it via DOM query '[role=main] ${anchor}'. Check your theme or template.` + ); + } + + // if anchor not specified or not found, fall back to main content + const docContent = htmlElement.querySelector('[role="main"]'); + if (docContent) return docContent.textContent; + + console.warn( + "Content block not found. Sphinx search tries to obtain it via DOM query '[role=main]'. Check your theme or template." + ); + return ""; + }, + + init: () => { + const query = new URLSearchParams(window.location.search).get("q"); + document + .querySelectorAll('input[name="q"]') + .forEach((el) => (el.value = query)); + if (query) Search.performSearch(query); + }, + + loadIndex: (url) => + (document.body.appendChild(document.createElement("script")).src = url), + + setIndex: (index) => { + Search._index = index; + if (Search._queued_query !== null) { + const query = Search._queued_query; + Search._queued_query = null; + Search.query(query); + } + }, + + hasIndex: () => Search._index !== null, + + deferQuery: (query) => (Search._queued_query = query), + + stopPulse: () => (Search._pulse_status = -1), + + startPulse: () => { + if (Search._pulse_status >= 0) return; + + const pulse = () => { + Search._pulse_status = (Search._pulse_status + 1) % 4; + Search.dots.innerText = ".".repeat(Search._pulse_status); + if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); + }; + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch: (query) => { + // create the required interface elements + const searchText = document.createElement("h2"); + searchText.textContent = _("Searching"); + const searchSummary = document.createElement("p"); + searchSummary.classList.add("search-summary"); + searchSummary.innerText = ""; + const searchList = document.createElement("ul"); + searchList.classList.add("search"); + + const out = document.getElementById("search-results"); + Search.title = out.appendChild(searchText); + Search.dots = Search.title.appendChild(document.createElement("span")); + Search.status = out.appendChild(searchSummary); + Search.output = out.appendChild(searchList); + + const searchProgress = document.getElementById("search-progress"); + // Some themes don't use the search progress node + if (searchProgress) { + searchProgress.innerText = _("Preparing search..."); + } + Search.startPulse(); + + // index already loaded, the browser was quick! + if (Search.hasIndex()) Search.query(query); + else Search.deferQuery(query); + }, + + _parseQuery: (query) => { + // stem the search terms and add them to the correct list + const stemmer = new Stemmer(); + const searchTerms = new Set(); + const excludedTerms = new Set(); + const highlightTerms = new Set(); + const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); + splitQuery(query.trim()).forEach((queryTerm) => { + const queryTermLower = queryTerm.toLowerCase(); + + // maybe skip this "word" + // stopwords array is from language_data.js + if ( + stopwords.indexOf(queryTermLower) !== -1 || + queryTerm.match(/^\d+$/) + ) + return; + + // stem the word + let word = stemmer.stemWord(queryTermLower); + // select the correct list + if (word[0] === "-") excludedTerms.add(word.substr(1)); + else { + searchTerms.add(word); + highlightTerms.add(queryTermLower); + } + }); + + if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js + localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) + } + + // console.debug("SEARCH: searching for:"); + // console.info("required: ", [...searchTerms]); + // console.info("excluded: ", [...excludedTerms]); + + return [query, searchTerms, excludedTerms, highlightTerms, objectTerms]; + }, + + /** + * execute search (requires search index to be loaded) + */ + _performSearch: (query, searchTerms, excludedTerms, highlightTerms, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + const allTitles = Search._index.alltitles; + const indexEntries = Search._index.indexentries; + + // Collect multiple result groups to be sorted separately and then ordered. + // Each is an array of [docname, title, anchor, descr, score, filename]. + const normalResults = []; + const nonMainIndexResults = []; + + _removeChildren(document.getElementById("search-progress")); + + const queryLower = query.toLowerCase().trim(); + for (const [title, foundTitles] of Object.entries(allTitles)) { + if (title.toLowerCase().trim().includes(queryLower) && (queryLower.length >= title.length/2)) { + for (const [file, id] of foundTitles) { + let score = Math.round(100 * queryLower.length / title.length) + normalResults.push([ + docNames[file], + titles[file] !== title ? `${titles[file]} > ${title}` : title, + id !== null ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // search for explicit entries in index directives + for (const [entry, foundEntries] of Object.entries(indexEntries)) { + if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { + for (const [file, id, isMain] of foundEntries) { + const score = Math.round(100 * queryLower.length / entry.length); + const result = [ + docNames[file], + titles[file], + id ? "#" + id : "", + null, + score, + filenames[file], + ]; + if (isMain) { + normalResults.push(result); + } else { + nonMainIndexResults.push(result); + } + } + } + } + + // lookup as object + objectTerms.forEach((term) => + normalResults.push(...Search.performObjectSearch(term, objectTerms)) + ); + + // lookup as search terms in fulltext + normalResults.push(...Search.performTermsSearch(searchTerms, excludedTerms)); + + // let the scorer override scores with a custom scoring function + if (Scorer.score) { + normalResults.forEach((item) => (item[4] = Scorer.score(item))); + nonMainIndexResults.forEach((item) => (item[4] = Scorer.score(item))); + } + + // Sort each group of results by score and then alphabetically by name. + normalResults.sort(_orderResultsByScoreThenName); + nonMainIndexResults.sort(_orderResultsByScoreThenName); + + // Combine the result groups in (reverse) order. + // Non-main index entries are typically arbitrary cross-references, + // so display them after other results. + let results = [...nonMainIndexResults, ...normalResults]; + + // remove duplicate search results + // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept + let seen = new Set(); + results = results.reverse().reduce((acc, result) => { + let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); + if (!seen.has(resultStr)) { + acc.push(result); + seen.add(resultStr); + } + return acc; + }, []); + + return results.reverse(); + }, + + query: (query) => { + const [searchQuery, searchTerms, excludedTerms, highlightTerms, objectTerms] = Search._parseQuery(query); + const results = Search._performSearch(searchQuery, searchTerms, excludedTerms, highlightTerms, objectTerms); + + // for debugging + //Search.lastresults = results.slice(); // a copy + // console.info("search results:", Search.lastresults); + + // print the results + _displayNextItem(results, results.length, searchTerms, highlightTerms); + }, + + /** + * search for object names + */ + performObjectSearch: (object, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const objects = Search._index.objects; + const objNames = Search._index.objnames; + const titles = Search._index.titles; + + const results = []; + + const objectSearchCallback = (prefix, match) => { + const name = match[4] + const fullname = (prefix ? prefix + "." : "") + name; + const fullnameLower = fullname.toLowerCase(); + if (fullnameLower.indexOf(object) < 0) return; + + let score = 0; + const parts = fullnameLower.split("."); + + // check for different match types: exact matches of full name or + // "last name" (i.e. last dotted part) + if (fullnameLower === object || parts.slice(-1)[0] === object) + score += Scorer.objNameMatch; + else if (parts.slice(-1)[0].indexOf(object) > -1) + score += Scorer.objPartialMatch; // matches in last name + + const objName = objNames[match[1]][2]; + const title = titles[match[0]]; + + // If more than one term searched for, we require other words to be + // found in the name/title/description + const otherTerms = new Set(objectTerms); + otherTerms.delete(object); + if (otherTerms.size > 0) { + const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); + if ( + [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) + ) + return; + } + + let anchor = match[3]; + if (anchor === "") anchor = fullname; + else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; + + const descr = objName + _(", in ") + title; + + // add custom score for some objects according to scorer + if (Scorer.objPrio.hasOwnProperty(match[2])) + score += Scorer.objPrio[match[2]]; + else score += Scorer.objPrioDefault; + + results.push([ + docNames[match[0]], + fullname, + "#" + anchor, + descr, + score, + filenames[match[0]], + ]); + }; + Object.keys(objects).forEach((prefix) => + objects[prefix].forEach((array) => + objectSearchCallback(prefix, array) + ) + ); + return results; + }, + + /** + * search for full-text terms in the index + */ + performTermsSearch: (searchTerms, excludedTerms) => { + // prepare search + const terms = Search._index.terms; + const titleTerms = Search._index.titleterms; + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + + const scoreMap = new Map(); + const fileMap = new Map(); + + // perform the search on the required terms + searchTerms.forEach((word) => { + const files = []; + const arr = [ + { files: terms[word], score: Scorer.term }, + { files: titleTerms[word], score: Scorer.title }, + ]; + // add support for partial matches + if (word.length > 2) { + const escapedWord = _escapeRegExp(word); + if (!terms.hasOwnProperty(word)) { + Object.keys(terms).forEach((term) => { + if (term.match(escapedWord)) + arr.push({ files: terms[term], score: Scorer.partialTerm }); + }); + } + if (!titleTerms.hasOwnProperty(word)) { + Object.keys(titleTerms).forEach((term) => { + if (term.match(escapedWord)) + arr.push({ files: titleTerms[term], score: Scorer.partialTitle }); + }); + } + } + + // no match but word was a required one + if (arr.every((record) => record.files === undefined)) return; + + // found search word in contents + arr.forEach((record) => { + if (record.files === undefined) return; + + let recordFiles = record.files; + if (recordFiles.length === undefined) recordFiles = [recordFiles]; + files.push(...recordFiles); + + // set score for the word in each file + recordFiles.forEach((file) => { + if (!scoreMap.has(file)) scoreMap.set(file, {}); + scoreMap.get(file)[word] = record.score; + }); + }); + + // create the mapping + files.forEach((file) => { + if (!fileMap.has(file)) fileMap.set(file, [word]); + else if (fileMap.get(file).indexOf(word) === -1) fileMap.get(file).push(word); + }); + }); + + // now check if the files don't contain excluded terms + const results = []; + for (const [file, wordList] of fileMap) { + // check if all requirements are matched + + // as search terms with length < 3 are discarded + const filteredTermCount = [...searchTerms].filter( + (term) => term.length > 2 + ).length; + if ( + wordList.length !== searchTerms.size && + wordList.length !== filteredTermCount + ) + continue; + + // ensure that none of the excluded terms is in the search result + if ( + [...excludedTerms].some( + (term) => + terms[term] === file || + titleTerms[term] === file || + (terms[term] || []).includes(file) || + (titleTerms[term] || []).includes(file) + ) + ) + break; + + // select one (max) score for the file. + const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); + // add result to the result list + results.push([ + docNames[file], + titles[file], + "", + null, + score, + filenames[file], + ]); + } + return results; + }, + + /** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words. + */ + makeSearchSummary: (htmlText, keywords, anchor) => { + const text = Search.htmlToText(htmlText, anchor); + if (text === "") return null; + + const textLower = text.toLowerCase(); + const actualStartPosition = [...keywords] + .map((k) => textLower.indexOf(k.toLowerCase())) + .filter((i) => i > -1) + .slice(-1)[0]; + const startWithContext = Math.max(actualStartPosition - 120, 0); + + const top = startWithContext === 0 ? "" : "..."; + const tail = startWithContext + 240 < text.length ? "..." : ""; + + let summary = document.createElement("p"); + summary.classList.add("context"); + summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; + + return summary; + }, +}; + +_ready(Search.init); diff --git a/_static/sphinx_highlight.js b/_static/sphinx_highlight.js new file mode 100644 index 0000000..8a96c69 --- /dev/null +++ b/_static/sphinx_highlight.js @@ -0,0 +1,154 @@ +/* Highlighting utilities for Sphinx HTML documentation. */ +"use strict"; + +const SPHINX_HIGHLIGHT_ENABLED = true + +/** + * highlight a given string on a node by wrapping it in + * span elements with the given class name. + */ +const _highlight = (node, addItems, text, className) => { + if (node.nodeType === Node.TEXT_NODE) { + const val = node.nodeValue; + const parent = node.parentNode; + const pos = val.toLowerCase().indexOf(text); + if ( + pos >= 0 && + !parent.classList.contains(className) && + !parent.classList.contains("nohighlight") + ) { + let span; + + const closestNode = parent.closest("body, svg, foreignObject"); + const isInSVG = closestNode && closestNode.matches("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.classList.add(className); + } + + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + const rest = document.createTextNode(val.substr(pos + text.length)); + parent.insertBefore( + span, + parent.insertBefore( + rest, + node.nextSibling + ) + ); + node.nodeValue = val.substr(0, pos); + /* There may be more occurrences of search term in this node. So call this + * function recursively on the remaining fragment. + */ + _highlight(rest, addItems, text, className); + + if (isInSVG) { + const rect = document.createElementNS( + "http://www.w3.org/2000/svg", + "rect" + ); + const bbox = parent.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute("class", className); + addItems.push({ parent: parent, target: rect }); + } + } + } else if (node.matches && !node.matches("button, select, textarea")) { + node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); + } +}; +const _highlightText = (thisNode, text, className) => { + let addItems = []; + _highlight(thisNode, addItems, text, className); + addItems.forEach((obj) => + obj.parent.insertAdjacentElement("beforebegin", obj.target) + ); +}; + +/** + * Small JavaScript module for the documentation. + */ +const SphinxHighlight = { + + /** + * highlight the search words provided in localstorage in the text + */ + highlightSearchWords: () => { + if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight + + // get and clear terms from localstorage + const url = new URL(window.location); + const highlight = + localStorage.getItem("sphinx_highlight_terms") + || url.searchParams.get("highlight") + || ""; + localStorage.removeItem("sphinx_highlight_terms") + url.searchParams.delete("highlight"); + window.history.replaceState({}, "", url); + + // get individual terms from highlight string + const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); + if (terms.length === 0) return; // nothing to do + + // There should never be more than one element matching "div.body" + const divBody = document.querySelectorAll("div.body"); + const body = divBody.length ? divBody[0] : document.querySelector("body"); + window.setTimeout(() => { + terms.forEach((term) => _highlightText(body, term, "highlighted")); + }, 10); + + const searchBox = document.getElementById("searchbox"); + if (searchBox === null) return; + searchBox.appendChild( + document + .createRange() + .createContextualFragment( + '" + ) + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms") + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; + if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(() => { + /* Do not call highlightSearchWords() when we are on the search page. + * It will highlight words from the *previous* search query. + */ + if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords(); + SphinxHighlight.initEscapeListener(); +}); diff --git a/genindex.html b/genindex.html new file mode 100644 index 0000000..4d27c8f --- /dev/null +++ b/genindex.html @@ -0,0 +1,613 @@ + + + + + + + Index — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ + +

Index

+ +
+ A + | B + | C + | D + | E + | F + | H + | I + | L + | M + | P + | Q + | R + | S + | U + | V + | W + +
+

A

+ + + +
+ +

B

+ + + +
+ +

C

+ + + +
+ +

D

+ + + +
+ +

E

+ + + +
+ +

F

+ + + +
+ +

H

+ + +
+ +

I

+ + + +
+ +

L

+ + + +
+ +

M

+ + +
+ +

P

+ + + +
+ +

Q

+ + + +
    +
  • + qs_codec + +
  • +
  • + qs_codec.decode + +
  • +
  • + qs_codec.encode + +
  • +
  • + qs_codec.enums + +
  • +
  • + qs_codec.enums.charset + +
  • +
  • + qs_codec.enums.duplicates + +
  • +
  • + qs_codec.enums.format + +
  • +
  • + qs_codec.enums.list_format + +
  • +
  • + qs_codec.enums.sentinel + +
  • +
  • + qs_codec.models + +
  • +
    +
  • + qs_codec.models.decode_options + +
  • +
  • + qs_codec.models.encode_options + +
  • +
  • + qs_codec.models.undefined + +
  • +
  • + qs_codec.models.weak_wrapper + +
  • +
  • + qs_codec.utils + +
  • +
  • + qs_codec.utils.decode_utils + +
  • +
  • + qs_codec.utils.encode_utils + +
  • +
  • + qs_codec.utils.str_utils + +
  • +
  • + qs_codec.utils.utils + +
  • +
+ +

R

+ + + +
+ +

S

+ + + +
+ +

U

+ + + +
+ +

V

+ + +
+ +

W

+ + +
+ + + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..f1a4ad4 --- /dev/null +++ b/index.html @@ -0,0 +1,161 @@ + + + + + + + + qs-codec — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

qs-codec

+

A query string encoding and decoding library for Python.

+

Ported from qs for JavaScript.

+

PyPI - Version PyPI - Downloads PyPI - Status PyPI - Python Version PyPI - Format Black +Test CodeQL Publish Docs codecov Codacy Black flake8 mypy pylint isort Security Status +License Contributor Covenant GitHub Sponsors GitHub Repo stars

+
+

Usage

+

A simple usage example:

+
import qs_codec
+
+# Encoding
+assert qs_codec.encode({'a': 'b'}) == 'a=b'
+
+# Decoding
+assert qs_codec.decode('a=b') == {'a': 'b'}
+
+
+ +
+
+
+

Indices and tables

+ +
+

Special thanks to the authors of +qs for JavaScript: - Jordan +Harband - TJ +Holowaychuk

+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/modules.html b/modules.html new file mode 100644 index 0000000..3a588eb --- /dev/null +++ b/modules.html @@ -0,0 +1,164 @@ + + + + + + + + qs_codec — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/objects.inv b/objects.inv new file mode 100644 index 0000000000000000000000000000000000000000..eef91daddcd46aafb61b381c9fabb0712c67a5e0 GIT binary patch literal 1180 zcmV;N1Y`RnAX9K?X>NERX>N99Zgg*Qc_4OWa&u{KZXhxWBOp+6Z)#;@bUGk$b1h?U zWMyLtBOq2~a&u{KZaN?eBOp|0Wgv28ZDDC{WMy(7Z)PBLXlZjGW@&6?AZc?TV{dJ6 za%FRKWn>_Ab7^j8AbMZ z|Ix+c55ahJs8ApEJE)VJRJ72yt^KVit~(;2uWSy*K)U`Q7yD^T%te$r!AU zU#>s7U`fnvr=}2qucH0z5-c}qY{%Nqt}lxcA))oc8x(M_{tvc*b`ZFkPo_V@#ZzyVnlq+nvISjt zUN=>}PBvkh6}g{F6u2!fpK9=l%1v%xAV8F+?=VialeMbN0Usxs+`+=UJ&7?AVsCJ0 zI*|t{`whuGx~f#G3<-lZ`{8GZBW0zSdln+F&y7zgU{ov#rEr5- zObJ^LmZXm{oJ6rE3WUryigf`2ieon(&@IJ2R$jn&5i2{z*v86B;P$byTS^ftAy0D_ zL&eVgNU;w(o%s6D&==cD#J@z&Z$xt}V9Myur<`&jGM;9b%bhd!icoKBT%U)yXB#(~ z?%_wLIqn4rl|mp&{!>P(lA~cMW4C}U$;!CsNkby#zEtBfrmHPdMMQ>Ut8jjxfESb3 zJBq(!w1w{+Wm$EbFmymB2>etRKWnJfs7x3r_qG12&m}o`o={eupPjC*GCr4>Ds6n( zBTsZ>5PP7^Cv+$7I}n*OEFzQ*f>wTIt2q->IpjIqcvtKF~fh#h7`T3TOieRU#c6=ioc_}S;aG2yoqr+h*45dPjK08ysyyhAGFD7 zur@JaqN}1kT+eW1VE)2?-YM;{rkFj(l+$?U;cyiw3)rGHK7IkBtz&&i9~{3faSW-> u?b|3uXbw)!`Hwl;aoaGp2?WQ%y@Cjgc(iG1PnYR#3tj(QwEZ74MaWE5)GRFk literal 0 HcmV?d00001 diff --git a/py-modindex.html b/py-modindex.html new file mode 100644 index 0000000..fe84003 --- /dev/null +++ b/py-modindex.html @@ -0,0 +1,213 @@ + + + + + + + Python Module Index — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ + +

Python Module Index

+ +
+ q +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 
+ q
+ qs_codec +
    + qs_codec.decode +
    + qs_codec.encode +
    + qs_codec.enums +
    + qs_codec.enums.charset +
    + qs_codec.enums.duplicates +
    + qs_codec.enums.format +
    + qs_codec.enums.list_format +
    + qs_codec.enums.sentinel +
    + qs_codec.models +
    + qs_codec.models.decode_options +
    + qs_codec.models.encode_options +
    + qs_codec.models.undefined +
    + qs_codec.models.weak_wrapper +
    + qs_codec.utils +
    + qs_codec.utils.decode_utils +
    + qs_codec.utils.encode_utils +
    + qs_codec.utils.str_utils +
    + qs_codec.utils.utils +
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/qs_codec.enums.html b/qs_codec.enums.html new file mode 100644 index 0000000..6e59817 --- /dev/null +++ b/qs_codec.enums.html @@ -0,0 +1,313 @@ + + + + + + + + qs_codec.enums package — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

qs_codec.enums package

+
+

Submodules

+
+
+

qs_codec.enums.charset module

+

Charset enum module.

+
+
+class qs_codec.enums.charset.Charset(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)[source]
+

Bases: _CharsetDataMixin, Enum

+

Character set.

+
+
+LATIN1 = _CharsetDataMixin(encoding='iso-8859-1')
+

ISO-8859-1 (Latin-1) character encoding.

+
+ +
+
+UTF8 = _CharsetDataMixin(encoding='utf-8')
+

UTF-8 character encoding.

+
+ +
+ +
+
+

qs_codec.enums.duplicates module

+

This module contains an enum of all available duplicate key handling strategies.

+
+
+class qs_codec.enums.duplicates.Duplicates(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)[source]
+

Bases: Enum

+

An enum of all available duplicate key handling strategies.

+
+
+COMBINE = 1
+

Combine duplicate keys into a single key with an array of values.

+
+ +
+
+FIRST = 2
+

Use the first value for duplicate keys.

+
+ +
+
+LAST = 3
+

Use the last value for duplicate keys.

+
+ +
+ +
+
+

qs_codec.enums.format module

+

An enum of all supported URI component encoding formats.

+
+
+class qs_codec.enums.format.Format(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)[source]
+

Bases: _FormatDataMixin, Enum

+

An enum of all supported URI component encoding formats.

+
+
+RFC1738 = _FormatDataMixin(format_name='RFC1738', formatter=<function Formatter.rfc1738>)
+

RFC 1738.

+
+ +
+
+RFC3986 = _FormatDataMixin(format_name='RFC3986', formatter=<function Formatter.rfc3986>)
+

RFC 3986.

+
+ +
+ +
+
+class qs_codec.enums.format.Formatter[source]
+

Bases: object

+

A class for formatting URI components.

+
+
+static rfc1738(value: str) str[source]
+

Format a string according to RFC 1738.

+
+ +
+
+static rfc3986(value: str) str[source]
+

Format a string according to RFC 3986.

+
+ +
+ +
+
+

qs_codec.enums.list_format module

+

An enum for all available list format options.

+
+
+class qs_codec.enums.list_format.ListFormat(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)[source]
+

Bases: _ListFormatDataMixin, Enum

+

An enum of all available list format 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.enums.list_format.ListFormatGenerator[source]
+

Bases: object

+

A class for formatting list items.

+
+
+static brackets(prefix: str, key: str | None = None) str[source]
+

Format a list item using brackets.

+
+ +
+
+static comma(prefix: str, key: str | None = None) str[source]
+

Format a list item using commas.

+
+ +
+
+static indices(prefix: str, key: str | None = None) str[source]
+

Format a list item using indices.

+
+ +
+
+static repeat(prefix: str, key: str | None = None) str[source]
+

Format a list item using repeats.

+
+ +
+ +
+
+

qs_codec.enums.sentinel module

+

This module defines the Sentinel enum, which contains all available sentinel values.

+
+
+class qs_codec.enums.sentinel.Sentinel(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)[source]
+

Bases: _SentinelDataMixin, Enum

+

An enum of all available sentinel values.

+
+
+CHARSET = _SentinelDataMixin(raw='✓', encoded='utf8=%E2%9C%93')
+

These are the percent-encoded utf-8 octets representing a checkmark, indicating that the request actually is +utf-8 encoded.

+
+ +
+
+ISO = _SentinelDataMixin(raw='&#10003;', encoded='utf8=%26%2310003%3B')
+

This is what browsers will submit when the character occurs in an application/x-www-form-urlencoded +body and the encoding of the page containing the form is iso-8859-1, or when the submitted form has an +accept-charset attribute of iso-8859-1. Presumably also with other charsets that do not contain the +character, such as us-ascii.

+
+ +
+ +
+
+

Module contents

+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/qs_codec.html b/qs_codec.html new file mode 100644 index 0000000..b398e86 --- /dev/null +++ b/qs_codec.html @@ -0,0 +1,315 @@ + + + + + + + + qs_codec package — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

qs_codec package

+
+

Subpackages

+
+ +
+
+
+

Submodules

+
+
+

qs_codec.decode module

+

A query string decoder (parser).

+
+
+qs_codec.decode.decode(value: str | ~typing.Mapping | None, options: ~qs_codec.models.decode_options.DecodeOptions = DecodeOptions(allow_dots=False, decode_dot_in_keys=False, allow_empty_lists=False, list_limit=20, charset=<Charset.UTF8: encoding='utf-8'>, charset_sentinel=False, comma=False, delimiter='&', depth=5, parameter_limit=1000, duplicates=<Duplicates.COMBINE: 1>, ignore_query_prefix=False, interpret_numeric_entities=False, parse_lists=True, strict_null_handling=False, decoder=<bound method DecodeUtils.decode of <class 'qs_codec.utils.decode_utils.DecodeUtils'>>)) dict[source]
+

Decodes a str or Mapping into a dict.

+

Providing custom DecodeOptions will override the default behavior.

+
+ +
+
+

qs_codec.encode module

+

A query string encoder (stringifier).

+
+
+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, sort=None)) str[source]
+

Encodes Any object into a query str ing.

+

Providing custom EncodeOptions will override the default behavior.

+
+ +
+
+

Module contents

+

A query string encoding and decoding library for Python. Ported from qs_codec for JavaScript.

+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/qs_codec.models.html b/qs_codec.models.html new file mode 100644 index 0000000..758f0ed --- /dev/null +++ b/qs_codec.models.html @@ -0,0 +1,421 @@ + + + + + + + + qs_codec.models package — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

qs_codec.models package

+
+

Submodules

+
+
+

qs_codec.models.decode_options module

+

This module contains the DecodeOptions class that configures the output of decode.

+
+
+class qs_codec.models.decode_options.DecodeOptions(allow_dots: bool = None, decode_dot_in_keys: bool = 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_null_handling: bool = False, decoder: ~typing.Callable[[str | None, ~qs_codec.enums.charset.Charset | None], ~typing.Any] = <bound method DecodeUtils.decode of <class 'qs_codec.utils.decode_utils.DecodeUtils'>>)[source]
+

Bases: object

+

Options that configure the output of decode.

+
+
+allow_dots: bool = None
+

Set to True to decode dot dict notation in the encoded input.

+
+ +
+
+allow_empty_lists: bool = False
+

Set to True to allow empty list values 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-urlencoded body was not sent as utf-8, +e.g. if the form had an accept-charset parameter or the containing page had a different character set.

+

qs_codec supports this mechanism via the charset_sentinel option. +If specified, the utf-8 parameter will be omitted from the returned dict. +It will be used to switch to LATIN1 or UTF8 mode depending on how the checkmark is encoded.

+

Important: When you specify both the charset option and the charset_sentinel option, +the charset will be overridden when the request contains a utf-8 parameter from which the actual charset +can be deduced. In that sense the charset will behave as the default charset rather than the authoritative +charset.

+
+ +
+
+comma: bool = False
+

Set to True to parse the input as a comma-separated value. +Note: nested dict s, such as 'a={b:1},{c:d}' are not supported.

+
+ +
+
+decode_dot_in_keys: bool = None
+

Set to True to decode dots in keys. +Note: it implies allow_dots, so decode will error if you set decode_dot_in_keys to True, and +allow_dots to False.

+
+ +
+
+classmethod decoder(string: str | None, charset: Charset | None = Charset.UTF8) str | None
+

Set a Callable to affect the decoding of the input.

+
+ +
+
+delimiter: str | Pattern[str] = '&'
+

The delimiter to use when splitting key-value pairs in the encoded input. Can be a str or a Pattern.

+
+ +
+
+depth: int = 5
+

By default, when nesting dicts qs_codec will only decode up to 5 children deep. +This depth can be overridden by setting the depth. +The depth limit helps mitigate abuse when qs_codec is used to parse user input, +and it is recommended to keep it a reasonably small number.

+
+ +
+
+duplicates: Duplicates = 1
+

Change the duplicate key handling strategy.

+
+ +
+
+ignore_query_prefix: bool = False
+

Set to True to ignore the leading question mark query prefix in the encoded input.

+
+ +
+
+interpret_numeric_entities: bool = False
+

Set to True to interpret HTML numeric entities (&#...;) in the encoded input.

+
+ +
+
+list_limit: int = 20
+

qs_codec will limit specifying indices in a list to a maximum index of 20. +Any list members with an index of greater than 20 will instead be converted to a dict with the index as +the key. This is needed to handle cases when someone sent, for example, a[999999999] and it will take +significant time to iterate over this huge list. +This limit can be overridden by passing a list_limit option.

+
+ +
+
+parameter_limit: int | float = 1000
+

For similar reasons, by default qs_codec will only parse up to 1000 parameters. This can be overridden by +passing a parameter_limit option.

+
+ +
+
+parse_lists: bool = True
+

To disable list parsing entirely, set parse_lists to False.

+
+ +
+
+strict_null_handling: bool = False
+

Set to true to decode values without = to None.

+
+ +
+ +
+
+

qs_codec.models.encode_options module

+

This module contains the EncodeOptions class that configures the output of encode.

+
+
+class qs_codec.models.encode_options.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, sort: ~typing.Callable[[~typing.Any, ~typing.Any], int] | None = None)[source]
+

Bases: object

+

Options that configure the output of encode.

+
+
+add_query_prefix: bool = False
+

Set to True to add a question mark ? prefix to the encoded output.

+
+ +
+
+allow_dots: bool = None
+

Set to True to use dot dict notation in the encoded output.

+
+ +
+
+allow_empty_lists: bool = False
+

Set to True to allow empty list s in the encoded output.

+
+ +
+
+charset: Charset = _CharsetDataMixin(encoding='utf-8')
+

The character encoding to use.

+
+ +
+
+charset_sentinel: bool = False
+

Set to True to announce the character by including an utf8=✓ parameter with the proper encoding of the +checkmark, similar to what Ruby on Rails and others do when submitting forms.

+
+ +
+
+comma_round_trip: bool | None = None
+

When list_format is set to ListFormat.COMMA, you can also set comma_round_trip option to True or +False, to append [] on single-item lists, so that they can round trip through a parse.

+
+ +
+
+delimiter: str = '&'
+

The delimiter to use when joining key-value pairs in the encoded output.

+
+ +
+
+encode: bool = True
+

Set to False to disable encoding.

+
+ +
+
+encode_dot_in_keys: bool = None
+

Encode dict keys using dot notation by setting encode_dot_in_keys to True. +Caveat: When encode_values_only is True as well as encode_dot_in_keys, only dots in keys and nothing +else will be encoded.

+
+ +
+
+encode_values_only: bool = False
+

Encoding can be disabled for keys by setting the encode_values_only to True.

+
+ +
+
+property encoder: Callable[[Any, Charset | None, Format | None], str]
+

Set an Encoder to affect the encoding of values. +Note: the encoder option does not apply if encode is False.

+
+ +
+
+filter: Callable | List[str | int] | None = None
+

Use the filter option to restrict which keys will be included in the encoded output. +If you pass a Callable, it will be called for each key to obtain the replacement value. +If you pass a list, it will be used to select properties and list indices to be encoded.

+
+ +
+
+format: Format = _FormatDataMixin(format_name='RFC3986', formatter=<function Formatter.rfc3986>)
+

The encoding format to use. +The default format is Format.RFC3986 which encodes ' ' to %20 which is backward compatible. +You can also set format to Format.RFC1738 which encodes ' ' to +.

+
+ +
+
+indices: bool | None = None
+

Use list_format instead.

+
+
Type:
+

Deprecated

+
+
+
+ +
+
+list_format: ListFormat = _ListFormatDataMixin(list_format_name='INDICES', generator=<function ListFormatGenerator.indices>)
+

The list encoding format to use.

+
+ +
+
+serialize_date() str
+

If you only want to override the serialization of datetime objects, you can provide a Callable.

+
+ +
+
+skip_nulls: bool = False
+

Set to True to completely skip encoding keys with None values.

+
+ +
+
+sort: Callable[[Any, Any], int] | None = None
+

Set a Callable to affect the order of parameter keys.

+
+ +
+
+strict_null_handling: bool = False
+

Set to True to distinguish between null values and empty strings. This way the encoded string +None values will have no = sign.

+
+ +
+ +
+
+

qs_codec.models.undefined module

+

Undefined class definition.

+
+
+class qs_codec.models.undefined.Undefined[source]
+

Bases: object

+

Singleton class to represent undefined values.

+
+ +
+
+

qs_codec.models.weak_wrapper module

+

A wrapper that allows weak references to be used as dictionary keys.

+
+
+class qs_codec.models.weak_wrapper.WeakWrapper(value: Any)[source]
+

Bases: object

+

A wrapper that allows weak references to be used as dictionary keys.

+
+
+value: Any
+
+ +
+ +
+
+

Module contents

+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/qs_codec.utils.html b/qs_codec.utils.html new file mode 100644 index 0000000..d5c828d --- /dev/null +++ b/qs_codec.utils.html @@ -0,0 +1,240 @@ + + + + + + + + qs_codec.utils package — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +
+

qs_codec.utils package

+
+

Submodules

+
+
+

qs_codec.utils.decode_utils module

+

Decode utility methods used by the library.

+
+
+class qs_codec.utils.decode_utils.DecodeUtils[source]
+

Bases: object

+

A collection of decode utility methods used by the library.

+
+
+classmethod decode(string: str | None, charset: Charset | None = Charset.UTF8) str | None[source]
+

Decode a URL-encoded string.

+
+ +
+
+classmethod unescape(string: str) str[source]
+

A Python representation the deprecated JavaScript unescape function.

+

https://developer.mozilla.org/en-US/docs/web/javascript/reference/global_objects/unescape

+
+ +
+ +
+
+

qs_codec.utils.encode_utils module

+

A collection of encode utility methods used by the library.

+
+
+class qs_codec.utils.encode_utils.EncodeUtils[source]
+

Bases: object

+

A collection of encode utility methods used by the library.

+
+
+HEX_TABLE: Tuple[str, ...] = ('%00', '%01', '%02', '%03', '%04', '%05', '%06', '%07', '%08', '%09', '%0A', '%0B', '%0C', '%0D', '%0E', '%0F', '%10', '%11', '%12', '%13', '%14', '%15', '%16', '%17', '%18', '%19', '%1A', '%1B', '%1C', '%1D', '%1E', '%1F', '%20', '%21', '%22', '%23', '%24', '%25', '%26', '%27', '%28', '%29', '%2A', '%2B', '%2C', '%2D', '%2E', '%2F', '%30', '%31', '%32', '%33', '%34', '%35', '%36', '%37', '%38', '%39', '%3A', '%3B', '%3C', '%3D', '%3E', '%3F', '%40', '%41', '%42', '%43', '%44', '%45', '%46', '%47', '%48', '%49', '%4A', '%4B', '%4C', '%4D', '%4E', '%4F', '%50', '%51', '%52', '%53', '%54', '%55', '%56', '%57', '%58', '%59', '%5A', '%5B', '%5C', '%5D', '%5E', '%5F', '%60', '%61', '%62', '%63', '%64', '%65', '%66', '%67', '%68', '%69', '%6A', '%6B', '%6C', '%6D', '%6E', '%6F', '%70', '%71', '%72', '%73', '%74', '%75', '%76', '%77', '%78', '%79', '%7A', '%7B', '%7C', '%7D', '%7E', '%7F', '%80', '%81', '%82', '%83', '%84', '%85', '%86', '%87', '%88', '%89', '%8A', '%8B', '%8C', '%8D', '%8E', '%8F', '%90', '%91', '%92', '%93', '%94', '%95', '%96', '%97', '%98', '%99', '%9A', '%9B', '%9C', '%9D', '%9E', '%9F', '%A0', '%A1', '%A2', '%A3', '%A4', '%A5', '%A6', '%A7', '%A8', '%A9', '%AA', '%AB', '%AC', '%AD', '%AE', '%AF', '%B0', '%B1', '%B2', '%B3', '%B4', '%B5', '%B6', '%B7', '%B8', '%B9', '%BA', '%BB', '%BC', '%BD', '%BE', '%BF', '%C0', '%C1', '%C2', '%C3', '%C4', '%C5', '%C6', '%C7', '%C8', '%C9', '%CA', '%CB', '%CC', '%CD', '%CE', '%CF', '%D0', '%D1', '%D2', '%D3', '%D4', '%D5', '%D6', '%D7', '%D8', '%D9', '%DA', '%DB', '%DC', '%DD', '%DE', '%DF', '%E0', '%E1', '%E2', '%E3', '%E4', '%E5', '%E6', '%E7', '%E8', '%E9', '%EA', '%EB', '%EC', '%ED', '%EE', '%EF', '%F0', '%F1', '%F2', '%F3', '%F4', '%F5', '%F6', '%F7', '%F8', '%F9', '%FA', '%FB', '%FC', '%FD', '%FE', '%FF')
+

Hex table of all 256 characters

+
+ +
+
+classmethod encode(value: Any, charset: Charset | None = Charset.UTF8, format: Format | None = Format.RFC3986) str[source]
+

Encode a value to a URL-encoded string.

+
+ +
+
+classmethod escape(string: str, format: Format | None = Format.RFC3986) str[source]
+

A Python representation the deprecated JavaScript escape function.

+

https://developer.mozilla.org/en-US/docs/web/javascript/reference/global_objects/escape

+
+ +
+
+static serialize_date(dt: datetime) str[source]
+

Serialize a datetime object to an ISO 8601 string.

+
+ +
+ +
+
+

qs_codec.utils.str_utils module

+

Utility functions for working with strings.

+
+
+qs_codec.utils.str_utils.code_unit_at(string: str, index: int) int[source]
+

Returns the 16-bit UTF-16 code unit at the given index.

+

This function first encodes the string in UTF-16 little endian format, then calculates the code unit at the +given index. The code unit is calculated by taking the byte at the index and adding it to 256 times the next +byte. This is because UTF-16 represents each code unit with two bytes, and in little endian format, the least +significant byte comes first.

+

Adapted from https://api.dart.dev/stable/3.3.3/dart-core/String/codeUnitAt.html

+
+ +
+
+

qs_codec.utils.utils module

+

A collection of utility methods used by the library.

+
+
+class qs_codec.utils.utils.Utils[source]
+

Bases: object

+

A collection of utility methods used by the library.

+
+
+static apply(val: list | tuple | Any, fn: Callable) List | Any[source]
+

Apply a function to a value or a list of values.

+
+ +
+
+static combine(a: list | tuple | Any, b: list | tuple | Any) List[source]
+

Combine two lists or values.

+
+ +
+
+static compact(value: Dict) Dict[source]
+

Remove all Undefined values from a dictionary.

+
+ +
+
+static is_non_nullish_primitive(val: Any, skip_nulls: bool = False) bool[source]
+

Check if a value is a non-nullish primitive.

+
+ +
+
+static merge(target: ~typing.Mapping | ~typing.List | ~typing.Tuple | None, source: ~typing.Mapping | ~typing.List | ~typing.Tuple | ~typing.Any | None, options: ~qs_codec.models.decode_options.DecodeOptions = DecodeOptions(allow_dots=False, decode_dot_in_keys=False, allow_empty_lists=False, list_limit=20, charset=<Charset.UTF8: encoding='utf-8'>, charset_sentinel=False, comma=False, delimiter='&', depth=5, parameter_limit=1000, duplicates=<Duplicates.COMBINE: 1>, ignore_query_prefix=False, interpret_numeric_entities=False, parse_lists=True, strict_null_handling=False, decoder=<bound method DecodeUtils.decode of <class 'qs_codec.utils.decode_utils.DecodeUtils'>>)) Dict | List | Tuple | Any[source]
+

Merge two objects together.

+
+ +
+ +
+
+

Module contents

+
+
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/search.html b/search.html new file mode 100644 index 0000000..c35ec62 --- /dev/null +++ b/search.html @@ -0,0 +1,125 @@ + + + + + + + Search — qs-codec 0.2.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + +
+ +

Search

+ + + + +

+ Searching for multiple words only shows matches that contain + all words. +

+ + +
+ + + +
+ + +
+ + +
+ +
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/searchindex.js b/searchindex.js new file mode 100644 index 0000000..6942d88 --- /dev/null +++ b/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({"alltitles": {"Contents:": [[1, null]], "Dealing with special character sets": [[0, "dealing-with-special-character-sets"]], "Decoding": [[0, "decoding"]], "Encoding": [[0, "encoding"]], "Handling None values": [[0, "handling-none-values"]], "Indices and tables": [[1, "indices-and-tables"]], "Module contents": [[3, "module-qs_codec"], [4, "module-qs_codec.enums"], [5, "module-qs_codec.models"], [6, "module-qs_codec.utils"]], "RFC 3986 and RFC 1738 space encoding": [[0, "rfc-3986-and-rfc-1738-space-encoding"]], "Submodules": [[3, "submodules"], [4, "submodules"], [5, "submodules"], [6, "submodules"]], "Subpackages": [[3, "subpackages"]], "Usage": [[1, "usage"]], "dictionaries": [[0, "dictionaries"]], "lists": [[0, "lists"]], "primitive values (int, bool, None, etc.)": [[0, "primitive-values-int-bool-none-etc"]], "qs-codec": [[1, "qs-codec"]], "qs_codec": [[2, "qs-codec"]], "qs_codec package": [[3, "qs-codec-package"]], "qs_codec.decode module": [[3, "module-qs_codec.decode"]], "qs_codec.encode module": [[3, "module-qs_codec.encode"]], "qs_codec.enums package": [[4, "qs-codec-enums-package"]], "qs_codec.enums.charset module": [[4, "module-qs_codec.enums.charset"]], "qs_codec.enums.duplicates module": [[4, "module-qs_codec.enums.duplicates"]], "qs_codec.enums.format module": [[4, "module-qs_codec.enums.format"]], "qs_codec.enums.list_format module": [[4, "module-qs_codec.enums.list_format"]], "qs_codec.enums.sentinel module": [[4, "module-qs_codec.enums.sentinel"]], "qs_codec.models package": [[5, "qs-codec-models-package"]], "qs_codec.models.decode_options module": [[5, "module-qs_codec.models.decode_options"]], "qs_codec.models.encode_options module": [[5, "module-qs_codec.models.encode_options"]], "qs_codec.models.undefined module": [[5, "module-qs_codec.models.undefined"]], "qs_codec.models.weak_wrapper module": [[5, "module-qs_codec.models.weak_wrapper"]], "qs_codec.utils package": [[6, "qs-codec-utils-package"]], "qs_codec.utils.decode_utils module": [[6, "module-qs_codec.utils.decode_utils"]], "qs_codec.utils.encode_utils module": [[6, "module-qs_codec.utils.encode_utils"]], "qs_codec.utils.str_utils module": [[6, "module-qs_codec.utils.str_utils"]], "qs_codec.utils.utils module": [[6, "module-qs_codec.utils.utils"]]}, "docnames": ["README", "index", "modules", "qs_codec", "qs_codec.enums", "qs_codec.models", "qs_codec.utils"], "envversion": {"sphinx": 61, "sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.viewcode": 1}, "filenames": ["README.rst", "index.rst", "modules.rst", "qs_codec.rst", "qs_codec.enums.rst", "qs_codec.models.rst", "qs_codec.utils.rst"], "indexentries": {"add_query_prefix (qs_codec.models.encode_options.encodeoptions attribute)": [[5, "qs_codec.models.encode_options.EncodeOptions.add_query_prefix", false]], "allow_dots (qs_codec.models.decode_options.decodeoptions attribute)": [[5, "qs_codec.models.decode_options.DecodeOptions.allow_dots", false]], "allow_dots (qs_codec.models.encode_options.encodeoptions attribute)": [[5, "qs_codec.models.encode_options.EncodeOptions.allow_dots", false]], "allow_empty_lists (qs_codec.models.decode_options.decodeoptions attribute)": [[5, "qs_codec.models.decode_options.DecodeOptions.allow_empty_lists", false]], "allow_empty_lists (qs_codec.models.encode_options.encodeoptions attribute)": [[5, "qs_codec.models.encode_options.EncodeOptions.allow_empty_lists", false]], "apply() (qs_codec.utils.utils.utils static method)": [[6, "qs_codec.utils.utils.Utils.apply", false]], "brackets (qs_codec.enums.list_format.listformat attribute)": [[4, "qs_codec.enums.list_format.ListFormat.BRACKETS", false]], "brackets() (qs_codec.enums.list_format.listformatgenerator static method)": [[4, "qs_codec.enums.list_format.ListFormatGenerator.brackets", false]], "charset (class in qs_codec.enums.charset)": [[4, "qs_codec.enums.charset.Charset", false]], "charset (qs_codec.enums.sentinel.sentinel attribute)": [[4, "qs_codec.enums.sentinel.Sentinel.CHARSET", false]], "charset (qs_codec.models.decode_options.decodeoptions attribute)": [[5, "qs_codec.models.decode_options.DecodeOptions.charset", false]], "charset (qs_codec.models.encode_options.encodeoptions attribute)": [[5, "qs_codec.models.encode_options.EncodeOptions.charset", false]], "charset_sentinel (qs_codec.models.decode_options.decodeoptions attribute)": [[5, "qs_codec.models.decode_options.DecodeOptions.charset_sentinel", false]], "charset_sentinel (qs_codec.models.encode_options.encodeoptions attribute)": [[5, "qs_codec.models.encode_options.EncodeOptions.charset_sentinel", false]], "code_unit_at() (in module qs_codec.utils.str_utils)": [[6, "qs_codec.utils.str_utils.code_unit_at", false]], "combine (qs_codec.enums.duplicates.duplicates attribute)": [[4, "qs_codec.enums.duplicates.Duplicates.COMBINE", false]], "combine() (qs_codec.utils.utils.utils static method)": [[6, "qs_codec.utils.utils.Utils.combine", false]], "comma (qs_codec.enums.list_format.listformat attribute)": [[4, "qs_codec.enums.list_format.ListFormat.COMMA", false]], "comma (qs_codec.models.decode_options.decodeoptions attribute)": [[5, "qs_codec.models.decode_options.DecodeOptions.comma", false]], "comma() (qs_codec.enums.list_format.listformatgenerator static method)": [[4, "qs_codec.enums.list_format.ListFormatGenerator.comma", false]], "comma_round_trip (qs_codec.models.encode_options.encodeoptions attribute)": [[5, "qs_codec.models.encode_options.EncodeOptions.comma_round_trip", false]], "compact() (qs_codec.utils.utils.utils static method)": [[6, "qs_codec.utils.utils.Utils.compact", false]], "decode() (in module qs_codec.decode)": [[3, "qs_codec.decode.decode", false]], "decode() (qs_codec.utils.decode_utils.decodeutils class method)": [[6, "qs_codec.utils.decode_utils.DecodeUtils.decode", false]], "decode_dot_in_keys (qs_codec.models.decode_options.decodeoptions attribute)": [[5, "qs_codec.models.decode_options.DecodeOptions.decode_dot_in_keys", false]], "decodeoptions (class in qs_codec.models.decode_options)": [[5, "qs_codec.models.decode_options.DecodeOptions", false]], "decoder() (qs_codec.models.decode_options.decodeoptions class method)": [[5, "qs_codec.models.decode_options.DecodeOptions.decoder", false]], "decodeutils (class in qs_codec.utils.decode_utils)": [[6, "qs_codec.utils.decode_utils.DecodeUtils", false]], "delimiter (qs_codec.models.decode_options.decodeoptions attribute)": [[5, "qs_codec.models.decode_options.DecodeOptions.delimiter", false]], "delimiter (qs_codec.models.encode_options.encodeoptions attribute)": [[5, "qs_codec.models.encode_options.EncodeOptions.delimiter", false]], "depth (qs_codec.models.decode_options.decodeoptions attribute)": [[5, "qs_codec.models.decode_options.DecodeOptions.depth", false]], "duplicates (class in qs_codec.enums.duplicates)": [[4, "qs_codec.enums.duplicates.Duplicates", false]], "duplicates (qs_codec.models.decode_options.decodeoptions attribute)": [[5, "qs_codec.models.decode_options.DecodeOptions.duplicates", false]], "encode (qs_codec.models.encode_options.encodeoptions attribute)": [[5, "qs_codec.models.encode_options.EncodeOptions.encode", false]], "encode() (in module qs_codec.encode)": [[3, "qs_codec.encode.encode", false]], "encode() (qs_codec.utils.encode_utils.encodeutils class method)": [[6, "qs_codec.utils.encode_utils.EncodeUtils.encode", false]], "encode_dot_in_keys (qs_codec.models.encode_options.encodeoptions attribute)": [[5, "qs_codec.models.encode_options.EncodeOptions.encode_dot_in_keys", false]], "encode_values_only (qs_codec.models.encode_options.encodeoptions attribute)": [[5, "qs_codec.models.encode_options.EncodeOptions.encode_values_only", false]], "encodeoptions (class in qs_codec.models.encode_options)": [[5, "qs_codec.models.encode_options.EncodeOptions", false]], "encoder (qs_codec.models.encode_options.encodeoptions property)": [[5, "qs_codec.models.encode_options.EncodeOptions.encoder", false]], "encodeutils (class in qs_codec.utils.encode_utils)": [[6, "qs_codec.utils.encode_utils.EncodeUtils", false]], "escape() (qs_codec.utils.encode_utils.encodeutils class method)": [[6, "qs_codec.utils.encode_utils.EncodeUtils.escape", false]], "filter (qs_codec.models.encode_options.encodeoptions attribute)": [[5, "qs_codec.models.encode_options.EncodeOptions.filter", false]], "first (qs_codec.enums.duplicates.duplicates attribute)": [[4, "qs_codec.enums.duplicates.Duplicates.FIRST", false]], "format (class in qs_codec.enums.format)": [[4, "qs_codec.enums.format.Format", false]], "format (qs_codec.models.encode_options.encodeoptions attribute)": [[5, "qs_codec.models.encode_options.EncodeOptions.format", false]], "formatter (class in qs_codec.enums.format)": [[4, "qs_codec.enums.format.Formatter", false]], "hex_table (qs_codec.utils.encode_utils.encodeutils attribute)": [[6, "qs_codec.utils.encode_utils.EncodeUtils.HEX_TABLE", false]], "ignore_query_prefix (qs_codec.models.decode_options.decodeoptions attribute)": [[5, "qs_codec.models.decode_options.DecodeOptions.ignore_query_prefix", false]], "indices (qs_codec.enums.list_format.listformat attribute)": [[4, "qs_codec.enums.list_format.ListFormat.INDICES", false]], "indices (qs_codec.models.encode_options.encodeoptions attribute)": [[5, "qs_codec.models.encode_options.EncodeOptions.indices", false]], "indices() (qs_codec.enums.list_format.listformatgenerator static method)": [[4, "qs_codec.enums.list_format.ListFormatGenerator.indices", false]], "interpret_numeric_entities (qs_codec.models.decode_options.decodeoptions attribute)": [[5, "qs_codec.models.decode_options.DecodeOptions.interpret_numeric_entities", false]], "is_non_nullish_primitive() (qs_codec.utils.utils.utils static method)": [[6, "qs_codec.utils.utils.Utils.is_non_nullish_primitive", false]], "iso (qs_codec.enums.sentinel.sentinel attribute)": [[4, "qs_codec.enums.sentinel.Sentinel.ISO", false]], "last (qs_codec.enums.duplicates.duplicates attribute)": [[4, "qs_codec.enums.duplicates.Duplicates.LAST", false]], "latin1 (qs_codec.enums.charset.charset attribute)": [[4, "qs_codec.enums.charset.Charset.LATIN1", false]], "list_format (qs_codec.models.encode_options.encodeoptions attribute)": [[5, "qs_codec.models.encode_options.EncodeOptions.list_format", false]], "list_limit (qs_codec.models.decode_options.decodeoptions attribute)": [[5, "qs_codec.models.decode_options.DecodeOptions.list_limit", false]], "listformat (class in qs_codec.enums.list_format)": [[4, "qs_codec.enums.list_format.ListFormat", false]], "listformatgenerator (class in qs_codec.enums.list_format)": [[4, "qs_codec.enums.list_format.ListFormatGenerator", false]], "merge() (qs_codec.utils.utils.utils static method)": [[6, "qs_codec.utils.utils.Utils.merge", false]], "module": [[3, "module-qs_codec", false], [3, "module-qs_codec.decode", false], [3, "module-qs_codec.encode", false], [4, "module-qs_codec.enums", false], [4, "module-qs_codec.enums.charset", false], [4, "module-qs_codec.enums.duplicates", false], [4, "module-qs_codec.enums.format", false], [4, "module-qs_codec.enums.list_format", false], [4, "module-qs_codec.enums.sentinel", false], [5, "module-qs_codec.models", false], [5, "module-qs_codec.models.decode_options", false], [5, "module-qs_codec.models.encode_options", false], [5, "module-qs_codec.models.undefined", false], [5, "module-qs_codec.models.weak_wrapper", false], [6, "module-qs_codec.utils", false], [6, "module-qs_codec.utils.decode_utils", false], [6, "module-qs_codec.utils.encode_utils", false], [6, "module-qs_codec.utils.str_utils", false], [6, "module-qs_codec.utils.utils", false]], "parameter_limit (qs_codec.models.decode_options.decodeoptions attribute)": [[5, "qs_codec.models.decode_options.DecodeOptions.parameter_limit", false]], "parse_lists (qs_codec.models.decode_options.decodeoptions attribute)": [[5, "qs_codec.models.decode_options.DecodeOptions.parse_lists", false]], "qs_codec": [[3, "module-qs_codec", false]], "qs_codec.decode": [[3, "module-qs_codec.decode", false]], "qs_codec.encode": [[3, "module-qs_codec.encode", false]], "qs_codec.enums": [[4, "module-qs_codec.enums", false]], "qs_codec.enums.charset": [[4, "module-qs_codec.enums.charset", false]], "qs_codec.enums.duplicates": [[4, "module-qs_codec.enums.duplicates", false]], "qs_codec.enums.format": [[4, "module-qs_codec.enums.format", false]], "qs_codec.enums.list_format": [[4, "module-qs_codec.enums.list_format", false]], "qs_codec.enums.sentinel": [[4, "module-qs_codec.enums.sentinel", false]], "qs_codec.models": [[5, "module-qs_codec.models", false]], "qs_codec.models.decode_options": [[5, "module-qs_codec.models.decode_options", false]], "qs_codec.models.encode_options": [[5, "module-qs_codec.models.encode_options", false]], "qs_codec.models.undefined": [[5, "module-qs_codec.models.undefined", false]], "qs_codec.models.weak_wrapper": [[5, "module-qs_codec.models.weak_wrapper", false]], "qs_codec.utils": [[6, "module-qs_codec.utils", false]], "qs_codec.utils.decode_utils": [[6, "module-qs_codec.utils.decode_utils", false]], "qs_codec.utils.encode_utils": [[6, "module-qs_codec.utils.encode_utils", false]], "qs_codec.utils.str_utils": [[6, "module-qs_codec.utils.str_utils", false]], "qs_codec.utils.utils": [[6, "module-qs_codec.utils.utils", false]], "repeat (qs_codec.enums.list_format.listformat attribute)": [[4, "qs_codec.enums.list_format.ListFormat.REPEAT", false]], "repeat() (qs_codec.enums.list_format.listformatgenerator static method)": [[4, "qs_codec.enums.list_format.ListFormatGenerator.repeat", false]], "rfc1738 (qs_codec.enums.format.format attribute)": [[4, "qs_codec.enums.format.Format.RFC1738", false]], "rfc1738() (qs_codec.enums.format.formatter static method)": [[4, "qs_codec.enums.format.Formatter.rfc1738", false]], "rfc3986 (qs_codec.enums.format.format attribute)": [[4, "qs_codec.enums.format.Format.RFC3986", false]], "rfc3986() (qs_codec.enums.format.formatter static method)": [[4, "qs_codec.enums.format.Formatter.rfc3986", false]], "sentinel (class in qs_codec.enums.sentinel)": [[4, "qs_codec.enums.sentinel.Sentinel", false]], "serialize_date() (qs_codec.models.encode_options.encodeoptions method)": [[5, "qs_codec.models.encode_options.EncodeOptions.serialize_date", false]], "serialize_date() (qs_codec.utils.encode_utils.encodeutils static method)": [[6, "qs_codec.utils.encode_utils.EncodeUtils.serialize_date", false]], "skip_nulls (qs_codec.models.encode_options.encodeoptions attribute)": [[5, "qs_codec.models.encode_options.EncodeOptions.skip_nulls", false]], "sort (qs_codec.models.encode_options.encodeoptions attribute)": [[5, "qs_codec.models.encode_options.EncodeOptions.sort", false]], "strict_null_handling (qs_codec.models.decode_options.decodeoptions attribute)": [[5, "qs_codec.models.decode_options.DecodeOptions.strict_null_handling", false]], "strict_null_handling (qs_codec.models.encode_options.encodeoptions attribute)": [[5, "qs_codec.models.encode_options.EncodeOptions.strict_null_handling", false]], "undefined (class in qs_codec.models.undefined)": [[5, "qs_codec.models.undefined.Undefined", false]], "unescape() (qs_codec.utils.decode_utils.decodeutils class method)": [[6, "qs_codec.utils.decode_utils.DecodeUtils.unescape", false]], "utf8 (qs_codec.enums.charset.charset attribute)": [[4, "qs_codec.enums.charset.Charset.UTF8", false]], "utils (class in qs_codec.utils.utils)": [[6, "qs_codec.utils.utils.Utils", false]], "value (qs_codec.models.weak_wrapper.weakwrapper attribute)": [[5, "qs_codec.models.weak_wrapper.WeakWrapper.value", false]], "weakwrapper (class in qs_codec.models.weak_wrapper)": [[5, "qs_codec.models.weak_wrapper.WeakWrapper", false]]}, "objects": {"": [[3, 0, 0, "-", "qs_codec"]], "qs_codec": [[3, 0, 0, "-", "decode"], [3, 0, 0, "-", "encode"], [4, 0, 0, "-", "enums"], [5, 0, 0, "-", "models"], [6, 0, 0, "-", "utils"]], "qs_codec.decode": [[3, 1, 1, "", "decode"]], "qs_codec.encode": [[3, 1, 1, "", "encode"]], "qs_codec.enums": [[4, 0, 0, "-", "charset"], [4, 0, 0, "-", "duplicates"], [4, 0, 0, "-", "format"], [4, 0, 0, "-", "list_format"], [4, 0, 0, "-", "sentinel"]], "qs_codec.enums.charset": [[4, 2, 1, "", "Charset"]], "qs_codec.enums.charset.Charset": [[4, 3, 1, "", "LATIN1"], [4, 3, 1, "", "UTF8"]], "qs_codec.enums.duplicates": [[4, 2, 1, "", "Duplicates"]], "qs_codec.enums.duplicates.Duplicates": [[4, 3, 1, "", "COMBINE"], [4, 3, 1, "", "FIRST"], [4, 3, 1, "", "LAST"]], "qs_codec.enums.format": [[4, 2, 1, "", "Format"], [4, 2, 1, "", "Formatter"]], "qs_codec.enums.format.Format": [[4, 3, 1, "", "RFC1738"], [4, 3, 1, "", "RFC3986"]], "qs_codec.enums.format.Formatter": [[4, 4, 1, "", "rfc1738"], [4, 4, 1, "", "rfc3986"]], "qs_codec.enums.list_format": [[4, 2, 1, "", "ListFormat"], [4, 2, 1, "", "ListFormatGenerator"]], "qs_codec.enums.list_format.ListFormat": [[4, 3, 1, "", "BRACKETS"], [4, 3, 1, "", "COMMA"], [4, 3, 1, "", "INDICES"], [4, 3, 1, "", "REPEAT"]], "qs_codec.enums.list_format.ListFormatGenerator": [[4, 4, 1, "", "brackets"], [4, 4, 1, "", "comma"], [4, 4, 1, "", "indices"], [4, 4, 1, "", "repeat"]], "qs_codec.enums.sentinel": [[4, 2, 1, "", "Sentinel"]], "qs_codec.enums.sentinel.Sentinel": [[4, 3, 1, "", "CHARSET"], [4, 3, 1, "", "ISO"]], "qs_codec.models": [[5, 0, 0, "-", "decode_options"], [5, 0, 0, "-", "encode_options"], [5, 0, 0, "-", "undefined"], [5, 0, 0, "-", "weak_wrapper"]], "qs_codec.models.decode_options": [[5, 2, 1, "", "DecodeOptions"]], "qs_codec.models.decode_options.DecodeOptions": [[5, 3, 1, "", "allow_dots"], [5, 3, 1, "", "allow_empty_lists"], [5, 3, 1, "", "charset"], [5, 3, 1, "", "charset_sentinel"], [5, 3, 1, "", "comma"], [5, 3, 1, "", "decode_dot_in_keys"], [5, 4, 1, "", "decoder"], [5, 3, 1, "", "delimiter"], [5, 3, 1, "", "depth"], [5, 3, 1, "", "duplicates"], [5, 3, 1, "", "ignore_query_prefix"], [5, 3, 1, "", "interpret_numeric_entities"], [5, 3, 1, "", "list_limit"], [5, 3, 1, "", "parameter_limit"], [5, 3, 1, "", "parse_lists"], [5, 3, 1, "", "strict_null_handling"]], "qs_codec.models.encode_options": [[5, 2, 1, "", "EncodeOptions"]], "qs_codec.models.encode_options.EncodeOptions": [[5, 3, 1, "", "add_query_prefix"], [5, 3, 1, "", "allow_dots"], [5, 3, 1, "", "allow_empty_lists"], [5, 3, 1, "", "charset"], [5, 3, 1, "", "charset_sentinel"], [5, 3, 1, "", "comma_round_trip"], [5, 3, 1, "", "delimiter"], [5, 3, 1, "", "encode"], [5, 3, 1, "", "encode_dot_in_keys"], [5, 3, 1, "", "encode_values_only"], [5, 5, 1, "", "encoder"], [5, 3, 1, "", "filter"], [5, 3, 1, "", "format"], [5, 3, 1, "", "indices"], [5, 3, 1, "", "list_format"], [5, 4, 1, "", "serialize_date"], [5, 3, 1, "", "skip_nulls"], [5, 3, 1, "", "sort"], [5, 3, 1, "", "strict_null_handling"]], "qs_codec.models.undefined": [[5, 2, 1, "", "Undefined"]], "qs_codec.models.weak_wrapper": [[5, 2, 1, "", "WeakWrapper"]], "qs_codec.models.weak_wrapper.WeakWrapper": [[5, 3, 1, "", "value"]], "qs_codec.utils": [[6, 0, 0, "-", "decode_utils"], [6, 0, 0, "-", "encode_utils"], [6, 0, 0, "-", "str_utils"], [6, 0, 0, "-", "utils"]], "qs_codec.utils.decode_utils": [[6, 2, 1, "", "DecodeUtils"]], "qs_codec.utils.decode_utils.DecodeUtils": [[6, 4, 1, "", "decode"], [6, 4, 1, "", "unescape"]], "qs_codec.utils.encode_utils": [[6, 2, 1, "", "EncodeUtils"]], "qs_codec.utils.encode_utils.EncodeUtils": [[6, 3, 1, "", "HEX_TABLE"], [6, 4, 1, "", "encode"], [6, 4, 1, "", "escape"], [6, 4, 1, "", "serialize_date"]], "qs_codec.utils.str_utils": [[6, 1, 1, "", "code_unit_at"]], "qs_codec.utils.utils": [[6, 2, 1, "", "Utils"]], "qs_codec.utils.utils.Utils": [[6, 4, 1, "", "apply"], [6, 4, 1, "", "combine"], [6, 4, 1, "", "compact"], [6, 4, 1, "", "is_non_nullish_primitive"], [6, 4, 1, "", "merge"]]}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "function", "Python function"], "2": ["py", "class", "Python class"], "3": ["py", "attribute", "Python attribute"], "4": ["py", "method", "Python method"], "5": ["py", "property", "Python property"]}, "objtypes": {"0": "py:module", "1": "py:function", "2": "py:class", "3": "py:attribute", "4": "py:method", "5": "py:property"}, "terms": {"": [0, 5], "0": [0, 4], "00": [0, 6], "01": [0, 6], "01t00": 0, "02": 6, "02x": 0, "03": 6, "04": 6, "05": 6, "06": 6, "07": [0, 6], "08": 6, "09": 6, "0a": 6, "0b": 6, "0c": 6, "0d": 6, "0e": 6, "0f": 6, "1": [0, 3, 4, 5, 6], "10": 6, "100": 0, "1000": [0, 3, 5, 6], "10003": 4, "11": [0, 6], "12": 6, "123": [0, 4], "13": 6, "14": 6, "15": [0, 6], "16": [0, 6], "17": 6, "1738": [1, 4], "18": 6, "19": 6, "1970": 0, "1a": 6, "1b": 6, "1c": 6, "1d": 6, "1e": 6, "1f": 6, "2": [0, 4], "20": [0, 3, 5, 6], "20c": 0, "21": 6, "22": 6, "23": 6, "2310003": [0, 4], "239786": 0, "24": 6, "25": 6, "252eobj": 0, "256": 6, "26": [0, 4, 6], "27": 6, "28": 6, "29": 6, "2a": 6, "2b": 6, "2c": 6, "2d": 6, "2e": 6, "2f": 6, "3": [0, 4, 6], "30": 6, "31": 6, "32": 6, "33": 6, "34": 6, "35": 6, "36": 6, "37": 6, "38": 6, "39": 6, "3986": [1, 4], "3a": 6, "3b": [0, 4, 6], "3c": 6, "3d": 6, "3df": 0, "3e": 6, "3f": 6, "4": 0, "40": 6, "41": 6, "42": 6, "43": 6, "44": 6, "45": 6, "456": 4, "46": 6, "47": 6, "48": 6, "49": [0, 6], "4a": 6, "4b": 6, "4c": 6, "4d": 6, "4e": 6, "4f": 6, "5": [0, 3, 5, 6], "50": 6, "51": 6, "52": 6, "53": 6, "54": 6, "55": 6, "56": 6, "57": 6, "58": 6, "59": 6, "5a": 6, "5b": 6, "5bb": 0, "5c": 6, "5d": [0, 6], "5e": 6, "5f": 6, "60": 6, "61": [0, 6], "62": 6, "63": 6, "64": 6, "65": 6, "66": 6, "67": 6, "68": 6, "69": 6, "6a": 6, "6b": 6, "6c": 6, "6d": 6, "6e": 6, "6f": 6, "7": 0, "70": 6, "71": 6, "72": 6, "73": 6, "74": 6, "75": 6, "76": 6, "77": 6, "78": 6, "789": 4, "79": 6, "7a": 6, "7b": 6, "7c": 6, "7d": 6, "7e": 6, "7f": 6, "8": [0, 3, 4, 5, 6], "80": 6, "81": [0, 6], "82": [0, 6], "83": 6, "84": 6, "85": 6, "86": 6, "8601": [0, 6], "87": 6, "88": 6, "8859": 4, "89": 6, "8a": 6, "8b": 6, "8c": 6, "8d": 6, "8e": 6, "8f": 6, "90": 6, "91": 6, "92": 6, "93": [0, 4, 6], "94": 6, "95": 6, "96": 6, "97": 6, "98": [0, 6], "99": 6, "999999999": [0, 5], "9a": [0, 6], "9b": 6, "9c": [0, 4, 6], "9d": 6, "9e": 6, "9f": 6, "A": [1, 3, 4, 5, 6], "BE": 6, "By": [0, 5], "For": [0, 5], "If": [0, 5], "In": [0, 5], "It": [0, 5], "The": [0, 5, 6], "These": 4, "To": [0, 5], "_charsetdatamixin": [4, 5], "_formatdatamixin": [4, 5], "_listformatdatamixin": [4, 5], "_sentineldatamixin": 4, "a0": 6, "a1": 6, "a2": 6, "a3": 6, "a4": 6, "a5": 6, "a6": 6, "a7": [0, 6], "a8": 6, "a9": 6, "aa": 6, "ab": 6, "abus": [0, 5], "ac": 6, "accept": [0, 4, 5], "accord": 4, "actual": [0, 4, 5], "ad": 6, "adapt": 6, "add": [0, 5], "add_query_prefix": [0, 3, 5], "addition": [0, 5], "ae": 6, "af": 6, "affect": [0, 5], "against": [0, 5], "all": [0, 4, 6], "allow": [0, 5], "allow_dot": [0, 3, 5, 6], "allow_empty_list": [0, 3, 5, 6], "also": [0, 4, 5], "an": [0, 4, 5, 6], "ani": [0, 3, 5, 6], "announc": [0, 5], "api": 6, "append": [0, 5], "appli": [0, 3, 5, 6], "applic": [0, 4, 5], "ar": [0, 4, 5], "arrai": 4, "ascii": 4, "assert": [0, 1], "attempt": 0, "attribut": 4, "author": 1, "authorit": [0, 5], "avail": 4, "b": [0, 1, 5, 6], "b0": 6, "b1": [0, 6], "b2": 6, "b3": 6, "b4": 6, "b5": 6, "b6": 6, "b7": 6, "b8": [0, 6], "b9": 6, "ba": [0, 6], "back": 0, "backward": [0, 5], "bar": 0, "base": [4, 5, 6], "baz": 0, "bb": 6, "bc": 6, "bd": 6, "becaus": 6, "been": 0, "behav": [0, 5], "behavior": [0, 3], "between": [0, 5], "beyond": 0, "bf": [0, 6], "bit": 6, "bodi": [0, 4, 5], "bool": [1, 5, 6], "both": [0, 5], "bound": [3, 5, 6], "boundari": 4, "bracket": [0, 3, 4], "break": 0, "browser": [0, 4], "buf": 0, "built": 0, "bypass": 0, "byte": [0, 6], "c": [0, 5], "c0": 6, "c1": 6, "c2": 6, "c3": [0, 6], "c4": 6, "c5": 6, "c6": 6, "c7": 6, "c8": 6, "c9": [0, 6], "ca": 6, "calcul": 6, "call": [0, 5], "callabl": [0, 5, 6], "can": [0, 5], "cannot": 0, "case": [0, 5], "caveat": [0, 5], "cb": 6, "cc": 6, "cd": [0, 6], "ce": 6, "cf": 6, "chang": [0, 5], "charact": [1, 4, 5, 6], "charset": [0, 2, 3, 5, 6], "charset_sentinel": [0, 3, 5, 6], "check": [0, 5, 6], "checkmark": [0, 4, 5], "children": [0, 5], "clariti": 0, "class": [3, 4, 5, 6], "classmethod": [5, 6], "code": 6, "code_unit_at": [3, 6], "codec": 0, "codeunitat": 6, "collect": 6, "combin": [0, 3, 4, 5, 6], "come": 6, "comma": [0, 3, 4, 5, 6], "comma_round_trip": [0, 3, 5], "commun": 0, "compact": [0, 3, 6], "compat": [0, 5], "compil": 0, "complet": [0, 5], "compon": 4, "configur": 5, "contain": [0, 4, 5], "content": 2, "convert": [0, 5], "core": 6, "creat": 0, "custom": [0, 3], "custom_decod": 0, "custom_encod": 0, "d": [0, 5], "d0": 6, "d1": 6, "d2": 6, "d3": 6, "d4": 6, "d5": 6, "d6": 6, "d7": 6, "d8": 6, "d9": 6, "da": 6, "dart": 6, "date": 0, "datetim": [0, 5, 6], "db": 6, "dc": 6, "dd": 6, "de": 6, "deal": 1, "decod": [1, 2, 5, 6], "decode_dot_in_kei": [0, 3, 5, 6], "decode_opt": [2, 3, 6], "decode_util": [2, 3, 5], "decodeopt": [0, 3, 5, 6], "decodeutil": [3, 5, 6], "deduc": [0, 5], "deep": [0, 5], "def": 0, "default": [0, 3, 5], "defin": 4, "definit": 5, "delimit": [0, 3, 5, 6], "depend": [0, 5], "deprec": [5, 6], "depth": [0, 3, 5, 6], "detect": [0, 5], "dev": 6, "develop": 6, "df": 6, "dict": [0, 3, 5, 6], "dictionari": [1, 5, 6], "differ": [0, 5], "disabl": [0, 5], "distinguish": [0, 5], "do": [0, 4, 5], "doc": 6, "doe": [0, 5], "don": 0, "done": 0, "dot": [0, 5], "dt": 6, "duplic": [0, 2, 3, 5, 6], "dure": 0, "e": [0, 5], "e0": 6, "e1": 6, "e2": [0, 4, 6], "e3": 6, "e4": 6, "e5": 6, "e6": [0, 6], "e7": 6, "e8": 6, "e9": 6, "ea": 6, "each": [0, 5, 6], "eb": 6, "ec": 6, "ed": 6, "ee": 6, "ef": 6, "els": [0, 5], "empti": [0, 5], "en": 6, "enabl": 0, "encod": [1, 2, 4, 5, 6], "encode_dot_in_kei": [0, 3, 5], "encode_opt": [2, 3], "encode_util": [2, 3], "encode_values_onli": [0, 3, 5], "encodeopt": [0, 3, 5], "encodeutil": [3, 5, 6], "encount": 0, "end": 0, "endian": 6, "entir": [0, 5], "entiti": [0, 5], "enum": [2, 3, 5], "equal": 0, "error": [0, 5], "escap": [3, 6], "etc": 1, "exampl": [0, 1, 4, 5], "except": 0, "exist": 0, "expect": 0, "explicit": 0, "explor": 0, "express": 0, "f": 0, "f0": 6, "f1": [0, 6], "f2": 6, "f3": 6, "f4": 6, "f5": 6, "f6": 6, "f7": 6, "f8": [0, 6], "f9": 6, "fa": 6, "fals": [0, 3, 5, 6], "fb": 6, "fc": 6, "fd": 6, "fe": 6, "ff": 6, "filter": [0, 3, 5], "final": 0, "first": [0, 3, 4, 6], "flag": 0, "float": 5, "fn": 6, "follow": 0, "foo": [0, 4], "foobarbaz": 0, "form": [0, 4, 5], "format": [0, 2, 3, 5, 6], "format_nam": [3, 4, 5], "formatt": [3, 4, 5], "from": [0, 1, 3, 5, 6], "fromtimestamp": 0, "function": [3, 4, 5, 6], "g": [0, 5], "gener": [3, 4, 5], "get": 0, "given": [4, 6], "global_object": 6, "greater": [0, 5], "group": 0, "h": 0, "ha": [0, 4], "had": [0, 5], "handl": [1, 4, 5], "harband": 1, "have": [0, 5], "help": [0, 5], "hex": 6, "hex_tabl": [3, 6], "holowaychuk": 1, "how": [0, 5], "html": [5, 6], "http": 6, "huge": [0, 5], "i": [0, 4, 5, 6], "ignor": 5, "ignore_query_prefix": [0, 3, 5, 6], "ignorecas": 0, "impli": [0, 5], "import": [0, 1, 5], "includ": [0, 5], "index": [0, 1, 5, 6], "indic": [0, 3, 4, 5], "ing": [0, 3, 5], "initi": [0, 5], "input": [0, 5], "insid": 5, "instead": [0, 5], "int": [1, 5, 6], "internet": 0, "internetexplor": 5, "interpret": 5, "interpret_numeric_ent": [0, 3, 5, 6], "is_non_nullish_primit": [3, 6], "isinst": 0, "iso": [0, 3, 4, 6], "item": [0, 4, 5], "iter": [0, 5], "j": 0, "javascript": [1, 3, 6], "ji": 0, "john": 0, "join": [0, 5], "jordan": 1, "keep": [0, 5], "kei": [0, 4, 5], "lambda": [0, 3], "last": [0, 3, 4], "latin": 4, "latin1": [0, 3, 4, 5], "lead": [0, 5], "least": 6, "legaci": 0, "librari": [1, 3, 6], "like": [0, 5], "limit": [0, 5], "list": [1, 4, 5, 6], "list_format": [0, 2, 3, 5], "list_format_nam": [3, 4, 5], "list_limit": [0, 3, 5, 6], "listformat": [0, 3, 4, 5], "listformatgener": [3, 4, 5], "littl": 6, "local": 3, "mai": 0, "major": 0, "map": [0, 3, 6], "mark": [0, 5], "match": 0, "maximum": [0, 5], "mean": 0, "mechan": [0, 5], "member": [0, 5], "merg": [0, 3, 6], "method": [3, 5, 6], "minor": 0, "mitig": [0, 5], "mix": 0, "mode": [0, 5], "model": [2, 3, 6], "modul": [1, 2], "more": [0, 5], "mozilla": 6, "must": 0, "name": [0, 4], "need": [0, 5], "nest": [0, 5], "next": 6, "non": 6, "none": [1, 3, 4, 5, 6], "notat": [0, 5], "note": [0, 5], "noth": [0, 5], "null": [0, 5], "nullish": 6, "number": [0, 5], "numer": [0, 5], "obj": 0, "object": [0, 3, 4, 5, 6], "obtain": [0, 5], "occur": 4, "octet": [0, 4], "old": [0, 5], "omit": [0, 5], "onli": [0, 5], "option": [0, 3, 4, 5, 6], "order": [0, 5], "org": 6, "other": [0, 4, 5], "otherwis": 0, "output": [0, 5], "over": [0, 5], "overrid": [0, 3, 5], "overridden": [0, 5], "packag": [1, 2], "page": [0, 1, 4, 5], "pair": 5, "paramet": [0, 5], "parameter_limit": [0, 3, 5, 6], "pars": [0, 5], "parse_list": [0, 3, 5, 6], "parser": 3, "pass": [0, 5], "pattern": 5, "percent": [0, 4], "place": 0, "pleas": 0, "point": 0, "port": [1, 3], "prefix": [0, 4, 5], "prepend": 0, "preserv": 0, "presum": 4, "primit": [1, 6], "proper": [0, 5], "properti": [0, 5], "provid": [0, 3, 5], "python": [1, 3, 6], "q": 0, "qs_codec": [0, 1], "qualnam": 4, "queri": [0, 1, 3, 5], "question": [0, 5], "r": 0, "rail": [0, 5], "rather": [0, 5], "raw": 4, "re": 0, "real": 0, "reason": [0, 5], "recommend": [0, 5], "refer": [5, 6], "regular": 0, "remain": 0, "remov": 6, "render": 0, "repeat": [0, 3, 4], "replac": [0, 5], "repres": [4, 5, 6], "represent": 6, "request": [0, 4, 5], "respect": 0, "restrict": [0, 5], "result": 0, "return": [0, 5, 6], "rfc": [1, 4], "rfc1738": [0, 3, 4, 5], "rfc3986": [0, 3, 4, 5, 6], "round": [0, 5], "rubi": [0, 5], "search": [0, 1], "second": 0, "select": [0, 5], "sens": [0, 5], "sent": [0, 5], "sentinel": [2, 3], "separ": 5, "serial": [0, 5, 6], "serialize_d": [0, 3, 5, 6], "server": [0, 5], "servic": [0, 5], "set": [1, 4, 5], "shift": 0, "shift_ji": 0, "shown": 0, "sign": [0, 5], "signific": [0, 5, 6], "similar": [0, 5], "simpl": 1, "singl": [0, 4, 5], "singleton": 5, "skip": [0, 5], "skip_nul": [0, 3, 5, 6], "small": [0, 5], "so": [0, 5], "some": [0, 5], "someon": [0, 5], "sort": [0, 3, 5], "sourc": [3, 4, 5, 6], "space": 1, "spars": 0, "special": 1, "specif": 0, "specifi": [0, 5], "split": 5, "squar": 0, "stabl": 6, "start": 4, "static": [4, 6], "str": [0, 3, 4, 5, 6], "str_util": [2, 3], "strategi": [4, 5], "strict_null_handl": [0, 3, 5, 6], "string": [0, 1, 3, 4, 5, 6], "stringifi": 3, "sub": 0, "submit": [0, 4, 5], "submodul": 2, "subpackag": 2, "support": [0, 4, 5], "surround": 0, "switch": [0, 5], "sy": 0, "syntax": 0, "system": 0, "t": 0, "tabl": 6, "take": [0, 5, 6], "target": 6, "than": [0, 5], "thank": 1, "thei": [0, 5], "thi": [0, 4, 5, 6], "third": 0, "though": 0, "through": [0, 5], "time": [0, 5, 6], "timestamp": 0, "tj": 1, "togeth": 6, "too": 0, "treat": 0, "trip": [0, 5], "true": [0, 3, 5, 6], "try": 0, "tupl": 6, "two": [0, 6], "type": [0, 3, 4, 5, 6], "u": [4, 6], "undefin": [0, 2, 3, 6], "unescap": [3, 6], "union": 0, "unit": 6, "up": [0, 5], "uri": [0, 4], "url": 6, "urlencod": [0, 4, 5], "us": [0, 4, 5, 6], "usag": 0, "user": [0, 5], "utc": 0, "utcfromtimestamp": 0, "utf": [0, 3, 4, 5, 6], "utf8": [0, 3, 4, 5, 6], "util": [2, 3, 5], "val": 6, "valu": [1, 3, 4, 5, 6], "valueerror": 0, "version": [0, 5], "version_info": 0, "via": [0, 5], "wa": [0, 5], "wai": 5, "want": [0, 5], "weak": 5, "weak_wrapp": [2, 3], "weakwrapp": [3, 5], "web": 6, "well": [0, 5], "what": [0, 4, 5], "when": [0, 4, 5], "which": [0, 4, 5], "while": 0, "wish": 0, "within": 0, "without": [0, 5], "work": [0, 6], "would": 0, "wrapper": 5, "wrong": [0, 5], "www": [0, 4, 5], "x": [0, 4, 5], "y": 0, "you": [0, 5], "your": 0, "z": 0, "\u00e6": 0, "\u00f8": 0, "\u010d": 0, "\u3053\u3093\u306b\u3061\u306f": 0}, "titles": ["Decoding", "qs-codec", "qs_codec", "qs_codec package", "qs_codec.enums package", "qs_codec.models package", "qs_codec.utils package"], "titleterms": {"1738": 0, "3986": 0, "bool": 0, "charact": 0, "charset": 4, "codec": 1, "content": [1, 3, 4, 5, 6], "deal": 0, "decod": [0, 3], "decode_opt": 5, "decode_util": 6, "dictionari": 0, "duplic": 4, "encod": [0, 3], "encode_opt": 5, "encode_util": 6, "enum": 4, "etc": 0, "format": 4, "handl": 0, "indic": 1, "int": 0, "list": 0, "list_format": 4, "model": 5, "modul": [3, 4, 5, 6], "none": 0, "packag": [3, 4, 5, 6], "primit": 0, "q": 1, "qs_codec": [2, 3, 4, 5, 6], "rfc": 0, "sentinel": 4, "set": 0, "space": 0, "special": 0, "str_util": 6, "submodul": [3, 4, 5, 6], "subpackag": 3, "tabl": 1, "undefin": 5, "usag": 1, "util": 6, "valu": 0, "weak_wrapp": 5}}) \ No newline at end of file

q~A+6VD21{OI4e6?6e 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 literal 0 HcmV?d00001 diff --git a/.doctrees/qs_codec.doctree b/.doctrees/qs_codec.doctree new file mode 100644 index 0000000000000000000000000000000000000000..73835c948cdea50011e9d0553deb79c4c018d15a GIT binary patch literal 23946 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 Vk%ycn+sA7XXb9Ue{*r6se*ufJ0p$Py literal 0 HcmV?d00001 diff --git a/.doctrees/qs_codec.enums.doctree b/.doctrees/qs_codec.enums.doctree new file mode 100644 index 0000000000000000000000000000000000000000..608e13bdde1a9ae2f02d84efac22212bf0622a0e GIT binary patch literal 84576 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