def create_change_default_directory_frame(self): config = Configuration() default_directory = None try: default_directory = config.get_default_directory() except SqlError: config.set_up_config_db() QtWidgets.QMessageBox.critical( self.window, "Config file error", """Failed to access configuration file. \nConfiguration file recreated with no default directory. \nPlease update your default directory.""") self.window.change_default_directory_frame = QtWidgets.QFrame() self.window.change_default_directory_frame.setVisible(False) self.change_default_directory_vertical_layout = QtWidgets.QVBoxLayout() self.change_default_directory_prompt = QtWidgets.QLabel() self.change_default_directory_prompt.setAlignment(QtCore.Qt.AlignLeft) self.change_default_directory_prompt.setVisible(True) self.change_default_directory_prompt.setText( "Default directory's path:") self.change_default_directory_vertical_layout.addWidget( self.change_default_directory_prompt) # Create a horizontal box to hold the input box for the # directory and the choose button self.change_default_directory_input_horizontal_box = \ QtWidgets.QHBoxLayout() # Create a textbox to contain the path to the directory that # contains the DICOM files self.change_default_directory_input_box = \ UIChangeDefaultDirDragAndDropEvent(self) self.change_default_directory_input_box.setCursorPosition(0) self.change_default_directory_input_box.setText(default_directory) self.change_default_directory_input_horizontal_box.addWidget( self.change_default_directory_input_box) # Create a choose button to open the file dialog self.change_default_directory_button = QtWidgets.QPushButton() self.change_default_directory_button.setText("Change") self.change_default_directory_button.resize( self.change_default_directory_button.sizeHint().width(), self.change_default_directory_input_box.height()) self.change_default_directory_button.setCursor( QtGui.QCursor(QtCore.Qt.PointingHandCursor)) self.change_default_directory_input_horizontal_box.addWidget( self.change_default_directory_button) self.change_default_directory_button.clicked.connect( self.change_button_clicked) # Create a widget to hold the input fields self.change_default_directory_input_widget = QtWidgets.QWidget() self.change_default_directory_input_horizontal_box.setStretch(0, 4) self.change_default_directory_input_widget.setLayout( self.change_default_directory_input_horizontal_box) self.change_default_directory_vertical_layout.addWidget( self.change_default_directory_input_widget, 1, QtCore.Qt.AlignTop) self.window.change_default_directory_frame.setLayout( self.change_default_directory_vertical_layout)
def init_first_time_window_config(request): configuration = Configuration('TestFirstTimeWelcomeWindow.db') db_file_path = os.environ['USER_HIDDEN'] + 'TestFirstTimeWelcomeWindow.db' configuration.set_db_file_path(db_file_path) def tear_down(): if os.path.isfile(db_file_path): os.remove(db_file_path) request.addfinalizer(tear_down)
def test_get_default_directory(init_sqlite_config): configuration = Configuration() new_default_dir = "/home/test/dir" # Insert new default dir init_sqlite_config.execute("""INSERT INTO configuration (id, default_dir) VALUES (1, "%s");""" % new_default_dir) init_sqlite_config.commit() # Get default dir from configuration object result = configuration.get_default_directory() # Compare the value returned from get_default_directory() and the value from database assert result == new_default_dir
def test_update_default_directory(init_sqlite_config): configuration = Configuration() new_default_dir = "/home/test/dir" # Update default_dir with configuration object configuration.update_default_directory(new_default_dir) # Select default dir from the database cursor = init_sqlite_config.cursor() cursor.execute("SELECT default_dir FROM CONFIGURATION WHERE id = 1") record = cursor.fetchone() # Check if the value from database is equal to the one that we want to update into assert record[0] == new_default_dir
def init_sqlite_config(request): configuration = Configuration('TestSqliteConfig.db') db_file_path = os.environ['USER_HIDDEN'] + 'TestSqliteConfig.db' configuration.set_db_file_path(db_file_path) connection = sqlite3.connect(db_file_path) def tear_down(): connection.close() if os.path.isfile(db_file_path): os.remove(db_file_path) request.addfinalizer(tear_down) return connection
def save_options(self): """ Saves options selected in the first time welcome window. """ self.filepath = self.first_time_welcome_input_box.text() self.csv_path = self.clinical_data_csv_input_box.text() if self.filepath == "" and self.csv_path == "": QMessageBox.about(self, "Unable to proceed", "No directories selected.") elif not os.path.exists(self.filepath) or not \ os.path.exists(self.csv_path): QMessageBox.about(self, "Unable to proceed", "Directories do not exist") else: config = Configuration() try: config.update_default_directory(self.filepath) # Update CSV path if it exists if self.csv_path != "" and os.path.exists(self.csv_path): config.update_clinical_data_csv_dir(self.csv_path) except SqlError: config.set_up_config_db() QMessageBox.critical( self, "Config file error", "Failed to access configuration file.\nPlease try again.") else: self.configured.emit(self.filepath)
def test_error_handling(init_sqlite_config): # Drop database file to reproduce SQL error configuration = Configuration() cursor = init_sqlite_config.cursor() # Lock the database to trigger SqlError cursor.execute("""PRAGMA locking_mode = EXCLUSIVE;""") cursor.execute("""BEGIN EXCLUSIVE;""") with pytest.raises(SqlError): configuration.get_default_directory() with pytest.raises(SqlError): configuration.update_default_directory('')
def init_config(request): configuration = Configuration('TestConfig.db') db_file_path = os.environ['USER_HIDDEN'] + 'TestConfig.db' configuration.set_db_file_path(db_file_path) connection = sqlite3.connect(db_file_path) configuration.update_default_directory("../testdata/DICOM-RT-TEST") def tear_down(): connection.close() if os.path.isfile(db_file_path): os.remove(db_file_path) request.addfinalizer(tear_down) return connection
def init_config(request): configuration = Configuration('TestConfig.db') db_file_path = Path( os.environ['USER_ONKODICOM_HIDDEN']).joinpath('TestConfig.db') configuration.set_db_file_path(db_file_path) connection = sqlite3.connect(db_file_path) configuration.update_default_directory(Path.cwd().joinpath( 'test', 'testdata')) def tear_down(): connection.close() if os.path.isfile(db_file_path): os.remove(db_file_path) request.addfinalizer(tear_down) return connection
def save_default_dir(self): self.filepath = self.first_time_welcome_input_box.text() if self.filepath == "": QMessageBox.about(self, "Unable to proceed", "No directory selected.") elif not os.path.exists(self.filepath): QMessageBox.about(self, "Unable to proceed", "Directory does not exist") else: config = Configuration() try: config.update_default_directory(self.filepath) except SqlError: config.set_up_config_db() QMessageBox.critical( self, "Config file error", "Failed to access configuration file.\nPlease try again.") else: self.configured.emit(self.filepath)
def import_clinical_data(self): """ Attempt to import clinical data from the CSV stored in the program's settings database. """ # Return if there is no RTDOSE in the dataset patient_dict_container = PatientDictContainer() if 'rtdose' not in list(patient_dict_container.dataset.keys()): message = "No RTDOSE found. Clinical data is only imported for " \ "datasets that include an RTDOSE." attrib = QtWidgets.QTableWidgetItem("Warning") value = QtWidgets.QTableWidgetItem(message) self.table_cd.insertRow(0) self.table_cd.setItem(0, 0, attrib) self.table_cd.setItem(0, 1, value) return # Return if data has been imported from DICOM SR if self.table_populated: return # Clear data dictionary and table self.data_dict = {} self.clear_table() # Current patient's ID patient_id = patient_dict_container.dataset[0].PatientID # Try get the clinical data CSV file path try: config = Configuration() file_path = config.get_clinical_data_csv_dir() except SqlError: # Write warning to table message = "Failed to access configuration file." attrib = QtWidgets.QTableWidgetItem("Warning") value = QtWidgets.QTableWidgetItem(message) self.table_cd.insertRow(0) self.table_cd.setItem(0, 0, attrib) self.table_cd.setItem(0, 1, value) return # Get CSV data if file_path == "" or file_path is None \ or not os.path.exists(file_path): # Clear table self.clear_table() # Write warning to table message = "Clinical data CSV could not be found." attrib = QtWidgets.QTableWidgetItem("Warning") value = QtWidgets.QTableWidgetItem(message) self.table_cd.insertRow(0) self.table_cd.setItem(0, 0, attrib) self.table_cd.setItem(0, 1, value) return with open(file_path, newline="") as stream: data = list(csv.reader(stream)) # See if CSV data matches patient ID patient_in_file = False row_num = 0 for i, row in enumerate(data): if row[0] == patient_id: patient_in_file = True row_num = i break # Return if patient's data not in the CSV file if not patient_in_file: # Clear table self.clear_table() # Write warning to table message = "Patient clinical data not found in CSV." attrib = QtWidgets.QTableWidgetItem("Warning") value = QtWidgets.QTableWidgetItem(message) self.table_cd.insertRow(0) self.table_cd.setItem(0, 0, attrib) self.table_cd.setItem(0, 1, value) return # Put patient data into dictionary headings = data[0] attribs = data[row_num] for i, heading in enumerate(headings): self.data_dict[heading] = attribs[i] # Update table self.populate_table() # Save clinical data to DICOM SR self.save_clinical_data()
os.environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = "1" app = QtWidgets.QApplication(sys.argv) print("PDPI: " + str(app.primaryScreen().physicalDotsPerInch())) # Set the font to Segoe UI, 9, when in windows OS if platform.system() == 'Windows': f = QFont("Segoe UI", 9) app.setFont(f) elif platform.system() == 'Darwin': f = QFont("Helvetica Neue", 13) app.setFont(f) if len(sys.argv) > 1: controller = Controller(default_directory=sys.argv[1]) controller.show_open_patient() else: # Get the default DICOM directory from SQLite database # stored in a hidden directory in the user home directory configuration = Configuration() default_dir = configuration.get_default_directory() if default_dir is None: controller = Controller() controller.show_first_time_welcome() else: controller = Controller(default_directory=default_dir) controller.show_welcome() sys.exit(app.exec_())
def create_change_clinical_data_csv_frame(self): config = Configuration() csv_dir = None # Try get the clinical data CSV directory try: csv_dir = config.get_clinical_data_csv_dir() except SqlError: config.set_up_config_db() QtWidgets.QMessageBox.critical( self.window, "Config file error", """Failed to access configuration file. \nConfiguration file recreated with no default directory. \nPlease update your default directory.""") # Clinical data prompt text text = "Importing Clinical Data\n\nClinical data can be " \ "automatically imported into the DICOM image set. This " \ "requires a matching process which is strict (see the User " \ "Manual). The three requirements are detailed below:\n\n1. " \ "The Patient's Clinical Data must be stored in the Comma " \ "Separated Values (CSV) format, which any spreadsheet " \ "program can produce, including MS Excel.\n\n2. This CSV " \ "file must contain the patient's identifier in the first " \ "column, and that first column must be titled \"Patient_ID\"." \ "\n\n3. The entry in the first CSV column [\"Patient_ID\"] " \ "must match the patient identifier in the DICOM dataset.\n\n" \ "4. The CSV file must contain the ICD10 code in the second " \ "column, and that column must be named \"ICD10\"." # Create the frame self.window.clinical_data_csv_dir_frame = QtWidgets.QFrame() self.window.clinical_data_csv_dir_frame.setVisible(False) # Create the layout self.clinical_data_csv_layout = QtWidgets.QVBoxLayout() self.change_clinical_data_csv_dir_prompt = QtWidgets.QLabel() self.change_clinical_data_csv_dir_prompt.setAlignment( QtCore.Qt.AlignJustify) self.change_clinical_data_csv_dir_prompt.setVisible(True) self.change_clinical_data_csv_dir_prompt.setMaximumWidth( self.window.clinical_data_csv_dir_frame.width() - 10) self.change_clinical_data_csv_dir_prompt.setText(text) self.change_clinical_data_csv_dir_prompt.setWordWrap(True) self.clinical_data_csv_layout.addWidget( self.change_clinical_data_csv_dir_prompt) # Create a horizontal box to hold the input box for the # directory and the choose button self.clinical_data_csv_dir_input_layout = QtWidgets.QHBoxLayout() # Create a textbox to contain the path to the directory that # contains the DICOM files self.clinical_data_csv_dir_input_box = \ UIChangeDefaultDirDragAndDropEvent(self) self.clinical_data_csv_dir_input_box.setCursorPosition(0) self.clinical_data_csv_dir_input_box.setText(csv_dir) self.clinical_data_csv_dir_input_layout.addWidget( self.clinical_data_csv_dir_input_box) # Create a choose button to open the file dialog self.clinical_data_csv_dir_button = QtWidgets.QPushButton() self.clinical_data_csv_dir_button.setText("Change") self.clinical_data_csv_dir_button.resize( self.clinical_data_csv_dir_button.sizeHint().width(), self.clinical_data_csv_dir_input_box.height()) self.clinical_data_csv_dir_button.setCursor( QtGui.QCursor(QtCore.Qt.PointingHandCursor)) self.clinical_data_csv_dir_button.clicked.connect( self.change_clinical_data_csv_button_clicked) self.clinical_data_csv_dir_input_layout.addWidget( self.clinical_data_csv_dir_button) # Create a widget to hold the input fields self.clinical_data_csv_dir_input_widget = QtWidgets.QWidget() self.clinical_data_csv_dir_input_widget.setLayout( self.clinical_data_csv_dir_input_layout) self.clinical_data_csv_layout.addWidget( self.clinical_data_csv_dir_input_widget) self.clinical_data_csv_layout.addStretch(1) # Set the frame's layout self.window.clinical_data_csv_dir_frame.setLayout( self.clinical_data_csv_layout)