AlphaFold3 / flax_model /alphafold3 /data /structure_stores.py
OneScience's picture
Upload folder using huggingface_hub
35cdf53 verified
Raw
History Blame Contribute Delete
2.87 kB
"""Library for loading structure data from various sources."""
from collections.abc import Mapping, Sequence
import functools
import os
import pathlib
import tarfile
class NotFoundError(KeyError):
"""Raised when the structure store doesn't contain the requested target."""
class StructureStore:
"""Handles the retrieval of mmCIF files from a filesystem."""
def __init__(
self,
structures: str | os.PathLike[str] | Mapping[str, str],
):
"""Initialises the instance.
Args:
structures: Path of the directory where the mmCIF files are or a Mapping
from target name to mmCIF string.
"""
if isinstance(structures, Mapping):
self._structure_mapping = structures
self._structure_path = None
self._structure_tar = None
else:
self._structure_mapping = None
path_str = os.fspath(structures)
if path_str.endswith('.tar'):
self._structure_tar = tarfile.open(path_str, 'r')
self._structure_path = None
else:
self._structure_path = pathlib.Path(structures)
self._structure_tar = None
@functools.cached_property
def _tar_members(self) -> Mapping[str, tarfile.TarInfo]:
assert self._structure_tar is not None
return {
path.stem: tarinfo
for tarinfo in self._structure_tar.getmembers()
if tarinfo.isfile()
and (path := pathlib.Path(tarinfo.path.lower())).suffix == '.cif'
}
def get_mmcif_str(self, target_name: str) -> str:
"""Returns an mmCIF for a given `target_name`.
Args:
target_name: Name specifying the target mmCIF.
Raises:
NotFoundError: If the target is not found.
"""
if self._structure_mapping is not None:
try:
return self._structure_mapping[target_name]
except KeyError as e:
raise NotFoundError(f'{target_name=} not found') from e
if self._structure_tar is not None:
try:
member = self._tar_members[target_name]
if struct_file := self._structure_tar.extractfile(member):
return struct_file.read().decode()
else:
raise NotFoundError(f'{target_name=} not found')
except KeyError:
raise NotFoundError(f'{target_name=} not found') from None
filepath = self._structure_path / f'{target_name}.cif'
try:
return filepath.read_text()
except FileNotFoundError as e:
raise NotFoundError(f'{target_name=} not found at {filepath=}') from e
def target_names(self) -> Sequence[str]:
"""Returns all targets in the store."""
if self._structure_mapping is not None:
return [*self._structure_mapping.keys()]
elif self._structure_tar is not None:
return sorted(self._tar_members.keys())
elif self._structure_path is not None:
return sorted([path.stem for path in self._structure_path.glob('*.cif')])
return ()