From f167fb935ceb8c654f7fcc77d6ed6a456918d42e Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Sat, 9 Aug 2025 12:52:43 -0300 Subject: [PATCH 1/3] fix: tz-aware tastypie datetimes --- ietf/api/__init__.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/ietf/api/__init__.py b/ietf/api/__init__.py index d70866083ec..d344048a339 100644 --- a/ietf/api/__init__.py +++ b/ietf/api/__init__.py @@ -4,6 +4,7 @@ import datetime import re +import sys from urllib.parse import urlencode @@ -25,6 +26,8 @@ OMITTED_APPS_APIS = ["ietf.status"] +HAVE_BROKEN_FROMISOFORMAT = sys.version_info < (3, 11, 0, "", 0) + def populate_api_list(): _module_dict = globals() for app_config in django_apps.get_app_configs(): @@ -58,6 +61,35 @@ def generate_cache_key(self, *args, **kwargs): # Use a list plus a ``.join()`` because it's faster than concatenation. return "%s:%s:%s:%s" % (self._meta.api_name, self._meta.resource_name, ':'.join(args), smooshed) + def _z_aware_fromisoformat(self, value): + """datetime.datetie.fromisoformat replacement that works with python < 3.11""" + if HAVE_BROKEN_FROMISOFORMAT: + if value.upper().endswith("Z"): + value = value[:-1] + "+00:00" # Z -> UTC + elif re.match(r"[+-][0-9][0-9]$", value[-3:]): + value = value + ":00" # -04 -> -04:00 + return value + + def filter_value_to_python( + self, value, field_name, filters, filter_expr, filter_type + ): + py_value = super().filter_value_to_python( + value, field_name, filters, filter_expr, filter_type + ) + if isinstance( + self.fields[field_name], tastypie.fields.DateTimeField + ) and isinstance(py_value, str): + # Ensure datetime values are TZ-aware, using UTC by default + try: + dt = self._z_aware_fromisoformat(py_value) + except ValueError: + pass # let tastypie deal with the original value + else: + if dt.tzinfo is None: + dt = dt.replace(tzinfo=datetime.timezone.utc) + py_value = dt.isoformat() + return py_value + TIMEDELTA_REGEX = re.compile(r'^(?P\d+d)?\s?(?P\d+h)?\s?(?P\d+m)?\s?(?P\d+s?)$') From bdc7d61a84b5825bc14d862de18d13057e63599f Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Sat, 9 Aug 2025 13:02:33 -0300 Subject: [PATCH 2/3] chore: comment --- ietf/api/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ietf/api/__init__.py b/ietf/api/__init__.py index d344048a339..474cadc5b3a 100644 --- a/ietf/api/__init__.py +++ b/ietf/api/__init__.py @@ -26,6 +26,7 @@ OMITTED_APPS_APIS = ["ietf.status"] +# Pre-py3.11, fromisoformat() does not handle -Z or +HH tz offsets HAVE_BROKEN_FROMISOFORMAT = sys.version_info < (3, 11, 0, "", 0) def populate_api_list(): From 569c6c26b9f9a22c930d5c60f8c5d317def9e4aa Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Sat, 9 Aug 2025 13:03:22 -0300 Subject: [PATCH 3/3] chore: clarify comment --- ietf/api/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ietf/api/__init__.py b/ietf/api/__init__.py index 474cadc5b3a..e2363479759 100644 --- a/ietf/api/__init__.py +++ b/ietf/api/__init__.py @@ -26,7 +26,7 @@ OMITTED_APPS_APIS = ["ietf.status"] -# Pre-py3.11, fromisoformat() does not handle -Z or +HH tz offsets +# Pre-py3.11, fromisoformat() does not handle Z or +HH tz offsets HAVE_BROKEN_FROMISOFORMAT = sys.version_info < (3, 11, 0, "", 0) def populate_api_list():