Package: lookslike
Lookslike - Simple datatype comparisonLookslike 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 useLikeobjects when comparing dictionaries (or lists) for values that don't match exactly.fromlookslikeimportLikefromurllib.requestimporturlopenimportjsondeftest_get_user():server_response=json.load(urlopen("http://localhost:8000/api/user?user_id=1"))assertserver_response=={'user-name':'John Doe','uuid':Like(str),'timestamp':Like(int,lambdavalue: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 examplesimportrefromlookslikeimportLike,utils# Check for type42==Like(int)# True42==Like(float)# False# Check using regular expressions'abc'==Like(re.compile('a.*'))# True'abc'==Like(re.compile('a'))# False123.456==Like(re.compile(r'\d+\.\d+'))# True# Check using custom function42==Like(lambdavalue:40<value<44)# True# Combine multiple checks42==Like(int,lambdavalue:40<value<44)# True42==Like(float,lambdavalue: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=lambdal:[numfornuminlifnum<=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,lambdanum:0<=num<=1)}# True# Complex server response exampledeftest_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',}}}assertserver_response=={'response_id':Like(int),'timestamp':Like(float),'pets':Like(['cat','chicken','dog'],convert=sorted),'number_of_pets':3,'info_url':Like(lambdavalue: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']))}}# TrueTo considerRegular expressionsWhen you provide a regex pattern, there are some things to consider:Pattern has to match the whole stringWhen you provide a regex Pattern, it has to match the whole string. This is to prevent False-positives. For example:This regexre.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 ExceptionNormally, you will get a TypeError when doing something like thisre.match(b'abc', 'a')However, thisb'abc' == Like(re.compile('a')will return False instead without raising an exception.String representationThe string representation ofLikeobjects 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 utilitiesIf you want to compare JSON only and want a tool that is more standardized you can have a look
atjsonschema.If you want not only to check, but to convert dictionaries to real Python objects, have a look
atpydantic.If you want to find the difference of two dictionaries have a look atdeepdiff.Changes1.0.0Don't panic, just move project status to "stable". No breaking changes.0.9.2Add new utility "is_truthy".0.9.1Restructure projectAdd support for old Python versions (up to 3.3)Change representation of "Like" to "!Like" when last comparison failed.0.9Add lookslike to PyPI