Skip to content

Commit 114caa1

Browse files
authored
Merge branch 'develop' into firehose
2 parents 0b48268 + a5755d4 commit 114caa1

File tree

79 files changed

+987
-182
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+987
-182
lines changed

CHANGELOG.md

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,39 +4,63 @@
44
<a name="unreleased"></a>
55
# Unreleased
66

7+
## Documentation
8+
9+
* **readme:** add lambda layer latest version badge
10+
11+
## Maintenance
12+
13+
* **layer:** bump to latest version 37
14+
15+
16+
<a name="v1.30.0"></a>
17+
## [v1.30.0] - 2022-10-05
718
## Bug Fixes
819

920
* **apigateway:** update Response class to require status_code only ([#1560](https://github.com/awslabs/aws-lambda-powertools-python/issues/1560))
21+
* **ci:** integrate isort 5.0 with black to resolve conflicts
1022
* **event_sources:** implement Mapping protocol on DictWrapper for better interop with existing middlewares ([#1516](https://github.com/awslabs/aws-lambda-powertools-python/issues/1516))
1123
* **typing:** fix mypy error
1224
* **typing:** level arg in copy_config_to_registered_loggers ([#1534](https://github.com/awslabs/aws-lambda-powertools-python/issues/1534))
1325

1426
## Documentation
1527

28+
* **batch:** document the new lambda context feature
29+
* **homepage:** introduce POWERTOOLS_DEV env var ([#1569](https://github.com/awslabs/aws-lambda-powertools-python/issues/1569))
30+
* **multiple:** fix highlighting after new isort/black integration
1631
* **parser:** add JSON string field extension example ([#1526](https://github.com/awslabs/aws-lambda-powertools-python/issues/1526))
1732

1833
## Features
1934

35+
* **batch:** inject lambda_context if record handler signature accepts it ([#1561](https://github.com/awslabs/aws-lambda-powertools-python/issues/1561))
36+
* **event-handler:** context support to share data between routers ([#1567](https://github.com/awslabs/aws-lambda-powertools-python/issues/1567))
37+
* **logger:** introduce POWERTOOLS_DEBUG for internal debugging ([#1572](https://github.com/awslabs/aws-lambda-powertools-python/issues/1572))
38+
* **logger:** include logger name attribute when copy_config_to_registered_logger is used ([#1568](https://github.com/awslabs/aws-lambda-powertools-python/issues/1568))
2039
* **logger:** pretty-print JSON when POWERTOOLS_DEV is set ([#1548](https://github.com/awslabs/aws-lambda-powertools-python/issues/1548))
2140

2241
## Maintenance
2342

24-
* **deps:** bump codecov/codecov-action from 3.1.0 to 3.1.1 ([#1529](https://github.com/awslabs/aws-lambda-powertools-python/issues/1529))
43+
* **dep:** bump pyproject to pypi sync
2544
* **deps:** bump fastjsonschema from 2.16.1 to 2.16.2 ([#1530](https://github.com/awslabs/aws-lambda-powertools-python/issues/1530))
2645
* **deps:** bump actions/setup-python from 3 to 4 ([#1528](https://github.com/awslabs/aws-lambda-powertools-python/issues/1528))
46+
* **deps:** bump codecov/codecov-action from 3.1.0 to 3.1.1 ([#1529](https://github.com/awslabs/aws-lambda-powertools-python/issues/1529))
47+
* **deps:** bump dependabot/fetch-metadata from 1.3.3 to 1.3.4 ([#1565](https://github.com/awslabs/aws-lambda-powertools-python/issues/1565))
2748
* **deps:** bump email-validator from 1.2.1 to 1.3.0 ([#1533](https://github.com/awslabs/aws-lambda-powertools-python/issues/1533))
49+
* **deps-dev:** bump mypy-boto3-secretsmanager from 1.24.54 to 1.24.83 ([#1557](https://github.com/awslabs/aws-lambda-powertools-python/issues/1557))
2850
* **deps-dev:** bump mkdocs-material from 8.5.3 to 8.5.4 ([#1563](https://github.com/awslabs/aws-lambda-powertools-python/issues/1563))
29-
* **deps-dev:** bump mypy-boto3-ssm from 1.24.80 to 1.24.81 ([#1544](https://github.com/awslabs/aws-lambda-powertools-python/issues/1544))
51+
* **deps-dev:** bump pytest-cov from 3.0.0 to 4.0.0 ([#1551](https://github.com/awslabs/aws-lambda-powertools-python/issues/1551))
52+
* **deps-dev:** bump flake8-bugbear from 22.9.11 to 22.9.23 ([#1541](https://github.com/awslabs/aws-lambda-powertools-python/issues/1541))
53+
* **deps-dev:** bump types-requests from 2.28.11 to 2.28.11.1 ([#1571](https://github.com/awslabs/aws-lambda-powertools-python/issues/1571))
3054
* **deps-dev:** bump mypy-boto3-ssm from 1.24.69 to 1.24.80 ([#1542](https://github.com/awslabs/aws-lambda-powertools-python/issues/1542))
3155
* **deps-dev:** bump mako from 1.2.2 to 1.2.3 ([#1537](https://github.com/awslabs/aws-lambda-powertools-python/issues/1537))
3256
* **deps-dev:** bump types-requests from 2.28.10 to 2.28.11 ([#1538](https://github.com/awslabs/aws-lambda-powertools-python/issues/1538))
33-
* **deps-dev:** bump flake8-bugbear from 22.9.11 to 22.9.23 ([#1541](https://github.com/awslabs/aws-lambda-powertools-python/issues/1541))
34-
* **deps-dev:** bump pytest-cov from 3.0.0 to 4.0.0 ([#1551](https://github.com/awslabs/aws-lambda-powertools-python/issues/1551))
3557
* **deps-dev:** bump mkdocs-material from 8.5.1 to 8.5.3 ([#1532](https://github.com/awslabs/aws-lambda-powertools-python/issues/1532))
36-
* **deps-dev:** bump mypy-boto3-secretsmanager from 1.24.54 to 1.24.83 ([#1557](https://github.com/awslabs/aws-lambda-powertools-python/issues/1557))
58+
* **deps-dev:** bump mypy-boto3-ssm from 1.24.80 to 1.24.81 ([#1544](https://github.com/awslabs/aws-lambda-powertools-python/issues/1544))
3759
* **deps-dev:** bump mypy-boto3-s3 from 1.24.36.post1 to 1.24.76 ([#1531](https://github.com/awslabs/aws-lambda-powertools-python/issues/1531))
3860
* **docs:** bump layer version to 36 (1.29.2)
3961
* **layers:** add dummy v2 layer automation
62+
* **lint:** use new isort black integration
63+
* **multiple:** localize powertools_dev env logic and warning ([#1570](https://github.com/awslabs/aws-lambda-powertools-python/issues/1570))
4064

4165

4266
<a name="v1.29.2"></a>
@@ -2366,7 +2390,8 @@
23662390
* Merge pull request [#5](https://github.com/awslabs/aws-lambda-powertools-python/issues/5) from jfuss/feat/python38
23672391

23682392

2369-
[Unreleased]: https://github.com/awslabs/aws-lambda-powertools-python/compare/v1.29.2...HEAD
2393+
[Unreleased]: https://github.com/awslabs/aws-lambda-powertools-python/compare/v1.30.0...HEAD
2394+
[v1.30.0]: https://github.com/awslabs/aws-lambda-powertools-python/compare/v1.29.2...v1.30.0
23702395
[v1.29.2]: https://github.com/awslabs/aws-lambda-powertools-python/compare/v1.29.1...v1.29.2
23712396
[v1.29.1]: https://github.com/awslabs/aws-lambda-powertools-python/compare/v1.29.0...v1.29.1
23722397
[v1.29.0]: https://github.com/awslabs/aws-lambda-powertools-python/compare/v1.28.0...v1.29.0

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1+
<!-- markdownlint-disable MD043 MD041 -->
12
# AWS Lambda Powertools for Python
23

34
[![Build](https://github.com/awslabs/aws-lambda-powertools-python/actions/workflows/python_build.yml/badge.svg)](https://github.com/awslabs/aws-lambda-powertools-python/actions/workflows/python_build.yml)
45
[![codecov.io](https://codecov.io/github/awslabs/aws-lambda-powertools-python/branch/develop/graphs/badge.svg)](https://app.codecov.io/gh/awslabs/aws-lambda-powertools-python)
5-
![PythonSupport](https://img.shields.io/static/v1?label=python&message=3.6%20|%203.7|%203.8|%203.9&color=blue?style=flat-square&logo=python) ![PyPI version](https://badge.fury.io/py/aws-lambda-powertools.svg) ![PyPi monthly downloads](https://img.shields.io/pypi/dm/aws-lambda-powertools)
6+
![PythonSupport](https://img.shields.io/static/v1?label=python&message=3.6%20|%203.7|%203.8|%203.9&color=blue?style=flat-square&logo=python) ![PyPI version](https://badge.fury.io/py/aws-lambda-powertools.svg) ![PyPi monthly downloads](https://img.shields.io/pypi/dm/aws-lambda-powertools) ![Lambda Layer](https://api.globadge.com/v1/badgen/aws/lambda/layer/latest-version/eu-central-1/017000801446/AWSLambdaPowertoolsPython)
67
[![Join our Discord](https://dcbadge.vercel.app/api/server/B8zZKbbyET)](https://discord.gg/B8zZKbbyET)
78

89
A suite of Python utilities for AWS Lambda functions to ease adopting best practices such as tracing, structured logging, custom metrics, and more. (AWS Lambda Powertools [Java](https://github.com/awslabs/aws-lambda-powertools-java) and [Typescript](https://github.com/awslabs/aws-lambda-powertools-typescript) is also available).

aws_lambda_powertools/event_handler/api_gateway.py

Lines changed: 55 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,24 @@
1010
from enum import Enum
1111
from functools import partial
1212
from http import HTTPStatus
13-
from typing import Any, Callable, Dict, List, Match, Optional, Pattern, Set, Tuple, Type, Union
13+
from typing import (
14+
Any,
15+
Callable,
16+
Dict,
17+
List,
18+
Match,
19+
Optional,
20+
Pattern,
21+
Set,
22+
Tuple,
23+
Type,
24+
Union,
25+
)
1426

1527
from aws_lambda_powertools.event_handler import content_types
1628
from aws_lambda_powertools.event_handler.exceptions import NotFoundError, ServiceError
1729
from aws_lambda_powertools.shared import constants
18-
from aws_lambda_powertools.shared.functions import resolve_truthy_env_var_choice
30+
from aws_lambda_powertools.shared.functions import powertools_dev_is_set, strtobool
1931
from aws_lambda_powertools.shared.json_encoder import Encoder
2032
from aws_lambda_powertools.utilities.data_classes import (
2133
ALBEvent,
@@ -237,6 +249,7 @@ def build(self, event: BaseProxyEvent, cors: Optional[CORSConfig] = None) -> Dic
237249
class BaseRouter(ABC):
238250
current_event: BaseProxyEvent
239251
lambda_context: LambdaContext
252+
context: dict
240253

241254
@abstractmethod
242255
def route(
@@ -383,6 +396,14 @@ def lambda_handler(event, context):
383396
"""
384397
return self.route(rule, "PATCH", cors, compress, cache_control)
385398

399+
def append_context(self, **additional_context):
400+
"""Append key=value data as routing context"""
401+
self.context.update(**additional_context)
402+
403+
def clear_context(self):
404+
"""Resets routing context"""
405+
self.context.clear()
406+
386407

387408
class ApiGatewayResolver(BaseRouter):
388409
"""API Gateway and ALB proxy resolver
@@ -444,10 +465,9 @@ def __init__(
444465
self._cors = cors
445466
self._cors_enabled: bool = cors is not None
446467
self._cors_methods: Set[str] = {"OPTIONS"}
447-
self._debug = resolve_truthy_env_var_choice(
448-
env=os.getenv(constants.EVENT_HANDLER_DEBUG_ENV, "false"), choice=debug
449-
)
468+
self._debug = self._has_debug(debug)
450469
self._strip_prefixes = strip_prefixes
470+
self.context: Dict = {} # early init as customers might add context before event resolution
451471

452472
# Allow for a custom serializer or a concise json serialization
453473
self._serializer = serializer or partial(json.dumps, separators=(",", ":"), cls=Encoder)
@@ -502,15 +522,37 @@ def resolve(self, event, context) -> Dict[str, Any]:
502522
"You don't need to serialize event to Event Source Data Class when using Event Handler; see issue #1152"
503523
)
504524
event = event.raw_event
525+
505526
if self._debug:
506527
print(self._json_dump(event), end="")
528+
529+
# Populate router(s) dependencies without keeping a reference to each registered router
507530
BaseRouter.current_event = self._to_proxy_event(event)
508531
BaseRouter.lambda_context = context
509-
return self._resolve().build(self.current_event, self._cors)
532+
533+
response = self._resolve().build(self.current_event, self._cors)
534+
self.clear_context()
535+
return response
510536

511537
def __call__(self, event, context) -> Any:
512538
return self.resolve(event, context)
513539

540+
@staticmethod
541+
def _has_debug(debug: Optional[bool] = None) -> bool:
542+
# It might have been explicitly switched off (debug=False)
543+
if debug is not None:
544+
return debug
545+
546+
# Maintenance: deprecate EVENT_HANDLER_DEBUG later in V2.
547+
env_debug = os.getenv(constants.EVENT_HANDLER_DEBUG_ENV)
548+
if env_debug is not None:
549+
warnings.warn(
550+
"POWERTOOLS_EVENT_HANDLER_DEBUG is set and will be deprecated in V2. Please use POWERTOOLS_DEV instead."
551+
)
552+
return strtobool(env_debug) or powertools_dev_is_set()
553+
554+
return powertools_dev_is_set()
555+
514556
@staticmethod
515557
def _compile_regex(rule: str):
516558
"""Precompile regex pattern
@@ -705,7 +747,7 @@ def _json_dump(self, obj: Any) -> str:
705747
return self._serializer(obj)
706748

707749
def include_router(self, router: "Router", prefix: Optional[str] = None) -> None:
708-
"""Adds all routes defined in a router
750+
"""Adds all routes and context defined in a router
709751
710752
Parameters
711753
----------
@@ -718,6 +760,11 @@ def include_router(self, router: "Router", prefix: Optional[str] = None) -> None
718760
# Add reference to parent ApiGatewayResolver to support use cases where people subclass it to add custom logic
719761
router.api_resolver = self
720762

763+
# Merge app and router context
764+
self.context.update(**router.context)
765+
# use pointer to allow context clearance after event is processed e.g., resolve(evt, ctx)
766+
router.context = self.context
767+
721768
for route, func in router._routes.items():
722769
if prefix:
723770
rule = route[0]
@@ -733,6 +780,7 @@ class Router(BaseRouter):
733780
def __init__(self):
734781
self._routes: Dict[tuple, Callable] = {}
735782
self.api_resolver: Optional[BaseRouter] = None
783+
self.context = {} # early init as customers might add context before event resolution
736784

737785
def route(
738786
self,

aws_lambda_powertools/event_handler/appsync.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
class BaseRouter:
1313
current_event: AppSyncResolverEventT # type: ignore[valid-type]
1414
lambda_context: LambdaContext
15+
context: dict
1516

1617
def __init__(self):
1718
self._resolvers: dict = {}
@@ -34,6 +35,14 @@ def register_resolver(func):
3435

3536
return register_resolver
3637

38+
def append_context(self, **additional_context):
39+
"""Append key=value data as routing context"""
40+
self.context.update(**additional_context)
41+
42+
def clear_context(self):
43+
"""Resets routing context"""
44+
self.context.clear()
45+
3746

3847
class AppSyncResolver(BaseRouter):
3948
"""
@@ -68,6 +77,7 @@ def common_field() -> str:
6877

6978
def __init__(self):
7079
super().__init__()
80+
self.context = {} # early init as customers might add context before event resolution
7181

7282
def resolve(
7383
self, event: dict, context: LambdaContext, data_model: Type[AppSyncResolverEvent] = AppSyncResolverEvent
@@ -144,8 +154,12 @@ def lambda_handler(event, context):
144154
# Maintenance: revisit generics/overload to fix [attr-defined] in mypy usage
145155
BaseRouter.current_event = data_model(event)
146156
BaseRouter.lambda_context = context
157+
147158
resolver = self._get_resolver(BaseRouter.current_event.type_name, BaseRouter.current_event.field_name)
148-
return resolver(**BaseRouter.current_event.arguments)
159+
response = resolver(**BaseRouter.current_event.arguments)
160+
self.clear_context()
161+
162+
return response
149163

150164
def _get_resolver(self, type_name: str, field_name: str) -> Callable:
151165
"""Get resolver for field_name
@@ -182,9 +196,15 @@ def include_router(self, router: "Router") -> None:
182196
router : Router
183197
A router containing a dict of field resolvers
184198
"""
199+
# Merge app and router context
200+
self.context.update(**router.context)
201+
# use pointer to allow context clearance after event is processed e.g., resolve(evt, ctx)
202+
router.context = self.context
203+
185204
self._resolvers.update(router._resolvers)
186205

187206

188207
class Router(BaseRouter):
189208
def __init__(self):
190209
super().__init__()
210+
self.context = {} # early init as customers might add context before event resolution

aws_lambda_powertools/event_handler/lambda_function_url.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
from typing import Callable, Dict, List, Optional
22

33
from aws_lambda_powertools.event_handler import CORSConfig
4-
from aws_lambda_powertools.event_handler.api_gateway import ApiGatewayResolver, ProxyEventType
4+
from aws_lambda_powertools.event_handler.api_gateway import (
5+
ApiGatewayResolver,
6+
ProxyEventType,
7+
)
58
from aws_lambda_powertools.utilities.data_classes import LambdaFunctionUrlEvent
69

710

aws_lambda_powertools/logging/formatter.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple, Union
1010

1111
from ..shared import constants
12-
from ..shared.functions import strtobool
12+
from ..shared.functions import powertools_dev_is_set
1313

1414
RESERVED_LOG_ATTRS = (
1515
"name",
@@ -116,7 +116,7 @@ def __init__(
116116
self.json_deserializer = json_deserializer or json.loads
117117
self.json_default = json_default or str
118118
self.json_indent = (
119-
constants.PRETTY_INDENT if strtobool(os.getenv("POWERTOOLS_DEV", "0")) else constants.COMPACT_INDENT
119+
constants.PRETTY_INDENT if powertools_dev_is_set() else constants.COMPACT_INDENT
120120
) # indented json serialization when in AWS SAM Local
121121
self.json_serializer = json_serializer or partial(
122122
json.dumps, default=self.json_default, separators=(",", ":"), indent=self.json_indent

aws_lambda_powertools/logging/logger.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@
1212
from ..shared.functions import resolve_env_var_choice, resolve_truthy_env_var_choice
1313
from .exceptions import InvalidLoggerSamplingRateError
1414
from .filters import SuppressFilter
15-
from .formatter import RESERVED_FORMATTER_CUSTOM_KEYS, BasePowertoolsFormatter, LambdaPowertoolsFormatter
15+
from .formatter import (
16+
RESERVED_FORMATTER_CUSTOM_KEYS,
17+
BasePowertoolsFormatter,
18+
LambdaPowertoolsFormatter,
19+
)
1620
from .lambda_context import build_lambda_context_model
1721

1822
logger = logging.getLogger(__name__)

aws_lambda_powertools/logging/utils.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ def _configure_logger(source_logger: Logger, logger: logging.Logger, level: Unio
8181
logger.handlers = []
8282
logger.setLevel(level)
8383
logger.propagate = False # ensure we don't propagate logs to existing loggers, #1073
84+
source_logger.append_keys(name="%(name)s") # include logger name, see #1267
85+
8486
source_logger.debug(f"Logger {logger} reconfigured to use logging level {level}")
8587
for source_handler in source_logger.handlers:
8688
logger.addHandler(source_handler)
Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,25 @@
11
import logging
22

3+
from aws_lambda_powertools.logging.logger import set_package_logger
4+
from aws_lambda_powertools.shared.functions import powertools_debug_is_set
5+
6+
7+
def set_package_logger_handler(stream=None):
8+
"""Sets up Lambda Powertools package logging.
9+
10+
By default, we discard any output to not interfere with customers logging.
11+
12+
When POWERTOOLS_DEBUG env var is set, we setup `aws_lambda_powertools` logger in DEBUG level.
13+
14+
Parameters
15+
----------
16+
stream: sys.stdout
17+
log stream, stdout by default
18+
"""
19+
20+
if powertools_debug_is_set():
21+
return set_package_logger(stream=stream)
322

4-
def set_package_logger_handler():
523
logger = logging.getLogger("aws_lambda_powertools")
624
logger.addHandler(logging.NullHandler())
725
logger.propagate = False

aws_lambda_powertools/shared/constants.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,6 @@
3636
# JSON indentation level
3737
PRETTY_INDENT: int = 4
3838
COMPACT_INDENT = None
39+
40+
POWERTOOLS_DEV_ENV: str = "POWERTOOLS_DEV"
41+
POWERTOOLS_DEBUG_ENV: str = "POWERTOOLS_DEBUG"

0 commit comments

Comments
 (0)