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

Convert on_trait_change decorators to observe decorators #864

Merged
merged 32 commits into from
Feb 1, 2021

Conversation

aaronayres35
Copy link
Contributor

@aaronayres35 aaronayres35 commented Jan 22, 2021

part of #732
also part of #637

This PR incrementally (effectively 1 file per commit) replaces all uses of the @on_trait_change decorator with the equivalent form of @observe.

Additionally, it removes any explicit use of setting comparison_mode as that is no longer needed with traits 6.2

Since traits 6.2 eggs are not on edm yet, I suspect CI will fail(? or at least give the comparison mode warnings), but very soon that will no longer occur. Looks like we also still have CI running with traits6.0 so it does fail
Looks like travis is also having failures that seem to stem from changes made to i_data_view_widget. Those changes were mostly to do with comparison_mode and I did not see them locally, so I'm suspecting they will be resolved with traits 6.2 (🤞 )

…nd tasks_application.py because it calls a super on one of the handlers so they needed to be updated togeter. Also specify comparaison mode to avoid warning (is this correct?)
…alled independently of change handling so I pass None as the event)
self._set_dock_title()
self._set_floating()
self._set_visible()
self._set_dock_features(None)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

When calling the change handlers independently (without a change actually occurring) they now need to take an event argument. If it is unused, as it is for these handlers I simply passed in None.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry for snooping... don't know if you have considered defining _set_dock_features like this?

def _set_dock_features(self, _=None):
    ...

Then the signature of the function is more explicit about that fact that the argument is not used.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That makes more sense, thanks!

# This should not throw
layout._qt4_active_editor_changed(None, None)
layout._qt4_active_editor_changed(DummyEvent(new=None))
Copy link
Contributor Author

Choose a reason for hiding this comment

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

similar to https://github.com/enthought/pyface/pull/864/files#r562936818 only here the handler was called with arguments. the handler must take a single event argument, and in the previous case we needed the new argument for the old signature to be None. So here I simply created a dummy class to serve the same purpose. This is a bit of a smell though

@@ -849,16 +849,15 @@ def _views_items_changed(self, event):

# Dynamic ----

@on_trait_change("layout.editor_closed")
def _on_editor_closed(self, editor):
@observe("layout:editor_closed")
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I believe the . from before was a bug and should have been a :. It seems from the handler itself that it was assumed editor was in fact an IEditor instance as we ultimately call self.editors.index(editor). Without this change I was not seeming test failuires, but exceptions were being raised in test_workbench_window.py saying a MagicMock instance was not in self.editors.

This made me learn a new behavior of otc. Previously, when we set workbench_window.layout = mock.MagicMock(spec=WorkbenchWindowLayout) this handler was invoked. However, by modifying the signature I saw that name was actually editor_closed not layout even though layout was changing. This caused the editor argument to come up as Undefined when running the test thus avoiding the self.editors.index(editor) line. When we make the switch, event.name is now layout not editor_changed and so event.new != Undefined as one might have suspected based on what happened before.

I'm not sure if this is explicitly documented in the old otc docs? Or if this is a bug? In any case I believe the new code is correct

""" Handle the destruction of the wrapper. """
if name == "control" and new is None:
self._wrappers.remove(object)
if event.new is None:
Copy link
Contributor Author

Choose a reason for hiding this comment

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

there are a decent number of cases like this, where previously we used . not : but then only do something when the second trait is the one changed?

With these types of changes the tests were all still passing and I believe behavior is preserved (code is cleaner IMO as well), but if we want to play it safe or if a reviewer sees why these might not be equivalent, I am happy to adjust

Copy link
Contributor

@rahulporuri rahulporuri left a comment

Choose a reason for hiding this comment

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

Marking this a request changes because there was one bug (missing event argument to method decorated with observe).

Apart from that, this PR LGTM. But, I'd prefer it if we can test these changes against some other project e.g. traitsui or an internal project to see if any errors are raised.

examples/application/python_editor/python_editor_task.py Outdated Show resolved Hide resolved
examples/tasks/advanced/example_task.py Outdated Show resolved Hide resolved
examples/tasks/basic/example_task.py Outdated Show resolved Hide resolved
pyface/ui/qt4/tasks/editor_area_pane.py Outdated Show resolved Hide resolved
pyface/ui/qt4/tasks/editor_area_pane.py Outdated Show resolved Hide resolved
pyface/ui/qt4/tasks/split_editor_area_pane.py Outdated Show resolved Hide resolved
pyface/ui/qt4/workbench/workbench_window_layout.py Outdated Show resolved Hide resolved
pyface/ui/wx/tasks/dock_pane.py Outdated Show resolved Hide resolved
pyface/ui/wx/tasks/editor_area_pane.py Outdated Show resolved Hide resolved
@rahulporuri
Copy link
Contributor

