PyQt6 on Python 3.14: emitting None through a pyqtSignal changes the refcount of None (immortal)
Darren Powierski
darren.powierski at tmeic.com.au
Mon Oct 19 06:11:49 BST 2026
Rename test file.
Thank you
From: Darren Powierski
Sent: Monday, 19 October 2026 4:06 PM
To: 'pyqt at riverbankcomputing.com' <pyqt at riverbankcomputing.com>
Subject: PyQt6 on Python 3.14: emitting None through a pyqtSignal changes the refcount of None (immortal)
Hello,
On Python 3.14, emitting a signal that carries None in an `object` argument changes the reference count of None. None is immortal since Python 3.12, so its refcount should never change. With identical PyQt6, Qt and sip packages on Python 3.13 the count is unchanged.
Environment
- Windows x64, embeddable Python distributions
- Python 3.14.5 (bug) and Python 3.13.16 (no bug)
- PyQt6 6.11.0, PyQt6-Qt6 6.11.1, PyQt6_sip 13.11.1
- Same result with PyQt6_sip 13.13.0
Reproducer (attached: repro_none_refcount.py)
It creates a QObject with pyqtSignal(str, object, object), connects it to a pyqtSlot, emits ("k", None, None) 100,000 times, and reads the raw refcount of None through ctypes before and after.
Result
- Python 3.13.16: delta 0 (RESULT: OK)
- Python 3.14.5: delta +200,000, i.e. 2 None args x 100,000 emits (RESULT: BUG)
Other observations on Python 3.14.5, from a longer test that I can supply
- Queued cross-thread emit of (str, None, None), 50,000 emits: +150,100
- QTimer.singleShot(0, lambda: None), 100,000 calls: +20
- No change for json.dumps with None, importing PyQt6, creating QApplication, or QPointF/QRect/QColor
Possible impact (suspected, not proven)
In a long-running application on 3.14, after several hours we saw a TypeError raised from json.dumps before any network I/O, then "__init__() should return None, not NoneType", then worker threads stuck. The same application ran about 33 hours on 3.13.16 with no errors. I have not shown that the refcount change causes these failures.
Questions
1. Is the refcount change in PyQt6 or in PyQt6_sip?
2. Is a change planned for Python 3.14 immortal objects?
3. Is there a recommended workaround, other than avoiding None in signals declared with object?
Attachments: repro_none_refcount.py, repro_output_3_13_16.txt, repro_output_3_14_5.txt
Thank you,
Darren Powierski
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20261019/d64a2d7e/attachment.htm>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: repro_none_refcount._py
Type: application/octet-stream
Size: 1243 bytes
Desc: repro_none_refcount._py
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20261019/d64a2d7e/attachment.obj>
More information about the PyQt
mailing list