Skip to content

Commit 25a65b2

Browse files
Migrating functions from v1 to v2
1 parent 75e6fb2 commit 25a65b2

25 files changed

+51
-41
lines changed

aws_lambda_powertools/utilities/batch/base.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ def _collect_sqs_failures(self):
309309
# we convert to an event source data class...but self.model is still true
310310
# therefore, we do an additional check on whether the failed message is still a model
311311
# see https://github.com/aws-powertools/powertools-lambda-python/issues/2091
312-
if self.model and getattr(msg, "parse_obj", None):
312+
if self.model and getattr(msg, "model_validate", None):
313313
msg_id = msg.messageId
314314
else:
315315
msg_id = msg.message_id
@@ -320,7 +320,7 @@ def _collect_kinesis_failures(self):
320320
failures = []
321321
for msg in self.fail_messages:
322322
# # see https://github.com/aws-powertools/powertools-lambda-python/issues/2091
323-
if self.model and getattr(msg, "parse_obj", None):
323+
if self.model and getattr(msg, "model_validate", None):
324324
msg_id = msg.kinesis.sequenceNumber
325325
else:
326326
msg_id = msg.kinesis.sequence_number
@@ -331,7 +331,7 @@ def _collect_dynamodb_failures(self):
331331
failures = []
332332
for msg in self.fail_messages:
333333
# see https://github.com/aws-powertools/powertools-lambda-python/issues/2091
334-
if self.model and getattr(msg, "parse_obj", None):
334+
if self.model and getattr(msg, "model_validate", None):
335335
msg_id = msg.dynamodb.SequenceNumber
336336
else:
337337
msg_id = msg.dynamodb.sequence_number

aws_lambda_powertools/utilities/idempotency/base.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,22 @@ def _prepare_data(data: Any) -> Any:
3939
We will convert Python dataclasses, pydantic models or event source data classes to a dict,
4040
otherwise return data as-is.
4141
"""
42+
43+
# Convert from dataclasses
4244
if hasattr(data, "__dataclass_fields__"):
4345
import dataclasses
4446

4547
return dataclasses.asdict(data)
4648

49+
# Convert from Pydantic model
50+
if callable(getattr(data, "model_dump", None)):
51+
return data.model_dump()
52+
53+
# Convert from event source data class
4754
if callable(getattr(data, "dict", None)):
4855
return data.dict()
4956

57+
# Return raw event
5058
return getattr(data, "raw_event", data)
5159

5260

aws_lambda_powertools/utilities/idempotency/serialization/pydantic.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,10 @@ def __init__(self, model: Type[BaseModel]):
2525
self.__model: Type[BaseModel] = model
2626

2727
def to_dict(self, data: BaseModel) -> Dict:
28-
if callable(getattr(data, "model_dump", None)):
29-
# Support for pydantic V2
30-
return data.model_dump() # type: ignore[unused-ignore,attr-defined]
31-
return data.dict()
28+
return data.model_dump()
3229

3330
def from_dict(self, data: Dict) -> BaseModel:
34-
if callable(getattr(self.__model, "model_validate", None)):
35-
# Support for pydantic V2
36-
return self.__model.model_validate(data) # type: ignore[unused-ignore,attr-defined]
37-
return self.__model.parse_obj(data)
31+
return self.__model.model_validate(data)
3832

3933
@classmethod
4034
def instantiate(cls, model_type: Any) -> BaseIdempotencySerializer:

aws_lambda_powertools/utilities/parser/envelopes/apigw.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,6 @@ def parse(self, data: Optional[Union[Dict[str, Any], Any]], model: Type[Model])
2727
Parsed detail payload with model provided
2828
"""
2929
logger.debug(f"Parsing incoming data with Api Gateway model {APIGatewayProxyEventModel}")
30-
parsed_envelope: APIGatewayProxyEventModel = APIGatewayProxyEventModel.parse_obj(data)
30+
parsed_envelope: APIGatewayProxyEventModel = APIGatewayProxyEventModel.model_validate(data)
3131
logger.debug(f"Parsing event payload in `detail` with {model}")
3232
return self._parse(data=parsed_envelope.body, model=model)

