From eda2326a97c8a4d3c4f23a72a578a24efae8b6cf Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Wed, 11 Dec 2024 23:05:25 -0600 Subject: [PATCH] fix: add way to set field widgets using pseudo-type more to come on this idea hopefully..i think it's a good pattern? --- src/wuttaweb/forms/base.py | 45 +++++++++++++++++++++++++++++++--- src/wuttaweb/views/upgrades.py | 3 +-- tests/forms/test_base.py | 20 +++++++++++++++ 3 files changed, 63 insertions(+), 5 deletions(-) diff --git a/src/wuttaweb/forms/base.py b/src/wuttaweb/forms/base.py index 83cd069..9caed35 100644 --- a/src/wuttaweb/forms/base.py +++ b/src/wuttaweb/forms/base.py @@ -457,23 +457,62 @@ class Form: if self.schema: self.schema[key] = node - def set_widget(self, key, widget): + def set_widget(self, key, widget, **kwargs): """ Set/override the widget for a field. + You can specify a widget instance or else a named "type" of + widget, in which case that is passed along to + :meth:`make_widget()`. + :param key: Name of field. - :param widget: Instance of - :class:`deform:deform.widget.Widget`. + :param widget: Either a :class:`deform:deform.widget.Widget` + instance, or else a widget "type" name. + + :param \**kwargs: Any remaining kwargs are passed along to + :meth:`make_widget()` - if applicable. Widget overrides are tracked via :attr:`widgets`. """ + if not isinstance(widget, deform.widget.Widget): + widget_obj = self.make_widget(widget, **kwargs) + if not widget_obj: + raise ValueError(f"widget type not supported: {widget}") + widget = widget_obj + self.widgets[key] = widget # update schema if necessary if self.schema and key in self.schema: self.schema[key].widget = widget + def make_widget(self, widget_type, **kwargs): + """ + Make and return a new field widget of the given type. + + This has built-in support for the following types (although + subclass can override as needed): + + * ``'notes'`` => :class:`~wuttaweb.forms.widgets.NotesWidget` + + See also :meth:`set_widget()` which may call this method + automatically. + + :param widget_type: Which of the above (or custom) widget + type to create. + + :param \**kwargs: Remaining kwargs are passed as-is to the + widget factory. + + :returns: New widget instance, or ``None`` if e.g. it could + not determine how to create the widget. + """ + from wuttaweb.forms import widgets + + if widget_type == 'notes': + return widgets.NotesWidget(**kwargs) + def set_grid(self, key, grid): """ Establish a :term:`grid` to be displayed for a field. This diff --git a/src/wuttaweb/views/upgrades.py b/src/wuttaweb/views/upgrades.py index 3a913d0..19f5bba 100644 --- a/src/wuttaweb/views/upgrades.py +++ b/src/wuttaweb/views/upgrades.py @@ -34,7 +34,6 @@ from sqlalchemy import orm from wuttjamaican.db.model import Upgrade from wuttaweb.views import MasterView -from wuttaweb.forms import widgets from wuttaweb.forms.schema import UserRef, WuttaEnum, FileDownload from wuttaweb.progress import get_progress_session @@ -147,7 +146,7 @@ class UpgradeView(MasterView): f.set_node('created_by', UserRef(self.request)) # notes - f.set_widget('notes', widgets.NotesWidget()) + f.set_widget('notes', 'notes') # status if self.creating: diff --git a/tests/forms/test_base.py b/tests/forms/test_base.py index 54bf4da..8808bfa 100644 --- a/tests/forms/test_base.py +++ b/tests/forms/test_base.py @@ -142,6 +142,26 @@ class TestForm(TestCase): self.assertIs(form.widgets['foo'], new_widget) self.assertIs(schema['foo'].widget, new_widget) + # can also just specify widget pseudo-type (invalid) + self.assertNotIn('bar', form.widgets) + self.assertRaises(ValueError, form.set_widget, 'bar', 'ldjfadjfadj') + + # can also just specify widget pseudo-type (valid) + self.assertNotIn('bar', form.widgets) + form.set_widget('bar', 'notes') + self.assertIsInstance(form.widgets['bar'], widgets.NotesWidget) + + def test_make_widget(self): + form = self.make_form(fields=['foo', 'bar']) + + # notes + widget = form.make_widget('notes') + self.assertIsInstance(widget, widgets.NotesWidget) + + # invalid + widget = form.make_widget('fdajvdafjjf') + self.assertIsNone(widget) + def test_set_grid(self): form = self.make_form(fields=['foo', 'bar']) self.assertNotIn('foo', form.widgets)