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

How to catch QtBindingsNotFoundError #412

Closed
cbrnr opened this issue Mar 16, 2023 · 9 comments · Fixed by #413
Closed

How to catch QtBindingsNotFoundError #412

cbrnr opened this issue Mar 16, 2023 · 9 comments · Fixed by #413

Comments

@cbrnr
Copy link
Contributor

cbrnr commented Mar 16, 2023

This is perhaps a stupid question, but assuming I have only qtpy installed and no Qt bindings – how am I supposed to catch the QtBindingsNotFoundError for import qtpy?

@CAM-Gerlach
Copy link
Member

CAM-Gerlach commented Mar 16, 2023

Good question!

As of now, you could try-except the import qtpy line catching RuntimeError, which QtBindingsNotFoundError subclasses, i.e.

try:
    import QtPy
except RuntimeError:
    ...

The only other error raised by qtpy.__init__ that subclasses this error class are the checks for incompatible Qt binding versions, which are conceptually similar in nature; it being raised by a the bindings themselves on import seems unlikely, but not impossible (and still likely traceable to a similar cause, broken or incompatible bindings installed).

If you want to be sure that the error class is that specific one, you can get the error message class from the type() of the exception object, and use e.g. string comparison from that:

try:
    import QtPy
except RuntimeError as error:
    if type(error).__name__ == "QtBindingsNotFoundError":
        ...
    else:
        raise

A bit inelegant, but gets the job done.

To note, since the error is fundamentally an ImportError, we should probably add ImportError to the bases of QtBindingsNotFoundError. Then you'd be able to catch that specific error, and those directly conceptually tied to it, with the more precise and idiomatic

try:
    import QtPy
except ImportError:
    ...

To note, in your code, you'd want to except ModuleNotFoundError first if you want to handle the case where QtPy itself was not found, rather than a binding (or you could use the same pattern as the above).

Would you like to submit a PR?

@dalthviz , any other ideas here?

@ccordoba12
Copy link
Member

To note, since the error is fundamentally an ImportError, we should probably add ImportError to the bases of QtBindingsNotFoundError

I agree with this. And perhaps we should make QtBindingsNotFoundError only inherit from ImportError?

@cbrnr
Copy link
Contributor Author

cbrnr commented Mar 16, 2023

I think inheriting from ImportError is a great idea! I can submit a PR.

The other option would be to let users import qtpy without any exception, and raise the QtBindingsNotFoundError at a later point.

@CAM-Gerlach
Copy link
Member

And perhaps we should make QtBindingsNotFoundError only inherit from ImportError?

Hmm, fair question, In terms of ideal purity, perhaps it could be argued yeah, but it would at minimum break compatibility with existing code checking for it, including via the required workaround as mentioned here. Furthermore, it would require one of the following:

  • QtBindingsNotFoundError not inherit from PythonQtError, which would introduce more substantial backward compat breakage, and would mean there's no longer a common QtPy error superclass)
  • Not have PythonQtError inherit Exception instead of RuntimeError, which would also break backward compatibility with existing code checking for any of the latter instead of either of the former—which could be added back to the subclasses, which would avoid most but not all breakage, increase verbosity and change the MRO
  • Complicate the QtPy exception hierarchy further with another layer of superclasses (making things more complex for us and users)

And even conceptually it's a wash, since it is still at least arguably a runtime error (a compatible Qt runtime either not being installed, or not initializing correctly, and/or the runtime configuration not being set to select the correct Qt binding). Therefore, I recommend we leave that as it is, as the cost is too large and the benefit too minimal to justify a change.

The other option would be to let users import qtpy without any exception, and raise the QtBindingsNotFoundError at a later point.

That's what we more or less did before, but it resulted in a bunch of code duplication, fragility, user difficulty and the other issues discussed in issue #367 and fixed in PR #379, with some followup refinements, whereas it was difficult to find much of a use case for exposing just a few constants, exception classes and minor helpers if no binding is available, given the cost and issues involved.

@ccordoba12
Copy link
Member

Therefore, I recommend we leave that as it is, as the cost is too large and the benefit too minimal to justify a change.

Ok, no problem.

@cbrnr
Copy link
Contributor Author

cbrnr commented Mar 16, 2023

So you are saying you don't want to change anything and users have to catch a RuntimeError? Or base QtBindingsNotFoundError on both RuntimeError and ImportError?

@CAM-Gerlach
Copy link
Member

So you are saying you don't want to change anything and users have to catch a RuntimeError? Or base QtBindingsNotFoundError on both RuntimeError and ImportError?

The latter, sorry.

@dalthviz dalthviz added this to the v2.3.1 milestone Mar 16, 2023
@dalthviz
Copy link
Member

Should we also add some documentation about this on the README? Like a section about possible exceptions that qtpy could raise and a suggested way on how to handle them?

@CAM-Gerlach
Copy link
Member

Yeah, that would be a good idea—#395 includes your suggestion of documenting the exception hierarchy, and from this we could include the suggested workarounds from my post above. I just haven't quite found the time yet between my research, teaching and various FOSS responsibilities, sorry.

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

Successfully merging a pull request may close this issue.

4 participants