def testWriteWithBinaryField(self): """ Test writing with a binary field :return: """ basetestpath = tempfile.mkdtemp() tmpfile = os.path.join(basetestpath, 'binaryfield.sqlite') ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile) lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint, options=['FID=fid']) lyr.CreateField(ogr.FieldDefn('strfield', ogr.OFTString)) lyr.CreateField(ogr.FieldDefn('intfield', ogr.OFTInteger)) lyr.CreateField(ogr.FieldDefn('binfield', ogr.OFTBinary)) lyr.CreateField(ogr.FieldDefn('binfield2', ogr.OFTBinary)) f = None ds = None vl = QgsVectorLayer(tmpfile) self.assertTrue(vl.isValid()) # check that 1 of its fields is a bool fields = vl.fields() self.assertEqual(fields.at(fields.indexFromName('binfield')).type(), QVariant.ByteArray) dp = vl.dataProvider() f = QgsFeature(fields) bin_1 = b'xxx' bin_2 = b'yyy' bin_val1 = QByteArray(bin_1) bin_val2 = QByteArray(bin_2) f.setAttributes([1, 'str', 100, bin_val1, bin_val2]) self.assertTrue(dp.addFeature(f)) # write a gpkg package with a binary field filename = os.path.join(str(QDir.tempPath()), 'with_bin_field') rc, errmsg = QgsVectorFileWriter.writeAsVectorFormat(vl, filename, 'utf-8', vl.crs(), 'GPKG') self.assertEqual(rc, QgsVectorFileWriter.NoError) # open the resulting geopackage vl = QgsVectorLayer(filename + '.gpkg', '', 'ogr') self.assertTrue(vl.isValid()) fields = vl.fields() # test type of converted field idx = fields.indexFromName('binfield') self.assertEqual(fields.at(idx).type(), QVariant.ByteArray) idx2 = fields.indexFromName('binfield2') self.assertEqual(fields.at(idx2).type(), QVariant.ByteArray) # test values self.assertEqual(vl.getFeature(1).attributes()[idx], bin_val1) self.assertEqual(vl.getFeature(1).attributes()[idx2], bin_val2) del vl os.unlink(filename + '.gpkg')
def _round_trip(value, field, version='1.1.0'): """Set a value on fid 22 and field and check it back""" encoded_data = post_data.format(field=field, value=value, version=version).encode('utf8') # Strip the field if NULL if value is None: encoded_data = encoded_data.replace(b'<wfs:Value>None</wfs:Value>', b'') header, body = self._execute_request("?MAP=%s&SERVICE=WFS&VERSION=%s" % ( self.testdata_path + 'test_project_wms_grouped_layers.qgs', version), QgsServerRequest.PostMethod, encoded_data) if version == '1.0.0': self.assertTrue(b'<SUCCESS/>' in body, body) else: self.assertTrue(b'<TotalUpdated>1</TotalUpdated>' in body, body) header, body = self._execute_request("?MAP=%s&SERVICE=WFS&REQUEST=GetFeature&TYPENAME=cdb_lines&FEATUREID=cdb_lines.22" % ( self.testdata_path + 'test_project_wms_grouped_layers.qgs')) if value is not None: xml_value = '<qgs:{0}>{1}</qgs:{0}>'.format(field, value).encode('utf8') self.assertTrue(xml_value in body, "%s not found in body" % xml_value) else: xml_value = '<qgs:{0}>'.format(field).encode('utf8') self.assertFalse(xml_value in body) # Check the backend vl = QgsVectorLayer( self.testdata_path + 'test_project_wms_grouped_layers.gpkg|layername=cdb_lines', 'vl', 'ogr') self.assertTrue(vl.isValid()) self.assertEqual( str(vl.getFeature(22)[field]), value if value is not None else 'NULL')
def testStringArray(self): vl = QgsVectorLayer('%s table="qgis_test"."string_array" sql=' % (self.dbconn), "teststringarray", "postgres") self.assertTrue(vl.isValid()) fields = vl.dataProvider().fields() self.assertEqual(fields.at(fields.indexFromName('value')).type(), QVariant.StringList) self.assertEqual(fields.at(fields.indexFromName('value')).subType(), QVariant.String) f = next(vl.getFeatures(QgsFeatureRequest())) value_idx = vl.fields().lookupField('value') self.assertIsInstance(f.attributes()[value_idx], list) self.assertEqual(f.attributes()[value_idx], ['a', 'b', 'c']) new_f = QgsFeature(vl.fields()) new_f['pk'] = NULL new_f['value'] = ['simple', '"doubleQuote"', "'quote'", 'back\\slash'] r, fs = vl.dataProvider().addFeatures([new_f]) self.assertTrue(r) new_pk = fs[0]['pk'] self.assertNotEqual(new_pk, NULL, fs[0].attributes()) try: read_back = vl.getFeature(new_pk) self.assertEqual(read_back['pk'], new_pk) self.assertEqual(read_back['value'], new_f['value']) finally: self.assertTrue(vl.startEditing()) self.assertTrue(vl.deleteFeatures([new_pk])) self.assertTrue(vl.commitChanges())
def testHstore(self): vl = QgsVectorLayer('%s table="qgis_test"."dict" sql=' % (self.dbconn), "testhstore", "postgres") self.assertTrue(vl.isValid()) fields = vl.dataProvider().fields() self.assertEqual(fields.at(fields.indexFromName("value")).type(), QVariant.Map) f = next(vl.getFeatures(QgsFeatureRequest())) value_idx = vl.fields().lookupField("value") self.assertIsInstance(f.attributes()[value_idx], dict) self.assertEqual(f.attributes()[value_idx], {"a": "b", "1": "2"}) new_f = QgsFeature(vl.fields()) new_f["pk"] = NULL new_f["value"] = {"simple": "1", "doubleQuote": '"y"', "quote": "'q'", "backslash": "\\"} r, fs = vl.dataProvider().addFeatures([new_f]) self.assertTrue(r) new_pk = fs[0]["pk"] self.assertNotEqual(new_pk, NULL, fs[0].attributes()) try: read_back = vl.getFeature(new_pk) self.assertEqual(read_back["pk"], new_pk) self.assertEqual(read_back["value"], new_f["value"]) finally: self.assertTrue(vl.startEditing()) self.assertTrue(vl.deleteFeatures([new_pk])) self.assertTrue(vl.commitChanges())
def testStringListField(self): source = os.path.join(TEST_DATA_DIR, 'stringlist.gml') vl = QgsVectorLayer(source) self.assertTrue(vl.isValid()) fields = vl.fields() descriptive_group_field = fields[fields.lookupField('descriptiveGroup')] self.assertEqual(descriptive_group_field.type(), QVariant.List) self.assertEqual(descriptive_group_field.typeName(), 'StringList') self.assertEqual(descriptive_group_field.subType(), QVariant.String) feature = vl.getFeature(1000002717654) self.assertEqual(feature['descriptiveGroup'], ['Building']) self.assertEqual(feature['reasonForChange'], ['Reclassified', 'Attributes']) tmpfile = os.path.join(self.basetestpath, 'newstringlistfield.gml') ds = ogr.GetDriverByName('GML').CreateDataSource(tmpfile) lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint) lyr.CreateField(ogr.FieldDefn('strfield', ogr.OFTString)) lyr.CreateField(ogr.FieldDefn('intfield', ogr.OFTInteger)) lyr.CreateField(ogr.FieldDefn('strlistfield', ogr.OFTStringList)) ds = None vl = QgsVectorLayer(tmpfile) self.assertTrue(vl.isValid()) dp = vl.dataProvider() fields = dp.fields() list_field = fields[fields.lookupField('strlistfield')] self.assertEqual(list_field.type(), QVariant.List) self.assertEqual(list_field.typeName(), 'StringList') self.assertEqual(list_field.subType(), QVariant.String)
def testHstore(self): vl = QgsVectorLayer('%s table="qgis_test"."dict" sql=' % (self.dbconn), "testhstore", "postgres") self.assertTrue(vl.isValid()) fields = vl.dataProvider().fields() self.assertEqual(fields.at(fields.indexFromName('value')).type(), QVariant.Map) f = next(vl.getFeatures(QgsFeatureRequest())) value_idx = vl.fields().lookupField('value') self.assertIsInstance(f.attributes()[value_idx], dict) self.assertEqual(f.attributes()[value_idx], {'a': 'b', '1': '2'}) new_f = QgsFeature(vl.fields()) new_f['pk'] = NULL new_f['value'] = {'simple': '1', 'doubleQuote': '"y"', 'quote': "'q'", 'backslash': '\\'} r, fs = vl.dataProvider().addFeatures([new_f]) self.assertTrue(r) new_pk = fs[0]['pk'] self.assertNotEqual(new_pk, NULL, fs[0].attributes()) try: read_back = vl.getFeature(new_pk) self.assertEqual(read_back['pk'], new_pk) self.assertEqual(read_back['value'], new_f['value']) finally: self.assertTrue(vl.startEditing()) self.assertTrue(vl.deleteFeatures([new_pk])) self.assertTrue(vl.commitChanges())
def _test_db(testPath): vl = QgsVectorLayer(testPath, 'test', 'spatialite') self.assertTrue(vl.isValid()) f = next(vl.getFeatures()) self.assertTrue(f.isValid()) fid = f.id() self.assertTrue(fid > 0) self.assertTrue(vl.getFeature(fid).isValid()) f2 = next(vl.getFeatures(QgsFeatureRequest().setFilterFid(fid))) self.assertTrue(f2.isValid()) self.assertEqual(f2.id(), f.id()) self.assertEqual(f2.geometry().asWkt(), f.geometry().asWkt()) for f in vl.getFeatures(): self.assertTrue(f.isValid()) self.assertTrue(vl.getFeature(f.id()).isValid()) self.assertEqual(vl.getFeature(f.id()).id(), f.id())
def test_arrays_write(self): """Test writing of layers with arrays""" l = QgsVectorLayer("dbname=%s table=test_arrays_write (geometry)" % self.dbname, "test_arrays", "spatialite") self.assertTrue(l.isValid()) new_f = QgsFeature(l.fields()) new_f['id'] = 2 new_f['array'] = ['simple', '"doubleQuote"', "'quote'", 'back\\slash'] new_f['strings'] = ['simple', '"doubleQuote"', "'quote'", 'back\\slash'] new_f['ints'] = [1, 2, 3, 4] new_f['reals'] = [1e67, 1e-56] r, fs = l.dataProvider().addFeatures([new_f]) self.assertTrue(r) read_back = l.getFeature(new_f['id']) self.assertEqual(read_back['id'], new_f['id']) self.assertEqual(read_back['array'], new_f['array']) self.assertEqual(read_back['strings'], new_f['strings']) self.assertEqual(read_back['ints'], new_f['ints']) self.assertEqual(read_back['reals'], new_f['reals']) new_f = QgsFeature(l.fields()) new_f['id'] = 3 new_f['array'] = [1, 1.2345, '"doubleQuote"', "'quote'", 'back\\slash'] new_f['strings'] = ['simple', '"doubleQuote"', "'quote'", 'back\\slash'] new_f['ints'] = [1, 2, 3, 4] new_f['reals'] = [1e67, 1e-56] r, fs = l.dataProvider().addFeatures([new_f]) self.assertTrue(r) read_back = l.getFeature(new_f['id']) self.assertEqual(read_back['id'], new_f['id']) self.assertEqual(read_back['array'], new_f['array']) self.assertEqual(read_back['strings'], new_f['strings']) self.assertEqual(read_back['ints'], new_f['ints']) self.assertEqual(read_back['reals'], new_f['reals']) read_back = l.getFeature(new_f['id'])
def test_zm(self): """Test Z dimension and M value""" l = QgsVectorLayer("dbname=%s table='test_z' (geometry) key='id'" % self.dbname, "test_z", "spatialite") self.assertTrue(l.isValid()) self.assertTrue(QgsWkbTypes.hasZ(l.wkbType())) feature = l.getFeature(1) geom = feature.geometry().constGet() self.assertEqual(geom.z(), 1.0) l = QgsVectorLayer("dbname=%s table='test_m' (geometry) key='id'" % self.dbname, "test_m", "spatialite") self.assertTrue(l.isValid()) self.assertTrue(QgsWkbTypes.hasM(l.wkbType())) feature = l.getFeature(1) geom = feature.geometry().constGet() self.assertEqual(geom.m(), 1.0) l = QgsVectorLayer("dbname=%s table='test_zm' (geometry) key='id'" % self.dbname, "test_zm", "spatialite") self.assertTrue(l.isValid()) self.assertTrue(QgsWkbTypes.hasZ(l.wkbType())) self.assertTrue(QgsWkbTypes.hasM(l.wkbType())) feature = l.getFeature(1) geom = feature.geometry().constGet() self.assertEqual(geom.z(), 1.0) self.assertEqual(geom.m(), 1.0)
def testWriteWithBoolField(self): # init connection string dbconn = 'dbname=\'qgis_test\'' if 'QGIS_PGTEST_DB' in os.environ: dbconn = os.environ['QGIS_PGTEST_DB'] # create a vector layer vl = QgsVectorLayer('{} table="qgis_test"."boolean_table" sql='.format(dbconn), "testbool", "postgres") self.assertTrue(vl.isValid()) # check that 1 of its fields is a bool fields = vl.fields() self.assertEqual(fields.at(fields.indexFromName('fld1')).type(), QVariant.Bool) # write a gpkg package with a bool field crs = QgsCoordinateReferenceSystem() crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId) filename = os.path.join(str(QDir.tempPath()), 'with_bool_field') rc, errmsg = QgsVectorFileWriter.writeAsVectorFormat(vl, filename, 'utf-8', crs, 'GPKG') self.assertEqual(rc, QgsVectorFileWriter.NoError) # open the resulting geopackage vl = QgsVectorLayer(filename + '.gpkg', '', 'ogr') self.assertTrue(vl.isValid()) fields = vl.fields() # test type of converted field idx = fields.indexFromName('fld1') self.assertEqual(fields.at(idx).type(), QVariant.Bool) # test values self.assertEqual(vl.getFeature(1).attributes()[idx], 1) self.assertEqual(vl.getFeature(2).attributes()[idx], 0) del vl os.unlink(filename + '.gpkg')
def test_arrays(self): """Test loading of layers with arrays""" l = QgsVectorLayer("dbname=%s table=test_arrays (geometry)" % self.dbname, "test_arrays", "spatialite") self.assertTrue(l.isValid()) features = [f for f in l.getFeatures()] self.assertEqual(len(features), 1) strings_field = l.fields().field('strings') self.assertEqual(strings_field.typeName(), 'jsonstringlist') self.assertEqual(strings_field.type(), QVariant.StringList) self.assertEqual(strings_field.subType(), QVariant.String) strings = features[0].attributes()[1] self.assertEqual(strings, ['toto', 'tutu']) ints_field = l.fields().field('ints') self.assertEqual(ints_field.typeName(), 'jsonintegerlist') self.assertEqual(ints_field.type(), QVariant.List) self.assertEqual(ints_field.subType(), QVariant.LongLong) ints = features[0].attributes()[2] self.assertEqual(ints, [1, -2, 724562]) reals_field = l.fields().field('reals') self.assertEqual(reals_field.typeName(), 'jsonreallist') self.assertEqual(reals_field.type(), QVariant.List) self.assertEqual(reals_field.subType(), QVariant.Double) reals = features[0].attributes()[3] self.assertEqual(reals, [1.0, -232567.22]) new_f = QgsFeature(l.fields()) new_f['id'] = 2 new_f['strings'] = ['simple', '"doubleQuote"', "'quote'", 'back\\slash'] new_f['ints'] = [1, 2, 3, 4] new_f['reals'] = [1e67, 1e-56] r, fs = l.dataProvider().addFeatures([new_f]) self.assertTrue(r) read_back = l.getFeature(new_f['id']) self.assertEqual(read_back['id'], new_f['id']) self.assertEqual(read_back['strings'], new_f['strings']) self.assertEqual(read_back['ints'], new_f['ints']) self.assertEqual(read_back['reals'], new_f['reals'])
def testWriteWithLongLongField(self): ml = QgsVectorLayer('NoGeometry?crs=epsg:4326&field=fldlonglong:long', 'test2', 'memory') provider = ml.dataProvider() feat = QgsFeature() feat.setAttributes([2262000000]) provider.addFeatures([feat]) filename = os.path.join(str(QDir.tempPath()), 'with_longlong_field') crs = QgsCoordinateReferenceSystem() crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId) rc, errmsg = QgsVectorFileWriter.writeAsVectorFormat(ml, filename, 'utf-8', crs, 'GPKG') # open the resulting geopackage vl = QgsVectorLayer(filename + '.gpkg', '', 'ogr') self.assertTrue(vl.isValid()) # test values idx = vl.fields().indexFromName('fldlonglong') self.assertEqual(vl.getFeature(1).attributes()[idx], 2262000000)
def calcQneatInterpolation(self, iso_pointcloud_featurelist, resolution, interpolation_raster_path): #prepare spatial index uri = 'PointM?crs={}&field=vertex_id:int(254)&field=cost:double(254,7)&key=vertex_id&index=yes'.format( self.AnalysisCrs.authid()) mIsoPointcloud = QgsVectorLayer(uri, "mIsoPointcloud_layer", "memory") mIsoPointcloud_provider = mIsoPointcloud.dataProvider() mIsoPointcloud_provider.addFeatures(iso_pointcloud_featurelist, QgsFeatureSink.FastInsert) #implement spatial index for lines (closest line, etc...) spt_idx = QgsSpatialIndex( mIsoPointcloud.getFeatures(QgsFeatureRequest()), self.feedback) #prepare numpy coordinate grids NoData_value = -9999 raster_rectangle = mIsoPointcloud.extent() #top left point xmin = raster_rectangle.xMinimum() ymin = raster_rectangle.yMinimum() xmax = raster_rectangle.xMaximum() ymax = raster_rectangle.yMaximum() cols = int((xmax - xmin) / resolution) rows = int((ymax - ymin) / resolution) output_interpolation_raster = gdal.GetDriverByName('GTiff').Create( interpolation_raster_path, cols, rows, 1, gdal.GDT_Float64) output_interpolation_raster.SetGeoTransform( (xmin, resolution, 0, ymax, 0, -resolution)) band = output_interpolation_raster.GetRasterBand(1) band.SetNoDataValue(NoData_value) #initialize zero array with 2 dimensions (according to rows and cols) raster_data = zeros(shape=(rows, cols)) #compute raster cell MIDpoints x_pos = linspace(xmin + (resolution / 2), xmax - (resolution / 2), raster_data.shape[1]) y_pos = linspace(ymax - (resolution / 2), ymin + (resolution / 2), raster_data.shape[0]) x_grid, y_grid = meshgrid(x_pos, y_pos) self.feedback.pushInfo( '[QNEAT3Network][calcQneatInterpolation] Beginning with interpolation' ) total_work = rows * cols counter = 0 self.feedback.pushInfo( '[QNEAT3Network][calcQneatInterpolation] Total workload: {} cells'. format(total_work)) self.feedback.setProgress(0) for i in range(rows): for j in range(cols): current_pixel_midpoint = QgsPointXY(x_grid[i, j], y_grid[i, j]) nearest_vertex_fid = spt_idx.nearestNeighbor( current_pixel_midpoint, 1)[0] nearest_feature = mIsoPointcloud.getFeature(nearest_vertex_fid) nearest_vertex = self.network.vertex( nearest_feature['vertex_id']) edges = nearest_vertex.incomingEdges( ) + nearest_vertex.outgoingEdges() vertex_found = False nearest_counter = 2 while vertex_found == False: n_nearest_feature_fid = spt_idx.nearestNeighbor( current_pixel_midpoint, nearest_counter)[nearest_counter - 1] n_nearest_feature = mIsoPointcloud.getFeature( n_nearest_feature_fid) n_nearest_vertex_id = n_nearest_feature['vertex_id'] for edge_id in edges: from_vertex_id = self.network.edge( edge_id).fromVertex() to_vertex_id = self.network.edge(edge_id).toVertex() if n_nearest_vertex_id == from_vertex_id: vertex_found = True vertex_type = "from_vertex" from_point = n_nearest_feature.geometry().asPoint() from_vertex_cost = n_nearest_feature['cost'] if n_nearest_vertex_id == to_vertex_id: vertex_found = True vertex_type = "to_vertex" to_point = n_nearest_feature.geometry().asPoint() to_vertex_cost = n_nearest_feature['cost'] nearest_counter = nearest_counter + 1 """ if nearest_counter == 5: vertex_found = True vertex_type = "end_vertex" """ if vertex_type == "from_vertex": nearest_edge_geometry = QgsGeometry().fromPolylineXY( [from_point, nearest_vertex.point()]) res = nearest_edge_geometry.closestSegmentWithContext( current_pixel_midpoint) segment_point = res[ 1] #[0: distance, 1: point, 2: left_of, 3: epsilon for snapping] dist_to_segment = segment_point.distance( current_pixel_midpoint) dist_edge = from_point.distance(segment_point) #self.feedback.pushInfo("dist_to_segment = {}".format(dist_to_segment)) #self.feedback.pushInfo("dist_on_edge = {}".format(dist_edge)) #self.feedback.pushInfo("cost = {}".format(from_vertex_cost)) pixel_cost = from_vertex_cost + dist_edge + dist_to_segment raster_data[i, j] = pixel_cost elif vertex_type == "to_vertex": nearest_edge_geometry = QgsGeometry().fromPolylineXY( [nearest_vertex.point(), to_point]) res = nearest_edge_geometry.closestSegmentWithContext( current_pixel_midpoint) segment_point = res[ 1] #[0: distance, 1: point, 2: left_of, 3: epsilon for snapping] dist_to_segment = segment_point.distance( current_pixel_midpoint) dist_edge = to_point.distance(segment_point) #self.feedback.pushInfo("dist_to_segment = {}".format(dist_to_segment)) #self.feedback.pushInfo("dist_on_edge = {}".format(dist_edge)) #self.feedback.pushInfo("cost = {}".format(from_vertex_cost)) pixel_cost = to_vertex_cost + dist_edge + dist_to_segment raster_data[i, j] = pixel_cost else: pixel_cost = -99999 #nearest_feature['cost'] + (nearest_vertex.point().distance(current_pixel_midpoint)) """ nearest_feature_pointxy = nearest_feature.geometry().asPoint() nearest_feature_cost = nearest_feature['cost'] dist_to_vertex = current_pixel_midpoint.distance(nearest_feature_pointxy) #implement time cost pixel_cost = dist_to_vertex + nearest_feature_cost raster_data[i,j] = pixel_cost """ counter = counter + 1 if counter % 1000 == 0: self.feedback.pushInfo( "[QNEAT3Network][calcQneatInterpolation] Interpolated {} cells..." .format(counter)) self.feedback.setProgress((counter / total_work) * 100) band.WriteArray(raster_data) outRasterSRS = osr.SpatialReference() outRasterSRS.ImportFromWkt(self.AnalysisCrs.toWkt()) output_interpolation_raster.SetProjection(outRasterSRS.ExportToWkt()) band.FlushCache()
def _test(autoTransaction): """Test buffer methods within and without transactions - create a feature - save - retrieve the feature - change geom and attrs - test changes are seen in the buffer """ def _check_feature(wkt): f = next(layer_a.getFeatures()) self.assertEqual(f.geometry().asWkt().upper(), wkt) f = list(buffer.addedFeatures().values())[0] self.assertEqual(f.geometry().asWkt().upper(), wkt) ml = QgsVectorLayer('Point?crs=epsg:4326&field=int:integer', 'test', 'memory') self.assertTrue(ml.isValid()) d = QTemporaryDir() options = QgsVectorFileWriter.SaveVectorOptions() options.driverName = 'GPKG' options.layerName = 'layer_a' err, _ = QgsVectorFileWriter.writeAsVectorFormatV2(ml, os.path.join(d.path(), 'transaction_test.gpkg'), QgsCoordinateTransformContext(), options) self.assertEqual(err, QgsVectorFileWriter.NoError) self.assertTrue(os.path.isfile(os.path.join(d.path(), 'transaction_test.gpkg'))) options.layerName = 'layer_b' options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteLayer err, _ = QgsVectorFileWriter.writeAsVectorFormatV2(ml, os.path.join(d.path(), 'transaction_test.gpkg'), QgsCoordinateTransformContext(), options) layer_a = QgsVectorLayer(os.path.join(d.path(), 'transaction_test.gpkg|layername=layer_a')) self.assertTrue(layer_a.isValid()) project = QgsProject() project.setAutoTransaction(autoTransaction) project.addMapLayers([layer_a]) ########################################### # Tests with a new feature self.assertTrue(layer_a.startEditing()) buffer = layer_a.editBuffer() f = QgsFeature(layer_a.fields()) f.setAttribute('int', 123) f.setGeometry(QgsGeometry.fromWkt('point(7 45)')) self.assertTrue(layer_a.addFeatures([f])) _check_feature('POINT (7 45)') # Need to fetch the feature because its ID is NULL (-9223372036854775808) f = next(layer_a.getFeatures()) self.assertEqual(len(buffer.addedFeatures()), 1) layer_a.undoStack().undo() self.assertEqual(len(buffer.addedFeatures()), 0) layer_a.undoStack().redo() self.assertEqual(len(buffer.addedFeatures()), 1) f = list(buffer.addedFeatures().values())[0] self.assertEqual(f.attribute('int'), 123) # Now change attribute self.assertEqual(buffer.changedAttributeValues(), {}) layer_a.changeAttributeValue(f.id(), 1, 321) self.assertEqual(len(buffer.addedFeatures()), 1) # This is surprising: because it was a new feature it has been changed directly self.assertEqual(buffer.changedAttributeValues(), {}) f = list(buffer.addedFeatures().values())[0] self.assertEqual(f.attribute('int'), 321) layer_a.undoStack().undo() self.assertEqual(buffer.changedAttributeValues(), {}) f = list(buffer.addedFeatures().values())[0] self.assertEqual(f.attribute('int'), 123) f = next(layer_a.getFeatures()) self.assertEqual(f.attribute('int'), 123) # Change geometry f = next(layer_a.getFeatures()) self.assertTrue(layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(9 43)'))) _check_feature('POINT (9 43)') self.assertEqual(buffer.changedGeometries(), {}) layer_a.undoStack().undo() _check_feature('POINT (7 45)') self.assertEqual(buffer.changedGeometries(), {}) self.assertTrue(layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(9 43)'))) _check_feature('POINT (9 43)') self.assertTrue(layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(10 44)'))) _check_feature('POINT (10 44)') # This is anothr surprise: geometry edits get collapsed into a single # one because they have the same hardcoded id layer_a.undoStack().undo() _check_feature('POINT (7 45)') self.assertTrue(layer_a.commitChanges()) ########################################### # Tests with the existing feature # Get the feature f = next(layer_a.getFeatures()) self.assertTrue(f.isValid()) self.assertEqual(f.attribute('int'), 123) self.assertEqual(f.geometry().asWkt().upper(), 'POINT (7 45)') self.assertTrue(layer_a.startEditing()) layer_a.changeAttributeValue(f.id(), 1, 321) buffer = layer_a.editBuffer() self.assertEqual(buffer.changedAttributeValues(), {1: {1: 321}}) layer_a.undoStack().undo() self.assertEqual(buffer.changedAttributeValues(), {}) # Change geometry self.assertTrue(layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(9 43)'))) f = next(layer_a.getFeatures()) self.assertEqual(f.geometry().asWkt().upper(), 'POINT (9 43)') self.assertEqual(buffer.changedGeometries()[1].asWkt().upper(), 'POINT (9 43)') layer_a.undoStack().undo() self.assertEqual(buffer.changedGeometries(), {}) f = next(layer_a.getFeatures()) self.assertEqual(f.geometry().asWkt().upper(), 'POINT (7 45)') self.assertEqual(buffer.changedGeometries(), {}) # Delete an existing feature self.assertTrue(layer_a.deleteFeature(f.id())) with self.assertRaises(StopIteration): next(layer_a.getFeatures()) self.assertEqual(buffer.deletedFeatureIds(), [f.id()]) layer_a.undoStack().undo() self.assertTrue(layer_a.getFeature(f.id()).isValid()) self.assertEqual(buffer.deletedFeatureIds(), []) ########################################### # Test delete # Delete a new feature f = QgsFeature(layer_a.fields()) f.setAttribute('int', 555) f.setGeometry(QgsGeometry.fromWkt('point(8 46)')) self.assertTrue(layer_a.addFeatures([f])) f = [f for f in layer_a.getFeatures() if f.attribute('int') == 555][0] self.assertTrue(f.id() in buffer.addedFeatures()) self.assertTrue(layer_a.deleteFeature(f.id())) self.assertFalse(f.id() in buffer.addedFeatures()) self.assertFalse(f.id() in buffer.deletedFeatureIds()) layer_a.undoStack().undo() self.assertTrue(f.id() in buffer.addedFeatures()) ########################################### # Add attribute field = QgsField('attr1', QVariant.String) self.assertTrue(layer_a.addAttribute(field)) self.assertNotEqual(layer_a.fields().lookupField(field.name()), -1) self.assertEqual(buffer.addedAttributes(), [field]) layer_a.undoStack().undo() self.assertEqual(layer_a.fields().lookupField(field.name()), -1) self.assertEqual(buffer.addedAttributes(), []) layer_a.undoStack().redo() self.assertNotEqual(layer_a.fields().lookupField(field.name()), -1) self.assertEqual(buffer.addedAttributes(), [field]) self.assertTrue(layer_a.commitChanges()) ########################################### # Remove attribute self.assertTrue(layer_a.startEditing()) buffer = layer_a.editBuffer() attr_idx = layer_a.fields().lookupField(field.name()) self.assertNotEqual(attr_idx, -1) self.assertTrue(layer_a.deleteAttribute(attr_idx)) self.assertEqual(buffer.deletedAttributeIds(), [2]) self.assertEqual(layer_a.fields().lookupField(field.name()), -1) layer_a.undoStack().undo() self.assertEqual(buffer.deletedAttributeIds(), []) self.assertEqual(layer_a.fields().lookupField(field.name()), attr_idx) layer_a.undoStack().redo() self.assertEqual(buffer.deletedAttributeIds(), [2]) self.assertEqual(layer_a.fields().lookupField(field.name()), -1) self.assertTrue(layer_a.rollBack()) ########################################### # Rename attribute self.assertTrue(layer_a.startEditing()) attr_idx = layer_a.fields().lookupField(field.name()) self.assertNotEqual(attr_idx, -1) self.assertEqual(layer_a.fields().lookupField('new_name'), -1) self.assertTrue(layer_a.renameAttribute(attr_idx, 'new_name')) self.assertEqual(layer_a.fields().lookupField('new_name'), attr_idx) layer_a.undoStack().undo() self.assertEqual(layer_a.fields().lookupField(field.name()), attr_idx) self.assertEqual(layer_a.fields().lookupField('new_name'), -1) layer_a.undoStack().redo() self.assertEqual(layer_a.fields().lookupField('new_name'), attr_idx) self.assertEqual(layer_a.fields().lookupField(field.name()), -1)
def processAlgorithm(self, parameters, context, feedback): source = self.parameterAsSource(parameters, self.INPUT, context) if source is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.INPUT)) name_field_name = self.parameterAsString(parameters, self.NAME_FIELD, context) elevation_field_name = self.parameterAsString(parameters, self.ELEVATION_FIELD, context) name_field_index = source.fields().lookupField(name_field_name) elevation_field_index = source.fields().lookupField( elevation_field_name) request = QgsFeatureRequest() request.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326'), context.transformContext()) expression_string = self.parameterAsString(parameters, self.ORDERBY_EXPRESSION, context) if expression_string: expression = QgsExpression(expression_string) if expression.hasParserError(): raise QgsProcessingException(expression.parserErrorString()) request.addOrderBy(expression_string) departure_point = QgsPointXY() destination_point = QgsPointXY() user_points = '' total = 100.0 / source.featureCount() if source.featureCount() else 0 features = source.getFeatures(request) for current, feature in enumerate(features): if feedback.isCanceled(): break if not feature.hasGeometry(): continue point = feature.geometry().asPoint() if departure_point.isEmpty(): departure_point = point destination_point = point name = 'UNTITLED' if name_field_index >= 0: name = feature[name_field_index] name = re.sub('[^0-9A-Za-z_]', '', re.sub('\s+', '_', name)) elevation = 1000.0 if elevation_field_index >= 0: elevation = feature[elevation_field_index] user_points += ' <ATCWaypoint id="{}">\n <ATCWaypointType>User</ATCWaypointType>\n <WorldPosition>{}</WorldPosition>\n </ATCWaypoint>\n'.format( name, self.formattedCoordinateElevation(point, elevation)) feedback.setProgress(int(current * total)) if departure_point.isEmpty(): raise QgsProcessingException('Error: departure point is missing') if destination_point.isEmpty(): raise QgsProcessingException('Error: destination point is missing') strips = QgsVectorLayer( os.path.join(os.path.dirname(__file__), 'data', 'strips.gpkg'), 'strips') index = QgsSpatialIndex(strips.getFeatures()) icao_index = strips.fields().lookupField('icao') name_short_index = strips.fields().lookupField('nameshort') departure_airport = self.parameterAsString(parameters, self.DEPARTURE_AIRPORT, context) if departure_airport: feature = QgsFeature() expression = QgsExpression( "icao ILIKE '{}'".format(departure_airport)) strips.getFeatures( QgsFeatureRequest(expression)).nextFeature(feature) if feature: departure_point = feature.geometry().asPoint() else: raise QgsProcessingException( 'Error: custom departure airport ICAO ID not found') destination_airport = self.parameterAsString(parameters, self.DESTINATION_AIRPORT, context) if destination_airport: feature = QgsFeature() expression = QgsExpression( "icao ILIKE '{}'".format(destination_airport)) strips.getFeatures( QgsFeatureRequest(expression)).nextFeature(feature) if feature: destination_point = feature.geometry().asPoint() else: raise QgsProcessingException( 'Error: custom destination airport ICAO ID not found') departure = '' departure_header = '' destination = '' destination_header = '' if not departure_point.isEmpty(): departure_id = index.nearestNeighbor(departure_point) feature = strips.getFeature(departure_id[0]) point = feature.geometry().asPoint() elevation = 50.0 departure = ' <ATCWaypoint id="{}">\n <ATCWaypointType>Airport</ATCWaypointType>\n <WorldPosition>{}</WorldPosition>\n <RunwayNumberFP>1</RunwayNumberFP>\n <ICAO>\n <ICAOIdent>{}</ICAOIdent>\n </ICAO>\n </ATCWaypoint>\n'.format( feature[icao_index], self.formattedCoordinateElevation(point, elevation), feature[icao_index]) departure_header = ' <DepartureID>{}</DepartureID>\n <DepartureLLA>{}</DepartureLLA>\n <DepartureName>{}</DepartureName>\n'.format( feature[icao_index], self.formattedCoordinateElevation(point, elevation), feature[name_short_index]) if not destination_point.isEmpty(): destination_id = index.nearestNeighbor(destination_point) feature = strips.getFeature(destination_id[0]) point = feature.geometry().asPoint() elevation = 50.0 destination = ' <ATCWaypoint id="{}">\n <ATCWaypointType>Airport</ATCWaypointType>\n <WorldPosition>{}</WorldPosition>\n <RunwayNumberFP>1</RunwayNumberFP>\n <ICAO>\n <ICAOIdent>{}</ICAOIdent>\n </ICAO>\n </ATCWaypoint>\n'.format( feature[icao_index], self.formattedCoordinateElevation(point, elevation), feature[icao_index]) destination_header = ' <DestinationID>{}</DestinationID>\n <DestinationLLA>{}</DestinationLLA>\n <DestinationName>{}</DestinationName>\n'.format( feature[icao_index], self.formattedCoordinateElevation(point, elevation), feature[name_short_index]) title = self.parameterAsString(parameters, self.TITLE, context) plan_file_path = self.parameterAsString(parameters, self.OUTPUT, context) plan_file = open(plan_file_path, 'w') plan_file.write( '<?xml version="1.0" encoding="UTF-8"?>\n\n<SimBase.Document Type="AceXML" version="1,0">\n <Descr>AceXML Document</Descr>\n <FlightPlan.FlightPlan>\n <Title>{}</Title>\n <FPType>IFR</FPType>\n <RouteType>LowAlt</RouteType>\n <CruisingAlt>11000.000</CruisingAlt>\n' .format(title)) plan_file.write(departure_header + destination_header) plan_file.write( ' <Descr>{}</Descr>\n <AppVersion>\n <AppVersionMajor>11</AppVersionMajor>\n <AppVersionBuild>282174</AppVersionBuild>\n </AppVersion>\n' .format(title)) plan_file.write(departure + user_points + destination) plan_file.write(' </FlightPlan.FlightPlan>\n</SimBase.Document>\n') plan_file.close() return {self.OUTPUT: plan_file_path}
def testTypeValidation(self): """Test that incompatible types in attributes raise errors""" vl = QgsVectorLayer( 'Point?crs=epsg:4326&field=int:integer', 'test', 'memory') self.assertTrue(vl.isValid()) invalid = QgsFeature(vl.fields()) invalid.setAttribute('int', 'A string') invalid.setGeometry(QgsGeometry.fromWkt('point(9 45)')) self.assertTrue(vl.startEditing()) # Validation happens on commit self.assertTrue(vl.addFeatures([invalid])) self.assertFalse(vl.commitChanges()) self.assertTrue(vl.rollBack()) self.assertFalse(vl.hasFeatures()) # Add a valid feature valid = QgsFeature(vl.fields()) valid.setAttribute('int', 123) self.assertTrue(vl.startEditing()) self.assertTrue(vl.addFeatures([valid])) self.assertTrue(vl.commitChanges()) self.assertEqual(vl.featureCount(), 1) f = vl.getFeature(1) self.assertEqual(f.attribute('int'), 123) # Add both vl = QgsVectorLayer( 'Point?crs=epsg:4326&field=int:integer', 'test', 'memory') self.assertEqual(vl.featureCount(), 0) self.assertTrue(vl.startEditing()) self.assertTrue(vl.addFeatures([valid, invalid])) self.assertFalse(vl.commitChanges()) self.assertEqual(vl.featureCount(), 2) self.assertTrue(vl.rollBack()) self.assertEqual(vl.featureCount(), 0) # Add both swapped vl = QgsVectorLayer( 'Point?crs=epsg:4326&field=int:integer', 'test', 'memory') self.assertTrue(vl.startEditing()) self.assertTrue(vl.addFeatures([invalid, valid])) self.assertFalse(vl.commitChanges()) self.assertEqual(vl.featureCount(), 2) self.assertTrue(vl.rollBack()) self.assertEqual(vl.featureCount(), 0) # Change attribute value vl = QgsVectorLayer( 'Point?crs=epsg:4326&field=int:integer', 'test', 'memory') self.assertTrue(vl.startEditing()) self.assertTrue(vl.addFeatures([valid])) self.assertTrue(vl.commitChanges()) self.assertTrue(vl.startEditing()) self.assertTrue(vl.changeAttributeValue(1, 0, 'A string')) self.assertFalse(vl.commitChanges()) f = vl.getFeature(1) self.assertEqual(f.attribute('int'), 'A string') self.assertTrue(vl.rollBack()) f = vl.getFeature(1) self.assertEqual(f.attribute('int'), 123) # Change attribute values vl = QgsVectorLayer( 'Point?crs=epsg:4326&field=int:integer', 'test', 'memory') self.assertTrue(vl.startEditing()) self.assertTrue(vl.addFeatures([valid])) self.assertTrue(vl.commitChanges()) self.assertTrue(vl.startEditing()) self.assertTrue(vl.changeAttributeValues(1, {0: 'A string'})) self.assertFalse(vl.commitChanges()) f = vl.getFeature(1) self.assertEqual(f.attribute('int'), 'A string') self.assertTrue(vl.rollBack()) f = vl.getFeature(1) self.assertEqual(f.attribute('int'), 123) ############################################## # Test direct data provider calls # No rollback (old behavior) vl = QgsVectorLayer( 'Point?crs=epsg:4326&field=int:integer', 'test', 'memory') dp = vl.dataProvider() self.assertFalse(dp.addFeatures([valid, invalid])[0]) self.assertEqual([f.attributes() for f in dp.getFeatures()], [[123]]) f = vl.getFeature(1) self.assertEqual(f.attribute('int'), 123) # Roll back vl = QgsVectorLayer( 'Point?crs=epsg:4326&field=int:integer', 'test', 'memory') dp = vl.dataProvider() self.assertFalse(dp.addFeatures([valid, invalid], QgsFeatureSink.RollBackOnErrors)[0]) self.assertFalse(dp.hasFeatures()) # Expected behavior for changeAttributeValues is to always roll back self.assertTrue(dp.addFeatures([valid])[0]) self.assertFalse(dp.changeAttributeValues({1: {0: 'A string'}})) f = vl.getFeature(1) self.assertEqual(f.attribute('int'), 123)
def testObjectIdDifferentName(self): """ Test that object id fields not named OBJECTID work correctly """ endpoint = self.basetestpath + '/oid_fake_qgis_http_endpoint' with open(sanitize(endpoint, '?f=json'), 'wb') as f: f.write(""" {"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description": "QGIS Provider Test Layer.\n","geometryType":"esriGeometryPoint","copyrightText":"","parentLayer":{"id":0,"name":"QGIS Tests"},"subLayers":[], "minScale":72225,"maxScale":0, "defaultVisibility":true, "extent":{"xmin":-71.123,"ymin":66.33,"xmax":-65.32,"ymax":78.3, "spatialReference":{"wkid":4326,"latestWkid":4326}}, "hasAttachments":false,"htmlPopupType":"esriServerHTMLPopupTypeAsHTMLText", "displayField":"LABEL","typeIdField":null, "fields":[{"name":"OBJECTID1","type":"esriFieldTypeOID","alias":"OBJECTID","domain":null}, {"name":"pk","type":"esriFieldTypeInteger","alias":"pk","domain":null}, {"name":"cnt","type":"esriFieldTypeInteger","alias":"cnt","domain":null}], "relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false, "capabilities":"Map,Query,Data","maxRecordCount":1000,"supportsStatistics":true, "supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF", "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""".encode( 'UTF-8')) with open(sanitize(endpoint, '/query?f=json_where=1=1&returnIdsOnly=true'), 'wb') as f: f.write(""" { "objectIdFieldName": "OBJECTID1", "objectIds": [ 5, 3, 1, 2, 4 ] } """.encode('UTF-8')) with open(sanitize(endpoint, '/query?f=json&objectIds=5,3,1,2,4&inSR=4326&outSR=4326&returnGeometry=true&outFields=OBJECTID1,pk,cnt&returnM=false&returnZ=false'), 'wb') as f: f.write(""" { "displayFieldName": "LABEL", "geometryType": "esriGeometryPoint", "spatialReference": { "wkid": 4326, "latestWkid": 4326 }, "fields":[{"name":"OBJECTID1","type":"esriFieldTypeOID","alias":"OBJECTID1","domain":null}, {"name":"pk","type":"esriFieldTypeInteger","alias":"pk","domain":null}, {"name":"cnt","type":"esriFieldTypeInteger","alias":"cnt","domain":null}, {"name":"Shape","type":"esriFieldTypeGeometry","alias":"Shape","domain":null}], "features": [ { "attributes": { "OBJECTID1": 5, "pk": 5, "cnt": -200, "name": null }, "geometry": { "x": -71.123, "y": 78.23 } } ] }""".encode('UTF-8')) # Create test layer vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver') assert vl.isValid() f = vl.getFeature(0) assert f.isValid()
class TestStratigraphy(utils_for_tests.MidvattenTestPostgisDbSv): @mock.patch('db_utils.QgsProject.instance', utils_for_tests.MidvattenTestPostgisNotCreated.mock_instance_settings_database) @mock.patch('db_utils.get_postgis_connections', utils_for_tests.MidvattenTestPostgisNotCreated.mock_postgis_connections) def create_and_select_vlayer(self): self.qgs = QgsApplication([], True) self.qgs.initQgis() self.midvatten.ms.settingsdict['secplotdrillstop'] = "%berg%" dbconnection = db_utils.DbConnectionManager() uri = dbconnection.uri uri.setDataSource('', 'obs_points', 'geometry', '', 'obsid') dbtype = db_utils.get_dbtype(dbconnection.dbtype) self.vlayer = QgsVectorLayer(uri.uri(), 'TestLayer', dbtype) features = self.vlayer.getFeatures() feature_ids = [feature.id() for feature in features] self.vlayer.selectByIds(feature_ids) print("1. Valid vlayer '{}'".format(self.vlayer.isValid())) print("2. feature_ids: " + str(feature_ids)) print("3. QgsVectorLayer.selectedFeatureIds: " + str(self.vlayer.selectedFeatureIds())) print("4. QgsVectorLayer.getSelectedFeatures: " + str([x.id() for x in self.vlayer.getSelectedFeatures()])) print("5. QgsVectorLayer.getFeature(): " + str([self.vlayer.getFeature(x).id() for x in feature_ids])) print("6. QgsVectorLayer.getFeature() type: " + str([str(type(self.vlayer.getFeature(x))) for x in feature_ids])) print("7. QgsVectorLayer.getFeatures(): " + str([x.id() for x in self.vlayer.getFeatures(feature_ids)])) @mock.patch('midvatten_utils.MessagebarAndLog') @mock.patch('stratigraphy.utils.pop_up_info', autospec=True) @mock.patch('db_utils.QgsProject.instance', utils_for_tests.MidvattenTestPostgisNotCreated.mock_instance_settings_database) @mock.patch('db_utils.get_postgis_connections', utils_for_tests.MidvattenTestPostgisNotCreated.mock_postgis_connections) def test_stratigraphy(self, mock_skippopup, mock_messagebar): """ :param mock_skippopup: :param mock_messagebar: :return: """ db_utils.sql_alter_db('''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('1', 5, ST_GeomFromText('POINT(633466 711659)', 3006))''') db_utils.sql_alter_db('''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('2', 10, ST_GeomFromText('POINT(6720727 016568)', 3006))''') db_utils.sql_alter_db('''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('3', 20, ST_GeomFromText('POINT(6720728 016569)', 3006))''') db_utils.sql_alter_db('''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('1', 1, 0, 1, 'sand', 'sand', '3', 'j')''') db_utils.sql_alter_db('''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('1', 2, 1, 4.5, 'morän', 'morän', '3', 'j')''') self.create_and_select_vlayer() #print(str(self.vlayer.isValid())) #print(str(db_utils.sql_load_fr_db('select * from obs_points'))) #print(str(db_utils.sql_load_fr_db('select * from stratigraphy'))) dlg = Stratigraphy(self.iface, self.vlayer, self.ms.settingsdict) #print(str(mock_messagebar.mock_calls)) #print(str(mock_skippopup.mock_calls)) dlg.showSurvey() test = utils.anything_to_string_representation(dlg.data) test_survey = utils.anything_to_string_representation(repr(dlg.data['1'])) test_strata = utils.anything_to_string_representation(utils.returnunicode(dlg.data['1'].strata, keep_containers=True)) assert len(mock_skippopup.mock_calls) == 0 print(str(mock_messagebar.mock_calls)) assert len(mock_messagebar.mock_calls) == 0 assert test == """{"1": SURVEY('1', 5.000000, '<QgsPointXY: POINT(633466 711659)>')}""" assert test_survey == '''"SURVEY('1', 5.000000, '<QgsPointXY: POINT(633466 711659)>')"''' print("test_strata: " + test_strata) assert test_strata == '''["strata(1, '3', 'sand', 'sand', 0.000000-1.000000)", "strata(2, '3', 'morän', 'moran', 1.000000-4.500000)"]''' @mock.patch('midvatten_utils.MessagebarAndLog') @mock.patch('stratigraphy.utils.pop_up_info', autospec=True) @mock.patch('db_utils.QgsProject.instance', utils_for_tests.MidvattenTestPostgisNotCreated.mock_instance_settings_database) @mock.patch('db_utils.get_postgis_connections', utils_for_tests.MidvattenTestPostgisNotCreated.mock_postgis_connections) def test_stratigraphy_with_other_obsid_numbers(self, mock_skippopup, mock_messagebar): """ :param mock_skippopup: :param mock_messagebar: :return: """ db_utils.sql_alter_db('''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('8', 5, ST_GeomFromText('POINT(633466 711659)', 3006))''') db_utils.sql_alter_db('''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('9', 10, ST_GeomFromText('POINT(6720727 016568)', 3006))''') db_utils.sql_alter_db('''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('10', 20, ST_GeomFromText('POINT(6720728 016569)', 3006))''') db_utils.sql_alter_db('''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('8', 1, 0, 1, 'sand', 'sand', '3', 'j')''') db_utils.sql_alter_db('''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('8', 2, 1, 4.5, 'morän', 'morän', '3', 'j')''') self.create_and_select_vlayer() dlg = Stratigraphy(self.iface, self.vlayer, self.ms.settingsdict) dlg.showSurvey() print(str(mock_skippopup.mock_calls)) test = utils.anything_to_string_representation(dlg.data) test_survey = utils.anything_to_string_representation(repr(dlg.data['8'])) test_strata = utils.anything_to_string_representation( utils.returnunicode(dlg.data['8'].strata, keep_containers=True)) assert len(mock_skippopup.mock_calls) == 0 assert len(mock_messagebar.mock_calls) == 0 assert test == """{"8": SURVEY('8', 5.000000, '<QgsPointXY: POINT(633466 711659)>')}""" assert test_survey == '''"SURVEY('8', 5.000000, '<QgsPointXY: POINT(633466 711659)>')"''' print("Test strata " + test_strata) assert test_strata == '''["strata(1, '3', 'sand', 'sand', 0.000000-1.000000)", "strata(2, '3', 'morän', 'moran', 1.000000-4.500000)"]''' @mock.patch('midvatten_utils.MessagebarAndLog') @mock.patch('stratigraphy.utils.pop_up_info', autospec=True) @mock.patch('db_utils.QgsProject.instance', utils_for_tests.MidvattenTestPostgisNotCreated.mock_instance_settings_database) @mock.patch('db_utils.get_postgis_connections', utils_for_tests.MidvattenTestPostgisNotCreated.mock_postgis_connections) def test_stratigraphy_with_string_obsid(self, mock_skippopup, mock_messagebar): """ :param mock_skippopup: :param mock_messagebar: :return: """ db_utils.sql_alter_db('''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('P1', 5, ST_GeomFromText('POINT(633466 711659)', 3006))''') db_utils.sql_alter_db('''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('P2', 10, ST_GeomFromText('POINT(6720727 016568)', 3006))''') db_utils.sql_alter_db('''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('P3', 20, ST_GeomFromText('POINT(6720728 016569)', 3006))''') db_utils.sql_alter_db('''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('P1', 1, 0, 1, 'sand', 'sand', '3', 'j')''') db_utils.sql_alter_db('''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('P1', 2, 1, 4.5, 'morän', 'morän', '3', 'j')''') self.create_and_select_vlayer() print(str(self.vlayer.isValid())) print(str(db_utils.sql_load_fr_db('select * from obs_points'))) print(str(db_utils.sql_load_fr_db('select * from stratigraphy'))) dlg = Stratigraphy(self.iface, self.vlayer, self.ms.settingsdict) print(str(mock_messagebar.mock_calls)) print(str(mock_skippopup.mock_calls)) dlg.showSurvey() test = utils.anything_to_string_representation(dlg.data) test_survey = utils.anything_to_string_representation(repr(dlg.data['P1'])) test_strata = utils.anything_to_string_representation(utils.returnunicode(dlg.data['P1'].strata, keep_containers=True)) assert len(mock_skippopup.mock_calls) == 0 print(str(mock_messagebar.mock_calls)) assert len(mock_messagebar.mock_calls) == 0 assert test == """{"P1": SURVEY('P1', 5.000000, '<QgsPointXY: POINT(633466 711659)>')}""" assert test_survey == '''"SURVEY('P1', 5.000000, '<QgsPointXY: POINT(633466 711659)>')"''' assert test_strata == '''["strata(1, '3', 'sand', 'sand', 0.000000-1.000000)", "strata(2, '3', 'morän', 'moran', 1.000000-4.500000)"]''' @mock.patch('midvatten_utils.MessagebarAndLog') @mock.patch('stratigraphy.utils.pop_up_info', autospec=True) @mock.patch('db_utils.QgsProject.instance', utils_for_tests.MidvattenTestPostgisNotCreated.mock_instance_settings_database) @mock.patch('db_utils.get_postgis_connections', utils_for_tests.MidvattenTestPostgisNotCreated.mock_postgis_connections) def test_stratigraphy_gap(self, mock_skippopup, mock_messagebar): """ :param mock_skippopup: :param mock_messagebar: :return: """ db_utils.sql_alter_db('''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('1', 5, ST_GeomFromText('POINT(633466 711659)', 3006))''') db_utils.sql_alter_db('''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('2', 10, ST_GeomFromText('POINT(6720727 016568)', 3006))''') db_utils.sql_alter_db('''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('3', 20, ST_GeomFromText('POINT(6720728 016569)', 3006))''') db_utils.sql_alter_db('''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('1', 1, 0, 1, 'sand', 'sand', '3', 'j')''') db_utils.sql_alter_db('''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('1', 2, 2, 4.5, 'morän', 'morän', '3', 'j')''') self.create_and_select_vlayer() print(str(self.vlayer.isValid())) print(str(db_utils.sql_load_fr_db('select * from obs_points'))) print(str(db_utils.sql_load_fr_db('select * from stratigraphy'))) dlg = Stratigraphy(self.iface, self.vlayer, self.ms.settingsdict) print(str(mock_messagebar.mock_calls)) print(str(mock_skippopup.mock_calls)) dlg.showSurvey() test = utils.anything_to_string_representation(dlg.data) test_survey = utils.anything_to_string_representation(repr(dlg.data['1'])) test_strata = utils.anything_to_string_representation(utils.returnunicode(dlg.data['1'].strata, keep_containers=True)) assert len(mock_skippopup.mock_calls) == 0 assert len(mock_messagebar.mock_calls) == 0 assert test == """{"1": SURVEY('1', 5.000000, '<QgsPointXY: POINT(633466 711659)>')}""" assert test_survey == '''"SURVEY('1', 5.000000, '<QgsPointXY: POINT(633466 711659)>')"''' assert test_strata == '''["strata(1, '3', 'sand', 'sand', 0.000000-1.000000)", "strata(2, '', '', '', 1.000000-2.000000)", "strata(3, '3', 'morän', 'moran', 2.000000-4.500000)"]''' @mock.patch('midvatten_utils.MessagebarAndLog') @mock.patch('stratigraphy.utils.pop_up_info', autospec=True) @mock.patch('db_utils.QgsProject.instance', utils_for_tests.MidvattenTestPostgisNotCreated.mock_instance_settings_database) @mock.patch('db_utils.get_postgis_connections', utils_for_tests.MidvattenTestPostgisNotCreated.mock_postgis_connections) def test_stratigraphy_missing_h_gs(self, mock_skippopup, mock_messagebar): """ :param mock_skippopup: :param mock_messagebar: :return: """ db_utils.sql_alter_db('''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('1', 5, ST_GeomFromText('POINT(633466 711659)', 3006))''') db_utils.sql_alter_db('''INSERT INTO obs_points (obsid, h_gs, h_toc, geometry) VALUES ('2', NULL, 10, ST_GeomFromText('POINT(6720727 016568)', 3006))''') db_utils.sql_alter_db('''INSERT INTO obs_points (obsid, geometry) VALUES ('3', ST_GeomFromText('POINT(6720728 016569)', 3006))''') db_utils.sql_alter_db('''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('1', 1, 0, 1, 'sand', 'sand', '3', 'j')''') db_utils.sql_alter_db('''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('1', 2, 1, 4.5, 'morän', 'morän', '3', 'j')''') db_utils.sql_alter_db('''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('2', 1, 0, 1, 'sand', 'sand', '3', 'j')''') db_utils.sql_alter_db('''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('2', 2, 1, 4.5, 'morän', 'morän', '3', 'j')''') db_utils.sql_alter_db('''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('3', 1, 0, 2, 'sand', 'sand', '3', 'j')''') db_utils.sql_alter_db('''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('3', 2, 2, 6, 'morän', 'morän', '3', 'j')''') self.create_and_select_vlayer() dlg = Stratigraphy(self.iface, self.vlayer, self.ms.settingsdict) dlg.showSurvey() test = utils.anything_to_string_representation(dlg.data) test_survey = utils.anything_to_string_representation(repr(dlg.data['1'])) test_strata = utils.anything_to_string_representation(utils.returnunicode(dlg.data['1'].strata, keep_containers=True)) assert len(mock_skippopup.mock_calls) == 1 print(str(mock_skippopup.mock_calls)) print(str(mock_messagebar.mock_calls)) assert mock_skippopup.mock_calls == [mock.call('Warning, h_gs is missing. See messagebar.')] assert mock_messagebar.mock_calls == [mock.call.warning(bar_msg="Obsid 2: using h_gs '' failed, using 'h_toc' instead.", duration=90, log_msg='False'), mock.call.warning(bar_msg="Obsid 3: using h_gs '' failed, using '-1' instead.", duration=90, log_msg='False')] print("test: " + test) assert test == """{"1": SURVEY('1', 5.000000, '<QgsPointXY: POINT(633466 711659)>'), "2": SURVEY('2', 10.000000, '<QgsPointXY: POINT(6720727 16568)>'), "3": SURVEY('3', -1.000000, '<QgsPointXY: POINT(6720728 16569)>')}""" print("test_survey " + test_survey) assert test_survey == '''"SURVEY('1', 5.000000, '<QgsPointXY: POINT(633466 711659)>')"''' print("Test strata " + test_strata) assert test_strata == '''["strata(1, '3', 'sand', 'sand', 0.000000-1.000000)", "strata(2, '3', 'morän', 'moran', 1.000000-4.500000)"]''' def tearDown(self): QgsProject.instance().addMapLayer(self.vlayer) QgsProject.instance().removeMapLayer(self.vlayer.id()) super(self.__class__, self).tearDown()
class AddField: def __init__(self, parent_widget): """This class handle the creation of Fields. This class is also imported in the MeanAnalyse class. Parameters ---------- parent_widget: GeoDataFarm """ self.iface = parent_widget.iface self.tsk_mngr = parent_widget.tsk_mngr self.db = parent_widget.db self.tr = parent_widget.tr self.dock_widget = parent_widget.dock_widget self.parent = parent_widget self.AFD = AddFieldFileDialog() self.field = None self.defined_field = '' def run(self): """Presents the sub widget AddField and connects the different buttons to their function""" self.AFD.show() self.AFD.PBSelectExtent.clicked.connect(self.clicked_define_field) self.AFD.PBSave.clicked.connect(self.save) self.AFD.PBHelp.clicked.connect(self.help) self.AFD.PBQuit.clicked.connect(self.quit) self.AFD.exec() self.parent.populate.reload_fields() def set_widget_connections(self): """Function that sets the main widget connections.""" self.parent.dock_widget.PBAddField.clicked.connect(self.run) self.parent.dock_widget.PBRemoveField.clicked.connect( self.remove_field) self.parent.dock_widget.PBViewFields.clicked.connect(self.view_fields) def clicked_define_field(self, ignore_name=True): """Creates an empty polygon that's define a field""" if ignore_name: self.field = QgsVectorLayer("Polygon?crs=epsg:4326", 'Search area', "memory") else: name = self.AFD.LEFieldName.text() if len(name) == 0: QMessageBox.information( None, self.tr('Error:'), self.tr('Field name must be filled in.')) return self.field = QgsVectorLayer("Polygon?crs=epsg:4326", name, "memory") add_background() set_zoom(self.parent.iface, 2) self.field.startEditing() self.iface.actionAddFeature().trigger() QgsProject.instance().addMapLayer(self.field) def remove_field(self): """Removes a field that the user wants, a check that there are no data that is depended on is made.""" j = -1 for i in range(self.parent.dock_widget.LWFields.count()): j += 1 item = self.parent.dock_widget.LWFields.item(j) if item.checkState() == 2: field_name = item.text() qm = QMessageBox() res = qm.question( None, self.tr('Question'), self.tr("Do you want to delete ") + str(field_name), qm.Yes, qm.No) if res == qm.No: continue field_names = [] for tble_type in [ 'plant', 'ferti', 'spray', 'harvest', 'soil' ]: field_names.extend( self.db.execute_and_return( "select field from {type}.manual".format( type=tble_type))) sql = """SELECT table_name FROM information_schema.tables WHERE table_schema = 'other'""" for tble_type in self.db.execute_and_return(sql): tbl = tble_type[0] field_names.extend( self.db.execute_and_return( "select field from other.{tbl}".format(tbl=tbl))) stop_removing = False for row in field_names: if row[0] == field_name: QMessageBox.information( None, self.tr('Error'), self. tr('There are data sets that are dependent on this field, ' 'it cant be removed.')) stop_removing = True if stop_removing: continue sql = "delete from fields where field_name='{f}'".format( f=field_name) self.db.execute_sql(sql) self.parent.dock_widget.LWFields.takeItem(j) j -= 1 def view_fields(self): """Add all fields that aren't displayed on the canvas, if no background map is loaded Google maps are loaded.""" defined_field = self.defined_field if defined_field == '': add_background() sources = [ layer.name().split('_')[0] for layer in QgsProject.instance().mapLayers().values() ] fields_db = self.db.execute_and_return("select field_name from fields") task = QgsTask.fromFunction('Adding fields to the canvas', add_fields_2_canvas, self.db, fields_db, defined_field, sources, on_finished=self.finish) self.tsk_mngr.addTask(task) def finish(self, result, values): """Produces either an error message telling what went wrong or adds the fields to canvas and zoom to the layers. Parameters ---------- result: object values: list If all went ok: [True, list of layers] Else: [False, exception, traceback] """ if values[0] is False: QMessageBox.information( None, self.tr('Error'), self.tr( 'Following error occurred: {m}\n\n Traceback: {t}'.format( m=values[1], t=values[2]))) return for layer in values[-1]: QgsProject.instance().addMapLayer(layer) if self.defined_field == '': set_zoom(self.parent.iface, 1.1) self.defined_field = '' def quit(self): """Closes the widget.""" self.AFD.PBSelectExtent.clicked.disconnect() self.AFD.PBSave.clicked.disconnect() self.AFD.PBHelp.clicked.disconnect() self.AFD.PBQuit.clicked.disconnect() self.AFD.done(0) def save(self): """Saves the field in the database""" try: self.iface.actionSaveActiveLayerEdits().trigger() self.iface.actionToggleEditing().trigger() feature = self.field.getFeature(1) QgsProject.instance().removeMapLayers([self.field.id()]) except: QMessageBox.information( None, self.tr("Error:"), self. tr('No coordinates where found, did you mark the field on the canvas?' )) return polygon = feature.geometry().asWkt() name = self.AFD.LEFieldName.text() if len(name) == 0: QMessageBox.information(None, self.tr('Error:'), self.tr('Field name must be filled in.')) return sql = """Insert into fields (field_name, polygon) VALUES ('{name}', st_geomfromtext('{poly}', 4326))""".format( name=name, poly=polygon) try: self.db.execute_sql(sql) except IntegrityError: QMessageBox.information( None, self.tr('Error:'), self.tr( 'Field name all ready exist, please select a new name')) return except InternalError as e: QMessageBox.information(None, self.tr('Error:'), str(e)) return _name = QApplication.translate("qadashboard", name, None) item = QListWidgetItem(_name, self.dock_widget.LWFields) item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable) item.setCheckState(QtCore.Qt.Unchecked) self.defined_field = name self.view_fields() def help(self): """A function that gives some advice on how the function works for the user. """ QMessageBox.information( None, self.tr("Help:"), self. tr('Here is where you add a field.\n' '1. Start with giving the field a name.\n' '2. Press "select extent" and switch to the QGIS window and zoom to your field.\n' '3. To mark your field, left click with the mouse in one corner of the field.\n' 'then left click in all corners of the field then right click anywhere on the map.\n' '(There might be some errors while clicking the corners if the lines are crossing each other but in the end this does not matter if they does not do it in the end)\n' '4. Press "Save field" to store the field.\n' '5. When all fields are added press "Finished"')) return
def testWriteWithBinaryField(self): """ Test writing with a binary field :return: """ basetestpath = tempfile.mkdtemp() tmpfile = os.path.join(basetestpath, 'binaryfield.sqlite') ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile) lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint, options=['FID=fid']) lyr.CreateField(ogr.FieldDefn('strfield', ogr.OFTString)) lyr.CreateField(ogr.FieldDefn('intfield', ogr.OFTInteger)) lyr.CreateField(ogr.FieldDefn('binfield', ogr.OFTBinary)) lyr.CreateField(ogr.FieldDefn('binfield2', ogr.OFTBinary)) f = None ds = None vl = QgsVectorLayer(tmpfile) self.assertTrue(vl.isValid()) # check that 1 of its fields is a bool fields = vl.fields() self.assertEqual( fields.at(fields.indexFromName('binfield')).type(), QVariant.ByteArray) dp = vl.dataProvider() f = QgsFeature(fields) bin_1 = b'xxx' bin_2 = b'yyy' bin_val1 = QByteArray(bin_1) bin_val2 = QByteArray(bin_2) f.setAttributes([1, 'str', 100, bin_val1, bin_val2]) self.assertTrue(dp.addFeature(f)) # write a gpkg package with a binary field filename = os.path.join(str(QDir.tempPath()), 'with_bin_field') rc, errmsg = QgsVectorFileWriter.writeAsVectorFormat( vl, filename, 'utf-8', vl.crs(), 'GPKG') self.assertEqual(rc, QgsVectorFileWriter.NoError) # open the resulting geopackage vl = QgsVectorLayer(filename + '.gpkg', '', 'ogr') self.assertTrue(vl.isValid()) fields = vl.fields() # test type of converted field idx = fields.indexFromName('binfield') self.assertEqual(fields.at(idx).type(), QVariant.ByteArray) idx2 = fields.indexFromName('binfield2') self.assertEqual(fields.at(idx2).type(), QVariant.ByteArray) # test values self.assertEqual(vl.getFeature(1).attributes()[idx], bin_val1) self.assertEqual(vl.getFeature(1).attributes()[idx2], bin_val2) del vl os.unlink(filename + '.gpkg')
class TestStratigraphy(utils_for_tests.MidvattenTestSpatialiteDbSv): @mock.patch('db_utils.QgsProject.instance', utils_for_tests.MidvattenTestSpatialiteNotCreated. mock_instance_settings_database) def create_and_select_vlayer(self): self.qgs = QgsApplication([], True) self.qgs.initQgis() self.midvatten.ms.settingsdict['secplotdrillstop'] = "%berg%" dbconnection = db_utils.DbConnectionManager() uri = dbconnection.uri uri.setDataSource('', 'obs_points', 'geometry', '', 'rowid') dbtype = db_utils.get_dbtype(dbconnection.dbtype) self.vlayer = QgsVectorLayer(uri.uri(), 'TestLayer', dbtype) features = self.vlayer.getFeatures() feature_ids = [feature.id() for feature in features] self.vlayer.selectByIds(feature_ids) print("1. Valid vlayer '{}'".format(self.vlayer.isValid())) print("2. feature_ids: " + str(feature_ids)) print("3. QgsVectorLayer.selectedFeatureIds: " + str(self.vlayer.selectedFeatureIds())) print("4. QgsVectorLayer.getSelectedFeatures: " + str([x.id() for x in self.vlayer.getSelectedFeatures()])) print("5. QgsVectorLayer.getFeature(): " + str([self.vlayer.getFeature(x).id() for x in feature_ids])) print("6. QgsVectorLayer.getFeature() type: " + str([str(type(self.vlayer.getFeature(x))) for x in feature_ids])) print("7. QgsVectorLayer.getFeatures(): " + str([x.id() for x in self.vlayer.getFeatures(feature_ids)])) @mock.patch('midvatten_utils.MessagebarAndLog') @mock.patch('stratigraphy.utils.pop_up_info', autospec=True) @mock.patch('db_utils.QgsProject.instance', utils_for_tests.MidvattenTestSpatialiteNotCreated. mock_instance_settings_database) def test_stratigraphy(self, mock_skippopup, mock_messagebar): """ :param mock_skippopup: :param mock_messagebar: :return: """ db_utils.sql_alter_db( '''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('1', 5, ST_GeomFromText('POINT(633466 711659)', 3006))''' ) db_utils.sql_alter_db( '''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('2', 10, ST_GeomFromText('POINT(6720727 016568)', 3006))''' ) db_utils.sql_alter_db( '''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('3', 20, ST_GeomFromText('POINT(6720728 016569)', 3006))''' ) db_utils.sql_alter_db( '''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('1', 1, 0, 1, 'sand', 'sand', '3', 'j')''' ) db_utils.sql_alter_db( '''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('1', 2, 1, 4.5, 'morän', 'morän', '3', 'j')''' ) self.create_and_select_vlayer() dlg = Stratigraphy(self.iface, self.vlayer, self.ms.settingsdict) dlg.showSurvey() print(str(mock_skippopup.mock_calls)) test = utils.anything_to_string_representation(dlg.data) test_survey = utils.anything_to_string_representation( repr(dlg.data['1'])) test_strata = utils.anything_to_string_representation( utils.returnunicode(dlg.data['1'].strata, keep_containers=True)) assert len(mock_skippopup.mock_calls) == 0 assert len(mock_messagebar.mock_calls) == 0 assert test == """{"1": SURVEY('1', 5.000000, '<QgsPointXY: POINT(633466 711659)>')}""" assert test_survey == '''"SURVEY('1', 5.000000, '<QgsPointXY: POINT(633466 711659)>')"''' print("Test strata " + test_strata) assert test_strata == '''["strata(1, '3', 'sand', 'sand', 0.000000-1.000000)", "strata(2, '3', 'morän', 'moran', 1.000000-4.500000)"]''' @mock.patch('midvatten_utils.MessagebarAndLog') @mock.patch('stratigraphy.utils.pop_up_info', autospec=True) @mock.patch('db_utils.QgsProject.instance', utils_for_tests.MidvattenTestSpatialiteNotCreated. mock_instance_settings_database) def test_stratigraphy_with_other_obsid_numbers(self, mock_skippopup, mock_messagebar): """ :param mock_skippopup: :param mock_messagebar: :return: """ db_utils.sql_alter_db( '''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('8', 5, ST_GeomFromText('POINT(633466 711659)', 3006))''' ) db_utils.sql_alter_db( '''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('9', 10, ST_GeomFromText('POINT(6720727 016568)', 3006))''' ) db_utils.sql_alter_db( '''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('10', 20, ST_GeomFromText('POINT(6720728 016569)', 3006))''' ) db_utils.sql_alter_db( '''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('8', 1, 0, 1, 'sand', 'sand', '3', 'j')''' ) db_utils.sql_alter_db( '''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('8', 2, 1, 4.5, 'morän', 'morän', '3', 'j')''' ) self.create_and_select_vlayer() dlg = Stratigraphy(self.iface, self.vlayer, self.ms.settingsdict) dlg.showSurvey() print(str(mock_skippopup.mock_calls)) test = utils.anything_to_string_representation(dlg.data) test_survey = utils.anything_to_string_representation( repr(dlg.data['8'])) test_strata = utils.anything_to_string_representation( utils.returnunicode(dlg.data['8'].strata, keep_containers=True)) assert len(mock_skippopup.mock_calls) == 0 assert len(mock_messagebar.mock_calls) == 0 assert test == """{"8": SURVEY('8', 5.000000, '<QgsPointXY: POINT(633466 711659)>')}""" assert test_survey == '''"SURVEY('8', 5.000000, '<QgsPointXY: POINT(633466 711659)>')"''' print("Test strata " + test_strata) assert test_strata == '''["strata(1, '3', 'sand', 'sand', 0.000000-1.000000)", "strata(2, '3', 'morän', 'moran', 1.000000-4.500000)"]''' @mock.patch('midvatten_utils.MessagebarAndLog') @mock.patch('stratigraphy.utils.pop_up_info', autospec=True) @mock.patch('db_utils.QgsProject.instance', utils_for_tests.MidvattenTestSpatialiteNotCreated. mock_instance_settings_database) def test_stratigraphy_with_string_obsid(self, mock_skippopup, mock_messagebar): """ :param mock_skippopup: :param mock_messagebar: :return: """ db_utils.sql_alter_db( '''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('P1', 5, ST_GeomFromText('POINT(633466 711659)', 3006))''' ) db_utils.sql_alter_db( '''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('P2', 10, ST_GeomFromText('POINT(6720727 016568)', 3006))''' ) db_utils.sql_alter_db( '''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('P3', 20, ST_GeomFromText('POINT(6720728 016569)', 3006))''' ) db_utils.sql_alter_db( '''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('P1', 1, 0, 1, 'sand', 'sand', '3', 'j')''' ) db_utils.sql_alter_db( '''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('P1', 2, 1, 4.5, 'morän', 'morän', '3', 'j')''' ) self.create_and_select_vlayer() dlg = Stratigraphy(self.iface, self.vlayer, self.ms.settingsdict) dlg.showSurvey() print(str(mock_skippopup.mock_calls)) test = utils.anything_to_string_representation(dlg.data) test_survey = utils.anything_to_string_representation( repr(dlg.data['P1'])) test_strata = utils.anything_to_string_representation( utils.returnunicode(dlg.data['P1'].strata, keep_containers=True)) assert len(mock_skippopup.mock_calls) == 0 assert len(mock_messagebar.mock_calls) == 0 assert test == """{"P1": SURVEY('P1', 5.000000, '<QgsPointXY: POINT(633466 711659)>')}""" assert test_survey == '''"SURVEY('P1', 5.000000, '<QgsPointXY: POINT(633466 711659)>')"''' print("Test strata " + test_strata) assert test_strata == '''["strata(1, '3', 'sand', 'sand', 0.000000-1.000000)", "strata(2, '3', 'morän', 'moran', 1.000000-4.500000)"]''' @mock.patch('midvatten_utils.MessagebarAndLog') @mock.patch('stratigraphy.utils.pop_up_info', autospec=True) @mock.patch('db_utils.QgsProject.instance', utils_for_tests.MidvattenTestSpatialiteNotCreated. mock_instance_settings_database) def test_stratigraphy_gap(self, mock_skippopup, mock_messagebar): """ :param mock_skippopup: :param mock_messagebar: :return: """ db_utils.sql_alter_db( '''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('1', 5, ST_GeomFromText('POINT(633466 711659)', 3006))''' ) db_utils.sql_alter_db( '''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('2', 10, ST_GeomFromText('POINT(6720727 016568)', 3006))''' ) db_utils.sql_alter_db( '''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('3', 20, ST_GeomFromText('POINT(6720728 016569)', 3006))''' ) db_utils.sql_alter_db( '''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('1', 1, 0, 1, 'sand', 'sand', '3', 'j')''' ) db_utils.sql_alter_db( '''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('1', 2, 2, 4.5, 'morän', 'morän', '3', 'j')''' ) self.create_and_select_vlayer() dlg = Stratigraphy(self.iface, self.vlayer, self.ms.settingsdict) dlg.showSurvey() test = utils.anything_to_string_representation(dlg.data) test_survey = utils.anything_to_string_representation( repr(dlg.data['1'])) test_strata = utils.anything_to_string_representation( utils.returnunicode(dlg.data['1'].strata, keep_containers=True)) assert len(mock_skippopup.mock_calls) == 0 assert len(mock_messagebar.mock_calls) == 0 assert test == """{"1": SURVEY('1', 5.000000, '<QgsPointXY: POINT(633466 711659)>')}""" assert test_survey == '''"SURVEY('1', 5.000000, '<QgsPointXY: POINT(633466 711659)>')"''' print("Test strata " + test_strata) assert test_strata == '''["strata(1, '3', 'sand', 'sand', 0.000000-1.000000)", "strata(2, '', '', '', 1.000000-2.000000)", "strata(3, '3', 'morän', 'moran', 2.000000-4.500000)"]''' @mock.patch('midvatten_utils.MessagebarAndLog') @mock.patch('stratigraphy.utils.pop_up_info', autospec=True) @mock.patch('db_utils.QgsProject.instance', utils_for_tests.MidvattenTestSpatialiteNotCreated. mock_instance_settings_database) def test_stratigraphy_missing_h_gs_use_h_toc(self, mock_skippopup, mock_messagebar): """ :param mock_skippopup: :param mock_messagebar: :return: """ db_utils.sql_alter_db( '''INSERT INTO obs_points (obsid, h_gs, geometry) VALUES ('1', 5, ST_GeomFromText('POINT(633466 711659)', 3006))''' ) db_utils.sql_alter_db( '''INSERT INTO obs_points (obsid, h_gs, h_toc, geometry) VALUES ('2', NULL, 10, ST_GeomFromText('POINT(6720727 016568)', 3006))''' ) db_utils.sql_alter_db( '''INSERT INTO obs_points (obsid, geometry) VALUES ('3', ST_GeomFromText('POINT(6720728 016569)', 3006))''' ) db_utils.sql_alter_db( '''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('1', 1, 0, 1, 'sand', 'sand', '3', 'j')''' ) db_utils.sql_alter_db( '''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('1', 2, 1, 4.5, 'morän', 'morän', '3', 'j')''' ) db_utils.sql_alter_db( '''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('2', 1, 0, 1, 'sand', 'sand', '3', 'j')''' ) db_utils.sql_alter_db( '''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('2', 2, 1, 4.5, 'morän', 'morän', '3', 'j')''' ) db_utils.sql_alter_db( '''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('3', 1, 0, 2, 'sand', 'sand', '3', 'j')''' ) db_utils.sql_alter_db( '''INSERT INTO stratigraphy (obsid, stratid, depthtop, depthbot, geology, geoshort, capacity, development) VALUES ('3', 2, 2, 6, 'morän', 'morän', '3', 'j')''' ) self.create_and_select_vlayer() dlg = Stratigraphy(self.iface, self.vlayer, self.ms.settingsdict) dlg.showSurvey() test = utils.anything_to_string_representation(dlg.data) test_survey = utils.anything_to_string_representation( repr(dlg.data['1'])) test_strata = utils.anything_to_string_representation( utils.returnunicode(dlg.data['1'].strata, keep_containers=True)) assert len(mock_skippopup.mock_calls) == 1 print(str(mock_skippopup.mock_calls)) print(str(mock_messagebar.mock_calls)) assert mock_skippopup.mock_calls == [ mock.call('Warning, h_gs is missing. See messagebar.') ] assert mock_messagebar.mock_calls == [ mock.call.warning( bar_msg="Obsid 2: using h_gs '' failed, using 'h_toc' instead.", duration=90, log_msg='False'), mock.call.warning( bar_msg="Obsid 3: using h_gs '' failed, using '-1' instead.", duration=90, log_msg='False') ] print(test) assert test == """{"1": SURVEY('1', 5.000000, '<QgsPointXY: POINT(633466 711659)>'), "2": SURVEY('2', 10.000000, '<QgsPointXY: POINT(6720727 16568)>'), "3": SURVEY('3', -1.000000, '<QgsPointXY: POINT(6720728 16569)>')}""" print("test_survey " + test_survey) assert test_survey == '''"SURVEY('1', 5.000000, '<QgsPointXY: POINT(633466 711659)>')"''' print("Test strata " + test_strata) assert test_strata == '''["strata(1, '3', 'sand', 'sand', 0.000000-1.000000)", "strata(2, '3', 'morän', 'moran', 1.000000-4.500000)"]''' def tearDown(self): QgsProject.instance().addMapLayer(self.vlayer) QgsProject.instance().removeMapLayer(self.vlayer.id()) super(self.__class__, self).tearDown()
def _test(autoTransaction): """Test buffer methods within and without transactions - create a feature - save - retrieve the feature - change geom and attrs - test changes are seen in the buffer """ def _check_feature(wkt): f = next(layer_a.getFeatures()) self.assertEqual(f.geometry().asWkt().upper(), wkt) f = list(buffer.addedFeatures().values())[0] self.assertEqual(f.geometry().asWkt().upper(), wkt) ml = QgsVectorLayer( 'Point?crs=epsg:4326&field=int:integer&field=int2:integer', 'test', 'memory') self.assertTrue(ml.isValid()) d = QTemporaryDir() options = QgsVectorFileWriter.SaveVectorOptions() options.driverName = 'GPKG' options.layerName = 'layer_a' err, msg, newFileName, newLayer = QgsVectorFileWriter.writeAsVectorFormatV3( ml, os.path.join(d.path(), 'transaction_test.gpkg'), QgsCoordinateTransformContext(), options) self.assertEqual(err, QgsVectorFileWriter.NoError) self.assertTrue(os.path.isfile(newFileName)) layer_a = QgsVectorLayer(newFileName + '|layername=layer_a') self.assertTrue(layer_a.isValid()) project = QgsProject() project.setAutoTransaction(autoTransaction) project.addMapLayers([layer_a]) ########################################### # Tests with a new feature self.assertTrue(layer_a.startEditing()) buffer = layer_a.editBuffer() f = QgsFeature(layer_a.fields()) f.setAttribute('int', 123) f.setGeometry(QgsGeometry.fromWkt('point(7 45)')) self.assertTrue(layer_a.addFeatures([f])) _check_feature('POINT (7 45)') # Need to fetch the feature because its ID is NULL (-9223372036854775808) f = next(layer_a.getFeatures()) self.assertEqual(len(buffer.addedFeatures()), 1) layer_a.undoStack().undo() self.assertEqual(len(buffer.addedFeatures()), 0) layer_a.undoStack().redo() self.assertEqual(len(buffer.addedFeatures()), 1) f = list(buffer.addedFeatures().values())[0] self.assertEqual(f.attribute('int'), 123) # Now change attribute self.assertEqual(buffer.changedAttributeValues(), {}) spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.changeAttributeValue(f.id(), 1, 321) self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 1, 321]) self.assertEqual(len(buffer.addedFeatures()), 1) # This is surprising: because it was a new feature it has been changed directly self.assertEqual(buffer.changedAttributeValues(), {}) f = list(buffer.addedFeatures().values())[0] self.assertEqual(f.attribute('int'), 321) spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.undoStack().undo() self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 1, 123]) self.assertEqual(buffer.changedAttributeValues(), {}) f = list(buffer.addedFeatures().values())[0] self.assertEqual(f.attribute('int'), 123) f = next(layer_a.getFeatures()) self.assertEqual(f.attribute('int'), 123) # Change multiple attributes spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.changeAttributeValues(f.id(), {1: 321, 2: 456}) self.assertEqual(len(spy_attribute_changed), 2) self.assertEqual(spy_attribute_changed[0], [f.id(), 1, 321]) self.assertEqual(spy_attribute_changed[1], [f.id(), 2, 456]) buffer = layer_a.editBuffer() # This is surprising: because it was a new feature it has been changed directly self.assertEqual(buffer.changedAttributeValues(), {}) spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.undoStack().undo() # This is because QgsVectorLayerUndoCommandChangeAttribute plural if not autoTransaction: layer_a.undoStack().undo() f = next(layer_a.getFeatures()) self.assertEqual(f.attribute('int'), 123) self.assertEqual(f.attribute('int2'), None) self.assertEqual(len(spy_attribute_changed), 2) self.assertEqual( spy_attribute_changed[1 if autoTransaction else 0], [f.id(), 2, None]) self.assertEqual( spy_attribute_changed[0 if autoTransaction else 1], [f.id(), 1, 123]) # Change geometry f = next(layer_a.getFeatures()) spy_geometry_changed = QSignalSpy(layer_a.geometryChanged) self.assertTrue( layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(9 43)'))) self.assertTrue(len(spy_geometry_changed), 1) self.assertEqual(spy_geometry_changed[0][0], f.id()) self.assertEqual(spy_geometry_changed[0][1].asWkt(), QgsGeometry.fromWkt('point(9 43)').asWkt()) _check_feature('POINT (9 43)') self.assertEqual(buffer.changedGeometries(), {}) layer_a.undoStack().undo() _check_feature('POINT (7 45)') self.assertEqual(buffer.changedGeometries(), {}) self.assertTrue( layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(9 43)'))) _check_feature('POINT (9 43)') self.assertTrue( layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(10 44)'))) _check_feature('POINT (10 44)') # This is another surprise: geometry edits get collapsed into a single # one because they have the same hardcoded id layer_a.undoStack().undo() _check_feature('POINT (7 45)') self.assertTrue(layer_a.commitChanges()) ########################################### # Tests with the existing feature # Get the feature f = next(layer_a.getFeatures()) self.assertTrue(f.isValid()) self.assertEqual(f.attribute('int'), 123) self.assertEqual(f.geometry().asWkt().upper(), 'POINT (7 45)') # Change single attribute self.assertTrue(layer_a.startEditing()) spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.changeAttributeValue(f.id(), 1, 321) self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 1, 321]) buffer = layer_a.editBuffer() self.assertEqual(buffer.changedAttributeValues(), {1: {1: 321}}) f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(1), 321) spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.undoStack().undo() f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(1), 123) self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 1, 123]) self.assertEqual(buffer.changedAttributeValues(), {}) # Change attributes spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.changeAttributeValues(f.id(), {1: 111, 2: 654}) self.assertEqual(len(spy_attribute_changed), 2) self.assertEqual(spy_attribute_changed[0], [1, 1, 111]) self.assertEqual(spy_attribute_changed[1], [1, 2, 654]) f = next(layer_a.getFeatures()) self.assertEqual(f.attributes(), [1, 111, 654]) self.assertEqual(buffer.changedAttributeValues(), {1: { 1: 111, 2: 654 }}) spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.undoStack().undo() # This is because QgsVectorLayerUndoCommandChangeAttribute plural if not autoTransaction: layer_a.undoStack().undo() self.assertEqual(len(spy_attribute_changed), 2) self.assertEqual( spy_attribute_changed[0 if autoTransaction else 1], [1, 1, 123]) self.assertEqual( spy_attribute_changed[1 if autoTransaction else 0], [1, 2, None]) f = next(layer_a.getFeatures()) self.assertEqual(f.attributes(), [1, 123, None]) self.assertEqual(buffer.changedAttributeValues(), {}) # Change geometry spy_geometry_changed = QSignalSpy(layer_a.geometryChanged) self.assertTrue( layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(9 43)'))) self.assertEqual(spy_geometry_changed[0][0], 1) self.assertEqual(spy_geometry_changed[0][1].asWkt(), QgsGeometry.fromWkt('point(9 43)').asWkt()) f = next(layer_a.getFeatures()) self.assertEqual(f.geometry().asWkt().upper(), 'POINT (9 43)') self.assertEqual(buffer.changedGeometries()[1].asWkt().upper(), 'POINT (9 43)') spy_geometry_changed = QSignalSpy(layer_a.geometryChanged) layer_a.undoStack().undo() self.assertEqual(spy_geometry_changed[0][0], 1) self.assertEqual(spy_geometry_changed[0][1].asWkt(), QgsGeometry.fromWkt('point(7 45)').asWkt()) self.assertEqual(buffer.changedGeometries(), {}) f = next(layer_a.getFeatures()) self.assertEqual(f.geometry().asWkt().upper(), 'POINT (7 45)') self.assertEqual(buffer.changedGeometries(), {}) # Delete an existing feature self.assertTrue(layer_a.deleteFeature(f.id())) with self.assertRaises(StopIteration): next(layer_a.getFeatures()) self.assertEqual(buffer.deletedFeatureIds(), [f.id()]) layer_a.undoStack().undo() self.assertTrue(layer_a.getFeature(f.id()).isValid()) self.assertEqual(buffer.deletedFeatureIds(), []) ########################################### # Test delete # Delete a new feature f = QgsFeature(layer_a.fields()) f.setAttribute('int', 555) f.setGeometry(QgsGeometry.fromWkt('point(8 46)')) self.assertTrue(layer_a.addFeatures([f])) f = [ f for f in layer_a.getFeatures() if f.attribute('int') == 555 ][0] self.assertTrue(f.id() in buffer.addedFeatures()) self.assertTrue(layer_a.deleteFeature(f.id())) self.assertFalse(f.id() in buffer.addedFeatures()) self.assertFalse(f.id() in buffer.deletedFeatureIds()) layer_a.undoStack().undo() self.assertTrue(f.id() in buffer.addedFeatures()) ########################################### # Add attribute field = QgsField('attr1', QVariant.String) self.assertTrue(layer_a.addAttribute(field)) self.assertNotEqual(layer_a.fields().lookupField(field.name()), -1) self.assertEqual(buffer.addedAttributes(), [field]) layer_a.undoStack().undo() self.assertEqual(layer_a.fields().lookupField(field.name()), -1) self.assertEqual(buffer.addedAttributes(), []) layer_a.undoStack().redo() self.assertNotEqual(layer_a.fields().lookupField(field.name()), -1) self.assertEqual(buffer.addedAttributes(), [field]) self.assertTrue(layer_a.commitChanges()) ########################################### # Remove attribute self.assertTrue(layer_a.startEditing()) buffer = layer_a.editBuffer() attr_idx = layer_a.fields().lookupField(field.name()) self.assertNotEqual(attr_idx, -1) self.assertTrue(layer_a.deleteAttribute(attr_idx)) self.assertEqual(buffer.deletedAttributeIds(), [attr_idx]) self.assertEqual(layer_a.fields().lookupField(field.name()), -1) layer_a.undoStack().undo() self.assertEqual(buffer.deletedAttributeIds(), []) self.assertEqual(layer_a.fields().lookupField(field.name()), attr_idx) # This is totally broken at least on OGR/GPKG: the rollback # does not restore the original fields if False: layer_a.undoStack().redo() self.assertEqual(buffer.deletedAttributeIds(), [attr_idx]) self.assertEqual(layer_a.fields().lookupField(field.name()), -1) # Rollback! self.assertTrue(layer_a.rollBack()) self.assertIn('attr1', layer_a.dataProvider().fields().names()) self.assertIn('attr1', layer_a.fields().names()) self.assertEqual(layer_a.fields().names(), layer_a.dataProvider().fields().names()) attr_idx = layer_a.fields().lookupField(field.name()) self.assertNotEqual(attr_idx, -1) self.assertTrue(layer_a.startEditing()) attr_idx = layer_a.fields().lookupField(field.name()) self.assertNotEqual(attr_idx, -1) ########################################### # Rename attribute attr_idx = layer_a.fields().lookupField(field.name()) self.assertEqual(layer_a.fields().lookupField('new_name'), -1) self.assertTrue(layer_a.renameAttribute(attr_idx, 'new_name')) self.assertEqual(layer_a.fields().lookupField('new_name'), attr_idx) layer_a.undoStack().undo() self.assertEqual(layer_a.fields().lookupField(field.name()), attr_idx) self.assertEqual(layer_a.fields().lookupField('new_name'), -1) layer_a.undoStack().redo() self.assertEqual(layer_a.fields().lookupField('new_name'), attr_idx) self.assertEqual(layer_a.fields().lookupField(field.name()), -1) ############################################# # Try hard to make this fail for transactions if autoTransaction: self.assertTrue(layer_a.commitChanges()) self.assertTrue(layer_a.startEditing()) f = next(layer_a.getFeatures()) # Do for i in range(10): spy_attribute_changed = QSignalSpy( layer_a.attributeValueChanged) layer_a.changeAttributeValue(f.id(), 2, i) self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 2, i]) buffer = layer_a.editBuffer() self.assertEqual(buffer.changedAttributeValues(), {f.id(): { 2: i }}) f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(2), i) # Undo/redo for i in range(9): # Undo spy_attribute_changed = QSignalSpy( layer_a.attributeValueChanged) layer_a.undoStack().undo() f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(2), 8 - i) self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 2, 8 - i]) buffer = layer_a.editBuffer() self.assertEqual(buffer.changedAttributeValues(), {f.id(): { 2: 8 - i }}) # Redo spy_attribute_changed = QSignalSpy( layer_a.attributeValueChanged) layer_a.undoStack().redo() f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(2), 9 - i) self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 2, 9 - i]) # Undo again spy_attribute_changed = QSignalSpy( layer_a.attributeValueChanged) layer_a.undoStack().undo() f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(2), 8 - i) self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 2, 8 - i]) buffer = layer_a.editBuffer() self.assertEqual(buffer.changedAttributeValues(), {f.id(): { 2: 8 - i }}) # Last check f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(2), 8 - i) self.assertEqual(buffer.changedAttributeValues(), {f.id(): { 2: 0 }}) layer_a.undoStack().undo() buffer = layer_a.editBuffer() self.assertEqual(buffer.changedAttributeValues(), {}) f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(2), None)
def layerSubsetSave(rasterLayer: QgsRasterLayer, domainLayer: QgsVectorLayer, subsetName: str) -> None: """Description: Processes a raster image into a vector polygon ocean/land mask. Make sure to save the shapefile, as it will be deleted otherwise! Input: QgsRasterLayer rasterLayer - layer that contains the raster image to process QgsVectorLayer domainLayer - layer that contains a polygon specifying the bounds of the raster image to process string name - output file name. Output: QgsRasterLayer, QgsVectorLayer - objects referencing the new mask layers """ # Get basic file name information on geotiff, raster image, masked raster subset image, and masked vector subset shp file fileSource = rasterLayer.source() fileInfo = QFileInfo(fileSource) fileName = fileInfo.baseName() savePaths = getSavePaths(fileSource, domainLayer, 'tif') subsetPath = savePaths + '/' + subsetName + '.tif' # Load geotiff and get domain layer/bounding box of area to mask geotiff = gdal.Open(fileSource) feature = domainLayer.getFeature(0) domain = feature.geometry().boundingBox() prj = geotiff.GetProjection() srs = osr.SpatialReference(wkt=prj) if srs.GetAttrValue("PROJCS|AUTHORITY", 1) is not None: epsgCode = srs.GetAttrValue("PROJCS|AUTHORITY", 1) elif srs.GetAttrValue("AUTHORITY", 1) is not None: epsgCode = srs.GetAttrValue("AUTHORITY", 1) else: epsgCode = str(32621) rasterCRS = "EPSG:" + epsgCode crs = rasterLayer.crs() crs.createFromId(int(epsgCode)) rasterLayer.setCrs(crs) rasterLayer.triggerRepaint() #rasterCRS = rasterLayer.crs().authid() domainCRS = domainLayer.crs().authid() bounds = geotiffWorldToPixelCoords(geotiff, domain, rasterCRS, domainCRS) band = geotiff.GetRasterBand(1) img_full = band.ReadAsArray(0, 0, geotiff.RasterXSize, geotiff.RasterYSize) img = img_full[int(round(bounds.yMinimum())):int(round(bounds.yMaximum())), int(round(bounds.xMinimum())):int(round(bounds.xMaximum()))] print('bounds', bounds.yMinimum(), bounds.yMaximum(), bounds.xMinimum(), bounds.xMaximum()) print('img.shape', img.shape, 'img_full.shape', img_full.shape) print("img min/max/mean:", img.min(), img.max(), np.mean(img, axis=(0, 1))) img = (img.astype(np.float32) / img.max() * 65535).astype(np.uint16) print("after img min/max/mean:", img.min(), img.max(), np.mean(img, axis=(0, 1))) # print('Save subset:', subsetPath, resolve('landsat_raw/' + domainLayer.name() + '/' + subsetName + '.png')) if not DRY_RUN: arrayToRaster(img, geotiff, bounds, subsetPath) imsave( resolve('landsat_raw/' + domainLayer.name() + '/' + subsetName + '.png'), img) # imsave(resolve('small/' + domainLayer.name() + '/' + subsetName + '.png'), img) # imsave(os.path.join(r'D:\Daniel\Documents\Github\CALFIN Repo\reprocessing\images_1024', domainLayer.name(), subsetName + '.png'), img) try: #Gather BQA info fileSourceBQA = fileSource[:-7] + '_BQA.TIF' #Save BQA subset geotiffBQA = gdal.Open(fileSourceBQA) imgBQA = geotiffBQA.GetRasterBand(1) imgBQA = imgBQA.ReadAsArray(0, 0, geotiffBQA.RasterXSize, geotiffBQA.RasterYSize).astype(np.uint16) imgBQA = imgBQA[ int(round(bounds.yMinimum())):int(round(bounds.yMaximum())), int(round(bounds.xMinimum())):int(round(bounds.xMaximum()))] # print('Save BQA subset:', subsetPathBQA, resolve('landsat_raw/' + domainLayer.name() + '/' + subsetName + '_bqa.png')) if not DRY_RUN: # arrayToRaster(imgBQA, geotiffBQA, bounds, subsetPathBQA) # print(fileSourceBQA, geotiffBQA.RasterXSize, geotiffBQA.RasterYSize) # print(int(round(bounds.yMinimum())), int(round(bounds.yMaximum())), int(round(bounds.xMinimum())), int(round(bounds.xMaximum()))) # imsave(resolve('landsat_raw/' + domainLayer.name() + '/' + subsetName + '_bqa.png'), imgBQA) pass #Gather MTL info fileSourceMTL = fileSource[:-7] + '_MTL.txt' #Save MTL subset if not DRY_RUN: image_feats = [''] * 6 with open(fileSourceMTL, 'r') as image_feats_source_file: lines = image_feats_source_file.readlines() for line in lines: if 'SUN_AZIMUTH =' in line: image_feats[0] = line.strip() elif 'SUN_ELEVATION =' in line: image_feats[1] = line.strip() elif 'CLOUD_COVER ' in line: image_feats[2] = line.strip() elif 'CLOUD_COVER_LAND ' in line: image_feats[3] = line.strip() elif 'DATE_ACQUIRED =' in line: image_feats[4] = line.strip() elif 'GRID_CELL_SIZE_REFLECTIVE =' in line: image_feats[5] = line.strip() savePath = resolve('landsat_raw/' + domainLayer.name() + '/' + subsetName + '_mtl.txt') with open(savePath, 'w') as image_feats_dest_file: for line in image_feats: image_feats_dest_file.write(str(line) + '\n') except: print('No BQA/MTL found for:', subsetName) return img.shape
def domainInRaster(rasterLayer: QgsRasterLayer, domainLayer: QgsVectorLayer) -> bool: """Returns bool if domain is within bounds of geotiff in rasterLayer :param rasterLayer: QgsRasterLayer :param domainLayer: QgsVectorLayer """ # Get basic file name information on geotiff, raster image, masked raster subset image, and masked vector subset shp file fileSource = rasterLayer.source() # Load geotiff and get domain layer/bounding box of area to mask geotiff = gdal.Open(fileSource) feature = domainLayer.getFeature(0) domain = feature.geometry().boundingBox() prj = geotiff.GetProjection() srs = osr.SpatialReference(wkt=prj) if srs.GetAttrValue("PROJCS|AUTHORITY", 1) is not None: epsgCode = srs.GetAttrValue("PROJCS|AUTHORITY", 1) elif srs.GetAttrValue("AUTHORITY", 1) is not None: epsgCode = srs.GetAttrValue("AUTHORITY", 1) else: epsgCode = str(32621) rasterCRS = "EPSG:" + epsgCode crs = rasterLayer.crs() crs.createFromId(int(epsgCode)) domainCRS = domainLayer.crs().authid() bounds = geotiffWorldToPixelCoords(geotiff, domain, rasterCRS, domainCRS) #Gather BQA info fileSourceBQA = fileSource[:-7] + '_BQA.TIF' #Save BQA subset geotiffBQA = gdal.Open(fileSourceBQA) minX = int(round(bounds.yMinimum())) maxX = int(round(bounds.yMaximum())) minY = int(round(bounds.xMinimum())) maxY = int(round(bounds.xMaximum())) if minX < 0 or maxX > geotiff.RasterXSize or maxX > geotiffBQA.RasterXSize or minY < 0 or maxY > geotiff.RasterYSize or maxY > geotiffBQA.RasterYSize: return False else: #Check image is above Nodata percentage threshold band = geotiff.GetRasterBand(1) # Get raster statistics stats = band.GetStatistics(True, True) min_value, max_value = stats[0], stats[1] img_full = band.ReadAsArray(0, 0, geotiff.RasterXSize, geotiff.RasterYSize) img = img_full[ int(round(bounds.yMinimum())):int(round(bounds.yMaximum())), int(round(bounds.xMinimum())):int(round(bounds.xMaximum()))] if img.shape[0] == 0 or img.shape[1] == 0: geotiff = None geotiffBQA = None print('Skipping: not in domain') return False noDataValue = 0.0 # print(min_value, max_value, img.shape) noDataValueThreshold = noDataValue + (max_value - min_value) * 0.006 noDataCount = np.sum(img < noDataValue + noDataValueThreshold) percentNoData = noDataCount / img.size # print('percentNoData', percentNoData, 'noDataCount', noDataCount, 'noDataValueThreshold', noDataValueThreshold) if percentNoData > nodata_threshold: geotiff = None geotiffBQA = None print('Skipping: Nodata percentage above threshold:', percentNoData, ' > ', nodata_threshold) return False #Check image is above cloud percentage threshold bandBQA = geotiffBQA.GetRasterBand(1) imgBQA = bandBQA.ReadAsArray(minX, minY, maxX - minX, maxY - minY).astype(np.uint16) print('warning: check cloud mask parameters for MSS! (year < 1985)') masked = imgBQA & maskClouds cloudCount = np.sum(masked) percentCloud = cloudCount / 8.0 / imgBQA.size if percentCloud > cloud_threshold: geotiff = None geotiffBQA = None print('Skipping: Cloud percentage above threshold:', percentCloud, ' > ', cloud_threshold) return False geotiff = None geotiffBQA = None return True
def testObjectIdDifferentName(self): """ Test that object id fields not named OBJECTID work correctly """ endpoint = self.basetestpath + '/oid_fake_qgis_http_endpoint' with open(sanitize(endpoint, '?f=json'), 'wb') as f: f.write(""" {"currentVersion":10.22,"id":1,"name":"QGIS Test","type":"Feature Layer","description": "QGIS Provider Test Layer.\n","geometryType":"esriGeometryPoint","copyrightText":"","parentLayer":{"id":0,"name":"QGIS Tests"},"subLayers":[], "minScale":72225,"maxScale":0, "defaultVisibility":true, "extent":{"xmin":-71.123,"ymin":66.33,"xmax":-65.32,"ymax":78.3, "spatialReference":{"wkid":4326,"latestWkid":4326}}, "hasAttachments":false,"htmlPopupType":"esriServerHTMLPopupTypeAsHTMLText", "displayField":"LABEL","typeIdField":null, "fields":[{"name":"OBJECTID1","type":"esriFieldTypeOID","alias":"OBJECTID","domain":null}, {"name":"pk","type":"esriFieldTypeInteger","alias":"pk","domain":null}, {"name":"cnt","type":"esriFieldTypeInteger","alias":"cnt","domain":null}], "relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false, "capabilities":"Map,Query,Data","maxRecordCount":1000,"supportsStatistics":true, "supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF", "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""" .encode('UTF-8')) with open( sanitize( endpoint, '/query?f=json_where=OBJECTID1=OBJECTID1_returnIdsOnly=true' ), 'wb') as f: f.write(""" { "objectIdFieldName": "OBJECTID1", "objectIds": [ 5, 3, 1, 2, 4 ] } """.encode('UTF-8')) with open( sanitize( endpoint, '/query?f=json&objectIds=5,3,1,2,4&inSR=4326&outSR=4326&returnGeometry=true&outFields=OBJECTID1,pk,cnt&returnM=false&returnZ=false' ), 'wb') as f: f.write(""" { "displayFieldName": "LABEL", "geometryType": "esriGeometryPoint", "spatialReference": { "wkid": 4326, "latestWkid": 4326 }, "fields":[{"name":"OBJECTID1","type":"esriFieldTypeOID","alias":"OBJECTID1","domain":null}, {"name":"pk","type":"esriFieldTypeInteger","alias":"pk","domain":null}, {"name":"cnt","type":"esriFieldTypeInteger","alias":"cnt","domain":null}, {"name":"Shape","type":"esriFieldTypeGeometry","alias":"Shape","domain":null}], "features": [ { "attributes": { "OBJECTID1": 5, "pk": 5, "cnt": -200, "name": null }, "geometry": { "x": -71.123, "y": 78.23 } } ] }""".encode('UTF-8')) # Create test layer vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver') assert vl.isValid() f = vl.getFeature(0) assert f.isValid()
def processAlgorithm(self, parameters, context, feedback): feedback.pushInfo(self.tr("[QNEAT3Algorithm] This is a QNEAT3 Algorithm: '{}'".format(self.displayName()))) network = self.parameterAsVectorLayer(parameters, self.INPUT, context) #QgsVectorLayer startPoint = self.parameterAsPoint(parameters, self.START_POINT, context, network.sourceCrs()) #QgsPointXY max_dist = self.parameterAsDouble(parameters, self.MAX_DIST, context)#float cell_size = self.parameterAsInt(parameters, self.CELL_SIZE, context)#int strategy = self.parameterAsEnum(parameters, self.STRATEGY, context) #int interpolation_method = self.parameterAsEnum(parameters, self.METHOD, context)#int entry_cost_calc_method = self.parameterAsEnum(parameters, self.ENTRY_COST_CALCULATION_METHOD, context) #int directionFieldName = self.parameterAsString(parameters, self.DIRECTION_FIELD, context) #str (empty if no field given) forwardValue = self.parameterAsString(parameters, self.VALUE_FORWARD, context) #str backwardValue = self.parameterAsString(parameters, self.VALUE_BACKWARD, context) #str bothValue = self.parameterAsString(parameters, self.VALUE_BOTH, context) #str defaultDirection = self.parameterAsEnum(parameters, self.DEFAULT_DIRECTION, context) #int speedFieldName = self.parameterAsString(parameters, self.SPEED_FIELD, context) #str defaultSpeed = self.parameterAsDouble(parameters, self.DEFAULT_SPEED, context) #float tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context) #float output_path = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) analysisCrs = network.sourceCrs() input_coordinates = [startPoint] input_point = getFeatureFromPointParameter(startPoint) feedback.pushInfo("[QNEAT3Algorithm] Building Graph...") feedback.setProgress(10) net = Qneat3Network(network, input_coordinates, strategy, directionFieldName, forwardValue, backwardValue, bothValue, defaultDirection, analysisCrs, speedFieldName, defaultSpeed, tolerance, feedback) feedback.setProgress(40) analysis_point = Qneat3AnalysisPoint("point", input_point, "point_id", net, net.list_tiedPoints[0], entry_cost_calc_method, feedback) feedback.pushInfo("[QNEAT3Algorithm] Calculating Iso-Pointcloud...") iso_pointcloud = net.calcIsoPoints([analysis_point], max_dist) feedback.setProgress(70) uri = "Point?crs={}&field=vertex_id:int(254)&field=cost:double(254,7)&field=origin_point_id:string(254)&index=yes".format(analysisCrs.authid()) iso_pointcloud_layer = QgsVectorLayer(uri, "iso_pointcloud_layer", "memory") iso_pointcloud_provider = iso_pointcloud_layer.dataProvider() iso_pointcloud_provider.addFeatures(iso_pointcloud, QgsFeatureSink.FastInsert) feedback.pushInfo("[QNEAT3Algorithm] Calculating Iso-Interpolation-Raster using QGIS TIN-Interpolator...") if interpolation_method == 0: feedback.pushInfo("[QNEAT3Algorithm] Calculating Iso-Interpolation-Raster using QGIS TIN-Interpolator...") net.calcIsoTinInterpolation(iso_pointcloud_layer, cell_size, output_path) feedback.setProgress(99) else: #prepare numpy coordinate grids NoData_value = -9999 raster_rectangle = iso_pointcloud_layer.extent() #implement spatial index for lines (closest line, etc...) spt_idx = QgsSpatialIndex(iso_pointcloud_layer.getFeatures(QgsFeatureRequest()), feedback) #top left point xmin = raster_rectangle.xMinimum() ymin = raster_rectangle.yMinimum() xmax = raster_rectangle.xMaximum() ymax = raster_rectangle.yMaximum() cols = int((xmax - xmin) / cell_size) rows = int((ymax - ymin) / cell_size) output_interpolation_raster = gdal.GetDriverByName('GTiff').Create(output_path, cols, rows, 1, gdal.GDT_Float64 ) output_interpolation_raster.SetGeoTransform((xmin, cell_size, 0, ymax, 0, -cell_size)) band = output_interpolation_raster.GetRasterBand(1) band.SetNoDataValue(NoData_value) #initialize zero array with 2 dimensions (according to rows and cols) raster_routingcost_data = zeros(shape=(rows, cols)) #compute raster cell MIDpoints x_pos = linspace(xmin+(cell_size/2), xmax -(cell_size/2), raster_routingcost_data.shape[1]) y_pos = linspace(ymax-(cell_size/2), ymin + (cell_size/2), raster_routingcost_data.shape[0]) x_grid, y_grid = meshgrid(x_pos, y_pos) feedback.pushInfo('[QNEAT3Network][calcQneatInterpolation] Beginning with interpolation') total_work = rows * cols counter = 0 feedback.pushInfo('[QNEAT3Network][calcQneatInterpolation] Total workload: {} cells'.format(total_work)) feedback.setProgress(0) for i in range(rows): for j in range(cols): current_pixel_midpoint = QgsPointXY(x_grid[i,j],y_grid[i,j]) nearest_vertex_fid = spt_idx.nearestNeighbor(current_pixel_midpoint, 1)[0] nearest_feature = iso_pointcloud_layer.getFeature(nearest_vertex_fid) nearest_vertex = net.network.vertex(nearest_feature['vertex_id']) #yields a list of all incoming and outgoing edges edges = nearest_vertex.incomingEdges() + nearest_vertex.outgoingEdges() vertex_found = False nearest_counter = 2 while vertex_found == False: #find the second nearest vertex (eg, the vertex with least cost of all edges incoming to the first nearest vertex) second_nearest_feature_fid = spt_idx.nearestNeighbor(current_pixel_midpoint, nearest_counter)[nearest_counter-1] second_nearest_feature = iso_pointcloud_layer.getFeature(second_nearest_feature_fid) second_nearest_vertex_id = second_nearest_feature['vertex_id'] for edge_id in edges: from_vertex_id = net.network.edge(edge_id).fromVertex() to_vertex_id = net.network.edge(edge_id).toVertex() if second_nearest_vertex_id == from_vertex_id: vertex_found = True vertex_type = "from_vertex" from_point = second_nearest_feature.geometry().asPoint() from_vertex_cost = second_nearest_feature['cost'] if second_nearest_vertex_id == to_vertex_id: vertex_found = True vertex_type = "to_vertex" to_point = second_nearest_feature.geometry().asPoint() to_vertex_cost = second_nearest_feature['cost'] nearest_counter = nearest_counter + 1 """ if nearest_counter == 5: vertex_found = True vertex_type = "end_vertex" """ if vertex_type == "from_vertex": nearest_edge_geometry = QgsGeometry().fromPolylineXY([from_point, nearest_vertex.point()]) res = nearest_edge_geometry.closestSegmentWithContext(current_pixel_midpoint) segment_point = res[1] #[0: distance, 1: point, 2: left_of, 3: epsilon for snapping] dist_to_segment = segment_point.distance(current_pixel_midpoint) dist_edge = from_point.distance(segment_point) #feedback.pushInfo("dist_to_segment = {}".format(dist_to_segment)) #feedback.pushInfo("dist_on_edge = {}".format(dist_edge)) #feedback.pushInfo("cost = {}".format(from_vertex_cost)) pixel_cost = from_vertex_cost + dist_edge + dist_to_segment raster_routingcost_data[i,j] = pixel_cost elif vertex_type == "to_vertex": nearest_edge_geometry = QgsGeometry().fromPolylineXY([nearest_vertex.point(), to_point]) res = nearest_edge_geometry.closestSegmentWithContext(current_pixel_midpoint) segment_point = res[1] #[0: distance, 1: point, 2: left_of, 3: epsilon for snapping] dist_to_segment = segment_point.distance(current_pixel_midpoint) dist_edge = to_point.distance(segment_point) #feedback.pushInfo("dist_to_segment = {}".format(dist_to_segment)) #feedback.pushInfo("dist_on_edge = {}".format(dist_edge)) #feedback.pushInfo("cost = {}".format(from_vertex_cost)) pixel_cost = to_vertex_cost + dist_edge + dist_to_segment raster_routingcost_data[i,j] = pixel_cost else: pixel_cost = -99999#nearest_feature['cost'] + (nearest_vertex.point().distance(current_pixel_midpoint)) """ nearest_feature_pointxy = nearest_feature.geometry().asPoint() nearest_feature_cost = nearest_feature['cost'] dist_to_vertex = current_pixel_midpoint.distance(nearest_feature_pointxy) #implement time cost pixel_cost = dist_to_vertex + nearest_feature_cost raster_data[i,j] = pixel_cost """ counter = counter+1 if counter%1000 == 0: feedback.pushInfo("[QNEAT3Network][calcQneatInterpolation] Interpolated {} cells...".format(counter)) feedback.setProgress((counter/total_work)*100) band.WriteArray(raster_routingcost_data) outRasterSRS = osr.SpatialReference() outRasterSRS.ImportFromWkt(net.AnalysisCrs.toWkt()) output_interpolation_raster.SetProjection(outRasterSRS.ExportToWkt()) band.FlushCache() feedback.pushInfo("[QNEAT3Algorithm] Ending Algorithm") feedback.setProgress(100) results = {} results[self.OUTPUT] = output_path return results
class TestVectorlayer(utils_for_tests.MidvattenTestSpatialiteDbSv): @mock.patch('db_utils.QgsProject.instance', utils_for_tests.MidvattenTestSpatialiteNotCreated.mock_instance_settings_database) def create_vlayer(self, no_print=False): self.qgs = QgsApplication([], True) self.qgs.initQgis() dbconnection = db_utils.DbConnectionManager() uri = dbconnection.uri uri.setDataSource('', 'obs_points', 'geometry', '', 'obsid') dbtype = db_utils.get_dbtype(dbconnection.dbtype) self.vlayer = QgsVectorLayer(uri.uri(), 'TestLayer', dbtype) features = self.vlayer.getFeatures() feature_ids = [feature.id() for feature in features] if not no_print: print("1. Valid vlayer '{}'".format(self.vlayer.isValid())) print("2. feature_ids: " + str(feature_ids)) print("5. QgsVectorLayer.getFeature(): " + str([self.vlayer.getFeature(x).id() for x in feature_ids])) print("6. QgsVectorLayer.getFeature() type: " + str([str(type(self.vlayer.getFeature(x))) for x in feature_ids])) print("7. QgsVectorLayer.getFeatures(): " + str([x.id() for x in self.vlayer.getFeatures(feature_ids)])) print("8. QgsVectorLayer.featureCount(): " + str(self.vlayer.featureCount())) def select_features(self, feature_ids=None, no_print=True): if feature_ids is None: features = self.vlayer.getFeatures() feature_ids = [feature.id() for feature in features] self.vlayer.selectByIds(feature_ids) if not no_print: print("3. QgsVectorLayer.selectedFeatureIds: " + str(self.vlayer.selectedFeatureIds())) print("4. QgsVectorLayer.getSelectedFeatures: " + str([x.id() for x in self.vlayer.getSelectedFeatures()])) @mock.patch('midvatten_utils.MessagebarAndLog') @mock.patch('stratigraphy.utils.pop_up_info', autospec=True) @mock.patch('db_utils.QgsProject.instance', utils_for_tests.MidvattenTestSpatialiteNotCreated.mock_instance_settings_database) def test_vlayer(self, mock_skippopup, mock_messagebar): """ :param mock_skippopup: :param mock_messagebar: :return: """ for obsid in [1, 2, 3]: db_utils.sql_alter_db('''INSERT INTO obs_points (obsid) VALUES ({})'''.format(str(obsid))) self.create_vlayer() self.select_features() feature_ids = [feature.id() for feature in self.vlayer.getFeatures()] reference_ids = (1, 2, 3) assert self.vlayer.isValid() assert len(feature_ids) == len(reference_ids) assert tuple(feature_ids) == reference_ids assert tuple(sorted([x for x in self.vlayer.selectedFeatureIds()])) == reference_ids assert tuple(sorted([x.id() for x in self.vlayer.getSelectedFeatures()])) == reference_ids assert tuple(sorted([x.id() for x in self.vlayer.getFeatures(feature_ids)])) == reference_ids assert self.vlayer.featureCount() == 3 @mock.patch('midvatten_utils.MessagebarAndLog') @mock.patch('stratigraphy.utils.pop_up_info', autospec=True) @mock.patch('db_utils.QgsProject.instance', utils_for_tests.MidvattenTestSpatialiteNotCreated.mock_instance_settings_database) def test_vlayer_other_ints_ids(self, mock_skippopup, mock_messagebar): """ :param mock_skippopup: :param mock_messagebar: :return: """ for obsid in [4, 5, 6]: db_utils.sql_alter_db('''INSERT INTO obs_points (obsid) VALUES ({})'''.format(str(obsid))) self.create_vlayer() self.select_features() feature_ids = [feature.id() for feature in self.vlayer.getFeatures()] reference_ids = (1, 2, 3) assert self.vlayer.isValid() assert len(feature_ids) == len(reference_ids) assert tuple(feature_ids) == reference_ids assert tuple(sorted([x for x in self.vlayer.selectedFeatureIds()])) == reference_ids assert tuple(sorted([x.id() for x in self.vlayer.getSelectedFeatures()])) == reference_ids assert tuple(sorted([x.id() for x in self.vlayer.getFeatures(feature_ids)])) == reference_ids assert self.vlayer.featureCount() == 3 @mock.patch('midvatten_utils.MessagebarAndLog') @mock.patch('stratigraphy.utils.pop_up_info', autospec=True) @mock.patch('db_utils.QgsProject.instance', utils_for_tests.MidvattenTestSpatialiteNotCreated.mock_instance_settings_database) def test_vlayer_strings(self, mock_skippopup, mock_messagebar): """ :param mock_skippopup: :param mock_messagebar: :return: """ for obsid in ['A', 'b', 'c1']: db_utils.sql_alter_db('''INSERT INTO obs_points (obsid) VALUES ('{}')'''.format(str(obsid))) self.create_vlayer() self.select_features() feature_ids = [feature.id() for feature in self.vlayer.getFeatures()] reference_ids = (1, 2, 3) assert self.vlayer.isValid() assert len(feature_ids) == len(reference_ids) assert tuple(feature_ids) == reference_ids assert tuple(sorted([x for x in self.vlayer.selectedFeatureIds()])) == reference_ids assert tuple(sorted([x.id() for x in self.vlayer.getSelectedFeatures()])) == reference_ids assert tuple(sorted([x.id() for x in self.vlayer.getFeatures(feature_ids)])) == reference_ids assert self.vlayer.featureCount() == 3 @mock.patch('midvatten_utils.MessagebarAndLog') @mock.patch('stratigraphy.utils.pop_up_info', autospec=True) @mock.patch('db_utils.QgsProject.instance', utils_for_tests.MidvattenTestSpatialiteNotCreated.mock_instance_settings_database) def test_vlayer_1000_features(self, mock_skippopup, mock_messagebar): """ :param mock_skippopup: :param mock_messagebar: :return: """ dbconnection = db_utils.DbConnectionManager() cur = dbconnection.cursor cur.execute('''BEGIN TRANSACTION;''') for obsid in range(1000): cur.execute('''INSERT INTO obs_points (obsid) VALUES ('{}');'''.format(str(obsid))) cur.execute('''END TRANSACTION;''') self.create_vlayer(no_print=True) self.select_features(no_print=True) feature_ids = [feature.id() for feature in self.vlayer.getFeatures()] reference_ids = tuple(range(1, 1001)) print("First 10 ids: " + str(feature_ids[:10])) print("Last 10 ids: " + str(feature_ids[-10:])) print("First 10 reference_ids: " + str(reference_ids[:10])) print("Last 10 reference_ids: " + str(reference_ids[-10:])) assert self.vlayer.isValid() assert len(feature_ids) == len(reference_ids) assert tuple(feature_ids) == reference_ids assert tuple(sorted([x for x in self.vlayer.selectedFeatureIds()])) == reference_ids assert tuple(sorted([x.id() for x in self.vlayer.getSelectedFeatures()])) == reference_ids assert tuple(sorted([x.id() for x in self.vlayer.getFeatures(feature_ids)])) == reference_ids assert self.vlayer.featureCount() == len(reference_ids) @mock.patch('midvatten_utils.MessagebarAndLog') @mock.patch('stratigraphy.utils.pop_up_info', autospec=True) @mock.patch('db_utils.QgsProject.instance', utils_for_tests.MidvattenTestSpatialiteNotCreated.mock_instance_settings_database) def test_vlayer_2000_ints(self, mock_skippopup, mock_messagebar): """ :param mock_skippopup: :param mock_messagebar: :return: """ dbconnection = db_utils.DbConnectionManager() cur = dbconnection.cursor cur.execute('''BEGIN TRANSACTION;''') for obsid in range(2000): cur.execute('''INSERT INTO obs_points (obsid) VALUES ('{}');'''.format(str(obsid))) cur.execute('''END TRANSACTION;''') self.create_vlayer(no_print=True) self.select_features(no_print=True) feature_ids = [feature.id() for feature in self.vlayer.getFeatures()] reference_ids = tuple(range(1, 2001)) print("First 10 ids: " + str(feature_ids[:10])) print("Last 10 ids: " + str(feature_ids[-10:])) print("First 10 reference_ids: " + str(reference_ids[:10])) print("Last 10 reference_ids: " + str(reference_ids[-10:])) assert self.vlayer.isValid() assert len(feature_ids) == len(reference_ids) assert tuple(feature_ids) == reference_ids assert tuple(sorted([x for x in self.vlayer.selectedFeatureIds()])) == reference_ids assert tuple(sorted([x.id() for x in self.vlayer.getSelectedFeatures()])) == reference_ids assert tuple(sorted([x.id() for x in self.vlayer.getFeatures(feature_ids)])) == reference_ids assert self.vlayer.featureCount() == len(reference_ids) @mock.patch('midvatten_utils.MessagebarAndLog') @mock.patch('stratigraphy.utils.pop_up_info', autospec=True) @mock.patch('db_utils.QgsProject.instance', utils_for_tests.MidvattenTestSpatialiteNotCreated.mock_instance_settings_database) def test_vlayer_2000_strings(self, mock_skippopup, mock_messagebar): """ :param mock_skippopup: :param mock_messagebar: :return: """ dbconnection = db_utils.DbConnectionManager() cur = dbconnection.cursor obsids = [letter + str(_int) for letter in string.ascii_letters for _int in range(80)] cur.execute('''BEGIN TRANSACTION;''') for obsid in obsids: cur.execute('''INSERT INTO obs_points (obsid) VALUES ('{}');'''.format(str(obsid))) cur.execute('''END TRANSACTION;''') dbconnection.commit() self.create_vlayer(no_print=True) self.select_features(no_print=True) feature_ids = [feature.id() for feature in self.vlayer.getFeatures()] reference_ids = tuple(range(1, len(obsids)+1)) print("First 10 ids: " + str(feature_ids[:10])) print("Last 10 ids: " + str(feature_ids[-10:])) print("First 10 reference_ids: " + str(reference_ids[:10])) print("Last 10 reference_ids: " + str(reference_ids[-10:])) print(str(self.vlayer.featureCount())) assert self.vlayer.isValid() assert len(feature_ids) == len(reference_ids) assert tuple(feature_ids) == reference_ids assert tuple(sorted([x for x in self.vlayer.selectedFeatureIds()])) == reference_ids assert tuple(sorted([x.id() for x in self.vlayer.getSelectedFeatures()])) == reference_ids assert tuple(sorted([x.id() for x in self.vlayer.getFeatures(feature_ids)])) == reference_ids assert self.vlayer.featureCount() == len(reference_ids) def tearDown(self): QgsProject.instance().addMapLayer(self.vlayer) QgsProject.instance().removeMapLayer(self.vlayer.id()) super(self.__class__, self).tearDown()
class TestVectorlayer(utils_for_tests.MidvattenTestSpatialiteDbSv): @mock.patch('db_utils.QgsProject.instance', utils_for_tests.MidvattenTestSpatialiteNotCreated. mock_instance_settings_database) def create_vlayer(self, no_print=False): self.qgs = QgsApplication([], True) self.qgs.initQgis() dbconnection = db_utils.DbConnectionManager() uri = dbconnection.uri uri.setDataSource('', 'obs_points', 'geometry', '', 'obsid') dbtype = db_utils.get_dbtype(dbconnection.dbtype) self.vlayer = QgsVectorLayer(uri.uri(), 'TestLayer', dbtype) features = self.vlayer.getFeatures() feature_ids = [feature.id() for feature in features] if not no_print: print("1. Valid vlayer '{}'".format(self.vlayer.isValid())) print("2. feature_ids: " + str(feature_ids)) print("5. QgsVectorLayer.getFeature(): " + str([self.vlayer.getFeature(x).id() for x in feature_ids])) print("6. QgsVectorLayer.getFeature() type: " + str( [str(type(self.vlayer.getFeature(x))) for x in feature_ids])) print("7. QgsVectorLayer.getFeatures(): " + str([x.id() for x in self.vlayer.getFeatures(feature_ids)])) print("8. QgsVectorLayer.featureCount(): " + str(self.vlayer.featureCount())) def select_features(self, feature_ids=None, no_print=True): if feature_ids is None: features = self.vlayer.getFeatures() feature_ids = [feature.id() for feature in features] self.vlayer.selectByIds(feature_ids) if not no_print: print("3. QgsVectorLayer.selectedFeatureIds: " + str(self.vlayer.selectedFeatureIds())) print("4. QgsVectorLayer.getSelectedFeatures: " + str([x.id() for x in self.vlayer.getSelectedFeatures()])) @mock.patch('midvatten_utils.MessagebarAndLog') @mock.patch('stratigraphy.utils.pop_up_info', autospec=True) @mock.patch('db_utils.QgsProject.instance', utils_for_tests.MidvattenTestSpatialiteNotCreated. mock_instance_settings_database) def test_vlayer(self, mock_skippopup, mock_messagebar): """ :param mock_skippopup: :param mock_messagebar: :return: """ for obsid in [1, 2, 3]: db_utils.sql_alter_db( '''INSERT INTO obs_points (obsid) VALUES ({})'''.format( str(obsid))) self.create_vlayer() self.select_features() feature_ids = [feature.id() for feature in self.vlayer.getFeatures()] reference_ids = (1, 2, 3) assert self.vlayer.isValid() assert len(feature_ids) == len(reference_ids) assert tuple(feature_ids) == reference_ids assert tuple(sorted([x for x in self.vlayer.selectedFeatureIds() ])) == reference_ids assert tuple( sorted([x.id() for x in self.vlayer.getSelectedFeatures() ])) == reference_ids assert tuple( sorted([x.id() for x in self.vlayer.getFeatures(feature_ids) ])) == reference_ids assert self.vlayer.featureCount() == 3 @mock.patch('midvatten_utils.MessagebarAndLog') @mock.patch('stratigraphy.utils.pop_up_info', autospec=True) @mock.patch('db_utils.QgsProject.instance', utils_for_tests.MidvattenTestSpatialiteNotCreated. mock_instance_settings_database) def test_vlayer_other_ints_ids(self, mock_skippopup, mock_messagebar): """ :param mock_skippopup: :param mock_messagebar: :return: """ for obsid in [4, 5, 6]: db_utils.sql_alter_db( '''INSERT INTO obs_points (obsid) VALUES ({})'''.format( str(obsid))) self.create_vlayer() self.select_features() feature_ids = [feature.id() for feature in self.vlayer.getFeatures()] reference_ids = (1, 2, 3) assert self.vlayer.isValid() assert len(feature_ids) == len(reference_ids) assert tuple(feature_ids) == reference_ids assert tuple(sorted([x for x in self.vlayer.selectedFeatureIds() ])) == reference_ids assert tuple( sorted([x.id() for x in self.vlayer.getSelectedFeatures() ])) == reference_ids assert tuple( sorted([x.id() for x in self.vlayer.getFeatures(feature_ids) ])) == reference_ids assert self.vlayer.featureCount() == 3 @mock.patch('midvatten_utils.MessagebarAndLog') @mock.patch('stratigraphy.utils.pop_up_info', autospec=True) @mock.patch('db_utils.QgsProject.instance', utils_for_tests.MidvattenTestSpatialiteNotCreated. mock_instance_settings_database) def test_vlayer_strings(self, mock_skippopup, mock_messagebar): """ :param mock_skippopup: :param mock_messagebar: :return: """ for obsid in ['A', 'b', 'c1']: db_utils.sql_alter_db( '''INSERT INTO obs_points (obsid) VALUES ('{}')'''.format( str(obsid))) self.create_vlayer() self.select_features() feature_ids = [feature.id() for feature in self.vlayer.getFeatures()] reference_ids = (1, 2, 3) assert self.vlayer.isValid() assert len(feature_ids) == len(reference_ids) assert tuple(feature_ids) == reference_ids assert tuple(sorted([x for x in self.vlayer.selectedFeatureIds() ])) == reference_ids assert tuple( sorted([x.id() for x in self.vlayer.getSelectedFeatures() ])) == reference_ids assert tuple( sorted([x.id() for x in self.vlayer.getFeatures(feature_ids) ])) == reference_ids assert self.vlayer.featureCount() == 3 @mock.patch('midvatten_utils.MessagebarAndLog') @mock.patch('stratigraphy.utils.pop_up_info', autospec=True) @mock.patch('db_utils.QgsProject.instance', utils_for_tests.MidvattenTestSpatialiteNotCreated. mock_instance_settings_database) def test_vlayer_1000_features(self, mock_skippopup, mock_messagebar): """ :param mock_skippopup: :param mock_messagebar: :return: """ dbconnection = db_utils.DbConnectionManager() cur = dbconnection.cursor cur.execute('''BEGIN TRANSACTION;''') for obsid in range(1000): cur.execute( '''INSERT INTO obs_points (obsid) VALUES ('{}');'''.format( str(obsid))) cur.execute('''END TRANSACTION;''') self.create_vlayer(no_print=True) self.select_features(no_print=True) feature_ids = [feature.id() for feature in self.vlayer.getFeatures()] reference_ids = tuple(range(1, 1001)) print("First 10 ids: " + str(feature_ids[:10])) print("Last 10 ids: " + str(feature_ids[-10:])) print("First 10 reference_ids: " + str(reference_ids[:10])) print("Last 10 reference_ids: " + str(reference_ids[-10:])) assert self.vlayer.isValid() assert len(feature_ids) == len(reference_ids) assert tuple(feature_ids) == reference_ids assert tuple(sorted([x for x in self.vlayer.selectedFeatureIds() ])) == reference_ids assert tuple( sorted([x.id() for x in self.vlayer.getSelectedFeatures() ])) == reference_ids assert tuple( sorted([x.id() for x in self.vlayer.getFeatures(feature_ids) ])) == reference_ids assert self.vlayer.featureCount() == len(reference_ids) @mock.patch('midvatten_utils.MessagebarAndLog') @mock.patch('stratigraphy.utils.pop_up_info', autospec=True) @mock.patch('db_utils.QgsProject.instance', utils_for_tests.MidvattenTestSpatialiteNotCreated. mock_instance_settings_database) def test_vlayer_2000_ints(self, mock_skippopup, mock_messagebar): """ :param mock_skippopup: :param mock_messagebar: :return: """ dbconnection = db_utils.DbConnectionManager() cur = dbconnection.cursor cur.execute('''BEGIN TRANSACTION;''') for obsid in range(2000): cur.execute( '''INSERT INTO obs_points (obsid) VALUES ('{}');'''.format( str(obsid))) cur.execute('''END TRANSACTION;''') self.create_vlayer(no_print=True) self.select_features(no_print=True) feature_ids = [feature.id() for feature in self.vlayer.getFeatures()] reference_ids = tuple(range(1, 2001)) print("First 10 ids: " + str(feature_ids[:10])) print("Last 10 ids: " + str(feature_ids[-10:])) print("First 10 reference_ids: " + str(reference_ids[:10])) print("Last 10 reference_ids: " + str(reference_ids[-10:])) assert self.vlayer.isValid() assert len(feature_ids) == len(reference_ids) assert tuple(feature_ids) == reference_ids assert tuple(sorted([x for x in self.vlayer.selectedFeatureIds() ])) == reference_ids assert tuple( sorted([x.id() for x in self.vlayer.getSelectedFeatures() ])) == reference_ids assert tuple( sorted([x.id() for x in self.vlayer.getFeatures(feature_ids) ])) == reference_ids assert self.vlayer.featureCount() == len(reference_ids) @mock.patch('midvatten_utils.MessagebarAndLog') @mock.patch('stratigraphy.utils.pop_up_info', autospec=True) @mock.patch('db_utils.QgsProject.instance', utils_for_tests.MidvattenTestSpatialiteNotCreated. mock_instance_settings_database) def test_vlayer_2000_strings(self, mock_skippopup, mock_messagebar): """ :param mock_skippopup: :param mock_messagebar: :return: """ dbconnection = db_utils.DbConnectionManager() cur = dbconnection.cursor obsids = [ letter + str(_int) for letter in string.ascii_letters for _int in range(80) ] cur.execute('''BEGIN TRANSACTION;''') for obsid in obsids: cur.execute( '''INSERT INTO obs_points (obsid) VALUES ('{}');'''.format( str(obsid))) cur.execute('''END TRANSACTION;''') dbconnection.commit() self.create_vlayer(no_print=True) self.select_features(no_print=True) feature_ids = [feature.id() for feature in self.vlayer.getFeatures()] reference_ids = tuple(range(1, len(obsids) + 1)) print("First 10 ids: " + str(feature_ids[:10])) print("Last 10 ids: " + str(feature_ids[-10:])) print("First 10 reference_ids: " + str(reference_ids[:10])) print("Last 10 reference_ids: " + str(reference_ids[-10:])) print(str(self.vlayer.featureCount())) assert self.vlayer.isValid() assert len(feature_ids) == len(reference_ids) assert tuple(feature_ids) == reference_ids assert tuple(sorted([x for x in self.vlayer.selectedFeatureIds() ])) == reference_ids assert tuple( sorted([x.id() for x in self.vlayer.getSelectedFeatures() ])) == reference_ids assert tuple( sorted([x.id() for x in self.vlayer.getFeatures(feature_ids) ])) == reference_ids assert self.vlayer.featureCount() == len(reference_ids) def tearDown(self): QgsProject.instance().addMapLayer(self.vlayer) QgsProject.instance().removeMapLayer(self.vlayer.id()) super(self.__class__, self).tearDown()