def install_packages():
        """
        installs  base packages via pip, e.g. packaging package
        :return: True if packages installed successfully else False
        """
        logger = QGISLogHandler("ModuleService")

        python = ModuleService.get_python()

        requirements = list("{}>={}".format(key, module_list[key]) for key in module_list.keys())
        cmd = [python, "-m", "pip", "install", "--force-reinstall", "--user", "--upgrade"] + requirements

        try:
            logger.info("Installing packages", ", ".join(requirements))
            logger.info("CMD: {}".format(" ".join(cmd)))

            result = run(cmd, stdout=PIPE, stderr=STDOUT, check=True)

            logger.info("installation result", result.stdout.decode())
            return True

        except CalledProcessError as e:
            logger.error("Package installation failed!")
            logger.error("RETURN-CODE: {} - CMD: {}".format(e.returncode, e.cmd))
            logger.error("OUTPUT: {}".format(e.output))
            return False
    def check_required_modules():
        """
        Check all module requirements
        :return: True is all modules with required versions were found, else false
        """
        logger = QGISLogHandler("ModuleService")

        # don't display logging to QGIS
        safed_iface = logger.qgis_iface
        logger.qgis_iface = None

        logger.info("Checking required modules")

        python = ModuleService.get_python()

        cmd = [python, "-m", "pip", "list", "--format", "json", "--user"]

        try:
            logger.info("Checking package versions")
            logger.info("CMD: {}".format(" ".join(cmd)))

            result = run(cmd, stdout=PIPE, stderr=STDOUT, check=True)
            logger.info("run pip info successful")
            packages = json.loads(result.stdout.decode())

        except CalledProcessError as e:
            # restore QGIS logging
            logger.qgis_iface = safed_iface
            logger.error("pip info request failed!")
            logger.error("RETURN-CODE: {} - CMD: {}".format(e.returncode, e.cmd))
            logger.error("OUTPUT: {}".format(e.output))
            return False

        ModuleService.modules = list()
        for module in module_list:
            module_found = False
            for package in packages:
                if package["name"] != module:
                    continue
                module_found = True

                logger.debug("found module {} [{}]".format(package["name"], package["version"]))

                v1 = version.parse(package["version"])
                v2 = version.parse(module_list[module])
                if v1 < v2:
                    logger.warn("Module version [{}] differs from required version [{}]".format(v1, v2))
                    ModuleService.modules.append("{}=={}".format(module, module_list[module]))

            if not module_found:
                logger.debug("Module not found, adding {}=={} to install list".format(module, module_list[module]))
                ModuleService.modules.append("{}=={}".format(module, module_list[module]))

        if len(ModuleService.modules) > 0:
            # restore QGIS logging
            logger.qgis_iface = safed_iface
            logger.info("Missing packages found: {}".format(ModuleService.modules))
            return False

        logger.info("All packages up to date")

        # restore QGIS logging
        logger.qgis_iface = safed_iface
        return True
