Multithreaded python application not hitting breakpoints in Visual Studio
Asked Answered
P

3

9

I am currently developing a PyQt application in Visual Studio. Debugging has been working great, until I decided to keep my UI responsive by moving stuff to a worker thread with Qt Threads.

class MainWindow(base, form):

    start_work = QtCore.pyqtSignal()

    def __init__(self, parent=None):
        # Create a seperate thread in which the update information is polled.
        self.thread = QtCore.QThread()
        # Create Worker object and move it to new thread
        self.worker = Worker()
        self.worker.moveToThread(self.thread)
        # connect signal to start work in the extra tread
        self.start_work.connect(self.worker.get_work_done)
        self.thread.start()

    #function emit a signal to start doing the work
    def do_work(self):
        self.startWork.emit()

Any function that is invoked on my worker object is connected via signal slots

class Worker(QtCore.QObject):
    @QtCore.pyqtSlot()
    def get_work_done(self):
        #lets do some time consuming work.

The code works fine. The only problem is now, I cannot debug anything that is happening inside get_work_done. Visual studio won't break at those breakpoints.

When I break inside any MainWindow function, the Visual Studio Debugger shows only one thread. It seems unaware of any other threads created by the application.

Pantograph answered 14/4, 2015 at 19:26 Comment(0)
C
8

As said already all threads not created using Python need to be registered with PTVS. To do this for a QThread, call this in the threads run method:

import pydevd;pydevd.settrace(suspend=False)

Some more info here: Can I put break points on background threads in Python?

Crystalcrystalline answered 12/5, 2019 at 3:26 Comment(0)
A
2

Debugger needs to play some tricks to detect new threads and set up its hooks (which are needed to hit breakpoints etc). It does so by hijacking the standard Python _thread module. If you're creating the threads in some way that circumvents that module altogether, which is what I suspect Qt does here, the debugger will not be aware of those threads.

Try using the standard threading module instead of QThread, and see if that helps.

Amaranthaceous answered 14/4, 2015 at 20:5 Comment(3)
If I use the regular threading module, I cannot use the signal and slot mechanism to communicate between the threads. This is why I would like to make use of Qt threading. There is no way to make the debugger aware of those threads?Pantograph
Have the same problem in Python for .Net... the thread is created in a .net module somwhere, and calling an event in Python. Need to be able to force the hooks somehow??Kiowa
There's no good generic solution to this, unfortunately, short of trying to support what every specific library does. You can hack the code for the debugger (visualstudio_py_debugger.py) to add such support, and perhaps it could be made extensible to make this easier. Feel free to file all of these on github.com/Microsoft/PTVSAmaranthaceous
H
0

When worker and moveToThread are used, just wrapping QThread.run() may not be enough:

class QTracedThread(QThread):
    @override
    def run(self):
        pydevd.settrace(suspend=False)
        super().run()

To get everything covered by tracing, it was also necessary for me to wrap a worker object entry slot:

# worker.moveToThread(traced_thread)
# traced_thread.started.connect(worker.run)

class QWorker(QObject):
    @Slot()
    def run(self):
        pydevd.settrace(suspend=False)
        ...

Specifically, traced_thread.run was emitted after traced_thread.started and this was the point of trace switching. Especially related to QTimer(parent=worker) timeouts. Changing parents can reduce need for the both traces, but not to the point when one of settrace stops to be useful.

Huskamp answered 11/7 at 5:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.