Skip to content

Review GPR183 #39

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

Review GPR183 #39

wants to merge 1 commit into from

Conversation

nvaulin
Copy link
Member

@nvaulin nvaulin commented Feb 26, 2024

Review GPR183

Copy link

@EkaterinShitik EkaterinShitik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Учитывая объем задания, работа выполнена очень хорошо!

  1. В парсере fastq реализован весь функционал и использованы все необходимые модули из BioPython
  2. В задании по классам выполнены все условия полиморфизма и наследования

Из моментов для доработки я бы подстветила несколько моментов.

  1. BiologicalSequence не реализован, как абстрактный класс. Соответственно, он не опеределяет свод правил для всех дочерних классов. Плюсом он подтягивает методы строки, которые нам могут даже помешать.
  2. Очень много мелких моментов PEP8. Автоматизированные проверки спасают!
  3. Нет аннотаций типов.

В любом случае, вы молодец!

Comment on lines +2 to +5
import os
from Bio import SeqIO
from Bio.SeqUtils import gc_fraction
from typing import Union

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Не совсем корректно представлены импорты. Корректирую все программы с помощью isort)

Suggested change
import os
from Bio import SeqIO
from Bio.SeqUtils import gc_fraction
from typing import Union
import os
from typing import Union
from Bio import SeqIO
from Bio.SeqUtils import gc_fraction

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Насколько я знаю, так необходимо делать, если импортируются какие-то кастомные (собственные) пакеты. В данном случае, пакет Bio таким не является и мне кажется, не обязательно их разделять пустой строкой.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Встроенные
  2. Сторонние
  3. Локальные

Между ними по строке, так что Катя (в лице isort'a) и isort (в лице Кати) правы

Comment on lines +13 to +28
This function work with FASTQ files and filters them by
GC content, length and Q-score.

Arguments (positional):
- input_path (str): full path to the file that you want to work with
- output_filename (str): enter just a name of the file, don't add extention

Arguments (keyword):
- gc_bound (tuple, int, float): tuple of required range of GC percentage (inclusive),
num or float if only higher border of the range is needed (exclusive).
- length_bound (tuple, int, float): tuple of required range of sequences length (inclusive),
num or float if only higher border of the range is needed (exclusive).
- quality_threshold (int): int of lowest level of Q-score (inclusive).

Output:
- list of BioSeq records. Write file to .fastq

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Классный и понятный докстринг!

Comment on lines +31 to +32
if input_path is None:
raise ValueError("You didn't enter any PATH to file")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Очень полезная ошибка) Облегчает работу с программой!

else:
output_path = f'{input_folder}/fastq_filtrator_resuls/{output_filename}.fastq'
# Create dict from FASTQ
seqs = list(SeqIO.parse(input_path, "fastq"))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Всё указано супер корректно, но не совсем понятно, зачем нам полученный результат переводить в лист?
При использовании парсера из BioPython, мы уже получаем коллекцию из SeqRecord, по которой можем итерироваться. У меня вот так работает :)

Suggested change
seqs = list(SeqIO.parse(input_path, "fastq"))
seqs = SeqIO.parse(input_path, "fastq")

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ровно так

Comment on lines +46 to +53
if len(seqs) <= 0:
raise ValueError('There are no fastq sequences')
# Check if all given argumets have relevant type
gc_bound_type = isinstance(gc_bound, (tuple, int, float))
length_bound_type = isinstance(length_bound, (tuple, int, float))
quality_thr_type = isinstance(quality_threshold, (int, float))
if not (gc_bound_type and length_bound_type and quality_thr_type):
raise ValueError('Your arguments are not suitable!')

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Тоже супер классные и полезные ошибки! Взяла себе на заметку!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

В данном случае тем не менее не совсем ясно какой же из аргументов не правильного типа. Так что лучше если проверять, то разделять

