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-1.0.1.tar.gz (18.4 kB view hashes)

Uploaded Source

Built Distribution

qstion-1.0.1-py3-none-any.whl (13.4 kB view hashes)

Uploaded Python 3

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