Skip to main content

Library to query python dicts

Project description

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"
    }
  ]
}

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

dictquery-0.5.0.tar.gz (13.3 kB view details)

Uploaded Source

Built Distribution

dictquery-0.5.0-py2.py3-none-any.whl (11.4 kB view details)

Uploaded Python 2 Python 3

File details

Details for the file dictquery-0.5.0.tar.gz.

File metadata

  • Download URL: dictquery-0.5.0.tar.gz
  • Upload date:
  • Size: 13.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.10.9

File hashes

Hashes for dictquery-0.5.0.tar.gz
Algorithm Hash digest
SHA256 15d056231e68a24ea13995c2e437cbb6867e60863dfc736148acaec92e1e3ab8
MD5 3a52cbf0d5ecd80c9e030a1053d39dba
BLAKE2b-256 30c63bc0359007aa09be047c5dbb48afb1e89673507b4c03f16b1310a87312d8

See more details on using hashes here.

File details

Details for the file dictquery-0.5.0-py2.py3-none-any.whl.

File metadata

  • Download URL: dictquery-0.5.0-py2.py3-none-any.whl
  • Upload date:
  • Size: 11.4 kB
  • Tags: Python 2, Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.10.9

File hashes

Hashes for dictquery-0.5.0-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 868f5bd93fd59af990c9452d2b7bde1048d1a7aa2b675f163cb1f74c71011dea
MD5 c4c00855ba87534b80ca18366951fe5a
BLAKE2b-256 c6807fcdf5c5b19bfcaf4291c5d593d55b6a6d47f7dbc7a9bee90d25fb19a041

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