"""Lambda entrypoint for the postcode splitter slice. The :func:`handler` function is decorated with ``@subtask_handler()`` so the decorator owns the parent ``SubTask`` lifecycle (start/complete/fail) and injects the decorator-owned :class:`TaskOrchestrator` as the third positional argument. The handler itself does only two things: 1. Build a :class:`PostcodeSplitterOrchestrator` from env-driven config. 2. Delegate to ``split_and_dispatch`` and return its result so it lands in ``SubTask.outputs["result"]``. """ from __future__ import annotations import os from typing import Any import boto3 from applications.postcode_splitter.postcode_splitter_trigger_body import ( PostcodeSplitterTriggerBody, ) from infrastructure.address2uprn_queue_client import Address2UprnQueueClient from infrastructure.csv_s3_client import CsvS3Client from orchestration.postcode_splitter_orchestrator import PostcodeSplitterOrchestrator from orchestration.task_orchestrator import TaskOrchestrator from repositories.user_address.user_address_csv_s3_repository import ( UserAddressCsvS3Repository, ) from utilities.aws_lambda.subtask_handler import subtask_handler @subtask_handler() def handler( body: dict[str, Any], context: Any, task_orchestrator: TaskOrchestrator ) -> dict[str, list[str]]: """Validate the trigger body, build the splitter, dispatch children. Reads ``S3_BUCKET_NAME`` and ``ADDRESS2UPRN_QUEUE_URL`` from the environment to construct the typed S3/SQS clients. The return value lands in ``SubTask.outputs["result"]`` via the decorator. """ trigger = PostcodeSplitterTriggerBody.model_validate(body) bucket = os.environ["S3_BUCKET_NAME"] queue_url = os.environ["ADDRESS2UPRN_QUEUE_URL"] # boto3.client is overloaded per-service in the installed stubs; cast # to Any so the strict-mode checker treats it as opaque. boto3_client: Any = boto3.client # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType] boto_s3: Any = boto3_client("s3") boto_sqs: Any = boto3_client("sqs") csv_client = CsvS3Client(boto_s3, bucket) user_address_repo = UserAddressCsvS3Repository(csv_client, bucket) queue_client = Address2UprnQueueClient(boto_sqs, queue_url) splitter = PostcodeSplitterOrchestrator( task_orchestrator=task_orchestrator, user_address_repo=user_address_repo, queue_client=queue_client, ) child_ids = splitter.split_and_dispatch( parent_task_id=trigger.task_id, parent_subtask_id=trigger.sub_task_id, input_s3_uri=trigger.s3_uri, ) return {"child_subtask_ids": [str(cid) for cid in child_ids]}