Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

object_changed(): fix list comparison #38

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

obfusk
Copy link
Contributor

@obfusk obfusk commented Sep 16, 2023

Currently, e.g. setting a list value (that was not empty before) to [] will never be detected as a change as the for loop is never run. Neither will changing a list to any prefix of the old one. And it will crash if changing a list to a longer one if the list contains something other than lists or dicts as the if value[i] != value2[i] doesn't check the length of value2:

# wrong
>>> bool(object_changed(dict(k=[1,2,3]),dict(k=[])))
False
# wrong
>>> bool(object_changed(dict(k=[1,2,3]),dict(k=[1,2])))
False

# crash
>>> bool(object_changed(dict(k=[1,2,3]),dict(k=[1,2,3,4])))
[...]
    if value[i] != value2[i]:
                   ~~~~~~^^^
IndexError: list index out of range

# wrong
>>> bool(object_changed(dict(k=[dict(a=1),dict(b=2)]),dict(k=[dict(a=1)])))
False
# correct and doesn't crash
>>> bool(object_changed(dict(k=[dict(a=1),dict(b=2)]),dict(k=[dict(a=1), dict(b=2), dict(b=3)])))
True

All of those correctly return True with this patch.

I'm not sure this has any unintended side-effects as some existing code might accidentally rely on the existing behaviour, but it's clearly a bug.

Not yet tested with our actual ansible config, just those examples. Will test soon.

@obfusk
Copy link
Contributor Author

obfusk commented Sep 16, 2023

I found more bugs with dict comparisons. The latest version should fix those.

Would probably be good if someone can run the test suite to make sure nothing breaks.

@obfusk
Copy link
Contributor Author

obfusk commented Sep 16, 2023

Deployed our ansible config with these changes. LGTM :)

@obfusk obfusk marked this pull request as ready for review September 16, 2023 23:47
@obfusk
Copy link
Contributor Author

obfusk commented Sep 16, 2023

I also looked at the code using this as best I could. I can't rule out it'll break something. And someone should definitely run the test suite. But it looks to me like none of the usages of object_changed() in the ansible role should be adversely affected. And all of the edit_ functions in the API seem to use the same pattern of

data = self.get_monitor(id_)
data.update(kwargs)

Which means that there should be no unintended side-effects from the changes that now check that nested dicts and lists will always be considered changed if they are not the same size. The top-level dict is still considered a superset and subset, as it should be, with extra keys present in the superset not counting as changes.

@obfusk
Copy link
Contributor Author

obfusk commented Sep 16, 2023

So unless something breaks as a result of actual changes now being recognised as such when they were not before -- which means it relied on broken behaviour -- I do not expect any issues.

@obfusk
Copy link
Contributor Author

obfusk commented Sep 30, 2023

FWIW we've been using this in production since I opened this PR and have had zero issues whilst the bug (unable to clear notifications as setting the list to [] is not detected as a change) is indeed fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant