Skip to content

Commit f0ff926

Browse files
committed
improv: simplify base envelope; increase test cov
1 parent 292c045 commit f0ff926

File tree

9 files changed

+38
-45
lines changed

9 files changed

+38
-45
lines changed

aws_lambda_powertools/utilities/parser/envelopes/base.py

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,30 +11,21 @@
1111

1212
class BaseEnvelope(ABC):
1313
@staticmethod
14-
def _parse_user_dict_schema(user_event: Dict[str, Any], schema: BaseModel) -> Any:
15-
if user_event is None:
16-
return None
14+
def _parse(event: Dict[str, Any], schema: BaseModel) -> Any:
15+
if event is None:
16+
logger.debug("Skipping parsing as event is None")
17+
return event
1718

1819
try:
19-
logger.debug("parsing user dictionary schema")
20-
return schema(**user_event)
20+
logger.debug("parsing event against schema")
21+
if isinstance(event, str):
22+
logger.debug("parsing event as string")
23+
return schema.parse_raw(event)
24+
else:
25+
return schema.parse_obj(event)
2126
except (ValidationError, TypeError) as e:
2227
raise SchemaValidationError("Failed to extract custom schema") from e
2328

24-
@staticmethod
25-
def _parse_user_json_string_schema(user_event: str, schema: BaseModel) -> Any:
26-
# this is used in cases where the underlying schema is not a Dict that can be parsed as baseModel
27-
# but a plain string as payload i.e. SQS: "body": "Test message."
28-
if schema is str:
29-
logger.debug("input is string, returning")
30-
return user_event
31-
32-
try:
33-
logger.debug("trying to parse as json encoded string")
34-
return schema.parse_raw(user_event)
35-
except (ValidationError, TypeError) as e:
36-
raise SchemaValidationError("Failed to extract custom schema from JSON string") from e
37-
3829
@abstractmethod
3930
def parse(self, event: Dict[str, Any], schema: BaseModel):
4031
return NotImplemented # pragma: no cover

