Spaces:
No application file
No application file
# Copyright 2014 Joe Cora. | |
# Revisions copyright 2017 Peter Cock. | |
# 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. | |
"""Objects to represent NEXUS standard data type matrix coding.""" | |
class NexusError(Exception): | |
"""Provision for the management of Nexus exceptions.""" | |
pass | |
class StandardData: | |
"""Create a StandardData iterable object. | |
Each coding specifies t [type] => (std [standard], multi [multistate] or | |
uncer [uncertain]) and d [data] | |
""" | |
def __init__(self, data): | |
"""Initialize the class.""" | |
self._data = [] | |
self._current_pos = 0 | |
# Enforce string data requirement | |
if not isinstance(data, str): | |
raise NexusError( | |
"The coding data given to a StandardData object should be a string" | |
) | |
# Transfer each coding to a position within a sequence | |
multi_coding = False | |
uncertain_coding = False | |
coding_list = {"t": "std", "d": []} | |
for pos, coding in enumerate(data): | |
# Check if in a multiple coded or uncertain character | |
if multi_coding: | |
# End multicoding if close parenthesis | |
if coding == ")": | |
multi_coding = False | |
else: | |
# Add current coding to list and advance to next coding | |
coding_list["d"].append(coding) | |
continue | |
elif uncertain_coding: | |
# End multicoding if close parenthesis | |
if coding == "}": | |
uncertain_coding = False | |
else: | |
# Add current coding to list and advance to next coding | |
coding_list["d"].append(coding) | |
continue | |
else: | |
# Check if a multiple coded or uncertain character is starting | |
if coding == "(": | |
multi_coding = True | |
coding_list["t"] = "multi" | |
continue | |
elif coding == "{": | |
uncertain_coding = True | |
coding_list["t"] = "uncer" | |
continue | |
elif coding in [")", "}"]: | |
raise NexusError( | |
"Improper character %s at position %i of a coding sequence." | |
% (coding, pos) | |
) | |
else: | |
coding_list["d"].append(coding) | |
# Add character coding to data | |
self._data.append(coding_list.copy()) | |
coding_list = {"t": "std", "d": []} | |
def __len__(self): | |
"""Return the length of the coding, use len(my_coding).""" | |
return len(self._data) | |
def __getitem__(self, arg): | |
"""Pull out child by index.""" | |
return self._data[arg] | |
def __iter__(self): | |
"""Iterate over the items.""" | |
return self | |
def __next__(self): | |
"""Return next item.""" | |
try: | |
return_coding = self._data[self._current_pos] | |
except IndexError: | |
self._current_pos = 0 | |
raise StopIteration from None | |
else: | |
self._current_pos += 1 | |
return return_coding | |
def raw(self): | |
"""Return the full coding as a python list.""" | |
return self._data | |
def __str__(self): | |
"""Return the full coding as a python string, use str(my_coding).""" | |
str_return = "" | |
for coding in self._data: | |
if coding["t"] == "multi": | |
str_return += "(" + "".join(coding["d"]) + ")" | |
elif coding["t"] == "uncer": | |
str_return += "{" + "".join(coding["d"]) + "}" | |
else: | |
str_return += coding["d"][0] | |
return str_return | |