aakash0017's picture
Upload folder using huggingface_hub
b7731cd
# Copyright 2006-2021 by Peter Cock.
# 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 module (not for general use).
Unless you are writing a new parser or writer for Bio.Align, you should not
use this module. It provides base classes to try and simplify things.
"""
from abc import ABC
from abc import abstractmethod
from Bio import StreamModeError
class AlignmentIterator(ABC):
"""Base class for building Alignment iterators.
You should write a parse method that returns an Alignment generator. You
may wish to redefine the __init__ method as well.
Subclasses may define the following class attributes:
- mode - 't' or 'b' for text or binary files, respectively
- fmt - a human-readable name for the file format.
"""
mode = "t" # assume text files by default
fmt = None # to be defined in the subclass
def __init__(self, source):
"""Create an AlignmentIterator object.
Arguments:
- source - input file stream, or path to input file
This method MAY be overridden by any subclass.
Note when subclassing:
- there should be a single non-optional argument, the source.
- you can add additional optional arguments.
"""
self.source = source
try:
self._stream = open(source, "r" + self.mode)
except TypeError: # not a path, assume we received a stream
if self.mode == "t":
if source.read(0) != "":
raise StreamModeError(
f"{self.fmt} files must be opened in text mode."
) from None
elif self.mode == "b":
if source.read(0) != b"":
raise StreamModeError(
f"{self.fmt} files must be opened in binary mode."
) from None
else:
raise ValueError(f"Unknown mode '{self.mode}'") from None
self._stream = source
try:
self._read_header(self._stream)
except Exception:
self._close()
raise
def __next__(self):
"""Return the next entry."""
try:
stream = self._stream
except AttributeError:
raise StopIteration from None
try:
alignment = self._read_next_alignment(stream)
if alignment is None:
raise StopIteration
except Exception:
self._close()
raise
return alignment
def __iter__(self):
"""Iterate over the entries as Alignment objects.
This method SHOULD NOT be overridden by any subclass. It should be
left as is, which will call the subclass implementation of __next__
to actually parse the file.
"""
return self
def _read_header(self, stream):
"""Read the file header and store it in metadata."""
return
@abstractmethod
def _read_next_alignment(self, stream):
"""Read one Alignment from the stream, and return it."""
def _close(self):
try:
stream = self._stream
except AttributeError:
return
if stream is not self.source:
stream.close()
del self._stream
class AlignmentWriter(ABC):
"""Base class for alignment writers. This class should be subclassed.
It is intended for alignment file formats with an (optional)
header, one or more alignments, and an (optional) footer.
The user may call the write_file() method to write a complete
file containing the alignments.
Alternatively, users may call the write_header(), followed
by multiple calls to format_alignment() and/or write_alignments(),
followed finally by write_footer().
Subclasses may define the following class attributes:
- mode - 'w' or 'wb' for text or binary files, respectively
- fmt - a human-readable name for the file format.
"""
mode = "w" # assume text files by default
fmt = None # to be defined in the subclass
def __init__(self, target):
"""Create the writer object.
Arguments:
- target - output file stream, or path to output file
This method MAY be overridden by any subclass.
Note when subclassing:
- there should be a single non-optional argument, the target.
- you can add additional optional arguments.
"""
if target is not None:
# target is None if we only use the writer to format strings.
if self.mode == "w":
try:
target.write("")
except TypeError:
# target was opened in binary mode
raise StreamModeError("File must be opened in text mode.") from None
except AttributeError:
# target is a path
stream = open(target, self.mode)
else:
stream = target
elif self.mode == "wb":
try:
target.write(b"")
except TypeError:
# target was opened in text mode
raise StreamModeError(
"File must be opened in binary mode."
) from None
except AttributeError:
# target is a path
stream = open(target, self.mode)
else:
stream = target
else:
raise RuntimeError("Unknown mode '%s'" % self.mode)
self.stream = stream
self._target = target
def write_header(self, alignments):
"""Write the file header to the output file."""
return
##################################################
# You MUST implement this method in the subclass #
# if the file format defines a file header. #
##################################################
def write_footer(self):
"""Write the file footer to the output file."""
return
##################################################
# You MUST implement this method in the subclass #
# if the file format defines a file footer. #
##################################################
def format_alignment(self, alignment):
"""Format a single alignment as a string.
alignment - an Alignment object
"""
raise NotImplementedError("This method should be implemented")
###################################################
# You MUST implement this method in the subclass. #
###################################################
def write_single_alignment(self, alignments):
"""Write a single alignment to the output file, and return 1.
alignments - A list or iterator returning Alignment objects
"""
count = 0
for alignment in alignments:
if count == 1:
raise ValueError(
f"Alignment files in the {self.fmt} format can contain a single alignment only."
)
line = self.format_alignment(alignment)
self.stream.write(line)
count += 1
return count
def write_multiple_alignments(self, alignments):
"""Write alignments to the output file, and return the number of alignments.
alignments - A list or iterator returning Alignment objects
"""
count = 0
for alignment in alignments:
line = self.format_alignment(alignment)
self.stream.write(line)
count += 1
return count
write_alignments = write_multiple_alignments
def write_file(self, alignments):
"""Write a file with the alignments, and return the number of alignments.
alignments - A list or iterator returning Alignment objects
"""
try:
self.write_header(alignments)
count = self.write_alignments(alignments)
self.write_footer()
finally:
if self.stream is not self._target:
self.stream.close()
return count