allpy
changeset 852:077e5e18a600
Added allpy.markups.MarkupIOMixin to simplify new saveable markups creation. Switched existing saveable makrups to using it. Tested. (closes #82)
author | Daniil Alexeyevsky <dendik@kodomo.fbb.msu.ru> |
---|---|
date | Wed, 20 Jul 2011 20:44:59 +0400 |
parents | 2b74596f3c64 |
children | 6cc007e68af6 |
files | allpy/markups.py |
diffstat | 1 files changed, 61 insertions(+), 32 deletions(-) [+] |
line diff
1.1 --- a/allpy/markups.py Wed Jul 20 19:17:03 2011 +0400 1.2 +++ b/allpy/markups.py Wed Jul 20 20:44:59 2011 +0400 1.3 @@ -22,23 +22,61 @@ 1.4 assert fullname not in by_name, "Samenamed markup already exists!" 1.5 by_name[fullname] = markup_class 1.6 1.7 -class IntMarkupMixin(base.Markup): 1.8 +class MarkupIOMixin(base.Markup): 1.9 + """Standard helper mixin for creating saveable markups.""" 1.10 + 1.11 + separator = ',' 1.12 + """Separator to use when saving/loading markup.""" 1.13 + 1.14 + io_class = None 1.15 + """MUST be overloaded when subclassing. io_class in file.""" 1.16 + 1.17 + @staticmethod 1.18 + def parse_item(key, value): 1.19 + """Deserialize one item of markup. Overload when subclassing.""" 1.20 + return value 1.21 + 1.22 + @staticmethod 1.23 + def repr_item(key, value): 1.24 + """Serialize one item of markup. Overload when subclassing.""" 1.25 + return str(value) 1.26 1.27 @classmethod 1.28 def from_record(cls, container, record, name=None): 1.29 - assert record['io_class'] == 'IntMarkup' 1.30 + """Read markup from semi-parsed record from 'markup' file.""" 1.31 + assert record['io_class'] == cls.io_class 1.32 + separator = record.get('separator', cls.separator) 1.33 + values = record['markup'].split(separator) 1.34 result = container.add_markup(name, markup_class=cls) 1.35 - separator = record.get('separator', ',') 1.36 - values = record['markup'].split(separator) 1.37 assert len(values) == len(result.sorted_keys()) 1.38 for key, value in zip(result.sorted_keys(), values): 1.39 if value: 1.40 - result[key] = int(value) 1.41 + result[key] = cls.parse_item(key, value) 1.42 return result 1.43 1.44 def to_record(self): 1.45 - values = self.sorted_values(default='', map=str) 1.46 - return {'markup': ','.join(values), 'io_class': 'IntMarkup'} 1.47 + """Write markup to semi-serialized record for 'markup' file.""" 1.48 + values = [] 1.49 + for key in self.sorted_keys(): 1.50 + if key in self: 1.51 + values.append(self.repr_item(key, self[key])) 1.52 + else: 1.53 + values.append('') 1.54 + markup = self.separator.join(values) 1.55 + return { 1.56 + 'markup': markup, 1.57 + 'io_class': self.io_class, 1.58 + 'separator': self.separator, 1.59 + } 1.60 + 1.61 +class IntMarkupMixin(MarkupIOMixin): 1.62 + """Markup that has integer values.""" 1.63 + 1.64 + io_class = 'IntMarkup' 1.65 + 1.66 + @staticmethod 1.67 + def parse_item(key, value): 1.68 + return int(value) 1.69 1.70 class SequenceNumberMarkup(base.SequenceMarkup): 1.71 1.72 @@ -72,9 +110,10 @@ 1.73 for index, column in enumerate(self.alignment.columns): 1.74 self[column] = index 1.75 1.76 -class SequenceCaseMarkup(base.SequenceMarkup): 1.77 +class SequenceCaseMarkup(base.SequenceMarkup, MarkupIOMixin): 1.78 1.79 name = 'case' 1.80 + io_class = 'SequenceCaseMarkup' 1.81 1.82 def refresh(self): 1.83 for monomer in self.sequence: 1.84 @@ -83,31 +122,21 @@ 1.85 elif monomer.input_code1.islower(): 1.86 monomer.case = 'lower' 1.87 1.88 - @classmethod 1.89 - def from_record(cls, container, record, name=None): 1.90 - assert record['io_class'] == 'SequenceCaseMarkup' 1.91 - result = container.add_markup(name, markup_class=cls) 1.92 - markup = record['markup'] 1.93 - assert markup[0] == markup[-1] == "'" 1.94 - markup = markup[1:-1] 1.95 - assert len(markup) == len(result.sequence) 1.96 - for monomer, mark in zip(result.sequence, markup): 1.97 - assert monomer.code1 == mark.upper() 1.98 - if mark.isupper(): 1.99 - monomer.case = 'upper' 1.100 - if mark.islower(): 1.101 - monomer.case = 'lower' 1.102 - return result 1.103 + @staticmethod 1.104 + def parse_value(monomer, value): 1.105 + assert mnomer.code1 == value.upper() 1.106 + if value.isupper(): 1.107 + return 'upper' 1.108 + if value.islower(): 1.109 + return 'lower' 1.110 1.111 - def to_record(self): 1.112 - markup = '' 1.113 - for monomer in self.sequence: 1.114 - case = self.get(monomer) 1.115 - if case == 'upper': 1.116 - markup += monomer.code1.upper() 1.117 - elif case == 'lower': 1.118 - markup += monomer.code1.lower() 1.119 - return {'markup': "'%s'" % markup, 'io_class': 'SequenceCaseMarkup'} 1.120 + @staticmethod 1.121 + def repr_value(monomer, value): 1.122 + if monomer.case == 'upper': 1.123 + return monomer.code1.upper() 1.124 + if monomer.case == 'lower': 1.125 + return monomer.code1.lower() 1.126 + raise AssertionError("Unknown monomer case") 1.127 1.128 class SequencePdbResiMarkup(base.SequenceMarkup, IntMarkupMixin): 1.129 name = 'pdb_resi'