Skip to content

Commit 476324c

Browse files
committed
* 'develop' of https://github.com/awslabs/aws-lambda-powertools-python: chore(deps): bump boto3 from 1.17.88 to 1.17.89 (#466) feat(data-classes): add AttributeValueType to DynamoDBStreamEvent (#462) chore(deps): bump boto3 from 1.17.87 to 1.17.88 (#463) chore(deps-dev): bump mkdocs-material from 7.1.6 to 7.1.7 (#464) feat(data-classes): decorator to instantiate data_classes and docs updates (#442) chore(deps): bump boto3 from 1.17.86 to 1.17.87 (#459)
2 parents efc3b16 + 070428a commit 476324c

File tree

10 files changed

+516
-231
lines changed

10 files changed

+516
-231
lines changed

aws_lambda_powertools/utilities/data_classes/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from .connect_contact_flow_event import ConnectContactFlowEvent
1111
from .dynamo_db_stream_event import DynamoDBStreamEvent
1212
from .event_bridge_event import EventBridgeEvent
13+
from .event_source import event_source
1314
from .kinesis_stream_event import KinesisStreamEvent
1415
from .s3_event import S3Event
1516
from .ses_event import SESEvent
@@ -31,4 +32,5 @@
3132
"SESEvent",
3233
"SNSEvent",
3334
"SQSEvent",
35+
"event_source",
3436
]

aws_lambda_powertools/utilities/data_classes/alb_event.py

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
class ALBEventRequestContext(DictWrapper):
77
@property
88
def elb_target_group_arn(self) -> str:
9+
"""Target group arn for your Lambda function"""
910
return self["requestContext"]["elb"]["targetGroupArn"]
1011

1112

@@ -15,6 +16,7 @@ class ALBEvent(BaseProxyEvent):
1516
Documentation:
1617
--------------
1718
- https://docs.aws.amazon.com/lambda/latest/dg/services-alb.html
19+
- https://docs.aws.amazon.com/elasticloadbalancing/latest/application/lambda-functions.html
1820
"""
1921

2022
@property

aws_lambda_powertools/utilities/data_classes/dynamo_db_stream_event.py

+75-2
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,42 @@
11
from enum import Enum
2-
from typing import Dict, Iterator, List, Optional
2+
from typing import Any, Dict, Iterator, List, Optional, Union
33

44
from aws_lambda_powertools.utilities.data_classes.common import DictWrapper
55

66

7+
class AttributeValueType(Enum):
8+
Binary = "B"
9+
BinarySet = "BS"
10+
Boolean = "BOOL"
11+
List = "L"
12+
Map = "M"
13+
Number = "N"
14+
NumberSet = "NS"
15+
Null = "NULL"
16+
String = "S"
17+
StringSet = "SS"
18+
19+
720
class AttributeValue(DictWrapper):
821
"""Represents the data for an attribute
922
10-
Documentation: https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_streams_AttributeValue.html
23+
Documentation:
24+
--------------
25+
- https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_streams_AttributeValue.html
26+
- https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html
1127
"""
1228

29+
def __init__(self, data: Dict[str, Any]):
30+
"""AttributeValue constructor
31+
32+
Parameters
33+
----------
34+
data: Dict[str, Any]
35+
Raw lambda event dict
36+
"""
37+
super().__init__(data)
38+
self.dynamodb_type = list(data.keys())[0]
39+
1340
@property
1441
def b_value(self) -> Optional[str]:
1542
"""An attribute of type Base64-encoded binary data object
@@ -106,6 +133,29 @@ def ss_value(self) -> Optional[List[str]]:
106133
"""
107134
return self.get("SS")
108135

136+
@property
137+
def get_type(self) -> AttributeValueType:
138+
"""Get the attribute value type based on the contained data"""
139+
return AttributeValueType(self.dynamodb_type)
140+
141+
@property
142+
def l_value(self) -> Optional[List["AttributeValue"]]:
143+
"""Alias of list_value"""
144+
return self.list_value
145+
146+
@property
147+
def m_value(self) -> Optional[Dict[str, "AttributeValue"]]:
148+
"""Alias of map_value"""
149+
return self.map_value
150+
151+
@property
152+
def get_value(self) -> Union[Optional[bool], Optional[str], Optional[List], Optional[Dict]]:
153+
"""Get the attribute value"""
154+
try:
155+
return getattr(self, f"{self.dynamodb_type.lower()}_value")
156+
except AttributeError:
157+
raise TypeError(f"Dynamodb type {self.dynamodb_type} is not supported")
158+
109159

110160
def _attribute_value_dict(attr_values: Dict[str, dict], key: str) -> Optional[Dict[str, AttributeValue]]:
111161
"""A dict of type String to AttributeValue object map
@@ -224,6 +274,29 @@ class DynamoDBStreamEvent(DictWrapper):
224274
Documentation:
225275
-------------
226276
- https://docs.aws.amazon.com/lambda/latest/dg/with-ddb.html
277+
278+
Example
279+
-------
280+
**Process dynamodb stream events and use get_type and get_value for handling conversions**
281+
282+
from aws_lambda_powertools.utilities.data_classes import event_source, DynamoDBStreamEvent
283+
from aws_lambda_powertools.utilities.data_classes.dynamo_db_stream_event import (
284+
AttributeValueType,
285+
AttributeValue,
286+
)
287+
from aws_lambda_powertools.utilities.typing import LambdaContext
288+
289+
290+
@event_source(data_class=DynamoDBStreamEvent)
291+
def lambda_handler(event: DynamoDBStreamEvent, context: LambdaContext):
292+
for record in event.records:
293+
key: AttributeValue = record.dynamodb.keys["id"]
294+
if key == AttributeValueType.Number:
295+
assert key.get_value == key.n_value
296+
print(key.get_value)
297+
elif key == AttributeValueType.Map:
298+
assert key.get_value == key.map_value
299+
print(key.get_value)
227300
"""
228301

229302
@property
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
from typing import Any, Callable, Dict, Type
2+
3+
from aws_lambda_powertools.middleware_factory import lambda_handler_decorator
4+
from aws_lambda_powertools.utilities.data_classes.common import DictWrapper
5+
from aws_lambda_powertools.utilities.typing import LambdaContext
6+
7+
8+
@lambda_handler_decorator
9+
def event_source(
10+
handler: Callable[[Any, LambdaContext], Any],
11+
event: Dict[str, Any],
12+
context: LambdaContext,
13+
data_class: Type[DictWrapper],
14+
):
15+
"""Middleware to create an instance of the passed in event source data class
16+
17+
Parameters
18+
----------
19+
handler: Callable
20+
Lambda's handler
21+
event: Dict
22+
Lambda's Event
23+
context: Dict
24+
Lambda's Context
25+
data_class: Type[DictWrapper]
26+
Data class type to instantiate
27+
28+
Example
29+
--------
30+
31+
**Sample usage**
32+
33+
from aws_lambda_powertools.utilities.data_classes import S3Event, event_source
34+
35+
@event_source(data_class=S3Event)
36+
def handler(event: S3Event, context):
37+
return {"key": event.object_key}
38+
"""
39+
return handler(data_class(event), context)

aws_lambda_powertools/utilities/idempotency/persistence/base.py

+1
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ def _generate_hash(self, data: Any) -> str:
224224
Hashed representation of the provided data
225225
226226
"""
227+
data = getattr(data, "raw_event", data) # could be a data class depending on decorator order
227228
hashed_data = self.hash_function(json.dumps(data, cls=Encoder).encode())
228229
return hashed_data.hexdigest()
229230

0 commit comments

Comments
 (0)