diff --git a/Makefile b/Makefile index a024f340263..e4f908614a6 100644 --- a/Makefile +++ b/Makefile @@ -99,4 +99,4 @@ changelog: docker run -v "${PWD}":/workdir quay.io/git-chglog/git-chglog > CHANGELOG.md mypy: - poetry run mypy --pretty aws_lambda_powertools + poetry run mypy --pretty aws_lambda_powertools examples diff --git a/aws_lambda_powertools/event_handler/__init__.py b/aws_lambda_powertools/event_handler/__init__.py index 112e2fe69d6..e7dc4608ee9 100644 --- a/aws_lambda_powertools/event_handler/__init__.py +++ b/aws_lambda_powertools/event_handler/__init__.py @@ -2,7 +2,14 @@ Event handler decorators for common Lambda events """ -from .api_gateway import ALBResolver, APIGatewayHttpResolver, ApiGatewayResolver, APIGatewayRestResolver, CORSConfig, Response +from .api_gateway import ( + ALBResolver, + APIGatewayHttpResolver, + ApiGatewayResolver, + APIGatewayRestResolver, + CORSConfig, + Response, +) from .appsync import AppSyncResolver __all__ = [ diff --git a/aws_lambda_powertools/event_handler/appsync.py b/aws_lambda_powertools/event_handler/appsync.py index 6a4bf989169..896b303cd08 100644 --- a/aws_lambda_powertools/event_handler/appsync.py +++ b/aws_lambda_powertools/event_handler/appsync.py @@ -142,6 +142,7 @@ def lambda_handler(event, context): ValueError If we could not find a field resolver """ + # Maintenance: revisit generics/overload to fix [attr-defined] in mypy usage BaseRouter.current_event = data_model(event) BaseRouter.lambda_context = context resolver = self._get_resolver(BaseRouter.current_event.type_name, BaseRouter.current_event.field_name) diff --git a/aws_lambda_powertools/tracing/base.py b/aws_lambda_powertools/tracing/base.py index 722652ce08b..d044817f920 100644 --- a/aws_lambda_powertools/tracing/base.py +++ b/aws_lambda_powertools/tracing/base.py @@ -2,39 +2,34 @@ import numbers import traceback from contextlib import contextmanager -from typing import Any, AsyncContextManager, ContextManager, List, NoReturn, Optional, Set, Union +from typing import Any, Generator, List, NoReturn, Optional, Sequence, Union -class BaseProvider(abc.ABC): - @abc.abstractmethod # type: ignore - @contextmanager - def in_subsegment(self, name=None, **kwargs) -> ContextManager: - """Return a subsegment context manger. +class BaseSegment(abc.ABC): + """Holds common properties and methods on segment and subsegment.""" + + @abc.abstractmethod + def close(self, end_time: Optional[int] = None): + """Close the trace entity by setting `end_time` + and flip the in progress flag to False. Parameters ---------- - name: str - Subsegment name - kwargs: Optional[dict] - Optional parameters to be propagated to segment + end_time: int + Time in epoch seconds, by default current time will be used. """ - @abc.abstractmethod # type: ignore - @contextmanager - def in_subsegment_async(self, name=None, **kwargs) -> AsyncContextManager: - """Return a subsegment async context manger. + @abc.abstractmethod + def add_subsegment(self, subsegment: Any): + """Add input subsegment as a child subsegment.""" - Parameters - ---------- - name: str - Subsegment name - kwargs: Optional[dict] - Optional parameters to be propagated to segment - """ + @abc.abstractmethod + def remove_subsegment(self, subsegment: Any): + """Remove input subsegment from child subsegments.""" @abc.abstractmethod def put_annotation(self, key: str, value: Union[str, numbers.Number, bool]) -> NoReturn: - """Annotate current active trace entity with a key-value pair. + """Annotate segment or subsegment with a key-value pair. Note: Annotations will be indexed for later search query. @@ -48,9 +43,8 @@ def put_annotation(self, key: str, value: Union[str, numbers.Number, bool]) -> N @abc.abstractmethod def put_metadata(self, key: str, value: Any, namespace: str = "default") -> NoReturn: - """Add metadata to the current active trace entity. - - Note: Metadata is not indexed but can be later retrieved by BatchGetTraces API. + """Add metadata to segment or subsegment. Metadata is not indexed + but can be later retrieved by BatchGetTraces API. Parameters ---------- @@ -63,45 +57,52 @@ def put_metadata(self, key: str, value: Any, namespace: str = "default") -> NoRe """ @abc.abstractmethod - def patch(self, modules: Set[str]) -> NoReturn: - """Instrument a set of supported libraries + def add_exception(self, exception: BaseException, stack: List[traceback.StackSummary], remote: bool = False): + """Add an exception to trace entities. Parameters ---------- - modules: Set[str] - Set of modules to be patched - """ - - @abc.abstractmethod - def patch_all(self) -> NoReturn: - """Instrument all supported libraries""" + exception: Exception + Caught exception + stack: List[traceback.StackSummary] + List of traceback summaries + Output from `traceback.extract_stack()`. + remote: bool + Whether it's a client error (False) or downstream service error (True), by default False + """ -class BaseSegment(abc.ABC): - """Holds common properties and methods on segment and subsegment.""" +class BaseProvider(abc.ABC): @abc.abstractmethod - def close(self, end_time: Optional[int] = None): - """Close the trace entity by setting `end_time` - and flip the in progress flag to False. + @contextmanager + def in_subsegment(self, name=None, **kwargs) -> Generator[BaseSegment, None, None]: + """Return a subsegment context manger. Parameters ---------- - end_time: int - Time in epoch seconds, by default current time will be used. + name: str + Subsegment name + kwargs: Optional[dict] + Optional parameters to be propagated to segment """ @abc.abstractmethod - def add_subsegment(self, subsegment: Any): - """Add input subsegment as a child subsegment.""" + @contextmanager + def in_subsegment_async(self, name=None, **kwargs) -> Generator[BaseSegment, None, None]: + """Return a subsegment async context manger. - @abc.abstractmethod - def remove_subsegment(self, subsegment: Any): - """Remove input subsegment from child subsegments.""" + Parameters + ---------- + name: str + Subsegment name + kwargs: Optional[dict] + Optional parameters to be propagated to segment + """ @abc.abstractmethod def put_annotation(self, key: str, value: Union[str, numbers.Number, bool]) -> NoReturn: - """Annotate segment or subsegment with a key-value pair. + """Annotate current active trace entity with a key-value pair. Note: Annotations will be indexed for later search query. @@ -115,8 +116,9 @@ def put_annotation(self, key: str, value: Union[str, numbers.Number, bool]) -> N @abc.abstractmethod def put_metadata(self, key: str, value: Any, namespace: str = "default") -> NoReturn: - """Add metadata to segment or subsegment. Metadata is not indexed - but can be later retrieved by BatchGetTraces API. + """Add metadata to the current active trace entity. + + Note: Metadata is not indexed but can be later retrieved by BatchGetTraces API. Parameters ---------- @@ -129,17 +131,15 @@ def put_metadata(self, key: str, value: Any, namespace: str = "default") -> NoRe """ @abc.abstractmethod - def add_exception(self, exception: BaseException, stack: List[traceback.StackSummary], remote: bool = False): - """Add an exception to trace entities. + def patch(self, modules: Sequence[str]) -> NoReturn: + """Instrument a set of supported libraries Parameters ---------- - exception: Exception - Caught exception - stack: List[traceback.StackSummary] - List of traceback summaries - - Output from `traceback.extract_stack()`. - remote: bool - Whether it's a client error (False) or downstream service error (True), by default False + modules: Set[str] + Set of modules to be patched """ + + @abc.abstractmethod + def patch_all(self) -> NoReturn: + """Instrument all supported libraries""" diff --git a/aws_lambda_powertools/tracing/tracer.py b/aws_lambda_powertools/tracing/tracer.py index 200325cfe9a..8d9ad16a3d0 100644 --- a/aws_lambda_powertools/tracing/tracer.py +++ b/aws_lambda_powertools/tracing/tracer.py @@ -155,7 +155,7 @@ def __init__( self.__build_config( service=service, disabled=disabled, auto_patch=auto_patch, patch_modules=patch_modules, provider=provider ) - self.provider = self._config["provider"] + self.provider: BaseProvider = self._config["provider"] self.disabled = self._config["disabled"] self.service = self._config["service"] self.auto_patch = self._config["auto_patch"] diff --git a/docs/core/event_handler/api_gateway.md b/docs/core/event_handler/api_gateway.md index 38d4bfb0617..707d9687e63 100644 --- a/docs/core/event_handler/api_gateway.md +++ b/docs/core/event_handler/api_gateway.md @@ -201,7 +201,7 @@ You can use **`not_found`** decorator to override this behavior, and return a cu You can use **`exception_handler`** decorator with any Python exception. This allows you to handle a common exception outside your route, for example validation errors. -```python hl_lines="14 15" title="Exception handling" +```python hl_lines="13-14" title="Exception handling" --8<-- "examples/event_handler_rest/src/exception_handling.py" ``` diff --git a/docs/core/event_handler/appsync.md b/docs/core/event_handler/appsync.md index 4d28b41a81f..dd9d1dd2d63 100644 --- a/docs/core/event_handler/appsync.md +++ b/docs/core/event_handler/appsync.md @@ -58,7 +58,7 @@ Here's an example where we have two separate functions to resolve `getTodo` and === "getting_started_graphql_api_resolver.py" - ```python hl_lines="7 13 23 25-26 35 37 48" + ```python hl_lines="14 20 30 32-33 42 44 55" --8<-- "examples/event_handler_graphql/src/getting_started_graphql_api_resolver.py" ``` @@ -112,7 +112,7 @@ You can nest `app.resolver()` decorator multiple times when resolving fields wit === "nested_mappings.py" - ```python hl_lines="4 10 20-21 23 30" + ```python hl_lines="11 17 27-28 28 30 37" --8<-- "examples/event_handler_graphql/src/nested_mappings.py" ``` @@ -126,7 +126,7 @@ You can nest `app.resolver()` decorator multiple times when resolving fields wit For Lambda Python3.8+ runtime, this utility supports async functions when you use in conjunction with `asyncio.run`. -```python hl_lines="7 14 24-25 34 36" title="Resolving GraphQL resolvers async" +```python hl_lines="14 21 31-32 41 43" title="Resolving GraphQL resolvers async" --8<-- "examples/event_handler_graphql/src/async_resolvers.py" ``` @@ -151,13 +151,13 @@ Use the following code for `merchantInfo` and `searchMerchant` functions respect === "graphql_transformer_merchant_info.py" - ```python hl_lines="4 6 22-23 27-28 36" + ```python hl_lines="11 13 29-30 34-35 43" --8<-- "examples/event_handler_graphql/src/graphql_transformer_merchant_info.py" ``` === "graphql_transformer_search_merchant.py" - ```python hl_lines="4 6 21-22 36 42" + ```python hl_lines="11 13 28-29 43 49" --8<-- "examples/event_handler_graphql/src/graphql_transformer_search_merchant.py" ``` @@ -185,7 +185,7 @@ You can subclass [AppSyncResolverEvent](../../utilities/data_classes.md#appsync- === "custom_models.py.py" - ```python hl_lines="4 7 23-25 28-29 36 43" + ```python hl_lines="11 14 30-32 35-36 43 50" --8<-- "examples/event_handler_graphql/src/custom_models.py" ``` @@ -214,7 +214,7 @@ Let's assume you have `split_operation.py` as your Lambda function entrypoint an We import **Router** instead of **AppSyncResolver**; syntax wise is exactly the same. - ```python hl_lines="4 8 18-19" + ```python hl_lines="11 15 25-26" --8<-- "examples/event_handler_graphql/src/split_operation_module.py" ``` @@ -242,7 +242,7 @@ Here's an example of how you can test your synchronous resolvers: === "assert_graphql_response_module.py" - ```python hl_lines="10" + ```python hl_lines="17" --8<-- "examples/event_handler_graphql/src/assert_graphql_response_module.py" ``` @@ -259,13 +259,13 @@ And an example for testing asynchronous resolvers. Note that this requires the ` === "assert_async_graphql_response.py" - ```python hl_lines="27" + ```python hl_lines="28" --8<-- "examples/event_handler_graphql/src/assert_async_graphql_response.py" ``` === "assert_async_graphql_response_module.py" - ```python hl_lines="14" + ```python hl_lines="21" --8<-- "examples/event_handler_graphql/src/assert_async_graphql_response_module.py" ``` diff --git a/examples/event_handler_graphql/src/assert_async_graphql_response.py b/examples/event_handler_graphql/src/assert_async_graphql_response.py index 22eceb1c5d0..e85816f2ca1 100644 --- a/examples/event_handler_graphql/src/assert_async_graphql_response.py +++ b/examples/event_handler_graphql/src/assert_async_graphql_response.py @@ -1,9 +1,10 @@ import json from dataclasses import dataclass from pathlib import Path +from typing import List import pytest -from assert_async_graphql_response_module import Location, app # instance of AppSyncResolver +from assert_async_graphql_response_module import Todo, app # instance of AppSyncResolver @pytest.fixture @@ -24,7 +25,7 @@ async def test_async_direct_resolver(lambda_context): fake_event = json.loads(Path("assert_async_graphql_response.json").read_text()) # WHEN - result: list[Location] = await app(fake_event, lambda_context) + result: List[Todo] = await app(fake_event, lambda_context) # alternatively, you can also run a sync test against `lambda_handler` # since `lambda_handler` awaits the coroutine to complete diff --git a/examples/event_handler_graphql/src/assert_async_graphql_response_module.py b/examples/event_handler_graphql/src/assert_async_graphql_response_module.py index 892da71fb0f..8ef072a02f7 100644 --- a/examples/event_handler_graphql/src/assert_async_graphql_response_module.py +++ b/examples/event_handler_graphql/src/assert_async_graphql_response_module.py @@ -1,5 +1,12 @@ +import sys + +if sys.version_info >= (3, 8): + from typing import TypedDict +else: + from typing_extensions import TypedDict + import asyncio -from typing import TypedDict +from typing import List import aiohttp @@ -22,11 +29,11 @@ class Todo(TypedDict, total=False): @app.resolver(type_name="Query", field_name="listTodos") -async def list_todos() -> list[Todo]: +async def list_todos() -> List[Todo]: async with aiohttp.ClientSession(trace_configs=[aiohttp_trace_config()]) as session: async with session.get("https://jsonplaceholder.typicode.com/todos") as resp: - # first two results to demo assertion - return await resp.json()[:2] + result: List[Todo] = await resp.json() + return result[:2] # first two results to demo assertion @logger.inject_lambda_context(correlation_id_path=correlation_paths.APPSYNC_RESOLVER) diff --git a/examples/event_handler_graphql/src/assert_graphql_response_module.py b/examples/event_handler_graphql/src/assert_graphql_response_module.py index 2f9c8ac3c41..c7869a587fc 100644 --- a/examples/event_handler_graphql/src/assert_graphql_response_module.py +++ b/examples/event_handler_graphql/src/assert_graphql_response_module.py @@ -1,4 +1,11 @@ -from typing import TypedDict +import sys + +if sys.version_info >= (3, 8): + from typing import TypedDict +else: + from typing_extensions import TypedDict + +from typing import List from aws_lambda_powertools import Logger, Tracer from aws_lambda_powertools.event_handler import AppSyncResolver @@ -20,7 +27,7 @@ class Location(TypedDict, total=False): @app.resolver(field_name="listLocations") @app.resolver(field_name="locations") @tracer.capture_method -def get_locations(name: str, description: str = "") -> list[Location]: # match GraphQL Query arguments +def get_locations(name: str, description: str = "") -> List[Location]: # match GraphQL Query arguments return [{"name": name, "description": description}] diff --git a/examples/event_handler_graphql/src/async_resolvers.py b/examples/event_handler_graphql/src/async_resolvers.py index 229e015c886..072f42dbba9 100644 --- a/examples/event_handler_graphql/src/async_resolvers.py +++ b/examples/event_handler_graphql/src/async_resolvers.py @@ -1,5 +1,12 @@ import asyncio -from typing import TypedDict +import sys + +if sys.version_info >= (3, 8): + from typing import TypedDict +else: + from typing_extensions import TypedDict + +from typing import List import aiohttp @@ -22,7 +29,7 @@ class Todo(TypedDict, total=False): @app.resolver(type_name="Query", field_name="listTodos") -async def list_todos() -> list[Todo]: +async def list_todos() -> List[Todo]: async with aiohttp.ClientSession(trace_configs=[aiohttp_trace_config()]) as session: async with session.get("https://jsonplaceholder.typicode.com/todos") as resp: return await resp.json() diff --git a/examples/event_handler_graphql/src/custom_models.py b/examples/event_handler_graphql/src/custom_models.py index 92763ca3401..594ef5ee248 100644 --- a/examples/event_handler_graphql/src/custom_models.py +++ b/examples/event_handler_graphql/src/custom_models.py @@ -1,4 +1,11 @@ -from typing import TypedDict +import sys + +if sys.version_info >= (3, 8): + from typing import TypedDict +else: + from typing_extensions import TypedDict + +from typing import List from aws_lambda_powertools import Logger, Tracer from aws_lambda_powertools.event_handler import AppSyncResolver @@ -23,21 +30,21 @@ class Location(TypedDict, total=False): class MyCustomModel(AppSyncResolverEvent): @property def country_viewer(self) -> str: - return self.get_header_value(name="cloudfront-viewer-country", default_value="", case_sensitive=False) + return self.get_header_value(name="cloudfront-viewer-country", default_value="", case_sensitive=False) # type: ignore[return-value] # sentinel typing # noqa: E501 @property def api_key(self) -> str: - return self.get_header_value(name="x-api-key", default_value="", case_sensitive=False) + return self.get_header_value(name="x-api-key", default_value="", case_sensitive=False) # type: ignore[return-value] # sentinel typing # noqa: E501 @app.resolver(type_name="Query", field_name="listLocations") -def list_locations(page: int = 0, size: int = 10) -> list[Location]: +def list_locations(page: int = 0, size: int = 10) -> List[Location]: # additional properties/methods will now be available under current_event - logger.debug(f"Request country origin: {app.current_event.country_viewer}") + logger.debug(f"Request country origin: {app.current_event.country_viewer}") # type: ignore[attr-defined] return [{"id": scalar_types_utils.make_id(), "name": "Perry, James and Carroll"}] @tracer.capture_lambda_handler @logger.inject_lambda_context(correlation_id_path=correlation_paths.APPSYNC_RESOLVER) def lambda_handler(event: dict, context: LambdaContext) -> dict: - app.resolve(event, context, data_model=MyCustomModel) + return app.resolve(event, context, data_model=MyCustomModel) diff --git a/examples/event_handler_graphql/src/getting_started_graphql_api_resolver.py b/examples/event_handler_graphql/src/getting_started_graphql_api_resolver.py index 4e42bd42f58..e4879d609f2 100644 --- a/examples/event_handler_graphql/src/getting_started_graphql_api_resolver.py +++ b/examples/event_handler_graphql/src/getting_started_graphql_api_resolver.py @@ -1,4 +1,11 @@ -from typing import TypedDict +import sys + +if sys.version_info >= (3, 8): + from typing import TypedDict +else: + from typing_extensions import TypedDict + +from typing import List import requests from requests import Response @@ -34,7 +41,7 @@ def get_todo( @app.resolver(type_name="Query", field_name="listTodos") @tracer.capture_method -def list_todos() -> list[Todo]: +def list_todos() -> List[Todo]: todos: Response = requests.get("https://jsonplaceholder.typicode.com/todos") todos.raise_for_status() diff --git a/examples/event_handler_graphql/src/graphql_transformer_merchant_info.py b/examples/event_handler_graphql/src/graphql_transformer_merchant_info.py index 272f119f3b8..55f963bb8d5 100644 --- a/examples/event_handler_graphql/src/graphql_transformer_merchant_info.py +++ b/examples/event_handler_graphql/src/graphql_transformer_merchant_info.py @@ -1,4 +1,11 @@ -from typing import TypedDict +import sys + +if sys.version_info >= (3, 8): + from typing import TypedDict +else: + from typing_extensions import TypedDict + +from typing import List from aws_lambda_powertools import Logger, Tracer from aws_lambda_powertools.event_handler import AppSyncResolver @@ -20,7 +27,7 @@ class Location(TypedDict, total=False): @app.resolver(type_name="Query", field_name="listLocations") -def list_locations(page: int = 0, size: int = 10) -> list[Location]: +def list_locations(page: int = 0, size: int = 10) -> List[Location]: return [{"id": scalar_types_utils.make_id(), "name": "Smooth Grooves"}] @@ -33,4 +40,4 @@ def common_field() -> str: @tracer.capture_lambda_handler @logger.inject_lambda_context(correlation_id_path=correlation_paths.APPSYNC_RESOLVER) def lambda_handler(event: dict, context: LambdaContext) -> dict: - app.resolve(event, context) + return app.resolve(event, context) diff --git a/examples/event_handler_graphql/src/graphql_transformer_search_merchant.py b/examples/event_handler_graphql/src/graphql_transformer_search_merchant.py index e2adb566f93..1dd52945f93 100644 --- a/examples/event_handler_graphql/src/graphql_transformer_search_merchant.py +++ b/examples/event_handler_graphql/src/graphql_transformer_search_merchant.py @@ -1,4 +1,11 @@ -from typing import TypedDict +import sys + +if sys.version_info >= (3, 8): + from typing import TypedDict +else: + from typing_extensions import TypedDict + +from typing import List from aws_lambda_powertools import Logger, Tracer from aws_lambda_powertools.event_handler import AppSyncResolver @@ -19,8 +26,8 @@ class Merchant(TypedDict, total=False): @app.resolver(type_name="Query", field_name="findMerchant") -def find_merchant(search: str) -> list[Merchant]: - merchants: list[Merchant] = [ +def find_merchant(search: str) -> List[Merchant]: + merchants: List[Merchant] = [ { "id": scalar_types_utils.make_id(), "name": "Parry-Wood", @@ -33,10 +40,10 @@ def find_merchant(search: str) -> list[Merchant]: }, ] - return next((merchant for merchant in merchants if search == merchant["name"]), [{}]) + return [merchant for merchant in merchants if search == merchant["name"]] @tracer.capture_lambda_handler @logger.inject_lambda_context(correlation_id_path=correlation_paths.APPSYNC_RESOLVER) def lambda_handler(event: dict, context: LambdaContext) -> dict: - app.resolve(event, context) + return app.resolve(event, context) diff --git a/examples/event_handler_graphql/src/nested_mappings.py b/examples/event_handler_graphql/src/nested_mappings.py index 2f9c8ac3c41..c7869a587fc 100644 --- a/examples/event_handler_graphql/src/nested_mappings.py +++ b/examples/event_handler_graphql/src/nested_mappings.py @@ -1,4 +1,11 @@ -from typing import TypedDict +import sys + +if sys.version_info >= (3, 8): + from typing import TypedDict +else: + from typing_extensions import TypedDict + +from typing import List from aws_lambda_powertools import Logger, Tracer from aws_lambda_powertools.event_handler import AppSyncResolver @@ -20,7 +27,7 @@ class Location(TypedDict, total=False): @app.resolver(field_name="listLocations") @app.resolver(field_name="locations") @tracer.capture_method -def get_locations(name: str, description: str = "") -> list[Location]: # match GraphQL Query arguments +def get_locations(name: str, description: str = "") -> List[Location]: # match GraphQL Query arguments return [{"name": name, "description": description}] diff --git a/examples/event_handler_graphql/src/scalar_functions.py b/examples/event_handler_graphql/src/scalar_functions.py index 0d8fa98b7b3..9b241f6c30d 100644 --- a/examples/event_handler_graphql/src/scalar_functions.py +++ b/examples/event_handler_graphql/src/scalar_functions.py @@ -8,8 +8,8 @@ # Scalars: https://docs.aws.amazon.com/appsync/latest/devguide/scalars.html -_: str = make_id() # Scalar: ID! -_: str = aws_date() # Scalar: AWSDate -_: str = aws_time() # Scalar: AWSTime -_: str = aws_datetime() # Scalar: AWSDateTime -_: int = aws_timestamp() # Scalar: AWSTimestamp +my_id: str = make_id() # Scalar: ID! +my_date: str = aws_date() # Scalar: AWSDate +my_timestamp: str = aws_time() # Scalar: AWSTime +my_datetime: str = aws_datetime() # Scalar: AWSDateTime +my_epoch_timestamp: int = aws_timestamp() # Scalar: AWSTimestamp diff --git a/examples/event_handler_graphql/src/split_operation_module.py b/examples/event_handler_graphql/src/split_operation_module.py index 43c413672b6..12569bc23bc 100644 --- a/examples/event_handler_graphql/src/split_operation_module.py +++ b/examples/event_handler_graphql/src/split_operation_module.py @@ -1,4 +1,11 @@ -from typing import TypedDict +import sys + +if sys.version_info >= (3, 8): + from typing import TypedDict +else: + from typing_extensions import TypedDict + +from typing import List from aws_lambda_powertools import Logger, Tracer from aws_lambda_powertools.event_handler.appsync import Router @@ -18,5 +25,5 @@ class Location(TypedDict, total=False): @router.resolver(field_name="listLocations") @router.resolver(field_name="locations") @tracer.capture_method -def get_locations(name: str, description: str = "") -> list[Location]: # match GraphQL Query arguments +def get_locations(name: str, description: str = "") -> List[Location]: # match GraphQL Query arguments return [{"name": name, "description": description}] diff --git a/examples/event_handler_rest/src/binary_responses.py b/examples/event_handler_rest/src/binary_responses.py index 00c027937b8..d56eda1afe8 100644 --- a/examples/event_handler_rest/src/binary_responses.py +++ b/examples/event_handler_rest/src/binary_responses.py @@ -11,7 +11,7 @@ app = APIGatewayRestResolver() -logo_file: bytes = Path(os.getenv("LAMBDA_TASK_ROOT") + "/logo.svg").read_bytes() +logo_file: bytes = Path(f"{os.getenv('LAMBDA_TASK_ROOT')}/logo.svg").read_bytes() @app.get("/logo") diff --git a/examples/event_handler_rest/src/exception_handling.py b/examples/event_handler_rest/src/exception_handling.py index fdac8589299..89a31e60bf1 100644 --- a/examples/event_handler_rest/src/exception_handling.py +++ b/examples/event_handler_rest/src/exception_handling.py @@ -1,8 +1,7 @@ import requests -from requests import Response from aws_lambda_powertools import Logger, Tracer -from aws_lambda_powertools.event_handler import APIGatewayRestResolver, content_types +from aws_lambda_powertools.event_handler import APIGatewayRestResolver, Response, content_types from aws_lambda_powertools.logging import correlation_paths from aws_lambda_powertools.utilities.typing import LambdaContext @@ -30,7 +29,7 @@ def get_todos(): # if a query string value for `limit` cannot be coerced to int max_results: int = int(app.current_event.get_query_string_value(name="limit", default_value=0)) - todos: Response = requests.get(f"https://jsonplaceholder.typicode.com/todos?limit={max_results}") + todos: requests.Response = requests.get(f"https://jsonplaceholder.typicode.com/todos?limit={max_results}") todos.raise_for_status() return {"todos": todos.json()} diff --git a/examples/event_handler_rest/src/split_route_module.py b/examples/event_handler_rest/src/split_route_module.py index eeb696ede56..0462623f90b 100644 --- a/examples/event_handler_rest/src/split_route_module.py +++ b/examples/event_handler_rest/src/split_route_module.py @@ -25,7 +25,7 @@ def get_todos(): @router.get("/todos/") @tracer.capture_method def get_todo_by_id(todo_id: str): # value come as str - api_key: str = router.current_event.get_header_value(name="X-Api-Key", case_sensitive=True, default_value="") + api_key: str = router.current_event.get_header_value(name="X-Api-Key", case_sensitive=True, default_value="") # type: ignore[assignment] # sentinel typing # noqa: E501 todos: Response = requests.get(f"{endpoint}/{todo_id}", headers={"X-Api-Key": api_key}) todos.raise_for_status() diff --git a/examples/event_handler_rest/src/split_route_prefix_module.py b/examples/event_handler_rest/src/split_route_prefix_module.py index b4035282776..41fcf8eed31 100644 --- a/examples/event_handler_rest/src/split_route_prefix_module.py +++ b/examples/event_handler_rest/src/split_route_prefix_module.py @@ -25,7 +25,7 @@ def get_todos(): @router.get("/") @tracer.capture_method def get_todo_by_id(todo_id: str): # value come as str - api_key: str = router.current_event.get_header_value(name="X-Api-Key", case_sensitive=True, default_value="") + api_key: str = router.current_event.get_header_value(name="X-Api-Key", case_sensitive=True, default_value="") # type: ignore[assignment] # sentinel typing # noqa: E501 todos: Response = requests.get(f"{endpoint}/{todo_id}", headers={"X-Api-Key": api_key}) todos.raise_for_status() diff --git a/examples/logger/src/bring_your_own_formatter_from_scratch.py b/examples/logger/src/bring_your_own_formatter_from_scratch.py index 3088bf2a80f..c591b421cc6 100644 --- a/examples/logger/src/bring_your_own_formatter_from_scratch.py +++ b/examples/logger/src/bring_your_own_formatter_from_scratch.py @@ -7,7 +7,7 @@ class CustomFormatter(BasePowertoolsFormatter): - def __init__(self, log_record_order: Optional[List[str]], *args, **kwargs): + def __init__(self, log_record_order: Optional[List[str]] = None, *args, **kwargs): self.log_record_order = log_record_order or ["level", "location", "message", "timestamp"] self.log_format = dict.fromkeys(self.log_record_order) super().__init__(*args, **kwargs) diff --git a/mypy.ini b/mypy.ini index 3061cc4a2d9..8274442fe4b 100644 --- a/mypy.ini +++ b/mypy.ini @@ -20,6 +20,9 @@ ignore_missing_imports=True [mypy-boto3] ignore_missing_imports = True +[mypy-botocore.response] +ignore_missing_imports = True + [mypy-boto3.dynamodb.conditions] ignore_missing_imports = True @@ -33,4 +36,10 @@ ignore_missing_imports = True ignore_missing_imports = True [mypy-dataclasses] +ignore_missing_imports = True + +[mypy-orjson] +ignore_missing_imports = True + +[mypy-aiohttp] ignore_missing_imports = True \ No newline at end of file diff --git a/poetry.lock b/poetry.lock index 76fa6c625e4..bdea1decfde 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1252,13 +1252,32 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "types-requests" +version = "2.28.5" +description = "Typing stubs for requests" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +types-urllib3 = "<1.27" + +[[package]] +name = "types-urllib3" +version = "1.26.17" +description = "Typing stubs for urllib3" +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "typing-extensions" -version = "4.1.1" -description = "Backported and Experimental Type Hints for Python 3.6+" +version = "4.3.0" +description = "Backported and Experimental Type Hints for Python 3.7+" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [[package]] name = "urllib3" @@ -1323,7 +1342,7 @@ pydantic = ["pydantic", "email-validator"] [metadata] lock-version = "1.1" python-versions = "^3.6.2" -content-hash = "242d708424414a3e52bf02ccbb2b6f49d88724c1d4583a133ebc703548b28e88" +content-hash = "783598fdfeef6abc4615ac9ba1ab8ade3cc2ad03859d0ea22d22bc1afe3cbb20" [metadata.files] atomicwrites = [ @@ -1563,28 +1582,12 @@ markdown = [ {file = "Markdown-3.3.5.tar.gz", hash = "sha256:26e9546bfbcde5fcd072bd8f612c9c1b6e2677cb8aadbdf65206674f46dde069"}, ] markupsafe = [ - {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-win32.whl", hash = "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"}, @@ -1593,27 +1596,14 @@ markupsafe = [ {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9"}, {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066"}, {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35"}, {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b"}, {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298"}, {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75"}, {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee"}, {file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"}, {file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"}, {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"}, @@ -1623,12 +1613,6 @@ markupsafe = [ {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135"}, {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902"}, {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1"}, {file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"}, {file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"}, {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"}, @@ -1730,7 +1714,6 @@ pbr = [ {file = "pbr-5.8.0.tar.gz", hash = "sha256:672d8ebee84921862110f23fcec2acea191ef58543d34dfe9ef3d9f13c31cddf"}, ] pdoc3 = [ - {file = "pdoc3-0.10.0-py3-none-any.whl", hash = "sha256:ba45d1ada1bd987427d2bf5cdec30b2631a3ff5fb01f6d0e77648a572ce6028b"}, {file = "pdoc3-0.10.0.tar.gz", hash = "sha256:5f22e7bcb969006738e1aa4219c75a32f34c2d62d46dc9d2fb2d3e0b0287e4b7"}, ] platformdirs = [ @@ -1979,9 +1962,17 @@ typed-ast = [ {file = "typed_ast-1.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:9c6d1a54552b5330bc657b7ef0eae25d00ba7ffe85d9ea8ae6540d2197a3788c"}, {file = "typed_ast-1.4.3.tar.gz", hash = "sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65"}, ] +types-requests = [ + {file = "types-requests-2.28.5.tar.gz", hash = "sha256:ac618bfefcb3742eaf97c961e13e9e5a226e545eda4a3dbe293b898d40933ad1"}, + {file = "types_requests-2.28.5-py3-none-any.whl", hash = "sha256:98ab647ae88b5e2c41d6d20cfcb5117da1bea561110000b6fdeeea07b3e89877"}, +] +types-urllib3 = [ + {file = "types-urllib3-1.26.17.tar.gz", hash = "sha256:73fd274524c3fc7cd8cd9ceb0cb67ed99b45f9cb2831013e46d50c1451044800"}, + {file = "types_urllib3-1.26.17-py3-none-any.whl", hash = "sha256:0d027fcd27dbb3cb532453b4d977e05bc1e13aefd70519866af211b3003d895d"}, +] typing-extensions = [ - {file = "typing_extensions-4.1.1-py3-none-any.whl", hash = "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2"}, - {file = "typing_extensions-4.1.1.tar.gz", hash = "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42"}, + {file = "typing_extensions-4.3.0-py3-none-any.whl", hash = "sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02"}, + {file = "typing_extensions-4.3.0.tar.gz", hash = "sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6"}, ] urllib3 = [ {file = "urllib3-1.26.7-py2.py3-none-any.whl", hash = "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844"}, diff --git a/pyproject.toml b/pyproject.toml index ebf6d3a0e9b..a07ce065857 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -66,7 +66,8 @@ pytest-benchmark = "^3.4.1" mypy-boto3-cloudwatch = "^1.24.35" mypy-boto3-lambda = "^1.24.0" mypy-boto3-xray = "^1.24.0" - +types-requests = "^2.28.5" +typing-extensions = { version = "^4.3.0", python = ">=3.7" } [tool.poetry.extras] pydantic = ["pydantic", "email-validator"]