Philip
Philip

Reputation: 1921

How can I monkey patch PyQT's QApplication.notify() to time events

In our PyQt application we want to time the duration of all Qt Events. Only in a special performance monitoring mode. Previously I subclassed QApplication and overrode the notify() method and that worked great. I wrote the data in chrome://tracing format and it was super helpful.

However when our application is run inside Jupyter there is a pre-existing QApplication instance. So I can't think of how to make it use my subclass.

Instead I tried monkey patching below, but my notify() is never called. I suspect notify() is a wrapped C++ method and it can't be monkey patched?

def monkey_patch_event_timing(app: QApplication):
    original_notify = app.notify

    def notify_with_timing(self, receiver, event):
        timer_name = _get_timer_name(receiver, event)

        # Time the event while we handle it.
        with perf.perf_timer(timer_name, "qt_event"):
            return original_notify(receiver, event)

    bound_notify = MethodType(notify_with_timing, app)

    # Check if we are already patched first.
    if not hasattr(app, '_myproject_event_timing'):
        print("Enabling Qt Event timing...")
        app.notify = bound_notify
        app._myproject_event_timing = True

Is there a way to monkey patch QApplication.notify or otherwise insert code somewhere that can time every Qt Event?

Upvotes: 2

Views: 386

Answers (1)

eyllanesc
eyllanesc

Reputation: 244202

A possible solution is to remove the old QApplication with the help of sip and create a new one:

def monkey_patch_event_timing():

    app = QApplication.instance()
    if app is not None:
        import sip
        sip.delete(app)

    class MyApplication(QApplication):
        def notify(self, receiver, event):
            ret = QApplication.notify(self, receiver, event)
            print(ret, receiver, event)
            return ret

    app = MyApplication([])
    return app

Upvotes: 2

Related Questions