Last active
December 8, 2015 18:36
-
-
Save gfrlv/309ff80542fb67966b58 to your computer and use it in GitHub Desktop.
PartialEntityMatcher.ipynb
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "code", | |
"execution_count": 4, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [ | |
{ | |
"ename": "AssertionError", | |
"evalue": "\nExpected: Object equal to given Entity, ignoring fields \n but: \nMissing fields: d\nUnexpected fields: a\nUnequal fields: \n\tb: 5 != 2\n", | |
"output_type": "error", | |
"traceback": [ | |
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", | |
"\u001b[1;31mAssertionError\u001b[0m Traceback (most recent call last)", | |
"\u001b[1;32m<ipython-input-4-386e59c15430>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m 69\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[0mPartialEntityMatcher\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mother_entity\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m{\u001b[0m\u001b[1;33m}\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 70\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 71\u001b[1;33m \u001b[0massert_that\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0me1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mis_equal_to_entity\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0me2\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", | |
"\u001b[1;32m/home/gfrolov/venvs/rueabe/local/lib/python2.7/site-packages/hamcrest/core/assert_that.pyc\u001b[0m in \u001b[0;36massert_that\u001b[1;34m(arg1, arg2, arg3)\u001b[0m\n\u001b[0;32m 41\u001b[0m \"\"\"\n\u001b[0;32m 42\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0marg2\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mMatcher\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 43\u001b[1;33m \u001b[0m_assert_match\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mactual\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0marg1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mmatcher\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0marg2\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mreason\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0marg3\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 44\u001b[0m \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 45\u001b[0m \u001b[0m_assert_bool\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0massertion\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0marg1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mreason\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0marg2\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", | |
"\u001b[1;32m/home/gfrolov/venvs/rueabe/local/lib/python2.7/site-packages/hamcrest/core/assert_that.pyc\u001b[0m in \u001b[0;36m_assert_match\u001b[1;34m(actual, matcher, reason)\u001b[0m\n\u001b[0;32m 55\u001b[0m \u001b[0mmatcher\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdescribe_mismatch\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mactual\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mdescription\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 56\u001b[0m \u001b[0mdescription\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mappend_text\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'\\n'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 57\u001b[1;33m \u001b[1;32mraise\u001b[0m \u001b[0mAssertionError\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdescription\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 58\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 59\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n", | |
"\u001b[1;31mAssertionError\u001b[0m: \nExpected: Object equal to given Entity, ignoring fields \n but: \nMissing fields: d\nUnexpected fields: a\nUnequal fields: \n\tb: 5 != 2\n" | |
] | |
} | |
], | |
"source": [ | |
"from hamcrest.core.base_matcher import BaseMatcher\n", | |
"from hamcrest import assert_that\n", | |
"\n", | |
"\n", | |
"class PartialEntityMatcher(BaseMatcher):\n", | |
" def __init__(self, entity, fields_to_skip):\n", | |
" self.entity = entity\n", | |
" self.fields_to_skip = fields_to_skip\n", | |
"\n", | |
" self.missing_fields = set()\n", | |
" self.extra_fields = set()\n", | |
" self.unequal_fields = dict()\n", | |
"\n", | |
" def _matches(self, other_entity):\n", | |
" fields_of_self = set(self.entity.__dict__.keys())\n", | |
" fields_of_other = set(other_entity.__dict__.keys())\n", | |
"\n", | |
" self.missing_fields = fields_of_self.difference(fields_of_other)\n", | |
" self.extra_fields = fields_of_other.difference(fields_of_self)\n", | |
"\n", | |
" for field_name in fields_of_self.intersection(fields_of_other):\n", | |
" if field_name in self.fields_to_skip:\n", | |
" continue\n", | |
" field_of_self = getattr(self.entity, field_name)\n", | |
" field_of_other = getattr(other_entity, field_name)\n", | |
" if isinstance(field_of_self, list):\n", | |
" field_of_self = sorted(field_of_self)\n", | |
" field_of_other = sorted(field_of_other)\n", | |
" if field_of_self != field_of_other:\n", | |
" self.unequal_fields[field_name] = (field_of_self, field_of_other)\n", | |
"\n", | |
" if self.unequal_fields or self.missing_fields or self.extra_fields:\n", | |
" return False\n", | |
" return True\n", | |
"\n", | |
" def describe_mismatch(self, item, mismatch_description):\n", | |
" if self.missing_fields:\n", | |
" mismatch_description.append_text(\n", | |
" '\\nMissing fields: {}'.format(', '.join(self.missing_fields))\n", | |
" )\n", | |
" if self.extra_fields:\n", | |
" mismatch_description.append_text(\n", | |
" '\\nUnexpected fields: {}'.format(', '.join(self.extra_fields))\n", | |
" )\n", | |
" if self.unequal_fields:\n", | |
" diff_description = '\\n\\t'.join(\n", | |
" '{}: {} != {}'.format(key, self_value, other_value)\n", | |
" for key, (self_value, other_value) in self.unequal_fields.iteritems()\n", | |
" )\n", | |
" mismatch_description.append_text('\\nUnequal fields: \\n\\t{}'.format(diff_description))\n", | |
"\n", | |
" def describe_to(self, description):\n", | |
" description.append_text(\n", | |
" 'Object equal to given {}, ignoring fields {}'.format(\n", | |
" self.entity.__class__.__name__,\n", | |
" ', '.join(self.fields_to_skip)\n", | |
" )\n", | |
" )\n", | |
"\n", | |
"class Entity(object):\n", | |
" def __init__(self, **kwargs):\n", | |
" self.__dict__.update(kwargs)\n", | |
"\n", | |
"\n", | |
"e1 = Entity(a=1, b=2, c=3)\n", | |
"e2 = Entity(b=5, c=3, d=4)\n", | |
"\n", | |
"def is_equal_to_entity(other_entity):\n", | |
" return PartialEntityMatcher(other_entity, {})\n", | |
"\n", | |
"assert_that(e1, is_equal_to_entity(e2))" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"Если вызываем как `assert_that(e1, is_equal_to_entity(e2))`, то подразумеваем\n", | |
"\n", | |
" \"missing\" == \"missing from e1\",\n", | |
"\n", | |
"т.е. поля, которые есть в e2, но не в e1\n", | |
"\n", | |
"В примере - поле `d`" | |
] | |
} | |
], | |
"metadata": { | |
"kernelspec": { | |
"display_name": "Python 2", | |
"language": "python", | |
"name": "python2" | |
}, | |
"language_info": { | |
"codemirror_mode": { | |
"name": "ipython", | |
"version": 2 | |
}, | |
"file_extension": ".py", | |
"mimetype": "text/x-python", | |
"name": "python", | |
"nbconvert_exporter": "python", | |
"pygments_lexer": "ipython2", | |
"version": "2.7.6" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 0 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment