Skip to content

Commit c24118c

Browse files
authored
Merge branch 'develop' into time2
2 parents 97ffef4 + 053baef commit c24118c

File tree

7 files changed

+104
-10
lines changed

7 files changed

+104
-10
lines changed

CHANGELOG.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,20 @@
1111
* **examples:** linting unnecessary whitespace
1212
* **homepage:** update default value for `POWERTOOLS_DEV` ([#1695](https://github.com/awslabs/aws-lambda-powertools-python/issues/1695))
1313

14+
## Features
15+
16+
* **apigateway:** multiple exceptions in exception_handler ([#1707](https://github.com/awslabs/aws-lambda-powertools-python/issues/1707))
17+
1418
## Maintenance
1519

1620
* **ci:** revert custom hw for E2E due to lack of hw
1721
* **ci:** prevent dependabot updates to trigger E2E
1822
* **ci:** use new custom hw for E2E
1923
* **ci:** limit to src only to prevent dependabot failures
2024
* **deps:** bump dependabot/fetch-metadata from 1.3.4 to 1.3.5 ([#1689](https://github.com/awslabs/aws-lambda-powertools-python/issues/1689))
21-
* **deps-dev:** bump flake8-comprehensions from 3.10.0 to 3.10.1 ([#1699](https://github.com/awslabs/aws-lambda-powertools-python/issues/1699))
25+
* **deps-dev:** bump mypy-boto3-logs from 1.25.0 to 1.26.3 ([#1702](https://github.com/awslabs/aws-lambda-powertools-python/issues/1702))
2226
* **deps-dev:** bump mkdocs-material from 8.5.7 to 8.5.9 ([#1697](https://github.com/awslabs/aws-lambda-powertools-python/issues/1697))
27+
* **deps-dev:** bump flake8-comprehensions from 3.10.0 to 3.10.1 ([#1699](https://github.com/awslabs/aws-lambda-powertools-python/issues/1699))
2328
* **deps-dev:** bump types-requests from 2.28.11.2 to 2.28.11.3 ([#1698](https://github.com/awslabs/aws-lambda-powertools-python/issues/1698))
2429
* **deps-dev:** bump pytest-benchmark from 3.4.1 to 4.0.0 ([#1659](https://github.com/awslabs/aws-lambda-powertools-python/issues/1659))
2530
* **deps-dev:** bump mypy-boto3-secretsmanager from 1.25.0 to 1.26.0.post1 ([#1691](https://github.com/awslabs/aws-lambda-powertools-python/issues/1691))

aws_lambda_powertools/event_handler/api_gateway.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -689,9 +689,14 @@ def not_found(self, func: Optional[Callable] = None):
689689
return self.exception_handler(NotFoundError)
690690
return self.exception_handler(NotFoundError)(func)
691691

692-
def exception_handler(self, exc_class: Type[Exception]):
692+
def exception_handler(self, exc_class: Union[Type[Exception], List[Type[Exception]]]):
693693
def register_exception_handler(func: Callable):
694-
self._exception_handlers[exc_class] = func
694+
if isinstance(exc_class, list):
695+
for exp in exc_class:
696+
self._exception_handlers[exp] = func
697+
else:
698+
self._exception_handlers[exc_class] = func
699+
return func
695700

696701
return register_exception_handler
697702

aws_lambda_powertools/logging/logger.py

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@
1818
Optional,
1919
TypeVar,
2020
Union,
21+
overload,
2122
)
2223

2324
import jmespath
2425

2526
from ..shared import constants
2627
from ..shared.functions import resolve_env_var_choice, resolve_truthy_env_var_choice
28+
from ..shared.types import AnyCallableT
2729
from .exceptions import InvalidLoggerSamplingRateError
2830
from .filters import SuppressFilter
2931
from .formatter import (
@@ -314,13 +316,33 @@ def _configure_sampling(self):
314316
f"Please review POWERTOOLS_LOGGER_SAMPLE_RATE environment variable."
315317
)
316318

319+
@overload
317320
def inject_lambda_context(
318321
self,
319-
lambda_handler: Optional[Callable[[Dict, Any], Any]] = None,
322+
lambda_handler: AnyCallableT,
320323
log_event: Optional[bool] = None,
321324
correlation_id_path: Optional[str] = None,
322325
clear_state: Optional[bool] = False,
323-
):
326+
) -> AnyCallableT:
327+
...
328+
329+
@overload
330+
def inject_lambda_context(
331+
self,
332+
lambda_handler: None = None,
333+
log_event: Optional[bool] = None,
334+
correlation_id_path: Optional[str] = None,
335+
clear_state: Optional[bool] = False,
336+
) -> Callable[[AnyCallableT], AnyCallableT]:
337+
...
338+
339+
def inject_lambda_context(
340+
self,
341+
lambda_handler: Optional[AnyCallableT] = None,
342+
log_event: Optional[bool] = None,
343+
correlation_id_path: Optional[str] = None,
344+
clear_state: Optional[bool] = False,
345+
) -> Any:
324346
"""Decorator to capture Lambda contextual info and inject into logger
325347
326348
Parameters

docs/core/event_handler/api_gateway.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,9 @@ You can use **`exception_handler`** decorator with any Python exception. This al
226226
--8<-- "examples/event_handler_rest/src/exception_handling.py"
227227
```
228228

229+
???+ info
230+
The `exception_handler` also supports passing a list of exception types you wish to handle with one handler.
231+
229232
### Raising HTTP errors
230233

231234
You can easily raise any HTTP Error back to the client using `ServiceError` exception. This ensures your Lambda function doesn't fail but return the correct HTTP response signalling the error.

poetry.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/events/apiGatewayProxyEvent.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,5 +76,5 @@
7676
"pathParameters": null,
7777
"stageVariables": null,
7878
"body": "Hello from Lambda!",
79-
"isBase64Encoded": true
80-
}
79+
"isBase64Encoded": false
80+
}

tests/functional/event_handler/test_api_gateway.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1388,6 +1388,65 @@ def get_lambda() -> Response:
13881388
assert result["body"] == json_dump(expected)
13891389

13901390

1391+
def test_exception_handler_supports_list(json_dump):
1392+
# GIVEN a resolver with an exception handler defined for a multiple exceptions in a list
1393+
app = ApiGatewayResolver()
1394+
event = deepcopy(LOAD_GW_EVENT)
1395+
1396+
@app.exception_handler([ValueError, NotFoundError])
1397+
def multiple_error(ex: Exception):
1398+
raise BadRequestError("Bad request")
1399+
1400+
@app.get("/path/a")
1401+
def path_a() -> Response:
1402+
raise ValueError("foo")
1403+
1404+
@app.get("/path/b")
1405+
def path_b() -> Response:
1406+
raise NotFoundError
1407+
1408+
# WHEN calling the app generating each exception
1409+
for route in ["/path/a", "/path/b"]:
1410+
event["path"] = route
1411+
result = app(event, {})
1412+
1413+
# THEN call the exception handler in the same way for both exceptions
1414+
assert result["statusCode"] == 400
1415+
assert result["multiValueHeaders"]["Content-Type"] == [content_types.APPLICATION_JSON]
1416+
expected = {"statusCode": 400, "message": "Bad request"}
1417+
assert result["body"] == json_dump(expected)
1418+
1419+
1420+
def test_exception_handler_supports_multiple_decorators(json_dump):
1421+
# GIVEN a resolver with an exception handler defined with multiple decorators
1422+
app = ApiGatewayResolver()
1423+
event = deepcopy(LOAD_GW_EVENT)
1424+
1425+
@app.exception_handler(ValueError)
1426+
@app.exception_handler(NotFoundError)
1427+
def multiple_error(ex: Exception):
1428+
raise BadRequestError("Bad request")
1429+
1430+
@app.get("/path/a")
1431+
def path_a() -> Response:
1432+
raise ValueError("foo")
1433+
1434+
@app.get("/path/b")
1435+
def path_b() -> Response:
1436+
raise NotFoundError
1437+
1438+
# WHEN calling the app generating each exception
1439+
for route in ["/path/a", "/path/b"]:
1440+
event["path"] = route
1441+
result = app(event, {})
1442+
1443+
# THEN call the exception handler in the same way for both exceptions
1444+
assert result["statusCode"] == 400
1445+
assert result["multiValueHeaders"]["Content-Type"] == [content_types.APPLICATION_JSON]
1446+
expected = {"statusCode": 400, "message": "Bad request"}
1447+
assert result["body"] == json_dump(expected)
1448+
1449+
13911450
def test_event_source_compatibility():
13921451
# GIVEN
13931452
app = APIGatewayHttpResolver()

0 commit comments

Comments
 (0)