Summary
This release adds support for the AppConfig Agent Lambda extension in Parameters and Feature Flags, brings Depends() injection to middlewares in Event Handler, and ships the Lambda layer with precompiled bytecode for faster cold starts. It also fixes bugs across Event Handler, Streaming, Idempotency, Circuit Breaker, Data Classes and Parser.
We are happy to welcome seven new contributors in this release: @abhinavs1920, @AtulJoshi1206, @unknownhackerworld, @LuisFigueroaG, @ArfiArfath21, @vyrnsynx and @reginaldalfret. Thank you for the reports, the fixes and the patience during reviews. Thanks also to @LemonCondor, @xili-ytl, @chiruu12 and @exg for coming back with more.
AppConfig Agent Lambda extension
The AppConfig Agent runs as a Lambda extension next to your function, polls AppConfig for you and serves the configuration over localhost. Reading from it takes a couple of milliseconds instead of a round trip to the service, and your function doesn't need an SDK client for it.
You can now read from the extension with AppConfigExtensionProvider:
from aws_lambda_powertools.utilities.parameters import AppConfigExtensionProvider
provider = AppConfigExtensionProvider(environment="prod", application="orders")
config = provider.get("features", transform="json")Feature Flags support it too. Pass use_extension=True to AppConfigStore, or use AppConfigExtensionStore:
from aws_lambda_powertools.utilities.feature_flags import AppConfigExtensionStore, FeatureFlags
store = AppConfigExtensionStore(environment="prod", application="orders", name="features")
feature_flags = FeatureFlags(store=store)The extension is configured through its own environment variables, such as AWS_APPCONFIG_EXTENSION_PREFETCH_LIST and AWS_APPCONFIG_EXTENSION_POLL_INTERVAL_SECONDS, and you attach the AWS-AppConfig-Extension layer to your function. The docs list the variables and the layer ARNs.
Depends() in middlewares
Function-based middlewares can now declare Depends() parameters, the same way route handlers do. Dependencies are resolved before the middleware runs, share the per-request cache with the route, and honour dependency_overrides in tests.
def user_middleware(
app: APIGatewayHttpResolver,
next_middleware: NextMiddleware,
user_dao: Annotated[UserDao, Depends(get_user_dao)],
):
sub = app.current_event.request_context.authorizer.jwt_claim.get("sub")
if sub and (user := user_dao.get(sub)):
app.append_context(user=user)
return next_middleware(app)
app.use(middlewares=[user_middleware])Exceptions raised inside a dependency are now handled like exceptions raised by the route: a ServiceError becomes the matching HTTP response and your exception_handler runs. Thank you @abhinavs1920 for the middleware support and @AtulJoshi1206 for the exception handling.
Faster cold starts with the Lambda layer
The Lambda layer now ships precompiled bytecode for every module, so Python skips compilation on cold start. Nothing changes in how you use the layer; it grows a few megabytes. Parser event models are also loaded on demand now, so importing aws_lambda_powertools.utilities.parser.models no longer builds every model up front.
Changes
- feat(parameters): add AppConfigExtensionProvider for the AppConfig Agent Lambda extension (#8562) by @leandrodamascena
- feat(event_handler): support Depends() injection in function-based middleware (#8573) by @abhinavs1920
- perf(layer): precompile Python sources in Lambda layers (#8520) by @leandrodamascena
- perf(parser): load event models on demand (#8519) by @leandrodamascena
- fix(event_handler): handle exceptions raised in Depends() like route exceptions (#8568) by @AtulJoshi1206
- fix(event_handler): route VPC Lattice requests that carry a query string (#8572) by @AtulJoshi1206
- fix(event_handler): resolve Depends() and Request params with a None default on Python 3.10 (#8649) by @leandrodamascena
- fix(event_handler): clear context when route resolution raises (#8539) by @vyrnsynx
- fix(event_handler): match AppSync Events wildcard routes on segment boundaries (#8546) by @LemonCondor
- fix(event_handler): preserve commas in scalar query and header parameters (#8509) by @leandrodamascena
- fix(idempotency): serialize PydanticSerializer output in JSON mode (#8570) by @AtulJoshi1206
- fix(circuit_breaker): start a fresh probe success streak on each probe election (#8646) by @unknownhackerworld
- fix(streaming): respect size in S3Object.readline (#8558) by @xili-ytl
- fix(streaming): report S3Object as closed after close() without building the transformed stream (#8566) by @ArfiArfath21
- fix(streaming): keep CsvTransform options intact across repeated use (#8565) by @ArfiArfath21
- fix(data-classes): keep CaseInsensitiveDict on copy and merge (#8537) by @chiruu12
- fix(data-classes): use user_uid for the Uid in Transfer Family PosixProfile (#8524) by @LuisFigueroaG
- fix(parser): support camelCase replyTo in SesMailCommonHeaders (#8542) by @reginaldalfret
- test(parser): cover optional SES common headers including replyTo (#8525) by @LuisFigueroaG
- refactor(typing): add type hints to middleware-based decorators (#8541) by @exg
📜 Documentation updates
- chore(docs): migrate docs build from MkDocs to Zensical (#8585) by @leandrodamascena
🔧 Maintenance
- chore(lint): enable Python 3.10 pyupgrade rules (#8561) by @leandrodamascena
- ci: optimize quality checks and isolate dependency tests (#8535) by @leandrodamascena
- chore(deps): bump fastjsonschema, isort, ijson, cfn-lint and ruff (#8647) by @leandrodamascena
- chore(deps): bump the github-actions group with 2 updates (#8644) by @dependabot[bot]