zapretgui/tests/test_qt_signal_links.py
loop-uh 2352c31303
Some checks failed
Windows-сборка / Dev Dev 21.1.7.171 опубликован
Zapret source guards / validate (push) Has been cancelled
Стрелка «назад» снова работает: подписки снимаются по квитанции, а не по обработчику
Жалоба 15.10.2026: на «Тексте профиля» стрелка «назад» ничего не делала,
а Alt+← работал. Причина: в сборке Nuitka отписка по методу
(signal.disconnect(obj.method)) не находит подписку — метод там при каждом
обращении новый объект compiled_method; ошибка глоталась. У стрелки
оставались два обработчика: библиотечный qrouter.pop переключал страницу,
журнал тут же возвращал её обратно. Из исходников всё работало, поэтому
стенд не ловил. Проверено на win10 модулем, собранным Nuitka: отписка по
методу — «is not connected», 2 обработчика; по квитанции — 1.

- utils/qt_signal_links: подписка снимается по объекту соединения,
  который вернул connect() (disconnect_link, SignalLinks).
- Стрелка «назад»: отвязываются все прежние обработчики, библиотечный
  список страниц выключен целиком; если обработчиков не один — ошибка в
  журнале.
- Те же молчаливые отписки в сборке исправлены везде: всплывающие меню и
  выпадающие списки (обработчики копились с каждым меню), страницы
  оркестратора (каждая настройка добавляла по обработчику), Telegram Proxy,
  подписка Premium, проверка текста профиля, списки и анимация строк,
  подсказка стратегий. Карточки больше не получают вторую подписку на
  смену темы: библиотека её в конструкторе не создаёт.
- architecture_checks запрещает отписку по обработчику.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 22:41:30 +03:00

64 lines
2.2 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Подписки снимаются по квитанции connect(), а не по обработчику.
В сборке Nuitka метод объекта при каждом обращении — новый объект, PyQt его
не узнаёт, и ``signal.disconnect(self.on_x)`` молча оставлял обработчик.
Здесь это изображает обработчик, который каждый раз новый: квитанция
снимает подписку и тогда.
"""
from __future__ import annotations
import os
import unittest
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
from PyQt6.QtCore import QObject, pyqtSignal
from utils.qt_signal_links import SignalLinks, disconnect_link
class _Source(QObject):
fired = pyqtSignal()
class QtSignalLinksTests(unittest.TestCase):
def test_link_removes_handler_that_cannot_be_recognized_again(self) -> None:
source = _Source()
calls = []
link = source.fired.connect(lambda: calls.append(1))
# Обработчик «по имени» снять нечем: тот же код — уже другой объект.
with self.assertRaises(TypeError):
source.fired.disconnect(lambda: calls.append(1))
disconnect_link(link)
source.fired.emit()
self.assertEqual(calls, [])
self.assertEqual(source.receivers(source.fired), 0)
def test_empty_or_repeated_link_is_not_an_error(self) -> None:
source = _Source()
link = source.fired.connect(lambda: None)
disconnect_link(link)
disconnect_link(link)
disconnect_link(None)
self.assertEqual(source.receivers(source.fired), 0)
def test_group_removes_only_its_own_links(self) -> None:
source = _Source()
calls = []
links = SignalLinks()
links.connect(source.fired, lambda: calls.append("mine"))
links.connect(source.fired, lambda: calls.append("mine too"))
source.fired.connect(lambda: calls.append("someone else"))
links.disconnect_all()
source.fired.emit()
self.assertEqual(calls, ["someone else"])
self.assertEqual(len(links), 0)
if __name__ == "__main__":
unittest.main()