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 KeyError when calling pyblish_qml.show() more than once #365

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

jboisvertrodeofx
Copy link
Contributor

@jboisvertrodeofx jboisvertrodeofx commented May 21, 2020

It seems that since pyblish-qml-1.9.6, a KeyError is raised when calling pyblish_qml.show() more than once if pyblish.api.deregister_all_callbacks() is called before the second call.

This is the stack trace:

# Traceback (most recent call last):
#   File "<maya console>", line 148, in <module>
#   File "/softwareLocal/rez_python_envs/shared/2.7.16/0xb578cca6b312bb8d/lib/python2.7/site-packages/pyblish_qml/__init__.py", line 21, in show
#     return host.show(parent, targets, modal, auto_publish, auto_validate)
#   File "/softwareLocal/rez_python_envs/shared/2.7.16/0xb578cca6b312bb8d/lib/python2.7/site-packages/pyblish_qml/host.py", line 107, in show
#     install(modal)
#   File "/softwareLocal/rez_python_envs/shared/2.7.16/0xb578cca6b312bb8d/lib/python2.7/site-packages/pyblish_qml/host.py", line 63, in install
#     uninstall()
#   File "/softwareLocal/rez_python_envs/shared/2.7.16/0xb578cca6b312bb8d/lib/python2.7/site-packages/pyblish_qml/host.py", line 75, in uninstall
#     uninstall_callbacks()
#   File "/softwareLocal/rez_python_envs/shared/2.7.16/0xb578cca6b312bb8d/lib/python2.7/site-packages/pyblish_qml/host.py", line 194, in uninstall_callbacks
#     pyblish.api.deregister_callback("instanceToggled", _toggle_instance)
#   File "/softwareLocal/rez_python_envs/shared/2.7.16/0xb578cca6b312bb8d/lib/python2.7/site-packages/pyblish/plugin.py", line 910, in deregister_callback
#     _registered_callbacks[signal].remove(callback)
# KeyError: 'instanceToggled' # 

I believe this is this the commit that exposed the issue: e4dacaa

I've seen in other places of the code that we deal with this case with a simple try/except, so I've the done the same in my fix here.

@jboisvertrodeofx
Copy link
Contributor Author

jboisvertrodeofx commented May 22, 2020

Code sample to replicate the issue:

import pyblish.api
import pyblish_qml

server = pyblish_qml.show()
server.wait()

pyblish.api.deregister_all_callbacks()
server = pyblish_qml.show()
server.wait()

@mottosso
Copy link
Member

Thanks for this @jboisvertrodeofx, and for hunting down the original cause. And for the replicable. But this doesn't seem like the right way to go. :/ I think you've identified the actual cause, install() being called multiple times to force an event handler to get installed.

Install was initially meant to be called by the user. It's designed as a one-off. It got rather consistent that you always call this whenever you show the GUI, so we made it automatic. But now that automation has become a problem, and the solution should be to to silence the warnings.

This isn't what you signed up for, but if you are able, I would much rather we revert that commit you found, for install() to conveniently and automatically get called if it hasn't already been called, and put the install of the event handler into the show() function explicitly. That's the only one that should get uninstalled when the GUI goes dormant, because it's a performance hog. It's an optimisation.

Let me know what you think.

@jboisvertrodeofx
Copy link
Contributor Author

Hey @mottosso thanks for the quick feedback!

Just to see if I understanding correctly, you'd add a call to install_callbacks directly in the host.show function, but you'd remove the call to install_callbacks from host.install, along with reverting the 1.9.6 commit that removed the check to see if host.install was previously called?

If that's the case, I think it could somewhat work, but one small issue I would see is that we'd have to add a check to see if the callbacks were previously installed before re-installing them, because pyblish.api.register_callback can append the same callback multiple times and it seems like we wouldn't be calling host.uninstall anymore.

@mottosso
Copy link
Member

Yes, I think so.

  1. On show()
  2. Install event handler

Along with..

  1. On installing the event handler..
  2. First uninstall any already installed

And finally..

  1. On close of window..
  2. Uninstall event handler

That way, it'll be guaranteed to be installed whenever the GUI is visible, and most likely be uninstalled whenever it's closed. The exception being crashes or such, when the close event is lost. But that's a fine compromise, as it would be uninstalled the next time around, and ultimately is just an optimisation that won't harm the overall function of the DCC.

@jboisvertrodeofx
Copy link
Contributor Author

I just committed a WIP, so it will be easier to explain.

There seems to be a side effect to reverting the e4dacaa commit, where QtHost.uninstall() will then only be called the first time host.show() is called, because QtHost.state seems diverge from the standalone _state at some point, and so the pyblishQmlClose and pyblishQmlCloseForced callbacks are not added the subsequent times.

I was planning on re-using QtHost.uninstall() to call uninstall_callbacks(), but maybe you had a different idea in mind?

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.

2 participants