be_protein_binding / backend /app /sequence.py
projectxddi's picture
AI server: backend, start-up, status and admin pages
093748c verified
Raw History Blame Contribute Delete
1.7 kB
"""Input sequence cleaning/validation (integration guide section 5)."""
from .errors import SequenceError
STANDARD_AA = frozenset("ACDEFGHIKLMNPQRSTVWY")
def clean_sequence(raw: str, min_length: int, max_length: int,
limit_reason: str = "the structure predictor: ESMFold API") -> str:
"""Strip one optional FASTA header and all whitespace, uppercase, then validate."""
lines = (raw or "").strip().splitlines()
headers = [line for line in lines if line.lstrip().startswith(">")]
if len(headers) > 1:
raise SequenceError(f"Only one sequence per request is supported (found {len(headers)} FASTA records).")
sequence = "".join("".join(line for line in lines if not line.lstrip().startswith(">")).split()).upper()
if not sequence:
raise SequenceError("Sequence is empty.")
invalid = [(i + 1, aa) for i, aa in enumerate(sequence) if aa not in STANDARD_AA]
if invalid:
shown = ", ".join(f"'{aa}' at {pos}" for pos, aa in invalid[:5])
more = f" (+{len(invalid) - 5} more)" if len(invalid) > 5 else ""
raise SequenceError(
f"Sequence may only contain the 20 standard amino acids (ACDEFGHIKLMNPQRSTVWY). "
f"Found {shown}{more}. Non-standard residues such as X, U, B, Z, O are not supported."
)
if len(sequence) < min_length:
raise SequenceError(f"Sequence has {len(sequence)} residues; the minimum is {min_length}.")
if len(sequence) > max_length:
raise SequenceError(
f"Sequence has {len(sequence)} residues; the maximum is {max_length} "
f"(limit of {limit_reason}).",
too_long=True,
)
return sequence