Compare dictionaries, lists and other objects convenient and readable
Project description
Lookslike - Simple datatype comparison
Lookslike is a library to simplify comparison of two objects (like numbers) within complex structures (like dictionaries) in a simple and readable way.
For example, it can be used to compare JSON data of server responses.
You can use Like
objects when comparing dictionaries (or lists) for values that don't match exactly.
from lookslike import Like
from urllib.request import urlopen
import json
def test_get_user():
server_response = json.load(urlopen("http://localhost:8000/api/user?user_id=1"))
assert server_response == {'user-name': 'John Doe',
'uuid': Like(str),
'timestamp': Like(int, lambda value: value > 0)}
Lookslike has no external dependencies and less than 100 lines of code with a bit of magic to provide you some sparkle.
Usage examples
import re
from lookslike import Like, utils
# Check for type
42 == Like(int) # True
42 == Like(float) # False
# Check using regular expressions
'abc' == Like(re.compile('a.*')) # True
'abc' == Like(re.compile('a')) # False
123.456 == Like(re.compile(r'\d+\.\d+')) # True
# Check using custom function
42 == Like(lambda value: 40 < value < 44) # True
# Combine multiple checks
42 == Like(int, lambda value: 40 < value < 44) # True
42 == Like(float, lambda value: 40 < value < 44) # False
# Convert values
['c', 'b', 'a'] == Like(['a', 'b', 'c'], convert=sorted) # True
{'a': 1, 'b': 'not important'} == Like({'a': 1},
convert=utils.filter_keys(['a'])) # True
[1, 2, 3, 4, 5] == Like([1, 2, 3], convert=lambda l: [num for num in l if num <= 3]) # True
# Usage in list and dict comparisons
[1, 2, 3] == [1, Like(int), 3] # True
{'a': 1, 'b': 0.5} == {'a': 1, 'b': Like(float, lambda num: 0 <= num <= 1)} # True
# Complex server response example
def test_server_response():
server_response = { # This is your test object of course
'response_id': 42,
'timestamp': 2134567.2355,
'pets': ['cat', 'dog', 'chicken'],
'number_of_pets': 3,
'info_url': 'https://petsdb.info/',
'vet name': 'Dr. Murphey',
'home': {
'home_id': 1242,
'address': {
'street': 'Rabbit street 42',
'city': 'New Bark',
}
}
}
assert server_response == {
'response_id': Like(int),
'timestamp': Like(float),
'pets': Like(['cat', 'chicken', 'dog'], convert=sorted),
'number_of_pets': 3,
'info_url': Like(lambda value: value.startswith('https://')),
'vet name': Like(re.compile(r'Dr\. .*')),
'home': {
'home_id': Like(int),
'address': Like({'city': 'New Bark'}, convert=utils.filter_keys(['city']))
}
} # True
To consider
Regular expressions
When you provide a regex pattern, there are some things to consider:
Pattern has to match the whole string
When you provide a regex Pattern, it has to match the whole string. This is to prevent False-positives. For example:
This regex re.match('a', 'abc')
in Python will find a match. But 'abc' == Like(re.compile('a'))
will be False.
Instead you have to use
'abc' == Like(re.compile('a.*')
Comparing strings with bytes does not raise an Exception
Normally, you will get a TypeError when doing something like this re.match(b'abc', 'a')
However, this b'abc' == Like(re.compile('a')
will return False instead without raising an exception.
String representation
The string representation of Like
objects changes depending on the last comparison result: If the last result was
False, the string representation will be '!Like(...)'. This is to make it easier to find non-matching items in logs.
Names will change in the debugger and e.g. in the AssertionError raised by pytest.
Other utilities
If you want to compare JSON only and want a tool that is more standardized you can have a look at jsonschema.
If you want not only to check, but to convert dictionaries to real Python objects, have a look at pydantic.
If you want to find the difference of two dictionaries have a look at deepdiff.
Changes
1.0.0
- Don't panic, just move project status to "stable". No breaking changes.
0.9.2
- Add new utility "is_truthy".
0.9.1
- Restructure project
- Add support for old Python versions (up to 3.3)
- Change representation of "Like" to "!Like" when last comparison failed.
0.9
- Add lookslike to PyPI
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
Hashes for lookslike-1.0.0-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | a6f6f92fe5e085d6c701ec3202a8ada92cb8371703c0e2f20b2f38fbcdffa661 |
|
MD5 | dc9bb023a490257799f517925891245c |
|
BLAKE2b-256 | 4367c45f3c049f5a049e7b56295e775199c77fa34018f49ca48eed9f01b75367 |