Skip to content

hash(JsonPatch) raises TypeError when an operation's value is an array or object #217

Closed

Description

@stefankoegl

JsonPatch and PatchOperation define __eq__ and __hash__, but hashing fails for any patch with an array or object value:

>>> import jsonpatch
>>> hash(jsonpatch.JsonPatch([{'op': 'add', 'path': '/a', 'value': []}]))
TypeError: unhashable type: 'list'
>>> hash(jsonpatch.JsonPatch([{'op': 'add', 'path': '/a', 'value': {}}]))
TypeError: unhashable type: 'dict'
>>> hash(jsonpatch.JsonPatch([{'op': 'add', 'path': '/a', 'value': 'x'}]))
1567954150907410962

So such patches can't go into sets or serve as dict keys, while patches with scalar values can.

Cause: PatchOperation.__hash__ returns hash(frozenset(self.operation.items())), which requires every member value to be hashable.

Suggested fix: hash only op, path and from. Operations that compare equal still get equal hashes. Hashing a json.dumps of the whole operation would break that while __eq__ uses Python equality: {'value': 1}, {'value': 1.0} and {'value': True} compare equal but serialize differently (see #216).

Test: JsonPatchProperties.test_equal_patches_have_equal_hashes in property_tests.py is marked @unittest.expectedFailure because of this bug.

Activity

  1. stefankoegl commented on Oct 10, 2026

    @stefankoegl
    OwnerAuthor

    Fixed by ccb5228 ("Hash patch operations by their 'op' and 'path'"), merged in #220.

    On current master (077b4f4), patches whose values are arrays or objects can be hashed, and equal patches get equal hashes. test_equal_patches_have_equal_hashes in property_tests.py no longer carries expectedFailure and passes, at 5,000 examples on two hash seeds as well.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions