Simple package for parsing querystrings into nested dictionaries and vice versa.
Project description
qstion
A querystring parsing and stringifying library with some added security. Library was based on this js library.
Usage
import qstion as qs
x = qs.parse('a=c')
assert x == {'a': 'c'}
x_str = qs.stringify(x)
assert x_str == 'a=c'
Parsing strings
qstion (as well as qs in js) allows you to parse string into nested objects.
import qstion as qs
assert qs.parse('a[b][c]=1') == {'a': {'b': {'c': '1'}}}
There is no support for plain object options or prototype pollution.
Uri encoded strings are supported
import qstion as qs
assert qs.parse('a%5Bb%5D=c') == {'a': { 'b': 'c' }}
Following options are supported:
from_url
: bool - ifTrue
thenparse
will parse querystring from url usingurlparse
fromurllib.parse
module, default:False
import qstion as qs
assert qs.parse('http://localhost:8080/?a=c', from_url=True) == {'a': 'c'}
assert qs.parse('a=c', from_url=False) == {'a': 'c'}
delimiter
: str|re.Pattern - delimiter for parsing, default:&
import qstion as qs
assert qs.parse('a=c&b=d', delimiter='&') == {'a': 'c', 'b': 'd'}
assert qs.parse('a=c;b=d,c=d', delimiter='[;,]') == {'a': 'c', 'b': 'd', 'c': 'd'}
depth
: int - maximum depth for parsing, default:5
import qstion as qs
assert qs.parse('a[b][c][d][e][f][g][h][i]=j', depth=5) == {'a': {'b': {'c': {'d': {'e': {'f': {'[g][h][i]': 'j'}}}}}}}
assert qs.parse('a[b][c][d][e][f][g][h][i]=j', depth=1) == {'a': {'b': {'[c][d][e][f][g][h][i]': 'j'}}}
parameter_limit
: int - maximum number of parameters to parse, default:1000
import qstion as qs
assert qs.parse('a=b&c=d&e=f&g=h&i=j&k=l&m=n&o=p&q=r&s=t&u=v&w=x&y=z', parameter_limit=5) == {'a': 'b', 'c': 'd', 'e': 'f', 'g': 'h', 'i': 'j'}
allow_dots
: bool - ifTrue
then dots in keys will be parsed as nested objects, default:False
import qstion as qs
assert qs.parse('a.b=c', allow_dots=True) == {'a': {'b': 'c'}}
parse_arrays
: bool - ifTrue
then arrays will be parsed, default:False
import qstion as qs
assert qs.parse('a[]=b&a[]=c', parse_arrays=True) == {'a': {0: 'b', 1: 'c'}}
assert qs.parse('a[0]=b&a[1]=c', parse_arrays=False) == {'a': {'0': 'b', '1': 'c'}}
array_limit
: int - maximum number of elements in array to keep array notation (only used with combination of argumentparse_arrays
), default:20
import qstion as qs
assert qs.parse('a[]=b&a[]=c&', parse_arrays=True) == {'a': {0: 'b', 1: 'c'}}
assert qs.parse('a[0]=b&a[1]=c&', array_limit=1, parse_arrays=True) == {'a': {'0': 'b', '1': 'c'}}
allow_empty
: bool - ifTrue
then empty values and keys are accepted, default:False
import qstion as qs
assert qs.parse('a=&b=', allow_empty=True) == {'a': '', 'b': ''}
assert qs.parse('a[]=&b[]=', allow_empty=True) == {'a': {'': ''}, 'b': {'': ''}}
charset
: str - charset to use when decoding uri encoded strings, default:utf-8
import qstion as qs
assert qs.parse('a=%A7', charset='iso-8859-1') == {'a': '§'}
assert qs.parse('a=%C2%A7', charset='utf-8') == {'a': '§'}
charset_sentinel
: bool - ifTrue
then, ifutf8=✓
arg is included in querystring, then charset will be deduced based on encoding of '✓' character (recognizes onlyutf8
andiso-8859-1
), default:False
import qstion as qs
assert qs.parse('a=%C2%A7&utf8=%E2%9C%93',charset='iso-8859-1', charset_sentinel=True) == {'a': '§'}
assert qs.parse('a=%A7&utf8=%26%2310003', charset='utf-8', charset_sentinel=True) == {'a': '§'}
interpret_numeric_entities
: bool - ifTrue
then numeric entities will be interpreted as unicode characters, default:False
import qstion as qs
assert qs.parse('a=%26%2310003',charset='iso-8859-1', interpret_numeric_entities=True) == {'a': '✓'}
parse_primitive
: bool - ifTrue
then primitive values will be parsed in their appearing types, default:False
import qstion as qs
assert qs.parse('a=1&b=2&c=3', parse_primitive=True) == {'a': 1, 'b': 2, 'c': 3}
assert qs.parse('a=true&b=false&c=null', parse_primitive=True) == {'a': True, 'b': False, 'c': None}
primitive_strict
: bool - ifTrue
then primitive values ofbool
andNoneType
will be parsed to reserved strict keywords (used only ifparse_primitive
isTrue
), default:True
import qstion as qs
assert qs.parse('a=true&b=false&c=null&d=None', parse_primitive=True, primitive_strict=True) == {'a': True, 'b': False, 'c': None, 'd': 'None'}
assert qs.parse('a=True&b=False&c=NULL', parse_primitive=True, primitive_strict=True) == {'a': 'True', 'b': 'False', 'c': 'NULL'}
assert qs.parse('a=True&b=False&c=NULL', parse_primitive=True, primitive_strict=False) == {'a': True, 'b': False, 'c': None}
comma
: bool - ifTrue
, then coma separated values will be parsed as multiple separate values instead of string, default:False
import qstion as qs
assert qs.parse('a=1,2,3', comma=True, parse_primitive=True) == {'a': [1, 2, 3]}
Stringifying objects
qstion (as well as qs in js) allows you to stringify objects into querystring.
import qstion as qs
assert qs.stringify({'a': 'b'}) == 'a=b'
Following options are supported:
allow_dots
: bool - ifTrue
then nested keys will be stringified using dot notation instead of brackets, default:False
import qstion as qs
assert qs.stringify({'a': {'b': 'c'}}, allow_dots=True) == 'a.b=c'
encode
: bool - ifTrue
then keys and values will be uri encoded (with defaultcharset
), default:True
import qstion as qs
assert qs.stringify({'a[b]': 'b'}, encode=False) == 'a[b]=b'
assert qs.stringify({'a[b]': 'b'}, encode=True) == 'a%5Bb%5D=b'
charset
: str - charset to use when encoding uri strings, default:utf-8
(ifencode
isTrue
), note that un-encodable characters will be encoded using their xml numeric entities
import qstion as qs
assert qs.stringify({'a': '§'}, charset='iso-8859-1') == 'a=%A7'
assert qs.stringify({'a': '☺'}, charset='iso-8859-1') == 'a=%26%2312850'
charset_sentinel
: bool - ifTrue
then,utf8=✓
will be added to querystring to indicate that charset based on encoding of '✓' character (recognizes onlyutf8
andiso-8859-1
), default:False
import qstion as qs
assert qs.stringify({'a': '§'}, charset='iso-8859-1', charset_sentinel=True) == 'a=%A7&utf8=%E2%9C%93'
delimiter
: str - delimiter for stringifying, default:&
import qstion as qs
assert qs.stringify({'a': 'b', 'c': 'd'}, delimiter='&') == 'a=b&c=d'
assert qs.stringify({'a': 'b', 'c': 'd'}, delimiter=';') == 'a=b;c=d'
encode_values_only
: bool - ifTrue
then only values will be encoded, default:False
(this option is overridden whenencode
isTrue
)
import qstion as qs
assert qs.stringify({'a': {'b': '☺'}}, encode_values_only=True, charset='iso-8859-1') == 'a[b]=%26%2312850'
array_format
: str - format for array notation, options: 'brackets','indices', 'repeat', 'comma', default: 'indices'
import qstion as qs
assert qs.stringify({'a': {1: 'b', 2: 'c'}}, array_format='brackets') == 'a[]=b&a[]=c'
assert qs.stringify({'a': {1: 'b', 2: 'c'}}, array_format='indices') == 'a[1]=b&a[2]=c'
assert qs.stringify({'a': {1: 'b', 2: 'c'}}, array_format='repeat') == 'a=b&a=c'
assert qs.stringify({'a': {1: 'b', 2: 'c'}}, array_format='comma') == 'a=b,c'
sort
: bool - ifTrue
then keys will be sorted alphabetically, default:False
import qstion as qs
assert qs.stringify({'x': 'y', 'a': 'b'}, sort=True) == 'a=b&x=y'
sort_reverse
: bool - ifTrue
then keys will be sorted (ifsort
isTrue
) in reverse order, default:False
import qstion as qs
assert qs.stringify({'x': 'y', 'a': 'b'}, sort=True, sort_reverse=True) == 'x=y&a=b'
filter
: list[str] - list of keys to filter, default:None
import qstion as qs
assert qs.stringify({'a': 'b', 'c': 'd'}, filter=['a']) == 'a=b'
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
qstion-0.0.1.tar.gz
(18.1 kB
view details)
Built Distribution
qstion-0.0.1-py3-none-any.whl
(13.1 kB
view details)
File details
Details for the file qstion-0.0.1.tar.gz
.
File metadata
- Download URL: qstion-0.0.1.tar.gz
- Upload date:
- Size: 18.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.1 CPython/3.11.6
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 07854dc115a7eca530459de4a05a1fec288e6069f8ee2914346325de20b36d93 |
|
MD5 | 8cb8914341b08c0c0e406cb4face90b6 |
|
BLAKE2b-256 | d97e9f207ea2d573fd382c384e0ad35c4316b7167caa8015e09021542d4eb025 |
File details
Details for the file qstion-0.0.1-py3-none-any.whl
.
File metadata
- Download URL: qstion-0.0.1-py3-none-any.whl
- Upload date:
- Size: 13.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.1 CPython/3.11.6
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | e50b10b3e2c0235f3b3f3c840b6376b0000180d7b4192eca18394d9be443ba02 |
|
MD5 | 205416ada3dc777df9e12cdde9c45a34 |
|
BLAKE2b-256 | 1112206bed7cc15ac6ec97ec154cbb42301d0eb86aef0dd75ed719e484b33350 |