From ce8d401f67a80a0c9947c0ba0928a4ced4854623 Mon Sep 17 00:00:00 2001 From: Chris Guidry Date: Thu, 13 Jun 2024 10:50:28 -0400 Subject: [PATCH] Preserve timezone information when validating Pendulum DateTimes Fixes #188 --- .gitignore | 1 + pydantic_extra_types/pendulum_dt.py | 11 +---------- tests/test_pendulum_dt.py | 26 ++++++++++++++++++++++++++ 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 8b265107..7a4d678d 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,4 @@ _build/ /.ghtopdep_cache/ /worktrees/ .ruff_cache/ +.python-version diff --git a/pydantic_extra_types/pendulum_dt.py b/pydantic_extra_types/pendulum_dt.py index 0f776be7..f75c95bf 100644 --- a/pydantic_extra_types/pendulum_dt.py +++ b/pydantic_extra_types/pendulum_dt.py @@ -82,16 +82,7 @@ def _validate(cls, value: Any, handler: core_schema.ValidatorFunctionWrapHandler # probably the best way to have feature parity with # https://docs.pydantic.dev/latest/api/standard_library_types/#datetimedatetime value = handler(value) - return DateTime( - value.year, - value.month, - value.day, - value.hour, - value.minute, - value.second, - value.microsecond, - value.tzinfo, - ) + return DateTime.instance(value) except ValueError: try: value = parse(value, strict=cls.strict) diff --git a/tests/test_pendulum_dt.py b/tests/test_pendulum_dt.py index 1c883397..817b3b9a 100644 --- a/tests/test_pendulum_dt.py +++ b/tests/test_pendulum_dt.py @@ -129,6 +129,32 @@ def test_pendulum_dt_from_serialized(dt): assert isinstance(model.dt, pendulum.DateTime) +@pytest.mark.parametrize( + 'dt', + [ + pendulum.now().to_iso8601_string(), + pendulum.now().to_w3c_string(), + ], +) +def test_pendulum_dt_from_serialized_preserves_timezones(dt): + """ + Verifies that building an instance from serialized, well-formed strings decode + properly and preserves the timezone information across all of the Pendulum DateTime + properties. Regression test for pydantic/pydantic-extra-types#188. + """ + dt_actual = pendulum.parse(dt) + model = DtModel(dt=dt) + assert model.dt == dt_actual + assert type(model.dt) is DateTime + assert isinstance(model.dt, pendulum.DateTime) + assert model.dt.tzinfo is not None + assert model.dt.tzinfo.utcoffset(model.dt) == dt_actual.tzinfo.utcoffset(dt_actual) + assert model.dt.tz is not None + assert model.dt.tz.utcoffset(model.dt) == dt_actual.tz.utcoffset(dt_actual) + assert model.dt.timezone is not None + assert model.dt.timezone.utcoffset(model.dt) == dt_actual.timezone.utcoffset(dt_actual) + + @pytest.mark.parametrize( 'dt', [