Public bug reported: When pysignal trigger magicgui, we found regressions for all archs. The relevant part of the failures are (from [1]):
pybuild-autopkgtest 269s I: pybuild base:311: cd /tmp/autopkgtest.RWhG6j/autopkgtest_tmp/build; python3.12 -m pytest tests 270s ============================= test session starts ============================== 270s platform linux -- Python 3.12.4, pytest-7.4.4, pluggy-1.5.0 270s PyQt5 5.15.11 -- Qt runtime 5.15.13 -- Qt compiled 5.15.13 270s rootdir: /tmp/autopkgtest.RWhG6j/autopkgtest_tmp/build 270s configfile: pyproject.toml 270s plugins: qt-4.3.1, xvfb-3.0.0 270s collected 313 items / 3 skipped 270s 270s tests/test_application.py . [ 0%] 270s tests/test_backends.py s......... [ 3%] 270s tests/test_container.py .............. [ 7%] 270s tests/test_docs.py ss. [ 8%] 270s tests/test_factory.py .......... [ 12%] 270s tests/test_gui_class.py F.FFF [ 13%] 271s tests/test_magicgui.py ...................x............................. [ 29%] 271s [ 29%] 272s tests/test_persistence.py ... [ 30%] 272s tests/test_signature.py .... [ 31%] 272s tests/test_table.py ............................sss......... [ 44%] 272s tests/test_types.py ............... [ 49%] 272s tests/test_ui_field.py ..ss....ss. [ 52%] 273s tests/test_widgets.py ......s.s..ss..s.ss..ss.sss.s..s.........s......s. [ 68%] 275s s.......s..s............................................................ [ 91%] 275s .......................... [100%] 275s 275s =================================== FAILURES =================================== 275s ________________________________ test_guiclass _________________________________ 275s 275s def test_guiclass(): 275s """Test that the guiclass decorator works as expected.""" 275s mock = Mock() 275s 275s @guiclass 275s class Foo: 275s a: int = 1 275s b: str = "bar" 275s 275s @button 275s def func(self): 275s mock(asdict(self)) 275s 275s # example recommended for type checking 275s if TYPE_CHECKING: 275s gui: ClassVar[Container] 275s events: ClassVar[psygnal.SignalGroup] 275s 275s foo = Foo() 275s 275s assert foo.a == 1 275s assert foo.b == "bar" 275s 275s > assert isinstance(foo.gui, Container) 275s 275s tests/test_gui_class.py:43: 275s _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 275s /usr/lib/python3/dist-packages/magicgui/schema/_guiclass.py:233: in __get__ 275s bind_gui_to_instance(wdg, instance) 275s /usr/lib/python3/dist-packages/magicgui/schema/_guiclass.py:274: in bind_gui_to_instance 275s widget.changed.connect_setattr( 275s _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 275s 275s self = <SignalInstance 'changed' on SpinBox(value=1, annotation=<class 'int'>, name='a')> 275s obj = test_guiclass.<locals>.Foo(a=1, b='bar'), attr = 'a' 275s maxargs = <object object at 0x74ef2bd01e60> 275s 275s def connect_setattr( 275s self, 275s obj: object, 275s attr: str, 275s maxargs: int | None | object = _NULL, 275s *, 275s on_ref_error: RefErrorChoice = "warn", 275s priority: int = 0, 275s ) -> WeakCallback[None]: 275s """Bind an object attribute to the emitted value of this signal. 275s 275s Equivalent to calling `self.connect(functools.partial(setattr, obj, attr))`, 275s but with additional weakref safety (i.e. a strong reference to `obj` will not 275s be retained). The return object can be used to 275s [`disconnect()`][psygnal.SignalInstance.disconnect], (or you can use 275s [`disconnect_setattr()`][psygnal.SignalInstance.disconnect_setattr]). 275s 275s Parameters 275s ---------- 275s obj : object 275s An object. 275s attr : str 275s The name of an attribute on `obj` that should be set to the value of this 275s signal when emitted. 275s maxargs : Optional[int] 275s max number of positional args to accept 275s on_ref_error: {'raise', 'warn', 'ignore'}, optional 275s What to do if a weak reference cannot be created. If 'raise', a 275s ReferenceError will be raised. If 'warn' (default), a warning will be 275s issued and a strong-reference will be used. If 'ignore' a strong-reference 275s will be used (silently). 275s priority : int 275s The priority of the callback. This is used to determine the order in which 275s callbacks are called when multiple are connected to the same signal. 275s Higher priority callbacks are called first. Negative values are allowed. 275s The default is 0. 275s 275s Returns 275s ------- 275s Tuple 275s (weakref.ref, name, callable). Reference to the object, name of the 275s attribute, and setattr closure. Can be used to disconnect the slot. 275s 275s Raises 275s ------ 275s ValueError 275s If this is not a single-value signal 275s AttributeError 275s If `obj` has no attribute `attr`. 275s 275s Examples 275s -------- 275s >>> class T: 275s ... sig = Signal(int) 275s >>> class SomeObj: 275s ... x = 1 275s >>> t = T() 275s >>> my_obj = SomeObj() 275s >>> t.sig.connect_setattr(my_obj, "x") 275s >>> t.sig.emit(5) 275s >>> assert my_obj.x == 5 275s """ 275s if maxargs is _NULL: 275s > warnings.warn( 275s "The default value of maxargs will change from `None` to `1` in " 275s "version 0.11. To silence this warning, provide an explicit value for " 275s "maxargs (`None` for current behavior, `1` for future behavior).", 275s FutureWarning, 275s stacklevel=2, 275s ) 275s E FutureWarning: The default value of maxargs will change from `None` to `1` in version 0.11. To silence this warning, provide an explicit value for maxargs (`None` for current behavior, `1` for future behavior). 275s 275s /usr/lib/python3/dist-packages/psygnal/_signal.py:858: FutureWarning 275s __________________________ test_on_existing_dataclass __________________________ 275s 275s def test_on_existing_dataclass(): 275s """Test that the guiclass decorator works on pre-existing dataclasses.""" 275s 275s @guiclass 275s @dataclass 275s class Foo: 275s a: int = 1 275s b: str = "bar" 275s 275s foo = Foo() 275s assert foo.a == 1 275s assert foo.b == "bar" 275s > assert isinstance(foo.gui, Container) 275s 275s tests/test_gui_class.py:83: 275s _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 275s /usr/lib/python3/dist-packages/magicgui/schema/_guiclass.py:233: in __get__ 275s bind_gui_to_instance(wdg, instance) 275s /usr/lib/python3/dist-packages/magicgui/schema/_guiclass.py:274: in bind_gui_to_instance 275s widget.changed.connect_setattr( 275s _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 275s 275s self = <SignalInstance 'changed' on SpinBox(value=1, annotation=<class 'int'>, name='a')> 275s obj = test_on_existing_dataclass.<locals>.Foo(a=1, b='bar'), attr = 'a' 275s maxargs = <object object at 0x74ef2bd01e60> 275s 275s def connect_setattr( 275s self, 275s obj: object, 275s attr: str, 275s maxargs: int | None | object = _NULL, 275s *, 275s on_ref_error: RefErrorChoice = "warn", 275s priority: int = 0, 275s ) -> WeakCallback[None]: 275s """Bind an object attribute to the emitted value of this signal. 275s 275s Equivalent to calling `self.connect(functools.partial(setattr, obj, attr))`, 275s but with additional weakref safety (i.e. a strong reference to `obj` will not 275s be retained). The return object can be used to 275s [`disconnect()`][psygnal.SignalInstance.disconnect], (or you can use 275s [`disconnect_setattr()`][psygnal.SignalInstance.disconnect_setattr]). 275s 275s Parameters 275s ---------- 275s obj : object 275s An object. 275s attr : str 275s The name of an attribute on `obj` that should be set to the value of this 275s signal when emitted. 275s maxargs : Optional[int] 275s max number of positional args to accept 275s on_ref_error: {'raise', 'warn', 'ignore'}, optional 275s What to do if a weak reference cannot be created. If 'raise', a 275s ReferenceError will be raised. If 'warn' (default), a warning will be 275s issued and a strong-reference will be used. If 'ignore' a strong-reference 275s will be used (silently). 275s priority : int 275s The priority of the callback. This is used to determine the order in which 275s callbacks are called when multiple are connected to the same signal. 275s Higher priority callbacks are called first. Negative values are allowed. 275s The default is 0. 275s 275s Returns 275s ------- 275s Tuple 275s (weakref.ref, name, callable). Reference to the object, name of the 275s attribute, and setattr closure. Can be used to disconnect the slot. 275s 275s Raises 275s ------ 275s ValueError 275s If this is not a single-value signal 275s AttributeError 275s If `obj` has no attribute `attr`. 275s 275s Examples 275s -------- 275s >>> class T: 275s ... sig = Signal(int) 275s >>> class SomeObj: 275s ... x = 1 275s >>> t = T() 275s >>> my_obj = SomeObj() 275s >>> t.sig.connect_setattr(my_obj, "x") 275s >>> t.sig.emit(5) 275s >>> assert my_obj.x == 5 275s """ 275s if maxargs is _NULL: 275s > warnings.warn( 275s "The default value of maxargs will change from `None` to `1` in " 275s "version 0.11. To silence this warning, provide an explicit value for " 275s "maxargs (`None` for current behavior, `1` for future behavior).", 275s FutureWarning, 275s stacklevel=2, 275s ) 275s E FutureWarning: The default value of maxargs will change from `None` to `1` in version 0.11. To silence this warning, provide an explicit value for maxargs (`None` for current behavior, `1` for future behavior). 275s 275s /usr/lib/python3/dist-packages/psygnal/_signal.py:858: FutureWarning 275s _____________________________ test_slots_guiclass ______________________________ 275s 275s @pytest.mark.skipif(sys.version_info < (3, 10), reason="slots are python3.10 or higher") 275s def test_slots_guiclass(): 275s """Test that the guiclass decorator works as expected.""" 275s 275s psyg_v = tuple(int(x.split("r")[0]) for x in psygnal.__version__.split(".")[:3]) 275s old_psygnal = psyg_v < (0, 6, 1) 275s 275s @guiclass(slots=True) 275s class Foo: 275s a: int = 1 275s b: str = "bar" 275s 275s foo = Foo() 275s 275s with ( 275s pytest.warns(UserWarning, match="Please update psygnal") 275s if old_psygnal 275s else contextlib.nullcontext() 275s ): 275s > gui = foo.gui 275s 275s tests/test_gui_class.py:105: 275s _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 275s /usr/lib/python3/dist-packages/magicgui/schema/_guiclass.py:233: in __get__ 275s bind_gui_to_instance(wdg, instance) 275s /usr/lib/python3/dist-packages/magicgui/schema/_guiclass.py:274: in bind_gui_to_instance 275s widget.changed.connect_setattr( 275s _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 275s 275s self = <SignalInstance 'changed' on SpinBox(value=1, annotation=<class 'int'>, name='a')> 275s obj = test_slots_guiclass.<locals>.Foo(a=1, b='bar'), attr = 'a' 275s maxargs = <object object at 0x74ef2bd01e60> 275s 275s def connect_setattr( 275s self, 275s obj: object, 275s attr: str, 275s maxargs: int | None | object = _NULL, 275s *, 275s on_ref_error: RefErrorChoice = "warn", 275s priority: int = 0, 275s ) -> WeakCallback[None]: 275s """Bind an object attribute to the emitted value of this signal. 275s 275s Equivalent to calling `self.connect(functools.partial(setattr, obj, attr))`, 275s but with additional weakref safety (i.e. a strong reference to `obj` will not 275s be retained). The return object can be used to 275s [`disconnect()`][psygnal.SignalInstance.disconnect], (or you can use 275s [`disconnect_setattr()`][psygnal.SignalInstance.disconnect_setattr]). 275s 275s Parameters 275s ---------- 275s obj : object 275s An object. 275s attr : str 275s The name of an attribute on `obj` that should be set to the value of this 275s signal when emitted. 275s maxargs : Optional[int] 275s max number of positional args to accept 275s on_ref_error: {'raise', 'warn', 'ignore'}, optional 275s What to do if a weak reference cannot be created. If 'raise', a 275s ReferenceError will be raised. If 'warn' (default), a warning will be 275s issued and a strong-reference will be used. If 'ignore' a strong-reference 275s will be used (silently). 275s priority : int 275s The priority of the callback. This is used to determine the order in which 275s callbacks are called when multiple are connected to the same signal. 275s Higher priority callbacks are called first. Negative values are allowed. 275s The default is 0. 275s 275s Returns 275s ------- 275s Tuple 275s (weakref.ref, name, callable). Reference to the object, name of the 275s attribute, and setattr closure. Can be used to disconnect the slot. 275s 275s Raises 275s ------ 275s ValueError 275s If this is not a single-value signal 275s AttributeError 275s If `obj` has no attribute `attr`. 275s 275s Examples 275s -------- 275s >>> class T: 275s ... sig = Signal(int) 275s >>> class SomeObj: 275s ... x = 1 275s >>> t = T() 275s >>> my_obj = SomeObj() 275s >>> t.sig.connect_setattr(my_obj, "x") 275s >>> t.sig.emit(5) 275s >>> assert my_obj.x == 5 275s """ 275s if maxargs is _NULL: 275s > warnings.warn( 275s "The default value of maxargs will change from `None` to `1` in " 275s "version 0.11. To silence this warning, provide an explicit value for " 275s "maxargs (`None` for current behavior, `1` for future behavior).", 275s FutureWarning, 275s stacklevel=2, 275s ) 275s E FutureWarning: The default value of maxargs will change from `None` to `1` in version 0.11. To silence this warning, provide an explicit value for maxargs (`None` for current behavior, `1` for future behavior). 275s 275s /usr/lib/python3/dist-packages/psygnal/_signal.py:858: FutureWarning 275s ____________________________ test_guiclass_as_class ____________________________ 275s 275s def test_guiclass_as_class(): 275s # variant on @guiclass, using class instead of decorator 275s class T2(GuiClass): 275s x: int 275s y: str = "hi" 275s 275s @button 275s def foo(self): 275s return asdict(self) 275s 275s t2 = T2(1) 275s assert t2.x == 1 275s assert t2.y == "hi" 275s > assert t2.gui.x.value == 1 275s 275s tests/test_gui_class.py:141: 275s _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 275s /usr/lib/python3/dist-packages/magicgui/schema/_guiclass.py:233: in __get__ 275s bind_gui_to_instance(wdg, instance) 275s /usr/lib/python3/dist-packages/magicgui/schema/_guiclass.py:274: in bind_gui_to_instance 275s widget.changed.connect_setattr( 275s _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 275s 275s self = <SignalInstance 'changed' on SpinBox(value=1, annotation=<class 'int'>, name='x')> 275s obj = test_guiclass_as_class.<locals>.T2(x=1, y='hi'), attr = 'x' 275s maxargs = <object object at 0x74ef2bd01e60> 275s 275s def connect_setattr( 275s self, 275s obj: object, 275s attr: str, 275s maxargs: int | None | object = _NULL, 275s *, 275s on_ref_error: RefErrorChoice = "warn", 275s priority: int = 0, 275s ) -> WeakCallback[None]: 275s """Bind an object attribute to the emitted value of this signal. 275s 275s Equivalent to calling `self.connect(functools.partial(setattr, obj, attr))`, 275s but with additional weakref safety (i.e. a strong reference to `obj` will not 275s be retained). The return object can be used to 275s [`disconnect()`][psygnal.SignalInstance.disconnect], (or you can use 275s [`disconnect_setattr()`][psygnal.SignalInstance.disconnect_setattr]). 275s 275s Parameters 275s ---------- 275s obj : object 275s An object. 275s attr : str 275s The name of an attribute on `obj` that should be set to the value of this 275s signal when emitted. 275s maxargs : Optional[int] 275s max number of positional args to accept 275s on_ref_error: {'raise', 'warn', 'ignore'}, optional 275s What to do if a weak reference cannot be created. If 'raise', a 275s ReferenceError will be raised. If 'warn' (default), a warning will be 275s issued and a strong-reference will be used. If 'ignore' a strong-reference 275s will be used (silently). 275s priority : int 275s The priority of the callback. This is used to determine the order in which 275s callbacks are called when multiple are connected to the same signal. 275s Higher priority callbacks are called first. Negative values are allowed. 275s The default is 0. 275s 275s Returns 275s ------- 275s Tuple 275s (weakref.ref, name, callable). Reference to the object, name of the 275s attribute, and setattr closure. Can be used to disconnect the slot. 275s 275s Raises 275s ------ 275s ValueError 275s If this is not a single-value signal 275s AttributeError 275s If `obj` has no attribute `attr`. 275s 275s Examples 275s -------- 275s >>> class T: 275s ... sig = Signal(int) 275s >>> class SomeObj: 275s ... x = 1 275s >>> t = T() 275s >>> my_obj = SomeObj() 275s >>> t.sig.connect_setattr(my_obj, "x") 275s >>> t.sig.emit(5) 275s >>> assert my_obj.x == 5 275s """ 275s if maxargs is _NULL: 275s > warnings.warn( 275s "The default value of maxargs will change from `None` to `1` in " 275s "version 0.11. To silence this warning, provide an explicit value for " 275s "maxargs (`None` for current behavior, `1` for future behavior).", 275s FutureWarning, 275s stacklevel=2, 275s ) 275s E FutureWarning: The default value of maxargs will change from `None` to `1` in version 0.11. To silence this warning, provide an explicit value for maxargs (`None` for current behavior, `1` for future behavior). 275s 275s /usr/lib/python3/dist-packages/psygnal/_signal.py:858: FutureWarning 275s =========================== short test summary info ============================ 275s FAILED tests/test_gui_class.py::test_guiclass - FutureWarning: The default va... 275s FAILED tests/test_gui_class.py::test_on_existing_dataclass - FutureWarning: T... 275s FAILED tests/test_gui_class.py::test_slots_guiclass - FutureWarning: The defa... 275s FAILED tests/test_gui_class.py::test_guiclass_as_class - FutureWarning: The d... 275s ============= 4 failed, 279 passed, 32 skipped, 1 xfailed in 5.97s ============= 276s E: pybuild pybuild:389: test: plugin pyproject failed with: exit code=1: cd /tmp/autopkgtest.RWhG6j/autopkgtest_tmp/build; python3.12 -m pytest tests 276s pybuild-autopkgtest: error: pybuild --autopkgtest --test-pytest -i python{version} -p 3.12 returned exit code 13 276s make: *** [/tmp/dc8bKKY9VU/run:4: pybuild-autopkgtest] Error 25 On upstream, this test are passing [2] with pyside6 (installing from pip). I tried adding python3-pyqt and python3-pyqt6 to d/control to see if this overcomes it and mimic the upstream's actions [3], with no luck [1] https://objectstorage.prodstack5.canonical.com/swift/v1/AUTH_0f9aae918d5b4744bf7b827671c86842/autopkgtest-oracular/oracular/amd64/m/magicgui/20240804_072247_72842@/log.gz [2] https://github.com/pyapp-kit/magicgui/actions/runs/10240968558/job/28328574711 [3] https://github.com/pyapp-kit/magicgui/actions/runs/10240968558/workflow ** Affects: magicgui (Ubuntu) Importance: Undecided Status: New ** Affects: magicgui (Debian) Importance: Unknown Status: Unknown ** Tags: update-excuse ** Bug watch added: Debian Bug tracker #1074724 https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1074724 ** Also affects: magicgui (Debian) via https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1074724 Importance: Unknown Status: Unknown -- You received this bug notification because you are a member of Ubuntu Bugs, which is subscribed to Ubuntu. https://bugs.launchpad.net/bugs/2076095 Title: Tests failing with python 3.12 To manage notifications about this bug go to: https://bugs.launchpad.net/ubuntu/+source/magicgui/+bug/2076095/+subscriptions -- ubuntu-bugs mailing list ubuntu-bugs@lists.ubuntu.com https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs