class Watermark:
"""Watermark is a sequence that may contain sub-sequences
that match patterns."""
def __init__(self, watermark):
"""Initialize a Watermark instance.
'watermark'
value representing a watermark, typically a string.
"""
raise NotImplementedError("Watermark.__init__")
def pattern_start_indices(self, pattern_length):
"""Return range of start indices that may match
a pattern of length 'pattern_length'.
'pattern_length'
length of pattern, integer.
"""
raise NotImplementedError("Watermark.start_indices")
def decode_start_indices(self):
"""Return range of start indices where decoding can begin.
"""
raise NotImplementedError("Watermark.start_indices")
def values(self, start, count=None):
"""Return watermark values as a sequence.
'start'
start index, an element of range returned by
'pattern_start_indices' or 'decode_start_indices'.
'count'
number of values to return, integer.
'None' means all.
"""
raise NotImplementedError("Watermark.value")
class DNAWatermark(Watermark):
"""DNAWatermark is a DNA sequence where starting position
may be any base (thereby handling frame shifts) and values
are codons."""
def __init__(self, watermark):
self.watermark = watermark
def pattern_start_indices(self, pattern_length):
codon_length = pattern_length * 3
return range(0, len(self.watermark) - codon_length + 1)
def decode_start_indices(self):
return range(0, 3)
def values(self, start, count=None):
if count is None:
left = len(self.watermark) - start
end = start + left - (left % 3)
else:
end = start + count * 3
if end > len(self.watermark):
raise IndexError("watermark too short")
return [ self.watermark[i:i+3] for i in range(start, end, 3) ]
if __name__ == "__main__":
import unittest
class TestWatermark(unittest.TestCase):
def setUp(self):
self.w = DNAWatermark("abcdefghi")
def test_decode_indices(self):
indices = self.w.decode_start_indices()
self.assertEqual(len(indices), 3)
def test_decode(self):
self.assertEqual(len(self.w.values(0)), 3)
self.assertEqual(self.w.values(1), ["bcd", "efg"])
self.assertEqual(len(self.w.values(2)), 2)
unittest.main()