def testTakeLayer(self): # test taking ownership of a layer from the project l1 = createLayer('l1') l2 = createLayer('l2') p = QgsProject() # add one layer to project p.addMapLayer(l1) self.assertEqual(p.mapLayers(), {l1.id(): l1}) self.assertEqual(l1.parent().parent(), p) # try taking some layers which don't exist in project self.assertFalse(p.takeMapLayer(None)) self.assertFalse(p.takeMapLayer(l2)) # but l2 should still exist.. self.assertTrue(l2.isValid()) # take layer from project self.assertEqual(p.takeMapLayer(l1), l1) self.assertFalse(p.mapLayers()) # no layers left # but l1 should still exist self.assertTrue(l1.isValid()) # layer should have no parent now self.assertFalse(l1.parent()) # destroy project p = None self.assertTrue(l1.isValid())
def testProject(self): layer = QgsVectorLayer('{}|layername=countries'.format(ABSOLUTE_PATH), 'Test', 'ogr') # write p = QgsProject() fh = NamedTemporaryFile(delete=False) p.setFileName(fh.name) p.addMapLayer(layer) self.assertTrue(p.write()) found = False with open(fh.name) as fh: for line in fh: if '<datasource>localized:data/world_map.gpkg|layername=countries</datasource>' in line: found = True break self.assertTrue(found) # read p2 = QgsProject() p2.setFileName(fh.name) p2.read() self.assertTrue(len(p2.mapLayers())) self.assertEqual( p2.mapLayers()[layer.id()].source(), '{}/{}|layername=countries'.format(BASE_PATH, MAP_PATH)) os.remove(fh.name)
def testSaveLoadProject(self): schema_uri = encode_uri(self.ds_uri, 'qgis_test') project_uri = encode_uri(self.ds_uri, 'qgis_test', 'abc') self.dropProjectsTable() # make sure we have a clean start prj = QgsProject() uri = self.vl.source() vl1 = QgsVectorLayer(uri, 'test', 'postgres') self.assertEqual(vl1.isValid(), True) prj.addMapLayer(vl1) prj_storage = QgsApplication.projectStorageRegistry().projectStorageFromType("postgresql") self.assertTrue(prj_storage) lst0 = prj_storage.listProjects(schema_uri) self.assertEqual(lst0, []) # try to save project in the database prj.setFileName(project_uri) res = prj.write() self.assertTrue(res) lst1 = prj_storage.listProjects(schema_uri) self.assertEqual(lst1, ["abc"]) # now try to load the project back prj2 = QgsProject() prj2.setFileName(project_uri) res = prj2.read() self.assertTrue(res) self.assertEqual(len(prj2.mapLayers()), 1) self.assertEqual(prj2.baseName(), "abc") self.assertEqual(prj2.absoluteFilePath(), "") # path not supported for project storages self.assertTrue(abs(prj2.lastModified().secsTo(QDateTime.currentDateTime())) < 10) # try to see project's metadata res, metadata = prj_storage.readProjectStorageMetadata(project_uri) self.assertTrue(res) self.assertEqual(metadata.name, "abc") time_project = metadata.lastModified time_now = QDateTime.currentDateTime() time_diff = time_now.secsTo(time_project) self.assertTrue(abs(time_diff) < 10) # try to remove the project res = prj_storage.removeProject(project_uri) self.assertTrue(res) lst2 = prj_storage.listProjects(schema_uri) self.assertEqual(lst2, []) self.dropProjectsTable() # make sure we have a clean finish... "leave no trace"
def test_zip_unzip(self): tmpDir = QTemporaryDir() tmpFile = "{}/project.qgz".format(tmpDir.path()) project = QgsProject() l0 = QgsVectorLayer(os.path.join(TEST_DATA_DIR, "points.shp"), "points", "ogr") l1 = QgsVectorLayer(os.path.join(TEST_DATA_DIR, "lines.shp"), "lines", "ogr") project.addMapLayers([l0, l1]) self.assertTrue(project.write(tmpFile)) project2 = QgsProject() self.assertFalse(project2.isZipped()) self.assertTrue(project2.fileName() == "") self.assertTrue(project2.read(tmpFile)) self.assertTrue(project2.isZipped()) self.assertTrue(project2.fileName() == tmpFile) layers = project2.mapLayers() self.assertEqual(len(layers.keys()), 2) self.assertTrue(layers[l0.id()].isValid(), True) self.assertTrue(layers[l1.id()].isValid(), True) project2.clear() self.assertFalse(project2.isZipped())
def test_can_load_project(data): """ Check if project can be loaded """ source = str(data / "france_parts.qgs") project = QgsProject() project.read(source) assert len(project.mapLayers()) >= 1
def findVectorLayer(layername: str, project: QgsProject) -> QgsVectorLayer: """ Find vector layer with name, short name or layer id """ for layer in project.mapLayers().values(): # only vector layer if layer.type() != QgsMapLayer.VectorLayer: continue # check name if layer.name() == layername: return layer # check short name if layer.shortName() == layername: return layer # check layer id if layer.id() == layername: return layer return None
def get_project_summary(key: str, project: QgsProject): """ Return json summary for cached project """ def layer_summary(layer_id: str, layer: QgsMapLayer): return dict( id=layer_id, name=layer.name(), source=layer.publicSource(), crs=layer.crs().userFriendlyIdentifier(), valid=layer.isValid(), spatial=layer.isSpatial(), ) layers = [ layer_summary(idstr, l) for (idstr, l) in project.mapLayers().items() ] return dict(cache_key=key, filename=project.fileName(), bad_layers_count=sum(1 for ls in layers if not ls['valid']), layers=layers, crs=project.crs().userFriendlyIdentifier(), last_modified=project.lastModified().toString(Qt.ISODate))
def populateLayerTable(self, layerType): """ Fill the table for a given layer type """ # Get parameters for the widget lt = self.layersTable[layerType] table = lt['tableWidget'] # Reset layerBoardChangedData self.layerBoardChangedData[layerType] = {} # disconnect itemChanged signal try: table.itemChanged.disconnect() except Exception: pass attributes = self.layersTable['generic']['attributes'] + lt['attributes'] self.layersAttributes[layerType] = attributes self.layerBoardData[layerType] = [] headerData = [a['key'] for a in attributes] self.layerBoardData[layerType].append(headerData) # empty previous content for row in range(table.rowCount()): table.removeRow(row) table.setRowCount(0) table.setColumnCount(0) # create columns and header row columns = [a['key'] for a in attributes] columnsLabels = [a['label'] for a in attributes] colCount = len(columns) table.setColumnCount(colCount) table.setHorizontalHeaderLabels(tuple(columnsLabels)) # load content from project layers lr = QgsProject().instance() for lid in lr.mapLayers(): layer = lr.mapLayer(lid) if layerType == 'vector' and layer.type() != QgsMapLayer.VectorLayer: continue if layerType == 'raster' and layer.type() != QgsMapLayer.RasterLayer: continue # Add layer in the layerBoardChangedData self.layerBoardChangedData[layerType][lid] = {} lineData = [] # Set row and column count twRowCount = table.rowCount() # add a new line table.setRowCount(twRowCount + 1) table.setColumnCount(colCount) i = 0 # get information for attr in attributes: newItem = QTableWidgetItem() newItem.setToolTip(layer.name()) if layerType == 'vector' and not layer.isSpatial() and attr.get('spatial_only'): newItem.setFlags(Qt.NoItemFlags) # Is editable or not elif attr.get('editable'): newItem.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEditable | Qt.ItemIsEnabled) else: newItem.setFlags(Qt.ItemIsSelectable) # Item value if layerType == 'vector' and not layer.isSpatial() and attr.get('spatial_only'): value = None else: value = self.getLayerProperty(layer, attr['key']) newItem.setData(Qt.EditRole, value) # Add cell data to lineData # encode it in the file system encoding, only if needed # TODO DISABLED due to migration to Python 3, related to CSV export # if hasattr(value, 'encode'): # value = value.encode(sys.getfilesystemencoding()) lineData.append(value) if attr['key'] == 'name': icon = QgsMapLayerModel.iconForLayer(layer) newItem.setIcon(icon) # Add item table.setItem(twRowCount, i, newItem) i += 1 # Add data to layerBoardData self.layerBoardData[layerType].append(lineData) # Launch slot on item changed slot slot = partial(self.onItemChanged, layerType) table.itemChanged.connect(slot)
def testProjectStorage(self): # New project without fileName p0 = QgsProject() self.assertTrue(p0.auxiliaryStorage().isValid()) # Create new layers with key otherwise auxiliary layers are not # automacially created when added in project vl0 = createLayer() vl0Shp = writeShape(vl0, 'vl0.shp') vl1 = createLayer() vl1Shp = writeShape(vl1, 'vl1.shp') vl0 = QgsVectorLayer(vl0Shp, 'points', 'ogr') self.assertTrue(vl0.isValid()) vl1 = QgsVectorLayer(vl1Shp, 'points', 'ogr') self.assertTrue(vl1.isValid()) # Add layers to project and check underlying auxiliary layers p0.addMapLayers([vl0, vl1]) self.assertTrue(vl0.loadAuxiliaryLayer(p0.auxiliaryStorage(), 'pk')) self.assertTrue(vl1.loadAuxiliaryLayer(p0.auxiliaryStorage(), 'num_char')) al0 = vl0.auxiliaryLayer() al1 = vl1.auxiliaryLayer() self.assertEqual(al0.joinInfo().targetFieldName(), 'pk') self.assertEqual(al1.joinInfo().targetFieldName(), 'num_char') # Add a field in auxiliary layers pdef0 = QgsPropertyDefinition('propname', QgsPropertyDefinition.DataTypeNumeric, '', '', 'ut') self.assertTrue(al0.addAuxiliaryField(pdef0)) pdef1 = QgsPropertyDefinition('propname1', QgsPropertyDefinition.DataTypeString, '', '', 'ut') self.assertTrue(al1.addAuxiliaryField(pdef1)) # Check auxiliary fields names af0Name = QgsAuxiliaryLayer.nameFromProperty(pdef0, False) self.assertEqual(af0Name, 'ut_propname') af1Name = QgsAuxiliaryLayer.nameFromProperty(pdef1, False) self.assertEqual(af1Name, 'ut_propname1') # Set value for auxiliary fields req = QgsFeatureRequest().setFilterExpression("name = 'Honey'") f = QgsFeature() vl0.getFeatures(req).nextFeature(f) self.assertTrue(f.isValid()) af0Name = QgsAuxiliaryLayer.nameFromProperty(pdef0, True) index0 = vl0.fields().indexOf(af0Name) vl0.changeAttributeValue(f.id(), index0, 333) req = QgsFeatureRequest().setFilterExpression("name = 'Apple'") f = QgsFeature() vl1.getFeatures(req).nextFeature(f) self.assertTrue(f.isValid()) af1Name = QgsAuxiliaryLayer.nameFromProperty(pdef1, True) index1 = vl1.fields().indexOf(af1Name) vl1.changeAttributeValue(f.id(), index0, 'myvalue') req = QgsFeatureRequest().setFilterExpression("name = 'Orange'") f = QgsFeature() vl1.getFeatures(req).nextFeature(f) self.assertTrue(f.isValid()) vl1.changeAttributeValue(f.id(), index0, 'myvalue1') # Save the project in a zip file f = tmpPath() + '.qgz' p0.write(f) # Open the zip file with embedded auxiliary storage p1 = QgsProject() p1.read(f) # Check that auxiliary fields are well loaded in layers self.assertEqual(len(p1.mapLayers().values()), 2) for vl in p1.mapLayers().values(): al = vl.auxiliaryLayer() self.assertEqual(len(al.auxiliaryFields()), 1) af = al.auxiliaryFields()[0] afPropDef = QgsAuxiliaryLayer.propertyDefinitionFromField(af) self.assertEqual(afPropDef.origin(), 'ut') if vl.auxiliaryLayer().joinInfo().targetFieldName() == 'pk': self.assertEqual(afPropDef.name(), 'propname') self.assertEqual(al.featureCount(), 1) req = QgsFeatureRequest().setFilterExpression("name = 'Honey'") f = QgsFeature() vl.getFeatures(req).nextFeature(f) self.assertTrue(f.isValid()) self.assertEqual(f.attributes()[index0], 333.0) else: # num_char self.assertEqual(al.featureCount(), 2) self.assertEqual(afPropDef.name(), 'propname1') req = QgsFeatureRequest().setFilterExpression("name = 'Apple'") f = QgsFeature() vl.getFeatures(req).nextFeature(f) self.assertTrue(f.isValid()) self.assertEqual(f.attributes()[index1], 'myvalue') req = QgsFeatureRequest().setFilterExpression("name = 'Orange'") f = QgsFeature() vl.getFeatures(req).nextFeature(f) self.assertTrue(f.isValid()) self.assertEqual(f.attributes()[index1], 'myvalue1')
def _convert(self, project: QgsProject) -> None: project.baseName() xml_elements_to_preserve = {} on_original_project_read = self._on_original_project_read_wrapper( xml_elements_to_preserve) project.readProject.connect(on_original_project_read) if self.export_type == ExportType.Cable: # the `backup_filename` is copied right after packaging is requested. It has all the unsaved # project settings, which means they will be available in the packaged project too. project.read(self.backup_filename) elif self.export_type == ExportType.Cloud: # if you save the project without QGIS GUI, the project no longer has `theMapCanvas` canvas # so we should use the original project file that already has `theMapCanvas`. There is no # gain using the `backup_filename`, since there is no user to modify the project. project.read(project.fileName()) else: raise NotImplementedError( f"Unknown package type: {self.export_type}") project.readProject.disconnect(on_original_project_read) self.export_folder.mkdir(parents=True, exist_ok=True) self.total_progress_updated.emit(0, 100, self.trUtf8("Converting project…")) self.__layers = list(project.mapLayers().values()) # We store the pks of the original vector layers for layer in self.__layers: pk_names = None if layer.type() == QgsMapLayer.VectorLayer: pk_names = [] for idx in layer.primaryKeyAttributes(): pk_name = layer.fields()[idx].name() # and we check that the primary key fields names don't have a comma in the name if "," in pk_name: raise ValueError("Comma in field names not allowed") pk_names.append(pk_name) layer.setCustomProperty("QFieldSync/sourceDataPrimaryKeys", ",".join(pk_names)) layer_data: LayerData = { "id": layer.id(), "name": layer.name(), "type": layer.type(), "source": layer.source(), "fields": layer.fields() if hasattr(layer, "fields") else None, "pk_names": pk_names, } self.__layer_data_by_id[layer.id()] = layer_data self.__layer_data_by_name[layer.name()] = layer_data if self.create_basemap and self.project_configuration.create_base_map: self._export_basemap() # Loop through all layers and copy/remove/offline them copied_files = list() non_ascii_filename_layers: Dict[str, str] = {} non_utf8_encoding_layers: Dict[str, str] = {} for layer_idx, layer in enumerate(self.__layers): self.total_progress_updated.emit( layer_idx - len(self.__offline_layers), len(self.__layers), self.trUtf8("Copying layers…"), ) layer_source = LayerSource(layer) layer_action = (layer_source.action if self.export_type == ExportType.Cable else layer_source.cloud_action) if not layer.isValid(): project.removeMapLayer(layer) continue if not layer_source.is_supported: project.removeMapLayer(layer) continue if layer_source.is_file and not isascii(layer_source.filename): non_ascii_filename_layers[layer.name()] = layer_source.filename if layer_source.is_localized_path: continue if (layer.type() == QgsMapLayer.VectorLayer and layer.dataProvider() and layer.dataProvider().encoding() != "UTF-8" # some providers return empty string as encoding, just ignore them and layer.dataProvider().encoding() != ""): non_utf8_encoding_layers[ layer.name()] = layer.dataProvider().encoding() if layer_action == SyncAction.OFFLINE: if self.project_configuration.offline_copy_only_aoi: extent = QgsCoordinateTransform( QgsCoordinateReferenceSystem( self.area_of_interest_crs), layer.crs(), QgsProject.instance(), ).transformBoundingBox(self.area_of_interest.boundingBox()) layer.selectByRect(extent) if not layer.selectedFeatureCount(): layer.selectByIds([FID_NULL]) self.__offline_layers.append(layer) self.__offline_layer_names.append(layer.name()) elif (layer_action == SyncAction.COPY or layer_action == SyncAction.NO_ACTION): copied_files = layer_source.copy(self.export_folder, copied_files) elif layer_action == SyncAction.KEEP_EXISTENT: layer_source.copy(self.export_folder, copied_files, True) elif layer_action == SyncAction.REMOVE: project.removeMapLayer(layer) if non_ascii_filename_layers: layers = ", ".join([ f'"{name}" at "{path}"' for name, path in non_ascii_filename_layers.items() ]) message = self.tr( "Some layers are stored at file paths that are not ASCII encoded: {}. Working with paths that are not in ASCII might cause problems. It is highly recommended to rename them to ASCII encoded paths." ).format(layers) self.warning.emit(self.tr("QFieldSync"), message) if non_utf8_encoding_layers: layers = ", ".join([ f"{name} ({encoding})" for name, encoding in non_utf8_encoding_layers.items() ]) message = self.tr( "Some layers do not use UTF-8 encoding: {}. Working with layers that do not use UTF-8 encoding might cause problems. It is highly recommended to convert them to UTF-8 encoded layers." ).format(layers) self.warning.emit(self.tr("QFieldSync"), message) export_project_filename = self.export_folder.joinpath( f"{self.original_filename.stem}_qfield.qgs") # save the original project path self.project_configuration.original_project_path = str( self.original_filename) # save the offline project twice so that the offline plugin can "know" that it's a relative path QgsProject.instance().write(str(export_project_filename)) # export the DCIM folder copy_images( str(self.original_filename.parent.joinpath("DCIM")), str(export_project_filename.parent.joinpath("DCIM")), ) try: # Run the offline plugin for gpkg gpkg_filename = "data.gpkg" if self.__offline_layers: offline_layer_ids = [o_l.id() for o_l in self.__offline_layers] if not self.offline_editing.convertToOfflineProject( str(self.export_folder), gpkg_filename, offline_layer_ids, self.project_configuration.offline_copy_only_aoi, self.offline_editing.GPKG, None, ): raise Exception( self. tr("QGIS Offline editing error: failed to convert layers to offline layers" )) except AttributeError: # Run the offline plugin for spatialite spatialite_filename = "data.sqlite" if self.__offline_layers: offline_layer_ids = [o_l.id() for o_l in self.__offline_layers] if not self.offline_editing.convertToOfflineProject( str(self.export_folder), spatialite_filename, offline_layer_ids, self.project_configuration.offline_copy_only_aoi, self.offline_editing.SpatiaLite, None, ): raise Exception( self. tr("QGIS Offline editing error: failed to convert layers to offline layers" )) # Disable project options that could create problems on a portable # project with offline layers self.post_process_layers() # Now we have a project state which can be saved as offline project on_original_project_write = self._on_original_project_write_wrapper( xml_elements_to_preserve) project.writeProject.connect(on_original_project_write) QgsProject.instance().write(str(export_project_filename)) project.writeProject.disconnect(on_original_project_write)
def get_memory_layers(project: QgsProject) -> List[QgsMapLayer]: return [ layer for layer in project.mapLayers().values() if layer.isValid() and layer.dataProvider().name() == "memory" ]
def testProjectStorage(self): # New project without fileName p0 = QgsProject() self.assertTrue(p0.auxiliaryStorage().isValid()) # Create new layers with key otherwise auxiliary layers are not # automacially created when added in project vl0 = createLayer() vl0Shp = writeShape(vl0, 'vl0.shp') vl1 = createLayer() vl1Shp = writeShape(vl1, 'vl1.shp') vl0 = QgsVectorLayer(vl0Shp, 'points', 'ogr') self.assertTrue(vl0.isValid()) vl1 = QgsVectorLayer(vl1Shp, 'points', 'ogr') self.assertTrue(vl1.isValid()) # Add layers to project and check underlying auxiliary layers p0.addMapLayers([vl0, vl1]) self.assertTrue(vl0.loadAuxiliaryLayer(p0.auxiliaryStorage(), 'pk')) self.assertTrue( vl1.loadAuxiliaryLayer(p0.auxiliaryStorage(), 'num_char')) al0 = vl0.auxiliaryLayer() al1 = vl1.auxiliaryLayer() self.assertEqual(al0.joinInfo().targetFieldName(), 'pk') self.assertEqual(al1.joinInfo().targetFieldName(), 'num_char') # Add a field in auxiliary layers pdef0 = QgsPropertyDefinition('propname', QgsPropertyDefinition.DataTypeNumeric, '', '', 'ut') self.assertTrue(al0.addAuxiliaryField(pdef0)) pdef1 = QgsPropertyDefinition('propname1', QgsPropertyDefinition.DataTypeString, '', '', 'ut') self.assertTrue(al1.addAuxiliaryField(pdef1)) # Check auxiliary fields names af0Name = QgsAuxiliaryLayer.nameFromProperty(pdef0, False) self.assertEqual(af0Name, 'ut_propname') af1Name = QgsAuxiliaryLayer.nameFromProperty(pdef1, False) self.assertEqual(af1Name, 'ut_propname1') # Set value for auxiliary fields req = QgsFeatureRequest().setFilterExpression("name = 'Honey'") f = QgsFeature() vl0.getFeatures(req).nextFeature(f) self.assertTrue(f.isValid()) af0Name = QgsAuxiliaryLayer.nameFromProperty(pdef0, True) index0 = vl0.fields().indexOf(af0Name) vl0.changeAttributeValue(f.id(), index0, 333) req = QgsFeatureRequest().setFilterExpression("name = 'Apple'") f = QgsFeature() vl1.getFeatures(req).nextFeature(f) self.assertTrue(f.isValid()) af1Name = QgsAuxiliaryLayer.nameFromProperty(pdef1, True) index1 = vl1.fields().indexOf(af1Name) vl1.changeAttributeValue(f.id(), index0, 'myvalue') req = QgsFeatureRequest().setFilterExpression("name = 'Orange'") f = QgsFeature() vl1.getFeatures(req).nextFeature(f) self.assertTrue(f.isValid()) vl1.changeAttributeValue(f.id(), index0, 'myvalue1') # Save the project in a zip file f = tmpPath() + '.qgz' p0.write(f) # Open the zip file with embedded auxiliary storage p1 = QgsProject() p1.read(f) # Check that auxiliary fields are well loaded in layers self.assertEqual(len(p1.mapLayers().values()), 2) for vl in p1.mapLayers().values(): al = vl.auxiliaryLayer() self.assertEqual(len(al.auxiliaryFields()), 1) af = al.auxiliaryFields()[0] afPropDef = QgsAuxiliaryLayer.propertyDefinitionFromField(af) self.assertEqual(afPropDef.origin(), 'ut') if vl.auxiliaryLayer().joinInfo().targetFieldName() == 'pk': self.assertEqual(afPropDef.name(), 'propname') self.assertEqual(al.featureCount(), 1) req = QgsFeatureRequest().setFilterExpression("name = 'Honey'") f = QgsFeature() vl.getFeatures(req).nextFeature(f) self.assertTrue(f.isValid()) self.assertEqual(f.attributes()[index0], 333.0) else: # num_char self.assertEqual(al.featureCount(), 2) self.assertEqual(afPropDef.name(), 'propname1') req = QgsFeatureRequest().setFilterExpression("name = 'Apple'") f = QgsFeature() vl.getFeatures(req).nextFeature(f) self.assertTrue(f.isValid()) self.assertEqual(f.attributes()[index1], 'myvalue') req = QgsFeatureRequest().setFilterExpression( "name = 'Orange'") f = QgsFeature() vl.getFeatures(req).nextFeature(f) self.assertTrue(f.isValid()) self.assertEqual(f.attributes()[index1], 'myvalue1')
QgsApplication.initQgis() # Open the project p = QgsProject() p.read(project_path) canvas = QgsMapCanvas() bridge = QgsLayerTreeMapCanvasBridge( p.layerTreeRoot(), canvas ) bridge.setCanvasLayers() # Get the layers in the project layerList = p.mapLayersByName(parcelle_layer) if not layerList: layers = p.mapLayers() for lname, layer in layers.items(): print(lname + ' ' + layer.name() + ' ' + parcelle_layer) layerList = [layer for lname, layer in layers.items() if layer.name() == parcelle_layer] layer = layerList[0] # Get Feature req = QgsFeatureRequest() req.setFilterExpression(' "geo_parcelle" = \'%s\' ' % parcelle_id) it = layer.getFeatures(req) feat = None for f in it: feat = f break # Get connecion params
def setUpTestData(cls): super().setUpTestData() cls.temp_dir = QTemporaryDir() cls.temp_project_path = os.path.join(cls.temp_dir.path(), 'pg_openrouteservice.qgs') # Create test layer conn_str = "dbname='{NAME}' host={HOST} port={PORT} user='******' password='******' sslmode=disable".format( **settings.DATABASES['default']) cls.conn_uri = conn_str md = QgsProviderRegistry.instance().providerMetadata('postgres') conn = md.createConnection(conn_str, {}) conn.executeSql( "DROP SCHEMA IF EXISTS \"openrouteservice test\" CASCADE") conn.executeSql("CREATE SCHEMA \"openrouteservice test\"") conn.executeSql( "CREATE TABLE \"openrouteservice test\".openrouteservice_poly_not_compatible ( pk SERIAL NOT NULL, name TEXT, geom GEOMETRY(POLYGON, 4326), PRIMARY KEY ( pk ) )" ) conn.executeSql( "CREATE TABLE \"openrouteservice test\".openrouteservice_point_not_compatible ( pk SERIAL NOT NULL, value NUMERIC, group_index INTEGER, area NUMERIC, reachfactor NUMERIC, total_pop INTEGER, geom GEOMETRY(POINT, 4326), PRIMARY KEY ( pk ) )" ) conn.executeSql( "CREATE TABLE \"openrouteservice test\".openrouteservice_compatible ( pk SERIAL NOT NULL, value NUMERIC, group_index INTEGER, area NUMERIC, reachfactor NUMERIC, total_pop INTEGER, geom GEOMETRY(POLYGON, 4326), PRIMARY KEY ( pk ) )" ) conn.executeSql( "CREATE TABLE \"openrouteservice test\".openrouteservice_compatible_3857 ( pk SERIAL NOT NULL, value NUMERIC, group_index INTEGER, area NUMERIC, reachfactor NUMERIC, total_pop INTEGER, geom GEOMETRY(POLYGON, 3857), PRIMARY KEY ( pk ) )" ) # Input layers for async tests conn.executeSql( "CREATE TABLE \"openrouteservice test\".openrouteservice_point_3857 ( pk SERIAL NOT NULL, geom GEOMETRY(POINT, 3857), PRIMARY KEY ( pk ) )" ) conn.executeSql( "CREATE TABLE \"openrouteservice test\".openrouteservice_multipoint_4326 ( pk SERIAL NOT NULL, geom GEOMETRY(MULTIPOINT, 4326), PRIMARY KEY ( pk ) )" ) # Add sample points for async tests conn.executeSql( """INSERT INTO "openrouteservice test".openrouteservice_multipoint_4326 (geom) VALUES ( 'SRID=4326;MULTIPOINT ((-77.55542807059459 37.56350130888833), (-77.5513628235481 37.547924590224554), (-77.53848954123421 37.58068563329007), (-77.59608054105951 37.59518182260462))'::geometry), ('SRID=4326;MULTIPOINT ((-77.4077240945721 37.538254644499624), (-77.41991983571157 37.54470141434406), (-77.4260177062813 37.55920460826607), (-77.39349572990939 37.562427156963516), (-77.40840163574651 37.58337032579007))'::geometry)""" ) conn.executeSql( """INSERT INTO "openrouteservice test".openrouteservice_point_3857 (geom) VALUES ('SRID=3857;POINT (-8636824.820306677 4510025.909782101)'::geometry), ('SRID=3857;POINT (-8633657.031688528 4512364.0394764505)'::geometry), ('SRID=3857;POINT (-8637126.514460787 4512741.157169087)'::geometry), ('SRID=3857;POINT (-8634109.572919691 4503916.603161385)'::geometry)""" ) cls.layer_specs = {} project = QgsProject() for table_name, table_spec in { 'openrouteservice_poly_not_compatible': ('Polygon', 4326), 'openrouteservice_point_not_compatible': ('Point', 4326), 'openrouteservice_compatible': ('Polygon', 4326), 'openrouteservice_compatible_3857': ('Polygon', 3857), 'openrouteservice_point_3857': ('Point', 3857), 'openrouteservice_multipoint_4326': ('MultiPoint', 4326), }.items(): layer_uri = conn_str + " sslmode=disable key='pk' estimatedmetadata=false srid={srid} type={geometry_type} checkPrimaryKeyUnicity='0' table=\"openrouteservice test\".\"{table_name}\" (geom)".format( table_name=table_name, geometry_type=table_spec[0], srid=table_spec[1]) layer = QgsVectorLayer(layer_uri, table_name, 'postgres') assert layer.isValid() cls.layer_specs[table_name] = layer_uri project.addMapLayers([layer]) assert project.write(cls.temp_project_path) Project.objects.filter(title='Test openrouteservice project').delete() toc = buildLayerTreeNodeObject(project.layerTreeRoot()) cls.qdjango_project = Project(qgis_file=File( open(cls.temp_project_path, 'r')), title='Test openrouteservice project', group=cls.project_group, layers_tree=toc) cls.qdjango_project.save() for layer_id, layer in project.mapLayers().items(): _, created = Layer.objects.get_or_create( name=layer.name(), title=layer.name(), origname=layer.name(), qgs_layer_id=layer_id, srid=layer.crs().postgisSrid(), project=cls.qdjango_project, layer_type='postgres', datasource=cls.layer_specs[layer.name()]) assert created OpenrouteserviceProject.objects.get_or_create( project=cls.qdjango_project, services={OpenrouteserviceService.ISOCHRONE.value})
def project_info(project_path): """Extracts project information and returns it as a dictionary""" info = {} p = QgsProject() canvas = QgsMapCanvas() def _readCanvasSettings(xmlDocument): canvas.readProject(xmlDocument) p.readProject.connect(_readCanvasSettings, Qt.DirectConnection) if p.read(project_path): # initial extent extent = canvas.extent() if p.crs().authid() != 4326: ct = QgsCoordinateTransform( p.crs(), QgsCoordinateReferenceSystem.fromEpsgId(4326), p.transformContext()) extent = ct.transform(extent) info['initial_extent'] = [ extent.xMinimum(), extent.yMinimum(), extent.xMaximum(), extent.yMaximum(), ] #################################################### # Main section info['title'] = p.metadata().title() if not info['title']: info['title'] = QgsServerProjectUtils.owsServiceTitle(p) if not info['title']: info['title'] = p.title() if not info['title']: info['title'] = p.baseName() info['description'] = p.metadata().abstract() if not info['description']: info['description'] = QgsServerProjectUtils.owsServiceAbstract(p) # Extent, CRS and published WMS layers typenames wmsOutputCrsList = QgsServerProjectUtils.wmsOutputCrsList(p) info[ 'crs'] = 'EPSG:4326' if 'EPSG:4326' in wmsOutputCrsList else wmsOutputCrsList[ 0] extent, info['wms_layers'] = project_wms(p, info['crs']) info['extent'] = [ extent.xMinimum(), extent.yMinimum(), extent.xMaximum(), extent.yMaximum() ] geographic_extent = extent if info['crs'] != 'EPSG:4326': extent_crs = QgsCoordinateReferenceSystem.fromEpsgId( int(info['crs'].split(':')[1])) ct = QgsCoordinateTransform( extent_crs, QgsCoordinateReferenceSystem.fromEpsgId(4326), p.transformContext()) geographic_extent = ct.transform(geographic_extent) info['geographic_extent'] = [ geographic_extent.xMinimum(), geographic_extent.yMinimum(), geographic_extent.xMaximum(), geographic_extent.yMaximum() ] #################################################### # Metadata section m = p.metadata() metadata = {} for prop in ( 'title', 'identifier', 'parentIdentifier', 'abstract', 'author', 'language', 'categories', 'history', 'type', ): metadata[prop] = getattr(m, prop)() # links array metadata['links'] = _read_links(m) # contacts array metadata['contacts'] = _read_contacts(m) metadata['creationDateTime'] = m.creationDateTime().toString( Qt.ISODate) info['metadata'] = metadata #################################################### # WMS Service Capabilities section capabilities = {} for c in ('owsServiceAbstract', 'owsServiceAccessConstraints', 'owsServiceCapabilities', 'owsServiceContactMail', 'owsServiceContactOrganization', 'owsServiceContactPerson', 'owsServiceContactPhone', 'owsServiceContactPosition', 'owsServiceFees', 'owsServiceKeywords', 'owsServiceOnlineResource', 'owsServiceTitle', 'wcsLayerIds', 'wcsServiceUrl', 'wfsLayerIds', 'wfsServiceUrl', 'wfstDeleteLayerIds', 'wfstInsertLayerIds', 'wfstUpdateLayerIds', 'wmsDefaultMapUnitsPerMm', 'wmsExtent', 'wmsFeatureInfoAddWktGeometry', 'wmsFeatureInfoDocumentElement', 'wmsFeatureInfoDocumentElementNs', 'wmsFeatureInfoLayerAliasMap', 'wmsFeatureInfoPrecision', 'wmsFeatureInfoSchema', 'wmsFeatureInfoSegmentizeWktGeometry', 'wmsImageQuality', 'wmsInfoFormatSia2045', 'wmsInspireActivate', 'wmsInspireLanguage', 'wmsInspireMetadataDate', 'wmsInspireMetadataUrl', 'wmsInspireMetadataUrlType', 'wmsInspireTemporalReference', 'wmsMaxAtlasFeatures', 'wmsMaxHeight', 'wmsMaxWidth', 'wmsOutputCrsList', 'wmsRestrictedComposers', 'wmsRestrictedLayers', 'wmsRootName', 'wmsServiceUrl', 'wmsTileBuffer', 'wmsUseLayerIds', 'wmtsServiceUrl'): capabilities[c] = getattr(QgsServerProjectUtils, c)(p) info['capabilities'] = capabilities #################################################### # WMS Layers section info['wms_root_name'] = capabilities['wmsRootName'] if capabilities[ 'wmsRootName'] else p.title() restricted_wms = capabilities['wmsRestrictedLayers'] wms_layers = {} use_ids = capabilities['wmsUseLayerIds'] # Map layer title to layer name (or id if use_ids) wms_layers_map = {} # Maps a typename to a layer id wms_layers_typename_id_map = {} wms_layers_searchable = [] wms_layers_queryable = [] for l in p.mapLayers().values(): if l.name() not in restricted_wms: wms_layers[l.id()] = layer_info(l) name = l.title() if l.title() else l.name() short_name = l.shortName() if l.shortName() else l.name() wms_layers_typename_id_map[short_name] = l.id() wms_layers_map[name] = l.id() if use_ids else short_name if bool(l.flags() & QgsMapLayer.Searchable): wms_layers_searchable.append(l.id()) if bool(l.flags() & QgsMapLayer.Identifiable): wms_layers_queryable.append(l.id()) info['wms_layers'] = wms_layers info['wms_layers_map'] = wms_layers_map info['wms_layers_searchable'] = wms_layers_searchable info['wms_layers_queryable'] = wms_layers_queryable info['wms_layers_typename_id_map'] = wms_layers_typename_id_map #################################################### # TOC tree (WMS published only) info['toc'] = get_toc(p, info) return info
QgsApplication.initQgis() # Open the project p = QgsProject() p.read(project_path) canvas = QgsMapCanvas() bridge = QgsLayerTreeMapCanvasBridge( p.layerTreeRoot(), canvas ) bridge.setCanvasLayers() # Get the layers in the project layerList = p.mapLayersByName(parcelle_layer) if not layerList: layers = p.mapLayers() for lname,layer in layers.items(): print(lname+' '+layer.name()+' '+parcelle_layer) layerList = [ layer for lname,layer in layers.items() if layer.name() == parcelle_layer ] layer = layerList[0] # Get Feature req = QgsFeatureRequest() req.setFilterExpression(' "geo_parcelle" = \'%s\' ' % parcelle_id) it = layer.getFeatures(req) feat = None for f in it: feat = f break # Get connecion params