Search code examples
pythonpython-3.xexceptiondecorator

How to use decorator, defined inside the class, with no warnings


I've defined decorator inside the class and trying to use it in the same class.
I've created the decorator according to this topic. But PyCharm tells me, that this is veeery sus way to do this.
Here is the code:

import sys
from typing import Callable


class TestClass:
    def __init__(self):
        self.smile = ':P'

    def handle_exception(func: Callable):
        def handle_exception_wrapper(self=None, *args, **kwargs):
            try:
                func(self, *args, **kwargs)
                return self.shutdown()
            except Exception as error:
                self.shutdown(error)

        return handle_exception_wrapper

    @handle_exception
    def some_function(self) -> None:
        print('some suspicious function is working')
        raise RuntimeError('Break Runtime - all be fine')
    
    def shutdown(error=None):
        if error:
            print('error:', error)
            print('function collapsed')
        else:
            print('good-boy function completed the task')
        print('goodbye', self.smile)
        sys.exit(1)

    


test = TestClass()
test.some_function()

And IDE warnings: IDE warniings

And this code works (bc of decorator passing a class object quietly). But looks kinda sus and "inPEPful".

Long story short, is it possible to define and use decorator inside the class beautifully? (One thing is important that I want to access class methods inside the decorator).


Solution

  • I won't confidently tell you that this does what you want it to, but you can fix the PyCharm errors by making handle_exception a static method, and adding a self argument to shutdown and a newline at the end. Here is the file, PyCharm warning-free version:

    import sys
    from typing import Callable
    
    
    class TestClass:
        def __init__(self):
            self.smile = ':P'
    
        @staticmethod
        def handle_exception(func: Callable):
            def handle_exception_wrapper(self, *args, **kwargs):
                try:
                    func(self, *args, **kwargs)
                    return self.shutdown()
                except Exception as error:
                    self.shutdown(error)
    
            return handle_exception_wrapper
    
        @handle_exception
        def some_function(self) -> None:
            print('some suspicious function is working')
            raise RuntimeError('Break Runtime - all be fine')
    
        def shutdown(self, error=None):
            if error:
                print('error:', error)
                print('function collapsed')
            else:
                print('good-boy function completed the task')
            print('goodbye', self.smile)
            sys.exit(1)
    
    
    test = TestClass()
    test.some_function()
    
    

    Tested on PyCharm 2023.3.4 Community Edition, Python 3.11.7 on Windows 11.