aws_lambda_powertools/utilities/parser/envelopes/dynamodb.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ def parse(self, event: Dict[str, Any], schema: BaseModel) -> List[Dict[Literal["
4747
for record in parsed_envelope.Records:
4848
output.append(
4949
{
50-
"NewImage": self._parse_user_dict_schema(record.dynamodb.NewImage, schema),
51-
"OldImage": self._parse_user_dict_schema(record.dynamodb.OldImage, schema),
50+
"NewImage": self._parse(record.dynamodb.NewImage, schema),
51+
"OldImage": self._parse(record.dynamodb.OldImage, schema),
5252
}
5353
)
5454
return output

aws_lambda_powertools/utilities/parser/envelopes/event_bridge.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,4 @@ def parse(self, event: Dict[str, Any], schema: BaseModel) -> BaseModel:
3838
parsed_envelope = EventBridgeSchema(**event)
3939
except ValidationError as e:
4040
raise SchemaValidationError("EventBridge input doesn't conform with schema") from e
41-
return self._parse_user_dict_schema(parsed_envelope.detail, schema)
41+
return self._parse(parsed_envelope.detail, schema)

aws_lambda_powertools/utilities/parser/envelopes/sqs.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,5 @@ def parse(self, event: Dict[str, Any], schema: Union[BaseModel, str]) -> List[Un
4444
parsed_envelope = SqsSchema(**event)
4545
except (ValidationError, TypeError) as e:
4646
raise SchemaValidationError("SQS input doesn't conform with schema") from e
47-
output = []
48-
for record in parsed_envelope.Records:
49-
output.append(self._parse_user_json_string_schema(record.body, schema))
47+
output = [self._parse(record.body, schema) for record in parsed_envelope.Records]
5048
return output

aws_lambda_powertools/utilities/parser/exceptions.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,7 @@ class InvalidEnvelopeError(Exception):
44

55
class SchemaValidationError(Exception):
66
"""Input data does not conform with schema"""
7+
8+
9+
class InvalidSchemaTypeError(Exception):
10+
"""Input schema does not implement BaseModel"""

aws_lambda_powertools/utilities/parser/parser.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from aws_lambda_powertools.middleware_factory import lambda_handler_decorator
77

88
from .envelopes.base import BaseEnvelope, parse_envelope
9-
from .exceptions import SchemaValidationError
9+
from .exceptions import InvalidSchemaTypeError, SchemaValidationError
1010

1111
logger = logging.getLogger(__name__)
1212

@@ -52,17 +52,19 @@ def handler(event: MyBusiness , context: LambdaContext):
5252
------
5353
SchemaValidationError
5454
When input event doesn't conform with schema provided
55+
InvalidSchemaTypeError
56+
When schema given does not implement BaseModel
5557
"""
5658
if envelope is None:
5759
try:
5860
logger.debug("Parsing and validating event schema; no envelope used")
59-
parsed_event = schema(**event)
60-
except ValidationError as e:
61+
parsed_event = schema.parse_obj(event)
62+
except (ValidationError, TypeError) as e:
6163
raise SchemaValidationError("Input event doesn't conform with schema") from e
62-
64+
except AttributeError:
65+
raise InvalidSchemaTypeError("Input schema must implement BaseModel")
6366
else:
6467
parsed_event = parse_envelope(event, envelope, schema)
6568

66-
lambda_handler_name = handler.__name__
67-
logger.debug(f"Calling handler {lambda_handler_name}")
69+
logger.debug(f"Calling handler {handler.__name__}")
6870
return handler(parsed_event, context)

tests/functional/parser/conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,6 @@ def parse(self, event: Dict[str, Any], schema: BaseModel):
4242
parsed_enveloped = dummy_envelope_schema(**event)
4343
except (ValidationError, TypeError) as e:
4444
raise SchemaValidationError("Dummy input doesn't conform with schema") from e
45-
return self._parse_user_dict_schema(user_event=parsed_enveloped.payload, schema=schema)
45+
return self._parse(event=parsed_enveloped.payload, schema=schema)
4646

4747
return MyDummyEnvelope

tests/functional/parser/test_parser.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ def test_parser_unsupported_event(dummy_schema, invalid_value):
1212
def handle_no_envelope(event: Dict, _: LambdaContext):
1313
return event
1414

15-
with pytest.raises(TypeError):
15+
with pytest.raises(exceptions.SchemaValidationError):
1616
handle_no_envelope(event=invalid_value, context=LambdaContext())
1717

1818

@@ -40,3 +40,13 @@ def handle_no_envelope(event: Dict, _: LambdaContext):
4040
return event
4141

4242
handle_no_envelope(dummy_event["payload"], LambdaContext())
43+
44+
45+
@pytest.mark.parametrize("invalid_schema", [None, str, bool(), [], (), object])
46+
def test_parser_with_invalid_schema_type(dummy_event, invalid_schema):
47+
@parser(schema=invalid_schema)
48+
def handle_no_envelope(event: Dict, _: LambdaContext):
49+
return event
50+
51+
with pytest.raises(exceptions.InvalidSchemaTypeError):
52+
handle_no_envelope(event=dummy_event, context=LambdaContext())

tests/functional/parser/test_sqs.py

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,6 @@
99
from tests.functional.validator.conftest import sqs_event # noqa: F401
1010

1111

12-
@parser(schema=str, envelope=envelopes.SQS)
13-
def handle_sqs_str_body(event: List[str], _: LambdaContext):
14-
assert len(event) == 2
15-
assert event[0] == "Test message."
16-
assert event[1] == "Test message2."
17-
18-
19-
def test_handle_sqs_trigger_event_str_body():
20-
event_dict = load_event("sqsEvent.json")
21-
handle_sqs_str_body(event_dict, LambdaContext())
22-
23-
2412
@parser(schema=MySqsBusiness, envelope=envelopes.SQS)
2513
def handle_sqs_json_body(event: List[MySqsBusiness], _: LambdaContext):
2614
assert len(event) == 1

0 commit comments

Comments
 (0)