Usage examples¶
Here we provide some brief usage examples of the code.
Importing, compiling, and validating a kmatch pattern¶
The K object can be imported directly from kmatch
from kmatch import K
Once imported, simply instantiating the K object performs validation on the pattern. It also compiles any regular expressions that are in the pattern for faster match
function calls.
k = K(['>', 'k1', 2])
Performing simple value filters¶
Simple value filters can be used directly when a logical operator is not needed. For example, performing a regex match on a key that has the ‘@’ symbol:
print K(['=~', 'k', '.*@.*']).match({'k': 'person@mail.com'})
True
This also applies to filtering numerical values:
print K(['>', 'num', 15]).match({'num': 16})
True
print K(['<=', 'num', 7]).match({'num': 8})
False
Performing simple key filters¶
Simple key filters can also be done to match dictionaries that have a key named ‘k1’:
print K(['?', 'k1']).match({'k1': True})
True
The inverse can also be checked:
print K(['!?', 'k1']).match({'k2': 'value'})
True
In the above example, ‘k1’ does not exist in the matched dictionary, so True
is returned.
Performing logical operations across filters¶
Filters can be combined with the &
(AND
) logical operator for more complex filtering:
print K(['&', [
['>', 'k1', 0],
['<=', 'k2', 5],
]]).match({
'k1': 50,
'k2': 1,
})
True
The same can be done with the |
(OR
) logical operator:
print K(['|', [
['==', 'k1', 'Hello'],
['==', 'k1', 'World'],
['==', 'k1', '!'],
]]).match({'k1': 'Hi'})
False
The !
(NOT
) logical operator operates on a single filter (or logical combination of filters):
print K(['!', ['==', 'k', 0]]).match({'k', 1})
True
Operators can be combined in various ways to form more complex patterns like so:
print K(['|', [
['&', [
['==', 'k1', 3],
['==', 'k2', 4],
]],
['!', ['=~', 'val', '.*Hello.*']],
]]).match({
'k1': 4,
'k2': 5,
'val', 'Hi',
})
True
Filtering with non-extant keys and suppressing KeyErrors¶
If keys from a kmatch pattern do not exist in the matched dictionary, the default behavior is to throw a KeyError
exception:
K(['==', 'k1', 5]).match({'k2': 1})
Traceback (most recent call last):
# Traceback message here ...
KeyError: 'k1'
This behavior, however, is not always desirable when matching dictionaries that have many keys that may or may not exist. It can be cumbersome to always have to check for existence along with doing filtering. To avoid this scenario, the K
object comes with an optional suppress_key_errors
flag that defaults to False
. If set to True
, the value False
will be returned any time a key does not exist for an associated filter instead of a KeyError
being raised.
Take our previous example, except with suppress_key_errors
set to True
.
print K(['==', 'k1', 5], suppress_key_errors=True).match({'k2': 1})
False
Using the test mixin¶
The KmatchTestMixin
can be used for test classes when you want to verify a dictionary matches a particular pattern.
from unittest import TestCase from kmatch import KmatchTestMixin class MyTestClass(KmatchTestMixin, TestCase): def my_test(self): self.assertKmatches(['<=', 'f', 0], {'f': -1}) def my_opposite_test(self): with self.assertRaises(AssertionError): self.assertNotKmatches(['<=', 'f', 0], {'f': -1}) self.assertNotKmatches(['<=', 'f', 0], {'g': 1})
Note
The suppress_key_errors
parameter is set to False
by default for .assertKmatches()
, and True
for .assertNotKmatches()
.