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

Fix shadow trait notifications #1188

Merged
merged 11 commits into from
Jun 5, 2020
Merged

Conversation

mdickinson
Copy link
Member

@mdickinson mdickinson commented Jun 4, 2020

This PR fixes the issue where shadow trait notifications were not being issued on the first change of the primary trait.

The essence of the change is to always call post_setattr (if it exists) when accessing a default value. That needs changes in two places:

  • in trait_getattr, where there's already a block that calls post_setattr, but the call is skipped for mapped traits, for no clear reason; we re-enable that call
  • in trait_setattr, where default_value_for is called if necessary to retrieve the old value for notifications. Here we add code to (1) poke the computed default value back onto the dictionary, just like we do already in trait_getattr, and (2) call post_setattr

There's scope for refactoring to remove the duplication, but I'd rather do that refactoring post-release, and do the minimum necessary to fix this bug for the release.

Note that this fix required fixing Map and PrefixMap to map a value of Undefined correctly; I think that's reasonable: mapped_value should be prepared to accept any valid value of the principal trait, and currently Undefined is such a value. (But see also #1187)

There's also a question of whether in trait_setattr we should be issuing notifications with old value Uninitialized, like we do in trait_getattr. It makes little difference in practice, since the notifiers don't call listeners when old is Uninitialized. We may want to make that change in master, for consistency, but for the bugfix I suggest leaving it out.

This builds on #1186, and will be easier to review once that PR is merged.

Fixes #1183

@kitchoi
Copy link
Contributor

kitchoi commented Jun 4, 2020

Is the dynamic default that depends on the mutable trait still needed or can it be removed now?

def _mapped_trait_default(trait, name, instance):
value = getattr(instance, name, Undefined)
if value is Undefined:
return Undefined
return trait.handler.mapped_value(value)

@mdickinson
Copy link
Member Author

@kitchoi It's still needed, to cope with the case where the shadow trait is accessed before the primary trait.

@mdickinson
Copy link
Member Author

the case where the shadow trait is accessed before the primary trait.

Let me make sure that we do have tests covering this case ...

@mdickinson
Copy link
Member Author

@kitchoi On the other hand, we can now remove that Undefined check from _mapped_trait_default.

@mdickinson
Copy link
Member Author

Hmm. Travis CI seems to have gone AWOL on recent commits on this PR.

@mdickinson
Copy link
Member Author

Closing and re-opening in an attempt to sort out the Travis CI status.

@mdickinson mdickinson closed this Jun 4, 2020
@mdickinson mdickinson reopened this Jun 4, 2020
Copy link
Contributor

@kitchoi kitchoi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Two questions.

traits/tests/test_map.py Show resolved Hide resolved
}

if (PyErr_ExceptionMatches(PyExc_KeyError)) {
PyErr_SetObject(PyExc_AttributeError, name);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This conversion from KeyError to AttributeError is removed. Do you know why it was there and that how it is not needed any more?
(Note: there is one like this near the bottom of setattr)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line isn't reachable in the C code, so that conversion was never exercised (at least since the move to Python 3 only).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(This is perhaps clearer in commit 4defec0 in PR #1186.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. Thank you.

@mdickinson mdickinson closed this Jun 4, 2020
@mdickinson mdickinson reopened this Jun 4, 2020
Copy link
Contributor

@kitchoi kitchoi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Still LGTM

@mdickinson mdickinson changed the title Fix/shadow trait notifications Fix shadow trait notifications Jun 4, 2020
@mdickinson
Copy link
Member Author

Leaving this unmerged for now; I want to give it a second self-review tomorrow morning, to check that it still makes sense to me.

@kitchoi
Copy link
Contributor

kitchoi commented Jun 4, 2020

That's probably wise... :)

@mdickinson
Copy link
Member Author

Merging this after re-review.

It's not ideal: one inelegance is that in the case of accessing the shadow trait for the first time (without first accessing the primary trait), mapped_value is called twice with the same input. But I think it's good enough for the release.

@mdickinson mdickinson merged commit e960be9 into master Jun 5, 2020
@mdickinson mdickinson deleted the fix/shadow-trait-notifications branch June 5, 2020 07:16
mdickinson added a commit that referenced this pull request Jun 5, 2020
* Remove unreachable code

* Refactor for readability

* Unwrap an unnecessarily wrapped line

* Another line unwrap

* Fix notifications from shadow traits

* Remove inappropriate reminder-to-self comment

* Additional tests for accessing shadow trait before primary trait

* Remove explicit Undefined check in _mapped_trait_default

* Flake8: remove unused import

* Additional tests (thanks to @kitchoi)

* Add changelog entry

(cherry picked from commit e960be9)
mdickinson added a commit that referenced this pull request Jun 5, 2020
* Fix truncated List description in documentation (#1178)

* Fix truncated List description in documentation

* Replace sys.maxint with sys.maxsize everywhere

* Add changelog entry

(cherry picked from commit 4e435d9)

* Tweaks and fixes to setup keywords (#1185)

* Tweaks and fixes to setup keywords

* Add changelog entry

* Fix incorrect PR number

(cherry picked from commit ff9ac19)

* Fix shadow trait notifications (#1188)

* Remove unreachable code

* Refactor for readability

* Unwrap an unnecessarily wrapped line

* Another line unwrap

* Fix notifications from shadow traits

* Remove inappropriate reminder-to-self comment

* Additional tests for accessing shadow trait before primary trait

* Remove explicit Undefined check in _mapped_trait_default

* Flake8: remove unused import

* Additional tests (thanks to @kitchoi)

* Add changelog entry

(cherry picked from commit e960be9)

* Change the 'default default' for Map and PrefixMap (#1189)

* Change the 'default default' for Map and PrefixMap

* API documentation for the default

* Add changelog entry

* Add explanatory comment

(cherry picked from commit fdcb5f8)
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.

Missing notification for shadow trait on first set of the main trait
2 participants