aakash0017's picture
Upload folder using huggingface_hub
b7731cd
# Copyright 2022 by Michiel de Hoon. All rights reserved.
#
# This file is part of the Biopython distribution and governed by your
# choice of the "Biopython License Agreement" or the "BSD 3-Clause License".
# Please see the LICENSE file that should have been included as part of this
# package.
"""Bio.Align support for A2M files.
A2M files are alignment files created by align2model or hmmscore in the SAM
Sequence Alignment and Modeling Software System.
"""
from Bio.Align import Alignment
from Bio.Align import interfaces
from Bio.Seq import Seq
from Bio.SeqRecord import SeqRecord
class AlignmentWriter(interfaces.AlignmentWriter):
"""Alignment file writer for the A2M file format."""
fmt = "A2M"
def format_alignment(self, alignment):
"""Return a string with the alignment in the A2M file format."""
if not isinstance(alignment, Alignment):
raise TypeError("Expected an Alignment object")
lines = []
state = alignment.column_annotations["state"]
for sequence, line in zip(alignment.sequences, alignment):
try:
name = sequence.id
except AttributeError:
name = ""
try:
description = sequence.description
except AttributeError:
description = ""
if description:
lines.append(f">{name} {description}")
else:
lines.append(f">{name}")
s = ""
for c, m in zip(line, state):
if m == "D":
s += c.upper()
elif m == "I":
if c == "-":
s += "."
else:
s += c.lower()
lines.append(s)
return "\n".join(lines) + "\n"
write_alignments = interfaces.AlignmentWriter.write_single_alignment
class AlignmentIterator(interfaces.AlignmentIterator):
"""Alignment iterator for files in the A2M file format.
An A2M file contains one multiple alignment. Matches are represented by
upper case letters and deletions by dashes in alignment columns containing
matches or deletions only. Insertions are represented by lower case letters,
with gaps aligned to the insertion shown as periods. Header lines start
with '>' followed by the name of the sequence, and optionally a description.
"""
fmt = "A2M"
def _read_next_alignment(self, stream):
names = []
descriptions = []
lines = []
for line in stream:
if line.startswith(">"):
parts = line[1:].rstrip().split(None, 1)
try:
name = parts[0]
except IndexError:
name = ""
try:
description = parts[1]
except IndexError:
description = ""
names.append(name)
descriptions.append(description)
lines.append("")
else:
lines[-1] += line.strip()
if not lines:
raise ValueError("Empty file.")
state = ""
for c in lines[0]:
if c == "-" or c.isupper():
state += "D" # Match/deletion state
elif c == "." or c.islower():
state += "I" # Insertion state
else:
raise Exception("Unexpected letter '%s' in alignment" % c)
for line in lines[1:]:
for c, m in zip(line, state):
if m == "D": # Match/deletion state
assert c == "-" or c.isupper()
elif m == "I": # Insertion state
assert c == "." or c.islower()
else:
raise Exception("Unexpected letter '%s' in alignment" % c)
for i, line in enumerate(lines):
lines[i] = line.upper().replace(".", "-")
coordinates = Alignment.infer_coordinates(lines)
records = []
for name, description, line in zip(names, descriptions, lines):
line = line.replace("-", "")
sequence = Seq(line)
record = SeqRecord(sequence, name, description=description)
records.append(record)
alignment = Alignment(records, coordinates)
alignment.column_annotations = {}
alignment.column_annotations["state"] = state
self._close() # a2m files contain only one alignment
return alignment