Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions slack_sdk/oauth/installation_store/internals.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,17 @@
from typing import Type, TypeVar, Union


def _replace_utc_designator(iso_datetime_str: str) -> str:
if iso_datetime_str.endswith(("Z", "z")):
return iso_datetime_str[:-1] + "+00:00"
return iso_datetime_str


def _from_iso_format_to_datetime(iso_datetime_str: str) -> datetime:
if "+" not in iso_datetime_str:
iso_datetime_str += "+00:00"
return datetime.fromisoformat(iso_datetime_str)
dt = datetime.fromisoformat(_replace_utc_designator(iso_datetime_str))
if dt.tzinfo is None:
dt = dt.replace(tzinfo=timezone.utc)
return dt
Comment on lines 11 to +15

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Swap a trailing Z for +00:00 before parsing so Z works on every supported version of python. Only the last character, not str.replace: RFC 3339 §5.6 only allows Z as the final offset, which is also how CPython's own parser treats it. Lowercase z is allowed by the RFC and already parses on main under CPython, so keeping it avoids a second regression.

Suggested change
def _from_iso_format_to_datetime(iso_datetime_str: str) -> datetime:
if "+" not in iso_datetime_str:
iso_datetime_str += "+00:00"
return datetime.fromisoformat(iso_datetime_str)
dt = datetime.fromisoformat(iso_datetime_str)
if dt.tzinfo is None:
dt = dt.replace(tzinfo=timezone.utc)
return dt
def _replace_utc_designator(iso_datetime_str: str) -> str:
if iso_datetime_str.endswith(("Z", "z")):
return iso_datetime_str[:-1] + "+00:00"
return iso_datetime_str
def _from_iso_format_to_datetime(iso_datetime_str: str) -> datetime:
dt = datetime.fromisoformat(_replace_utc_designator(iso_datetime_str))
if dt.tzinfo is None:
dt = dt.replace(tzinfo=timezone.utc)
return dt



def _from_iso_format_to_unix_timestamp(iso_datetime_str: str) -> float:
Expand Down
13 changes: 13 additions & 0 deletions tests/slack_sdk/oauth/installation_store/test_internals.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,17 @@ def test_iso_format(self):
dt = _from_iso_format_to_datetime("2021-07-14 08:00:17")
self.assertEqual(dt.timestamp(), 1626249617.0)

def test_iso_format_with_utc_offset(self):
dt = _from_iso_format_to_datetime("2021-07-14 17:00:17+09:00")
self.assertEqual(dt.timestamp(), 1626249617.0)
dt = _from_iso_format_to_datetime("2021-07-14 03:00:17-05:00")
self.assertEqual(dt.timestamp(), 1626249617.0)

def test_iso_format_with_utc_designator(self):
for iso_datetime_str in ["2021-07-14T08:00:17Z", "2021-07-14T08:00:17z", "2021-07-14T08:00:17.000Z"]:
dt = _from_iso_format_to_datetime(iso_datetime_str)
self.assertEqual(dt.timestamp(), 1626249617.0)


Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add coverage for the UTC designator? No test exercises Z right now, which is why the 3.7-3.10 regression doesn't show up in CI.

    def test_iso_format_with_utc_designator(self):
        for iso_datetime_str in ["2021-07-14T08:00:17Z", "2021-07-14T08:00:17z", "2021-07-14T08:00:17.000Z"]:
            dt = _from_iso_format_to_datetime(iso_datetime_str)
            self.assertEqual(dt.timestamp(), 1626249617.0)

and a ("2023-11-28T22:11:19Z", int, 1701209479) case in the test_timestamp_to_type parametrize list.

@pytest.mark.parametrize(
"ts,target_type,expected_result",
Expand All @@ -30,6 +41,8 @@ def test_iso_format(self):
(datetime(2023, 11, 28, 22, 9, 7, tzinfo=timezone.utc), int, 1701209347),
("1701209605", int, 1701209605),
("2023-11-28 22:11:19", int, 1701209479),
("2023-11-28 17:11:19-05:00", int, 1701209479),
("2023-11-28T22:11:19Z", int, 1701209479),
(1701209998.3429494, float, 1701209998.3429494),
(datetime(2023, 11, 28, 22, 20, 25, 262571, tzinfo=timezone.utc), float, 1701210025.262571),
("1701210054.4672053", float, 1701210054.4672053),
Expand Down
Loading