Skip to content

Commit

Permalink
Merge pull request #70 from nolar/fix-diff-on-field-removal
Browse files Browse the repository at this point in the history
Fix the detection of field deletion in diffs
  • Loading branch information
Sergey Vasilyev authored May 23, 2019
2 parents 0da996e + a251676 commit b6e3ec4
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 9 deletions.
4 changes: 2 additions & 2 deletions kopf/reactor/handling.py
Original file line number Diff line number Diff line change
Expand Up @@ -454,8 +454,8 @@ async def _call_handler(
"""

# For the field-handlers, the old/new/diff values must match the field, not the whole object.
old = cause.old if handler.field is None else resolve(cause.old, handler.field)
new = cause.new if handler.field is None else resolve(cause.new, handler.field)
old = cause.old if handler.field is None else resolve(cause.old, handler.field, None)
new = cause.new if handler.field is None else resolve(cause.new, handler.field, None)
diff = cause.diff if handler.field is None else reduce(cause.diff, handler.field)
cause = cause._replace(old=old, new=new, diff=diff)

Expand Down
20 changes: 14 additions & 6 deletions kopf/structs/diffs.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,20 @@
DiffItem = Tuple[DiffOp, DiffPath, Any, Any]
Diff = Sequence[DiffItem]


def resolve(d: Mapping, path: DiffPath):
result = d
for key in path:
result = result[key]
return result
_UNSET = object()


def resolve(d: Mapping, path: DiffPath, default=_UNSET):
try:
result = d
for key in path:
result = result[key]
return result
except KeyError:
if default is _UNSET:
raise
else:
return default


def reduce_iter(d: Diff, path: DiffPath) -> Generator[DiffItem, None, None]:
Expand Down
15 changes: 14 additions & 1 deletion tests/diffs/test_resolving.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,25 @@ def test_existing_key():
assert r == 'val'


def test_unexisting_key():
def test_unexisting_key_with_no_default():
d = {'abc': {'def': {'hij': 'val'}}}
with pytest.raises(KeyError):
resolve(d, ['abc', 'def', 'xyz'])


def test_unexisting_key_with_default_none():
d = {'abc': {'def': {'hij': 'val'}}}
r = resolve(d, ['abc', 'def', 'xyz'], None)
assert r is None


def test_unexisting_key_with_default_value():
default = object()
d = {'abc': {'def': {'hij': 'val'}}}
r = resolve(d, ['abc', 'def', 'xyz'], default)
assert r is default


def test_nonmapping_key():
d = {'key': 'val'}
with pytest.raises(TypeError):
Expand Down

0 comments on commit b6e3ec4

Please sign in to comment.