Skip to content

Conversation

nvaulin
Copy link
Member

@nvaulin nvaulin commented Feb 26, 2024

Review PCDHA12

Copy link

@anshtompel anshtompel left a comment

Choose a reason for hiding this comment

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

Хорошая работа! Понравился фильтратор, а еще некоторые реализации функций, очень компактно. Спасибо за работу!

Comment on lines +24 to +26
def filter_fastq(input_path: str,
gc_bounds: tuple = (0, 100),
length_bounds: tuple = (0, 2 ** 32),

Choose a reason for hiding this comment

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

Всё круто! Хорошее решение делать фильтрацию, возвращая bool от проверок

Comment on lines +43 to +46
class BiologicalSequence(ABC, str):
@abstractmethod
def check_alphabet(self) -> bool:
pass

Choose a reason for hiding this comment

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

В вашем абстрактном классе не реализованы еще сет методов: работа c len, индексация и вывод в печать

Comment on lines +61 to +62
complement_seq = ''.join(type(self).COMPLEMENT_DICT.get(base)
for base in self.sequence)

Choose a reason for hiding this comment

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

Интересная конструкция) Возьму на заметку

pass


class NucleicAcidSequence(BiologicalSequence):

Choose a reason for hiding this comment

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

Не хватает докстринг в классах

Comment on lines +94 to +98
ONE_LETTER_ALPHABET = ('A', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'K', 'L',
'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'V', 'W', 'Y')
THREE_LETTER_ALPHABET = ('Ala', 'Cys', 'Asp', 'Glu', 'Phe', 'Gly', 'His',
'Ile', 'Lys', 'Leu', 'Met', 'Pro', 'Gln', 'Arg',
'Ser', 'Thr', 'Val', 'Trp', 'Tyr')

Choose a reason for hiding this comment

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

Круто, что предусмотрено два варианта алфавита

Copy link

@BeskrovnaiaM BeskrovnaiaM left a comment

Choose a reason for hiding this comment

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

Супер! Ты молодец 🥇

Comment on lines +43 to +47
class BiologicalSequence(ABC, str):
@abstractmethod
def check_alphabet(self) -> bool:
pass

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 +70 to +73
class RNASequence(NucleicAcidSequence):
ALPHABET = ('A', 'U', 'G', 'C', 'N')
COMPLEMENT_DICT = {'A': 'U', 'U': 'A', 'G': 'C', 'C': 'G', 'N': 'N',
'a': 'u', 'u': 'a', 'g': 'c', 'c': 'g'}

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 +50 to +51
def __init__(self, sequence):
raise NotImplementedError('An instance of this class cannot be created')

Choose a reason for hiding this comment

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

Здесь можно было бы при ините делать последовательность сразу большими буквами, чтобы потом в словаре не хранить и маленькие, и большие буквы. И в целом инит вынести в этот класс, и убрать его в дочерних, с точки зрения информации подаваемой, что АА, что РНК, что ДНК это все строчки с буковками. Так что я бы вместо ошибки добавила вот это, а потом от этого дальше наследовалась, чтобы не дублироваться.

Suggested change
def __init__(self, sequence):
raise NotImplementedError('An instance of this class cannot be created')
def __init__(self, sequence):
self.seq = seq.upper()

Comment on lines +28 to +30
""" Reads a FASTQ file, filters sequences based on GC content, sequence
length and quality threshold, and writes the filtered sequences to
a new file """

Choose a reason for hiding this comment

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

Спасибо за докстринг! Но мне казалось, что туда необходимо добавлять, какой инпут и какой аутпут функции идет. Что-то вот такое

Suggested change
""" Reads a FASTQ file, filters sequences based on GC content, sequence
length and quality threshold, and writes the filtered sequences to
a new file """
"""
Reads a FASTQ file, filters sequences based on GC content, sequence
length and quality threshold, and writes the filtered sequences to
a new file
Args:
input_path (str): Path to the input FASTQ file.
gc_bounds (tuple): A tuple of two integers specifying the lower and
upper bounds of the GC content, in percent. Sequences with GC
content outside these bounds will be filtered out.
length_bounds (tuple): A tuple of two integers specifying the lower and
upper bounds of the sequence length, in base pairs. Sequences
with length outside these bounds will be filtered out.
quality_threshold (int): An integer specifying the minimum average
quality score for a sequence to be kept. Sequences with average
quality score below this threshold will be filtered out.
"""


def filter_quality(record: SeqRecord, quality_threshold: int) -> bool:
avg_quality = np.mean(record.letter_annotations["phred_quality"])
return avg_quality >= quality_threshold

Choose a reason for hiding this comment

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

мне очень нравится реализация этих функций: кратко и понятно (есть аннотация с каждому аргументу, почти все уместилось на одну строку, без лишних переменных)

однако я помню, что по заданию границы для длины и GC состава могут быть заданы как в виде одного числа, так и в виде интервала. в ваших функциях есть только интервал

a new file """
path, filename = os.path.split(input_path)
name, ext = os.path.splitext(filename)
output_path = path + "/" + f"{name}_filtered{ext}"

Choose a reason for hiding this comment

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

мне нравится способ генерации имени выходного файла, здесь также можно было учесть из тз, что пользователь сам тоже может задавать имя файла.

output_path = path + "/" + f"{name}_filtered{ext}"
input_seq_iterator = SeqIO.parse(input_path, 'fastq')
filtered_seq_iterator = (record for record in input_seq_iterator
if filter_length(record, length_bounds)

Choose a reason for hiding this comment

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

отличный способ проверить все три условия и сразу записать, list comprehension тут лаконично и эффективно вписался. то, что функции возвращают bool позволяет его провести- это хороший подход

class RNASequence(NucleicAcidSequence):
ALPHABET = ('A', 'U', 'G', 'C', 'N')
COMPLEMENT_DICT = {'A': 'U', 'U': 'A', 'G': 'C', 'C': 'G', 'N': 'N',
'a': 'u', 'u': 'a', 'g': 'c', 'c': 'g'}

Choose a reason for hiding this comment

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

да, верно, словарь лучше вынести за функцию. помимо этого, мне нравится логика наследования методов и полиморфизм здесь: то есть методы проверки на ДНК/РНК и построения комплементарной цепи реализуются для каждого дочернего класса называются одинаково, но учитывают отличия дня/рнк

def transcribe(self) -> RNASequence:
"""Transcribes DNA sequence into RNA sequence.
Returns RMASequence object"""
return RNASequence(self.sequence.replace('T', 'U').replace('t', 'u'))

Choose a reason for hiding this comment

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

я также реализовала транскрипцию, но оказалось это не самый оптимальный вариант, так как двойной replace = двойной проход по последовательности.

молодец, что возвращаешь экземпляр класса RNASeq


def get_molecular_weight(self) -> float:
""" calculate molecular weight for one-letter amino acid sequence"""
WEIGHT_DICT = {

Choose a reason for hiding this comment

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

насколько мне известно, словарь лучше вынести за функцию

'D': 115.087, 'Q': 128.129, 'K': 128.172, 'E': 129.114, 'M': 131.196,
'H': 137.139, 'F': 147.174, 'R': 156.186, 'Y': 163.173, 'W': 186.210
}
terminal_h_oh_weight = 18.02

Choose a reason for hiding this comment

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

круто, даже масса терминальной hoh учтена)

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.

4 participants