3
0
Fork 0

fix: prevent error in DateTime schema type if no widget/request set

when we use this intentionally, the widget/request should be set as
expected. but apparently this gets instantiated sometimes (by
ColanderAlchemy?) without a widget.

so this adds sane fallback logic, instead of outright error
This commit is contained in:
Lance Edgar 2025-12-17 17:46:31 -06:00
parent 131eb22580
commit 2ccfe29553
2 changed files with 28 additions and 9 deletions

View file

@ -31,6 +31,7 @@ import colander
import sqlalchemy as sa
from wuttjamaican.conf import parse_list
from wuttjamaican.util import localtime
from wuttaweb.db import Session
from wuttaweb.forms import widgets
@ -38,28 +39,38 @@ from wuttaweb.forms import widgets
class WuttaDateTime(colander.DateTime):
"""
Custom schema type for ``datetime`` fields.
Custom schema type for :class:`~python:datetime.datetime` fields.
This should be used automatically for
:class:`sqlalchemy:sqlalchemy.types.DateTime` columns unless you
register another default.
:class:`~sqlalchemy:sqlalchemy.types.DateTime` ORM columns unless
you register another default.
This schema type exists for sake of convenience, when working with
the Buefy datepicker + timepicker widgets.
It also follows the datetime handling "rules" as outlined in
:doc:`wuttjamaican:narr/datetime`. On the Python side, values
should be naive/UTC datetime objects. On the HTTP side, values
will be ISO-format strings representing aware/local time.
"""
def serialize(self, node, appstruct):
if not appstruct:
return colander.null
# nb. request should be present when it matters
if node.widget and node.widget.request:
request = node.widget.request
config = request.wutta_config
app = config.get_app()
appstruct = app.localtime(appstruct)
else:
# but if not, fallback to config-less logic
appstruct = localtime(appstruct)
dt = app.localtime(appstruct)
if self.format:
return dt.strftime(self.format)
return dt.isoformat()
return appstruct.strftime(self.format)
return appstruct.isoformat()
def deserialize( # pylint: disable=inconsistent-return-statements
self, node, cstruct
@ -72,6 +83,7 @@ class WuttaDateTime(colander.DateTime):
"%Y-%m-%dT%I:%M %p",
]
# nb. request is always assumed to be present here
request = node.widget.request
config = request.wutta_config
app = config.get_app()

View file

@ -62,6 +62,13 @@ class TestWuttaDateTime(WebTestCase):
)
self.assertEqual(result, "2024-12-11 02:33 PM")
# missing widget/request/config
typ = mod.WuttaDateTime()
node = colander.SchemaNode(typ)
result = typ.serialize(node, datetime.datetime(2024, 12, 11, 22, 33))
# nb. not possible to know which timezone is system-local
self.assertTrue(result.startswith("2024-12-"))
def test_deserialize(self):
tzlocal = get_timezone_by_name("America/Los_Angeles")
with patch.object(self.app, "get_timezone", return_value=tzlocal):