diff --git "a/DNA features \342\200\224 \320\272\320\276\320\277\320\270\321\217.pptx" "b/DNA features \342\200\224 \320\272\320\276\320\277\320\270\321\217.pptx" new file mode 100644 index 0000000..22809c4 Binary files /dev/null and "b/DNA features \342\200\224 \320\272\320\276\320\277\320\270\321\217.pptx" differ diff --git a/DNA_feature_server.py b/DNA_feature_server.py index f7efd8e..28a265c 100644 --- a/DNA_feature_server.py +++ b/DNA_feature_server.py @@ -1,8 +1,10 @@ - from flask import Flask, render_template, request, redirect, url_for, flash -from random import randint, choice -from homopol_tract import polytract_finder # поиск однобуквенных повторов +from homopol_tract import polytract_finder, format_homopol # поиск однобуквенных повторов import gc_graphic as gc +import random_seq as rs +from verification_seq import InputDNA +import tandem_search as ts +import genebank app = Flask(__name__) @@ -11,8 +13,13 @@ 'remove_count': -1, 'random_seq':None, 'is_random': 0, - 'tandem_test':0, - 'redirect_test':None, + 'genbank_seq_id': None, + 'genebank_name': None, + 'genebank_length': None, + 'genebank_seq': None, + 'genebank_error':None, + 'is_genebank': 0, + 'tandem_list': None, 'homopol_tract': None, 'homopol_tract_number': 0, 'gc_frame_length': 0, @@ -22,18 +29,22 @@ @app.route("/") def index(): #обрабатываем главную страницу title = "DNA feature finder" - return render_template('index.html', page_title=title, querry_length = '', remove_count = test_querry['remove_count'], is_random=test_querry['is_random'] ) + return render_template('index.html', page_title=title, querry_length = '', remove_count = 0, + is_random=test_querry['is_random'], is_rna = 0, + non_identified = 0, is_genebank = test_querry['is_genebank'], + genebank_error = test_querry['genebank_error'] ) @app.route("/", methods=['POST']) def input_seq(): #запрос последовательности из окна try: - dna_query = request.form.get('dna_querry') - test_querry['input_seq'] = dna_query.strip() #здесь будет применена функция форматирования, запись в словарь - dna_query_lengh = len(test_querry['input_seq']) - return render_template('index.html', querry_length = dna_query_lengh, remove_count = test_querry['remove_count']) + dna_query = InputDNA(request.form.get('dna_querry')) + test_querry['input_seq'] = dna_query.formated_sequence #сохраняем в словарь + return render_template('index.html', querry_length = dna_query.input_lenth, remove_count = dna_query.counter, + is_rna = dna_query.is_uracil, non_identified = dna_query.is_non_identified) except (TypeError, IndexError): - return render_template('index.html', remove_count = test_querry['remove_count'], querry_length = '') + return render_template('index.html', remove_count = dna_query.counter, querry_length = '') + @app.route("/input_report", methods=['POST']) def input_report(): #обрабатываем кнопку показа введенной последоваьельности после ввода и форматирования @@ -43,22 +54,26 @@ def input_report(): #обрабатываем кнопку показа введ else: return 'No DNA sequence input' #почему то не работает, хотя когда ничего не вводится там сотит пробел (ord=32) + @app.route("/random_gen", methods=['POST']) def input_random(): #симуляция рандомной генерации, далее нужно подключать модуль try: random_length = int(request.form.get('random_length')) - if random_length > 0: - test_output = ''.join([choice('atgc') for nucleotide in range(random_length)]) - test_querry['random_seq'] = test_output #запись в словарь - test_querry['is_random'] = 1 #для вывода сообщения что прошла генерация - return redirect(url_for('index')) - else: - test_querry['is_random'] = 0 #убираем сообщение о генерации когда 0 - return redirect(url_for('index')) + #if random_length > 10: + test_output = rs.random_seq(random_length) + print(test_output) + test_querry['random_seq'] = test_output #запись в словарь + test_querry['is_random'] = 1 #для вывода сообщения что прошла генерация + test_querry['genebank_error'] = None + return redirect(url_for('index')) + except rs.LengthError: + test_querry ['is_random'] = -1 #значит неправильное значение + return redirect(url_for('index')) except (TypeError, IndexError, ValueError): test_querry['is_random'] = 0 #убираем сообщение о генерации если кликнули с пустым полем return redirect(url_for('index')) + @app.route("/random_report", methods=['POST']) def random_report(): #обработки кнопки что за последоватльность сгенерировалася if test_querry['random_seq'] is not None: @@ -67,33 +82,73 @@ def random_report(): #обработки кнопки что за последо return 'No DNA generated' +@app.route('/genebank_download', methods=['POST']) +def genebank_download(): #запрос для поиска в genbank + try: + genebank_querry = str(request.form.get('genebank_id')).strip() + nucleotide_querry = genebank.Nucleotide(genebank_querry) + test_querry['genebank_length'] = nucleotide_querry.length + test_querry['genbank_seq_id'] = genebank_querry + test_querry['genebank_name'] = nucleotide_querry.dna_name + test_querry['genebank_seq'] = nucleotide_querry.sequence + test_querry['is_genebank'] = 1 + try: + nucleotide_querry.type_check() + return redirect(url_for('index')) + except genebank.NonDNAError: + test_querry['genebank_error'] = 'NonDNAError' + return redirect(url_for('index')) + except genebank.NoIDError: + test_querry['is_genebank'] = 0 + test_querry['genebank_error'] = 'NoIDError' + return redirect(url_for('index')) + except genebank.DNALengthError: + test_querry['is_genebank'] = 0 + test_querry['genebank_error'] = 'DNALenghtError' + return redirect(url_for('index')) + except genebank.NonDNAError: + test_querry['genebank_error'] = 'NonDNAError' + return redirect(url_for('index')) + + + @app.route("/repeats") def repeat_page(): #страница работы с повторами - return render_template('repeats.html', tandem_found = test_querry['tandem_test'], tract_number = test_querry['homopol_tract_number']) + return render_template('repeats.html', tandem_found = '', tract_number = test_querry['homopol_tract_number']) + @app.route("/repeats", methods=['POST']) def input_tandem(): #ввод длины повтора, его обработка и вывод try: - tandem_length = request.form.get('tandem_length') - test_querry['tandem_test'] = int(tandem_length)*10 #переменная для тестирвоания кнопки - return render_template('repeats.html', tandem_found = test_querry['tandem_test']) + tandem_length = int(request.form.get('tandem_length')) + sequence_fold = ts.fold(test_querry['input_seq'], tandem_length) + test_querry['tandem_list'] = ts.tandem_repeat(sequence_fold) + return render_template('repeats.html', tandem_found = len(test_querry['tandem_list'])) except (TypeError, IndexError, ValueError): return render_template('repeats.html', tandem_found = '') -''' + + @app. route("/tandem_report") def tandem_report_page(): #заготовка странциы с описание найдленых повторов в упододавимой форме - return redirect(url_for('repeats')) -''' + formated_repeats = [] + return render_template('tandem_report.html', repeats = formated_repeats) + + @app.route("/tandem_report", methods=['POST']) def tandem_report(): #обработка кнопки для показа найденых повторов (отчет уже готов когда произведен поиск - if test_querry['tandem_test'] > 0: - test_querry['redirect_test'] = test_querry['tandem_test']*10 #тестовый вывод обработки - return f"{test_querry['redirect_test']}" #пока примитивный вывод + if test_querry['tandem_list'] is not None and test_querry['tandem_list'] != []: + formated_repeats = [] + for (count, repeat) in enumerate(test_querry['tandem_list']): + formated_repeats.append(ts.format_seq(repeat, count+1)) + #return f"{test_querry['tandem_list']}" #пока примитивный вывод + return render_template('tandem_report.html', repeats=formated_repeats, homopol_tracts = test_querry['homopol_tract']) else: - return 'No repeats found' - + return render_template('tandem_report.html', repeats=['No repeats found'], homopol_tracts = test_querry['homopol_tract']) + + + @app. route("/poly_tract", methods=['POST']) def poly_tract_finder(): #кнопка поиска поиск гомопимерных трактов #пока последовательнотсь будет браться из input как разнести последовательности из дургих источнико я пока не знаю @@ -102,24 +157,21 @@ def poly_tract_finder(): #кнопка поиска поиск гомопиме return redirect(url_for('repeat_page')) -''' -@app. route("/poly_tract_report") -def poly_tract_report_page(): #заготовка странциы с описание найдленых гомополимероных участков в упододавимой форме - return render_template('homopolymer_report.html', page_title=title) -''' @app. route("/poly_tract_report", methods=['POST']) def poly_tract_report(): #кнопка показа найденых повторов if test_querry['homopol_tract'] is not None and test_querry['homopol_tract'] != {}: - #вызопв тип тракта - return f'{test_querry["homopol_tract"]}' + formated_tracts = format_homopol(test_querry['homopol_tract']) + return render_template('tandem_report.html', homopol_tracts = formated_tracts) else: - return f'No homopolymer tracts' - + return render_template('tandem_report.html', homopol_tracts = ['No homopolymer tracts found']) + + @app.route('/gc_content') def gc_content(): return render_template('gc_content.html', total_GC_content = '') + @app.route('/gc_content', methods=['POST']) def input_frame_gc(): #ввод длины окна поиска try: @@ -131,7 +183,8 @@ def input_frame_gc(): #ввод длины окна поиска return render_template('gc_content.html', total_GC_content=total_gc) except (TypeError, IndexError, ValueError): return render_template('gc_content.html', total_GC_content = '') - + + @app.route('/gc_content_min', methods=['POST']) def gc_min_report(): #ввод участков с минимальными GC if test_querry['gc_content'] is not None: @@ -140,6 +193,7 @@ def gc_min_report(): #ввод участков с минимальными GC else: return 'Please calculate content before' + @app.route('/gc_content_max', methods=['POST']) def gc_max_report(): #ввод участков с минимальными GC if test_querry['gc_content'] is not None: diff --git a/GC_graphic.py b/GC_graphic.py index 806fe21..9eee0b8 100644 --- a/GC_graphic.py +++ b/GC_graphic.py @@ -53,8 +53,8 @@ def draw_gc_content(sequence, frame): ax.plot(current_plot[0], current_plot[1]) ax.yaxis.set_major_locator(ticker.MultipleLocator(10)) ax.yaxis.set_minor_locator(ticker.MultipleLocator(5)) - ax.set_xlabel('GC content, %', fontsize = 15) - ax.set_ylabel('DNA positnion, bp', fontsize = 15) + ax.set_xlabel('DNA positnion, bp', fontsize = 15) + ax.set_ylabel('GC content, %', fontsize = 15) gc_fig_clearance() fig.savefig(os.path.join(fig_path, 'gc_fig.jpg'), dpi=150) diff --git a/genebank.py b/genebank.py index 3108db5..0246450 100644 --- a/genebank.py +++ b/genebank.py @@ -5,23 +5,27 @@ примеры ID :NM_018094, NM_001374734.1, NC_052532.1 (1 млн), CM021573.2 (170 млн - может долго грузить) ''' -from Bio import Entrez, SeqIO +from Bio import Entrez, SeqIO + class DNALengthError(ValueError): #сделал ошибки чтобы при их возникновении веб быстрее их обрабатывал pass class NonDNAError(TypeError): pass +class NoIDError(NameError): + pass class Nucleotide: def __init__(self,id_seq): self.id_seq = id_seq - self.dna_description = id_parsing(self.id_seq) + self.dna_description = id_parsing(self.id_seq)['description'] + self.dna_name = id_parsing(self.id_seq)['name'] self.length = int(self.dna_description[2]) self.nuc_type = self.dna_description[4] - if self.length <= 100000: + if self.length <=1000000: self.sequence = genebank_querry(self.id_seq) else: - raise DNALengthError (f'The lengh of the query:{id_seq} is longer than 100 kb!') + raise DNALengthError (f'The lengh of the query:{self.id_seq} is longer than 100 kb!') def __repr__(self): return f'The query contains {self.nuc_type} with length {self.length}' @@ -34,20 +38,32 @@ def type_check(self): Entrez.email = 'somemailsomemail@gmail.cpm' #необходим любой email чтобы больше запросов длеать -def id_parsing(id_seq:str) -> str: - handle = Entrez.efetch(db="nucleotide", id=id_seq, rettype="gb", retmode="text") #хэндрел из другого типа описания, где содержится длин - dna_description = handle.readline().split() #первая строка опсиания гена из базы данных Gene bank где через знаки табуляции тип гена, id, длина, тип полимера, топология, дата обновления - return dna_description +def id_parsing(id_seq:str) -> dict: + try: + result = {'description': None, 'name': None} + handle = Entrez.efetch(db="nucleotide", id=id_seq, rettype="gb", retmode="text") #хэндрел из другого типа описания, где содержится длин + dna_description = handle.readline().split() #первая строка опсиания гена из базы данных Gene bank где через знаки табуляции тип гена, id, длина, тип полимера, топология, дата обновления + gene_name= handle.readline().split()[1:-1] + result['description'] = dna_description + result['name'] = ' '.join(gene_name).strip(',') + return result + except: + raise NoIDError def genebank_querry(id_seq:str) -> str: - handle = Entrez.efetch(db="nucleotide", id=id_seq, rettype="fasta", retmode='text') #создается хэндлей который уже содержит информацию о последвоательности и с нип проводятся дальнейшие манипуляции - record = SeqIO.read(handle, 'fasta') - return str(record.seq) - + try: + handle = Entrez.efetch(db="nucleotide", id=id_seq, rettype="fasta", retmode='text') #создается хэндлей который уже содержит информацию о последвоательности и с нип проводятся дальнейшие манипуляции + record = SeqIO.read(handle, 'fasta') + return str(record.seq) + except: + raise NoIDError if __name__ == '__main__': id = input() dna_query = Nucleotide(id) + print(dna_query.dna_description) + print(dna_query.dna_name) + print(dna_query.length) print(dna_query.sequence) print(dna_query.type_check()) \ No newline at end of file diff --git a/homopol_tract.py b/homopol_tract.py index e5f124f..29d75ee 100644 --- a/homopol_tract.py +++ b/homopol_tract.py @@ -24,6 +24,13 @@ def polytract_finder(sequence: str) -> dict: 'hpt_type': sequence[-1]} return tract_dict +def format_homopol(tract_dict): + format_seq = [] + for item in tract_dict: + formated_tract = f'Tract #{item}: type: {tract_dict[item]["hpt_type"]}, length {tract_dict[item]["hpt_lenght"]}, start at {tract_dict[item]["hpt_start"]} nt, end at {tract_dict[item]["hpt_end"]} nt' + format_seq.append(formated_tract) + return format_seq + if __name__ == '__main__': test_1 = 'aaaagct' #длина повтора <5, повтро в начале test_2 = 'aaaaagct' #длина повтора >=5, повтор в начале diff --git a/random_seq.py b/random_seq.py index fa09d36..fd3e5c5 100644 --- a/random_seq.py +++ b/random_seq.py @@ -1,11 +1,20 @@ import random -dna_symbols = ["a", "t", "g", "c"] +class LengthError(ValueError): + pass def random_seq(size): - if size >= 100 and size <= 100000: # задаём ограничение длины последовательности - random_seq = "".join([random.choice(dna_symbols) for symbol in range(size)]) # рандомно набираем допустимые символы согласно требуемой длине - random.shuffle(random_seq) # перемешиваем ещё раз + dna_symbols = ["a", "t", "g", "c"] + if size >= 10 and size <= 100000: # задаём ограничение длины последовательности + random_seq_list = [random.choice(dna_symbols) for symbol in range(size)] # рандомно набираем допустимые символы согласно требуемой длине + random.shuffle(random_seq_list) # перемешиваем ещё раз + random_seq = ''.join(random_seq_list) return random_seq else: - raise ValueError("Недопустимая длина последовательности") \ No newline at end of file + raise LengthError("Недопустимая длина последовательности") + + +if __name__ == '__main__': + + size = int(input()) + print(random_seq(size)) \ No newline at end of file diff --git a/static/images/gc_fig.jpg b/static/images/gc_fig.jpg index 8ea4b2d..5a9583f 100644 Binary files a/static/images/gc_fig.jpg and b/static/images/gc_fig.jpg differ diff --git a/tandem_search.py b/tandem_search.py new file mode 100644 index 0000000..8485150 --- /dev/null +++ b/tandem_search.py @@ -0,0 +1,78 @@ + +# расклаываем исходную последовательность на фрагметы размером с длину повтора для каждого из фреймшифта +def fold (sequence:str, n_fold:int) ->list: + seq_split = [] #список для списков разбивки последовательностей с разынми фреймшифтами + if n_fold >= 2 and n_fold <= (len(sequence) // 2): # задаём ограничение длины повтора + for item in range(n_fold): #цикл для создания фреймшифта, +1 чтобы проверять является ли элемент последним + fold_seq = "" #последвоательность раная длине повтора + seq_frameshift = [] #cписок элементов последовательности равных длине повтора + for nucleotide in sequence[item:]: # дробим последовательность для каждого из фреймшифтов + fold_seq += nucleotide + if len(fold_seq) == n_fold: + seq_frameshift.append(fold_seq) + fold_seq = '' #обнуляем для следующего фрагмента + seq_split.append(seq_frameshift) + else: + raise ValueError("Недопустимая длина повтора") + return seq_split + +def format_seq(raw_repeat, count): + return f'Repeat #{count}:Number of repated elements: {raw_repeat["number_elements"]}, type: {raw_repeat["repeat_type"]}, start at {raw_repeat["first_nucleotide"]} nt, end at {raw_repeat["last_nucleotide"]}, frameshift: {raw_repeat["frameshift"]}' + + + +def tandem_repeat(folded_seq: list) -> list: #находит тип повтора, начало и конец каждого повтора + repeat_list = [] + for (frameshift_index, frameshift_list) in enumerate(folded_seq): + repeat_lenght = 0 + print(frameshift_list, frameshift_list[-1]) + for index in range(1, len(frameshift_list)): + n_fold = len(frameshift_list[index]) + if frameshift_list[index] == frameshift_list[index - 1]: + repeat_lenght += 1 + else: + if repeat_lenght >= 1: + start_nucleotide = ((index - repeat_lenght - 1)*(n_fold)) + (frameshift_index + 1) + repeat_list.append({'repeat_start_element': index - repeat_lenght, + 'repeat_end_element': index, + 'number_elements' : repeat_lenght + 1, + 'element_length': n_fold, + 'repeat_type': frameshift_list[index -1], + 'frameshift': frameshift_index + 1, + 'first_nucleotide': start_nucleotide, #абсолютная начальная позиция в исходной последовательности + 'last_nucleotide': start_nucleotide + (repeat_lenght+1)*n_fold - 1 #абсолютная конечная позиция в исходной последовательности + }) + repeat_lenght = 0 + if repeat_lenght >=1: #если после цикла длина повтора != 0 значит последвоательность кончается на повтор + repeat_list.append({'repeat_start_element': len(frameshift_list)- repeat_lenght, + 'repeat_end_element': len(frameshift_list), + 'number_elements' : repeat_lenght + 1, + 'element_length': n_fold, + 'repeat_type': frameshift_list[-1], + 'frameshift': frameshift_index + 1, + 'first_nucleotide': (start_nucleotide := (len(frameshift_list)- repeat_lenght - 1)*n_fold + (frameshift_index + 1)), + 'last_nucleotide': start_nucleotide + (repeat_lenght+1)*n_fold - 1, + }) + + repeat_list.sort(key=lambda item: item['first_nucleotide']) + +#формируем список из не-вложеных повторов + final_list = [] + if len(repeat_list) != 0: + final_list.append(repeat_list[0]) + for index in range(1, len(repeat_list)): + if repeat_list[index]['first_nucleotide'] > repeat_list[index - 1]['last_nucleotide']: + final_list.append(repeat_list[index]) + + + return final_list + + +if __name__ == '__main__': + seq = input('enter sequence') #принимаем последовательность от пользователя + n_fold = int(input()) #принимаем длину повтора от пользователя которая будет использоваться для формирования фремшифтов + + fold_seq = fold(seq, n_fold) + print(fold_seq) + rep_lst = tandem_repeat(fold_seq) + print(rep_lst) \ No newline at end of file diff --git a/templates/gc_content.html b/templates/gc_content.html index 6247b0e..458cf8e 100644 --- a/templates/gc_content.html +++ b/templates/gc_content.html @@ -166,47 +166,20 @@

