Skip to content

Review CEP170B #40

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 CEP170B #40

wants to merge 1 commit into from

Conversation

nvaulin
Copy link
Member

@nvaulin nvaulin commented Feb 26, 2024

Review CEP170B

Copy link

@zmitserbio zmitserbio left a comment

Choose a reason for hiding this comment

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

В целом, работа оставляет положительное впечатление. Код читабельный, в основном рабочий.
Однако есть проблема с нереализованностью функционала, и в будущем имеет смысл использовать линтер.

from abc import ABC, abstractmethod
from Bio import SeqIO
from Bio.SeqUtils import gc_fraction
from typing import Tuple

Choose a reason for hiding this comment

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

Насколько мне известно, после python 3.9 не рекомендуется использовать Tuple, хотя работе кода это не мешает.

Comment on lines +8 to +11
def filter_fastq(input_path: str,
output_filename: str = None,
gc_bounds: Tuple[int, int] = (0, 100),
length_bounds: Tuple[int, int] = (0, 2**32),

Choose a reason for hiding this comment

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

Есть некоторое нарушение pep8: не следует оставлять пробелы на концах строк.

quality_threshold: int = 0) -> None:
'''
Filter FASTQ-sequences based on entered requirements.

Choose a reason for hiding this comment

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

Следует убрать \t.

Comment on lines +16 to +30
Arguments:
- input_path (str): path to the file with FASTQ-sequences
- output_filename (str): name of the output file with
filtered FASTQ-sequences
- gc_bounds (tuple or int, default = (0, 100)): GC-content
interval (percentage) for filtering. Tuple if contains
lower and upper bounds, int if only contains an upper bound.
- length_bounds (tuple or int, default = (0, 2**32)): length
interval for filtering. Tuple if contains lower and upper
bounds, int if only contains an upper bound.
- quality_threshold (int, default = 0): threshold value of average
read quality for filtering.

Note: the output file is saved to the /fastq_filtrator_results
directory. The default output file name is the name of the input file.
Copy link

@zmitserbio zmitserbio Mar 9, 2024

Choose a reason for hiding this comment

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

В некоторых строках имеются пробелы на концах.
Гораздо более существенно то, что функция не соответствует заявленному функционалу. Если подать int аргументам gc_bounds и length_bounds, то падает с ошибкой, т.к. не реализован перевод этого int в соответствующий tuple. Это можно было реализовать, например, так:

if isinstance(gc_bounds, int):
    gc_bounds = tuple([0, gc_bounds])
if isinstance(length_bounds, int):
    length_bounds = tuple([0, length_bounds])

Возможно, в будущем имеет смысл писать себе pass или комментарии, чтобы не забывать.

records = [record for record in SeqIO.parse(handle, "fastq")]

filtered_records = []
for record in records:

Choose a reason for hiding this comment

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

Здесь была возможность использовать SeqIO:

Suggested change
for record in records:
for i, record in enumerate(SeqIO.parse(input_path, "fastq")):

print(f"Filtered sequences saved to {output_path}")


class BiologicalSequence(ABC):

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.

Все так



class BiologicalSequence(ABC):
def __init__(self, seq: str = None):

Choose a reason for hiding this comment

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

Хотя это и не запрещено, в лекции/консультации упоминалось, что лучше не писать код в абстрактном классе.

return self.seq

def check_alphabet(self):
return set(self.seq.upper()).issubset(self.ALPHABET)

Choose a reason for hiding this comment

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

Считаю это достаточно изящным решением.

def __repr__(self):
return self.seq

def check_alphabet(self):

Choose a reason for hiding this comment

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

Я думаю, что проверять алфавит разумно было бы в init в обязательном порядке.

Comment on lines +121 to +122
ALPHABET = {"A", "C", "D", "E", "F", "G", "H", "I","K", "L",
"M", "N","P", "Q", "R", "S", "T", "V", "W", "Y"}

Choose a reason for hiding this comment

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

Suggested change
ALPHABET = {"A", "C", "D", "E", "F", "G", "H", "I","K", "L",
"M", "N","P", "Q", "R", "S", "T", "V", "W", "Y"}
ALPHABET = {"A", "C", "D", "E", "F", "G", "H", "I", "K", "L",
"M", "N", "P", "Q", "R", "S", "T", "V", "W", "Y"}

Стоит добавить пробелы. Помимо этого, есть еще некоторое количество пробелов на концах строк и \t в пустых строках, но я полагаю, не имеет смысла на каждом останавливаться. Стоит проверять код линтером, так можно выявить те огрехи, которые невооруженному глазу плохо заметны.

Copy link

@anisssum anisssum left a comment

Choose a reason for hiding this comment

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

Особенно хорошо, что вы использовали абстрактные классы и соблюдали принципы ООП. Ваш код довольно лаконичен и легко читаем, что является плюсом.
В целом, код отлично справляется с поставленными задачами, и замечания касаются мелких деталей и стиля. Отличная работа!


def gc_content(self):
gc_count = self.seq.count('G') + self.seq.count('C')
return gc_count / len(self.seq) * 100

Choose a reason for hiding this comment

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

Можно учесть деление на 0.

Copy link
Member Author

Choose a reason for hiding this comment

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

Верно подмечено

if output_filename is None:
output_filename = input_path.split("/")[-1].split(".")[0] + "_filtered.fastq"

output_path = "fastq_filtrator_results/" + output_filename

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.

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

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.

3 participants