Документ взят из кэша поисковой машины. Адрес оригинального документа : http://kodomo.fbb.msu.ru/hg/allpy/diff/d87129162eb4/allpy/base.py
Дата изменения: Unknown
Дата индексирования: Sun Feb 3 22:29:42 2013
Кодировка:
allpy: allpy/base.py diff

allpy

diff allpy/base.py @ 822:d87129162eb4

Implemented & tested new markup API. See #95 1) Sequences, Alignment and Blocks now have two new methods: - add_markup(name, markup_class=optional, **kwargs=optional) - remove_markup(name) name refers to the same name as in aln.markups[name] or sequence[i].name It is now explicitly denied to create markups any other way. 2) Markups now have `remove()` method that means 'release all memory that would not be released otherwised, if we just remove markup from the dictionary'. For sequences markups it removes markup attribute from each monomer. 3) Added necessary del sequence_markup[monomer] method. 4) Many base classes have attribute `kind`; for Alignments and Blocks it is 'alignment', for Sequences it is 'sequence' for AlignmentMarkups it is 'alignment_markup' for SequenceMarkups it is 'sequence_markup'. This attribute is crucial for new alignment construction API. 5) Common stuff for MarkupContainers (Alignments and Sequences) is in MarkupContainerMixin.
author Daniil Alexeyevsky <dendik@kodomo.fbb.msu.ru>
date Fri, 15 Jul 2011 16:43:03 +0400
parents 91e73fb1ac79
children 0192c5c09ce8
line diff
     1.1 --- a/allpy/base.py	Fri Jul 15 13:57:56 2011 +0400
     1.2 +++ b/allpy/base.py	Fri Jul 15 16:43:03 2011 +0400
     1.3 @@ -101,7 +101,43 @@
     1.4      def __ne__(self, other):
     1.5          return not (self == other)
     1.6  
     1.7 -class Sequence(list):
     1.8 +class MarkupContainerMixin(object):
     1.9 +    """Common functions for alignment and sequence for dealing with markups.
    1.10 +    """
    1.11 +
    1.12 +    def _init(self):
    1.13 +        """Hook to be called from __init__ of actual class."""
    1.14 +        self.markups = {}
    1.15 +
    1.16 +    def add_markup(self, name, markup_class=None, **markup_kwargs):
    1.17 +        """Create a markup object, add to self. Return the created markup.
    1.18 +
    1.19 +        - `name` is name for markup in `self.markups` dictionary
    1.20 +        - optional `markup_class` is class for created markup
    1.21 +        - optional keyword arguments are passed on to the markup constructor
    1.22 +
    1.23 +        For user markups you have to specify `name` and `markup_class`,
    1.24 +        for the standard automatical markups just `name` is enough.
    1.25 +        """
    1.26 +        # We have to import markups here, and not in the module header
    1.27 +        # so as not to create bad import loops.
    1.28 +        # `base` module is used extensively in `markups` for inherinance,
    1.29 +        # so breaking the loop here seems a lot easier.
    1.30 +        import markups
    1.31 +        if markup_class is None:
    1.32 +            kind = self.kind + "_" + "markup"
    1.33 +            markup_class = markups.by_name[kind, name]
    1.34 +        assert name not in self.markups
    1.35 +        markup = markup_class(self, name, caller='container', **markup_kwargs)
    1.36 +        self.markups[name] = markup
    1.37 +        return markup
    1.38 +
    1.39 +    def remove_markup(self, name):
    1.40 +        """Remove markup."""
    1.41 +        self.markups[name].remove()
    1.42 +        del self.markups[name]
    1.43 +
    1.44 +class Sequence(list, MarkupContainerMixin):
    1.45      """Sequence of Monomers.
    1.46  
    1.47      This behaves like list of monomer objects. In addition to standard list
    1.48 @@ -117,13 +153,16 @@
    1.49      types = base
    1.50      """Mapping of related types. SHOULD be redefined in subclasses."""
    1.51  
    1.52 +    kind = 'sequence'
    1.53 +    """Description of object kind."""
    1.54 +
    1.55      name = ''
    1.56      description = ''
    1.57      source = ''
    1.58  
    1.59      def __init__(self, *args):
    1.60 -        self.markups = {}
    1.61          list.__init__(self, *args)
    1.62 +        MarkupContainerMixin._init(self)
    1.63  
    1.64      @classmethod
    1.65      def from_monomers(cls, monomers=[], name=None, description=None, source=None):
    1.66 @@ -158,7 +197,7 @@
    1.67          """Hash sequence by identity."""
    1.68          return id(self)
    1.69  
    1.70 -class Alignment(object):
    1.71 +class Alignment(MarkupContainerMixin):
    1.72      """Alignment. It is a list of Columns."""
    1.73  
    1.74      types = base
    1.75 @@ -167,11 +206,14 @@
    1.76      sequences = None
    1.77      """Ordered list of sequences in alignment. Read, but DO NOT FIDDLE!"""
    1.78  
    1.79 +    kind = 'alignment'
    1.80 +    """Description of object kind."""
    1.81 +
    1.82      def __init__(self):
    1.83          """Initialize empty alignment."""
    1.84          self.sequences = []
    1.85          self.columns = []
    1.86 -        self.markups = {}
    1.87 +        MarkupContainerMixin._init(self)
    1.88  
    1.89      # Alignment grow & IO methods
    1.90      # ==============================
    1.91 @@ -507,22 +549,24 @@
    1.92      name = None
    1.93      """Name of markup elements"""
    1.94  
    1.95 -    def _register(self, container, name):
    1.96 -        """Register self within container.
    1.97 +    def __init__(self, container, name, **kwargs):
    1.98 +        """Markup takes mandatory container and name and optional kwargs.
    1.99  
   1.100 -        Assure the name is not taken before. If name is not given, look in the
   1.101 -        class. Make sure we have some name at all.
   1.102 +        Markups should never be created by the user. They are created by
   1.103 +        Sequence or Alignment.
   1.104          """
   1.105 -        if name:
   1.106 -            self.name = name
   1.107 -        assert self.name is not None
   1.108 -        assert self.name not in container.markups
   1.109 -        container.markups[self.name] = self
   1.110 +        self.name = name
   1.111 +        assert kwargs.get('caller') == 'container', "Improper call"
   1.112 +        self.refresh()
   1.113  
   1.114      def refresh(self):
   1.115          """Recalculate markup values (if they are generated automatically)."""
   1.116          pass
   1.117  
   1.118 +    def remove(self):
   1.119 +        """Remove the traces of markup object. Do not call this yourself!"""
   1.120 +        pass
   1.121 +
   1.122      @classmethod
   1.123      def from_record(cls, container, record, name=None):
   1.124          """Restore markup from `record`. (Used for loading from file).
   1.125 @@ -533,7 +577,7 @@
   1.126          Markup values should be stored in `record['markup']`, which is a list
   1.127          of items separated with either `record['separator']` or a comma.
   1.128          """
   1.129 -        return cls(container, name)
   1.130 +        return container.add_markup(name, markup_class=cls)
   1.131  
   1.132      def to_record(self):
   1.133          """Save markup to `record`, for saving to file.
   1.134 @@ -561,10 +605,14 @@
   1.135  
   1.136      kind = 'sequence_markup'
   1.137  
   1.138 -    def __init__(self, sequence, name=None):
   1.139 +    def __init__(self, sequence, name, **kwargs):
   1.140          self.sequence = sequence
   1.141 -        self._register(sequence, name)
   1.142 -        self.refresh()
   1.143 +        Markup.__init__(self, sequence, name, **kwargs)
   1.144 +
   1.145 +    def remove(self):
   1.146 +        """Remove the traces of markup object. Do not call this yourself!"""
   1.147 +        for monomer in self.monomers:
   1.148 +            del self[monomer]
   1.149  
   1.150      def sorted_keys(self):
   1.151          """Return list of monomers."""
   1.152 @@ -592,6 +640,10 @@
   1.153          """Part of Mapping collection interface."""
   1.154          return setattr(monomer, self.name, value)
   1.155  
   1.156 +    def __delitem__(self, monomer):
   1.157 +        """Part of Mapping collection interface."""
   1.158 +        return delattr(monomer, self.name)
   1.159 +
   1.160  class AlignmentMarkup(dict, Markup):
   1.161      """Markupf for alignment.
   1.162  
   1.163 @@ -601,10 +653,9 @@
   1.164  
   1.165      kind = 'alignment_markup'
   1.166  
   1.167 -    def __init__(self, alignment, name=None):
   1.168 +    def __init__(self, alignment, name, **kwargs):
   1.169          self.alignment = alignment
   1.170 -        self._register(alignment, name)
   1.171 -        self.refresh()
   1.172 +        Markup.__init__(self, alignment, name, **kwargs)
   1.173  
   1.174      def sorted_keys(self):
   1.175          """Return a list of columns."""