class Lg_addFiles(QDialog, Ui_addFile, object): closeGUI_signal = pyqtSignal() inputSig = pyqtSignal(list, list, bool, str) inputContentSig = pyqtSignal(str, str) exception_signal = pyqtSignal(str) progressDiologSig = pyqtSignal(int) fastaDownloadFinishedSig = pyqtSignal(str) inputFasSig = pyqtSignal(str, str) def __init__(self, exportPath=None, parent=None): super(Lg_addFiles, self).__init__(parent) self.factory = Factory() self.parent = parent self.thisPath = self.factory.thisPath self.exportPath = exportPath # 保存设置 self.addFiles_settings = QSettings( self.thisPath + '/settings/addFiles_settings.ini', QSettings.IniFormat) self.closeGUI_signal.connect(self.close) self.progressDiologSig.connect(self.runProgressDialog) # self.close() 不能在信号槽里面 self.fastaDownloadFinishedSig.connect(self.parent.setTreeViewFocus) # 开始装载样式表 with open(self.thisPath + os.sep + 'style.qss', encoding="utf-8", errors='ignore') as f: self.qss_file = f.read() self.setStyleSheet(self.qss_file) self.setupUi(self) self.guiRestore() self.exception_signal.connect(self.popupException) self.interrupt = False self.label_3.clicked.connect(lambda : QDesktopServices.openUrl(QUrl( "https://dongzhang0725.github.io/dongzhang0725.github.io/documentation/#4-3-1-1-Brief-example"))) def fetSeqFromNCBI(self, id_array): batch_size = 20 count = len(id_array) download_contents = "" for start in range(0, count, batch_size): if self.interrupt: return end = min(count, start + batch_size) print("Going to download record %i to %i" % (start + 1, end)) if (start + batch_size) > count: batch_size = count - start Entrez.email = self.email if self.email else "*****@*****.**" fetch_handle = Entrez.efetch(db="nucleotide", rettype=self.rettype, retmode="text", retstart=start, retmax=batch_size, id=id_array) download_contents += fetch_handle.read() self.progressDiologSig.emit(end * 100 / count) if self.rettype == "gb": self.inputContentSig.emit( download_contents, self.outputPath) else: with open(self.outputPath + os.sep + self.fasta_file_name, "w", encoding="utf-8") as f: f.write(download_contents) self.fastaDownloadFinishedSig.emit(self.outputPath) # result_handle = Entrez.efetch( # db="nucleotide", rettype="gb", id=id_array, retmode="text") # # with open(self.exportPath + os.sep + "new.gb", "w", encoding="utf-8") as f2: # # f2.write(result_handle.read()) # self.inputContentSig.emit( # result_handle.read(), []) @pyqtSlot() def on_pushButton_clicked(self): self.outputPath = self.fetchOutputPath() if self.parent.isWorkFolder(self.outputPath, mode="gb"): files = QFileDialog.getOpenFileNames( self, "Input GenBank Files", filter="GenBank and Fasta Format (*.gb *.gbk *.gbf *.gp *.gbff *.fas *.fasta);;") if files[0]: list_gbs = [] list_fas = [] for i in files[0]: if os.path.splitext(i)[1].upper() in [".GB", ".GBK", ".GP", ".GBF", ".GBFF"]: list_gbs.append(i) elif os.path.splitext(i)[1].upper() in [".FAS", ".FASTA"]: list_fas.append(i) if list_gbs: self.inputSig.emit(list_gbs, [], False, self.outputPath) if list_fas: fasContent = "" for i in list_fas: with open(i, encoding="utf-8", errors='ignore') as f: fasContent += f.read() + "\n" self.inputFasSig.emit(fasContent, self.outputPath) self.close() self.deleteLater() del self else: files = QFileDialog.getOpenFileNames( self, "Input Files", filter="Supported Format (*.docx *.doc *.odt *.docm *.dotx *.dotm *.dot " "*.fas *.fasta *.phy *.phylip *.nex *.nxs *.nexus);;") if files[0]: self.inputSig.emit([], files[0], False, self.outputPath) self.close() self.deleteLater() del self @pyqtSlot() def on_pushButton_2_clicked(self): # download self.interrupt = False text_content = self.plainTextEdit.toPlainText() if text_content: self.outputPath = self.fetchOutputPath() self.rettype = "gb" if self.parent.isWorkFolder(self.outputPath, mode="gb") else "fasta" if self.rettype == "fasta": name, ok = QInputDialog.getText( self, 'Set output file name', 'Output file name:', text="sequence.fas") if ok: self.fasta_file_name = name + ".fas" if "." not in name else name if os.path.exists(self.outputPath + os.sep + self.fasta_file_name): reply = QMessageBox.question( self, "Concatenate sequence", "<p style='line-height:25px; height:25px'>The file exists, replace it?</p>", QMessageBox.Yes, QMessageBox.Cancel) if reply == QMessageBox.Cancel: return else: QMessageBox.information( self, "Information", "<p style='line-height:25px; height:25px'>Download canceled!</p>") return self.downloadState("start") self.progressDialog = self.factory.myProgressDialog( "Please Wait", "Downloading...", parent=self) self.progressDialog.show() self.id_array = re.split(r"\s|,", text_content) while "" in self.id_array: self.id_array.remove("") self.email = self.lineEdit.text() self.worker_download = WorkThread(self.run_command, parent=self) self.progressDialog.canceled.connect(lambda: [setattr(self, "interrupt", True), self.worker_download.stopWork(), self.progressDialog.close(), self.downloadState("stop")]) self.worker_download.start() else: QMessageBox.information( self, "Information", "<p style='line-height:25px; height:25px'>Please input ID(s) first</p>") @pyqtSlot() def on_pushButton_8_clicked(self): #search in NCBI self.close() self.parent.on_SerhNCBI_triggered() @pyqtSlot() def on_toolButton_clicked(self): info = '''To make use of NCBI's E-utilities, NCBI requires you to specify your email address with each request.<br> In case of excessive usage of the E-utilities, NCBI will attempt to contact a user at the email address provided before blocking access to the E-utilities.''' QMessageBox.information( self, "Information", "<p style='line-height:25px; height:25px'>%s</p>"%info) def run_command(self): try: self.fetSeqFromNCBI(self.id_array) self.closeGUI_signal.emit() except BaseException: self.exceptionInfo = ''.join( traceback.format_exception( *sys.exc_info())) # 捕获报错内容,只能在这里捕获,没有报错的地方无法捕获 self.exception_signal.emit(self.exceptionInfo) # self.popupException(self.exceptionInfo) # 激发这个信号 def popupException(self, exception): msg = QMessageBox(self) msg.setIcon(QMessageBox.Critical) msg.setText( 'The program encountered an unforeseen problem, please report the bug at <a href="https://github.com/dongzhang0725/PhyloSuite/issues">https://github.com/dongzhang0725/PhyloSuite/issues</a> or send an email with the detailed traceback to [email protected]') msg.setWindowTitle("Error") msg.setDetailedText(exception) msg.setStandardButtons(QMessageBox.Ok) msg.exec_() self.pushButton_2.setEnabled(True) self.pushButton_2.setStyleSheet(self.qss_file) self.pushButton_2.setText("Start") def guiSave(self): # Save geometry self.addFiles_settings.setValue('size', self.size()) # self.addFiles_settings.setValue('pos', self.pos()) # for name, obj in inspect.getmembers(self): # if type(obj) is QComboBox: # this works similar to isinstance, but # missed some field... not sure why? # if isinstance(obj, QTextBrowser): # # save combobox selection to registry # htmlText = obj.toHtml() # self.addFiles_settings.setValue(name, htmlText) def guiRestore(self): # Restore geometry self.resize(self.addFiles_settings.value('size', QSize(500, 500))) # self.move(self.addFiles_settings.value('pos', QPoint(875, 254))) for name, obj in inspect.getmembers(self): if isinstance(obj, QComboBox): if name == "comboBox": allItems = self.factory.fetchAllWorkFolders(self.exportPath) model = obj.model() obj.clear() for num, i in enumerate(allItems): if self.parent.isWorkFolder(i, mode="gb"): text = "\"%s\" in GenBank_File (GenBank format)"%os.path.basename(i) else: text = "\"%s\" in Other_File" % os.path.basename(i) item = QStandardItem(text) item.setToolTip(i) # 背景颜色 if num % 2 == 0: item.setBackground(QColor(255, 255, 255)) else: item.setBackground(QColor(237, 243, 254)) model.appendRow(item) if self.parent.isWorkFolder(self.exportPath, mode="gb"): obj.setCurrentText("\"%s\" in GenBank_File (GenBank format)"%os.path.basename(self.exportPath)) else: obj.setCurrentText("\"%s\" in Other_File" % os.path.basename(self.exportPath)) def closeEvent(self, event): self.interrupt = True if hasattr(self, "worker_download"): self.worker_download.stopWork() if hasattr(self, "progressDialog"): self.progressDialog.close() self.guiSave() def runProgressDialog(self, num): oldValue = self.progressDialog.value() done_int = int(num) if done_int > oldValue: self.progressDialog.setProperty("value", done_int) QCoreApplication.processEvents() if done_int == 100: self.progressDialog.close() def fetchOutputPath(self): index = self.comboBox.currentIndex() return self.comboBox.itemData(index, role=Qt.ToolTipRole) def downloadState(self, state): if state == "start": self.pushButton_2.setEnabled(False) # 使之失效 self.pushButton_2.setStyleSheet( 'QPushButton {color: red; background-color: rgb(219, 217, 217)}') self.pushButton_2.setText("Downloading...") elif state == "stop": self.pushButton_2.setText("Download") self.pushButton_2.setStyleSheet(self.qss_file) self.pushButton_2.setEnabled(True)
class Lg_ReANNT(QDialog, Ui_tRNA_ANNT, object): progressSig = pyqtSignal(int) # 控制进度条 startButtonStatusSig = pyqtSignal(list) close_sig = pyqtSignal() exception_signal = pyqtSignal(str) # 定义所有类都可以使用的信号 def __init__(self, unRecognisetRNA=None, gbContent=None, predict_signal=None, parent=None): super(Lg_ReANNT, self).__init__(parent) # self.thisPath = os.path.dirname(os.path.realpath(__file__)) self.factory = Factory() self.thisPath = self.factory.thisPath self.setupUi(self) self.textBrowser.setText(unRecognisetRNA) self.gbContent = gbContent self.predict_signal = predict_signal self.totaltRNA = unRecognisetRNA.count(">") # 开始装载样式表 with open(self.thisPath + os.sep + 'style.qss', encoding="utf-8", errors='ignore') as f: self.qss_file = f.read() self.setStyleSheet(self.qss_file) # 信号和槽 self.progressSig.connect(self.normProgress) self.close_sig.connect(self.closeWindow) self.exception_signal.connect(self.popupException) @pyqtSlot() def on_pushButton_clicked(self): text = self.textBrowser.toPlainText() fileName = QFileDialog.getSaveFileName( self, "Predict tRNA", "tRNAs", "fasta Format(*.fas)") if fileName[0]: with open(fileName[0], "w", encoding="utf-8") as f: f.write(text) QMessageBox.information( self, "Predict tRNA", "<p style='line-height:25px; height:25px'>File saved successfully!</p>") @pyqtSlot() def on_pushButton_2_clicked(self): self.arwenContents = self.textBrowser_2.toPlainText() if self.arwenContents: # 进度条 self.progressDialog = self.factory.myProgressDialog( "Please Wait", "replacing...", parent=self) self.progressDialog.show() self.worker = WorkThread(self.run_command, parent=self) self.worker.start() else: QMessageBox.information( self, "Predict tRNA", "<p style='line-height:25px; height:25px'>No ARWEN results found!</p>") def run_command(self): try: # raise BaseException self.startButtonStatusSig.emit( [ self.pushButton_2, None, "start", None, self.qss_file, self]) self.reANNT = ReANNT( self.arwenContents, self.gbContent, self.totaltRNA, self.progressSig) self.startButtonStatusSig.emit( [self.pushButton_2, None, "simple stop", None, self.qss_file, self]) self.close_sig.emit() except BaseException: self.exceptionInfo = ''.join( traceback.format_exception( *sys.exc_info())) # 捕获报错内容,只能在这里捕获,没有报错的地方无法捕获 self.exception_signal.emit(self.exceptionInfo) # 激发这个信号 self.startButtonStatusSig.emit( [ self.pushButton, self.progressBar, "except", self.dict_args["exportPath"], self.qss_file, self]) def normProgress(self, num): oldValue = self.progressDialog.value() done_int = int(num) if done_int > oldValue: self.progressDialog.setProperty("value", done_int) QCoreApplication.processEvents() if done_int == 100: self.progressDialog.close() def closeWindow(self): self.progressDialog.close() self.close() self.predict_signal.emit(self.reANNT.gbContent) def popupException(self, exception): msg = QMessageBox(self) msg.setIcon(QMessageBox.Critical) msg.setText( 'The program encountered an unforeseen problem, please report the bug at <a href="https://github.com/dongzhang0725/PhyloSuite/issues">https://github.com/dongzhang0725/PhyloSuite/issues</a> or send an email with the detailed traceback to [email protected]') msg.setWindowTitle("Error") msg.setDetailedText(exception) msg.setStandardButtons(QMessageBox.Ok) msg.exec_()
class SerhNCBI(QMainWindow, Ui_SerhNCBI, object): exception_signal = pyqtSignal(str) # 定义所有类都可以使用的信号 updateSig = pyqtSignal(list) searchSig = pyqtSignal(str) progressBarSig = pyqtSignal(int) # 控制进度条 progressDiologSig = pyqtSignal(int) ctrlItemsSig = pyqtSignal(int) inputContentSig = pyqtSignal(str, str) downloadFinished = pyqtSignal() fastaDownloadFinishedSig = pyqtSignal(str) def __init__(self, workPath=None, parent=None): super(SerhNCBI, self).__init__(parent) # self.thisPath = os.path.dirname(os.path.realpath(__file__)) self.parent = parent self.factory = Factory() self.thisPath = self.factory.thisPath self.workPath = workPath self.setupUi(self) # 保存设置 self.serhNCBI_settings = QSettings( self.thisPath + '/settings/serhNCBI_settings.ini', QSettings.IniFormat) # File only, no fallback to registry or or. self.serhNCBI_settings.setFallbacksEnabled(False) # 开始装载样式表 with open(self.thisPath + os.sep + 'style.qss', encoding="utf-8", errors='ignore') as f: self.qss_file = f.read() self.setStyleSheet(self.qss_file) # 恢复用户的设置 self.guiRestore() self.exception_signal.connect(self.popupException) # self.progressSig.connect(self.runProgress) # self.logGuiSig.connect(self.addText2Log) self.lineEdit.buttonSearch.clicked.connect(lambda: [ self.startSearch(), self.sync_completer_texts(self.lineEdit.text()) ]) self.lineEdit.buttonStop.clicked.connect(self.stopSearch) # self.lineEdit.completer().popup().show() # self.lineEdit.clicked.connect(lambda : self.lineEdit.completer().popup()) self.dict_ncbi_headers = { "GBSeq_accession-version": "ID", "GBSeq_definition": "Description", "GBSeq_organism": "Organism", "GBSeq_length": "Length", "GBSeq_update-date": "Update date", "GBSeq_taxonomy": "Taxonomy", "GBSeq_create-date": "Create date", "GBSeq_moltype": "Molecular type", "GBSeq_topology": "Topology", "GBSeq_references": "References", "GBSeq_source": "Source", "GBSeq_keywords": "Keywords", "GBSeq_project": "Project", "GBSeq_other-seqids": "Other IDs", "GBSeq_strandedness": "Strandedness", "GBSeq_comment": "Comments" } self.init_list() self.updateSig.connect(self.updateTable) self.searchSig.connect(self.ctrlSearchState) self.progressBarSig.connect(self.searchProgress) self.progressDiologSig.connect(self.runProgressDialog) self.spinBox.valueChanged.connect(self.sync_display_items) self.ctrlItemsSig.connect(self.ctrlItems) # self.downloadFinished.connect(self.downloadDone) self.fastaDownloadFinishedSig.connect(self.parent.setTreeViewFocus) self.NCBI_model = MyNCBITableModel([self.list_table_header], parent=self) self.tableView.setModel(self.NCBI_model) header = CheckBoxHeader(parent=self.tableView) header.clicked.connect(self.check_displayed) self.tableView.setHorizontalHeader(header) self.NCBI_model.checkedChanged.connect(self.ctrl_text) self.interrupt = False ##下载的状态 widget = QWidget(self) horizBox = QHBoxLayout(widget) horizBox.setContentsMargins(0, 0, 0, 0) spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.disp_check_label = QLabel( "<span style='font-weight:600; color:red;'>Searching...</span>", self) self.disp_check_gifLabel = QLabel(self) movie = QMovie(":/picture/resourses/Spinner-1s-34px.gif") self.disp_check_gifLabel.setMovie(movie) self.disp_check_progress = QProgressBar(self) self.disp_check_progress.setFixedWidth(100) movie.start() horizBox.addItem(spacerItem) horizBox.addWidget(self.disp_check_gifLabel) horizBox.addWidget(self.disp_check_label) horizBox.addWidget(self.disp_check_progress) self.statusbar.addPermanentWidget(widget) self.disp_check_label.setVisible(False) self.disp_check_gifLabel.setVisible(False) self.disp_check_progress.setVisible(False) self.lineEdit.installEventFilter(self) self.spinBox.installEventFilter(self) table_popMenu = QMenu(self) table_popMenu.setToolTipsVisible(True) OpenID = QAction(QIcon(":/seq_Viewer/resourses/field-Display.png"), "Open in NCBI webpage", self, triggered=self.openID) OpenID.setToolTip("Open sequence in NCBI webpage") table_popMenu.addAction(OpenID) def table_popmenu(qpoint): if self.tableView.indexAt(qpoint).isValid(): table_popMenu.exec_(QCursor.pos()) self.tableView.setContextMenuPolicy(Qt.CustomContextMenu) self.tableView.customContextMenuRequested.connect(table_popmenu) # self.tableView.horizontalHeader().resizeSection(1, 300) # self.tableView.horizontalHeader().resizeSection(2, 80) # ##增加check按钮 # self.check_all = QCheckBox("Check/Uncheck", self) # self.check_all.toggled.connect(self.check_displayed) # self.statusbar.addWidget(self.check_all) ## brief demo self.label_6.clicked.connect(lambda: QDesktopServices.openUrl( QUrl( "https://dongzhang0725.github.io/dongzhang0725.github.io/documentation/#4-3-3-1-Brief-example" ))) @pyqtSlot() def on_toolButton_clicked(self): info = '''To make use of NCBI's E-utilities, NCBI requires you to specify your email address with each request.<br> In case of excessive usage of the E-utilities, NCBI will attempt to contact a user at the email address provided before blocking access to the E-utilities.''' QMessageBox.information( self, "Information", "<p style='line-height:25px; height:25px'>%s</p>" % info) @pyqtSlot() def on_toolButton_2_clicked(self): #refresh self.interrupt = False self.exist_base = self.NCBI_model.rowCount(self.tableView) if not self.exist_base: return if hasattr(self, "worker_addition") and self.worker_addition.isRunning(): return if self.display_items > self.exist_base: self.worker_addition = WorkThread(self.addition_search, parent=self) self.worker_addition.start() # elif self.display_items < self.exist_base: # list_checked = self.NCBI_model.list_checked # array = self.NCBI_model.array[:self.display_items+1] # self.NCBI_model = MyNCBITableModel(array, list_checked, self.tableView) # self.tableView.setModel(self.NCBI_model) # self.tableView.update() @pyqtSlot() def on_toolButton_3_clicked(self): # download index = self.comboBox.currentIndex() self.outputPath = self.comboBox.itemData(index, role=Qt.ToolTipRole) self.rettype = "gb" if self.parent.isWorkFolder(self.outputPath, mode="gb") else "fasta" if self.rettype == "fasta": name, ok = QInputDialog.getText(self, 'Set output file name', 'Output file name:', text="sequence.fas") if ok: self.fasta_file_name = name + ".fas" if "." not in name else name if os.path.exists(self.outputPath + os.sep + self.fasta_file_name): reply = QMessageBox.question( self, "Concatenate sequence", "<p style='line-height:25px; height:25px'>The file exists, replace it?</p>", QMessageBox.Yes, QMessageBox.Cancel) if reply == QMessageBox.Cancel: return else: QMessageBox.information( self, "Information", "<p style='line-height:25px; height:25px'>Download canceled!</p>" ) return if self.NCBI_model.arraydata: self.interrupt = False self.progressDialog = self.factory.myProgressDialog( "Please Wait", "Downloading...", parent=self) self.progressDialog.show() self.worker_download = WorkThread(self.downloadSeq, parent=self) self.progressDialog.canceled.connect(lambda: [ setattr(self, "interrupt", True), self.worker_download.stopWork(), self.progressDialog.close() ]) self.worker_download.finished.connect(self.downloadDone) self.worker_download.start() else: QMessageBox.information( self, "Information", "<p style='line-height:25px; height:25px'>Please search first!</p>" ) def downloadSeq(self): try: checked_ids = self.NCBI_model.list_checked # if not checked_ids: # checked_ids = self.NCBI_model.fetchAllIDs() batch_size = 20 count = len(checked_ids) if checked_ids else self.count self.download_contents = "" for start in range(0, count, batch_size): if self.interrupt: return end = min(count, start + batch_size) print("Going to download record %i to %i" % (start + 1, end)) if (start + batch_size) > count: batch_size = count - start if not checked_ids: #下载所有序列的模式 fetch_handle = Entrez.efetch(db=self.database, rettype=self.rettype, retmode="text", retstart=start, retmax=batch_size, webenv=self.webenv, query_key=self.query_key) else: fetch_handle = Entrez.efetch(db=self.database, rettype=self.rettype, retmode="text", retstart=start, retmax=batch_size, id=checked_ids) self.download_contents += fetch_handle.read() self.progressDiologSig.emit(end * 100 / count) # index = self.comboBox.currentIndex() # filepath = self.comboBox.itemData(index, role=Qt.ToolTipRole) # self.downloadFinished.emit() except: self.exception_signal.emit(''.join( traceback.format_exception(*sys.exc_info()))) def downloadDone(self): self.progressDialog.close() QMessageBox.information( self, "Download finished", "<p style='line-height:25px; height:25px'>Done! Back to home page to view them.</p>" ) if self.rettype == "gb": self.inputContentSig.emit(self.download_contents, self.outputPath) else: with open(self.outputPath + os.sep + self.fasta_file_name, "w", encoding="utf-8") as f: f.write(self.download_contents) self.fastaDownloadFinishedSig.emit(self.outputPath) def startSearch(self): if hasattr(self, "worker") and self.worker.isRunning(): return if self.spinBox.value() == 0: self.spinBox.setValue(20) if self.lineEdit.text(): self.interrupt = False self.NCBI_model.init_table() #刷新一下table(归零) self.worker = WorkThread(self.search, parent=self) self.worker.start() else: QMessageBox.information( self, "Search in NCBI", "<p style='line-height:25px; height:25px'>Please input keywords first!</p>" ) def guiSave(self): # Save geometry self.serhNCBI_settings.setValue('size', self.size()) # self.serhNCBI_settings.setValue('pos', self.pos()) for name, obj in inspect.getmembers(self): # if type(obj) is QComboBox: # this works similar to isinstance, but # missed some field... not sure why? # if isinstance(obj, QComboBox): # # save combobox selection to registry # text = obj.currentText() # if text: # allItems = [ # obj.itemText(i) for i in range(obj.count())] # allItems.remove(text) # sortItems = [text] + allItems # self.serhNCBI_settings.setValue(name, sortItems) if isinstance(obj, QLineEdit): if name == "lineEdit": self.serhNCBI_settings.setValue(name, self.completer_texts) if isinstance(obj, QSpinBox): if name == "spinBox": self.serhNCBI_settings.setValue(name, self.display_items) def guiRestore(self): # Restore geometry self.resize(self.serhNCBI_settings.value('size', QSize(1000, 600))) self.factory.centerWindow(self) # self.move(self.serhNCBI_settings.value('pos', QPoint(875, 254))) for name, obj in inspect.getmembers(self): if isinstance(obj, QComboBox): if name == "comboBox": allItems = self.factory.fetchAllWorkFolders(self.workPath) model = obj.model() obj.clear() for num, i in enumerate(allItems): if self.parent.isWorkFolder(i, mode="gb"): text = "\"%s\" in GenBank_File (GenBank format)" % os.path.basename( i) else: text = "\"%s\" in Other_File (Fasta format)" % os.path.basename( i) item = QStandardItem(text) item.setToolTip(i) # 背景颜色 if num % 2 == 0: item.setBackground(QColor(255, 255, 255)) else: item.setBackground(QColor(237, 243, 254)) model.appendRow(item) # obj.setCurrentText(os.path.basename(self.workPath)) if self.parent.isWorkFolder(self.workPath, mode="gb"): obj.setCurrentText( "\"%s\" in GenBank_File (GenBank format)" % os.path.basename(self.workPath)) else: obj.setCurrentText( "\"%s\" in Other_File (Fasta format)" % os.path.basename(self.workPath)) if isinstance(obj, QLineEdit): if name == "lineEdit": self.completer_texts = self.serhNCBI_settings.value( name, []) # get stored value from registry self.setLCompleter() if isinstance(obj, QSpinBox): if name == "spinBox": self.display_items = int( self.serhNCBI_settings.value( name, 100)) # get stored value from registry obj.setValue(self.display_items) def runProgressDialog(self, num): oldValue = self.progressDialog.value() done_int = int(num) if done_int > oldValue: self.progressDialog.setProperty("value", done_int) QCoreApplication.processEvents() if done_int == 100: self.progressDialog.close() def popupException(self, exception): if ("getaddrinfo failed" in exception) or ("RuntimeError" in exception): text = "<p style='line-height:25px; height:25px'>Search failed, try to check your network connection!</p>" else: text = "<p style='line-height:25px; height:25px'>The search failed for some of the sequences. As this may have been caused by a network problem, you can wait for a while and try again.<br> If the problem persists you may report it at " \ "<a href=\"https://github.com/dongzhang0725/PhyloSuite/issues\">https://github.com/dongzhang0725/PhyloSuite/issues</a> " \ "or send an email with the detailed traceback to [email protected]</p>" msg = QMessageBox(self) msg.setIcon(QMessageBox.Critical) msg.setText(text) msg.setWindowTitle("Error") msg.setDetailedText(exception) msg.setStandardButtons(QMessageBox.Ok) msg.exec_() def closeEvent(self, event): self.interrupt = True if hasattr(self, "worker") and self.worker.isRunning(): self.worker.stopWork() if hasattr(self, "worker_addition") and self.worker_addition.isRunning(): self.worker_addition.stopWork() if hasattr(self, "worker_download") and self.worker_download.isRunning(): self.worker_download.stopWork() if hasattr(self, "progressDialog"): self.progressDialog.close() self.guiSave() # self.log_gui.close() # 关闭子窗口 def eventFilter(self, obj, event): name = obj.objectName() if event.type() == QEvent.KeyPress: # 首先得判断type if event.key() == Qt.Key_Return: if name == "lineEdit": self.sync_completer_texts(self.lineEdit.text()) self.startSearch() return True if name == "spinBox": self.on_toolButton_2_clicked() return True # return QMainWindow.eventFilter(self, obj, event) # # 其他情况会返回系统默认的事件处理方法。 return super(SerhNCBI, self).eventFilter(obj, event) # 0 def sync_completer_texts(self, text): if text and (text not in self.completer_texts): self.completer_texts.insert(0, text) if len(self.completer_texts) > 15: self.completer_texts = self.completer_texts[:15] self.guiSave() self.setLCompleter() def setLCompleter(self): comp = QCompleter(self.completer_texts) comp.setFilterMode(Qt.MatchContains) comp.setCompletionMode(QCompleter.UnfilteredPopupCompletion) # comp.popup().setStyleSheet("background-color: yellow") self.lineEdit.setCompleter(comp) def init_list(self): self.list_table_header = [ "ID", "Description", "Organism", "Length", "Update date", "Taxonomy", "Create date", "Molecular type", "Topology", "References", "Source", "Keywords", "Project", "Other IDs", "Strandedness", "Comments" ] def updateTable(self, list_): # print(array) # 测试array是新添加的list self.NCBI_model.appendTable(list_) def ctrlSearchState(self, state): if state == "searching": self.disp_check_label.setText("Searching...") self.disp_check_label.setVisible(True) self.disp_check_gifLabel.setVisible(True) self.lineEdit.buttonSearch.setDisabled(True) self.lineEdit.buttonStop.setDisabled(False) self.toolButton_2.setDisabled(True) self.toolButton_3.setDisabled(True) elif state == "fetching": self.disp_check_label.setText("Fetching...") self.disp_check_label.setVisible(True) self.disp_check_gifLabel.setVisible(True) self.disp_check_progress.setValue(0) self.disp_check_progress.setVisible(True) self.lineEdit.buttonStop.setDisabled(False) elif state == "except": self.disp_check_label.setVisible(False) self.disp_check_gifLabel.setVisible(False) self.disp_check_progress.setVisible(False) self.lineEdit.buttonSearch.setDisabled(False) self.lineEdit.buttonStop.setDisabled(True) self.toolButton_2.setDisabled(False) self.toolButton_3.setDisabled(False) elif state == "finished": self.disp_check_label.setVisible(False) self.disp_check_gifLabel.setVisible(False) self.disp_check_progress.setVisible(False) self.lineEdit.buttonSearch.setDisabled(False) self.lineEdit.buttonStop.setDisabled(True) self.toolButton_2.setDisabled(False) self.toolButton_3.setDisabled(False) ##如果啥也没搜到 self.exist_base = self.NCBI_model.rowCount(self.tableView) if not self.exist_base: QMessageBox.information( self, "Download finished", "<p style='line-height:25px; height:25px'>No items found!</p>" ) def ctrlItems(self, count): count = count if count != 0 else 20 self.spinBox.setMaximum(count) if count == 0: self.spinBox.setValue(20) self.label_4.setText("items of %s (total)" % count) self.label_2.setText("Download all (%s) sequences to:" % count) # if count < self.display_items: # self.display_items = count # self.spinBox.setValue(count) def searchProgress(self, value): oldValue = self.disp_check_progress.value() done_int = int(value) if done_int > oldValue: self.disp_check_progress.setProperty("value", done_int) QCoreApplication.processEvents() def sync_display_items(self, value): self.display_items = value def search(self): try: self.searchSig.emit("searching") self.init_list() self.ctrl_text() #文本还原 self.NCBI_model.list_checked = [] self.database = self.comboBox_2.currentText() keywords = self.lineEdit.text() email = self.lineEdit_2.text() email = email if email else "*****@*****.**" Entrez.email = email search_handle = Entrez.esearch(db=self.database, term=keywords, usehistory="y") search_results = Entrez.read(search_handle) self.webenv = search_results["WebEnv"] self.query_key = search_results["QueryKey"] self.count = int(search_results["Count"]) self.ctrlItemsSig.emit( self.count) #如果只有2个序列,self.display_items也会变成2 search_handle.close() batch_size = 20 self.searchSig.emit("fetching") # time_start = time.time() total_displayed = self.display_items if self.count < total_displayed: total_displayed = self.count for start in range(0, total_displayed, batch_size): # try: if self.interrupt: return end = min(total_displayed, start + batch_size) print("Going to download record %i to %i" % (start + 1, end)) if (start + batch_size) > total_displayed: batch_size = total_displayed - start fetch_handle = Entrez.efetch(db=self.database, retmode="xml", retstart=start, retmax=batch_size, webenv=self.webenv, query_key=self.query_key) fetch_records = Entrez.read(fetch_handle) for num, record in enumerate(fetch_records): list_ = [] for i in [ "GBSeq_accession-version", "GBSeq_definition", "GBSeq_organism", "GBSeq_length", "GBSeq_update-date", "GBSeq_taxonomy", "GBSeq_create-date", "GBSeq_moltype", "GBSeq_topology", "GBSeq_references", "GBSeq_source", "GBSeq_keywords", "GBSeq_project", "GBSeq_other-seqids", "GBSeq_strandedness", "GBSeq_comment" ]: if i in record: list_.append(str(record[i])) else: list_.append("N/A") self.updateSig.emit(list_) self.progressBarSig.emit( (start + num + 1) * 100 / total_displayed) fetch_handle.close() # except: # pass self.searchSig.emit("finished") except: self.searchSig.emit("except") self.exception_signal.emit(''.join( traceback.format_exception(*sys.exc_info()))) # time_end = time.time() # print("time:", time_end - time_start) def addition_search(self): try: total_displayed = self.display_items if self.count < total_displayed: total_displayed = self.count batch_size = 20 self.searchSig.emit("fetching") for start in range(self.exist_base, total_displayed, batch_size): if self.interrupt: break end = min(total_displayed, start + batch_size) print("Going to download record %i to %i" % (start + 1, end)) if (start + batch_size) > total_displayed: batch_size = total_displayed - start fetch_handle = Entrez.efetch(db=self.database, retmode="xml", retstart=start, retmax=batch_size, webenv=self.webenv, query_key=self.query_key) fetch_records = Entrez.read(fetch_handle) for num, record in enumerate(fetch_records): list_ = [] for i in [ "GBSeq_accession-version", "GBSeq_definition", "GBSeq_organism", "GBSeq_length", "GBSeq_update-date", "GBSeq_taxonomy", "GBSeq_create-date", "GBSeq_moltype", "GBSeq_topology", "GBSeq_references", "GBSeq_source", "GBSeq_keywords", "GBSeq_project", "GBSeq_other-seqids", "GBSeq_strandedness", "GBSeq_comment" ]: if i in record: list_.append(str(record[i])) else: list_.append("N/A") self.updateSig.emit(list_) self.progressBarSig.emit( (start - self.exist_base + num + 1) * 100 / (total_displayed - self.exist_base)) # self.progressBarSig.emit((start - self.exist_base)*100/(total_displayed - self.exist_base)) fetch_handle.close() self.searchSig.emit("finished") except: self.searchSig.emit("except") self.exception_signal.emit(''.join( traceback.format_exception(*sys.exc_info()))) def ctrl_text(self): selected_num = len(self.NCBI_model.list_checked) if selected_num: self.label_2.setText("Download selected (%d) sequences to:" % (selected_num)) else: text = "Download all (%d) sequences to:" % self.count if hasattr( self, "count") else "Download all sequences to:" self.label_2.setText(text) def openID(self): indices = self.tableView.selectedIndexes() arraydata = self.NCBI_model.arraydata ID = arraydata[indices[0].row()][0].text() url = "https://www.ncbi.nlm.nih.gov/nuccore/%s"%ID if self.comboBox_2.currentText() == "nucleotide" \ else "https://www.ncbi.nlm.nih.gov/protein/%s"%ID QDesktopServices.openUrl(QUrl(url)) def stopSearch(self): self.interrupt = True if hasattr(self, "worker") and self.worker.isRunning(): self.worker.stopWork() if hasattr(self, "worker_addition") and self.worker_addition.isRunning(): self.worker_addition.stopWork() self.searchSig.emit("except") def check_displayed(self, isCheck): if hasattr(self, "NCBI_model") and self.NCBI_model.rowCount( self.tableView): # self.NCBI_model.beginResetModel() self.NCBI_model.layoutAboutToBeChanged.emit() if isCheck: self.NCBI_model.list_checked = [ i[0].text() for i in self.NCBI_model.arraydata ] else: self.NCBI_model.list_checked = [] self.NCBI_model.layoutChanged.emit() self.ctrl_text()
class GbEditor(QDialog, Ui_GBeditor, object): progressSig = pyqtSignal(int) # 控制进度条 findSig = pyqtSignal() predict_signal = pyqtSignal(str) exception_signal = pyqtSignal(str) def __init__(self, nmlgb): self.dict_args = nmlgb.dict_args super(GbEditor, self).__init__(self.dict_args["parent"]) # self.thisPath = os.path.dirname(os.path.realpath(__file__)) self.factory = Factory() self.thisPath = self.factory.thisPath # 保存设置 self.gbEditor_settings = QSettings( self.thisPath + '/settings/gbEditor_settings.ini', QSettings.IniFormat, parent=self) # File only, no fallback to registry or or. self.gbEditor_settings.setFallbacksEnabled(False) self.settings_ini = QSettings(self.thisPath + '/settings/setting_settings.ini', QSettings.IniFormat) self.settings_ini.setFallbacksEnabled(False) self.setupUi(self) self.allcontent = nmlgb.allContent self.errors = nmlgb.errors self.warings = nmlgb.warnings self.unRecognisetRNA = nmlgb.unRecognisetRNA self.dict_replace = nmlgb.dict_replace self.workPath = self.dict_args["outpath"] self.showOn() # 信号和槽 self.progressSig.connect(self.normProgress) self.findSig.connect(self.popupFindOver) self.predict_signal.connect(self.reANNT_validate) self.exception_signal.connect(lambda x: self.factory.popupException(self, x)) # 开始装载样式表 with open(self.thisPath + os.sep + 'style.qss', encoding="utf-8", errors='ignore') as f: self.qss_file = f.read() self.setStyleSheet(self.qss_file) self.installEventFilter(self) self.guiRestore() self.checkBox.toggled.connect(self.askRemoveMisc) self.removeMISC = False def showOn(self): self.tableWidget.verticalHeader().setVisible(False) self.textBrowser.setHtml(self.allcontent) self.tableWidget.setColumnCount(3) self.tableWidget.setHorizontalHeaderLabels( ['Type', 'Indices', 'Description']) error_list = [str(i + 1) for i in range(len(self.errors))] warning_list = [str(i + 1) for i in range(len(self.warings))] combo_box_options = [error_list, warning_list] data1 = [ '%d Errors' % len(error_list), '%d Warnings' % len(warning_list)] self.combo_errors = QComboBox() self.combo_warnings = QComboBox() self.combo_errors.activated.connect(self.skip_description) self.combo_warnings.activated.connect(self.skip_description) self.combo_box_widget = [self.combo_errors, self.combo_warnings] self.combo_box_data = [self.errors, self.warings] self.tableWidget.setRowCount(2) def setColortoRow(table, rowIndex, color): # 颜色 for j in range(table.columnCount()): if j != 1: itemWid = table.item(rowIndex, j) if itemWid: itemWid.setBackground(color) colors = [QColor("red"), QColor("blue")] for row in range(2): item1 = QTableWidgetItem(data1[row]) item1.setForeground(QColor("white")) self.tableWidget.setItem(row, 0, item1) for t in combo_box_options[row]: self.combo_box_widget[row].addItem(t) self.tableWidget.setCellWidget( row, 1, self.combo_box_widget[row]) if self.combo_box_data[row] != []: # label = QLabel(self.combo_box_data[row][0][1], self) # setColortoRow(self.tableWidget, row, colors[row]) # self.tableWidget.setItem(row, 2, QTableWidgetItem("")) ##必须设置一个空去item,才能设置背景色 # self.tableWidget.setCellWidget( # row, 2, label) widget = QWidget(self) hlayout = QHBoxLayout(widget) hlayout.setContentsMargins(0, 0, 0, 0) spacerItem = QSpacerItem(50, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) hlayout.addItem(spacerItem) toolButton_2 = QToolButton(self) self.factory.highlightWidgets(toolButton_2) toolButton_2.setToolTip("Configure identifiers") # toolButton_2.setAutoRaise(True) toolButton_2.clicked.connect(self.openExtractSet) toolButton_2.setIcon(QIcon(":/picture/resourses/cog.png")) hlayout.addWidget(toolButton_2) self.tableWidget.setCellWidget(row, 2, widget) # print(self.combo_box_data[row][0][1]) # if not "identifiers" in self.combo_box_data[row][0][1]: # # print("no identifiers") # self.tableWidget.cellWidget(row, 2).setVisible(False) ##设置item item2 = QTableWidgetItem(self.combo_box_data[row][0][1]) item2.setForeground(QColor("white")) self.tableWidget.setItem(row, 2, item2) setColortoRow(self.tableWidget, row, colors[row]) else: # 当没有错误时 item2 = QTableWidgetItem( "No %s to display" % data1[row].split(" ")[1]) item2.setForeground(QColor("white")) self.tableWidget.setItem(row, 2, item2) setColortoRow(self.tableWidget, row, QColor("green")) # self.tableWidget.resizeColumnsToContents() ##模拟点击 # QTimer.singleShot(100, lambda: [self.tableWidget.cellWidget(0, 1).activated.emit(0), # self.tableWidget.cellWidget(1, 1).activated.emit(0)]) def skip_description(self, index): current_comb_box = self.sender() rowIndex = self.combo_box_widget.index(current_comb_box) # 0行是error,1行是waring content_data = self.combo_box_data[rowIndex] # description item = QTableWidgetItem(content_data[index][1]) item.setForeground(QColor("white")) color = QColor("red") if rowIndex == 0 else QColor("blue") widget = self.tableWidget.cellWidget(rowIndex, 2) if "identifiers" in content_data[index][1]: widget.setVisible(True) else: widget.setVisible(False) self.tableWidget.setItem(rowIndex, 2, item) # 保持颜色 self.tableWidget.item(rowIndex, 2).setBackground(color) # 跳转到指定位置 f = Find( parent=self.textBrowser, target=content_data[index][0], sig=self.findSig) @pyqtSlot() def on_pushButton_clicked(self): # text = self.textBrowser.toPlainText() f = Find(parent=self.textBrowser) f.show() @pyqtSlot() def on_pushButton_2_clicked(self, predict=False): ''' validate, predict即预测过后执行这个 ''' currentContent = self.textBrowser.toPlainText() totalID = currentContent.count("//") # 进度条 self.progressDialog = self.factory.myProgressDialog( "Please Wait", "validating...", parent=self) ##替换掉misc_feature的内容 if self.removeMISC: rgx_miscfeature = re.compile(r"(?sm) misc_feature.+?(?= \w|^\w)") currentContent = rgx_miscfeature.sub("", currentContent) self.progressDialog.show() self.dict_args["MarkNCR"] = self.checkBox.isChecked() self.dict_args["ncrLenth"] = self.spinBox.value() self.dict_args["progressSig"] = self.progressSig self.dict_args["gbContents"] = currentContent self.dict_args["outpath"] = self.workPath self.dict_args["totalID"] = totalID nmlgb = Normalize_MT(**self.dict_args) self.progressDialog.close() self.allcontent = nmlgb.allContent self.errors = nmlgb.errors self.warings = nmlgb.warnings self.showOn() QMessageBox.information( self, "GenBank file editor", "<p style='line-height:25px; height:25px'>Validation complete!!</p>") # @pyqtSlot() # def on_pushButton_6_clicked(self): # ''' # save # ''' # currentContent = self.textBrowser.toPlainText() # gbManager = GbManager(self.workPath, parent=self) # gbManager.addRefinedContent(currentContent) # gbManager.close() # QMessageBox.information(self, # "GenBank file editor", "<p style='line-height:25px; height:25px'>File saved succesfully!</p>") @pyqtSlot() def on_pushButton_7_clicked(self): ''' PREDICT TRNA ''' if self.unRecognisetRNA: currentContent = self.textBrowser.toPlainText() self.Lg_ReANNT = Lg_ReANNT( self.unRecognisetRNA, currentContent, self.predict_signal, parent=self) # 添加最大化按钮 self.Lg_ReANNT.setWindowFlags(self.Lg_ReANNT.windowFlags() | Qt.WindowMinMaxButtonsHint) self.Lg_ReANNT.show() # self.textBrowser.setText(self.unRecognisetRNA) else: QMessageBox.information(self, "GenBank file editor", "<p style='line-height:25px; height:25px'>No tRNA(s) needing predict</p>") def normProgress(self, num): oldValue = self.progressDialog.value() done_int = int(num) if done_int > oldValue: self.progressDialog.setProperty("value", done_int) QCoreApplication.processEvents() if done_int == 100: self.progressDialog.close() def popupFindOver(self): reply = QMessageBox.information( self, "GenBank file editor", 'This item has changed, please click "validate" button to validate changes', QMessageBox.Yes, QMessageBox.Cancel) if reply == QMessageBox.Yes: self.on_pushButton_2_clicked() def eventFilter(self, obj, event): modifiers = QApplication.keyboardModifiers() if event.type() == QEvent.KeyPress: # 首先得判断type if (modifiers == Qt.ControlModifier) and (event.key() == Qt.Key_S): self.on_pushButton_6_clicked() return True if (modifiers == Qt.ControlModifier) and (event.key() == Qt.Key_F): self.on_pushButton_clicked() return True return super(GbEditor, self).eventFilter(obj, event) def guiSave(self): # Save geometry self.gbEditor_settings.setValue('size', self.size()) # self.gbEditor_settings.setValue('pos', self.pos()) def guiRestore(self): # Restore geometry self.resize(self.gbEditor_settings.value('size', QSize(600, 600))) self.factory.centerWindow(self) # self.move(self.gbEditor_settings.value('pos', QPoint(875, 254))) def closeEvent(self, event): self.guiSave() def reANNT_validate(self, gbContent): totalID = gbContent.count("//") # 进度条 self.progressDialog = self.factory.myProgressDialog( "Please Wait", "validating...", parent=self) self.progressDialog.show() self.dict_args["progressSig"] = self.progressSig self.dict_args["gbContents"] = gbContent self.dict_args["outpath"] = self.workPath self.dict_args["totalID"] = totalID nmlgb = Normalize_MT(**self.dict_args) self.progressDialog.close() self.allcontent = nmlgb.allContent self.errors = nmlgb.errors self.warings = nmlgb.warnings self.showOn() QMessageBox.information( self, "GenBank file editor", "<p style='line-height:25px; height:25px'>Validation complete!!</p>") def openExtractSet(self): """ GenBank file extract settings """ self.extract_setting = ExtractSettings(self) self.extract_setting.closeSig.connect(self.saveExtractSet) # 添加最大化按钮 self.extract_setting.setWindowFlags(self.extract_setting.windowFlags() | Qt.WindowMinMaxButtonsHint) self.extract_setting.exec_() def saveExtractSet(self, dict_gbExtract_set): dict_settings = dict_gbExtract_set[list(dict_gbExtract_set.keys())[0]] changed = False for i in self.dict_args: if i in dict_settings and (self.dict_args[i] != dict_settings[i]): changed = True self.dict_args[i] = dict_settings[i] if changed: self.on_pushButton_2_clicked() def askRemoveMisc(self, bool_): if bool_: reply = QMessageBox.question( self, "Confirmation", "<p style='line-height:25px; height:25px'>Would you like to remove the \"misc_feature\" annotation before using \"Validate\" button?</p>", QMessageBox.Yes, QMessageBox.Cancel) if reply == QMessageBox.Yes: self.removeMISC = True