Skip to main content

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:

  1. from_url : bool - if True then parse will parse querystring from url using urlparse from urllib.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'}
  1. 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'}
  1. 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'}}}
  1. 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'}
  1. allow_dots : bool - if True 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'}}
  1. parse_arrays: bool - if True 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'}}
  1. array_limit : int - maximum number of elements in array to keep array notation (only used with combination of argument parse_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'}}
  1. allow_empty : bool - if True 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': {'': ''}}
  1. 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': '§'}
  1. charset_sentinel : bool - if True then, if utf8=✓ arg is included in querystring, then charset will be deduced based on encoding of '✓' character (recognizes only utf8 and iso-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': '§'}
  1. interpret_numeric_entities : bool - if True 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': '✓'}
  1. parse_primitive: bool - if True 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}
  1. primitive_strict: bool - if True then primitive values of bool and NoneType will be parsed to reserved strict keywords (used only if parse_primitive is True), 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}
  1. comma: bool - if True, 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:

  1. allow_dots : bool - if True 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'
  1. encode : bool - if True then keys and values will be uri encoded (with default charset), 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'
  1. charset : str - charset to use when encoding uri strings, default: utf-8 (if encode is True), 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'
  1. charset_sentinel : bool - if True then, utf8=✓ will be added to querystring to indicate that charset based on encoding of '✓' character (recognizes only utf8 and iso-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'
  1. 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'
  1. encode_values_only : bool - if True then only values will be encoded, default: False (this option is overridden when encode is True)
import qstion as qs

assert qs.stringify({'a': {'b': '☺'}}, encode_values_only=True, charset='iso-8859-1') == 'a[b]=%26%2312850'
  1. 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'
  1. sort : bool - if True 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'
  1. sort_reverse : bool - if True then keys will be sorted (if sort is True) 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'
  1. 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


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)

Uploaded Source

Built Distribution

qstion-0.0.1-py3-none-any.whl (13.1 kB view details)

Uploaded Python 3

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

Hashes for qstion-0.0.1.tar.gz
Algorithm Hash digest
SHA256 07854dc115a7eca530459de4a05a1fec288e6069f8ee2914346325de20b36d93
MD5 8cb8914341b08c0c0e406cb4face90b6
BLAKE2b-256 d97e9f207ea2d573fd382c384e0ad35c4316b7167caa8015e09021542d4eb025

See more details on using hashes here.

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

Hashes for qstion-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 e50b10b3e2c0235f3b3f3c840b6376b0000180d7b4192eca18394d9be443ba02
MD5 205416ada3dc777df9e12cdde9c45a34
BLAKE2b-256 1112206bed7cc15ac6ec97ec154cbb42301d0eb86aef0dd75ed719e484b33350

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page