11# -*- coding: utf-8 -*-
2-
32"""
43Batch processing utilities
54"""
5+ from __future__ import annotations
6+
67import asyncio
78import copy
89import inspect
1112import sys
1213from abc import ABC , abstractmethod
1314from enum import Enum
14- from typing import Any , Callable , List , Optional , Tuple , Union , overload
15+ from typing import TYPE_CHECKING , Any , Callable , Tuple , Union , overload
1516
1617from aws_lambda_powertools .shared import constants
1718from aws_lambda_powertools .utilities .batch .exceptions import (
1819 BatchProcessingError ,
1920 ExceptionInfo ,
2021)
21- from aws_lambda_powertools .utilities .batch .types import BatchTypeModels , PartialItemFailureResponse , PartialItemFailures
22+ from aws_lambda_powertools .utilities .batch .types import BatchTypeModels
2223from aws_lambda_powertools .utilities .data_classes .dynamo_db_stream_event import (
2324 DynamoDBRecord ,
2425)
2526from aws_lambda_powertools .utilities .data_classes .kinesis_stream_event import (
2627 KinesisStreamRecord ,
2728)
2829from aws_lambda_powertools .utilities .data_classes .sqs_event import SQSRecord
29- from aws_lambda_powertools .utilities .typing import LambdaContext
30+
31+ if TYPE_CHECKING :
32+ from aws_lambda_powertools .utilities .batch .types import (
33+ PartialItemFailureResponse ,
34+ PartialItemFailures ,
35+ )
36+ from aws_lambda_powertools .utilities .typing import LambdaContext
3037
3138logger = logging .getLogger (__name__ )
3239
@@ -41,7 +48,7 @@ class EventType(Enum):
4148# and depending on what EventType it's passed it'll correctly map to the right record
4249# When using Pydantic Models, it'll accept any subclass from SQS, DynamoDB and Kinesis
4350EventSourceDataClassTypes = Union [SQSRecord , KinesisStreamRecord , DynamoDBRecord ]
44- BatchEventTypes = Union [EventSourceDataClassTypes , " BatchTypeModels" ]
51+ BatchEventTypes = Union [EventSourceDataClassTypes , BatchTypeModels ]
4552SuccessResponse = Tuple [str , Any , BatchEventTypes ]
4653FailureResponse = Tuple [str , str , BatchEventTypes ]
4754
@@ -54,9 +61,9 @@ class BasePartialProcessor(ABC):
5461 lambda_context : LambdaContext
5562
5663 def __init__ (self ):
57- self .success_messages : List [BatchEventTypes ] = []
58- self .fail_messages : List [BatchEventTypes ] = []
59- self .exceptions : List [ExceptionInfo ] = []
64+ self .success_messages : list [BatchEventTypes ] = []
65+ self .fail_messages : list [BatchEventTypes ] = []
66+ self .exceptions : list [ExceptionInfo ] = []
6067
6168 @abstractmethod
6269 def _prepare (self ):
@@ -79,7 +86,7 @@ def _process_record(self, record: dict):
7986 """
8087 raise NotImplementedError ()
8188
82- def process (self ) -> List [ Tuple ]:
89+ def process (self ) -> list [ tuple ]:
8390 """
8491 Call instance's handler for each record.
8592 """
@@ -92,7 +99,7 @@ async def _async_process_record(self, record: dict):
9299 """
93100 raise NotImplementedError ()
94101
95- def async_process (self ) -> List [ Tuple ]:
102+ def async_process (self ) -> list [ tuple ]:
96103 """
97104 Async call instance's handler for each record.
98105
@@ -135,13 +142,13 @@ def __enter__(self):
135142 def __exit__ (self , exception_type , exception_value , traceback ):
136143 self ._clean ()
137144
138- def __call__ (self , records : List [dict ], handler : Callable , lambda_context : Optional [ LambdaContext ] = None ):
145+ def __call__ (self , records : list [dict ], handler : Callable , lambda_context : LambdaContext | None = None ):
139146 """
140147 Set instance attributes before execution
141148
142149 Parameters
143150 ----------
144- records: List [dict]
151+ records: list [dict]
145152 List with objects to be processed.
146153 handler: Callable
147154 Callable to process "records" entries.
@@ -222,14 +229,14 @@ def failure_handler(self, record, exception: ExceptionInfo) -> FailureResponse:
222229class BasePartialBatchProcessor (BasePartialProcessor ): # noqa
223230 DEFAULT_RESPONSE : PartialItemFailureResponse = {"batchItemFailures" : []}
224231
225- def __init__ (self , event_type : EventType , model : Optional [ " BatchTypeModels" ] = None ):
232+ def __init__ (self , event_type : EventType , model : BatchTypeModels | None = None ):
226233 """Process batch and partially report failed items
227234
228235 Parameters
229236 ----------
230237 event_type: EventType
231238 Whether this is a SQS, DynamoDB Streams, or Kinesis Data Stream event
232- model: Optional[" BatchTypeModels"]
239+ model: BatchTypeModels | None
233240 Parser's data model using either SqsRecordModel, DynamoDBStreamRecordModel, KinesisDataStreamRecord
234241
235242 Exceptions
@@ -294,7 +301,7 @@ def _has_messages_to_report(self) -> bool:
294301 def _entire_batch_failed (self ) -> bool :
295302 return len (self .exceptions ) == len (self .records )
296303
297- def _get_messages_to_report (self ) -> List [PartialItemFailures ]:
304+ def _get_messages_to_report (self ) -> list [PartialItemFailures ]:
298305 """
299306 Format messages to use in batch deletion
300307 """
@@ -343,13 +350,13 @@ def _to_batch_type(
343350 self ,
344351 record : dict ,
345352 event_type : EventType ,
346- model : " BatchTypeModels" ,
347- ) -> " BatchTypeModels" : ... # pragma: no cover
353+ model : BatchTypeModels ,
354+ ) -> BatchTypeModels : ... # pragma: no cover
348355
349356 @overload
350357 def _to_batch_type (self , record : dict , event_type : EventType ) -> EventSourceDataClassTypes : ... # pragma: no cover
351358
352- def _to_batch_type (self , record : dict , event_type : EventType , model : Optional [ " BatchTypeModels" ] = None ):
359+ def _to_batch_type (self , record : dict , event_type : EventType , model : BatchTypeModels | None = None ):
353360 if model is not None :
354361 # If a model is provided, we assume Pydantic is installed and we need to disable v2 warnings
355362 return model .model_validate (record )
@@ -363,7 +370,7 @@ def _register_model_validation_error_record(self, record: dict):
363370 # and downstream we can correctly collect the correct message id identifier and make the failed record available
364371 # see https://github.com/aws-powertools/powertools-lambda-python/issues/2091
365372 logger .debug ("Record cannot be converted to customer's model; converting without model" )
366- failed_record : " EventSourceDataClassTypes" = self ._to_batch_type (record = record , event_type = self .event_type )
373+ failed_record : EventSourceDataClassTypes = self ._to_batch_type (record = record , event_type = self .event_type )
367374 return self .failure_handler (record = failed_record , exception = sys .exc_info ())
368375
369376
@@ -453,7 +460,7 @@ def record_handler(record: DynamoDBRecord):
453460 logger.info(record.dynamodb.new_image)
454461 payload: dict = json.loads(record.dynamodb.new_image.get("item"))
455462 # alternatively:
456- # changes: Dict [str, Any] = record.dynamodb.new_image # noqa: ERA001
463+ # changes: dict [str, Any] = record.dynamodb.new_image # noqa: ERA001
457464 # payload = change.get("Message") -> "<payload>"
458465 ...
459466
@@ -481,7 +488,7 @@ def lambda_handler(event, context: LambdaContext):
481488 async def _async_process_record (self , record : dict ):
482489 raise NotImplementedError ()
483490
484- def _process_record (self , record : dict ) -> Union [ SuccessResponse , FailureResponse ] :
491+ def _process_record (self , record : dict ) -> SuccessResponse | FailureResponse :
485492 """
486493 Process a record with instance's handler
487494
@@ -490,7 +497,7 @@ def _process_record(self, record: dict) -> Union[SuccessResponse, FailureRespons
490497 record: dict
491498 A batch record to be processed.
492499 """
493- data : Optional [ " BatchTypeModels" ] = None
500+ data : BatchTypeModels | None = None
494501 try :
495502 data = self ._to_batch_type (record = record , event_type = self .event_type , model = self .model )
496503 if self ._handler_accepts_lambda_context :
@@ -602,7 +609,7 @@ async def record_handler(record: DynamoDBRecord):
602609 logger.info(record.dynamodb.new_image)
603610 payload: dict = json.loads(record.dynamodb.new_image.get("item"))
604611 # alternatively:
605- # changes: Dict [str, Any] = record.dynamodb.new_image # noqa: ERA001
612+ # changes: dict [str, Any] = record.dynamodb.new_image # noqa: ERA001
606613 # payload = change.get("Message") -> "<payload>"
607614 ...
608615
@@ -630,7 +637,7 @@ def lambda_handler(event, context: LambdaContext):
630637 def _process_record (self , record : dict ):
631638 raise NotImplementedError ()
632639
633- async def _async_process_record (self , record : dict ) -> Union [ SuccessResponse , FailureResponse ] :
640+ async def _async_process_record (self , record : dict ) -> SuccessResponse | FailureResponse :
634641 """
635642 Process a record with instance's handler
636643
@@ -639,7 +646,7 @@ async def _async_process_record(self, record: dict) -> Union[SuccessResponse, Fa
639646 record: dict
640647 A batch record to be processed.
641648 """
642- data : Optional [ " BatchTypeModels" ] = None
649+ data : BatchTypeModels | None = None
643650 try :
644651 data = self ._to_batch_type (record = record , event_type = self .event_type , model = self .model )
645652 if self ._handler_accepts_lambda_context :
0 commit comments