diff --git a/HISTORY.md b/HISTORY.md index a2753c6b..7cbfbc1b 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -19,6 +19,13 @@ --> # Version History +- 0.2.195 - Cancel CapsuleButton ``_animate_id`` callbacks during tab detachment to + avoid repeated button images and ``invalid command name`` errors when + closing roots. + - Extend ``cancel_after_events`` to handle identifiers suffixed with + ``_animate_id`` or ``_after_id``. + - Add regression test covering cleanup when ``after info`` for a + widget is unavailable. - 0.2.194 - Clone widgets using keyword configuration to respect CapsuleButton's signature and preserve options like cursor. - Add regression test ensuring cursor configuration copies correctly. diff --git a/README.md b/README.md index e777e36c..38df345c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -version: 0.2.194 +version: 0.2.195 Author: Miguel Marina - [LinkedIn](https://www.linkedin.com/in/progman32/) # AutoML diff --git a/gui/utils/closable_notebook.py b/gui/utils/closable_notebook.py index eaae6d10..8315b99a 100644 --- a/gui/utils/closable_notebook.py +++ b/gui/utils/closable_notebook.py @@ -90,7 +90,9 @@ def _cancel_ident(ident: str) -> None: try: for name in dir(widget): - if name.endswith(("_anim", "_after", "_timer", "_animate")): + if name.endswith( + ("_anim", "_after", "_timer", "_animate", "_animate_id", "_after_id") + ): ident = getattr(widget, name, None) if isinstance(ident, str) and ident not in cancelled: _cancel_ident(ident) diff --git a/mainappsrc/version.py b/mainappsrc/version.py index 33a121ca..47849f30 100644 --- a/mainappsrc/version.py +++ b/mainappsrc/version.py @@ -18,6 +18,6 @@ """Project version information.""" -VERSION = "0.2.194" +VERSION = "0.2.195" __all__ = ["VERSION"] diff --git a/tests/detachment/after_callbacks/test_capsule_button_animate_cleanup.py b/tests/detachment/after_callbacks/test_capsule_button_animate_cleanup.py index 9072a21a..309f0421 100644 --- a/tests/detachment/after_callbacks/test_capsule_button_animate_cleanup.py +++ b/tests/detachment/after_callbacks/test_capsule_button_animate_cleanup.py @@ -79,3 +79,26 @@ def test_close_clears_animate(self, monkeypatch): root.update() assert "_animate" not in str(root.tk.call("after", "info")) root.destroy() + + def test_detach_clears_animate_without_after_info(self, monkeypatch): + root = tk.Tk(); root.withdraw() + nb = ClosableNotebook(root) + btn = self.AnimatedButton(nb) + nb.add(btn, text="Tab") + nb.update_idletasks() + + orig_call = btn.tk.call + + def fake_call(*args): + if args[:3] == ("after", "info", str(btn)): + raise tk.TclError("unsupported") + return orig_call(*args) + + monkeypatch.setattr(btn.tk, "call", fake_call) + + self._detach(nb, monkeypatch) + root.update() + assert "_animate" not in str(root.tk.call("after", "info")) + win = nb._floating_windows[0] + win.destroy() + root.destroy()