Skip to content

Commit 3750d55

Browse files
committed
improv: address Koudai's PR feedback
1 parent 9e42863 commit 3750d55

File tree

6 files changed

+42
-36
lines changed

6 files changed

+42
-36
lines changed

aws_lambda_powertools/utilities/parser/envelopes/base.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import logging
22
from abc import ABC, abstractmethod
3-
from typing import Any, Dict, Union
3+
from typing import Any, Dict, TypeVar, Union
44

5-
from pydantic import BaseModel
5+
from ..types import Model
66

77
logger = logging.getLogger(__name__)
88

@@ -11,14 +11,14 @@ class BaseEnvelope(ABC):
1111
"""ABC implementation for creating a supported Envelope"""
1212

1313
@staticmethod
14-
def _parse(data: Union[Dict[str, Any], str], model: BaseModel) -> Any:
14+
def _parse(data: Union[Dict[str, Any], str], model: Model) -> Model:
1515
"""Parses envelope data against model provided
1616
1717
Parameters
1818
----------
1919
data : Dict
2020
Data to be parsed and validated
21-
model
21+
model : Model
2222
Data model to parse and validate data against
2323
2424
Returns
@@ -38,7 +38,7 @@ def _parse(data: Union[Dict[str, Any], str], model: BaseModel) -> Any:
3838
return model.parse_obj(data)
3939

4040
@abstractmethod
41-
def parse(self, data: Dict[str, Any], model: BaseModel):
41+
def parse(self, data: Dict[str, Any], model: Model):
4242
"""Implementation to parse data against envelope model, then against the data model
4343
4444
NOTE: Call `_parse` method to fully parse data with model provided.
@@ -56,3 +56,8 @@ def parse(...):
5656
return self._parse(data=parsed_envelope.detail, model=data_model)
5757
"""
5858
return NotImplemented # pragma: no cover
59+
60+
61+
# Generic to support type annotations throughout parser
62+
# Note: Can't be defined under types.py due to circular dependency
63+
Envelope = TypeVar("Envelope", bound=BaseEnvelope)

aws_lambda_powertools/utilities/parser/envelopes/dynamodb.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import logging
22
from typing import Any, Dict, List
33

4-
from pydantic import BaseModel
54
from typing_extensions import Literal
65

76
from ..models import DynamoDBStreamModel
7+
from ..types import Model
88
from .base import BaseEnvelope
99

1010
logger = logging.getLogger(__name__)
@@ -17,14 +17,14 @@ class DynamoDBStreamEnvelope(BaseEnvelope):
1717
length of the list is the record's amount in the original event.
1818
"""
1919

20-
def parse(self, data: Dict[str, Any], model: BaseModel) -> List[Dict[Literal["NewImage", "OldImage"], BaseModel]]:
20+
def parse(self, data: Dict[str, Any], model: Model) -> List[Dict[Literal["NewImage", "OldImage"], Model]]:
2121
"""Parses DynamoDB Stream records found in either NewImage and OldImage with model provided
2222
2323
Parameters
2424
----------
2525
data : Dict
2626
Lambda event to be parsed
27-
model : BaseModel
27+
model : Model
2828
Data model provided to parse after extracting data using envelope
2929
3030
Returns
@@ -33,14 +33,14 @@ def parse(self, data: Dict[str, Any], model: BaseModel) -> List[Dict[Literal["Ne
3333
List of records parsed with model provided
3434
"""
3535
logger.debug(f"Parsing incoming data with DynamoDB Stream model {DynamoDBStreamModel}")
36-
parsed_envelope = DynamoDBStreamModel(**data)
36+
parsed_envelope = DynamoDBStreamModel.parse_obj(data)
3737
output = []
3838
logger.debug(f"Parsing DynamoDB Stream new and old records with {model}")
3939
for record in parsed_envelope.Records:
4040
output.append(
4141
{
42-
"NewImage": self._parse(record.dynamodb.NewImage, model),
43-
"OldImage": self._parse(record.dynamodb.OldImage, model),
42+
"NewImage": self._parse(data=record.dynamodb.NewImage, model=model),
43+
"OldImage": self._parse(data=record.dynamodb.OldImage, model=model),
4444
}
4545
)
4646
# noinspection PyTypeChecker
Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import logging
22
from typing import Any, Dict
33

4-
from pydantic import BaseModel
5-
64
from ..models import EventBridgeModel
5+
from ..types import Model
76
from .base import BaseEnvelope
87

98
logger = logging.getLogger(__name__)
@@ -12,14 +11,14 @@
1211
class EventBridgeEnvelope(BaseEnvelope):
1312
"""EventBridge envelope to extract data within detail key"""
1413