aws_lambda_powertools/utilities/parser/envelopes/apigwv2.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,6 @@ def parse(self, data: Optional[Union[Dict[str, Any], Any]], model: Type[Model])
2727
Parsed detail payload with model provided
2828
"""
2929
logger.debug(f"Parsing incoming data with Api Gateway model V2 {APIGatewayProxyEventV2Model}")
30-
parsed_envelope: APIGatewayProxyEventV2Model = APIGatewayProxyEventV2Model.parse_obj(data)
30+
parsed_envelope: APIGatewayProxyEventV2Model = APIGatewayProxyEventV2Model.model_validate(data)
3131
logger.debug(f"Parsing event payload in `detail` with {model}")
3232
return self._parse(data=parsed_envelope.body, model=model)

aws_lambda_powertools/utilities/parser/envelopes/bedrock_agent.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,6 @@ def parse(self, data: Optional[Union[Dict[str, Any], Any]], model: Type[Model])
2727
Parsed detail payload with model provided
2828
"""
2929
logger.debug(f"Parsing incoming data with Bedrock Agent model {BedrockAgentEventModel}")
30-
parsed_envelope: BedrockAgentEventModel = BedrockAgentEventModel.parse_obj(data)
30+
parsed_envelope: BedrockAgentEventModel = BedrockAgentEventModel.model_validate(data)
3131
logger.debug(f"Parsing event payload in `input_text` with {model}")
3232
return self._parse(data=parsed_envelope.input_text, model=model)

