Spaces:
Sleeping
Sleeping
| """ | |
| Sequence part models for the parts library. | |
| SequencePart is the base class; specialized part types inherit to add | |
| bespoke fields (e.g., CDS has protein_sequence, codon_usage; UTRs have | |
| stability metrics). | |
| Parts are auto-extracted when sequences are analyzed or imported. | |
| """ | |
| from __future__ import annotations | |
| import hashlib | |
| import uuid | |
| from dataclasses import dataclass, field | |
| from typing import Any, Dict, Literal, Optional | |
| class SequencePart: | |
| """ | |
| Base class for reusable sequence parts. | |
| Each part can be mixed and matched in the Parts Workshop to | |
| assemble new mRNA sequences. | |
| """ | |
| name: str | |
| sequence: str | |
| part_type: Literal["5_utr", "kozak", "cds", "3_utr", "polya"] | |
| source: str # "database_import", "generated", "manual", "extracted" | |
| id: str = field(default_factory=lambda: str(uuid.uuid4())) | |
| origin_sequence_id: Optional[str] = None # ID of parent mRNASequence | |
| metadata: Dict[str, Any] = field(default_factory=dict) | |
| def length(self) -> int: | |
| return len(self.sequence) | |
| def sequence_hash(self) -> str: | |
| """SHA256 hash for deduplication.""" | |
| return hashlib.sha256(self.sequence.encode()).hexdigest()[:16] | |
| def to_dict(self) -> Dict[str, Any]: | |
| return { | |
| "id": self.id, | |
| "name": self.name, | |
| "sequence": self.sequence, | |
| "part_type": self.part_type, | |
| "source": self.source, | |
| "origin_sequence_id": self.origin_sequence_id, | |
| "metadata": self.metadata, | |
| } | |
| class UTR5Part(SequencePart): | |
| """5' UTR part with stability and structure metrics.""" | |
| part_type: Literal["5_utr"] = field(default="5_utr", init=False) | |
| # Predicted secondary structure stability | |
| stability_score: Optional[float] = None | |
| mfe: Optional[float] = None # Minimum free energy from ViennaRNA | |
| secondary_structure_dot: Optional[str] = None # Dot-bracket notation | |
| class KozakPart(SequencePart): | |
| """Kozak consensus sequence part.""" | |
| part_type: Literal["kozak"] = field(default="kozak", init=False) | |
| # Consensus score (0-1) based on optimal Kozak pattern | |
| consensus_score: Optional[float] = None | |
| # Canonical Kozak is: gcc(A/G)ccATGG | |
| matches_canonical: Optional[bool] = None | |
| class CDSPart(SequencePart): | |
| """Coding sequence part with translation and codon metrics.""" | |
| part_type: Literal["cds"] = field(default="cds", init=False) | |
| # Translated protein sequence | |
| protein_sequence: Optional[str] = None | |
| # Codon usage metrics | |
| codon_usage: Optional[Dict[str, float]] = None # {codon: frequency} | |
| cai: Optional[float] = None # Codon Adaptation Index | |
| # Quality checks | |
| has_start_codon: Optional[bool] = None | |
| has_stop_codon: Optional[bool] = None | |
| in_frame: Optional[bool] = None | |
| class UTR3Part(SequencePart): | |
| """3' UTR part with stability and regulatory element annotations.""" | |
| part_type: Literal["3_utr"] = field(default="3_utr", init=False) | |
| # Predicted stability | |
| stability_score: Optional[float] = None | |
| mfe: Optional[float] = None | |
| # Regulatory elements (AU-rich elements, miRNA binding sites, etc.) | |
| regulatory_elements: Optional[Dict[str, Any]] = None | |
| class PolyAPart(SequencePart): | |
| """Poly(A) tail part.""" | |
| part_type: Literal["polya"] = field(default="polya", init=False) | |
| # Length of the poly(A) stretch | |
| tail_length: Optional[int] = None | |
| # Purity (percentage of A nucleotides) | |
| purity: Optional[float] = None | |
| # Type alias for all part types | |
| AnyPart = UTR5Part | KozakPart | CDSPart | UTR3Part | PolyAPart | |
| def create_part_from_component( | |
| sequence: str, | |
| part_type: Literal["5_utr", "kozak", "cds", "3_utr", "polya"], | |
| name: str, | |
| source: str, | |
| origin_sequence_id: Optional[str] = None, | |
| ) -> AnyPart: | |
| """ | |
| Factory function to create the appropriate Part subclass. | |
| Used during auto-extraction from mRNASequence objects. | |
| """ | |
| if part_type == "5_utr": | |
| return UTR5Part( | |
| name=name, | |
| sequence=sequence, | |
| source=source, | |
| origin_sequence_id=origin_sequence_id, | |
| ) | |
| elif part_type == "kozak": | |
| return KozakPart( | |
| name=name, | |
| sequence=sequence, | |
| source=source, | |
| origin_sequence_id=origin_sequence_id, | |
| ) | |
| elif part_type == "cds": | |
| return CDSPart( | |
| name=name, | |
| sequence=sequence, | |
| source=source, | |
| origin_sequence_id=origin_sequence_id, | |
| ) | |
| elif part_type == "3_utr": | |
| return UTR3Part( | |
| name=name, | |
| sequence=sequence, | |
| source=source, | |
| origin_sequence_id=origin_sequence_id, | |
| ) | |
| elif part_type == "polya": | |
| return PolyAPart( | |
| name=name, | |
| sequence=sequence, | |
| source=source, | |
| origin_sequence_id=origin_sequence_id, | |
| ) | |
| else: | |
| raise ValueError(f"Unknown part type: {part_type}") | |