Repository navigation
Conversation
|
Thanks for the contribution! Before we can merge this, we need @auraseb to sign the Salesforce Inc. Contributor License Agreement. |
|
Hello 👋 Please sign the CLA |
WilliamBergamin
left a comment
There was a problem hiding this comment.
Hello and thanks for your interest in our project 💯 The negative offset fix is real: I checked that the new tests fail on main and pass on this branch
There's one regression to fix before merging. On CPython 3.7-3.10, a timestamp ending in Z (e.g. "2021-07-14T08:00:17Z") parses on main and raises ValueError with this change. main only handles it by accident: it appends +00:00, and the C fromisoformat on those versions lets the stray Z through. With the string passed to fromisoformat as-is, nothing before 3.11 accepts Z (gh-80010). Since the SDK supports 3.7+ and both #1989 and the description say Z is fixed, I think we should handle it explicitly. Suggestions inline.
Also, the CLA check needs signing before we can run CI.
| 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 |
There was a problem hiding this comment.
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.
| 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 |
| dt = _from_iso_format_to_datetime("2021-07-14 03:00:17-05:00") | ||
| self.assertEqual(dt.timestamp(), 1626249617.0) | ||
|
|
||
|
|
There was a problem hiding this comment.
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.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #1990 +/- ##
=======================================
Coverage 84.35% 84.36%
=======================================
Files 118 118
Lines 13793 13798 +5
=======================================
+ Hits 11635 11640 +5
Misses 2158 2158 ☔ View full report in Codecov by Harness. |
Signed-off-by: Sebastian Turner <sebastiant3484@gmail.com>
459c032 to
6bd1361
Compare
|
Thanks for catching the 3.7 to 3.10 regression. Applied your suggestion as written, added test_iso_format_with_utc_designator and the trailing Z case in test_timestamp_to_type. test_internals.py passes 16 of 16 on 3.10 and 3.13. |
|
hi @auraseb! Thanks so much for your contribution, could you sign the Salesforce Inc. Contributor License Agreement? |
Summary
_from_iso_format_to_datetimeappended+00:00to any string without a+character, so ISO 8601 timestamps with a negative offset (2021-07-14T03:00:17-05:00) were turned into invalid strings and raisedValueError. AZsuffix had the same problem on Python 3.11+ (on 3.7 to 3.10 it only parsed by accident). This affectsInstallation,Botand anything else that goes through_timestamp_to_typewith a string value.The function now swaps a trailing
Zorzfor+00:00(only the last character, per RFC 3339 §5.6), parses the string, and only sets UTC when the result has notzinfo, the same approach #1970 took for naivedatetimevalues. Strings without an offset are still treated as UTC, so existing behavior is unchanged for them.Testing
New cases cover a positive offset, a negative offset, and the
Z/zUTC designator, directly and through_timestamp_to_type. The negative offset cases fail onmainand pass with this change; the UTC designator cases pass on Python 3.10 and 3.13.Category
/docs(Documents)/tutorial(PythOnBoardingBot tutorial)tests/integration_tests(Automated tests for this library)Requirements
python3 -m venv .venv && source .venv/bin/activate && ./scripts/run_validation.shafter making the changes.Fixes #1989