DNA feature finder

  • - + - Content and free energy + Content
  • -
  • - - - Palindromes - -
  • -
  • - - - Quadruplexes - -
  • - + -
    - +
    diff --git a/templates/index.html b/templates/index.html index e69dc3a..4975174 100644 --- a/templates/index.html +++ b/templates/index.html @@ -172,57 +172,31 @@

    DNA feature finder

  • - Content and free energy + Content -
  • -
  • - - - Palindromes - -
  • -
  • - - - Quadruplexes - -
  • + -
    - +
    -
    +

    Querry: choose DNA of interest

    -
    +
    - +
    -
    +
    +
    Lenght of DNA: {{ querry_length }}
    @@ -239,15 +213,41 @@

    Querry: choose DNA of interest

    {% if remove_count > 0 %}
    - Info Non DNA symbols were removed! + Info: {{ remove_count }} Non DNA symbols were removed!
    - {% elif remove_count ==0 %} + {% elif remove_count ==0 and querry_length != 0 %}
    - Success! DNA sequence is loaded. + Success! DNA sequence is loaded in database +
    + {% else %} +
    + {% endif %} + + {% if is_rna == 1 %} +
    + Info: RNA symbol was detected! {{ is_rna }} uracil symbol was replaced. +
    + {% elif is_rna >1 %} +
    + Info: RNA symbols were detected! {{ is_rna }} uracil symbol were replaced.
    {% else %}
    {% endif %} + + {% if non_identified == 1 %} +
    + Warning: {{ non_identified }} non-identified nucleotide was detected +
    + {% elif non_identified > 1 %} +
    + Warning: {{ non_identified }} non-identified nucleotides were detected +
    + {% else %} +
    + {% endif %} + +

    @@ -262,13 +262,13 @@
    Random genrator
    - +
    -
    +
    @@ -288,6 +288,10 @@
    Random genrator
    Success! DNA sequence is generated.
    + {% elif is_random == -1 %} +
    + Attention: set length of DNA 10-100000 +
    {% else %}
    {% endif %} @@ -301,16 +305,17 @@
    Random genrator
    -
    Download DNA sequence from database:
    -
    -
    - - +
    Download DNA sequence from Genebank:
    + +
    +
    +
    -
    - +
    +
    - + +
    @@ -321,6 +326,22 @@
    Download DNA sequence from database:
    + {% if is_genebank == 1 and not genebank_error %} +
    + Success! DNA from Genebank downloaded.
    + {% elif is_genebank == 1 and genebank_error == 'NonDNAError' %} +
    + Info: The downoladed sequence is originaly RNA
    + {% elif is_genebank == 0 and genebank_error == 'NoIDError' %} +
    + Warning! Wrong acsession number!
    + {% elif is_genebank == 0 and genebank_error == 'DNALenghtError' %} +
    + Warning! The requested DNA is too long (>1 Mbase)
    + {% else %} +
    + + {% endif %} diff --git a/templates/repeats.html b/templates/repeats.html index c0cf7bd..a50411c 100644 --- a/templates/repeats.html +++ b/templates/repeats.html @@ -174,39 +174,13 @@

    DNA feature finder

  • - Content and free energy - -
  • -
  • - - - Palindromes - -
  • -
  • - - - Quadruplexes + Content
  • + -
    - +
    diff --git a/templates/tandem_report.html b/templates/tandem_report.html new file mode 100644 index 0000000..b86df5e --- /dev/null +++ b/templates/tandem_report.html @@ -0,0 +1,228 @@ + + + + + + + + + + Bootstrap demo + + + Sidebars · Bootstrap v5.3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Bootstrap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +

    DNA feature finder

    + + + +
    + + +
    +
    +

    Found repeats

    +
    Tandem repeats
    +
    +
    + {% if repeats %} + {% for repeat in repeats %} +

    {{repeat}}

    + {% endfor %} + {% endif %} + +
    +
    +
    Homopolymer tracts (longer 4 bp)
    +
    + {% if homopol_tracts %} + {% for tract in homopol_tracts %} +

    {{tract}}

    + {% endfor %} + {% endif %} +
    +
    +
    + + + + +
    + + + + + + + + + + + diff --git a/verification_seq.py b/verification_seq.py new file mode 100644 index 0000000..e3a9dad --- /dev/null +++ b/verification_seq.py @@ -0,0 +1,25 @@ +class InputDNA: + + dna_symbols = ["a", "t", "g", "c", "u", "n"] #допустимые символы + + def __init__(self, sequence:str) -> str: + self.initial_seq = sequence.lower().strip() #приводим к нижнему регистру и стрипим + self.counter = 0 # счетчик недопустимых символов + self.is_uracil = 0 + self.is_non_identified = 0 + self.__seq_format = [] # список для отформатированной строки, где удаляем недопустимые символы + for symbol in self.initial_seq: + if symbol in InputDNA.dna_symbols: # посимвольное сравнение элемента исходной строки и добавление в новую, если символ допустимый + if symbol == 'u': #заменяем u на t, записываем что нашли РНК символы + self.__seq_format.append('t') + self.is_uracil += 1 + else: + self.__seq_format.append(symbol) + if symbol == 'n': #такие тоже бывают при ошибках в секвенаторе - их лучше не удалять, но логировать + self.is_non_identified += 1 + else: + self.counter += 1 # если находим недопустимый символ + + self.formated_sequence = "".join(self.__seq_format) # отформатированный список преобразовываем в строку + self.input_lenth = len(self.formated_sequence) +