Skip to content

`jsonmatch` is a small library for diffing Python JSON dictionaries in a flexible, informative way

License

Notifications You must be signed in to change notification settings

percolate/jsonmatch

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

51 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

jsonmatch

CircleCI

jsonmatch is a small library for matching Python JSON dictionaries against a specification in a flexible, informative way. It was created to make testing API responses simple, quick, and easy.

>>> import jsonmatch, re

>>> m = jsonmatch.compile({'a': int, 'b': re.compile(r'\d+'), 'c': 'c'})

>>> m.matches({'a': 1, 'b': '321', 'c': 'c'})
True

>>> m.matches({'a': 1, 'b': 'not a digit', 'c': 'c'})
False

>>> m.assert_matches({'a': 1, 'b': 'not a digit', 'c': 'c'})
Expected:
{'a': <type 'int'>, 'b': <_sre.SRE_Pattern object at 0x7f70340d5160>, 'c': 'c'}

Got:
{'a': 1, 'b': 'not a digit', 'c': 'c'}

Diffs:
{('b',): (RegexpMatch(r'\d+'), 'not a digit')}

---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
...

>>> m.breaks({'a': 1, 'b': 'not a digit', 'c': 'c'}).paths_to_breaks
{('b',): (RegexpMatch(r'\d+'), 'not a digit')}

Installing

jsonmatch is on pypi

pip install jsonmatch

Features

  • Flexible matching based on
    • type
    • regexp
    • callable
    • or plain ol' object.
  • Return unmet expectations in a useful datastructure, not just a string.
    • {('path', 'to', 'diff'): (expected_val, actual_val), ...}
  • Optionally ignore ordering in lists.

Related projects

There are some other great solutions out there for doing data validation in Python, including

These libraries are much more robust than jsonmatch, but they're also significantly more complex.

Example

>>> import jsonmatch
>>> import re

>>> matcher = jsonmatch.compile({
  'a': 123,
  'b': {
    'c': re.compile('[abc][ABC]{3}'),  # we can use regexp
    'd': [1, 2, 3]},
  'e': lambda x: len(x) == 3,          # and callables
  'f': list,                           # and also types
})

# candidates that match the specification yield no breaks
>>> None == matcher.breaks({
  'a': 123,
  'b': {
    'c': 'aABC',
    'd': [1, 2, 3],
  },
  'e': 'one',
  'f': [],
})

True


# on the other hand, mismatches yield Breaks objects (scalar breakage in 'a')
>>> print matcher.breaks({
  'a': 1234,
  'b': {
    'c': 'aABC',
    'd': [1, 2, 3],
  },
  'e': 'one',
  'f': [],
}).breaks_str

"""
Expected:
{'a': 123,
 'b': {'c': <_sre.SRE_Pattern object at 0x2c8ed78>, 'd': [1, 2, 3]},
 'e': <function <lambda> at 0x2e8c1b8>,
 'f': []}

Got:
{'a': 1234, 'b': {'c': 'aABCeee', 'd': [1, 2, 3]}, 'e': 'one', 'f': []}

Diffs:
{('a',): (123, 1234)}
"""


# regexp breakage in 'b.c'
>>> print matcher.breaks({
  'a': 123,
  'b': {
    'c': "doesn't match",
    'd': [1, 2, 3],
  },
  'e': 'one',
  'f': [],
}).breaks_str

"""
Expected:
{'a': 123,
 'b': {'c': <_sre.SRE_Pattern object at 0x2c8ed78>, 'd': [1, 2, 3]},
 'e': <function <lambda> at 0x2e8c1b8>,
 'f': []}

Got:
{'a': 123, 'b': {'c': "doesn't match", 'd': [1, 2, 3]}, 'e': 'one', 'f': []}

Diffs:
{('b', 'c'): (RegexpMatch('[abc][ABC]{3}'), "doesn't match")}
"""

Python 2/3 compatibility

from __future__ import print_function, unicode_literals

>>> import jsonmatch
>>> msg = '\U0001f600'
>>> print(msg)
😀

# In PY2, the `str` type will match both unicode and byte string

>>> matcher = jsonmatch.compile({'message': str})
>>> print(matcher.matches({'message': b'bytestring'}))
True
>>> print(matcher.matches({'message': msg}))
True


# In PY3, `str` will ONLY match unicode string

>>> matcher = jsonmatch.compile({'message': str})
>>> print(matcher.matches({'message': b'bytestring'}))
False
>>> print(matcher.matches({'message': msg}))
True

# In order to match byte string, we must compile as `bytes`

>>> matcher = jsonmatch.compile({'message': bytes})
>>> print(matcher.matches({'message': b'bytestring'}))
True
>>> print(matcher.matches({'message': msg}))
False

About

`jsonmatch` is a small library for diffing Python JSON dictionaries in a flexible, informative way

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages