Inspect PyQt/PySide elements like Chrome DevTools
Source Code | 中文文档 | PyPI
For Python GUI programs developed with PyQt/PySide using Qt Widgets, it is difficult to view control information, locate the code where they are defined, and perform other operations at runtime. It's not as easy as inspecting HTML elements in Chrome/Firefox browsers. This project aims to solve this problem by providing an element inspector tool for PyQt/PySide programs, similar to Chrome's element inspector.
-
Python 3.7+
-
One of the following Qt for Python frameworks installed: PyQt5/PySide2/PyQt6/PySide6
Install with pip install PyQtInspect.
If you want to experience the latest features introduced in the master branch as soon as possible, you can install from git or download the source ZIP package and install after extraction:
Install from Git:
pip install git+https://github.com/JezaChen/PyQtInspect-Open.git
⚠️ Note: Installing directly from the default branch is not reproducible. For deterministic installs, pin to a specific tag (pip install git+https://github.com/JezaChen/PyQtInspect-Open.git@0.5.0) or commit (pip install git+https://github.com/JezaChen/PyQtInspect-Open.git@<commit-sha>).
Install from Source ZIP:
- Download the source ZIP package
- Extract the ZIP package to a local directory
- Navigate to the extracted directory and run:
pip install .Use Direct Mode to quickly attach PyQtInspect to your app. The GUI inspector will start alongside your app.
python -m PyQtInspect --direct --file path/to/your_app.py [your_app_args]The PyQtInspect architecture has two parts:
-
Debugger/Server/Inspector: A GUI app for developers to visually inspect elements, locate code, etc.
-
Debuggee/Client: Runs inside the target Python process, patches the host’s Python Qt framework, responds to the debugger, and sends host information back.
Two startup modes are supported:
-
Detached Mode: Manually start the GUI server first, then start the debuggee to connect to it. When the debuggee exits, the GUI server remains running.
-
Direct Mode (Recommended): Start only the debuggee; it will launch a local GUI server automatically (no need to start the server yourself). When the debuggee exits, the GUI server exits with it.
Note that in Direct Mode, each client (debuggee) creates its own server, i.e., a one-to-one relationship. And you cannot manually specify the listening port, close connections, or attach to processes.
Detached Mode supports remote debugging (server and client on different machines). Direct Mode does not, since the client and its auto-launched server run on the same machine.
PyQtInspect also supports running in IDEs like PyCharm and attaching to an existing PyQt/PySide process.
This recommended one-step method launches both the PyQtInspect server and client together. It requires full access to the source code of the debugged program.
If you normally run your app via python xxx.py param1 param2, simply insert -m PyQtInspect --direct --file between python and xxx.py, i.e.:
python -m PyQtInspect --direct --file xxx.py param1 param2 to start debugging with PyQtInspect.
✨ New in v0.5.0: Automatic Qt Framework Detection
PyQtInspect now automatically detects which Qt framework your application uses (PyQt5, PyQt6, PySide2, or PySide6). You no longer need to specify--qt-supportin most cases! The tool will detect and patch the appropriate framework based on the debugged program's imports.
For Direct Mode, the full command is:
python -m PyQtInspect --direct [--multiprocess] [--show-pqi-stack] [--qt-support=[auto|pyqt5|pyside2|pyqt6|pyside6]] --file py_file [file_args]Parameter meanings:
--direct: Use Direct Mode--multiprocess: Enable multi-process debugging--show-pqi-stack: Show call stacks related to PyQtInspect--qt-support: Qt framework used by the target app, defaultauto(auto-detect); choose fromauto,pyqt5,pyside2,pyqt6,pyside6--file: Path to the target app’s Python entry filefile_args: Command-line arguments for the debuggee
⚠️ Important: When relying on auto-detection, make sure the IDE’s ‘PyQt compatible’ option matches the Qt framework used by your project. A mismatch can prevent PyQtInspect from working correctly or even crash the program.If you encounter issues with auto-detection, try explicitly specifying the framework with
--qt-support.
In Detached Mode, make sure to start the GUI server before launching the debugged Python program.
Run pqi-server in a terminal to launch the server GUI. After launch, set the listening port (default 19394) and click Serve to start the server.
Prerequisite: You must have the target program’s source code.
Similar to Direct Mode, if you run an app via python xxx.py param1 param2, insert -m PyQtInspect --file between python and xxx.py (no --direct!), i.e.:
python -m PyQtInspect --file xxx.py param1 param2 to start debugging with PyQtInspect.
PyQtInspect auto-detects the Qt framework (PyQt5/PyQt6/PySide2/PySide6) by default, so --qt-support is optional unless you want to override the detection.
For running the debuggee in detached mode, the full command is:
python -m PyQtInspect [--port N] [--client hostname] [--multiprocess] [--show-pqi-stack] [--qt-support=[auto|pyqt5|pyside2|pyqt6|pyside6]] --file py_file [file_args]Parameter meanings:
--port: Server listening port (default19394)--client: Server address (default127.0.0.1)--multiprocess: Enable multi-process debugging (off by default)--show-pqi-stack: Show call stacks related to PyQtInspect (hidden by default)--qt-support: Qt framework used by the target app, defaultauto(auto-detect); choose fromauto,pyqt5,pyside2,pyqt6,pyside6--file: Path to the target app’s Python entry filefile_args: Command-line arguments for the target app
⚠️ Reminder: When relying on auto-detection, make sure the IDE’s ‘PyQt compatible’ option matches the Qt framework used by your project (PyQt5/PyQt6/PySide2/PySide6). A mismatch can prevent PyQtInspect from working correctly or even crash the program.
Debug the PyQtInspect module directly in PyCharm (or other IDEs/editors like VSCode/Cursor); this won’t interfere with debugging your app.
Also taking PyQt-Fluent-Widgets as an example, you can create a new Debug configuration like so:
Then simply Run/Debug.
If you don’t have the target app’s source code, you can try enabling inspect via process attach.
Click More → Attach To Process to open the attach window, choose the target process, then click Attach.
Note: For most controls, you cannot retrieve their creation call stacks unless they were created after you attached.
Click Select to start picking. Hover over a control to highlight it and preview basic info (class name, object name, size, relative position, styles, etc.).
Left-click to select the control. You can then inspect it in depth: view and jump to its initialization call stack, execute code in its context, view hierarchy info, view the control tree, and inspect properties.
The second tab below the basic info shows detailed properties, organized hierarchically by class inheritance and property type.
The first tab below the basic info shows the call stack at control creation. Double-click to open your configured IDE (PyCharm/VSCode/Cursor or a custom command) and navigate to the file and line.
If IDE jump fails, please configure the IDE type and executable path under More → Settings.
P.S. For clients started via Attach to Process, if the control already existed when you attached, creation info won’t be available and the call stack will be empty.
After selecting a control, click Run Snippet… to execute code in the scope of the selected control (self is the control instance; essentially this runs inside a method of the control object).
At the bottom is the hierarchy breadcrumb. You can view, highlight, and locate ancestor and child controls of the selection, making it easy to navigate the hierarchy. Combined with mouse selection, this enables more precise control picking.
(Enabled by default. To disable, go to More → Treat Right Click as Left Click When Selecting Elements and uncheck.)
Some controls only appear after a left-click. For easier picking, you can simulate left-click with the right mouse button.
P.S. This only applies while mouse selecting is active.
(Only available on Windows, enabled by default. To disable, go to More → Finish Selection with F8 and uncheck.)
For controls that are hard to pick with the mouse, press F8 to finish selection. Note that F8 only ends an ongoing selection; when selection isn’t active, pressing F8 will not start it.
Click View → Control Tree to see the control tree of the process that contains the selected control. Click (or hover) a row in the tree to highlight the corresponding control.
-
Patching fails with multiple inheritance involving more than two PyQt classes, such as class
A(B, C), whereBandCinherit from QObject. This might cause the__init__method ofCto not execute, leading to exceptions.The author of PyQt has warned against multiple inheritance with more than two PyQt classes, as it can also cause abnormal behavior in PyQt itself.
-
Cannot select some controls for PyQt6.
-
For some computers, sometimes the
QEnterEventwill have the type170(which isQEvent.DynamicPropertyChange), which may cause a crash when accessing thepropertyNamemethod.
- 🎉 Auto-Detection Support: PyQtInspect now automatically detects which Qt framework (PyQt5, PyQt6, PySide2, PySide6) your application uses - no need to specify
--qt-supportfor most applications. - IDE jump supports PyCharm, VSCode, Cursor, and custom commands, with auto-detection of IDE paths
- Some bug fixes and improvements
- Minor UI refinements
- Added the “Properties” tab
- Added toolbar entries to open/clear logs
- Fixed a series of issues










