Skip to content

fix(parser): make etag optional field on S3 notification events #4173

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
14 changes: 7 additions & 7 deletions aws_lambda_powertools/utilities/data_classes/s3_event.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,14 @@ def key(self) -> str:
return unquote_plus(self["key"])

@property
def size(self) -> str:
"""Object size"""
return self["size"]
def size(self) -> Optional[int]:
"""Object size. Object deletion event doesn't contain size."""
return self.get("size")

@property
def etag(self) -> str:
"""Object etag"""
return self["etag"]
"""Object etag. Object deletion event doesn't contain etag; we default to empty string"""
return self.get("etag", "") # type: ignore[return-value] # false positive

@property
def version_id(self) -> str:
Expand Down Expand Up @@ -178,8 +178,8 @@ def size(self) -> int:

@property
def etag(self) -> str:
"""object eTag"""
return self["s3"]["object"]["eTag"]
"""Object eTag. Object deletion event doesn't contain eTag; we default to empty string"""
return self["s3"]["object"].get("eTag", "")

@property
def version_id(self) -> Optional[str]:
Expand Down
2 changes: 1 addition & 1 deletion aws_lambda_powertools/utilities/parser/models/s3.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class S3Message(BaseModel):
class S3EventNotificationObjectModel(BaseModel):
key: str
size: Optional[NonNegativeFloat] = None
etag: str
etag: str = Field(default="")
version_id: str = Field(None, alias="version-id")
sequencer: Optional[str] = None

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
},
"object": {
"key": "IMG_m7fzo3.jpg",
"size": 184662,
"etag": "4e68adba0abe2dc8653dc3354e14c01d",
"sequencer": "006408CAD69598B05E"
},
"request-id": "0BH729840619AG5K",
Expand All @@ -26,4 +24,4 @@
"reason": "DeleteObject",
"deletion-type": "Delete Marker Created"
}
}
}
4 changes: 2 additions & 2 deletions tests/unit/data_classes/test_s3_eventbridge_notification.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ def test_s3_eventbridge_notification_detail_parsed(raw_event: Dict):
assert parsed_event.detail.deletion_type == raw_event["detail"].get("deletion-type")
assert parsed_event.detail.destination_access_tier == raw_event["detail"].get("destination-access-tier")
assert parsed_event.detail.destination_storage_class == raw_event["detail"].get("destination-storage-class")
assert parsed_event.detail.object.etag == raw_event["detail"]["object"]["etag"]
assert parsed_event.detail.object.etag == raw_event["detail"]["object"].get("etag", "")
assert parsed_event.detail.object.key == raw_event["detail"]["object"]["key"]
assert parsed_event.detail.object.sequencer == raw_event["detail"]["object"]["sequencer"]
assert parsed_event.detail.object.size == raw_event["detail"]["object"]["size"]
assert parsed_event.detail.object.size == raw_event["detail"]["object"].get("size")
assert parsed_event.detail.reason == raw_event["detail"].get("reason")
assert parsed_event.detail.version == raw_event["detail"].get("version")
assert parsed_event.detail.request_id == raw_event["detail"]["request-id"]
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/parser/test_s3_notification.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ def test_s3_eventbridge_notification_object_deleted_event():
assert model.detail.version == raw_event["detail"]["version"]
assert model.detail.bucket.name == raw_event["detail"]["bucket"]["name"]
assert model.detail.object.key == raw_event["detail"]["object"]["key"]
assert model.detail.object.size == raw_event["detail"]["object"]["size"]
assert model.detail.object.etag == raw_event["detail"]["object"]["etag"]
assert model.detail.object.size == raw_event["detail"]["object"].get("size")
assert model.detail.object.etag == raw_event["detail"]["object"].get("etag", "")
assert model.detail.object.sequencer == raw_event["detail"]["object"]["sequencer"]
assert model.detail.request_id == raw_event["detail"]["request-id"]
assert model.detail.requester == raw_event["detail"]["requester"]
Expand Down