Source code for buildcompiler.stages.transformation

"""Transformation stage orchestration."""

from __future__ import annotations

import sbol2

from buildcompiler.adapters.pudu import transformation_to_pudu_json
from buildcompiler.api.options import BuildOptions
from buildcompiler.domain import (
    BuildRequest,
    BuildStage,
    IndexedPlasmid,
    MissingBuildInput,
    StageResult,
    StageStatus,
)
from buildcompiler.sbol.transformation import TransformationJob, TransformationService


[docs] class TransformationStage: def __init__( self, *, transformation_service: TransformationService | None = None, options: BuildOptions | None = None, ) -> None: self.transformation_service = transformation_service or TransformationService() self.options = options or BuildOptions()
[docs] def run( self, plasmid_or_request: IndexedPlasmid | BuildRequest, *, source_document: sbol2.Document | None = None, target_document: sbol2.Document | None = None, ) -> StageResult: source = source_document or sbol2.Document() target = target_document or source request_id = ( plasmid_or_request.id if isinstance(plasmid_or_request, BuildRequest) else f"transform:{plasmid_or_request.identity}" ) plasmid = self._plasmid_from_input(plasmid_or_request) if plasmid is None: return StageResult( id=f"{request_id}:{BuildStage.TRANSFORMATION.value}", stage=BuildStage.TRANSFORMATION, status=StageStatus.FAILED, request_ids=[request_id], logs=["Transformation input must be an IndexedPlasmid."], ) chassis_identity = self.options.transformation.chassis_identity chassis_display_id = self.options.transformation.chassis_display_id if not chassis_identity: return StageResult( id=f"{request_id}:{BuildStage.TRANSFORMATION.value}", stage=BuildStage.TRANSFORMATION, status=StageStatus.BLOCKED, request_ids=[request_id], missing_inputs=[ MissingBuildInput( source_stage=BuildStage.TRANSFORMATION, source_design_identity=plasmid.identity, missing_identity="chassis", missing_display_id=None, missing_kind="chassis", required_stage="fatal", reason="Transformation requires options.transformation.chassis_identity.", ) ], logs=["Transformation blocked on missing chassis identity."], ) result = self.transformation_service.run( TransformationJob( plasmid=plasmid, chassis_identity=chassis_identity, chassis_display_id=chassis_display_id or chassis_identity.rsplit("/", 1)[-1], source_document=source, target_document=target, ) ) json_intermediate = transformation_to_pudu_json( strain_identity=result.product.identity, chassis_identity=chassis_identity, plasmids=[plasmid], ) return StageResult( id=f"{request_id}:{BuildStage.TRANSFORMATION.value}", stage=BuildStage.TRANSFORMATION, status=StageStatus.SUCCESS, request_ids=[request_id], products=[result.product], sbol_document=result.stage_document, json_intermediate=json_intermediate, protocol_artifacts=result.artifacts, logs=result.logs, )
def _plasmid_from_input( self, value: IndexedPlasmid | BuildRequest ) -> IndexedPlasmid | None: if isinstance(value, IndexedPlasmid): return value raw = value.constraints.get("plasmid") if value.constraints else None return raw if isinstance(raw, IndexedPlasmid) else None