0

Problem:

I'm trying to figure out the best method to handle unhandled exceptions that usually get suppressed by PyQt.

My solution right now is to decorate appropriate methods with the following decorator

def handleExceptions(func):
    """
    Decorator: create and show message box for every unhandled exception that
    reaches the decorator
    """
    @functools.wraps(func)
    def decorator(self):
        try:
            func(self)
        except Exception as error:

            # ...

            if errBox.exec_() == QMessageBox.Ok:
                try:
                    self.closeApp()
                except AttributeError:
                    exit()

    return decorator

However this solution only works if none of the decorated methods require more parameters than self. I tried extending the decorator like this

...
def decorator(self, *args)
    try:
        func(self, *args)
...

This allows calling functions with one or more parameters (including self). Unfortunately this code breaks access to methods which require no parameter except self which fail with the message TypeError: method() takes 1 positional argument but 2 were given.

After using a debugger I figured out that the second parameter in *args seems to be a bool (False).

Questions:

  1. Why does this additional parameter get passed?
  2. How can the decorator be modified to allow usage with functions of varying parameter lengths?
  3. Is this even a good way to handle exceptions? I would be grateful if someone could tell me the usual method to deal with unhandled exceptions in PyQt.

I looked up other solutions like this one (which I don't fully understant) and tried to implement them without success (it either throws exceptions like my one or breaks the decorated methods completely).

Thanks in advance!

Community
  • 1
  • 1
  • A decorator seems horribly overcomplicated and difficult to maintain. The [other answer](http://www.riverbankcomputing.com/news) in the question you linked to suggests using an [excepthook](http://docs.python.org/3/library/sys.html#sys.excepthook). I don't know why anyone would consider using anything else, given how simple it is to implement. – ekhumoro Oct 21 '16 at 22:47

1 Answers1

0

While I agree with the comment that excepthook is probably the way to go, here is something similar I did once:

def handle_exception_decorator(exceptions_to_catch = (ValueError, IndexError, TypeError), return_on_fail=False):
    def wrap(fn):
        @functools.wraps(fn)
        def f(*args, **kwargs):
            try:
                return fn(*args, **kwargs)
            except tuple(exceptions_to_catch) as e:
                # handle the exception here:
                return return_on_fail
        return f
    return wrap

Decorate your methods with:

@handle_exception_decorator

or

@handle_exception_decorator(exceptions_to_catch=(AnExceptionType,))

or

@handle_exception_decorator(exceptions_to_catch=(Exception,), return_on_fail=7)    

etc...

EDIT: Oh, actually I think your issue is because the method you are decorating is a slot connected to a signal, and your slot is ignoring one of the arguments the signal emits. The only way to fix that is to update the decorated function to accept an optional keyword argument that takes the parameter emitted by the signal. You of course don't have to use it in your method, you just need the method signature to match what the signal will emit (Qt usually gracefully handles this, but decorators like this mess that up!)

three_pineapples
  • 11,579
  • 5
  • 38
  • 75