Exemple #3
0
class ImportViewInterface(QObject):
    """
    interface class defining signals and slots for all import views
    """

    def __init__(self, dock_widget: GeologicalDataProcessingDockWidget) -> None:
        """
        Initialize the view
        :param dock_widget: current GeologicalDataProcessingDockWidget instance
        """

        self.logger = QGISLogHandler(self.__class__.__name__)
        self.__combos = dict()
        self._dwg = dock_widget

        # initialize user interface
        self._import_service = ImportService.get_instance()
        self._import_service.reset_import.connect(self.reset_import)
        self._import_service.import_columns_changed.connect(self._on_import_columns_changed)

        self._table_view: QTableView or None = None
        self._only_number_in_table_view: bool = False
        self._table_model: PropertyImportModel = PropertyImportModel()
        self._dwg.start_import_button.clicked.connect(self._on_start_import)
        self._controller_thread: ImportControllersInterface or None = None

        super().__init__()

    def _connect_combo_listener(self):
        """
        connects all combobox elements to the on_selection_changed slot
        :return: Nothing
        """
        [combo.currentIndexChanged.connect(self.on_selection_changed) for combo in self.__combos]

    @property
    def combobox_names(self) -> Dict:
        """
        Returns a dictionary of comboboxes for the current view
        :return: returns a dictionary of comboboxes for the current view
        """
        return self.__combos

    @combobox_names.setter
    def combobox_names(self, combo_dict: Dict) -> None:
        """
        Sets a new dictionary to the combobox list. Disconnects the old ones and connects the new to the
        on_selection_changed slot
        :param combo_dict: dictionary with new combobox elements
        :return: Nothing
        :raises TypeError: if a dictionary value is not an instance of QComboBox or a key is not a str. Sets an empty
        dictionary instead
        """

        self._disconnect_selection_changed()

        for key in combo_dict:
            if not isinstance(key, str):
                self.__combos = dict()
                raise TypeError("{} is not a string".format(str(key)))
            if not isinstance(combo_dict[key], QComboBox):
                self.__combos = dict()
                raise TypeError("{} is not an instance of QComboBox".format(str(key)))

        self.__combos = combo_dict
        self._connect_selection_changed()

    @property
    def table_view(self) -> QTableView or None:
        return self._table_view

    @table_view.setter
    def table_view(self, widget: QTableView) -> None:
        if not isinstance(widget, QTableView):
            raise TypeError("submitted object is not of type QTableView: {}", str(widget))

        self._table_model.clear()
        self._table_view = widget
        self._table_view.setModel(self._table_model)

        if self._only_number_in_table_view:
            self._table_view.setItemDelegate(LogImportDelegate())
        else:
            self._table_view.setItemDelegate(PropertyImportDelegate())
        # self._table_view.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
        # self._table_view.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch)
        self._table_view.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)

    @property
    def dockwidget(self) -> GeologicalDataProcessingDockWidget:
        """
        Returns the current dockwidget
        :return: the current dockwidget
        """
        return self._dwg

    #
    # signals
    #

    selection_changed = pyqtSignal(list)
    """data changed signal which gives the index or name of the changed column and the newly selected text"""

    start_import = pyqtSignal()
    """signal to start the data import through an ImportController Thread"""

    #
    # slots
    #

    def on_selection_changed(self, _=None) -> None:
        """
        Emits the combobox_changed signal with a list of changed text
        :return: Nothing
        """
        selection_list = [self.combobox_names[key].currentText() for key in self.combobox_names]
        self.selection_changed.emit(selection_list)

        if self._table_view is None:
            self.logger.debug("No list widget specified for additional columns")
            return

        if self._only_number_in_table_view:
            cols = diff(self._import_service.number_columns, selection_list)
        else:
            cols = diff(self._import_service.selectable_columns, selection_list)

        self.logger.debug("selectable_columns: " + str(self._import_service.selectable_columns))
        self.logger.debug("selected_cols: " + str(selection_list))
        self.logger.debug("additional cols: " + str(cols))

        if self._table_view is not None:
            self._table_view.show()
            self._table_view.setEnabled(True)
            self._table_view.clearSelection()

        self._table_model.clear()
        for col in cols:
            property_type = PropertyTypes.FLOAT if col in self._import_service.number_columns else PropertyTypes.STRING
            self._table_model.add(PropertyImportData(name=col[0], unit=col[1], property_type=property_type))

    def _on_import_columns_changed(self) -> None:
        """
        change the import columns
        :return: Nothing
        """
        self.logger.debug("(Interface) _on_import_columns_changed")
        self._connect_selection_changed()
        self.on_selection_changed()

    def _on_start_import(self) -> None:
        self.logger.debug("(Interface) _on_start_import")
        self._update_progress_bar(0)
        self._dwg.progress_bar_layout.setVisible(True)

    def _on_import_failed(self, msg: str) -> None:
        self.logger.debug("(Interface) _on_import_failed")
        self.__import_finished()
        self.logger.error("Import failed", msg, to_messagebar=True)

    def _on_import_finished_with_warnings(self, msg: str) -> None:
        self.logger.debug("(Interface) _on_import_finished_with_warnings")
        self.logger.warn("Import finished with warnings", msg, to_messagebar=True)
        self.__import_finished()

    def _on_import_successful(self):
        self.logger.debug("(Interface) _on_import_successful")
        self.logger.info("Import successful", to_messagebar=True)
        self.__import_finished()

    def _on_cancel_import(self):
        self._controller_thread.cancel_import("Import canceled by user")

    def __import_finished(self):
        self._dwg.progress_bar_layout.setVisible(False)
        self._disconnect_thread()

        self._controller_thread.wait(2000)
        self._controller_thread = None

    #
    # public functions
    #

    def combobox_data(self, index: int or str) -> str:
        """
        Returns the currently selected item of the gui element with the given index
        :param index: index of the requested gui element as integer or string
        :return: Returns the data at the given index
        :raises IndexError: if index is not part in the available list
        """

        if isinstance(index, int):
            index = [self.combobox_names.keys()][index]
        else:
            index = str(index)

        if index not in self.combobox_names:
            raise IndexError("{} is not available".format(index))

        return self.combobox_names[index].currentText()

    def get_name(self, index: int) -> str or None:
        """
        Returns the name of the combobox with the given index
        :param index: index of the requested combobox
        :return: Returns the name of the combobox with the given index
        :raises IndexError: if the requested index is not in the list
        :raises ValueError: if the index is not convertible to an integer
        """
        index = int(index)

        if 0 <= index < len(self.combobox_names.keys()):
            return list(self.combobox_names.keys())[0]

    def get_names(self):
        """
        Returns a list of the combobox names
        :return: Returns a list of the combobox names
        """
        return list(self.combobox_names.keys())

    def set_combobox_data(self, index: int or str, values: List[str], default_index: int = 0) -> None:
        """
        Sets the committed values list to the gui combobox elements for the given index
        :param index: index of the requested gui element as integer or string
        :param values: new values for the combo boxes as a list of strings
        :param default_index: default selected index. If no default value is given, or the index is not part of the
                              list, the first entry will be selected by default
        :return: Returns, if the data setting was successful
        :raises IndexError: if index is not part in the available list
        :raises TypeError: if default_index is not an instance of int
        """

        if isinstance(index, int):
            index = [self.combobox_names.keys()][index]
        else:
            index = str(index)

        if index not in self.combobox_names:
            raise IndexError("{} is not available".format(index))

        if not isinstance(default_index, int):
            raise TypeError("default_index({}) is not an instance of int!".format(default_index))

        self.combobox_names[index].clear()
        for item in values:
            self.combobox_names[index].addItem(str(item))

        if not (0 <= default_index <= len(values)):
            default_index = 0
        self.combobox_names[index].setCurrentIndex(default_index)

    def reset_import(self) -> None:
        """
        Clears all import combo boxes, in case of a failure
        :return: Nothing
        """
        [self.set_combobox_data(name, []) for name in self.get_names()]

    def get_property_columns(self) -> List[PropertyImportData]:
        selection = set([x.row() for x in self._table_view.selectedIndexes()])
        self.logger.debug("selected rows indices: {}".format(selection))
        erg = [self._table_model.row(x) for x in selection]
        self.logger.debug("Selection:")
        [self.logger.debug("\t{}".format(x)) for x in erg]
        return erg

    #
    # protected functions
    #

    def _update_progress_bar(self, value):
        """
        slot to set the current progress bar value
        :param value: value in percent
        :return: nothing
        """
        self.logger.debug("Update progressbar with value {} called".format(value))
        if value < 0:
            self.dockwidget.progress_bar.setValue(0)
        elif value > 100:
            self.dockwidget.progress_bar.setValue(100)
        else:
            self.dockwidget.progress_bar.setValue(int(value))

    def _connect_selection_changed(self):
        self.logger.debug("_connect_selection_changed")
        [self.__combos[key].currentTextChanged.connect(self.on_selection_changed) for key in self.__combos]

    def _disconnect_selection_changed(self):
        for key in self.__combos:
            try:
                self.__combos[key].currentTextChanged.disconnect(self.on_selection_changed)
            except TypeError:
                # not connected
                pass

    def _connect_thread(self):
        self._controller_thread.import_finished.connect(self._on_import_successful)
        self._controller_thread.import_failed.connect(self._on_import_failed)
        self._controller_thread.import_finished_with_warnings.connect(self._on_import_finished_with_warnings)
        self._controller_thread.update_progress.connect(self._update_progress_bar)
        self._dwg.cancel_import.clicked.connect(self._on_cancel_import)

    def _disconnect_thread(self):
        self._controller_thread.import_finished.disconnect(self._on_import_successful)
        self._controller_thread.import_failed.disconnect(self._on_import_failed)
        self._controller_thread.import_finished_with_warnings.disconnect(self._on_import_finished_with_warnings)
        self._controller_thread.update_progress.disconnect(self._update_progress_bar)
        self._dwg.cancel_import.clicked.disconnect(self._on_cancel_import)
