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

Don't use html for a variable name when using html module from standard library #1540

Merged
merged 18 commits into from
Mar 26, 2021

Conversation

aaronayres35
Copy link
Contributor

@aaronayres35 aaronayres35 commented Mar 15, 2021

fixes #1538

Previously we were using the html module from the python standard library in a function, as well as defining a local variable html that held on to the html content to be used to create an HTMLHelpWindow instance. This PR adds a very simple test to showcase the bug, and fixes it by giving the html variable a new name html_content. Additionally, I changed the import statement to only import what we need from html. Namely, from html import escape. Either of these fixes would work alone (it may be overkill to do them both), but I figured it couldn't hurt.

@aaronayres35
Copy link
Contributor Author

aaronayres35 commented Mar 16, 2021

CI is stalling on the new tests but I am unable to reproduce locally. I thought it may have been an issue from the Modal Dialog, but I am not sure. It also seems to be OS/toolkit specific? In some cases the test runs fine on CI.

I will investigate more tomorrow

@rahulporuri rahulporuri self-requested a review March 19, 2021 03:43
@aaronayres35
Copy link
Contributor Author

aaronayres35 commented Mar 22, 2021

I was able to reproduce the test suite hanging on an Ubuntu machine. Investigating more now

Edit:
The test does not hang if I only run the single test module, ie. python -m unittest traitsui/tests/test_ui_panel.py but it does if I run the whole test suite

@aaronayres35
Copy link
Contributor Author

aaronayres35 commented Mar 22, 2021

I got this working locally on Ubuntu, but I had to force the help dialog to be modal... :/ which we very well may want to avoid. The help window that pops up is blocking the test, however it is not modal so trying to us modal dialog tester did not work. However if I call exec_ instead of show the dialog is modal and the test works exactly as expected. See:
https://srinikom.github.io/pyside-docs/PySide/QtGui/QDialog.html#PySide.QtGui.PySide.QtGui.QDialog.exec_

This is a change in behavior and so should probably be avoided.

I am unsure how to resolve this test hanging without this...
I tried to simply close the original window by clicking ok while the help window was up, but that proved unsuccessful.
I will keep looking for an alternative

EDIT: Looks like its still occurring with pyqt. Locally I had reproduced and resolved the issue with pyqt5 using what I described above.

Also to clarify, this is purely a testing issue at this point. Behavior is as expected with the fixes in this PR (aside from the change to exec_ which causes the change in behavior of the help window now being modal). Investigating this has turned into a bit of a time sink, so I think I will pause and come back to this later

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 a few comments/caveat. I tested this with the code from #1538 - and it works as expected.

traitsui/qt4/ui_panel.py Show resolved Hide resolved
traitsui/qt4/ui_panel.py Outdated Show resolved Hide resolved
traitsui/wx/ui_panel.py Show resolved Hide resolved
@rahulporuri rahulporuri self-requested a review March 23, 2021 12:35
Comment on lines +85 to +87
class MyTester(ModalDialogTester):
def get_dialog_widget(self):
return self._qt_app.activeWindow()
Copy link
Contributor Author

Choose a reason for hiding this comment

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

FWIW the test passed for me on mac and ubuntu locally without this but without this the call of x.click_button(OK) effectively ends up doing nothing as we are trying to call a method on None.

This way we are actually closing the window we open which feels like the right thing to do.

The real cause of the test hang I believe was not having auto_process_events=False. I should have realized this much faster than I did. Previously I had only remembered this being necessary when using UITester inside the use of the ModalDialogTester callback.
For example:

