def save_state(self): """Store the options into the user's stored session info.""" # Save boolean settings for key, check_box in self.boolean_settings.items(): self.save_boolean_setting(key, check_box) # Save text settings for key, line_edit in self.text_settings.items(): self.save_text_setting(key, line_edit) self.settings.setValue('inasafe/north_arrow_path', self.leNorthArrowPath.text()) self.settings.setValue('inasafe/organisation_logo_path', self.leOrganisationLogoPath.text()) self.settings.setValue('inasafe/reportTemplatePath', self.leReportTemplatePath.text()) self.settings.setValue('inasafe/reportDisclaimer', self.txtDisclaimer.toPlainText()) self.settings.setValue('inasafe/defaultUserDirectory', self.leUserDirectoryPath.text()) index = self.earthquake_function.currentIndex() value = self.earthquake_function.itemData(index) set_setting('earthquake_function', value, qsettings=self.settings) currency_index = self.currency_combo_box.currentIndex() currency_key = self.currency_combo_box.itemData(currency_index) set_setting('currency', currency_key, qsettings=self.settings) # Save InaSAFE default values self.save_default_values()
def test_export_import_setting(self): """Test for export_setting method.""" profile_file = unique_filename( suffix='.json', dir='population_preference') original_settings = { 'key': 'value', 'key_bool': True, 'population_preference': generate_default_profile(), 'key_int': 1, 'key_float': 2.0 } # Write for key, value in list(original_settings.items()): set_setting(key, value, self.qsettings) # Export inasafe_settings = export_setting(profile_file, self.qsettings) # Check result self.assertTrue(os.path.exists(profile_file)) self.assertEqual(inasafe_settings['key'], 'value') self.assertEqual( inasafe_settings['population_preference'], generate_default_profile()) # Import read_setting = import_setting(profile_file, self.qsettings) self.assertDictEqual(inasafe_settings, read_setting) self.assertDictEqual(original_settings, read_setting)
def test_export_import_setting(self): """Test for export_setting method.""" profile_file = unique_filename(suffix='.json', dir='population_preference') original_settings = { 'key': 'value', 'key_bool': True, 'population_preference': generate_default_profile(), 'key_int': 1, 'key_float': 2.0 } # Write for key, value in list(original_settings.items()): set_setting(key, value, self.qsettings) # Export inasafe_settings = export_setting(profile_file, self.qsettings) # Check result self.assertTrue(os.path.exists(profile_file)) self.assertEqual(inasafe_settings['key'], 'value') self.assertEqual(inasafe_settings['population_preference'], generate_default_profile()) # Import read_setting = import_setting(profile_file, self.qsettings) self.assertDictEqual(inasafe_settings, read_setting) self.assertDictEqual(original_settings, read_setting)
def show_welcome_message(self): """Show the welcome message.""" # import here only so that it is AFTER i18n set up from safe.gui.tools.options_dialog import OptionsDialog # Do not show by default show_message = False previous_version = StrictVersion(setting('previous_version')) current_version = StrictVersion(inasafe_version) # Set previous_version to the current inasafe_version set_setting('previous_version', inasafe_version) if setting('always_show_welcome_message', expected_type=bool): # Show if it the setting said so show_message = True elif previous_version < current_version: # Always show if the user installed new version show_message = True # Allow to disable welcome message when running automated tests if os.environ.get('INASAFE_DISABLE_WELCOME_MESSAGE', False): show_message = False if show_message: dialog = OptionsDialog(iface=self.iface, parent=self.iface.mainWindow()) dialog.show_welcome_dialog() if dialog.exec_(): # modal self.dock_widget.read_settings()
def save_state(self): """Store the options into the user's stored session info.""" # Save boolean settings for key, check_box in self.boolean_settings.items(): self.save_boolean_setting(key, check_box) # Save text settings for key, line_edit in self.text_settings.items(): self.save_text_setting(key, line_edit) self.settings.setValue( 'inasafe/north_arrow_path', self.leNorthArrowPath.text()) self.settings.setValue( 'inasafe/organisation_logo_path', self.leOrganisationLogoPath.text()) self.settings.setValue( 'inasafe/reportTemplatePath', self.leReportTemplatePath.text()) self.settings.setValue( 'inasafe/reportDisclaimer', self.txtDisclaimer.toPlainText()) self.settings.setValue( 'inasafe/defaultUserDirectory', self.leUserDirectoryPath.text()) index = self.earthquake_function.currentIndex() value = self.earthquake_function.itemData(index) set_setting('earthquake_function', value) # Save InaSAFE default values self.save_default_values()
def test_read_write_setting(self): """Test read and write setting.""" # General Setting set_general_setting('key', 'value', self.qsettings) self.assertEqual('value', general_setting('key', qsettings=self.qsettings)) delete_general_setting('key', qsettings=self.qsettings) self.assertEqual( 'default', general_setting('key', default='default', qsettings=self.qsettings)) set_general_setting('key', 'True', self.qsettings) self.assertEqual( 'True', general_setting('key', qsettings=self.qsettings, expected_type=str)) self.assertEqual( True, general_setting('key', qsettings=self.qsettings, expected_type=bool)) delete_general_setting('key', qsettings=self.qsettings) self.assertEqual( 'default', general_setting('key', default='default', qsettings=self.qsettings)) set_general_setting('key', 'false', self.qsettings) self.assertEqual( 'false', general_setting('key', qsettings=self.qsettings, expected_type=str)) self.assertEqual( False, general_setting('key', qsettings=self.qsettings, expected_type=bool)) delete_general_setting('key', qsettings=self.qsettings) self.assertEqual( 'default', general_setting('key', default='default', qsettings=self.qsettings)) # Under InaSAFE scope set_setting('key', 'value', self.qsettings) self.assertEqual('value', setting('key', qsettings=self.qsettings)) delete_setting('key', qsettings=self.qsettings) self.assertEqual( 'default', setting('key', default='default', qsettings=self.qsettings)) # Using InaSAFE setting default key = 'developer_mode' actual_value = inasafe_default_settings.get(key) self.assertEqual(actual_value, setting(key, qsettings=self.qsettings))
def save_text_setting(self, key, line_edit): """Save text setting according to line_edit value. :param key: Key to retrieve setting value. :type key: str :param line_edit: Line edit for user to edit the setting :type line_edit: PyQt5.QtWidgets.QLineEdit.QLineEdit """ set_setting(key, line_edit.text(), self.settings)
def save_boolean_setting(self, key, check_box): """Save boolean setting according to check_box state. :param key: Key to retrieve setting value. :type key: str :param check_box: Check box to show and set the setting. :type check_box: PyQt5.QtWidgets.QCheckBox.QCheckBox """ set_setting(key, check_box.isChecked(), qsettings=self.settings)
def test_read_boolean_setting(self): """Test read developer mode setting.""" set_setting('developer_mode', inasafe_default_settings['developer_mode']) actual_setting = setting('developer_mode', inasafe_default_settings['developer_mode']) self.assertFalse(actual_setting) set_setting('developer_mode', not (inasafe_default_settings['developer_mode'])) actual_setting = setting('developer_mode', inasafe_default_settings['developer_mode']) self.assertTrue(actual_setting)
def test_read_write_setting(self): """Test read and write setting.""" # General Setting set_general_setting('key', 'value', self.qsettings) self.assertEqual( 'value', general_setting('key', qsettings=self.qsettings)) delete_general_setting('key', qsettings=self.qsettings) self.assertEqual('default', general_setting( 'key', default='default', qsettings=self.qsettings)) set_general_setting('key', 'True', self.qsettings) self.assertEqual( 'True', general_setting( 'key', qsettings=self.qsettings, expected_type=str)) self.assertEqual( True, general_setting( 'key', qsettings=self.qsettings, expected_type=bool)) delete_general_setting('key', qsettings=self.qsettings) self.assertEqual('default', general_setting( 'key', default='default', qsettings=self.qsettings)) set_general_setting('key', 'false', self.qsettings) self.assertEqual( 'false', general_setting( 'key', qsettings=self.qsettings, expected_type=str)) self.assertEqual( False, general_setting( 'key', qsettings=self.qsettings, expected_type=bool)) delete_general_setting('key', qsettings=self.qsettings) self.assertEqual('default', general_setting( 'key', default='default', qsettings=self.qsettings)) # Under InaSAFE scope set_setting('key', 'value', self.qsettings) self.assertEqual('value', setting('key', qsettings=self.qsettings)) delete_setting('key', qsettings=self.qsettings) self.assertEqual('default', setting( 'key', default='default', qsettings=self.qsettings)) # Using InaSAFE setting default key = 'developer_mode' actual_value = inasafe_default_settings.get(key) self.assertEqual(actual_value, setting(key, qsettings=self.qsettings))
def test_read_boolean_setting(self): """Test read developer mode setting.""" set_setting( 'developer_mode', inasafe_default_settings['developer_mode']) actual_setting = setting( 'developer_mode', inasafe_default_settings['developer_mode']) self.assertFalse(actual_setting) set_setting( 'developer_mode', not(inasafe_default_settings['developer_mode'])) actual_setting = setting( 'developer_mode', inasafe_default_settings['developer_mode']) self.assertTrue(actual_setting)
def select_test_package(self): """Select the test package.""" default_package = 'safe' user_package = str( setting('testPackage', default_package, expected_type=str)) test_package, _ = QInputDialog.getText( self.iface.mainWindow(), self.tr('Select the python test package'), self.tr('Select the python test package'), QLineEdit.Normal, user_package) if test_package == '': test_package = default_package set_setting('testPackage', test_package) msg = self.tr('Run tests in %s' % test_package) self.action_run_tests.setWhatsThis(msg) self.action_run_tests.setText(msg)
def set_user_extent(self, extent, crs): """Setter for the user requested extent. This function will redraw the rubberband if needed. :param extent: The user extent. :type extent: QgsGeometry :param crs: The CRS of the extent. :type crs: QgsCoordinateReferenceSystem """ extent = QgsGeometry(extent) transform = QgsCoordinateTransform(crs, self.crs) extent.transform(transform) self._user_extent = extent set_setting('user_extent', extent.exportToWkt()) set_setting('user_extent_crs', crs.authid()) if self._show_rubber_bands: self.display_user_extent()
def test_read_write_dictionary(self): """Test for reading and writing dictionary in QSettings.""" dictionary = { 'a': 'a', 'b': 1, 'c': { 'd': True, 'e': { 'f': 1.0, 'g': 2 } } } set_setting('key', dictionary, self.qsettings) value = setting('key', qsettings=self.qsettings) self.assertDictEqual(dictionary, value) profile_dictionary = generate_default_profile() set_setting('population_preference', profile_dictionary, self.qsettings) value = setting('population_preference', qsettings=self.qsettings) self.assertDictEqual(profile_dictionary, value)
def test_read_write_dictionary(self): """Test for reading and writing dictionary in QSettings.""" dictionary = { 'a': 'a', 'b': 1, 'c': { 'd': True, 'e': { 'f': 1.0, 'g': 2 } } } set_setting('key', dictionary, self.qsettings) value = setting('key', qsettings=self.qsettings) self.assertDictEqual(dictionary, value) profile_dictionary = generate_default_profile() set_setting( 'population_preference', profile_dictionary, self.qsettings) value = setting('population_preference', qsettings=self.qsettings) self.assertDictEqual(profile_dictionary, value)
def reset_defaults(self): """Reset login and password in QgsSettings.""" self.save_login.setChecked(False) self.save_password.setChecked(False) self.save_url.setChecked(False) set_setting(GEONODE_USER, '') set_setting(GEONODE_PASSWORD, '') set_setting(GEONODE_URL, '') self.login.setText('') self.password.setText('') self.url.setText('')
def test_get_displacement_rate_and_affected_with_qsetting(self): """Test for get_displacement_rate and is_affected with QSettings.""" # Create custom qsettings qsettings = QSettings(INASAFE_TEST) qsettings.clear() # Save the default profile to qsettings default_profile = generate_default_profile() set_setting('population_preference', default_profile, qsettings) # Check the default one first default_profile = generate_default_profile() class_key = flood_hazard_classes['classes'][0]['key'] value = is_affected(hazard_flood['key'], flood_hazard_classes['key'], class_key, qsettings) expected_value = default_profile[hazard_flood['key']][ flood_hazard_classes['key']][class_key]['affected'] self.assertEqual(value, expected_value) value = get_displacement_rate(hazard_flood['key'], flood_hazard_classes['key'], class_key, qsettings) expected_value = default_profile[hazard_flood['key']][ flood_hazard_classes['key']][class_key]['displacement_rate'] self.assertEqual(value, expected_value) # Change displacement rate new_displacement_rate = 1 default_profile[hazard_flood['key']][ flood_hazard_classes['key']][class_key]['displacement_rate'] = 1 set_setting('population_preference', default_profile, qsettings) value = get_displacement_rate(hazard_flood['key'], flood_hazard_classes['key'], class_key, qsettings) self.assertEqual(value, new_displacement_rate) # Change affected value new_affected = False default_profile[hazard_flood['key']][ flood_hazard_classes['key']][class_key]['affected'] = new_affected set_setting('population_preference', default_profile, qsettings) value = is_affected(hazard_flood['key'], flood_hazard_classes['key'], class_key, qsettings) self.assertEqual(value, new_affected) value = get_displacement_rate(hazard_flood['key'], flood_hazard_classes['key'], class_key, qsettings) # Should be 0 since it's not affected self.assertEqual(value, 0)
def accept(self): """User accepted the rectangle.""" mode = None if self.hazard_exposure_view_extent.isChecked(): mode = HAZARD_EXPOSURE_VIEW elif self.exposure_only.isChecked(): mode = EXPOSURE elif self.hazard_exposure_only.isChecked(): mode = HAZARD_EXPOSURE elif self.hazard_exposure_bookmark.isChecked(): mode = HAZARD_EXPOSURE_BOOKMARK elif self.hazard_exposure_user_extent.isChecked(): mode = HAZARD_EXPOSURE_BOUNDINGBOX set_setting('analysis_extents_mode', mode) self.canvas.unsetMapTool(self.tool) if self.previous_map_tool != self.tool: self.canvas.setMapTool(self.previous_map_tool) if self.tool.rectangle() is not None: self.extent_defined.emit( self.tool.rectangle(), self.canvas.mapSettings().destinationCrs()) extent = QgsGeometry.fromRect(self.tool.rectangle()) LOGGER.info( 'Requested extent : {wkt}'.format(wkt=extent.exportToWkt())) else: self.clear_extent.emit() # State handlers for showing warning message bars set_setting('show_extent_warnings', self.show_warnings.isChecked()) set_setting( 'show_extent_confirmations', self.show_confirmations.isChecked()) self.tool.reset() self.extent_selector_closed.emit() super(ExtentSelectorDialog, self).accept()
def accept(self): """User accepted the rectangle.""" mode = None if self.hazard_exposure_view_extent.isChecked(): mode = HAZARD_EXPOSURE_VIEW elif self.exposure_only.isChecked(): mode = EXPOSURE elif self.hazard_exposure_only.isChecked(): mode = HAZARD_EXPOSURE elif self.hazard_exposure_bookmark.isChecked(): mode = HAZARD_EXPOSURE_BOOKMARK elif self.hazard_exposure_user_extent.isChecked(): mode = HAZARD_EXPOSURE_BOUNDINGBOX set_setting('analysis_extents_mode', mode) self.canvas.unsetMapTool(self.tool) if self.previous_map_tool != self.tool: self.canvas.setMapTool(self.previous_map_tool) if self.tool.rectangle() is not None: self.extent_defined.emit( self.tool.rectangle(), self.canvas.mapSettings().destinationCrs()) extent = QgsGeometry.fromRect(self.tool.rectangle()) LOGGER.info( 'Requested extent : {wkt}'.format(wkt=extent.exportToWkt())) else: self.clear_extent.emit() # State handlers for showing warning message bars set_setting('show_extent_warnings', self.show_warnings.isChecked()) set_setting('show_extent_confirmations', self.show_confirmations.isChecked()) self.tool.reset() self.extent_selector_closed.emit() super(ExtentSelectorDialog, self).accept()
def save_state(self): """Store current state of GUI to configuration file.""" set_setting('lastSourceDir', self.output_directory)
def save_state(self): """Save current state of GUI to configuration file.""" set_setting('lastSourceDir', self.source_directory.text()) set_setting('lastOutputDir', self.output_directory.text()) set_setting( 'useDefaultOutputDir', self.scenario_directory_radio.isChecked())
def test_get_displacement_rate_and_affected_with_qsetting(self): """Test for get_displacement_rate and is_affected with QSettings.""" # Create custom qsettings qsettings = QSettings(INASAFE_TEST) qsettings.clear() # Save the default profile to qsettings default_profile = generate_default_profile() set_setting('population_preference', default_profile, qsettings) # Check the default one first default_profile = generate_default_profile() class_key = flood_hazard_classes['classes'][0]['key'] value = is_affected( hazard_flood['key'], flood_hazard_classes['key'], class_key, qsettings) expected_value = default_profile[ hazard_flood['key']][flood_hazard_classes['key']][class_key][ 'affected'] self.assertEqual(value, expected_value) value = get_displacement_rate( hazard_flood['key'], flood_hazard_classes['key'], class_key, qsettings) expected_value = default_profile[ hazard_flood['key']][flood_hazard_classes['key']][class_key][ 'displacement_rate'] self.assertEqual(value, expected_value) # Change displacement rate new_displacement_rate = 1 default_profile[ hazard_flood['key']][flood_hazard_classes['key']][class_key][ 'displacement_rate'] = 1 set_setting('population_preference', default_profile, qsettings) value = get_displacement_rate( hazard_flood['key'], flood_hazard_classes['key'], class_key, qsettings) self.assertEqual(value, new_displacement_rate) # Change affected value new_affected = False default_profile[ hazard_flood['key']][flood_hazard_classes['key']][class_key][ 'affected'] = new_affected set_setting('population_preference', default_profile, qsettings) value = is_affected( hazard_flood['key'], flood_hazard_classes['key'], class_key, qsettings) self.assertEqual(value, new_affected) value = get_displacement_rate( hazard_flood['key'], flood_hazard_classes['key'], class_key, qsettings) # Should be 0 since it's not affected self.assertEqual(value, 0)
def save_state(self): """Store current state of GUI to configuration file.""" set_setting('directory', self.output_directory.text())
def save_population_parameters(self): """Helper to save population parameter to QSettings.""" population_parameter = self.profile_widget.data set_setting('population_preference', population_parameter)
def accept(self): """Upload the layer to Geonode.""" enable_busy_cursor() self.button_box.setEnabled(False) layer = layer_from_combo(self.layers) login = self.login.text() if self.save_login.isChecked(): set_setting(GEONODE_USER, login) else: set_setting(GEONODE_USER, '') password = self.password.text() if self.save_password.isChecked(): set_setting(GEONODE_PASSWORD, password) else: set_setting(GEONODE_PASSWORD, '') url = self.url.text() if self.save_url.isChecked(): set_setting(GEONODE_URL, url) else: set_setting(GEONODE_URL, '') geonode_session = login_user(url, login, password) try: result = upload(url, geonode_session, layer.source()) except GeoNodeLayerUploadError as e: result = { 'success': False, 'message': str(e) } finally: self.button_box.setEnabled(True) disable_busy_cursor() if result['success']: self.done(QDialog.Accepted) layer_url = urljoin(url, result['url']) # Link is not working in QGIS 2. # It's gonna work in QGIS 3. if qgis_version() >= 29900: external_link = '<a href=\"{url}\">{url}</a>'.format( url=layer_url) else: external_link = layer_url display_success_message_bar( tr('Uploading done'), tr('Successfully uploaded to {external_link}').format( external_link=external_link), ) else: display_warning_message_box( self, tr('Error while uploading the layer.'), str(result) )
def save_state(self): """Store the options into the user's stored session info.""" # Save boolean settings for key, check_box in list(self.boolean_settings.items()): self.save_boolean_setting(key, check_box) # Save text settings for key, line_edit in list(self.text_settings.items()): self.save_text_setting(key, line_edit) set_setting( 'north_arrow_path', self.leNorthArrowPath.text(), self.settings) set_setting( 'organisation_logo_path', self.organisation_logo_path_line_edit.text(), self.settings) set_setting( 'reportTemplatePath', self.leReportTemplatePath.text(), self.settings) set_setting( 'reportDisclaimer', self.txtDisclaimer.toPlainText(), self.settings) set_setting( 'defaultUserDirectory', self.leUserDirectoryPath.text(), self.settings) index = self.earthquake_function.currentIndex() value = self.earthquake_function.itemData(index) set_setting('earthquake_function', value, qsettings=self.settings) currency_index = self.currency_combo_box.currentIndex() currency_key = self.currency_combo_box.itemData(currency_index) set_setting('currency', currency_key, qsettings=self.settings) # Save InaSAFE default values self.save_default_values() # Save population parameters self.save_population_parameters()
def get_qgis_app(requested_locale='en_US', qsetting=''): """ Start one QGIS application to test against. :param locale: The locale we want the qgis to launch with. :type locale: str :param qsetting: String to specify the QSettings. By default, use empty string. :type qsetting: str :returns: Handle to QGIS app, canvas, iface and parent. If there are any errors the tuple members will be returned as None. :rtype: (QgsApplication, CANVAS, IFACE, PARENT) If QGIS is already running the handle to that app will be returned. """ global QGIS_APP, PARENT, IFACE, CANVAS # pylint: disable=W0603 from qgis.PyQt.QtCore import QSettings if qsetting: settings = QSettings(qsetting) else: settings = QSettings() default_user_directory = setting('defaultUserDirectory') current_locale = general_setting( 'locale/userLocale', default='en_US', qsettings=settings) locale_match = current_locale == requested_locale if iface and locale_match: from qgis.core import QgsApplication QGIS_APP = QgsApplication CANVAS = iface.mapCanvas() PARENT = iface.mainWindow() IFACE = iface try: from qgis.core import QgsApplication from qgis.gui import QgsMapCanvas # pylint: disable=no-name-in-module # noinspection PyPackageRequirements from qgis.PyQt import QtWidgets, QtCore # pylint: disable=W0621 # noinspection PyPackageRequirements from qgis.PyQt.QtCore import QCoreApplication, QSettings from safe.test.qgis_interface import QgisInterface except ImportError: return None, None, None, None if qsetting: settings = QSettings(qsetting) else: settings = QSettings() if not QGIS_APP: gui_flag = True # All test will run qgis in gui mode # AG: For testing purposes, we use our own configuration file # instead of using the QGIS apps conf of the host # noinspection PyCallByClass,PyArgumentList QCoreApplication.setOrganizationName('QGIS') # noinspection PyCallByClass,PyArgumentList QCoreApplication.setOrganizationDomain('qgis.org') # noinspection PyCallByClass,PyArgumentList QCoreApplication.setApplicationName('QGIS2InaSAFETesting') # We disabled message bars for now for extent selector as # we don't have a main window to show them in TS - version 3.2 set_setting('show_extent_warnings', False, settings) set_setting('showRubberBands', True, settings) set_setting('show_extent_confirmations', False, settings) set_setting('analysis_extents_mode', HAZARD_EXPOSURE, settings) if default_user_directory: set_setting( 'defaultUserDirectory', default_user_directory, settings) # noinspection PyPep8Naming if 'argv' in dir(sys): QGIS_APP = QgsApplication([p.encode('utf-8') for p in sys.argv], gui_flag) else: QGIS_APP = QgsApplication([], gui_flag) # Make sure QGIS_PREFIX_PATH is set in your env if needed! QGIS_APP.initQgis() # Initialize processing processing.Processing.initialize() s = QGIS_APP.showSettings() LOGGER.debug(s) if not locale_match: """Setup internationalisation for the plugin.""" # Save some settings set_general_setting('locale/overrideFlag', True, settings) set_general_setting('locale/userLocale', requested_locale, settings) locale_name = str(requested_locale).split('_')[0] # Also set the system locale to the user overridden local # so that the inasafe library functions gettext will work # .. see:: :py:func:`common.utilities` os.environ['LANG'] = str(locale_name) inasafe_translation_path = os.path.join( safe_dir('i18n'), 'inasafe_' + str(locale_name) + '.qm') if os.path.exists(inasafe_translation_path): if isinstance(QGIS_APP, sip.wrappertype): translator = QTranslator() else: translator = QTranslator(QGIS_APP) result = translator.load(inasafe_translation_path) if not result: message = 'Failed to load translation for %s' % locale_name raise Exception(message) # noinspection PyTypeChecker,PyCallByClass QCoreApplication.installTranslator(translator) # at the end, reload InaSAFE modules so it will get translated too reload_inasafe_modules() if PARENT is None: # noinspection PyPep8Naming PARENT = QtWidgets.QWidget() if CANVAS is None: # noinspection PyPep8Naming CANVAS = QgsMapCanvas(PARENT) CANVAS.resize(QtCore.QSize(400, 400)) if IFACE is None: # QgisInterface is a stub implementation of the QGIS plugin interface # noinspection PyPep8Naming IFACE = QgisInterface(CANVAS) return QGIS_APP, CANVAS, IFACE, PARENT