Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
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
6 changes: 1 addition & 5 deletions src/firebase_functions/eventarc_fn.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
"""Cloud functions to handle Eventarc events."""

# pylint: disable=protected-access
import datetime as _dt
import functools as _functools
import typing as _typing

Expand Down Expand Up @@ -64,10 +63,7 @@ def on_custom_event_published_wrapped(raw: _ce.CloudEvent):
source=event_dict["source"],
specversion=event_dict["specversion"],
subject=event_dict["subject"] if "subject" in event_dict else None,
time=_dt.datetime.strptime(
event_dict["time"],
"%Y-%m-%dT%H:%M:%S.%f%z",
),
time=_util.timestamp_conversion(event_dict["time"]),
type=event_dict["type"],
)
_with_init(func)(event)
Expand Down
21 changes: 2 additions & 19 deletions src/firebase_functions/pubsub_fn.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
# pylint: disable=protected-access
import base64 as _base64
import dataclasses as _dataclasses
import datetime as _dt
import functools as _functools
import json as _json
import typing as _typing
Expand Down Expand Up @@ -105,25 +104,9 @@ def _message_handler(
data = event_dict["data"]
message_dict = data["message"]

# if no microseconds are present, we should set them to 0 to prevent parsing from failing
if "." not in event_dict["time"]:
event_dict["time"] = event_dict["time"].replace("Z", ".000000Z")
if "." not in message_dict["publish_time"]:
message_dict["publish_time"] = message_dict["publish_time"].replace("Z", ".000000Z")

time = _dt.datetime.strptime(
event_dict["time"],
"%Y-%m-%dT%H:%M:%S.%f%z",
)

publish_time = _dt.datetime.strptime(
message_dict["publish_time"],
"%Y-%m-%dT%H:%M:%S.%f%z",
)

# Convert the UTC string into a datetime object
event_dict["time"] = time
message_dict["publish_time"] = publish_time
event_dict["time"] = _util.timestamp_conversion(event_dict["time"])
message_dict["publish_time"] = _util.timestamp_conversion(message_dict["publish_time"])
Comment on lines +108 to +109
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.

high

The replacement of manual parsing with _util.timestamp_conversion introduces a potential regression for Python versions prior to 3.11. The previous implementation (lines 109-112 in the original code) explicitly handled the 'Z' suffix by replacing it or using a format that worked. However, _util.timestamp_conversion uses strptime with the %z directive for second and microsecond precisions, which does not support the 'Z' suffix in Python < 3.11. Since this library likely supports Python 3.10, this change will cause a ValueError when processing timestamps ending in 'Z'. It is recommended to update the utility function _util.timestamp_conversion to handle the 'Z' suffix for all precisions.


# Pop unnecessary keys from the message data
# (we get these keys from the snake case alternatives that are provided)
Expand Down
7 changes: 2 additions & 5 deletions src/firebase_functions/remote_config_fn.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ def _config_handler(func: _C1, raw: _ce.CloudEvent) -> None:

config_data = ConfigUpdateData(
version_number=event_data["versionNumber"],
update_time=_dt.datetime.strptime(event_data["updateTime"], "%Y-%m-%dT%H:%M:%S.%f%z"),
update_time=_util.timestamp_conversion(event_data["updateTime"]),
update_user=ConfigUser(
name=event_data["updateUser"]["name"],
email=event_data["updateUser"]["email"],
Expand All @@ -182,10 +182,7 @@ def _config_handler(func: _C1, raw: _ce.CloudEvent) -> None:
source=event_dict["source"],
specversion=event_dict["specversion"],
subject=event_dict["subject"] if "subject" in event_dict else None,
time=_dt.datetime.strptime(
event_dict["time"],
"%Y-%m-%dT%H:%M:%S.%f%z",
),
time=_util.timestamp_conversion(event_dict["time"]),
type=event_dict["type"],
)

Expand Down
23 changes: 5 additions & 18 deletions src/firebase_functions/scheduler_fn.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,24 +105,11 @@ def on_schedule_wrapped(request: _Request) -> _Response:
schedule_time = _dt.datetime.now(_timezone.utc)
else:
try:
# Try to parse with the stdlib which supports fractional
# seconds and offsets in Python 3.11+ via fromisoformat.
# Normalize RFC3339 'Z' to '+00:00' for fromisoformat.
iso_str = schedule_time_str
if iso_str.endswith("Z"):
iso_str = iso_str[:-1] + "+00:00"
schedule_time = _dt.datetime.fromisoformat(iso_str)
except ValueError:
# Fallback to strict parsing without fractional seconds
try:
schedule_time = _dt.datetime.strptime(
schedule_time_str,
"%Y-%m-%dT%H:%M:%S%z",
)
except ValueError as e:
# If all parsing fails, log and use current UTC time
_logging.exception(e)
schedule_time = _dt.datetime.now(_timezone.utc)
schedule_time = _util.timestamp_conversion(schedule_time_str)
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.

high

The refactor to use _util.timestamp_conversion removes the explicit normalization of the 'Z' suffix to '+00:00' (previously at lines 112-113). While datetime.fromisoformat and strptime with %z support 'Z' in Python 3.11+, they do not in Python 3.10. Since this library supports Python 3.10, this change introduces a regression where timestamps ending in 'Z' will fail to parse. It is recommended to update the utility function _util.timestamp_conversion to handle the 'Z' suffix for all precisions, or to retain the normalization here.

except ValueError as e:
# If parsing fails, log and use current UTC time.
_logging.exception(e)
schedule_time = _dt.datetime.now(_timezone.utc)
event = ScheduledEvent(
job_name=request.headers.get("X-CloudScheduler-JobName"),
schedule_time=schedule_time,
Expand Down
7 changes: 2 additions & 5 deletions src/firebase_functions/test_lab_fn.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ def _event_handler(func: _C1, raw: _ce.CloudEvent) -> None:
event_dict = {**event_data, **event_attributes}

test_lab_data = TestMatrixCompletedData(
create_time=_dt.datetime.strptime(event_data["createTime"], "%Y-%m-%dT%H:%M:%S.%f%z"),
create_time=_util.timestamp_conversion(event_data["createTime"]),
state=TestState(event_data["state"]),
invalid_matrix_details=event_data.get("invalidMatrixDetails"),
outcome_summary=OutcomeSummary(event_data["outcomeSummary"]),
Expand All @@ -237,10 +237,7 @@ def _event_handler(func: _C1, raw: _ce.CloudEvent) -> None:
source=event_dict["source"],
specversion=event_dict["specversion"],
subject=event_dict["subject"] if "subject" in event_dict else None,
time=_dt.datetime.strptime(
event_dict["time"],
"%Y-%m-%dT%H:%M:%S.%f%z",
),
time=_util.timestamp_conversion(event_dict["time"]),
type=event_dict["type"],
)

Expand Down
Loading