Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions aws_lambda_powertools/utilities/parser/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,30 @@
"""Advanced event_parser utility"""

from __future__ import annotations

from typing import TYPE_CHECKING

from pydantic import BaseModel, Field, ValidationError, field_validator, model_validator

from aws_lambda_powertools.utilities.parser import envelopes
from aws_lambda_powertools.utilities.parser.envelopes import BaseEnvelope
from aws_lambda_powertools.utilities.parser.parser import event_parser, parse

if TYPE_CHECKING:
from aws_lambda_powertools.utilities.parser import envelopes as envelopes
from aws_lambda_powertools.utilities.parser.envelopes import BaseEnvelope


def __getattr__(name: str) -> object:
if name == "envelopes":
from aws_lambda_powertools.utilities.parser import envelopes as _envelopes # noqa: PLC0415

return _envelopes
if name == "BaseEnvelope":
from aws_lambda_powertools.utilities.parser.envelopes import BaseEnvelope as _BaseEnvelope # noqa: PLC0415

return _BaseEnvelope
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")


__all__ = [
"event_parser",
"parse",
Expand Down
27 changes: 27 additions & 0 deletions tests/functional/parser/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,3 +308,30 @@ def handler(event: SqsModel, _: LambdaContext):
assert parsed_event[0].version == "version"

handler(event, LambdaContext())


def test_parser_import_does_not_eagerly_load_envelopes():
"""Importing parse from parser __init__ must not eagerly load all envelope modules.

Envelopes are only needed when envelope= is passed to parse()/event_parser().
Eager loading all 16 envelopes adds ~900ms to Lambda cold start for functions
that only use parse() without an envelope.
"""
import sys

# Remove any previously cached parser modules to simulate a fresh import
parser_modules = [key for key in sys.modules if "aws_lambda_powertools.utilities.parser.envelopes" in key]
for mod in parser_modules:
del sys.modules[mod]

# Also remove the parser __init__ itself so __getattr__ is exercised
sys.modules.pop("aws_lambda_powertools.utilities.parser", None)

# Re-import — only parse is needed, envelopes should NOT be loaded
from aws_lambda_powertools.utilities.parser import parse # noqa: F401

envelope_modules_loaded = [key for key in sys.modules if "aws_lambda_powertools.utilities.parser.envelopes" in key]
assert not envelope_modules_loaded, (
f"Envelope modules were eagerly loaded on parser import: {envelope_modules_loaded}. "
"This adds significant Lambda cold start latency for functions not using envelopes."
)