Spaces:
No application file
No application file
# Copyright 2012 by Wibowo Arindrarto. 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. | |
"""Common SearchIO utility functions.""" | |
def getattr_str(obj, attr, fmt=None, fallback="?"): | |
"""Return string of the given object's attribute. | |
Defaults to the given fallback value if attribute is not present. | |
""" | |
try: | |
value = getattr(obj, attr) | |
except AttributeError: | |
return fallback | |
if fmt is None: | |
return str(value) | |
return fmt % value | |
def read_forward(handle): | |
"""Read through whitespaces, return the first non-whitespace line.""" | |
while True: | |
line = handle.readline() | |
# if line is empty or line has characters and stripping does not remove | |
# them, return the line | |
if (not line) or (line and line.strip()): | |
return line | |
def get_processor(format, mapping): | |
"""Return the object to process the given format according to the mapping. | |
:param format: format name | |
:type format: string, lower case | |
:param mapping: mapping of format name and its processor object | |
:type mapping: dictionary {string: object} | |
""" | |
# map file format to iterator name | |
try: | |
obj_info = mapping[format] | |
except KeyError: | |
# handle the errors with helpful messages | |
if format is None: | |
raise ValueError("Format required (lower case string)") from None | |
elif not isinstance(format, str): | |
raise TypeError("Need a string for the file format (lower case)") from None | |
elif format != format.lower(): | |
raise ValueError("Format string %r should be lower case" % format) from None | |
else: | |
raise ValueError( | |
"Unknown format %r. Supported formats are %r" | |
% (format, "', '".join(mapping)) | |
) from None | |
mod_name, obj_name = obj_info | |
mod = __import__("Bio.SearchIO.%s" % mod_name, fromlist=[""]) | |
return getattr(mod, obj_name) | |
def singleitem(attr=None, doc=""): | |
"""Property for fetching attribute from first entry of container. | |
Returns a property that fetches the given attribute from | |
the first item in a SearchIO container object. | |
""" | |
def getter(self): | |
if len(self._items) > 1: | |
raise ValueError("More than one HSPFragment objects found in HSP") | |
if attr is None: | |
return self._items[0] | |
return getattr(self._items[0], attr) | |
return property(fget=getter, doc=doc) | |
def allitems(attr=None, doc=""): | |
"""Property for fetching attribute from all entries of container. | |
Returns a property that fetches the given attributes from | |
all items in a SearchIO container object. | |
""" | |
def getter(self): | |
if attr is None: | |
return self._items | |
return [getattr(frag, attr) for frag in self._items] | |
return property(fget=getter, doc=doc) | |
def fullcascade(attr, doc=""): | |
"""Return a getter property with a cascading setter. | |
This is similar to ``optionalcascade``, but for SearchIO containers that have | |
at least one item (HSP). The getter always retrieves the attribute | |
value from the first item. If the items have more than one attribute values, | |
an error will be raised. The setter behaves like ``partialcascade``, except | |
that it only sets attributes to items in the object, not the object itself. | |
""" | |
def getter(self): | |
return getattr(self._items[0], attr) | |
def setter(self, value): | |
for item in self: | |
setattr(item, attr, value) | |
return property(fget=getter, fset=setter, doc=doc) | |
def optionalcascade(cont_attr, item_attr, doc=""): | |
"""Return a getter property with a cascading setter. | |
This is used for the ``id`` and ``description`` properties of the container | |
objects with zero or more items. These items have their own private | |
attributes that stores query and/or hit ID and description. When the | |
container has zero items, attribute values are always retrieved from the | |
container's attribute. Otherwise, the first item's attribute is used. | |
To keep the container items' query and/or hit ID and description in-sync, | |
the setter cascades any new value given to the items' values. | |
""" | |
def getter(self): | |
if self._items: | |
# don't use self._items here, so QueryResult can use this property | |
# as well (the underlying dict is not integer-indexable) | |
return getattr(self[0], item_attr) | |
else: | |
return getattr(self, cont_attr) | |
def setter(self, value): | |
setattr(self, cont_attr, value) | |
for item in self: | |
setattr(item, item_attr, value) | |
return property(fget=getter, fset=setter, doc=doc) | |
def fragcascade(attr, seq_type, doc=""): | |
"""Return a getter property with cascading setter, for HSPFragment objects. | |
Similar to ``partialcascade``, but for HSPFragment objects and acts on ``query`` | |
or ``hit`` properties of the object if they are not None. | |
""" | |
assert seq_type in ("hit", "query") | |
attr_name = f"_{seq_type}_{attr}" | |
def getter(self): | |
return getattr(self, attr_name) | |
def setter(self, value): | |
setattr(self, attr_name, value) | |
seq = getattr(self, seq_type) | |
if seq is not None: | |
setattr(seq, attr, value) | |
return property(fget=getter, fset=setter, doc=doc) | |