I ran the testsuite locally (windows) with the pyqt5 toolkit and i did not see any test failures.

@rahulporuri
Copy link
Contributor

Also, just to confirm, you'll be opening a separate PR to address the other uses of on_trait_change e.g. object.on_trait_change(...). Is that correct? I'm happy if that's the plan - given how big this PR already is.

@aaronayres35
Copy link
Contributor Author

Also, just to confirm, you'll be opening a separate PR to address the other uses of on_trait_change e.g. object.on_trait_change(...). Is that correct? I'm happy if that's the plan - given how big this PR already is.

yep that was the plan, and possibly first opening a separate PR to address the first bullet of #732.

@rahulporuri
Copy link
Contributor

rahulporuri commented Jan 27, 2021

I restarted CI but Travis CI isn't completely happy. Looks like #865 needs to be merged first - and then this PR needs to be updated - to make CI happy.

@aaronayres35
Copy link
Contributor Author

aaronayres35 commented Jan 27, 2021

CI is now passing with #865 merged. Going to checkout this branch and run traitsui test suite now

EDIT: Done, I did not see any new errors from this branch compared to master (I ran testsuite with pyqt5 and wx)

@rahulporuri rahulporuri self-requested a review January 27, 2021 13:47
Copy link
Contributor

@rahulporuri rahulporuri left a comment

Choose a reason for hiding this comment

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

LGTM.

I apologize for the large number of suggestions at the last minute. Almost all of them are _=None changes - it would be best to ensure that we are using this convention wherever it is relevant.

Please batch all of the suggestions into a single commit to prevent spamming this PR with 27 commits - one per suggestion made in this review :D

pyface/gui_application.py Outdated Show resolved Hide resolved
pyface/gui_application.py Outdated Show resolved Hide resolved
pyface/tests/test_gui_application.py Outdated Show resolved Hide resolved
pyface/ui/qt4/tasks/advanced_editor_area_pane.py Outdated Show resolved Hide resolved
pyface/ui/qt4/tasks/advanced_editor_area_pane.py Outdated Show resolved Hide resolved
@rahulporuri
Copy link
Contributor

rahulporuri commented Jan 28, 2021

@kitchoi @aaronayres35 _=None is not standard python and we have been recommended against using it - we could use event=None instead, if not just event.

Update : On further thought, let's just leave it as event instead of using event=None either. There is no need to complicate this further.

@rahulporuri
Copy link
Contributor

@mdickinson ^

@aaronayres35
Copy link
Contributor Author

@kitchoi @aaronayres35 _=None is not standard python and we have been recommended against using it - we could use event=None instead, if not just event.

Update : On further thought, let's just leave it as event instead of using event=None either. There is no need to complicate this further.

There are some occasions where the methods are called explicitly, independently of any listening to changes. I take that the suggestion then (at least for now / on this PR) is to when we call those methods explicitly pass None as the event there rather than having it as a default? Long term we will probably want to transition to Robert's solution of redefining the methods that will be called separately as normal methods and then calling those within the listening handlers

Co-authored-by: Poruri Sai Rahul <rporuri@enthought.com>
Copy link
Contributor

@rahulporuri rahulporuri left a comment

Choose a reason for hiding this comment

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

LGTM with two necessary code changes (undiscovered bugs) and a lot of style changes (from _=None to event).

pyface/ui/qt4/tasks/dock_pane.py Outdated Show resolved Hide resolved
pyface/ui/qt4/tasks/dock_pane.py Outdated Show resolved Hide resolved
pyface/ui/qt4/tasks/dock_pane.py Outdated Show resolved Hide resolved
pyface/ui/qt4/tasks/dock_pane.py Outdated Show resolved Hide resolved
pyface/ui/qt4/tasks/dock_pane.py Outdated Show resolved Hide resolved
pyface/ui/qt4/tasks/editor_area_pane.py Outdated Show resolved Hide resolved
pyface/ui/wx/tasks/editor_area_pane.py Outdated Show resolved Hide resolved
pyface/workbench/action/view_menu_manager.py Outdated Show resolved Hide resolved
pyface/workbench/debug/debug_view.py Outdated Show resolved Hide resolved
aaronayres35 and others added 3 commits February 1, 2021 08:54
@aaronayres35
Copy link
Contributor Author

I've opened #876 for dealing with the refactor/cleanup of cases where we call handlers standalone and pass event=None. I think I will make those fixes in a separate PR.

@mdickinson mdickinson changed the title Convert otc decorators to observe decorators Convert on_trait_change decorators to observe decorators Feb 1, 2021
@rahulporuri
Copy link
Contributor

CI is green and still LGTM

@aaronayres35 aaronayres35 merged commit a38976c into master Feb 1, 2021
@aaronayres35 aaronayres35 deleted the convert-otc-decorators-to-observe branch February 1, 2021 16:46
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.

4 participants