Skip to content

fix: PyQt6 migration completion and crash fixes across frontend and NGHDL#521

Open
VaradhaCodes wants to merge 2 commits into
FOSSEE:masterfrom
VaradhaCodes:fix/pyqt6-migration-and-bugfixes
Open

fix: PyQt6 migration completion and crash fixes across frontend and NGHDL#521
VaradhaCodes wants to merge 2 commits into
FOSSEE:masterfrom
VaradhaCodes:fix/pyqt6-migration-and-bugfixes

Conversation

@VaradhaCodes
Copy link
Copy Markdown
Contributor

Context

PR #498 migrated PyQt5 to PyQt6 and got merged. The stated testing was "main window and workspace initialization". That's it. No simulation, no KicadtoNgspice, no NGHDL, no model editor -- just the app opening.

As a result, most of the actual features were broken on the merged branch. This PR goes through them one by one. Every crash listed below was triggered by actually using the feature and testing it.

src/ngspiceSimulation/ module is handled separately in the companion PR.


Crashes fixed (in order of how bad they were)

1. NGHDL model upload hangs and never finishes

QProcess.start("make install") passes the full string as the program name in Qt6 -- the args need to be a separate list. So make install was silently hanging. On top of that, readAllStandard was reading self.process instead of self.sender(), so if you tried twice in the same session it would read from the wrong process and crash. make install was also being called immediately instead of waiting for make to finish.

Fixed: start(prog, [args]) split, signals connected before start(), make install sequenced via finished signal, slot reads self.sender().

nghdl/src/ngspice_ghdl.py

2. NgVeri refresh button causes segfault

The toggle QThread was calling option.setStyleSheet() directly from the background thread. Touching Qt GUI objects from a non-main thread is undefined behaviour and causes random segfaults. Separately, the watchdog on_modified handler was creating and calling QErrorMessage from watchdog's thread, same problem.

Fixed: pyqtSignal(str) bridge in toggle so style changes go through the main thread. Same for the modified dialog. Added proper closeEvent to stop threads and observer on widget close.

src/maker/Maker.py

3. Simulation plot doesn't open after ngspice finishes

plotSimulationData was declared (self, exitCode, exitStatus) but QProcess.finished emits (exitCode: int, exitStatus: QProcess.ExitStatus) -- the two args are in that order. The slot had them reversed, so it was receiving the enum as an int and vice versa. In PyQt6 the type checking is stricter so it fails silently.

src/frontEnd/Application.py

4. KicadtoNgspice has stale data from previous session

TrackWidget stores everything at the class level (shared across instances). The reset at the start of each conversion only cleared 3 of the 14 attributes. So if you opened KicadtoNgspice, closed it, and opened it again for a different schematic, it would mix in subcircuit/model data from the previous run.

Fixed: added TrackWidget.reset() classmethod that resets all 14 attributes, called at the start of each conversion.

src/kicadtoNgspice/TrackWidget.py, KicadtoNgspice.py

5. KicadtoNgspice crashes on netlists with simple DC sources

words[3] was accessed directly without checking len(words). A plain DC source line doesn't have a 4th token, so IndexError was crashing the entire window.

src/kicadtoNgspice/Processing.py

6. Analysis panel crashes loading saved simulations

root[x][y].text returns None when an XML element is empty. This was passed directly to setText() and findText(), both of which crash on None. Also setCurrentIndex was called with -1 (what findText returns on no match), which resets the combo to blank.

Added or "" on all text reads and if index >= 0 before setCurrentIndex.

src/kicadtoNgspice/Analysis.py

7. KicadtoNgspice crashes on empty unit string in conversion

scientificConversion accessed string_obj[0] without checking for empty string. Added early return.

src/kicadtoNgspice/Convert.py

8. TerminalUi fails to load when launched from a different working directory

uic.loadUi("TerminalUi.ui") resolves relative to whatever the process CWD happens to be. Fixed to use os.path.dirname(__file__).

Also: self.Flag = "Flase" was a string instead of a bool.

src/frontEnd/TerminalUi.py

9. Startup crash when workspace.txt is empty or truncated

readline().split(' ', 1) on an empty file raises ValueError on unpack. Only IOError was caught, so a corrupted workspace.txt would abort startup entirely.

src/configuration/Appconfig.py

10. TimeExplorer crashes on snapshot operations when no project is open

clear_snapshots and restore_snapshot would proceed with an empty project name, build a bad path, and crash.

src/frontEnd/TimeExplorer.py

11. NewProject continues executing after permission error dialog

After showing "no write permission" dialog, the function was missing return None, None, so it would fall through and try to create the project anyway.

src/projManagement/newProject.py

12. ProjectExplorer: stray msg.exec() always executes after snapshot

A msg.exec() call was left at the wrong indentation level after a refactor, outside the if block, so it would pop a dialog every time regardless of outcome.

src/frontEnd/ProjectExplorer.py


PyQt5 to PyQt6 renames that #498 missed

These are the things that actually needed fixing beyond what the original PR did:

  • QMessageBox.Ok / Cancel --> QMessageBox.StandardButton.Ok / StandardButton.Cancel, with | for multiple buttons (not a tuple)
  • QPalette.Base --> QPalette.ColorRole.Base
  • QLineEdit.Normal --> QLineEdit.EchoMode.Normal
  • QFileDialog.AnyFile --> QFileDialog.FileMode.AnyFile
  • combo.activated[str].connect(...) --> combo.currentTextChanged.connect(...) -- PyQt6 dropped the indexed signal syntax entirely; this was the most common breakage
  • process.pid() --> process.processId()
  • PyQt5 imports still present in createKicadLibrary.py, ngspice_ghdl.py, TimeExplorer.py

Other fixes found along the way

These weren't from #498 but showed up while testing:

  • nghdl/src/createKicadLibrary.py, ngspice_ghdl.py: contributor's personal Mac file paths and Mac venv shebang were hardcoded in the Linux fallback. Replaced with /usr/share/kicad/symbols/eSim_Nghdl.kicad_sym and #!/usr/bin/env python3.
  • nghdl/src/model_generation.py: home directory was computed via os.path.abspath(__file__, "..", "..") instead of os.path.expanduser('~'), pointing at the wrong directory.
  • NGHDL upload button now disables during processing and re-enables on finish. createSchematicLib wrapped in try/except with error dialog so failures don't disappear silently. Upload button now validates that a file is selected before proceeding.

Closes #497 (properly this time).

…netlist lines

Malformed SPICE component lines with fewer tokens than expected caused
IndexError crashes when opening KiCad→Ngspice converter. Added len(words)
guards on all five device branches (q, d, j, s, m) — short lines are
silently skipped, consistent with existing try/except BaseException patterns.

Triggered by SN55451B netlist where diode lines had only 2 tokens (D2 __D2).
@VaradhaCodes VaradhaCodes changed the title Fix/pyqt6 migration and bugfixes fix: PyQt6 migration completion and crash fixes across frontend and NGHDL Jun 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Migrate GUI framework from PyQt5 to PyQt6

1 participant