From 74e2a4f0e278117229178722a050d1cc3b2a5cb4 Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Wed, 11 Dec 2024 09:48:50 -0600 Subject: [PATCH] fix: correct "empty option" behavior for `ObjectRef` schema type --- src/wuttaweb/forms/schema.py | 5 +++++ src/wuttaweb/forms/widgets.py | 2 +- src/wuttaweb/templates/deform/readonly/objectref.pt | 2 +- tests/forms/test_schema.py | 5 +++++ tests/forms/test_widgets.py | 10 ++++++++++ 5 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/wuttaweb/forms/schema.py b/src/wuttaweb/forms/schema.py index 6347b61..b618187 100644 --- a/src/wuttaweb/forms/schema.py +++ b/src/wuttaweb/forms/schema.py @@ -207,6 +207,11 @@ class ObjectRef(colander.SchemaType): def serialize(self, node, appstruct): """ """ + # nb. normalize to empty option if no object ref, so that + # works as expected + if self.empty_option and not appstruct: + return self.empty_option[0] + if appstruct is colander.null: return colander.null diff --git a/src/wuttaweb/forms/widgets.py b/src/wuttaweb/forms/widgets.py index 2d91eb9..b4ed6a3 100644 --- a/src/wuttaweb/forms/widgets.py +++ b/src/wuttaweb/forms/widgets.py @@ -102,7 +102,7 @@ class ObjectRefWidget(SelectWidget): # add url, only if rendering readonly readonly = kw.get('readonly', self.readonly) if readonly: - if 'url' not in values and self.url and field.schema.model_instance: + if 'url' not in values and self.url and hasattr(field.schema, 'model_instance'): values['url'] = self.url(field.schema.model_instance) return values diff --git a/src/wuttaweb/templates/deform/readonly/objectref.pt b/src/wuttaweb/templates/deform/readonly/objectref.pt index 3ab9e0e..70c1040 100644 --- a/src/wuttaweb/templates/deform/readonly/objectref.pt +++ b/src/wuttaweb/templates/deform/readonly/objectref.pt @@ -4,6 +4,6 @@ ${str(field.schema.model_instance or '')} - ${str(field.schema.model_instance or '')} + ${str(getattr(field.schema, 'model_instance', None) or '')} diff --git a/tests/forms/test_schema.py b/tests/forms/test_schema.py index e7f9f36..97b9719 100644 --- a/tests/forms/test_schema.py +++ b/tests/forms/test_schema.py @@ -102,6 +102,11 @@ class TestObjectRef(DataTestCase): value = typ.serialize(node, person) self.assertEqual(value, person.uuid.hex) + # null w/ empty option + typ = mod.ObjectRef(self.request, empty_option=('bad', 'BAD')) + value = typ.serialize(node, colander.null) + self.assertEqual(value, 'bad') + def test_deserialize(self): model = self.app.model node = colander.SchemaNode(colander.String()) diff --git a/tests/forms/test_widgets.py b/tests/forms/test_widgets.py index f479e5a..0ff5696 100644 --- a/tests/forms/test_widgets.py +++ b/tests/forms/test_widgets.py @@ -61,6 +61,7 @@ class TestObjectRefWidget(WebTestCase): self.session.add(person) self.session.commit() + # standard node = colander.SchemaNode(PersonRef(self.request, session=self.session)) widget = self.make_widget() field = self.make_field(node) @@ -68,6 +69,15 @@ class TestObjectRefWidget(WebTestCase): self.assertIn('cstruct', values) self.assertNotIn('url', values) + # readonly w/ empty option + node = colander.SchemaNode(PersonRef(self.request, session=self.session, + empty_option=('_empty_', '(empty)'))) + widget = self.make_widget(readonly=True, url=lambda obj: '/foo') + field = self.make_field(node) + values = widget.get_template_values(field, '_empty_', {}) + self.assertIn('cstruct', values) + self.assertNotIn('url', values) + class TestFileDownloadWidget(WebTestCase):