diff --git a/source/Architecture_and_design.rst b/source/Architecture_and_design.rst new file mode 100644 index 0000000000000000000000000000000000000000..25c6d822148fdd4028e2bcdc1ff3e5a868b43768 --- /dev/null +++ b/source/Architecture_and_design.rst @@ -0,0 +1,73 @@ +.. sectnum:: + :start: 14 + + +.. _Architecture_and_Design: + +*********************** +Architecture and Design +*********************** + + +Exercises +========= + +Exercise +-------- + +Create 2 classes + + * Sequence + * MutableSequence + +These 2 classes have same attributes but Sequence can be mutate and extend whereas Sequence are immutable. + +example of code using these classes: :: + + >>> eco = Sequence('toto' , 'GAATTC') + >>> eco.mutate(1, 'T') + >>> eco.sequence + 'GTATTC' + >>> eco.mutate(10, 'T') + Traceback (most recent call last): + File "<stdin>", line 1, in <module> + File "mutableSequence.py", line 97, in mutate + raise ValueError("pos must be >0 and < {}".format(len(self._sequence))) + ValueError: pos must be >0 and < 6 + + +Exercise +-------- + +how can you modeling + + * non mutable DNA sequence + * mutable DNA sequence + * non mutable amino acid sequence + * mutable amino acid sequence + + can you easily extend your model to support no mutable/ mutable RNA sequence ? + + +.. literalinclude:: _static/code/multi_inheritance.py + :linenos: + :language: python + +:download:`multi_inheritance.py <_static/code/multi_inheritance.py>` + +Exercise +-------- + +work with in small groups (2-3 people). +To solve a problem we need to design + + * genome + * gene + * sequence + +in context in eukaryote and prokaryote. propose an architecture. you hav not to implement methods just +do a schema of the components and the relations between the components. + + .. note:: + you can add objects not listed above if you need for your architecture. + diff --git a/source/_static/code/multi_inheritance.py b/source/_static/code/multi_inheritance.py new file mode 100644 index 0000000000000000000000000000000000000000..bf1460caf8889e1fb4ec925fd5843d02235dcd3c --- /dev/null +++ b/source/_static/code/multi_inheritance.py @@ -0,0 +1,145 @@ +from abc import ABCMeta, abstractmethod + + +class BaseSequence(object, metaclass=ABCMeta): + + _water = 18.0153 + + def __init__(self, name, seq): + """ + :param seq: the sequence + :type seq: string + """ + self.name = name + self._sequence = seq + + @property + def alphabet(self): + return self._alphabet + + @property + def sequence(self): + return self._sequence + + + def __len__(self): + """ + :return: the length of this sequence (number of bases or aa) + :rtype: integer + """ + return len(self._sequence) + + + def to_fasta(self): + """ + :return: a string in fasta format of this sequence + :rtype: basestring + """ + id_ = self.name.replace(' ', '_') + fasta = '>{}\n'.format(id_) + start = 0 + while start < len(self._sequence): + end = start + 80 + fasta += self._sequence[start: end + 1] + '\n' + start = end + return fasta + + + def _one_strand_molec_weight(self, seq): + """ + helper function to compute the mw of the seq + :param seq: the seq (nucleic or proteic) to compute the mw + :type seq: string + :return: mw of seq + :rtype: float + """ + return sum([self._weight_table[base] for base in seq]) - (len(seq) - 1) * self._water + + + @abstractmethod + def molecular_weight(self): + """ + tihis method is abstract and must be implemented in child classes + :return: The molecular weight + :rtype: float + """ + pass + + +class Mutable(object): + + + def mutate(self, pos, base): + """ + mutate the sequence replace the base at pos with base + :param pos: the position of the base to mutate (starting count = 0) + :type pos: integer + :param base: the base to replace with it must be a char belonging to the alphabet + :type base: string (one char) + :return: + """ + if base not in self._alphabet: + raise ValueError("base must be {}".format(', '.join(["'{}'".format(c) for c in self._alphabet]))) + if pos < 0 or pos > len(self._sequence): + raise ValueError("pos must be > 0 and < {}".format(len(self._sequence))) + head = self._sequence[0:pos] + tail = self._sequence[pos+1:] + self._sequence = head + base + tail + + +class NonMutableDNASequence(BaseSequence): + + _weight_table = {'A': 347.2212, 'C': 323.1965, 'G': 363.2206, 'T': 322.2085} + _alphabet = 'ACGT' + + def molecular_weight(self): + """ + :return: The molecular weight + :rtype: float + """ + direct_weight = self._one_strand_molec_weight(self._sequence) + rev_comp = self.rev_comp() + rev_comp_weight = self._one_strand_molec_weight(rev_comp.sequence) + return direct_weight + rev_comp_weight + + + def rev_comp(self): + """ + :return: a new sequence representing the reverse complement + :rtype: :class:`Sequence` object + """ + rev = self.sequence[::-1] + table = str.maketrans(self._alphabet, self._alphabet[::-1]) + rev_comp = str.translate(rev, table) + return self.__class__(self.name + '_reverse', rev_comp) + + +class MutableDNASequence(NonMutableDNASequence, Mutable): + + pass + + +class NonMutableAASequence(BaseSequence): + + _weight_table = {'A': 89.0932, 'C': 121.1582, 'E': 147.1293, + 'D': 133.1027, 'G': 75.0666, 'F': 165.1891, + 'I': 131.1729, 'H': 155.1546, 'K': 146.1876, + 'M': 149.2113, 'L': 131.1729, 'O': 255.3134, + 'N': 132.1179, 'Q': 146.1445, 'P': 115.1305, + 'S': 105.0926, 'R': 174.201, 'U': 168.0532, + 'T': 119.1192, 'W': 204.2252, 'V': 117.1463, + 'Y': 181.1885} + + _alphabet = ''.join(_weight_table.keys()) + + def molecular_weight(self): + """ + :return: The molecular weight + :rtype: float + """ + return super()._one_strand_molec_weight(self.sequence) + + +class MutableAASequence(NonMutableAASequence, Mutable): + + pass \ No newline at end of file diff --git a/source/_static/code/mutableSequence.py b/source/_static/code/mutableSequence.py new file mode 100644 index 0000000000000000000000000000000000000000..cf50080ff20126616aa54cf40ca5575ebaf4a20b --- /dev/null +++ b/source/_static/code/mutableSequence.py @@ -0,0 +1,100 @@ + + + +class NonMutableSequence(object): + + _water = 18.0153 + _alphabet = 'ACGT' + + def __init__(self, name, seq): + """ + :param seq: the sequence + :type seq: string + """ + self.name = name + self._sequence = seq + + @property + def alphabet(self): + return self._alphabet + + @property + def sequence(self): + return self._sequence + + + def __len__(self): + """ + :return: the length of this sequence (number of bases or aa) + :rtype: integer + """ + return len(self._sequence) + + + def to_fasta(self): + """ + :return: a string in fasta format of this sequence + :rtype: basestring + """ + id_ = self.name.replace(' ', '_') + fasta = '>{}\n'.format(id_) + start = 0 + while start < len(self._sequence): + end = start + 80 + fasta += self._sequence[start: end + 1] + '\n' + start = end + return fasta + + + def _one_strand_molec_weight(self, seq): + """ + helper function to compute the mw of the seq + :param seq: the seq (nucleic or proteic) to compute the mw + :type seq: string + :return: mw of seq + :rtype: float + """ + return sum([self._weight_table[base] for base in seq]) - (len(seq) - 1) * self._water + + + def molecular_weight(self): + """ + :return: The molecular weight + :rtype: float + """ + direct_weight = self._one_strand_molec_weight(self._sequence) + rev_comp = self.rev_comp() + rev_comp_weight = self._one_strand_molec_weight(rev_comp.sequence) + return direct_weight + rev_comp_weight + + + def rev_comp(self): + """ + :return: a new sequence representing the reverse complement + :rtype: :class:`Sequence` object + """ + rev = self.sequence[::-1] + table = str.maketrans(self._alphabet, self._alphabet[::-1]) + rev_comp = str.translate(rev, table) + return self.__class__(self.name + '_reverse', rev_comp) + + +class Sequence(NonMutableSequence): + + + def mutate(self, pos, base): + """ + mutate the sequence replace the base at pos with base + :param pos: the position of the base to mutate (starting count = 0) + :type pos: integer + :param base: the base to replace with it must be a char belonging to the alphabet + :type base: string (one char) + :return: + """ + if base not in self._alphabet: + raise ValueError("base must be {}".format(', '.join(["'{}'".format(c) for c in self._alphabet]))) + if pos < 0 or pos > len(self._sequence): + raise ValueError("pos must be > 0 and < {}".format(len(self._sequence))) + head = self._sequence[0:pos] + tail = self._sequence[pos+1:] + self._sequence = head + base + tail \ No newline at end of file