Skip to content

Commit

Permalink
rename BioSeq.get() and BioBasket.get() to getitem(), rename Feature.…
Browse files Browse the repository at this point in the history
…overlap() to overlaps(), more docs
  • Loading branch information
trichter committed Oct 22, 2024
1 parent 2c255bd commit e73e95a
Show file tree
Hide file tree
Showing 6 changed files with 229 additions and 47 deletions.
4 changes: 3 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ def download_logo():
.. _Infernal: http://eddylab.org/infernal/
.. _MMseqs2: https://github.com/soedinglab/MMseqs2
.. _Stockholm: https://en.wikipedia.org/wiki/Stockholm_format
.. _str: https://docs.python.org/3/library/stdtypes.html#string-methods
"""

extensions = ['sphinx.ext.autodoc',
Expand Down Expand Up @@ -94,5 +95,6 @@ def download_logo():


intersphinx_mapping = {
'python': ('https://docs.python.org/3/', None)
'python': ('https://docs.python.org/3/', None),
#'seaborn': ('https://seaborn.pydata.org/', None),
}
1 change: 0 additions & 1 deletion docs/src/sugar.core.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,3 @@ Submodules
:hidden:

sugar.core.*

85 changes: 76 additions & 9 deletions sugar/core/fts.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,6 @@
import sys
from enum import Flag, StrEnum, auto
from sugar.core.meta import Meta
# from .sequence import Sequence
# from ..copyable import Copyable
# from .seqtypes import NucleotideSequence


class Defect(Flag):
Expand Down Expand Up @@ -117,7 +114,7 @@ def __init__(self, start, stop, strand=Strand.FORWARD,
Inclusive ending base or residue position of the feature.
strand : Strand
The strand direction.
Always :attr:`Strand.FORWARD` for peptide features.
Always `Strand.FORWARD` for peptide features.
defect : Defect
A possible defect of the location.
"""
Expand Down Expand Up @@ -149,7 +146,10 @@ def __hash__(self):

@property
def stride(self):
return 1 if self.strand == Strand.FORWARD else -1
"""
Stride is -1 for the negative strand, else +1
"""
return -1 if self.strand == '-' else 1

def __len__(self):
return self.stop - self.start
Expand Down Expand Up @@ -179,6 +179,7 @@ def defect(self, v):


def _slice_locs(seq, locs, splitter=None, filler=None, gap=None):
# TODO document
# Concatenate subsequences for each location of the feature
strand = None
for loc in locs:
Expand All @@ -202,7 +203,7 @@ def _slice_locs(seq, locs, splitter=None, filler=None, gap=None):
# slice_start = loc.start - seq._seqstart
# slice_stop = loc.stop - seq._seqstart
# add_seq = seq[slice_start:slice_stop]
add_seq = seq.get(slice(loc.start, loc.stop), gap=gap)
add_seq = seq.getitem(slice(loc.start, loc.stop), gap=gap)
if loc.strand == '-':
add_seq = add_seq.reverse().complement()
if filler is not None and prev_loc is not None:
Expand Down Expand Up @@ -245,7 +246,7 @@ class Feature():
:param dict meta:
The metadata describing the feature.
..note::
.. note::
The following metadata attributes can be accessed directly as an
attribute of Feature: *type*, *name*, *id* and *seqid*.
For example the feature id can be obtained by both `Feature.id`
Expand All @@ -268,6 +269,9 @@ def __init__(self, type=None, locs=None, start=None, stop=None, meta=None):

@property
def type(self):
"""
Alias for ``Feature.meta.type``
"""
return self.meta.get('type')

@type.setter
Expand All @@ -276,6 +280,9 @@ def type(self, value):

@property
def id(self):
"""
Alias for ``Feature.meta.id``
"""
return self.meta.get('id')

@id.setter
Expand All @@ -284,6 +291,9 @@ def id(self, value):

@property
def seqid(self):
"""
Alias for ``Feature.meta.seqid``
"""
return self.meta.get('seqid')

@seqid.setter
Expand All @@ -292,6 +302,9 @@ def seqid(self, value):

@property
def name(self):
"""
Alias for ``Feature.meta.name``
"""
return self.meta.get('name')

@name.setter
Expand Down Expand Up @@ -328,6 +341,9 @@ def _slice(self): # needs to return list of slices

@property
def loc(self):
"""
Access first location
"""
l, *_ = self.locs
return l

Expand Down Expand Up @@ -375,7 +391,10 @@ def __len__(self):
lr = self.loc_range
return lr[1] - lr[0]

