Skip to main content

DictQuery

Library to query python dicts

Several syntax examples:

"age >= 12"
"`user.name` == 'cyberlis'"
"`user.email` MATCH /\w+@\w+\.com/ AND age != 11"
"`user.friends.age` > 12 AND `user.friends.name` LIKE 'Ra*ond'"
"email LIKE 'mariondelgado?bleendot?com'"
"eyeColor IN ['blue', 'green', 'black']"
"isActive AND (gender == 'female' OR age == 27)"
"latitude != longitude"

Supported data types

type example
KEY name, age, `friends.name.firstname`, `friends.age`
NUMBER 42, -12, 34.7
STRING 'hello', "hellow"
BOOLEAN true, false
NONE none, null
NOW utc current datetime
REGEXP /\d+\d+\w+/
ARRAY list of any items and any types

Keys

Key literals must start with a letter or an underscore, such as:

  • _underscore
  • underscore_

The remainder of your variable name may consist of letters, numbers and underscores.

  • password1
  • n00b
  • un_der_scores

If you need a key with separator character (. or /) because you use nested keys, or need spaces or other punctuation characters in key, use back-ticks (``)

DictQuery supports nested dicts splited by dot . or any separator specified in key_separator param. Default key_separator='.'

>>> import dictquery as dq
>>> dq.match(data, "`friends.age` <= 26")
True
>>> compiled = dq.compile("`friends/age` <= 26", key_separator='/')
>>> compiled.match(data)
True

if you don't need nested keys parsing and want get keys as is or if your keys contain separator char, you can disable nested keys behaviour by setting use_nested_keys=False

>>> import dictquery as dq
>>> dq.match(data, "`user.address`")
False
>>> dq.match(data, "age")
True
>>> compiled = dq.compile("`user.address`", use_nested_keys=False)
>>> compiled.match(data)
True

In query you can use dict keys 'as is' without any binary operation. DictQuery will get value by the key and evaluate it to bool

>>> import dictquery as dq
>>> dq.match(data, "isActive")
False
>>> dq.match(data, "isActive == false")
True

if key is not found by default this situation evaluates to boolean False (no exception raised). You can set raise_keyerror=True to raise keyerror if key would not be found.

>>> import dictquery as dq
>>> dq.match(data, "favoriteFruit")
False
>>> compiled = dq.compile("`favoriteFruit`", raise_keyerror=True)
>>> compiled.match(data)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File ".../dictquery/dictquery/visitors.py", line 41, in match
    return self.evaluate(data)
  File ".../dictquery/dictquery/visitors.py", line 35, in evaluate
    result = bool(self.ast.accept(self))
  File ".../dictquery/dictquery/parsers.py", line 80, in accept
    return visitor.visit_key(self)
  File ".../dictquery/dictquery/visitors.py", line 84, in visit_key
    values=self._get_dict_value(expr.value),
  File ".../dictquery/dictquery/visitors.py", line 30, in _get_dict_value
    self.key_separator, self.raise_keyerror)
  File ".../dictquery/dictquery/datavalue.py", line 112, in query_value
    raise DQKeyError("Key '{}' not found".format(data_key))
dictquery.exceptions.DQKeyError: "Key 'favoriteFruit' not found"

Comparisons

Operation Meaning
< strictly less than
<= less than or equal
> strictly greater than
>= greater than or equal
== equal
!= not equal
>>> import dictquery as dq
>>> dq.match(data, "age == 26")
True
>>> dq.match(data, "latitude > 12")
True
>>> dq.match(data, "longitude < 30")
True
>>> dq.match(data, "`friends.age` <= 26")
True
>>> dq.match(data, "longitude >= -130")
True
>>> dq.match(data, "id != 0")
True
>>> dq.match(data, "gender == 'male'")
False

String comparisons and matching

String literals are written in a variety of ways:

  • Single quotes: 'allows embedded "double" quotes'
  • Double quotes: "allows embedded 'single' quotes".
Operation Meaning
MATCH regexp matching
LIKE glob like matching
IN dict item substring in string
CONTAINS dict item substring contains string

< , <= , > , >= , == , != works same way with strings as python

>>> import dictquery as dq
>>> dq.match(data, "eyeColor == 'green'")
True
>>> dq.match(data, "`name.firstname` != 'Ratliff'")
True
>>> dq.match(data, "eyeColor IN 'string with green color'")
True
>>> dq.match(data, "email CONTAINS '.com'")
True
>>> dq.match(data, r"email MATCH /\w+@\w+\.\w+/")
True
>>> dq.match(data, r"email LIKE 'mariondelgado@*'")
True
>>> dq.match(data, r"email LIKE 'mariondelgado?bleendot?com'")
True

