diff --git a/HW4_Toropov/protein_tools.py b/HW4_Toropov/protein_tools.py
new file mode 100644
index 0000000..50b670f
--- /dev/null
+++ b/HW4_Toropov/protein_tools.py
@@ -0,0 +1,336 @@
+alphabet_protein = {
+ "A",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "K",
+ "L",
+ "M",
+ "N",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "V",
+ "W",
+ "Y",
+}
+
+alphabet_rna = {"A", "U", "G", "C"}
+
+amino_acid_masses = {
+ "A": 71.03711,
+ "R": 156.10111,
+ "N": 114.04293,
+ "D": 115.02694,
+ "C": 103.00919,
+ "Q": 128.05858,
+ "E": 129.04259,
+ "G": 57.02146,
+ "H": 137.05891,
+ "I": 113.08406,
+ "L": 113.08406,
+ "K": 128.09496,
+ "M": 131.04049,
+ "F": 147.06841,
+ "P": 97.05276,
+ "S": 87.03203,
+ "T": 101.04768,
+ "W": 186.07931,
+ "Y": 163.06333,
+ "V": 99.06841,
+}
+
+gydrophobic_aminoacids = {"A", "V", "L", "I", "P", "F", "W", "M"}
+
+dna_codons = {
+ "A": ["GCT", "GCC", "GCA", "GCG"],
+ "C": ["TGT", "TGC"],
+ "D": ["GAT", "GAC"],
+ "E": ["GAA", "GAG"],
+ "F": ["TTT", "TTC"],
+ "G": ["GGT", "GGC", "GGA", "GGG"],
+ "H": ["CAT", "CAC"],
+ "I": ["ATT", "ATC", "ATA"],
+ "K": ["AAA", "AAG"],
+ "L": ["TTA", "TTG", "CTT", "CTC", "CTA", "CTG"],
+ "M": ["ATG"],
+ "N": ["AAT", "AAC"],
+ "P": ["CCT", "CCC", "CCA", "CCG"],
+ "Q": ["CAA", "CAG"],
+ "R": ["CGT", "CGC", "CGA", "CGG", "AGA", "AGG"],
+ "S": ["TCT", "TCC", "TCA", "TCG", "AGT", "AGC"],
+ "T": ["ACT", "ACC", "ACA", "ACG"],
+ "V": ["GTT", "GTC", "GTA", "GTG"],
+ "W": ["TGG"],
+ "Y": ["TAT", "TAC"],
+ "*": ["UAA", "UAG", "UGA"],
+}
+
+rna_codons = {
+ "F": ["UUC", "UUU"],
+ "L": ["UUA", "UUG", "CUU", "CUC", "CUA", "CUG"],
+ "I": ["AUU", "AUC", "AUA"],
+ "M": ["AUG"],
+ "V": ["GUU", "GUC", "GUA", "GUG"],
+ "S": ["UCU", "UCC", "UCA", "UCG"],
+ "P": ["CCU", "CCC", "CCA", "CCG"],
+ "T": ["ACU", "ACC", "ACA", "ACG"],
+ "A": ["GCU", "GCC", "GCA", "GCG"],
+ "Y": ["UAC", "UAU"],
+ "*": ["UAA", "UAG", "UGA"],
+ "H": ["CAU", "CAC"],
+ "Q": ["CAA", "CAG"],
+ "N": ["AAU", "AAC"],
+ "K": ["AAA", "AAG"],
+ "D": ["GAU", "GAC"],
+ "E": ["GAA", "GAG"],
+ "C": ["UGU", "UGC"],
+ "W": ["UGG"],
+ "R": ["CGU", "CGC", "CGA", "CGG", "AGA", "AGG"],
+ "S": ["AGU", "AGC"],
+ "G": ["GGU", "GGC", "GGA", "GGG"],
+}
+
+
+def is_protein(seq: str):
+ """
+ Check the existence of a protein sequence, return boolean.
+ """
+ unique_chars = set(seq.upper())
+ return unique_chars <= alphabet_protein
+
+
+def is_rna(seq: str):
+ """
+ Check the existence of a RNA sequence, return boolean.
+ """
+ unique_chars = set(seq.upper())
+ return unique_chars <= alphabet_rna
+
+
+def compute_molecular_weight(protein: str) -> tuple:
+ """
+ Compute molecular weight (g/mol) of protein sequence.
+
+ Argument:
+ - protein (str): protein sequence.
+
+ Return:
+ - tuple with protein sequence and computed molecular
+ weight (float rounded to 3 decimal places).
+ """
+ molecular_weight = 0
+ for amino_acid in protein.upper():
+ molecular_weight += amino_acid_masses[amino_acid]
+ return protein, round(molecular_weight, 3)
+
+
+def compute_length(protein: str) -> tuple:
+ """
+ Compute the length of the input protein sequence.
+
+ Argument:
+ - protein (str): protein sequence.
+
+ Return:
+ - tuple with protein sequence and computed length.
+ """
+ return protein, len(protein)
+
+
+def protein_to_dna(protein: str) -> str:
+ """
+ Returns possible variants of DNAs for a given protein sequence.
+
+ Argument:
+ - protein (str): protein sequence.
+
+ Return:
+ - string, variants of nucleic acids.
+ If several codons correspond to a given amino acid they are displayed with a '/'.
+
+ Does not distinguish between lowercase and uppercase letters.
+
+ Examples:
+
+ -'MACDRS' -> 'ATG GCT/GCC/GCA/GCG TGT/TGC GAT/GAC CGT/CGC/CGA/CGG/AGA/AGG TCT/TCC/TCA/TCG/AGT/AGC'
+ -'MaCdrS' -> 'ATG GCT/GCC/GCA/GCG TGT/TGC GAT/GAC CGT/CGC/CGA/CGG/AGA/AGG TCT/TCC/TCA/TCG/AGT/AGC'
+ """
+ nucleic_acid_seq = ""
+
+ for aa in protein.upper():
+ codons = dna_codons.get(aa)
+ nucleic_acid_seq += "/".join(codons) + " "
+
+ return nucleic_acid_seq[:-1]
+
+
+def count_amino_acids(protein: str) -> dict:
+ """
+ Calculates the number of each aminoacid in a given protein sequence.
+
+ Argument:
+ - protein (str): protein sequence.
+
+ Return:
+ - dictionary, where a key is the aminoacid letter and value is number of this aminoacid.
+
+ Does not distinguish between lowercase and uppercase letters.
+
+ Examples:
+
+ -'MACDRS' -> {'M': 1, 'A': 1, 'C': 1, 'D': 1, 'R': 1, 'S': 1}
+ -'MaCdrS' -> {'M': 1, 'A': 1, 'C': 1, 'D': 1, 'R': 1, 'S': 1}
+ """
+ amino_acids_dict = {}
+ for aa in protein.upper():
+ if aa in amino_acids_dict:
+ amino_acids_dict[aa] += 1
+ else:
+ amino_acids_dict[aa] = 1
+ return amino_acids_dict
+
+
+def compute_hydrophobicity(protein: str) -> tuple:
+ """
+ Compute the percentage of gydrophobic aminoacids in protein sequence.
+
+ Argument:
+ - protein (str): protein sequence. Includes hydrophobic
+ and hydrophilic aminoacids.
+
+ Return:
+ - tuple with protein sequence and computed percentage
+ of gydrophobic aminoacids.
+ """
+ count_of_gydrophobic = 0
+ for i in range(len(protein)):
+ if protein[i] in gydrophobic_aminoacids:
+ count_of_gydrophobic += 1
+
+ percentage = round(count_of_gydrophobic / len(protein) * 100, 3)
+
+ return protein, percentage
+
+
+def translate_rna(rna: str) -> str:
+ """
+ Perform the translation of mRNA seguence into protein sequence.
+
+ Argument:
+ - rna (str): mRNA sequence. Must contain start-codon and one of
+ the stop-codons.
+
+ Return:
+ - str, protein sequence after translation.
+ Always starts with "M" and ends with "*".
+ """
+ triplets = [rna[i : i + 3].upper() for i in range(0, len(rna), 3)]
+ protein = []
+ for triplet in triplets:
+ for aminoacid in rna_codons.keys():
+ if triplet in rna_codons[aminoacid]:
+ protein.append(aminoacid)
+
+ if protein[-1] != "*":
+ raise ValueError("Stop-codon (*) is absent in mRNA")
+ if protein[0] != "M":
+ raise ValueError("Start-codon (M) is absent in mRNA")
+
+ start = protein.index("M")
+ stop = protein.index("*")
+ return "".join(protein[start : stop + 1])
+
+
+def check_mutations(rna: str, protein: str) -> str:
+ """
+ Check missense mutations in the protein sequence after translation.
+
+ Uses additional function "translate_rna(seq)".
+
+ Arguments:
+ - rna (str): sequence of mRNA with/without mutations.
+ Must contain start-codon and one of the stop-codons.
+ - protein (str): protein sequence translated from mRNA.
+ Must start with "M" and ends with "*" (stop-codon).
+
+ Note: is_protein(seq) doesn't see "*", but it's used in the other part of function.
+
+ Return:
+ - str, if mRNA without mutations return "Protein without mutations."
+ If there are mutations in protein, returns aminoacid(s) and their position(s)
+
+ Examples:
+ - "AUGGUAGGGAAAUUUUGA", "MVGKF*" -> "Protein without mutations."
+ - "AUGGUAGGGAAAUUUUGA", "MGGVF*" -> "Mutations:G2, V4."
+ - "AUGGUAGGGAAAUUUUGA", "MGGKF" –> "ValueError: Stop (*) is absent"
+ - "AUGGUAGGGAAAUUUUGA", "GGKF*" –> "ValueError: Start (M) is absent"
+ - "AUGAAAAAAUGA", "MK*" -> "ValueError: Different length of translated protein and protein"
+ """
+ correct_protein = translate_rna(rna)
+ bank_of_mutations = []
+
+ if is_protein(protein[:-1]) is not True:
+ raise ValueError("Invalid protein sequence")
+ if is_rna(rna) is not True:
+ raise ValueError("Invalid RNA sequence")
+ if protein[-1] != "*":
+ raise ValueError("Stop (*) is absent")
+ if protein[0] != "M":
+ raise ValueError("Start (M) is absent")
+ if len(protein) != len(rna) / 3:
+ raise ValueError("Different length of translated protein and protein")
+
+ for i in range(len(correct_protein)):
+ if correct_protein[i] != protein[i]:
+ bank_of_mutations.append(f"{protein[i]}{i + 1}")
+
+ if len(bank_of_mutations) == 0:
+ return "Protein without mutations."
+ else:
+ return "Mutations: " + ", ".join(bank_of_mutations) + "."
+
+
+def run_protein_tools(*args: str):
+ """
+ Function containing methods for protein analysis.
+
+ Takes arbitrary number of arguments with protein sequencies
+ and the name of the procedure to be performed (always the last
+ argument). Returns the result of the procedure as string, tuple
+ or dictionary if one sequnce is submitted or list if several.
+
+ Note: if procedure 'check_mutations' is used then input must
+ contain only three arguments: RNA sequence, protein sequence
+ and the name of procedure itself.
+ """
+ *seqs, procedure = args
+ results = []
+ d_of_functions = {
+ "compute_molecular_weight": compute_molecular_weight,
+ "compute_length": compute_length,
+ "compute_hydrophobicity": compute_hydrophobicity,
+ "count_amino_acids": count_amino_acids,
+ "protein_to_dna": protein_to_dna
+
+ }
+ if procedure == "check_mutations":
+ results.append(check_mutations(seqs[0], seqs[1]))
+ else:
+ for seq in seqs:
+ if is_protein(seq) is not True:
+ raise ValueError("Invalid protein sequence")
+ if procedure not in d_of_functions:
+ raise ValueError("Wrong procedure name")
+ else:
+ results.append(d_of_functions[procedure](seq))
+ if len(results) == 1:
+ return results[0]
+ else:
+ return results
diff --git a/README.md b/README.md
index f918170..734790f 100644
--- a/README.md
+++ b/README.md
@@ -1,65 +1,66 @@
-# HW 4. Functions 2
-> *This is the repo for the fourth homework of the BI Python 2023 course*
-
-### Homework description
-
-На прошлой неделе вы делали утилиту для работы с последовательностями нуклеиновых кислот (с весьма строгим ТЗ). Пришло время для чего-то более самостоятельного.
-
-#### Основное задание
-
-
-Напишите утилиту для работы с последовательностями белков. Там должно быть минимум 5 различных операций, должна быть какая-то точка входа через которую пользователь будет всё это дело использовать. На этом, по сути, всё. Всё целиком зависит от вашей фантазии и креативности. Можете опираться на ДЗ №2 и №3.
-
-Самая главная часть задания - это файл `README.md`. Сделайте краткое введение, напишите описание тула, приведите документацию по использованию со списком аргументов. Добавьте примеры использования. Возможно, вы захотите сделать секцию Troubleshooting. ***Почему это нужно?*** В этот раз проверяющий не будет знать того, как должен работать ваш тул. Это ваш авторский код. Даже самая прекрасная функциональность, не будучи отраженной в README, скорее всего останется незамеченной. README - это ваш способ познакомить пользователя с тулом, показать всё лучше и обосновать, почему именно ваша команда должна получить наивысший балл.
-
-Есть люди которые, любят писать документации, а есть те - кто не любит. Найдите в вашей команде того, кто любит. И в будущем в своих рабочих проектах всегда держите рядом такого человек (или будьте им).
-
-Примеры некоторых README, которыми можно вдохновляться:
-
-- [MetaFX](https://github.com/ctlab/metafx), тул Артёма Иванова. Там еще и [wiki](https://github.com/ctlab/metafx/wiki) крутое.
-- [samovar](https://github.com/nvaulin/samovar)
-- [MetaGEM](https://github.com/franciscozorrilla/metaGEM)
-- [Pharokka](https://github.com/gbouras13/pharokka)
-
-Типовые секции, на которые стоит обратить внимание: Title, Overview, Usage, Options, Examples, Troubleshooting, Contacts.
-
-**Tехническое требование к заданию.**
-
-Это задание будет выполняться в командах по 3 человека. Каждый из членов команды должен внести ***как минимум*** 2 функции. Каждое внесение функции должно сопровождаться коммитом с осмысленным описанием коммита. Ниже приведена последовательность действий для успешного выполнения задания (аналогично ДЗ №2):
-
-1. Посмотрите состав своей команды здесь ([**ССЫЛКА**](https://docs.google.com/spreadsheets/d/1KMBBBu8LqauRpDJb0v1ldPwpvzNn8-KakcHexAcqLsE/edit?usp=sharing)).
-2. Тимлид делает форк данного репозитория. **В форке создает ветку `HW4_`, в ветке создает папку `HW4_`, в этой папке вы всё делаете.**
-3. Члены команды могут либо делать свои форки, либо работать в репозитории тимлида в качестве колабораторов ("contributors"). В любом случае делаете клоны => пишите код локально => пушите.
-4. В конце тимлид делайет pull-request из `HW4_` своего репозитория в `main` этого.
-
-
-А также:
-- Сопроводите программу лучшим `README.md` файлом в вашей жизни (на английском языке).
-- В этом ДЗ проблемы с качеством кода (нейминги, пустые строки, анноатции типов, док.стринги, пробелы) могут привести к снижению балла. Воспользуйтесь линтерами чтобы себя обезопасить. IDE по типу PyCharm или VSCode имеют фунцонал по авто-исправлению многих проблем такого рода.
-
-Автотестов на GitHub в этом ДЗ нет, но вы можете прогнать линтеры на качество кода локально (как в ДЗ №3, подробнее читайте [тут](https://plausible-cannon-091.notion.site/Code-auto-checks-02b2ea69c1d545fca07b50ce5933ed5f?pvs=4)).
-
-- Программа должна сохранять регистр символов.
-- Программа должна работать только с последовательностями белков.
-- Запрещается использование сторонних модулей.
-
-
-### Форма сдачи
-
-Прикрепите ссылку на pull-request тимлида в Google Class (можете сделать от лица каждого члена команды, но это не обязательно).
-
-
-### Pазбалловка
-
-- За каждую из 5 операций - максимум **1.5 балла**
-- За README - максимум **2.5 балла**
-- Если вы не внесли как минимум 2 функции от себя, вы получаете 0 баллов (на баллы остальных членов команды это не влияет).
-- За фото созвона в README можно получить 0.2 доп. балла (но не более 10 баллов суммарно)
-
-
-
-### **Предполагаемый учебный результат**
-
-Это задание позволит вам проявить креативность и учиться быть не только кодером, но и автором. Также это задание поможет окончательно закрепить материал по функциям который мы прошли.
-
-Удачи! ✨✨
+# protein_tools.py
+
+**protein_tools.py** - is a tool which allows the performing of various procedures for a user entered protein sequences.
+
+### Usage
+
+The tool works by calling the function `run_protein_tools`, which takes arbitrary number of arguments with protein sequencies (*str*) and the name of the procedure to be performed (always the last argument, *str*, see the usage examples below). The output is the result of the procedure as *string, tuple* or *dictionary* if one sequence is submitted or *list* if several.
+
+**NOTE:** For the procedure `check_mutations` a fixed number of string arguments are used: one RNA sequence, one protein sequence and the name of procedure itself.
+
+### Procedures
+
+- `compute_molecular_weight` — computes molecular weight of protein sequence in g/mol
+- `compute_length` — computes the number of amino acids in protein sequence
+- `compute_hydrophobicity` — computes the percentage of gydrophobic aminoacids in protein sequence
+- `check_mutations` — checks missense mutations in the protein sequence after translation
+- `protein_to_dna`- returns possible variants of DNAs for a given protein sequence
+- `count_amino_acids` - calculates the number of each aminoacid in protein sequence
+
+### Examples
+```python
+run_protein_tools('MAEGEITNLP', 'tGQYLAMDTSgLLYGSQT', 'compute_length')
+#[('MAEGEITNLP', 10), ('tGQYLAMDTSgLLYGSQT', 18)]
+
+run_protein_tools('MAEGEITNLP', 'tGQYLAMDTSgLLYGSQT', 'compute_molecular_weight')
+#[('MAEGEITNLP', 1055.496), ('tGQYLAMDTSgLLYGSQT', 1886.872)]
+
+run_protein_tools('MAEGEITNLP', 'tGQYLAMDTSgLLYGSQT', 'compute_hydrophobicity')
+#[('MAEGEITNLP', 50.0), ('tGQYLAMDTSgLLYGSQT', 27.778)]
+
+run_protein_tools('AUGGAUCAUcAAUAA', 'MDKL*', 'check_mutations')
+#'Mutations: K3, L4.'
+
+run_protein_tools('MAEGLP', 'LYGSQT','protein_to_dna')
+#['ATG GCT/GCC/GCA/GCG GAA/GAG GGT/GGC/GGA/GGG TTA/TTG/CTT/CTC/CTA/CTG CCT/CCC/CCA/CCG',
+#'TTA/TTG/CTT/CTC/CTA/CTG TAT/TAC GGT/GGC/GGA/GGG TCT/TCC/TCA/TCG/AGT/AGC CAA/CAG ACT/ACC/ACA/ACG']
+
+run_protein_tools('MAEGLP', 'LYGSQT','count_amino_acids')
+#[{'M': 1, 'A': 1, 'E': 1, 'G': 1, 'L': 1, 'P': 1},
+#{'L': 1, 'Y': 1, 'G': 1, 'S': 1, 'Q': 1, 'T': 1}]
+```
+
+### Additional information
+- The program works **only** with protein and RNA sequences. If any of the entered sequences contain inappropriate characters or cannot exist, the program will display an error. Sequences can contain characters of any case.
+
+```python
+run_protein_tools('PROTEIN', 'compute_molecular_weight') #ValueError: Invalid protein sequence
+run_protein_tools('AUGGAU_AUcAAUAA', 'MDKL*', 'check_mutations') #ValueError: Invalid RNA sequence
+```
+- For the procedure `check_mutations` there are extra requirements for RNA and protein sequences: mRNA sequences must contain **start-codon** and **one of the stop-codons**, protein sequnces must start with **"M"** and ends with **"*"** (stop-codon).
+```python
+run_protein_tools("AUGGUAGGGAAAUUUUGA", "MGGKF", 'check_mutations') #ValueError: Stop (*) is absent
+run_protein_tools("AUGGUAGGGAAAUUUUGA", "GGKF*", 'check_mutations') #ValueError: Start (M) is absent
+```
+### Contacts
+Please use contacts below to reach out with any comments, concerns, or discussions regarding **protein_tools.py.**
+- Artyom Toropov ([@artyomtorr](https://github.com/artyomtorr/))
+- Sofiya Vinogradova ([@sofiyaga57](https://github.com/sofiyaga57/))
+- Nikita Zherko ([@rereremin](https://github.com/rereremin/))
+
+
+
+*Author contributions:*
+Artyom Toropov (teamlead): functions `is_protein`, `is_rna`, `compute_molecular_weight`, `run_protein_tools`
+Sofiya Vinogradova: functions `compute_length`, `count_amino_acids`, `protein_to_dna`
+Nikita Zherko: functions `compute_hydrophobicity`, `translate_rna`, `check_mutations`