def overlap(self, other):
def overlaps(self, other):
"""
Weather the location ranges overlaps with other feature
"""
if not isinstance(other, Feature):
raise NotImplementedError()
lr1 = self.loc_range
Expand All @@ -390,6 +409,11 @@ def __sub__(self, other):
return (sum(lr1) - sum(lr2)) // 2

def reverse(self):
"""
Reverse the feature.
After the operation the feature will be located on the reverse complement strand.
"""
ft = self
for loc in ft.locs:
loc.start, loc.stop = -loc.stop, -loc.start
Expand All @@ -413,7 +437,7 @@ def write(self, *args, **kw):
class FeatureList(collections.UserList):
def __init__(self, data=None):
"""
A `FeatureList` is a set of features belonging to one sequence.
A `FeatureList` is a set of features belonging to one or several sequences.
Its advantage over a simple list is the base/residue position based
indexing:
Expand Down Expand Up @@ -504,6 +528,9 @@ def _repr_pretty_(self, p, cycle):
p.text(str(self))

def tostr(self, raw=False, w=80, wt=12, wl=20, h=80, exclude_fts=()):
"""
Return string with information about features, used by ``__str__()`` method
"""
def _sort_meta_key(m):
order = ['name', 'gene']
try:
Expand Down Expand Up @@ -561,11 +588,19 @@ def _sort_meta_key(m):
return '\n'.join(out)

def tofmtstr(self, fmt, **kw):
"""
Write features to a string of specified format, see `~.main.write_fts()`
"""
out = io.StringIO()
self.write(out, fmt=fmt, **kw)
return out.getvalue()

def get(self, type):
"""
Return the first feature of specified feature type, e.g. ``'cds'``
:param type: String or list of multiple strings
"""
type_ = type
if isinstance(type_, tuple):
type_ = tuple(t.lower() for t in type_)
Expand All @@ -575,6 +610,11 @@ def get(self, type):
return ft

def select(self, type):
"""
Return new `featureList` with all features of specified feature type, e.g. ``'cds'``
:param type: String or list of multiple strings
"""
type_ = type
if isinstance(type_, tuple):
type_ = tuple(t.lower() for t in type_)
Expand All @@ -586,6 +626,9 @@ def select(self, type):
return FeatureList(fts)

def todict(self):
"""
Return a dictionary with sequence ids as keys and FeatureLists as values
"""
d = {}
for ft in self:
seqid = ft.meta.get('seqid', '')
Expand All @@ -594,6 +637,9 @@ def todict(self):

@property
def d(self):
"""
Alias for `FeatureList.todict()`
"""
return self.todict()

@property
Expand Down Expand Up @@ -629,6 +675,9 @@ def write(self, fname, fmt=None, **kw):


def slice(self, start, stop):
"""
Return a sub-annotation between start and stop
"""
if start is None:
i_start = -sys.maxsize
else:
Expand Down Expand Up @@ -670,11 +719,26 @@ def slice(self, start, stop):
return sub_annot

def reverse(self):
"""
Reverse all features, see `Feature.reverse()`
:return: Reversed features
"""
for ft in self:
ft.reverse()
return self

def sort(self, key=None, reverse=False):
"""
Sort features in-place
:param key: Key to use for sorting.
Should be a string, which is expected to be a valid attribute in the metadata of each feature.
Alternatively, the key sort function can be specified directly.
:param reverse: Use reversed order (default: False)
:return: Sorted features
"""
if key is not None and isinstance(key, str):
kfunc = lambda ft: ft.meta[key]
else:
Expand All @@ -683,6 +747,9 @@ def sort(self, key=None, reverse=False):
return self

def copy(self):
"""
Return a deep copy of the object
"""
return deepcopy(self)


Expand Down
5 changes: 5 additions & 0 deletions sugar/core/meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,11 @@ def __getattr__(self, name):
__delattr__ = __delitem__

def copy(self):
"""Return a deep copy of the object"""
return copy.deepcopy(self)

def update(self, adict={}):
"""Update from other mapping or iterable"""
for (key, value) in adict.items():
self.__setitem__(key, value)

Expand All @@ -93,6 +95,9 @@ def _repr_pretty_(self, p, cycle):
p.text(str(self))

def tostr(self, w=80):
"""
Return string describing the metadata, is used by ``__str__()`` method.
"""
def _key2str():
line = f'{k:>{lenkey}}: {self[k]}'
if len(line) > w:
Expand Down
Loading

0 comments on commit e73e95a

Please sign in to comment.