def testCancel(self): f = QgsFeedback() self.assertFalse(f.isCanceled()) cancel_spy = QSignalSpy(f.canceled) f.cancel() self.assertTrue(f.isCanceled()) self.assertEqual(len(cancel_spy), 1)
def testProgress(self): f = QgsFeedback() self.assertEqual(f.progress(), 0.0) progress_spy = QSignalSpy(f.progressChanged) f.setProgress(25) self.assertEqual(f.progress(), 25.0) self.assertEqual(len(progress_spy), 1) self.assertEqual(progress_spy[0][0], 25.0)
def testProcessedCount(self): f = QgsFeedback() self.assertEqual(f.processedCount(), 0) processed_spy = QSignalSpy(f.processedCountChanged) f.setProcessedCount(25) self.assertEqual(f.processedCount(), 25) self.assertEqual(len(processed_spy), 1) self.assertEqual(processed_spy[0][0], 25)
def test_process_err(self): def std_out(ba): std_out.val += ba.data().decode('UTF-8') std_out.val = '' def std_err(ba): std_err.val += ba.data().decode('UTF-8') std_err.val = '' p = QgsBlockingProcess('ogrinfo', []) p.setStdOutHandler(std_out) p.setStdErrHandler(std_err) f = QgsFeedback() self.assertEqual(p.run(f), 1) self.assertIn('Usage', std_out.val) self.assertIn('FAILURE', std_err.val)
def test_process_ok(self): def std_out(ba): std_out.val += ba.data().decode('UTF-8') std_out.val = '' def std_err(ba): std_err.val += ba.data().decode('UTF-8') std_err.val = '' p = QgsBlockingProcess('ogrinfo', ['--version']) p.setStdOutHandler(std_out) p.setStdErrHandler(std_err) f = QgsFeedback() self.assertEqual(p.run(f), 0) self.assertIn('GDAL', std_out.val) self.assertEqual(std_err.val, '')
def testRunChecks(self): registry = QgsValidityCheckRegistry() res1 = QgsValidityCheckResult() res1.type = QgsValidityCheckResult.Warning res1.title = 'test' res1.detailedDescription = 'blah blah' c1 = TestCheck('c1', 'my check', 1, [res1]) registry.addCheck(c1) res2 = QgsValidityCheckResult() res2.type = QgsValidityCheckResult.Critical res2.title = 'test2' res2.detailedDescription = 'blah blah2' c2 = TestCheck('c2', 'my check2', 2, [res2]) registry.addCheck(c2) res3 = QgsValidityCheckResult() res3.type = QgsValidityCheckResult.Warning res3.title = 'test3' res3.detailedDescription = 'blah blah3' res4 = QgsValidityCheckResult() res4.type = QgsValidityCheckResult.Warning res4.title = 'test4' res4.detailedDescription = 'blah blah4' c3 = TestCheck('c3', 'my check3', 1, [res3, res4]) registry.addCheck(c3) context = TestContext() feedback = QgsFeedback() self.assertFalse(registry.runChecks(0, context, feedback)) self.assertEqual([r.type for r in registry.runChecks(1, context, feedback)], [QgsValidityCheckResult.Warning, QgsValidityCheckResult.Warning, QgsValidityCheckResult.Warning]) self.assertEqual([r.title for r in registry.runChecks(1, context, feedback)], ['test', 'test3', 'test4']) self.assertEqual([r.detailedDescription for r in registry.runChecks(1, context, feedback)], ['blah blah', 'blah blah3', 'blah blah4']) self.assertEqual([r.type for r in registry.runChecks(2, context, feedback)], [QgsValidityCheckResult.Critical]) self.assertEqual([r.title for r in registry.runChecks(2, context, feedback)], ['test2']) self.assertEqual([r.detailedDescription for r in registry.runChecks(2, context, feedback)], ['blah blah2'])
def _start_process(self): """Make some stuff before launching the process.""" QApplication.setOverrideCursor(Qt.WaitCursor) self.dialog.feedback_process = QgsFeedback() if self.panel == Panels.QuickQuery: self.dialog.button_show_query.setDisabled(True) if self.panel == Panels.Query: self.dialog.button_generate_query.setDisabled(True) self.dialog.execute_buttons[self.panel].setCurrentIndex(1) if self.dialog.output_directories[self.panel]: self.dialog.output_directories[self.panel].setDisabled(True) self.dialog.progress_bar.setMinimum(0) self.dialog.progress_bar.setMaximum(0) self.dialog.progress_bar.setValue(0) self.dialog.progress_text.setText('') QApplication.processEvents()
def testExecuteSqlCancel(self): """Test that feedback can cancel an executeSql query""" if hasattr(self, 'slowQuery'): md = QgsProviderRegistry.instance().providerMetadata(self.providerKey) conn = md.createConnection(self.uri, {}) feedback = QgsFeedback() def _run(task): conn.executeSql(self.slowQuery, feedback=feedback) def _cancel(): feedback.cancel() start = time.time() QtCore.QTimer.singleShot(500, _cancel) task = QgsTask.fromFunction('test long running query', _run) QgsApplication.taskManager().addTask(task) while task.status() not in [QgsTask.Complete, QgsTask.Terminated]: QgsApplication.processEvents() end = time.time() self.assertTrue(end - start < 1)
def open_style(input_file): # pylint: disable=too-many-locals,too-many-branches,too-many-statements """ Opens a .style file """ if not Extractor.is_mdb_tools_binary_available(): bar = iface.messageBar() widget = bar.createMessage('SLYR', "MDB Tools utility not found") settings_button = QPushButton("Configure…", pressed=partial(open_settings, widget)) widget.layout().addWidget(settings_button) bar.pushWidget(widget, Qgis.Critical) return True style = QgsStyle() style.createMemoryDatabase() symbol_names = set() def make_name_unique(name): """ Ensures that the symbol name is unique (in a case insensitive way) """ counter = 0 candidate = name while candidate.lower() in symbol_names: # make name unique if counter == 0: candidate += '_1' else: candidate = candidate[:candidate.rfind('_') + 1] + str(counter) counter += 1 symbol_names.add(candidate.lower()) return candidate feedback = QgsFeedback() progress_dialog = QProgressDialog("Loading style database…", "Abort", 0, 100, None) progress_dialog.setWindowTitle("Loading Style") def progress_changed(progress): """ Handles feedback to progress dialog bridge """ progress_dialog.setValue(progress) iters = 0 while QCoreApplication.hasPendingEvents() and iters < 100: QCoreApplication.processEvents() iters += 1 feedback.progressChanged.connect(progress_changed) def cancel(): """ Slot to cancel the import """ feedback.cancel() progress_dialog.canceled.connect(cancel) unreadable = [] warnings = set() errors = set() types_to_extract = [Extractor.FILL_SYMBOLS, Extractor.LINE_SYMBOLS, Extractor.MARKER_SYMBOLS, Extractor.COLOR_RAMPS, Extractor.TEXT_SYMBOLS, Extractor.LABELS, Extractor.MAPLEX_LABELS, Extractor.AREA_PATCHES, Extractor.LINE_PATCHES] type_percent = 100 / len(types_to_extract) for type_index, symbol_type in enumerate(types_to_extract): try: raw_symbols = Extractor.extract_styles(input_file, symbol_type) except MissingBinaryException: show_warning('MDB Tools utility not found', 'Convert style', 'The MDB tools "mdb-export" utility is required to convert .style databases. Please setup a path to the MDB tools utility in the SLYR options panel.', level=Qgis.Critical) progress_dialog.deleteLater() return True if feedback.isCanceled(): break for index, raw_symbol in enumerate(raw_symbols): feedback.setProgress(index / len(raw_symbols) * type_percent + type_percent * type_index) if feedback.isCanceled(): break name = raw_symbol[Extractor.NAME] tags = raw_symbol[Extractor.TAGS].split(';') if symbol_type in ( Extractor.AREA_PATCHES, Extractor.LINE_PATCHES, Extractor.TEXT_SYMBOLS, Extractor.MAPLEX_LABELS, Extractor.LABELS): if symbol_type == Extractor.AREA_PATCHES: type_string = 'area patches' elif symbol_type == Extractor.LINE_PATCHES: type_string = 'line patches' elif symbol_type == Extractor.TEXT_SYMBOLS: type_string = 'text symbols' elif symbol_type == Extractor.MAPLEX_LABELS: type_string = 'maplex labels' elif symbol_type == Extractor.LABELS: type_string = 'labels' else: type_string = '' unreadable.append('<b>{}</b>: {} conversion requires a licensed version of the SLYR plugin'.format( html.escape(name), type_string)) continue unique_name = make_name_unique(name) handle = BytesIO(raw_symbol[Extractor.BLOB]) stream = Stream(handle) stream.allow_shortcuts = False try: symbol = stream.read_object() except UnreadableSymbolException as e: e = 'Unreadable object: {}'.format(e) unreadable.append('<b>{}</b>: {}'.format(html.escape(name), html.escape(str(e)))) continue except NotImplementedException as e: unreadable.append('<b>{}</b>: {}'.format(html.escape(name), html.escape(str(e)))) continue except UnsupportedVersionException as e: e = 'Unsupported version: {}'.format(e) unreadable.append('<b>{}</b>: {}'.format(html.escape(name), html.escape(str(e)))) continue except UnknownClsidException as e: unreadable.append('<b>{}</b>: {}'.format(html.escape(name), html.escape(str(e)))) continue except UnreadablePictureException as e: unreadable.append('<b>{}</b>: {}'.format(html.escape(name), html.escape(str(e)))) continue context = Context() context.symbol_name = unique_name def unsupported_object_callback(msg, level=Context.WARNING): if level == Context.WARNING: warnings.add('<b>{}</b>: {}'.format(html.escape(unique_name), html.escape(msg))) elif level == Context.CRITICAL: errors.add('<b>{}</b>: {}'.format(html.escape(unique_name), html.escape(msg))) context.unsupported_object_callback = unsupported_object_callback # context.style_folder, _ = os.path.split(output_file) try: qgis_symbol = SymbolConverter.Symbol_to_QgsSymbol(symbol, context) except NotImplementedException as e: unreadable.append('<b>{}</b>: {}'.format(html.escape(name), html.escape(str(e)))) continue except UnreadablePictureException as e: unreadable.append('<b>{}</b>: {}'.format(html.escape(name), html.escape(str(e)))) continue if isinstance(qgis_symbol, QgsSymbol): # self.check_for_missing_fonts(qgis_symbol, feedback) style.addSymbol(unique_name, qgis_symbol, True) elif isinstance(qgis_symbol, QgsColorRamp): style.addColorRamp(unique_name, qgis_symbol, True) if tags: if isinstance(qgis_symbol, QgsSymbol): assert style.tagSymbol(QgsStyle.SymbolEntity, unique_name, tags) elif isinstance(qgis_symbol, QgsColorRamp): assert style.tagSymbol(QgsStyle.ColorrampEntity, unique_name, tags) progress_dialog.deleteLater() if feedback.isCanceled(): return True if errors or unreadable or warnings: message = '' if unreadable: message = '<p>The following symbols could not be converted:</p>' message += '<ul>' for w in unreadable: message += '<li>{}</li>'.format(w.replace('\n', '<br>')) message += '</ul>' if errors: message += '<p>The following errors were generated while converting symbols:</p>' message += '<ul>' for w in errors: message += '<li>{}</li>'.format(w.replace('\n', '<br>')) message += '</ul>' if warnings: message += '<p>The following warnings were generated while converting symbols:</p>' message += '<ul>' for w in warnings: message += '<li>{}</li>'.format(w.replace('\n', '<br>')) message += '</ul>' show_warning('style could not be completely converted', 'Convert style', message, level=Qgis.Critical if (unreadable or errors) else Qgis.Warning) if Qgis.QGIS_VERSION_INT >= 30800: dlg = QgsStyleManagerDialog(style, readOnly=True) dlg.setFavoritesGroupVisible(False) dlg.setSmartGroupsVisible(False) fi = QFileInfo(input_file) dlg.setBaseStyleName(fi.baseName()) else: dlg = QgsStyleManagerDialog(style) dlg.exec_() return True
def processing(options, f, progressBar, progressMessage): ''' Select trees which are on the contour of the forest and isolated trees. ''' # Export Grid contour and isolated to crowns values forestSelectedPath = options['dst'] + 'tif/' + f + \ '_forest_selected.tif' crownsPath = options['dst'] + 'shp/' + f + '_crowns.shp' # crownsStatsPath = options['dst'] + 'shp/' + f + '_crowns_stats.shp' outputDir = options["dst"] fileTxt = open(outputDir + "/log.txt", "a") fileTxt.write("gridstatisticsforpolygons started\n") fileTxt.close() crowns = QgsVectorLayer(crownsPath, "crowns", "ogr") inputStatRaster = QgsRasterLayer(forestSelectedPath, "forestSelected") z_stat = QgsZonalStatistics(crowns, inputStatRaster, '_', 1, QgsZonalStatistics.Max) result_z_stat = z_stat.calculateStatistics(QgsFeedback()) outputDir = options["dst"] fileTxt = open(outputDir + "/log.txt", "a") fileTxt.write("gridstatisticsforpolygons passed\n") fileTxt.close() # crowns = QgsVectorLayer(crownsStatsPath, 'Crowns stats', 'ogr') crowns.selectByExpression('"_max"=1.0') selected_array = crowns.getValues("N", True) crowns.invertSelection() unselected_array = crowns.getValues("N", True) unselected_crowns_ids = crowns.getValues("$id", True) unselected_top_ids = crowns.getValues('"N" - 1', True) crowns.dataProvider().deleteFeatures(unselected_crowns_ids[0]) treetopsPath = options['dst'] + 'shp/' + f + '_treetops.shp' treetops = QgsVectorLayer(treetopsPath, 'Tree tops', 'ogr') treetops.dataProvider().deleteFeatures(unselected_top_ids[0]) treetopsSelectedPath = options['dst'] + 'shp/' + f + \ '_treetops_selected.shp' crownsSelectedPath = options['dst'] + 'shp/' + f + '_crowns_selected.shp' treetopsTrianglesPath = options['dst'] + 'shp/' + f + \ '_treetops_triangles.shp' outputDir = options["dst"] fileTxt = open(outputDir + "/log.txt", "a") fileTxt.write("advancedpythonfieldcalculator started\n") fileTxt.close() treetops.dataProvider().addAttributes([QgsField('N', QVariant.Int)]) treetops.updateFields() treetops.startEditing() for treetop in treetops.getFeatures(): treetops.changeAttributeValue(treetop.id(), treetop.fieldNameIndex('N'), treetop.id()) treetops.commitChanges() outputDir = options["dst"] fileTxt = open(outputDir + "/log.txt", "a") fileTxt.write("joinattributesbylocation started\n") fileTxt.close() # Adapted from https://github.com/qgis/QGIS-Processing # TODO: replace by native QGIS c++ algo when available... crowns.dataProvider().addAttributes([QgsField('tid', QVariant.Int)]) crowns.updateFields() crowns.startEditing() fcount = crowns.featureCount() counter = 0 for crown in crowns.getFeatures(): counter += 1 progressBar.setValue(100 + int(counter * (600 / fcount))) progressMessage.setText('Joining crown ' + str(counter) + '/' + str(fcount)) request = QgsFeatureRequest() request.setFilterRect(crown.geometry().boundingBox()) dp = treetops.dataProvider() for r in dp.getFeatures(request): if crown.geometry().intersects(r.geometry()): crowns.changeAttributeValue(crown.id(), crown.fieldNameIndex('tid'), r.id()) crowns.commitChanges() fileTxt = open(outputDir + "/log.txt", "a") fileTxt.write("delaunaytriangulation started\n") fileTxt.close() # delaunay triangulation Adapted from official Python plugin # TODO: replace by native QGIS c++ algo when available... fields = QgsFields() fields.append(QgsField('POINTA', QVariant.Double, '', 24, 15)) fields.append(QgsField('POINTB', QVariant.Double, '', 24, 15)) fields.append(QgsField('POINTC', QVariant.Double, '', 24, 15)) crs = QgsCoordinateReferenceSystem('EPSG:2056') triangleFile = QgsVectorFileWriter(treetopsTrianglesPath, 'utf-8', fields, QgsWkbTypes.Polygon, crs, 'ESRI Shapefile') pts = [] ptDict = {} ptNdx = -1 c = voronoi.Context() features = treetops.getFeatures() total = 100.0 / treetops.featureCount() if treetops.featureCount() else 0 progressMessage.setText('Starting triangulation...') for current, inFeat in enumerate(features): geom = QgsGeometry(inFeat.geometry()) if geom.isNull(): continue if geom.isMultipart(): points = geom.asMultiPoint() else: points = [geom.asPoint()] for n, point in enumerate(points): x = point.x() y = point.y() pts.append((x, y)) ptNdx += 1 ptDict[ptNdx] = (inFeat.id(), n) progressMessage.setText('Triangulation step 1 ok') if len(pts) < 3: raise QgsProcessingException( 'Input file should contain at least 3 points. Choose ' 'another file and try again.') uniqueSet = set(item for item in pts) ids = [pts.index(item) for item in uniqueSet] sl = voronoi.SiteList([voronoi.Site(*i) for i in uniqueSet]) c.triangulate = True voronoi.voronoi(sl, c) triangles = c.triangles feat = QgsFeature() total = 100.0 / len(triangles) if triangles else 1 for current, triangle in enumerate(triangles): indices = list(triangle) indices.append(indices[0]) polygon = [] attrs = [] step = 0 for index in indices: fid, n = ptDict[ids[index]] request = QgsFeatureRequest().setFilterFid(fid) inFeat = next(treetops.getFeatures(request)) geom = QgsGeometry(inFeat.geometry()) point = QgsPoint(geom.asPoint()) polygon.append(point) if step <= 3: attrs.append(ids[index]) step += 1 linestring = QgsLineString(polygon) poly = QgsPolygon() poly.setExteriorRing(linestring) feat.setAttributes(attrs) geometry = QgsGeometry().fromWkt(poly.asWkt()) feat.setGeometry(geometry) triangleFile.addFeature(feat) progressMessage.setText('Triangulation terminated') # Remove triangles with perimeter higher than threshold triangles = QgsVectorLayer(treetopsTrianglesPath, 'triangles', 'ogr') maxPeri = str(options['MaxTrianglePerimeter']) triangles.selectByExpression('$perimeter > ' + maxPeri) triangles_to_delete_ids = triangles.getValues("$id", True) triangles.dataProvider().deleteFeatures(triangles_to_delete_ids[0]) outputDir = options["dst"] fileTxt = open(outputDir + "/log.txt", "a") fileTxt.write("treeSelector passed\n") fileTxt.close() progressMessage.setText('Starting convexhull computing...')
def test_process_env(self): """ Test that process inherits system environment correctly """ temp_folder = tempfile.mkdtemp() script_file = os.path.join(temp_folder, 'process_env.sh') with open(script_file, 'wt') as f: f.write('echo $my_var') os.chmod(script_file, 0o775) def std_out(ba): std_out.val += ba.data().decode('UTF-8') std_out.val = '' def std_err(ba): std_err.val += ba.data().decode('UTF-8') std_err.val = '' # environment variable not set: p = QgsBlockingProcess('sh', [script_file]) p.setStdOutHandler(std_out) p.setStdErrHandler(std_err) f = QgsFeedback() self.assertEqual(p.run(f), 0) self.assertEqual(p.exitStatus(), QProcess.NormalExit) self.assertFalse(std_out.val.strip()) self.assertFalse(std_err.val.strip()) # set environment variable os.environ['my_var'] = 'my test variable' std_out.val = '' std_err.val = '' p = QgsBlockingProcess('sh', [script_file]) p.setStdOutHandler(std_out) p.setStdErrHandler(std_err) f = QgsFeedback() self.assertEqual(p.run(f), 0) self.assertEqual(p.exitStatus(), QProcess.NormalExit) self.assertEqual(std_out.val.strip(), 'my test variable') self.assertFalse(std_err.val.strip()) # test python changing path script_file = os.path.join(temp_folder, 'process_env_path.sh') with open(script_file, 'wt') as f: f.write('echo $PATH') prev_path_val = os.getenv('PATH') new_path = "{}{}{}".format('/my_test/folder', os.pathsep, prev_path_val) os.environ['PATH'] = new_path std_out.val = '' std_err.val = '' p = QgsBlockingProcess('sh', [script_file]) p.setStdOutHandler(std_out) p.setStdErrHandler(std_err) f = QgsFeedback() self.assertEqual(p.run(f), 0) self.assertEqual(p.exitStatus(), QProcess.NormalExit) self.assertEqual(std_out.val.strip(), new_path) self.assertFalse(std_err.val.strip())
class ExportTask(ScenarioBaseTask): """ A background task for exporting electorates, meshblock assignments """ GN = 'GN' GS = 'GS' M = 'M' def __init__(self, task_name: str, dest_file: str, electorate_registry: LinzElectoralDistrictRegistry, meshblock_layer: QgsVectorLayer, meshblock_number_field_name: str, scenario_registry: ScenarioRegistry, scenario, user_log_layer: QgsVectorLayer): """ Constructor for ExportTask :param task_name: user-visible, translated name for task :param dest_file: destination filename :param electorate_registry: electorate registry :param meshblock_layer: meshblock layer :param meshblock_number_field_name: name of meshblock number field :param scenario_registry: scenario registry :param scenario: target scenario id to switch to :param user_log_layer: user log layer """ self.electorate_registry = electorate_registry super().__init__( task_name=task_name, electorate_layer=self.electorate_registry.source_layer, meshblock_layer=meshblock_layer, meshblock_number_field_name=meshblock_number_field_name, scenario_registry=scenario_registry, scenario=scenario, task=None) self.dest_file = dest_file self.message = None self.user_log_layer = user_log_layer self.feedback = QgsFeedback() def cancel(self): """ Cancels the export """ super().cancel() self.feedback.cancel() def run(self): # pylint: disable=missing-docstring,too-many-locals,too-many-return-statements,too-many-branches,too-many-statements try: electorate_geometries, electorate_attributes = self.calculate_new_electorates( ) except CanceledException: return False # we also need a dictionary of meshblock number to all electorate types meshblock_electorates = {} electorate_features = [] for electorate_feature_id, attributes in electorate_attributes.items(): if self.isCanceled(): return False electorate_code = attributes[self.ELECTORATE_CODE] geometry = electorate_geometries[electorate_feature_id] meshblocks = attributes[self.MESHBLOCKS] electorate_type = attributes[self.ELECTORATE_TYPE] name = attributes[self.ELECTORATE_NAME] for m in meshblocks: meshblock_number = m[self.meshblock_number_idx] if meshblock_number not in meshblock_electorates: meshblock_electorates[meshblock_number] = {} meshblock_electorates[meshblock_number][ electorate_type] = electorate_code if self.isCanceled(): return False electorate_feature = QgsFeature() electorate_feature.setGeometry(geometry) electorate_feature.setAttributes( [electorate_type, electorate_code, name]) electorate_features.append(electorate_feature) electorate_layer = QgsVectorLayer( "Polygon?crs=EPSG:2193&field=type:string(2)&field=code:string&field=name:string", "source", "memory") if not electorate_layer.dataProvider().addFeatures( electorate_features): return False if self.isCanceled(): return False options = QgsVectorFileWriter.SaveVectorOptions() options.driverName = 'GPKG' options.layerName = 'electorates' options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteFile options.feedback = self.feedback error, self.message = QgsVectorFileWriter.writeAsVectorFormat( electorate_layer, self.dest_file, options) if error: return False if self.isCanceled(): return False layer = QgsVectorLayer( "NoGeometry?field=meshblock_number:int&field=gn_code:string&field=gs_code:string&field=m_code:string", "source", "memory") meshblock_features = [] for meshblock_number, electorates in meshblock_electorates.items(): f = QgsFeature() gn = electorates[self.GN] if self.GN in electorates else NULL gs = electorates[self.GS] if self.GS in electorates else NULL m = electorates[self.M] if self.M in electorates else NULL f.setAttributes([meshblock_number, gn, gs, m]) meshblock_features.append(f) if self.isCanceled(): return False layer.dataProvider().addFeatures(meshblock_features) options = QgsVectorFileWriter.SaveVectorOptions() options.driverName = 'GPKG' options.layerName = 'meshblocks' options.feedback = self.feedback options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteLayer error, self.message = QgsVectorFileWriter.writeAsVectorFormat( layer, self.dest_file, options) if error: return False if self.isCanceled(): return False options = QgsVectorFileWriter.SaveVectorOptions() options.driverName = 'GPKG' options.layerName = 'user_log' options.feedback = self.feedback options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteLayer error, self.message = QgsVectorFileWriter.writeAsVectorFormat( self.user_log_layer, self.dest_file, options) if error: return False return True
def __init__(self, iface=None, parent=None): """Constructor.""" QDialog.__init__(self, parent) self.setupUi(self) self._iface = iface self.query_menu_index = 2 self.preset_menu_index = 0 # Table mapping # Explaining quickly, these letters are referring to the panel # in the UI: # mp : Map preset # qq : Quick Query # q : Query # f : file self.external_panels = { Panels.MapPreset: MapPresetPanel(self), Panels.QuickQuery: QuickQueryPanel(self), Panels.Query: QueryPanel(self), Panels.File: OsmFilePanel(self), Panels.Configuration: ConfigurationPanel(self), } self.places_edits = { Panels.MapPreset: self.line_place_mp, Panels.QuickQuery: self.line_place_qq, Panels.Query: self.line_place_q, } self.query_type_buttons = { Panels.MapPreset: self.combo_query_type_mp, Panels.QuickQuery: self.combo_query_type_qq, Panels.Query: self.combo_query_type_q, } self.layers_buttons = { Panels.MapPreset: self.combo_extent_layer_mp, Panels.QuickQuery: self.combo_extent_layer_qq, Panels.Query: self.combo_extent_layer_q, } self.selection_features = { Panels.MapPreset: self.checkbox_selection_mp, Panels.QuickQuery: self.checkbox_selection_qq, Panels.Query: self.checkbox_selection_q, } self.run_buttons = { Panels.MapPreset: self.button_run_query_mp, Panels.QuickQuery: self.button_run_query_qq, Panels.Query: self.button_run_query_q, Panels.File: self.button_run_file, } self.cancel_buttons = { Panels.MapPreset: self.button_cancel_query_mp, Panels.QuickQuery: self.button_cancel_query_qq, Panels.Query: self.button_cancel_query_q, Panels.File: self.button_cancel_file, } self.execute_buttons = { Panels.MapPreset: self.stacked_execute_query_mp, Panels.QuickQuery: self.stacked_execute_query_qq, Panels.Query: self.stacked_execute_query_q, Panels.File: self.stacked_execute_file, } self.output_buttons = { Panels.MapPreset: [], Panels.QuickQuery: [ self.checkbox_points_qq, self.checkbox_lines_qq, self.checkbox_multilinestrings_qq, self.checkbox_multipolygons_qq ], Panels.Query: [ self.checkbox_points_q, self.checkbox_lines_q, self.checkbox_multilinestrings_q, self.checkbox_multipolygons_q, ], Panels.File: [ self.checkbox_points_f, self.checkbox_lines_f, self.checkbox_multilinestrings_f, self.checkbox_multipolygons_f, ] } self.output_directories = { Panels.MapPreset: None, Panels.QuickQuery: self.output_directory_qq, Panels.Query: self.output_directory_q, Panels.File: self.output_directory_f } self.output_format = { Panels.MapPreset: None, Panels.QuickQuery: self.combo_format_qq, Panels.Query: self.combo_format_q, Panels.File: self.combo_format_f } self.prefix_edits = { Panels.MapPreset: None, Panels.QuickQuery: self.line_file_prefix_qq, Panels.Query: self.line_file_prefix_q, Panels.File: self.line_file_prefix_file, } self.advanced_panels = { Panels.MapPreset: None, Panels.QuickQuery: self.advanced_qq, Panels.Query: self.advanced_q, } self.query_language = { Panels.MapPreset: None, Panels.QuickQuery: QueryLanguage.OQL, Panels.Query: QueryLanguage.OQL, } self.action_oql_qq = QAction('OQL') self.action_oql_q = QAction('OQL') self.action_oql = { Panels.QuickQuery: self.action_oql_qq, Panels.Query: self.action_oql_q, } self.action_xml_qq = QAction('XML') self.action_xml_q = QAction('XML') self.action_xml = { Panels.QuickQuery: self.action_xml_qq, Panels.Query: self.action_xml_q, } icon = QIcon(resources_path('icons', 'QuickOSM.svg')) self.reload_action = QAction(icon, tr("Reload the query in a new file"), self.iface) actions = Actions(self) reloader = partial(actions.pre_run_reload) self.reload_action.triggered.connect(reloader) self.iface.addCustomActionForLayerType(self.reload_action, "", QgsMapLayer.VectorLayer, False) self.feedback_process = QgsFeedback() item = self.menu_widget.item(0) item.setIcon(QIcon(resources_path('icons', 'map_tools.svg'))) item = self.menu_widget.item(1) item.setIcon(QIcon(resources_path('icons', 'quick.png'))) item = self.menu_widget.item(2) item.setIcon(QIcon(resources_path('icons', 'edit.png'))) item = self.menu_widget.item(3) item.setIcon(QIcon(resources_path('icons', 'open.png'))) item = self.menu_widget.item(4) item.setIcon(QIcon(resources_path('icons', 'general.svg'))) item = self.menu_widget.item(5) item.setIcon(QIcon(resources_path('icons', 'info.png'))) self.label_gnu.setPixmap(QPixmap(resources_path('icons', 'gnu.png'))) # Set minimum width for the menu self.menu_widget.setMinimumWidth( self.menu_widget.sizeHintForColumn(0) + 10) self.progress_text.setText('') self.menu_widget.currentRowChanged['int'].connect( self.stacked_panels_widget.setCurrentIndex) for panel in self.external_panels.values(): panel.setup_panel() self.menu_widget.setCurrentRow(1)
def exportCompo(self, cView, folder, title, extension): """Function that sets how to export files. Returns a file :param cView: The print layout to export :param folder: The folder in which to store the output file :param title: The print layout name :param extension: The file extension to use for the output :return: A file representing the layout in the selected format """ #self.msgWMSWarning(cView) myAtlas = cView.atlas() #Let's use custom export properties if there are exportSettings = self.overrideExportSettings(cView, extension) # Do the export process exporter = QgsLayoutExporter(cView) if myAtlas.enabled(): feedback = QgsFeedback() # if single file export is required (only compatible with pdf, yet) # singleFile can be true and None in that case if cView.customProperty( 'singleFile') is not False and extension == '.pdf': result, error = exporter.exportToPdf( myAtlas, os.path.join(folder, title + '.pdf'), exportSettings, feedback) else: #If instead multiple files will be output # Check if there's a valid expression for filenames, # and otherwise inform that a default one will be used and set it using the layout name. # replacement in the GUI is failing at the moment # if len(myAtlas.filenameExpression()) == 0: # self.iface.messageBar().pushMessage( # self.tr(u'Empty filename expression'), # self.tr(u'The print layout "{}" has an empty output filename expression. {}_@atlas_pagename is used as default.').format(title, title), # level = Qgis.Warning # ) # myAtlas.setFilenameExpression(u"'{}_'||@atlas_pagename".format(title)) current_fileName = myAtlas.filenameExpression() #export atlas to multiple pdfs if extension == '.pdf': result, error = exporter.exportToPdfs( myAtlas, os.path.join(folder, current_fileName), exportSettings, feedback) # export atlas to svg format elif extension == '.svg': result, error = exporter.exportToSvg( myAtlas, os.path.join(folder, current_fileName), exportSettings, feedback) # export atlas to image format else: result, error = exporter.exportToImage( myAtlas, os.path.join(folder, current_fileName), extension, exportSettings, feedback) myAtlas.endRender() # if the composition has no atlas else: if extension == '.pdf': result = exporter.exportToPdf( os.path.join(folder, title + '.pdf'), exportSettings) elif extension == '.svg': result = exporter.exportToSvg( os.path.join(folder, title + '.svg'), exportSettings) else: result = exporter.exportToImage( os.path.join(folder, title + extension), exportSettings) return result == QgsLayoutExporter.Success
def test_geocode(self): geocoder = TestGeocoder() canvas = QgsMapCanvas() filter = QgsGeocoderLocatorFilter('testgeocoder', 'my geocoder', 'pref', geocoder, canvas, QgsRectangle(-1, -1, 1, 1)) self.assertEqual(filter.name(), 'testgeocoder') self.assertEqual(filter.displayName(), 'my geocoder') self.assertEqual(filter.prefix(), 'pref') self.assertEqual(filter.geocoder(), geocoder) self.assertEqual(filter.boundingBox(), QgsRectangle(-1, -1, 1, 1)) spy = QSignalSpy(filter.resultFetched) context = QgsLocatorContext() feedback = QgsFeedback() # no results filter.fetchResults('cvxbcvb', context, feedback) self.assertEqual(len(spy), 0) # one result filter.fetchResults('a', context, feedback) self.assertEqual(len(spy), 1) res = spy[-1][0] self.assertEqual(res.displayString, 'res 1') # some sip weirdness here -- if we directly access the QgsLocatorResult object here then we get segfaults! # so instead convert back to QgsGeocoderResult. This makes the test more robust anyway... geocode_result = filter.locatorResultToGeocoderResult(res) self.assertEqual(geocode_result.identifier(), 'res 1') self.assertEqual(geocode_result.geometry().asWkt(), 'Point (1 2)') self.assertEqual(geocode_result.crs().authid(), 'EPSG:4326') self.assertEqual(geocode_result.additionalAttributes(), { 'b': 123, 'c': 'xyz' }) self.assertTrue(geocode_result.viewport().isNull()) self.assertFalse(geocode_result.description()) self.assertFalse(geocode_result.group()) # two possible results filter.fetchResults('b', context, feedback) self.assertEqual(len(spy), 3) res1 = spy[-2][0] res2 = spy[-1][0] self.assertEqual(res1.displayString, 'res 1') geocode_result = filter.locatorResultToGeocoderResult(res1) self.assertEqual(geocode_result.identifier(), 'res 1') self.assertEqual(geocode_result.geometry().asWkt(), 'Point (11 12)') self.assertEqual(geocode_result.crs().authid(), 'EPSG:4326') self.assertEqual(geocode_result.additionalAttributes(), { 'b': 123, 'c': 'xyz' }) self.assertTrue(geocode_result.viewport().isNull()) self.assertEqual(geocode_result.description(), 'desc') self.assertEqual(geocode_result.group(), 'group') self.assertEqual(res2.displayString, 'res 2') geocode_result = filter.locatorResultToGeocoderResult(res2) self.assertEqual(geocode_result.identifier(), 'res 2') self.assertEqual(geocode_result.geometry().asWkt(), 'Point (13 14)') self.assertEqual(geocode_result.crs().authid(), 'EPSG:3857') self.assertEqual(geocode_result.additionalAttributes(), {'d': 456}) self.assertEqual(geocode_result.viewport(), QgsRectangle(1, 2, 3, 4)) self.assertFalse(geocode_result.description()) self.assertFalse(geocode_result.group())
def open_file(dialog: QDialog = None, osm_file: str = None, output_geom_types: list = None, white_list_column: dict = None, key: Union[str, List[str]] = None, layer_name: str = "OsmFile", config_outputs: dict = None, output_dir: str = None, output_format: Format = None, final_query: str = None, prefix_file: str = None, subset: bool = False, subset_query: str = None, feedback: QgsFeedback = None) -> int: """ Open an osm file. Memory layer if no output directory is set, or Geojson in the output directory. :param final_query: The query where the file comes from. Might be empty if it's a local OSM file. :type final_query: basestring """ if output_geom_types is None: output_geom_types = OSM_LAYERS # Legacy, waiting to remove the OsmParser for QGIS >= 3.6 # Change in osm_file_dialog.py L131 too output_geom_legacy = [geom.value.lower() for geom in output_geom_types] if not white_list_column: white_list_column = None LOGGER.info('The OSM file is: {}'.format(osm_file)) if feedback: if feedback.isCanceled(): return None # Parsing the file osm_parser = OsmParser(osm_file=osm_file, layers=output_geom_legacy, output_format=output_format, output_dir=output_dir, prefix_file=prefix_file, layer_name=layer_name, key=key, white_list_column=white_list_column, subset=subset, subset_query=subset_query, feedback=feedback) if dialog: osm_parser.signalText.connect(dialog.set_progress_text) osm_parser.signalPercentage.connect(dialog.set_progress_percentage) start_time = time.time() layers = osm_parser.processing_parse() elapsed_time = time.time() - start_time parser_time = time.strftime("%Hh %Mm %Ss", time.gmtime(elapsed_time)) LOGGER.info('The OSM parser took: {}'.format(parser_time)) if feedback: if feedback.isCanceled(): return None # Finishing the process with an output format or memory layer num_layers = 0 for i, (layer, item) in enumerate(layers.items()): if dialog: dialog.set_progress_percentage(i / len(layers) * 100) QApplication.processEvents() if item['featureCount'] and (LayerType(layer.capitalize()) in output_geom_types): final_layer_name = layer_name # If configOutputs is not None (from My Queries) if config_outputs: if config_outputs[layer]['namelayer']: final_layer_name = config_outputs[layer]['namelayer'] new_layer = item['vector_layer'] new_layer.setName(final_layer_name) # Try to set styling if defined if config_outputs and config_outputs[layer]['style']: new_layer.loadNamedStyle(config_outputs[layer]['style']) else: if "colour" in item['tags']: index = item['tags'].index('colour') colors = new_layer.uniqueValues(index) categories = [] for value in colors: if str(value) == 'None': value = '' if layer in ['lines', 'multilinestrings']: symbol = QgsSymbol.defaultSymbol( QgsWkbTypes.LineGeometry) elif layer == "points": symbol = QgsSymbol.defaultSymbol( QgsWkbTypes.PointGeometry) elif layer == "multipolygons": symbol = QgsSymbol.defaultSymbol( QgsWkbTypes.PolygonGeometry) symbol.setColor(QColor(value)) category = QgsRendererCategory(str(value), symbol, str(value)) categories.append(category) renderer = QgsCategorizedSymbolRenderer( "colour", categories) new_layer.setRenderer(renderer) # Add action about OpenStreetMap actions.add_actions(new_layer, item['tags']) QgsProject.instance().addMapLayer(new_layer) if final_query: QgsExpressionContextUtils.setLayerVariable( new_layer, 'quickosm_query', final_query) actions.add_relaunch_action(new_layer, final_layer_name) if dialog: dialog.iface.addCustomActionForLayer( dialog.reload_action, new_layer) metadata = QgsLayerMetadata() metadata.setRights([tr("© OpenStreetMap contributors")]) metadata.setLicenses(['https://openstreetmap.org/copyright']) new_layer.setMetadata(metadata) num_layers += 1 return num_layers