0

I'm running an application made with PyQt that basically reads information from an OPC server and updates a plot every time new data comes in.

I would like to be able to safely disconnect from the OPC server every time the application is closed. This includes the user manually closing the window and any runtime error that might occur. It would be something like this:

from opcua import Client
from matplotlib.backends.qt_compat import QtWidgets

class ApplicationWindow_Realtime(QtWidgets.QMainWindow):      
    def __init__(self, parent=None):
        super(ApplicationWindow_Realtime, self).__init__(parent)
        self.opc_url = 'opc.tcp://127.0.0.1:53530/UA/Sim'
        self.opc_initialize()

        ## DO STUFF

    ## Connect to OPC
    def opc_initialize(self):
        self.client = Client(self.opc_url)
        self.client.connect()

    ## OTHER METHODS

    # Disconnect if window is closed
    def closeEvent(self, event):
        self.client.disconnect()

I want to know if there is some way to call self.client.disconnect() if any error occurs in runtime when running the application. I found this question but the accepted answer starts with "Warning: if you want something like this, it's likely you don't... but if you really want to...", so I'm not sure if this is the right way to tackle the problem.

Tendero
  • 1,136
  • 2
  • 19
  • 34
  • You should probably separate the code that implements your interface from the code that executes your application logic. Instead of connecting to the client from within `__init__`, initialize the connection in the same place that you create the window. – chepner Sep 06 '18 at 15:35
  • @chepner I'm creating the window from another window (its parent). Is it possible then to treat from the original window exceptions that were raised in the child window? – Tendero Sep 06 '18 at 15:42
  • 2
    Exceptions percolate up the run-time call stack; where methods are defined isn't really important. – chepner Sep 06 '18 at 15:51
  • @chepner But how can I catch any exception that has been raised? I only know of the `try ... except...` way. Is this the way to go, with the child creation in the `try` block only? – Tendero Sep 06 '18 at 15:53

1 Answers1

0

I would do something similar to the answer you linked but I would define it within the class itself.

from functools import wraps

def _emergency_disconnect(the_func):
    @wraps(the_func)
    def wrapper(*args, **kwargs):
        output = None
        try:
            output = the_func(*args, **kwargs)
        except:
            #args[0] will always be self
            args[0].client.disconnect()
        if output != None:
            return output
    return wrapper

Then you can decorate your functions with it

@_emergency_disconnect
def myFunction(myArg):
    pass

This will cause self.client.disconnect() to be called whenever a method call results in an error.

Simon
  • 855
  • 9
  • 24