@unittest.skipIf(no_modal_dialog_tester, "ModalDialogTester unavailable")
def test_simple_editor_modal(self):
# Test launching the instance editor with kind set to 'modal'
obj = ObjectWithInstance()
ui_tester = UITester()
with ui_tester.create_ui(obj, dict(view=modal_view)) as ui:
def click_button():
ui_tester.find_by_name(ui, "inst").perform(MouseClick())
def when_opened(tester):
with tester.capture_error():
try:
dialog_ui = tester.get_dialog_widget()._ui
# If auto_process_events was not set to false, this
# will block due to deadlocks with ModalDialogTester.
ui_tester = UITester(auto_process_events=False)
value = ui_tester.find_by_name(dialog_ui, "value")
value.perform(KeySequence("Hello"))
self.assertEqual(obj.inst.value, "")
ok_button = ui_tester.find_by_id(dialog_ui, "OK")
ok_button.perform(MouseClick())
finally:
# If the block above fails, the dialog will block
# forever. Close it regardless.
if tester.get_dialog_widget() is not None:
tester.close(accept=True)
mdtester = ModalDialogTester(click_button)
mdtester.open_and_run(when_opened=when_opened)
self.assertTrue(mdtester.dialog_was_opened)
self.assertEqual(obj.inst.value, "Hello")

In cases where we just use UI Tester to trigger the dialog being opened, it has not been needed (until now at least AFAICR)
e.g.

@unittest.skipIf(no_modal_dialog_tester, "ModalDialogTester unavailable")
class TestButtonEditorDemo(unittest.TestCase):
def test_button_editor_demo(self):
demo = runpy.run_path(DEMO_PATH)["demo"]
tester = UITester()
with tester.create_ui(demo) as ui:
simple_button = tester.find_by_id(ui, "simple")
custom_button = tester.find_by_id(ui, "custom")
# funcion object for instantiating ModalDialogTester should be a
# function that opens the dialog
# we want clicking the buttons to do that
def click_simple_button():
simple_button.perform(MouseClick())
def click_custom_button():
custom_button.perform(MouseClick())
mdtester_simple = ModalDialogTester(click_simple_button)
mdtester_simple.open_and_run(lambda x: x.click_button(OK))
self.assertTrue(mdtester_simple.dialog_was_opened)
mdtester_custom = ModalDialogTester(click_custom_button)
mdtester_custom.open_and_run(lambda x: x.click_button(OK))
self.assertTrue(mdtester_custom.dialog_was_opened)

Nonetheless, this test does what we want it to now and test suite seems to not be hanging

Copy link
Member

Choose a reason for hiding this comment

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

But now this test is Qt-specific, without being marked as such

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 think it implicitly will be skipped if there is no qt as modal dialog tester only exists for qt currently, but you are right we should definitely be explicit here in saying this is a very qt specific test.
Will update this now

Copy link
Member

@jwiggins jwiggins left a comment

Choose a reason for hiding this comment

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

Mostly looks OK, but the test is Qt-only

traitsui/qt4/ui_panel.py Show resolved Hide resolved
traitsui/qt4/tests/test_ui_panel.py Outdated Show resolved Hide resolved
Comment on lines +85 to +87
class MyTester(ModalDialogTester):
def get_dialog_widget(self):
return self._qt_app.activeWindow()
Copy link
Member

Choose a reason for hiding this comment

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

But now this test is Qt-specific, without being marked as such

traitsui/wx/ui_panel.py Show resolved Hide resolved
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

@aaronayres35
Copy link
Contributor Author

aaronayres35 commented Mar 26, 2021

CI is failing with:

======================================================================
FAIL: test_qt_process_events_process_all (traitsui.testing.tests.test_gui.TestProcessEventsRepeated)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "D:\a\traitsui\traitsui\.edm\envs\traitsui-test-3.6-pyqt5\lib\site-packages\traitsui\testing\tests\test_gui.py", line 154, in test_qt_process_events_process_all
    self.assertEqual(n_left_behind_events, 0, msg)
AssertionError: 8 != 0 : Expected 10 events processed on the objects and zero events left on the queue after running process_cascade_events. Found 2 processed with 8 left behind.

----------------------------------------------------------------------

I believe we have/had an issue open related to this intermittent failure. Looking for issue number now #951

2 CI runs in a row now :/ it appears this is happening more frequently

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.

Help Button issue
3 participants