15-
def parse(self, data: Dict[str, Any], model: BaseModel) -> BaseModel:
14+
def parse(self, data: Dict[str, Any], model: Model) -> Model:
1615
"""Parses data found with model provided
1716
1817
Parameters
1918
----------
2019
data : Dict
2120
Lambda event to be parsed
22-
model : BaseModel
21+
model : Model
2322
Data model provided to parse after extracting data using envelope
2423
2524
Returns
@@ -28,6 +27,6 @@ def parse(self, data: Dict[str, Any], model: BaseModel) -> BaseModel:
2827
Parsed detail payload with model provided
2928
"""
3029
logger.debug(f"Parsing incoming data with EventBridge model {EventBridgeModel}")
31-
parsed_envelope = EventBridgeModel(**data)
30+
parsed_envelope = EventBridgeModel.parse_obj(data)
3231
logger.debug(f"Parsing event payload in `detail` with {model}")
3332
return self._parse(data=parsed_envelope.detail, model=model)

aws_lambda_powertools/utilities/parser/envelopes/sqs.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import logging
2-
from typing import Any, Dict, List, Union
3-
4-
from pydantic import BaseModel
2+
from typing import Any, Dict, List
53

64
from ..models import SqsModel
5+
from ..types import Model
76
from .base import BaseEnvelope
87

98
logger = logging.getLogger(__name__)
@@ -19,14 +18,14 @@ class SqsEnvelope(BaseEnvelope):
1918
all items in the list will be parsed as str and npt as JSON (and vice versa)
2019
"""
2120

22-
def parse(self, data: Dict[str, Any], model: Union[BaseModel, str]) -> List[BaseModel]:
21+
def parse(self, data: Dict[str, Any], model: Model) -> List[Model]:
2322
"""Parses records found with model provided
2423
2524
Parameters
2625
----------
2726
data : Dict
2827
Lambda event to be parsed
29-
model : BaseModel
28+
model : Model
3029
Data model provided to parse after extracting data using envelope
3130
3231
Returns
@@ -35,9 +34,9 @@ def parse(self, data: Dict[str, Any], model: Union[BaseModel, str]) -> List[Base
3534
List of records parsed with model provided
3635
"""
3736
logger.debug(f"Parsing incoming data with SQS model {SqsModel}")
38-
parsed_envelope = SqsModel(**data)
37+
parsed_envelope = SqsModel.parse_obj(data)
3938
output = []
4039
logger.debug(f"Parsing SQS records in `body` with {model}")
4140
for record in parsed_envelope.Records:
42-
output.append(self._parse(record.body, model))
41+
output.append(self._parse(data=record.body, model=model))
4342
return output

aws_lambda_powertools/utilities/parser/parser.py

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
11
import logging
2-
from typing import Any, Callable, Dict, Optional, Type, TypeVar
3-
4-
from pydantic import BaseModel
2+
from typing import Any, Callable, Dict, Optional
53

64
from ...middleware_factory import lambda_handler_decorator
75
from ..typing import LambdaContext
8-
from .envelopes.base import BaseEnvelope
6+
from .envelopes.base import Envelope
97
from .exceptions import InvalidEnvelopeError, InvalidModelTypeError
8+
from .types import Model
109

11-
Model = TypeVar("Model", bound=BaseModel)
12-
Envelope = TypeVar("Envelope", bound=BaseEnvelope)
1310
logger = logging.getLogger(__name__)
1411

1512

@@ -18,8 +15,8 @@ def event_parser(
1815
handler: Callable[[Dict, Any], Any],
1916
event: Dict[str, Any],
2017
context: LambdaContext,
21-
model: Type[Model],
22-
envelope: Optional[Type[Envelope]] = None,
18+
model: Model,
19+
envelope: Optional[Envelope] = None,
2320
) -> Any:
2421
"""Lambda handler decorator to parse & validate events using Pydantic models
2522
@@ -67,9 +64,9 @@ def handler(event: Order, context: LambdaContext):
6764
Lambda event to be parsed & validated
6865
context: LambdaContext
6966
Lambda context object
70-
model: BaseModel
67+
model: Model
7168
Your data model that will replace the event.
72-
envelope: BaseEnvelope
69+
envelope: Envelope
7370
Optional envelope to extract the model from
7471
7572
Raises
@@ -86,7 +83,7 @@ def handler(event: Order, context: LambdaContext):
8683
return handler(parsed_event, context)
8784

8885

89-
def parse(event: Dict[str, Any], model: Type[Model], envelope: Optional[Type[Envelope]] = None) -> Any:
86+
def parse(event: Dict[str, Any], model: Model, envelope: Optional[Envelope] = None) -> Model:
9087
"""Standalone function to parse & validate events using Pydantic models
9188
9289
Typically used when you need fine-grained control over error handling compared to event_parser decorator.
@@ -126,9 +123,9 @@ def handler(event: Order, context: LambdaContext):
126123
----------
127124
event: Dict
128125
Lambda event to be parsed & validated
129-
model: BaseModel
126+
model: Model
130127
Your data model that will replace the event
131-
envelope: BaseEnvelope
128+
envelope: Envelope
132129
Optional envelope to extract the model from
133130
134131
Raises
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
"""Generics and other shared types used across parser"""
2+
from typing import TypeVar
3+
4+
from pydantic import BaseModel
5+
6+
Model = TypeVar("Model", bound=BaseModel)

0 commit comments

Comments
 (0)