By default all string related operations are case sensitive. To change this behaviour you have to create instance of DictQuery with case_sensitive=False

>>> import dictquery as dq
>>> dq.match(data, "`name.firstname` == 'marion'")
False
>>> compiled = dq.compile("`name.firstname` == 'marion'", case_sensitive=False)
>>> compiled.match(data)
True

Array comparisons

Operation Meaning
IN dict item in array
CONTAINS dict item contains matching item
>>> import dictquery as dq
>>> dq.match(data, "tags CONTAINS 'dolor'")
True
>>> dq.match(data, "eyeColor IN ['blue', 'green', 'black']")
True

Key presence in dict

CONTAINS can be used with dict items to check if key in dict

>>> import dictquery as dq
>>> dq.match(data, "name CONTAINS 'firstname'")
True
>>> dq.match(data, "name CONTAINS 'thirdname'")
False

Datetime comparisons with NOW

NOW returns current utc datetime

dict item can be compared with NOW using standard operations (< , <= , > , >= , == , !=)

>>> import dictquery as dq
>>> dq.match(data, "registered < NOW")
True
>>> dq.match(data, "registered != NOW")
True

Logical operators

Operator Meaning Example
and True if both the operands are true x and y
or True if either of the operands is true x or y
not True if operand is false (complements the operand) not x
>>> import dictquery as dq
>>> dq.match(data, "isActive AND gender == 'female'")
False
>>> dq.match(data, "isActive OR gender == 'female'")
True
>>> dq.match(data, "NOT isActive AND gender == 'female'")
True

You can use parentheses to group statements or change evaluation order

>>> import dictquery as dq
>>> dq.match(data, "isActive AND gender == 'female' OR age == 27")
True
>>> dq.match(data, "isActive AND (gender == 'female' OR age == 27)")
False

Data for examples above:

from datetime import datetime
data = {
  "_id": 10,
  "isActive": False,
  "age": 27,
  "eyeColor": "green",
  "name": {
    "firstname": "Marion",
    "secondname": "Delgado",
  },
  "gender": "female",
  "email": "mariondelgado@bleendot.com",
  "registered": datetime.strptime("2015-03-29T06:07:58", "%Y-%m-%dT%H:%M:%S"),
  "latitude": 74.785608,
  "longitude": -112.366088,
  "tags": [
    "voluptate",
    "ex",
    "dolor",
    "aute"
  ],
  "user.address": "155 Village Road, Enetai, Puerto Rico, 2634",
  "friends": [
    {
      "id": 0,
      "name": {
        "firstname": "Ratliff",
        "secondname": "Becker",
      },
      "age": 27,
      "eyeColor": "green"
    },
    {
      "id": 1,
      "name": {
        "firstname": "Raymond",
        "secondname": "Albert",
      },
      "age": 19,
      "eyeColor": "brown"
    },
    {
      "id": 2,
      "name": {
        "firstname": "Mavis",
        "secondname": "Sheppard",
      },
      "age": 34,
      "eyeColor": "blue"
    }
  ]
}

Release files for dictquery 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for dictquery 0.5.0
File Size Uploaded
dictquery-0.5.0.tar.gz 13.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for dictquery 0.5.0
File Interpreter ABI Platform
dictquery-0.5.0-py2.py3-none-any.whl Python 2, Python 3 none any Details

Total release size: 24.7 kB

Release files / dictquery-0.5.0.tar.gz

Download URL dictquery-0.5.0.tar.gz
Size 13.3 kB
Tags Source
SHA-256 checksum
How to use checksums
15d056231e68a24ea13995c2e437cbb6867e60863dfc736148acaec92e1e3ab8
BLAKE2b-256 checksum
How to use checksums
30c63bc0359007aa09be047c5dbb48afb1e89673507b4c03f16b1310a87312d8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.1 CPython/3.10.9

Release files / dictquery-0.5.0-py2.py3-none-any.whl

Download URL dictquery-0.5.0-py2.py3-none-any.whl
Size 11.4 kB
Tags Python 2 Python 3
SHA-256 checksum
How to use checksums
868f5bd93fd59af990c9452d2b7bde1048d1a7aa2b675f163cb1f74c71011dea
BLAKE2b-256 checksum
How to use checksums
c6807fcdf5c5b19bfcaf4291c5d593d55b6a6d47f7dbc7a9bee90d25fb19a041
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.1 CPython/3.10.9

Release history Release notifications | RSS feed

This release

0.5.0 This release

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page