diff --git a/CHANGELOG.md b/CHANGELOG.md index 18526c3..7b38913 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,13 +5,6 @@ All notable changes to wuttaweb will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). -## v0.20.4 (2025-01-15) - -### Fix - -- add `WuttaDateWidget` and associated logic -- add `serialize_object()` method for `ObjectRef` schema node - ## v0.20.3 (2025-01-14) ### Fix diff --git a/pyproject.toml b/pyproject.toml index 8858f8a..7798cb3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "hatchling.build" [project] name = "WuttaWeb" -version = "0.20.4" +version = "0.20.3" description = "Web App for Wutta Framework" readme = "README.md" authors = [{name = "Lance Edgar", email = "lance@wuttaproject.org"}] diff --git a/src/wuttaweb/forms/base.py b/src/wuttaweb/forms/base.py index edd1e2d..c9567bc 100644 --- a/src/wuttaweb/forms/base.py +++ b/src/wuttaweb/forms/base.py @@ -546,13 +546,10 @@ class Form: This is generally only possible if :attr:`model_class` is set to a valid SQLAlchemy mapped class. - This only checks for a couple of data types, with mapping as - follows: - - * :class:`sqlalchemy:sqlalchemy.types.Date` -> - :class:`~wuttaweb.forms.widgets.WuttaDateWidget` - * :class:`sqlalchemy:sqlalchemy.types.DateTime` -> - :class:`~wuttaweb.forms.widgets.WuttaDateTimeWidget` + As of writing this only looks for + :class:`sqlalchemy:sqlalchemy.types.DateTime` fields and if + any are found, they are configured to use + :class:`~wuttaweb.forms.widgets.WuttaDateTimeWidget()`. """ from wuttaweb.forms import widgets @@ -568,9 +565,8 @@ class Form: prop = getattr(attr, 'prop', None) if prop and isinstance(prop, orm.ColumnProperty): column = prop.columns[0] - if isinstance(column.type, sa.Date): - self.set_widget(key, widgets.WuttaDateWidget(self.request)) - elif isinstance(column.type, sa.DateTime): + if isinstance(column.type, sa.DateTime): + # self.set_renderer(key, self.render_datetime) self.set_widget(key, widgets.WuttaDateTimeWidget(self.request)) def set_grid(self, key, grid): diff --git a/src/wuttaweb/forms/schema.py b/src/wuttaweb/forms/schema.py index 77e443e..b3f0105 100644 --- a/src/wuttaweb/forms/schema.py +++ b/src/wuttaweb/forms/schema.py @@ -334,21 +334,8 @@ class ObjectRef(colander.SchemaType): # nb. keep a ref to this for later use node.model_instance = appstruct - # serialize to PK as string - return self.serialize_object(appstruct) - - def serialize_object(self, obj): - """ - Serialize the given object to its primary key as string. - - Default logic assumes the object has a UUID; subclass can - override as needed. - - :param obj: Object reference for the node. - - :returns: Object primary key as string. - """ - return obj.uuid.hex + # serialize to uuid + return appstruct.uuid.hex def deserialize(self, node, cstruct): """ """ @@ -430,7 +417,7 @@ class ObjectRef(colander.SchemaType): if 'values' not in kwargs: query = self.get_query() objects = query.all() - values = [(self.serialize_object(obj), str(obj)) + values = [(obj.uuid.hex, str(obj)) for obj in objects] if self.empty_option: values.insert(0, self.empty_option) diff --git a/src/wuttaweb/forms/widgets.py b/src/wuttaweb/forms/widgets.py index f87e8b1..1d3035c 100644 --- a/src/wuttaweb/forms/widgets.py +++ b/src/wuttaweb/forms/widgets.py @@ -36,7 +36,6 @@ in the namespace: * :class:`deform:deform.widget.CheckboxWidget` * :class:`deform:deform.widget.SelectWidget` * :class:`deform:deform.widget.CheckboxChoiceWidget` -* :class:`deform:deform.widget.DateInputWidget` * :class:`deform:deform.widget.DateTimeInputWidget` * :class:`deform:deform.widget.MoneyInputWidget` """ @@ -50,7 +49,7 @@ import humanize from deform.widget import (Widget, TextInputWidget, TextAreaWidget, PasswordWidget, CheckedPasswordWidget, CheckboxWidget, SelectWidget, CheckboxChoiceWidget, - DateInputWidget, DateTimeInputWidget, MoneyInputWidget) + DateTimeInputWidget, MoneyInputWidget) from webhelpers2.html import HTML from wuttjamaican.conf import parse_list @@ -154,43 +153,6 @@ class WuttaCheckboxChoiceWidget(CheckboxChoiceWidget): self.app = self.config.get_app() -class WuttaDateWidget(DateInputWidget): - """ - Custom widget for :class:`python:datetime.date` fields. - - The main purpose of this widget is to leverage - :meth:`~wuttjamaican:wuttjamaican.app.AppHandler.render_date()` - for the readonly display. - - It is automatically used for SQLAlchemy mapped classes where the - field maps to a :class:`sqlalchemy:sqlalchemy.types.Date` column. - For other (non-mapped) date fields, or mapped datetime fields for - which a date widget is preferred, use - :meth:`~wuttaweb.forms.base.Form.set_widget()`. - - This is a subclass of - :class:`deform:deform.widget.DateInputWidget` and uses these - Deform templates: - - * ``dateinput`` - """ - - def __init__(self, request, *args, **kwargs): - super().__init__(*args, **kwargs) - self.request = request - self.config = self.request.wutta_config - self.app = self.config.get_app() - - def serialize(self, field, cstruct, **kw): - """ """ - readonly = kw.get('readonly', self.readonly) - if readonly and cstruct: - dt = datetime.datetime.fromisoformat(cstruct) - return self.app.render_date(dt) - - return super().serialize(field, cstruct, **kw) - - class WuttaDateTimeWidget(DateTimeInputWidget): """ Custom widget for :class:`python:datetime.datetime` fields. diff --git a/tests/forms/test_base.py b/tests/forms/test_base.py index bc229eb..914c9f7 100644 --- a/tests/forms/test_base.py +++ b/tests/forms/test_base.py @@ -3,8 +3,6 @@ from unittest import TestCase from unittest.mock import MagicMock, patch -import sqlalchemy as sa - import colander import deform from pyramid import testing @@ -190,18 +188,6 @@ class TestForm(TestCase): self.assertIn('created', form.widgets) self.assertIsInstance(form.widgets['created'], MyWidget) - # mock up a table with all relevant column types - class Whatever(model.Base): - __tablename__ = 'whatever' - id = sa.Column(sa.Integer(), primary_key=True) - date = sa.Column(sa.Date()) - date_time = sa.Column(sa.DateTime()) - - # widget set for all known types - form = self.make_form(model_class=Whatever) - self.assertIsInstance(form.widgets['date'], widgets.WuttaDateWidget) - self.assertIsInstance(form.widgets['date_time'], widgets.WuttaDateTimeWidget) - def test_set_grid(self): form = self.make_form(fields=['foo', 'bar']) self.assertNotIn('foo', form.widgets) diff --git a/tests/forms/test_widgets.py b/tests/forms/test_widgets.py index e571b88..4874c25 100644 --- a/tests/forms/test_widgets.py +++ b/tests/forms/test_widgets.py @@ -87,46 +87,6 @@ class TestObjectRefWidget(WebTestCase): self.assertNotIn('url', values) -class TestWuttaDateWidget(WebTestCase): - - def make_field(self, node, **kwargs): - # TODO: not sure why default renderer is in use even though - # pyramid_deform was included in setup? but this works.. - kwargs.setdefault('renderer', deform.Form.default_renderer) - return deform.Field(node, **kwargs) - - def make_widget(self, **kwargs): - return mod.WuttaDateWidget(self.request, **kwargs) - - def test_serialize(self): - node = colander.SchemaNode(colander.Date()) - field = self.make_field(node) - - # first try normal date - widget = self.make_widget() - dt = datetime.date(2025, 1, 15) - - # editable widget has normal picker html - result = widget.serialize(field, str(dt)) - self.assertIn('