# Path: alphafold/data/parsers.py
# class Msa:
# class TemplateHit:
# class HitMetadata:
#   def __post_init__(self):
#   def __len__(self):
#   def truncate(self, max_seqs: int):
# def parse_fasta(fasta_string: str) -> Tuple[Sequence[str], Sequence[str]]:
# def parse_stockholm(stockholm_string: str) -> Msa:
# def parse_a3m(a3m_string: str) -> Msa:
# def _convert_sto_seq_to_a3m(
#     query_non_gaps: Sequence[bool], sto_seq: str) -> Iterable[str]:
# def convert_stockholm_to_a3m(stockholm_format: str,
#                              max_sequences: Optional[int] = None,
#                              remove_first_row_gaps: bool = True) -> str:
# def _keep_line(line: str, seqnames: Set[str]) -> bool:
# def truncate_stockholm_msa(stockholm_msa_path: str, max_sequences: int) -> str:
# def remove_empty_columns_from_stockholm_msa(stockholm_msa: str) -> str:
# def deduplicate_stockholm_msa(stockholm_msa: str) -> str:
# def _get_hhr_line_regex_groups(
#     regex_pattern: str, line: str) -> Sequence[Optional[str]]:
# def _update_hhr_residue_indices_list(
#     sequence: str, start_index: int, indices_list: List[int]):
# def _parse_hhr_hit(detailed_lines: Sequence[str]) -> TemplateHit:
# def parse_hhr(hhr_string: str) -> Sequence[TemplateHit]:
# def parse_e_values_from_tblout(tblout: str) -> Dict[str, float]:
# def _get_indices(sequence: str, start: int) -> List[int]:
# def _parse_hmmsearch_description(description: str) -> HitMetadata:
# def parse_hmmsearch_a3m(query_sequence: str,
#                         a3m_string: str,
#                         skip_first: bool = True) -> Sequence[TemplateHit]:
# 
# Path: alphafold/data/tools/utils.py
# def tmpdir_manager(base_dir: Optional[str] = None):
# def timing(msg: str):


import glob
import os
import subprocess
from typing import Sequence
from absl import logging
from alphafold.data import parsers
from alphafold.data.tools import utils
    Args:
      binary_path: The path to the HHsearch executable.
      databases: A sequence of HHsearch database paths. This should be the
        common prefix for the database files (i.e. up to but not including
        _hhm.ffindex etc.)
      maxseq: The maximum number of rows in an input alignment. Note that this
        parameter is only supported in HHBlits version 3.1 and higher.

    Raises:
      RuntimeError: If HHsearch binary not found within the path.
    """
    self.binary_path = binary_path
    self.databases = databases
    self.maxseq = maxseq

    for database_path in self.databases:
      if not glob.glob(database_path + '_*'):
        logging.error('Could not find HHsearch database %s', database_path)
        raise ValueError(f'Could not find HHsearch database {database_path}')

  @property
  def output_format(self) -> str:
    return 'hhr'

  @property
  def input_format(self) -> str:
    return 'a3m'

  def query(self, a3m: str) -> str:
    """Queries the database using HHsearch using a given a3m."""

# Path: alphafold/data/parsers.py
# class Msa:
# class TemplateHit:
# class HitMetadata:
#   def __post_init__(self):
#   def __len__(self):
#   def truncate(self, max_seqs: int):
# def parse_fasta(fasta_string: str) -> Tuple[Sequence[str], Sequence[str]]:
# def parse_stockholm(stockholm_string: str) -> Msa:
# def parse_a3m(a3m_string: str) -> Msa:
# def _convert_sto_seq_to_a3m(
#     query_non_gaps: Sequence[bool], sto_seq: str) -> Iterable[str]:
# def convert_stockholm_to_a3m(stockholm_format: str,
#                              max_sequences: Optional[int] = None,
#                              remove_first_row_gaps: bool = True) -> str:
# def _keep_line(line: str, seqnames: Set[str]) -> bool:
# def truncate_stockholm_msa(stockholm_msa_path: str, max_sequences: int) -> str:
# def remove_empty_columns_from_stockholm_msa(stockholm_msa: str) -> str:
# def deduplicate_stockholm_msa(stockholm_msa: str) -> str:
# def _get_hhr_line_regex_groups(
#     regex_pattern: str, line: str) -> Sequence[Optional[str]]:
# def _update_hhr_residue_indices_list(
#     sequence: str, start_index: int, indices_list: List[int]):
# def _parse_hhr_hit(detailed_lines: Sequence[str]) -> TemplateHit:
# def parse_hhr(hhr_string: str) -> Sequence[TemplateHit]:
# def parse_e_values_from_tblout(tblout: str) -> Dict[str, float]:
# def _get_indices(sequence: str, start: int) -> List[int]:
# def _parse_hmmsearch_description(description: str) -> HitMetadata:
# def parse_hmmsearch_a3m(query_sequence: str,
#                         a3m_string: str,
#                         skip_first: bool = True) -> Sequence[TemplateHit]:
# 
# Path: alphafold/data/tools/utils.py
# def tmpdir_manager(base_dir: Optional[str] = None):
# def timing(msg: str):


# Path: alphafold/data/tools/hhsearch.py
import glob
import os
import subprocess
from typing import Sequence
from absl import logging
from alphafold.data import parsers
from alphafold.data.tools import utils

    Args:
      binary_path: The path to the HHsearch executable.
      databases: A sequence of HHsearch database paths. This should be the
        common prefix for the database files (i.e. up to but not including
        _hhm.ffindex etc.)
      maxseq: The maximum number of rows in an input alignment. Note that this
        parameter is only supported in HHBlits version 3.1 and higher.

    Raises:
      RuntimeError: If HHsearch binary not found within the path.
    """
    self.binary_path = binary_path
    self.databases = databases
    self.maxseq = maxseq

    for database_path in self.databases:
      if not glob.glob(database_path + '_*'):
        logging.error('Could not find HHsearch database %s', database_path)
        raise ValueError(f'Could not find HHsearch database {database_path}')

  @property
  def output_format(self) -> str:
    return 'hhr'

  @property
  def input_format(self) -> str:
    return 'a3m'

  def query(self, a3m: str) -> str:
    """Queries the database using HHsearch using a given a3m."""

    with utils.tmpdir_manager() as query_tmp_dir: