diff --git a/doc/release_notes/release_3.17.md b/doc/release_notes/release_3.17.md index 368d33d..5fcd522 100644 --- a/doc/release_notes/release_3.17.md +++ b/doc/release_notes/release_3.17.md @@ -14,6 +14,7 @@ * **Application startup blocked by a corrupted translation file** — when a `.mo` translation catalog was corrupted or unreadable (e.g. truncated during installation), importing guidata failed with an error such as `OSError: Bad magic number`. The same applied to any application relying on `guidata.configtools.get_translation`, like PlotPy, Sigima or DataLab, so the application could not start at all. The interface now falls back to English, and a `RuntimeWarning` identifies the faulty catalog (fixes [Issue #119](https://github.com/PlotPyStack/guidata/issues/119)). * **Error when editing a dictionary field in a JSON Schema based form** — in a form generated with `guidata.dataset.dataset_to_schema` (e.g. in a web frontend), editing a `DictItem` field failed with `TypeError: DictItem.__dictedit() missing 1 required positional argument: 'parent'`: the button opening the dictionary editor in the Qt interface was handled as a callback updating the other fields. `DictItem` fields are no longer flagged with `x-guidata-has-callback`, and `resolve_dataset_callbacks` returns an empty mapping for them (fixes [Issue #123](https://github.com/PlotPyStack/guidata/issues/123)). * **Date/time callback never called** — the `display` callback of a `DateTimeItem` was never called when the date or time was changed in a dataset editor, so that the values computed from it were not updated. The callback is now called on each change, with the new value of the item (a `datetime.datetime` object), like for the other items (fixes [Issue #123](https://github.com/PlotPyStack/guidata/issues/123)). +* **Date callback received a Qt object** — the `display` callback of a `DateItem` received a Qt `QDateTime` object, whose type depends on the Qt binding (PyQt5, PyQt6 or PySide6), instead of the value of the item. It now receives the new value of the item (a `datetime.date` object), like the other items. Callbacks relying on the previous `QDateTime` argument must be updated (fixes [Issue #126](https://github.com/PlotPyStack/guidata/issues/126)). * **Plain-text "about" information** — `guidata.widgets.about.about(html=False)` (and `AboutInfo.about(html=False)`) failed with `UnboundLocalError` instead of returning the information about the package as plain text (fixes [Issue #123](https://github.com/PlotPyStack/guidata/issues/123)). * **French translations of the DataFrame editor** — when entering a number format not starting with `%`, the French error message stated the opposite of the actual rule ("must not start with '%'"), and the title of the export dialog box was shown in English. Both are now correctly translated (fixes [Issue #123](https://github.com/PlotPyStack/guidata/issues/123)). diff --git a/guidata/dataset/qtitemwidgets.py b/guidata/dataset/qtitemwidgets.py index 743d1c6..a118a1c 100644 --- a/guidata/dataset/qtitemwidgets.py +++ b/guidata/dataset/qtitemwidgets.py @@ -757,9 +757,10 @@ def __init__( qt_fmt = convert_date_format(fmt) self.dateedit.setDisplayFormat(qt_fmt) - def date_changed(self, value): - """Date changed""" - _display_callback(self, value) + def date_changed(self, _value) -> None: + """Date changed (the ``QDateTime`` argument is ignored: the callback + receives the Python value of the widget)""" + _display_callback(self, self.value()) self.notify_value_change() def get(self) -> None: diff --git a/guidata/tests/unit/test_datetime_display_callback.py b/guidata/tests/unit/test_datetime_display_callback.py index 09dec3b..731f151 100644 --- a/guidata/tests/unit/test_datetime_display_callback.py +++ b/guidata/tests/unit/test_datetime_display_callback.py @@ -4,10 +4,11 @@ # (see guidata/LICENSE for details) """ -Test the display callback of DateTimeItem +Test the display callbacks of DateItem and DateTimeItem -When the date/time is changed in a dataset editor, the ``display`` callback of a -``DateTimeItem`` must be called with the Python value of the item (``datetime``). +When the date (or date/time) is changed in a dataset editor, the ``display`` +callback of a ``DateItem`` (or ``DateTimeItem``) must be called with the Python +value of the item (``date`` or ``datetime``), not with a Qt object. """ from __future__ import annotations @@ -18,11 +19,41 @@ from qtpy import QtWidgets as QW from guidata.dataset import DataSet -from guidata.dataset.dataitems import DateTimeItem +from guidata.dataset.dataitems import DateItem, DateTimeItem from guidata.dataset.qtwidgets import DataSetEditLayout from guidata.qthelpers import qt_app_context +def test_date_display_callback() -> None: + """Changing the date calls the display callback with a date""" + calls = [] + + def callback(instance: DataSet, _item: DateItem, value) -> None: + """Record the callback value and the dataset value""" + calls.append((value, instance.date)) + + class _DateDataSet(DataSet): + """Dataset with a date item having a display callback""" + + date = DateItem("Date", default=datetime.date(2010, 10, 10)).set_prop( + "display", callback=callback + ) + + with qt_app_context(): + dialog = QW.QDialog() + dataset = _DateDataSet() + layout = DataSetEditLayout(dialog, dataset, QW.QGridLayout(dialog)) + try: + (widget,) = layout.get_terminal_widgets() + calls.clear() + widget.dateedit.setDate(QC.QDate(2024, 1, 2)) + expected = datetime.date(2024, 1, 2) + assert calls == [(expected, expected)] + assert type(calls[0][0]) is datetime.date + finally: + dialog.deleteLater() + + def test_datetime_display_callback() -> None: """Changing the date/time calls the display callback with a datetime""" calls = []