aws_lambda_powertools/utilities/parser/envelopes/cloudwatch.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def parse(self, data: Optional[Union[Dict[str, Any], Any]], model: Type[Model])
3434
List of records parsed with model provided
3535
"""
3636
logger.debug(f"Parsing incoming data with SNS model {CloudWatchLogsModel}")
37-
parsed_envelope = CloudWatchLogsModel.parse_obj(data)
37+
parsed_envelope = CloudWatchLogsModel.model_validate(data)
3838
logger.debug(f"Parsing CloudWatch records in `body` with {model}")
3939
return [
4040
self._parse(data=record.message, model=model) for record in parsed_envelope.awslogs.decoded_data.logEvents

aws_lambda_powertools/utilities/parser/envelopes/dynamodb.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def parse(self, data: Optional[Union[Dict[str, Any], Any]], model: Type[Model])
3131
List of dictionaries with NewImage and OldImage records parsed with model provided
3232
"""
3333
logger.debug(f"Parsing incoming data with DynamoDB Stream model {DynamoDBStreamModel}")
34-
parsed_envelope = DynamoDBStreamModel.parse_obj(data)
34+
parsed_envelope = DynamoDBStreamModel.model_validate(data)
3535
logger.debug(f"Parsing DynamoDB Stream new and old records with {model}")
3636
return [
3737
{

aws_lambda_powertools/utilities/parser/envelopes/event_bridge.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,6 @@ def parse(self, data: Optional[Union[Dict[str, Any], Any]], model: Type[Model])
2727
Parsed detail payload with model provided
2828
"""
2929
logger.debug(f"Parsing incoming data with EventBridge model {EventBridgeModel}")
30-
parsed_envelope: EventBridgeModel = EventBridgeModel.parse_obj(data)
30+
parsed_envelope: EventBridgeModel = EventBridgeModel.model_validate(data)
3131
logger.debug(f"Parsing event payload in `detail` with {model}")
3232
return self._parse(data=parsed_envelope.detail, model=model)

aws_lambda_powertools/utilities/parser/envelopes/kafka.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def parse(self, data: Optional[Union[Dict[str, Any], Any]], model: Type[Model])
3838
)
3939

4040
logger.debug(f"Parsing incoming data with Kafka event model {model_parse_event}")
41-
parsed_envelope = model_parse_event.parse_obj(data)
41+
parsed_envelope = model_parse_event.model_validate(data)
4242
logger.debug(f"Parsing Kafka event records in `value` with {model}")
4343
ret_list = []
4444
for records in parsed_envelope.records.values():

aws_lambda_powertools/utilities/parser/envelopes/kinesis.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def parse(self, data: Optional[Union[Dict[str, Any], Any]], model: Type[Model])
3535
List of records parsed with model provided
3636
"""
3737
logger.debug(f"Parsing incoming data with Kinesis model {KinesisDataStreamModel}")
38-
parsed_envelope: KinesisDataStreamModel = KinesisDataStreamModel.parse_obj(data)
38+
parsed_envelope: KinesisDataStreamModel = KinesisDataStreamModel.model_validate(data)
3939
logger.debug(f"Parsing Kinesis records in `body` with {model}")
4040
models = []
4141
for record in parsed_envelope.Records:

aws_lambda_powertools/utilities/parser/envelopes/kinesis_firehose.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def parse(self, data: Optional[Union[Dict[str, Any], Any]], model: Type[Model])
3737
List of records parsed with model provided
3838
"""
3939
logger.debug(f"Parsing incoming data with Kinesis Firehose model {KinesisFirehoseModel}")
40-
parsed_envelope: KinesisFirehoseModel = KinesisFirehoseModel.parse_obj(data)
40+
parsed_envelope: KinesisFirehoseModel = KinesisFirehoseModel.model_validate(data)
4141
logger.debug(f"Parsing Kinesis Firehose records in `body` with {model}")
4242
models = []
4343
for record in parsed_envelope.records:

aws_lambda_powertools/utilities/parser/envelopes/lambda_function_url.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,6 @@ def parse(self, data: Optional[Union[Dict[str, Any], Any]], model: Type[Model])
2727
Parsed detail payload with model provided
2828
"""
2929
logger.debug(f"Parsing incoming data with Lambda function URL model {LambdaFunctionUrlModel}")
30-
parsed_envelope: LambdaFunctionUrlModel = LambdaFunctionUrlModel.parse_obj(data)
30+
parsed_envelope: LambdaFunctionUrlModel = LambdaFunctionUrlModel.model_validate(data)
3131
logger.debug(f"Parsing event payload in `detail` with {model}")
3232
return self._parse(data=parsed_envelope.body, model=model)

aws_lambda_powertools/utilities/parser/envelopes/sns.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def parse(self, data: Optional[Union[Dict[str, Any], Any]], model: Type[Model])
3434
List of records parsed with model provided
3535
"""
3636
logger.debug(f"Parsing incoming data with SNS model {SnsModel}")
37-
parsed_envelope = SnsModel.parse_obj(data)
37+
parsed_envelope = SnsModel.model_validate(data)
3838
logger.debug(f"Parsing SNS records in `body` with {model}")
3939
return [self._parse(data=record.Sns.Message, model=model) for record in parsed_envelope.Records]
4040

@@ -66,11 +66,11 @@ def parse(self, data: Optional[Union[Dict[str, Any], Any]], model: Type[Model])
6666
List of records parsed with model provided
6767
"""
6868
logger.debug(f"Parsing incoming data with SQS model {SqsModel}")
69-
parsed_envelope = SqsModel.parse_obj(data)
69+
parsed_envelope = SqsModel.model_validate(data)
7070
output = []
7171
for record in parsed_envelope.Records:
7272
# We allow either AWS expected contract (str) or a custom Model, see #943
7373
body = cast(str, record.body)
74-
sns_notification = SnsNotificationModel.parse_raw(body)
74+
sns_notification = SnsNotificationModel.model_validate_json(body)
7575
output.append(self._parse(data=sns_notification.Message, model=model))
7676
return output

aws_lambda_powertools/utilities/parser/envelopes/sqs.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,6 @@ def parse(self, data: Optional[Union[Dict[str, Any], Any]], model: Type[Model])
3434
List of records parsed with model provided
3535
"""
3636
logger.debug(f"Parsing incoming data with SQS model {SqsModel}")
37-
parsed_envelope = SqsModel.parse_obj(data)
37+
parsed_envelope = SqsModel.model_validate(data)
3838
logger.debug(f"Parsing SQS records in `body` with {model}")
3939
return [self._parse(data=record.body, model=model) for record in parsed_envelope.Records]

aws_lambda_powertools/utilities/parser/envelopes/vpc_lattice.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,6 @@ def parse(self, data: Optional[Union[Dict[str, Any], Any]], model: Type[Model])
2727
Parsed detail payload with model provided
2828
"""
2929
logger.debug(f"Parsing incoming data with VPC Lattice model {VpcLatticeModel}")
30-
parsed_envelope: VpcLatticeModel = VpcLatticeModel.parse_obj(data)
30+
parsed_envelope: VpcLatticeModel = VpcLatticeModel.model_validate(data)
3131
logger.debug(f"Parsing event payload in `detail` with {model}")
3232
return self._parse(data=parsed_envelope.body, model=model)

aws_lambda_powertools/utilities/parser/envelopes/vpc_latticev2.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,6 @@ def parse(self, data: Optional[Union[Dict[str, Any], Any]], model: Type[Model])
2727
Parsed detail payload with model provided
2828
"""
2929
logger.debug(f"Parsing incoming data with VPC Lattice V2 model {VpcLatticeV2Model}")
30-
parsed_envelope: VpcLatticeV2Model = VpcLatticeV2Model.parse_obj(data)
30+
parsed_envelope: VpcLatticeV2Model = VpcLatticeV2Model.model_validate(data)
3131
logger.debug(f"Parsing event payload in `detail` with {model}")
3232
return self._parse(data=parsed_envelope.body, model=model)

aws_lambda_powertools/utilities/parser/models/s3.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ class S3RecordModel(BaseModel):
101101
s3: S3Message
102102
glacierEventData: Optional[S3EventRecordGlacierEventData] = None
103103

104-
@root_validator(allow_reuse=True, skip_on_failure=True)
104+
@root_validator(allow_reuse=True, skip_on_failure=True) # review
105105
def validate_s3_object(cls, values):
106106
event_name = values.get("eventName")
107107
s3_object = values.get("s3").object

aws_lambda_powertools/utilities/parser/models/s3_batch_operation.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class S3BatchOperationTaskModel(BaseModel):
1212
s3BucketArn: Optional[str] = None
1313
s3Bucket: Optional[str] = None
1414

15-
@validator("s3Bucket", pre=True, always=True)
15+
@validator("s3Bucket", pre=True, always=True) # review
1616
def validate_bucket(cls, current_value, values):
1717
# Get the s3 bucket, either from 's3Bucket' property (invocationSchemaVersion '2.0')
1818
# or from 's3BucketArn' (invocationSchemaVersion '1.0')

docs/utilities/parser.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ Here's a snippet of how the EventBridge envelope we demonstrated previously is i
414414
Any
415415
Parsed detail payload with model provided
416416
"""
417-
parsed_envelope = EventBridgeModel.parse_obj(data)
417+
parsed_envelope = EventBridgeModel.model_validate(data)
418418
return self._parse(data=parsed_envelope.detail, model=model)
419419
```
420420

tests/functional/batch/sample_models.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import json
22
from typing import Dict, Optional
33

4-
from aws_lambda_powertools.utilities.parser import BaseModel, validator
4+
from pydantic import field_validator
5+
6+
from aws_lambda_powertools.utilities.parser import BaseModel
57
from aws_lambda_powertools.utilities.parser.models import (
68
DynamoDBStreamChangedRecordModel,
79
DynamoDBStreamRecordModel,
@@ -33,7 +35,7 @@ class OrderDynamoDB(BaseModel):
3335

3436
# auto transform json string
3537
# so Pydantic can auto-initialize nested Order model
36-
@validator("Message", pre=True)
38+
@field_validator("Message", mode="before")
3739
def transform_message_to_dict(cls, value: Dict[Literal["S"], str]):
3840
try:
3941
return json.loads(value["S"])

tests/functional/event_handler/test_openapi_encoders.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import pytest
66
from pydantic import BaseModel
7-
from pydantic.color import Color
7+
from pydantic.color import Color # review
88

99
from aws_lambda_powertools.event_handler.openapi.encoders import jsonable_encoder
1010

tests/functional/event_handler/test_openapi_responses.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,12 @@ class User(BaseModel):
8888

8989
@app.get(
9090
"/",
91-
responses={200: {"description": "Custom response", "content": {"application/json": {"schema": User.schema()}}}},
91+
responses={
92+
200: {
93+
"description": "Custom response",
94+
"content": {"application/json": {"schema": User.model_json_schema()}},
95+
},
96+
},
9297
)
9398
def handler():
9499
return {"message": "hello world"}

tests/functional/idempotency/test_idempotency.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1344,7 +1344,7 @@ class PaymentOutput(BaseModel):
13441344
output_serializer=output_serializer,
13451345
)
13461346
def collect_payment(payment: PaymentInput) -> PaymentOutput:
1347-
return PaymentOutput(**payment.dict())
1347+
return PaymentOutput(**payment.model_dump())
13481348

13491349
# WHEN
13501350
payment = PaymentInput(**mock_event)
@@ -1383,7 +1383,7 @@ class PaymentOutput(BaseModel):
13831383

13841384
@idempotent_function_decorator
13851385
def collect_payment(payment: PaymentInput):
1386-
return PaymentOutput(**payment.dict())
1386+
return PaymentOutput(**payment.model_dump())
13871387

13881388

13891389
def test_idempotent_function_serialization_pydantic_failure_bad_type():
@@ -1411,7 +1411,7 @@ class PaymentOutput(BaseModel):
14111411

14121412
@idempotent_function_decorator
14131413
def collect_payment(payment: PaymentInput) -> dict:
1414-
return PaymentOutput(**payment.dict())
1414+
return PaymentOutput(**payment.model_dump())
14151415

14161416

14171417
@pytest.mark.parametrize("output_serializer_type", ["explicit", "deduced"])
@@ -1747,7 +1747,7 @@ class Foo(BaseModel):
17471747
expected_result = {"name": "Bar"}
17481748
data = Foo(name="Bar")
17491749
as_dict = _prepare_data(data)
1750-
assert as_dict == data.dict()
1750+
assert as_dict == data.model_dump()
17511751
assert as_dict == expected_result
17521752

17531753

tests/functional/test_utilities_batch.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import pytest
77
from botocore.config import Config
8+
from pydantic import field_validator
89

910
from aws_lambda_powertools.utilities.batch import (
1011
AsyncBatchProcessor,
@@ -24,7 +25,7 @@
2425
KinesisStreamRecord,
2526
)
2627
from aws_lambda_powertools.utilities.data_classes.sqs_event import SQSRecord
27-
from aws_lambda_powertools.utilities.parser import BaseModel, validator
28+
from aws_lambda_powertools.utilities.parser import BaseModel
2829
from aws_lambda_powertools.utilities.parser.models import (
2930
DynamoDBStreamChangedRecordModel,
3031
DynamoDBStreamRecordModel,
@@ -523,7 +524,7 @@ class OrderDynamoDB(BaseModel):
523524

524525
# auto transform json string
525526
# so Pydantic can auto-initialize nested Order model
526-
@validator("Message", pre=True)
527+
@field_validator("Message", mode="before")
527528
def transform_message_to_dict(cls, value: Dict[Literal["S"], str]):
528529
return json.loads(value["S"])
529530

@@ -567,7 +568,7 @@ class OrderDynamoDB(BaseModel):
567568

568569
# auto transform json string
569570
# so Pydantic can auto-initialize nested Order model
570-
@validator("Message", pre=True)
571+
@field_validator("Message", mode="before")
571572
def transform_message_to_dict(cls, value: Dict[Literal["S"], str]):
572573
return json.loads(value["S"])
573574

0 commit comments

Comments
 (0)