Repository navigation
change(pubsub): accept messages without data - #322
Conversation
There was a problem hiding this comment.
Code Review
This pull request updates the Message class in pubsub_fn.py to change the type of publish_time to a timezone-aware datetime and allows data to be None when a Pub/Sub message is published without a payload. It also updates the message handler to default data to None and adds comprehensive unit tests to verify these behaviors. I have no feedback to provide as there are no review comments.
CorieW
left a comment
There was a problem hiding this comment.
LGTM
nits:
data=""still makes.jsonraise, whiledata=NonereturnsNone. Should""returnNonetoo, in case the emulator sends attribute-only messages that way?data: str | Nonemay cause new mypy/pyright warnings for users (e.g.b64decode(msg.data)). Worth a changelog note?- No test covers a present
orderingKey(e.g."abc"→ordering_key == "abc"). - The older tests could reuse
_raw_eventinstead of building the CloudEvent by hand.
The emulator sends data as an empty string for attribute-only messages. Also cover a present ordering key and reuse _raw_event in older tests.
ajperel
left a comment
There was a problem hiding this comment.
Agree with Corie on "data: str | None may cause new mypy/pyright warnings for users (e.g. b64decode(msg.data)). Worth a changelog note?"
In the extreme should we consider it a breaking change with the type widening and say change(pubsub) ?
| subscription=data["subscription"], | ||
| ) | ||
|
|
||
| event_dict["data"] = message |
There was a problem hiding this comment.
AI is suggesting that we instead do
raw_data = message_dict.get("data")
message_dict["data"] = raw_data if raw_data else None
Emulator vs. Production Payload Normalization ("" vs. None)
Context: Production GCP Pub/Sub omits the "data" field from CloudEvents for attribute-only messages (resulting in message.data is None), whereas the Firebase Local Emulator emits {"data": ""} (resulting in message.data == "").
Observation: While Message.json now returns None for both cases, user code inspecting message.data directly will observe "" in local emulator runs and None in production GCP. Under Python, b64decode("") succeeds locally (b""), but b64decode(None) crashes in production with TypeError.
This also satisfies the exact docstring contract: "or None if the message was published without a payload".
A Pub/Sub message that has attributes but no data crashed
on_message_publishedwithTypeError: Message.__init__() missing 1 required positional argument: 'data'before the handler ran.This lets those messages through with
dataset toNone, makesNonethe default fordatawhen building aMessagedirectly, and typespublish_timeas thedatetimeit already is.ordering_keyis nowstr | None = None. The field afterdataneeds a default too, and the handler already passedNonewhen there is no ordering key.datais now typedstr | None, so type checkers will flag code that passesmsg.datastraight tob64decode. The emulator sends""for attribute-only messages, so the handler turns that intoNonetoo.Tested with unit tests and in the emulator with an attribute-only message. Not tested with a real Pub/Sub delivery.