Exemple #4
0
class DatabaseController(QObject):
    """
    Controller class for database interaction
    """
    def __init__(self, settings: SettingsDialog = None) -> None:
        """
        Constructor
        :param settings: settings dialog
        :return: nothing
        """
        QObject.__init__(self)

        self.logger = QGISLogHandler(DatabaseController.__name__)

        self.__db_service = DatabaseService.get_instance()
        self.__last_db_settings = dict()

        self.__settings = None
        self.__config = ConfigHandler()
        self.settings = settings

        db_type = self.__config.get("General", "db_type")
        if db_type != "" and db_type in ["SQLite", "PostgreSQL"]:
            self.settings.DB_type.setCurrentText(db_type)
        else:
            db_type = "SQLite"
            self.__config.set("General", "db_type", db_type)
            self.settings.DB_type.setCurrentText(db_type)

        self.__on_db_type_changed(db_type)

    #
    # slots
    #

    def __on_db_type_changed(self, db_type: str):
        """
        Slot called, when the database type was changed to show / hide specific elements
        :param db_type: selected database type
        :return: nothing
        :raises ValueError: if type is unknown
        """
        self.logger.debug("Selecting new database type: {}".format(db_type))
        if db_type == "SQLite":
            self.settings.create_DB_button.show()
            self.settings.select_DB_button.show()
            self.settings.password_label.hide()
            self.settings.password.hide()
            self.settings.username_label.hide()
            self.settings.username.hide()
            self.settings.save_password.hide()

            tempdir = "/tmp" if platform.system(
            ) == "Darwin" else tempfile.gettempdir()
            filename = "geology.sqlite"
            self.settings.database_connection.setPlaceholderText(
                os.path.join(tempdir, filename))

        elif db_type == "PostgreSQL":
            self.settings.create_DB_button.hide()
            self.settings.select_DB_button.hide()
            self.settings.password_label.show()
            self.settings.password.show()
            self.settings.username_label.show()
            self.settings.username.show()
            if found_keyring:
                self.settings.save_password.show()
            else:
                self.settings.save_password.hide()

            self.settings.database_connection.setPlaceholderText(
                "localhost:5432/geology")
            self.settings.username.setPlaceholderText("postgres")
            self.settings.password.setPlaceholderText("")
        else:
            self.settings.database_connection.setText("")
            self.settings.username.setText("")
            self.settings.password.setText("")
            self.settings.database_connection.setPlaceholderText("")
            self.settings.username.setPlaceholderText("")
            self.settings.password.setPlaceholderText("")
            raise ValueError("Unknown DB Format: {}".format(db_type))

        if self.__config.has_section(db_type):
            self.settings.database_connection.setText(
                self.__config.get(db_type, "connection"))
            self.settings.username.setText(
                self.__config.get(db_type, "username"))
            self.settings.password.setText("")

        else:
            self.settings.database_connection.setText("")
            self.settings.username.setText("")
            self.settings.password.setText("")

        self.__update_db_service()

    def __on_create_db_clicked(self) -> None:
        """
        slot for creating a new database
        :return: Nothing
        """

        self.__validate()
        # noinspection PyCallByClass,PyArgumentList
        filename = get_file_name(
            QFileDialog.getSaveFileName(
                parent=self.settings,
                caption="Select database file",
                directory="",
                filter="Databases(*.db *.sqlite *.data);;Any File Type (*)"))

        if filename != "":
            # noinspection PyTypeChecker
            if os.path.splitext(filename)[-1].lower().lstrip('.') not in [
                    "db", "data", "sqlite"
            ]:
                filename += ".data"
            self.settings.database_connection.setText(filename)

    def __on_select_db(self) -> None:
        """
        slot for selecting a sqlite database file and set the result to the related lineedit
        :return: Nothing
        """

        self.__validate()
        # noinspection PyCallByClass,PyArgumentList
        filename = get_file_name(
            QFileDialog.getOpenFileName(
                self.settings, "Select database file", "",
                "Databases(*.db *.sqlite *.data);;Any File Type (*)"))

        if filename != "":
            # noinspection PyTypeChecker
            if os.path.splitext(filename)[-1].lower().lstrip('.') not in [
                    "db", "data", "sqlite"
            ]:
                filename += ".data"
            self.settings.database_connection.setText(filename)

    def __on_check_connection(self):
        """
        Check the requested database connection
        :return: if the connection check was successful
        :raises ValueError: if database type is unknown
        """
        result = self.__db_service.check_connection()

        if result == "":
            self.logger.info("Connection test successful")
            return True

        else:
            self.logger.error("connection test failed", result)
            return False

    def __on_save(self):
        self.__last_db_settings = self.__get_db_settings()
        self.__update_db_service()
        if self.__on_check_connection():
            self.__update_config()
            self.settings.accept()
        else:
            self.__restore_db_settings(self.__last_db_settings)

    def __on_cancel(self):
        self.__on_db_type_changed(self.settings.DB_type.currentText())
        self.settings.reject()

    #
    # private functions
    #

    def __update_db_service(self, _: object = None) -> None:
        """
        Update the database service, if a GUI input element changed
        :param _: temporary parameter for QLineEdit update
        :return: Nothing
        """

        self.__db_service.db_type = self.settings.DB_type.currentText()
        self.__db_service.connection = self.settings.database_connection.text()
        self.__db_service.username = self.settings.username.text()
        self.__db_service.password = self.settings.password.text()

        if self.__db_service.connection == "":
            self.__db_service.connection = self.settings.database_connection.placeholderText(
            )
        if self.__db_service.username == "":
            self.__db_service.username = self.settings.username.placeholderText(
            )
        if self.__db_service.password == "" and found_keyring:
            # empty password ? try request from system keystore
            self.__db_service.password = keyring.get_password(
                "Postgres {}".format(self.__db_service.connection),
                self.__db_service.username)

        # self.logger.debug("Connection settings:\ndatabase:\t{}\nconnection:\t{}\nusername:\t{}\npassword:\t{}".format(
        #    self.__db_service.db_type, self.__db_service.connection,
        #    self.__db_service.username, self.__db_service.password))

    def __get_db_settings(self) -> Dict:
        """
        Returns the current database connection settings as dictionary
        :return: current database connection settings
        """
        return {
            "db": self.__db_service.db_type,
            "connection": self.__db_service.connection,
            "username": self.__db_service.username,
            "password": self.__db_service.password
        }

    def __restore_db_settings(self, values: Dict) -> None:
        """
        Restores the database connection settings
        :param values: dictionary with connection settings
        :return: Nothing
        """
        try:
            self.__db_service.db_type = values["db"]
            self.__db_service.connection = values["connection"]
            self.__db_service.username = values["username"]
            self.__db_service.password = values["password"]
        except KeyError as e:
            self.logger.error("Can't restore database settings: {}", str(e))

    def __update_config(self):
        db_type = self.settings.DB_type.currentText()

        if db_type == "PostgreSQL":
            self.__config.set("PostgreSQL", "connection",
                              self.__db_service.connection)
            self.__config.set("PostgreSQL", "username",
                              self.__db_service.username)

            if self.settings.save_password.isChecked() and found_keyring:
                keyring.set_password(
                    "Postgres {}".format(self.__db_service.connection),
                    self.__db_service.username, self.__db_service.password)

        elif db_type == "SQLite":
            self.__config.set("SQLite", "connection",
                              self.__db_service.connection)

        if db_type in ["PostgreSQL", "SQLite"]:
            self.__config.set("General", "db_type", db_type)
            self.__on_db_type_changed(self.__config.get("General", "db_type"))

    def __validate(self):
        """
        Validates, if the service can be executed
        :return: Nothing
        :raises
        """

        if self.settings is None:
            raise AttributeError("No settings dialog is set")

        if self.__config is None:
            raise AttributeError("No config is set")

    #
    # setter and getter
    #

    @property
    def settings(self) -> SettingsDialog:
        """
        Returns the currently active settings dialog
        :return: returns the currently active settings dialog
        """
        return self.__settings

    @settings.setter
    def settings(self, value: SettingsDialog) -> None:
        """
        Sets the currently active settings dialog
        :return: returns the currently active settings dialog
        :raises TypeError: if value is not of type SettingsDialog
        """

        if isinstance(value, SettingsDialog):
            if self.__settings is not None:
                self.__settings.create_DB_button.clicked.disconnect(
                    self.__on_create_db_clicked)
                self.__settings.select_DB_button.clicked.disconnect(
                    self.__on_select_db)
                self.__settings.DB_type.currentIndexChanged[str].disconnect(
                    self.__on_db_type_changed)
                self.__settings.save_button.clicked.disconnect(self.__on_save)
                self.__settings.cancel_button.clicked.disconnect(
                    self.__on_cancel)

            self.__settings = value

            self.__settings.create_DB_button.clicked.connect(
                self.__on_create_db_clicked)
            self.__settings.select_DB_button.clicked.connect(
                self.__on_select_db)
            self.__settings.DB_type.currentIndexChanged[str].connect(
                self.__on_db_type_changed)
            self.__settings.save_button.clicked.connect(self.__on_save)
            self.__settings.cancel_button.clicked.connect(self.__on_cancel)

        else:
            raise TypeError(
                "committed parameter is not of type SettingsDialog")
    def run(self) -> None:
        """Run method that loads and starts the plugin"""

        if not self.pluginIsActive:
            self.pluginIsActive = True

            try:
                # initialize logger
                logger = QGISLogHandler()
                logger.qgis_iface = self.iface
                logger.save_to_file = True

                if packages_found == "NO_PACKAGES" or not ModuleService.check_required_modules():
                    logger.info("installing or updating packages")
                    if not ModuleService.install_packages():
                        logger.error("package installation failed, please restart QGIS to try again.")
                    else:
                        logger.info("package installation successful, please restart QGIS")
                        msg = QMessageBox()
                        msg.setIcon(QMessageBox.Information)
                        msg.setText("packages installation successful")
                        msg.setInformativeText("Please restart QGIS to use the GeologicalDataProcessing extension")

                        msg.setWindowTitle("package update")
                        msg.exec_()
                        return

                    return
                else:
                    logger.debug("all required packages up2date")

                # dockwidget may not exist if:
                #    first run of plugin
                #    removed on close (see self.onClosePlugin method)
                if self.dockwidget is None:
                    # Create the dockwidget (after translation) and keep reference
                    self.dockwidget = GeologicalDataProcessingDockWidget()

                if self.settings_dialog is None:
                    self.settings_dialog = SettingsDialog(parent=self.dockwidget)
                    self.settings_dialog.setModal(True)
                    self.dockwidget.settings_button.clicked.connect(self.settings_dialog.exec)

                # connect to provide cleanup on closing of dockwidget
                self.dockwidget.closingPlugin.connect(self.onClosePlugin)

                # show the dockwidget
                # TODO: fix to allow choice of dock location
                self.iface.addDockWidget(Qt.RightDockWidgetArea, self.dockwidget)
                self.dockwidget.show()

                from GeologicalDataProcessing.controller.database_controller import DatabaseController
                from GeologicalDataProcessing.services.import_service import ImportService
                from GeologicalDataProcessing.views.import_views import LineImportView, PointImportView, \
                    WellImportView, PropertyImportView, WellLogImportView

                ImportService.get_instance(self.dockwidget)

                # initialize the gui and connect signals and slots
                self.dockwidget.import_type.currentChanged.connect(self.on_import_type_changed_event)

                # start tests button
                # -> only visible and active when the debug flag is True
                if config.debug:
                    self.dockwidget.start_tests_button.clicked.connect(self.on_start_tests)
                else:
                    self.dockwidget.start_tests_button.setVisible(False)
                    self.dockwidget.start_tests_separator.setVisible(False)

                self.dockwidget.progress_bar_layout.setVisible(False)

                self.__views["import_points"] = PointImportView(self.dockwidget)
                self.__views["import_lines"] = LineImportView(self.dockwidget)
                self.__views["import_wells"] = WellImportView(self.dockwidget)
                self.__views["import_properties"] = PropertyImportView(self.dockwidget)
                self.__views["import_well_logs"] = WellLogImportView(self.dockwidget)

                self.__db_controller = DatabaseController(self.settings_dialog)

                if config.debug:
                    self.dockwidget.import_file.setText(
                        "/Users/stephan/Library/Application Support/QGIS/QGIS3/profiles/" +
                        "default/python/plugins/GeologicalDataProcessing/tests/test_data/point_data.txt")

            except Exception as e:
                ExceptionHandler(e).log()