Source code for pyexpressionatlas.validation
"""Validation utilities for Expression Atlas."""
import re
from collections.abc import Sequence
from .exceptions import InvalidAccessionError
# Pattern: E-XXXX-#### where XXXX is 4 word characters and #### is one or more digits
ACCESSION_PATTERN = re.compile(r"^E-\w{4}-\d+$")
[docs]
def is_valid_accession(accession: str) -> bool:
"""Check if experiment accession matches expected ArrayExpress/BioStudies format.
Valid format: E-XXXX-#### (e.g., E-MTAB-1624, E-GEOD-11175)
Args:
accession:
The experiment accession to validate.
Returns:
True if valid, False otherwise.
Examples:
>>> is_valid_accession(
... "E-MTAB-1624"
... )
True
>>> is_valid_accession(
... "E-GEOD-11175"
... )
True
>>> is_valid_accession(
... "DRP000391"
... )
False
>>> is_valid_accession(
... "invalid"
... )
False
"""
if not accession:
return False
return bool(ACCESSION_PATTERN.match(accession))
[docs]
def validate_accession(accession: str) -> str:
"""Validate accession and raise error if invalid.
Args:
accession:
The experiment accession to validate.
Returns:
The validated accession (unchanged if valid).
Raises:
InvalidAccessionError:
If the accession format is invalid.
"""
if not is_valid_accession(accession):
raise InvalidAccessionError(accession)
return accession
[docs]
def filter_valid_accessions(
accessions: Sequence[str],
raise_on_invalid: bool = False,
) -> list[str]:
"""Filter a list of accessions to only include valid ones.
Args:
accessions:
List of experiment accessions to filter.
raise_on_invalid:
If True, raise error on first invalid accession.
If False (default), silently skip invalid accessions.
Returns:
List containing only valid accessions.
Raises:
InvalidAccessionError:
If raise_on_invalid is True and an invalid accession is found.
"""
valid = []
for acc in accessions:
if is_valid_accession(acc):
valid.append(acc)
elif raise_on_invalid:
raise InvalidAccessionError(acc)
return valid