Skip to content

feat(parser): infer model from type hint #3181

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
merged 8 commits into from
Oct 12, 2023
16 changes: 13 additions & 3 deletions aws_lambda_powertools/utilities/parser/parser.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import logging
import typing
from typing import Any, Callable, Dict, Optional, Type, overload

from aws_lambda_powertools.utilities.parser.compat import disable_pydantic_v2_warning
Expand All @@ -17,7 +18,7 @@ def event_parser(
handler: Callable[[Any, LambdaContext], EventParserReturnType],
event: Dict[str, Any],
context: LambdaContext,
model: Type[Model],
model: Type[Model] = None,
envelope: Optional[Type[Envelope]] = None,
) -> EventParserReturnType:
"""Lambda handler decorator to parse & validate events using Pydantic models
Expand Down Expand Up @@ -76,11 +77,20 @@ def handler(event: Order, context: LambdaContext):
ValidationError
When input event does not conform with model provided
InvalidModelTypeError
When model given does not implement BaseModel
When model given does not implement BaseModel or is not provided
InvalidEnvelopeError
When envelope given does not implement BaseEnvelope
"""
parsed_event = parse(event=event, model=model, envelope=envelope) if envelope else parse(event=event, model=model)
if model is None:
type_hints = typing.get_type_hints(handler)
model = type_hints.get("event")
if model is None:
raise InvalidModelTypeError(
"The model must be provided either as the `model` argument to `event_parser`"
"or as the type hint of `event` in the handler that it wraps",
)

parsed_event = parse(event=event, model=model, envelope=envelope)
logger.debug(f"Calling handler {handler.__name__}")
return handler(parsed_event, context)

Expand Down
17 changes: 17 additions & 0 deletions tests/functional/parser/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,20 @@ def handle_no_envelope(event: Union[Dict, str], _: LambdaContext):
return event

handle_no_envelope(dummy_event, LambdaContext())


def test_parser_event_with_type_hint(dummy_event, dummy_schema):
@event_parser()
def handler(event: dummy_schema, _: LambdaContext):
assert event.message == "hello world"

handler(dummy_event["payload"], LambdaContext())


def test_parser_event_without_type_hint(dummy_event, dummy_schema):
@event_parser()
def handler(event, _):
assert event.message == "hello world"

with pytest.raises(exceptions.InvalidModelTypeError):
handler(dummy_event["payload"], LambdaContext())