Comment on lines +141 to +150
dictionary = {
'A': 'U',
'G': 'C',
'U': 'A',
'C': 'G',
'a': 'u',
'g': 'c',
'u': 'a',
'c': 'g',
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PEP8

Suggested change
dictionary = {
'A': 'U',
'G': 'C',
'U': 'A',
'C': 'G',
'a': 'u',
'g': 'c',
'u': 'a',
'c': 'g',
}
dictionary = {
'A': 'U',
'G': 'C',
'U': 'A',
'C': 'G',
'a': 'u',
'g': 'c',
'u': 'a',
'c': 'g',
}

Comment on lines +82 to +83
def __len__(self):
return len(self.sequence)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Вернусь к теме про абстрактный класс. BiologicalSequence должен был быть просто шаблоном, определяющим правила создания всех последующих классов. В данном шаблоне мы не должны прописывать никакие функции, так как они не выполняются, а только являются сводом правил. Данный код необходимо было перенести в дочерние классы. В данном случае, это NucleicAcidSequence и AminoAcidSequence

Suggested change
def __len__(self):
return len(self.sequence)
@abstractmethod
def __len__(self):
pass

Comment on lines +88 to +91
def alphabet_checking(self):
if not set(self.sequence) <= set(type(self).dictionary.keys()):
raise WrongSequence('Wrong sequence')
return True
Copy link

@EkaterinShitik EkaterinShitik Mar 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Проверка - супер разумная, но, во-первых, она должна быть определена в следующем поколении классов.
А во-вторых, она дублирует возврат True. Само условие уже подразумевает возвращение True или False, поэтому лучше бы сделать так

Suggested change
def alphabet_checking(self):
if not set(self.sequence) <= set(type(self).dictionary.keys()):
raise WrongSequence('Wrong sequence')
return True
def alphabet_checking(self):
return set(self.sequence) <= set(type(self).dictionary.keys())

Comment on lines +176 to +180
def __init__(self, sequence):
super().__init__(sequence)
if not self.alphabet_checking():
del self.sequence
raise WrongSequence('You have entered a wrong sequence')

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Перед init должна быть одна строчка

Suggested change
def __init__(self, sequence):
super().__init__(sequence)
if not self.alphabet_checking():
del self.sequence
raise WrongSequence('You have entered a wrong sequence')
def __init__(self, sequence):
super().__init__(sequence)
if not self.alphabet_checking():
raise WrongSequence('You have entered a wrong sequence')

del self.sequence
raise WrongSequence('You have entered a wrong sequence')

def protein_mass(self):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

C функцией всё отлично, но тут добавлю комментарий по всему заданию по классам. Нигде не приведена аннотация. Кажется, с ней просматривать код намного приятней)

Suggested change
def protein_mass(self):
def protein_mass(self) -> float:

Comment on lines +9 to +11
gc_bound: Union[tuple, int, float] = (0, 100),
length_bound: Union[tuple, int, float] = (0, 2**32),
quality_threshold: Union[int, float] = 0) -> None:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Интересное решение с Union, взяла себе на заметку

raise WrongSequence('You have entered a wrong sequence')

def protein_mass(self):
mass = sum(self.dictionary.get(aa) for aa in self.sequence)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

С точки зрения кода всё отлично, но биологически при вычисления массы белка нужно вычитать воду, например:

Suggested change
mass = sum(self.dictionary.get(aa) for aa in self.sequence)
list_input_seq = list(seq)
water_mw = 18
for aa in list_input_seq:
total_mw = sum(aa_weight_dict[a] for a in list_input_seq)
mw_water_removed = (total_mw - (water_mw * (len(list_input_seq)-1)))
return mw_water_removed

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Хе-хе, вот она разница между биоинформатиком и программистом!

pass


class BiologicalSequence(str):
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

По заданию, BiologicalSequence должен был быть абстрактным классом, то есть никакого функционала тут быть не должно. Абстрактные классы создают только шаблон структуры.

self.gc_cont = None

def complement(self):
return type(self)(''.join([type(self).dictionary[i] for i in self.sequence]))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Отличное решение!

class BiologicalSequence(str):
def __init__(self, sequence):
self.sequence = sequence

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

еще по заданию нужно было добавить вот это:

Suggested change
def __str__(self) -> str:
return self.sequence

Copy link

@Zoea1 Zoea1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Очень классная работа, мне особо и сказать нечего (тем более, что много чего уже было сказано до меня). Ты молодец!

pass


class BiologicalSequence(str):
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

По заданию это должен был быть абстрактный класс.

"V": 99.06841,
"W": 186.07931,
"Y": 163.06333,
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PEP8

@nvaulin
Copy link
Member Author

nvaulin commented Mar 17, 2024

Очень классная работа, мне особо и сказать нечего (тем более, что много чего уже было сказано до меня). Ты молодец!

Ну тут все таки важно чтобы вы учились комментировать код, поэтому нет ничего плохого в том чтобы повторять чьи-то комментарии если вам тоже они пришли в голову

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants