#!/usr/bin/env python # Copyright 2004 by Michael Hoffman. 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. """Run and process output from the Wise2 package tool psw. Bio.Wise contains modules for running and processing the output of some of the models in the Wise2 package by Ewan Birney available from: ftp://ftp.ebi.ac.uk/pub/software/unix/wise2/ http://www.ebi.ac.uk/Wise2/ Bio.Wise.psw is for protein Smith-Waterman alignments Bio.Wise.dnal is for Smith-Waterman DNA alignments """ from __future__ import print_function import os import re import sys from Bio import Wise _CMDLINE_PSW = ["psw", "-l", "-F"] _OPTION_GAP_START = "-g" _OPTION_GAP_EXTENSION = "-e" _OPTION_SCORES = "-m" class AlignmentColumnFullException(Exception): """Manage exception in the alignment output.""" pass class Alignment(list): """Define a container for all alignment Columns, output from running psw.""" def append(self, column_unit): """Add an alignment Column to Alignment.""" try: self[-1].append(column_unit) except AlignmentColumnFullException: list.append(self, AlignmentColumn(column_unit)) except IndexError: list.append(self, AlignmentColumn(column_unit)) class AlignmentColumn(list): """Define a container for the units that made the Column.""" def _set_kind(self, column_unit): if self.kind == "SEQUENCE": self.kind = column_unit.kind def __init__(self, column_unit): """Initialize the class.""" assert column_unit.unit == 0 self.kind = column_unit.kind list.__init__(self, [column_unit.column, None]) def __repr__(self): """Represent the AlignmentColumn object as a string for debugging.""" return "%s(%r, %r)" % (self.kind, self[0], self[1]) def append(self, column_unit): """Add a unit to the Column.""" if self[1] is not None: raise AlignmentColumnFullException assert column_unit.unit == 1 self._set_kind(column_unit) self[1] = column_unit.column class ColumnUnit(object): """Define a container for the details of each sequence alignment.""" def __init__(self, unit, column, kind): """Initialize the class.""" self.unit = unit self.column = column self.kind = kind def __repr__(self): """Represent the ColumnUnit object as a string for debugging.""" return "ColumnUnit(unit=%r, column=%r, kind=%r)" % (self.unit, self.column, self.kind) _re_unit = re.compile(r"^Unit +([01])- \[ *(-?\d+)- *(-?\d+)\] \[(\w+)\]$") def parse_line(line): """Parse a line from psw. >>> print(parse_line("Column 0:")) None >>> parse_line("Unit 0- [ -1- 0] [SEQUENCE]") ColumnUnit(unit=0, column=0, kind='SEQUENCE') >>> parse_line("Unit 1- [ 85- 86] [SEQUENCE]") ColumnUnit(unit=1, column=86, kind='SEQUENCE') """ match = _re_unit.match(line.rstrip()) if not match: return return ColumnUnit(int(match.group(1)), int(match.group(3)), match.group(4)) def parse(iterable): """Parse a file. format Column 0: Unit 0- [ -1- 0] [SEQUENCE] Unit 1- [ 85- 86] [SEQUENCE] means that seq1[0] == seq2[86] (0-based) """ alignment = Alignment() for line in iterable: try: if os.environ["WISE_PY_DEBUG"]: print(line) except KeyError: pass column_unit = parse_line(line) if column_unit: alignment.append(column_unit) return alignment def align(pair, scores=None, gap_start=None, gap_extension=None, *args, **keywds): """Align a pair of DNA files using Wise2 psw.""" cmdline = _CMDLINE_PSW[:] if scores: cmdline.extend((_OPTION_SCORES, scores)) if gap_start: cmdline.extend((_OPTION_GAP_START, str(gap_start))) if gap_extension: cmdline.extend((_OPTION_GAP_EXTENSION, str(gap_extension))) temp_file = Wise.align(cmdline, pair, *args, **keywds) return parse(temp_file) def main(): """Command line implementation.""" print(align(sys.argv[1:3])) def _test(*args, **keywds): import doctest doctest.testmod(sys.modules[__name__], *args, **keywds) if __name__ == "__main__": if __debug__: _test() """Initialize the class.""" main()