diff --git a/changelogs/fragments/tagged-time-datetime-fold.yml b/changelogs/fragments/tagged-time-datetime-fold.yml new file mode 100644 index 00000000000..38f89731ec3 --- /dev/null +++ b/changelogs/fragments/tagged-time-datetime-fold.yml @@ -0,0 +1,2 @@ +bugfixes: + - serialization - Preserve ``fold`` on tagged ``datetime.time`` and ``datetime.datetime`` instances. diff --git a/lib/ansible/module_utils/_internal/_datatag/__init__.py b/lib/ansible/module_utils/_internal/_datatag/__init__.py index a00214e2a02..db33ac9e9fb 100644 --- a/lib/ansible/module_utils/_internal/_datatag/__init__.py +++ b/lib/ansible/module_utils/_internal/_datatag/__init__.py @@ -330,8 +330,7 @@ class AnsibleSerializableTime(AnsibleSerializableWrapper[datetime.time]): @classmethod def _from_dict(cls: t.Type[_TAnsibleSerializable], d: t.Dict[str, t.Any]) -> datetime.time: - value = datetime.time.fromisoformat(d['iso8601']) - value.replace(fold=d['fold']) + value = datetime.time.fromisoformat(d['iso8601']).replace(fold=d['fold']) return value @@ -347,8 +346,7 @@ class AnsibleSerializableDateTime(AnsibleSerializableWrapper[datetime.datetime]) @classmethod def _from_dict(cls: t.Type[_TAnsibleSerializable], d: t.Dict[str, t.Any]) -> datetime.datetime: - value = datetime.datetime.fromisoformat(d['iso8601']) - value.replace(fold=d['fold']) + value = datetime.datetime.fromisoformat(d['iso8601']).replace(fold=d['fold']) return value diff --git a/test/units/module_utils/datatag/test_datatag.py b/test/units/module_utils/datatag/test_datatag.py index 20ffdd00bdf..355363bfa6d 100644 --- a/test/units/module_utils/datatag/test_datatag.py +++ b/test/units/module_utils/datatag/test_datatag.py @@ -94,6 +94,9 @@ def assert_round_trip(original_value, round_tripped_value, via_copy=False): assert original_value == round_tripped_value assert AnsibleTagHelper.tags(original_value) == AnsibleTagHelper.tags(round_tripped_value) + if isinstance(original_value, (datetime.datetime, datetime.time)) and isinstance(round_tripped_value, (datetime.datetime, datetime.time)): + assert original_value.fold == round_tripped_value.fold # fold isn't included in equality, so we have to check it explicitly + if via_copy and type(original_value) is tuple: # pylint: disable=unidiomatic-typecheck # copy.copy/copy.deepcopy significantly complicate the rules for reference equality with tuple, skip the following checks for values sourced that way # tuple impl of __copy__ always returns the same instance, __deepcopy__ always returns the same instance if its contents are immutable @@ -376,9 +379,9 @@ class TestDatatagTarget(AutoParamSupport): 42.0, 42, "hi mom", - datetime.datetime(2023, 9, 15, 21, 5, 30, 1900, datetime.timezone.utc), + datetime.datetime(2023, 9, 15, 21, 5, 30, 1900, datetime.timezone.utc, fold=1), datetime.date(2023, 9, 15), - datetime.time(21, 5, 30, 1900), + datetime.time(21, 5, 30, 1900, fold=1), ] tagged_object_instances: t.List[AnsibleTaggedObject] = [