def testNoSliverPolygons(self): # create a layer with some polygons that will be used as a source for "avoid intersections" l = QgsVectorLayer('MultiPolygon', 'test_layer', 'memory') assert l.isValid() QgsProject.instance().addMapLayer(l) QgsProject.instance().writeEntry("Digitizing", "/AvoidIntersectionsList", [l.id()]) features = [] for i, wkt in enumerate(feat_wkt): f = QgsFeature(i + 1) f.setGeometry(QgsGeometry.fromWkt(wkt)) features.append(f) l.dataProvider().addFeatures(features) assert l.pendingFeatureCount() == 7 # create a geometry and remove its intersections with other geometries g = QgsGeometry.fromWkt(newg_wkt) assert g.avoidIntersections() == 0 # the resulting multi-polygon must have exactly three parts # (in QGIS 2.0 it has one more tiny part that appears at the border between two of the original polygons) mpg = g.asMultiPolygon() assert len(mpg) == 3
def createLayer(cls): vl = QgsVectorLayer( "Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&key=pk", "test", "memory", ) assert vl.isValid() f1 = QgsFeature() f1.setAttributes([5, -200, NULL, "NuLl", "5"]) f1.setGeometry(QgsGeometry.fromWkt("Point (-71.123 78.23)")) f2 = QgsFeature() f2.setAttributes([3, 300, "Pear", "PEaR", "3"]) f3 = QgsFeature() f3.setAttributes([1, 100, "Orange", "oranGe", "1"]) f3.setGeometry(QgsGeometry.fromWkt("Point (-70.332 66.33)")) f4 = QgsFeature() f4.setAttributes([2, 200, "Apple", "Apple", "2"]) f4.setGeometry(QgsGeometry.fromWkt("Point (-68.2 70.8)")) f5 = QgsFeature() f5.setAttributes([4, 400, "Honey", "Honey", "4"]) f5.setGeometry(QgsGeometry.fromWkt("Point (-65.32 78.3)")) vl.dataProvider().addFeatures([f1, f2, f3, f4, f5]) return vl
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_Join(self): l1 = QgsVectorLayer(os.path.join(self.testDataDir, "points.shp"), "points", "ogr", False) self.assertEqual(l1.isValid(), True) QgsProject.instance().addMapLayer(l1) l2 = QgsVectorLayer(os.path.join(self.testDataDir, "points_relations.shp"), "points_relations", "ogr", False) self.assertEqual(l2.isValid(), True) QgsProject.instance().addMapLayer(l2) ref_sum = sum(f.attributes()[1] for f in l2.getFeatures()) # use a temporary file query = toPercent( "select id,Pilots,vtab1.geometry from vtab1,vtab2 where intersects(vtab1.geometry,vtab2.geometry)" ) l3 = QgsVectorLayer( "?layer_ref=%s&layer_ref=%s&uid=id&query=%s&geometry=geometry:1:4326" % (l1.id(), l2.id(), query), "vtab", "virtual", False, ) self.assertEqual(l3.isValid(), True) self.assertEqual(l3.dataProvider().wkbType(), 1) self.assertEqual(l3.dataProvider().fields().count(), 2) ref_sum2 = sum(f.id() for f in l3.getFeatures()) self.assertEqual(ref_sum, ref_sum2) QgsProject.instance().removeMapLayer(l1) QgsProject.instance().removeMapLayer(l2)
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 createLayer(cls): vl = QgsVectorLayer( 'Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&key=pk', 'test', 'pythonprovider') assert (vl.isValid()) f1 = QgsFeature() f1.setAttributes([5, -200, NULL, 'NuLl', '5']) f1.setGeometry(QgsGeometry.fromWkt('Point (-71.123 78.23)')) f2 = QgsFeature() f2.setAttributes([3, 300, 'Pear', 'PEaR', '3']) f3 = QgsFeature() f3.setAttributes([1, 100, 'Orange', 'oranGe', '1']) f3.setGeometry(QgsGeometry.fromWkt('Point (-70.332 66.33)')) f4 = QgsFeature() f4.setAttributes([2, 200, 'Apple', 'Apple', '2']) f4.setGeometry(QgsGeometry.fromWkt('Point (-68.2 70.8)')) f5 = QgsFeature() f5.setAttributes([4, 400, 'Honey', 'Honey', '4']) f5.setGeometry(QgsGeometry.fromWkt('Point (-65.32 78.3)')) vl.dataProvider().addFeatures([f1, f2, f3, f4, f5]) return vl
def testStringWithMaxLen(self): """ tests that text edit wrappers correctly handle string fields with a maximum length """ layer = QgsVectorLayer("none?field=fldint:integer", "layer", "memory") assert layer.isValid() layer.dataProvider().addAttributes([QgsField('max', QVariant.String, 'string', 10), QgsField('nomax', QVariant.String, 'string', 0)]) layer.updateFields() QgsMapLayerRegistry.instance().addMapLayer(layer) reg = QgsEditorWidgetRegistry.instance() config = {'IsMultiline': 'True'} # first test for field without character limit editor = QTextEdit() editor.setPlainText('this_is_a_long_string') w = reg.create('TextEdit', layer, 2, config, editor, None) self.assertEqual(w.value(), 'this_is_a_long_string') # next test for field with character limit editor = QTextEdit() editor.setPlainText('this_is_a_long_string') w = reg.create('TextEdit', layer, 1, config, editor, None) self.assertEqual(w.value(), 'this_is_a_') QgsMapLayerRegistry.instance().removeAllMapLayers()
def test_representValue(self): QgsSettings().setValue("qgis/nullValue", "NULL") layer = QgsVectorLayer("none?field=number1:integer&field=number2:double&field=text1:string&field=number3:integer&field=number4:double&field=text2:string", "layer", "memory") self.assertTrue(layer.isValid()) QgsProject.instance().addMapLayer(layer) f = QgsFeature() f.setAttributes([2, 2.5, 'NULL', None, None, None]) layer.dataProvider().addFeatures([f]) fieldFormatter = QgsValueMapFieldFormatter() # Tests with different value types occurring in the value map config = {'map': {'two': '2', 'twoandhalf': '2.5', 'NULL text': 'NULL', 'nothing': self.VALUEMAP_NULL_TEXT}} self.assertEqual(fieldFormatter.representValue(layer, 0, config, None, 2), 'two') self.assertEqual(fieldFormatter.representValue(layer, 1, config, None, 2.5), 'twoandhalf') self.assertEqual(fieldFormatter.representValue(layer, 2, config, None, 'NULL'), 'NULL text') # Tests with null values of different types, if value map contains null self.assertEqual(fieldFormatter.representValue(layer, 3, config, None, None), 'nothing') self.assertEqual(fieldFormatter.representValue(layer, 4, config, None, None), 'nothing') self.assertEqual(fieldFormatter.representValue(layer, 5, config, None, None), 'nothing') # Tests with fallback display for different value types config = {} self.assertEqual(fieldFormatter.representValue(layer, 0, config, None, 2), '(2)') self.assertEqual(fieldFormatter.representValue(layer, 1, config, None, 2.5), '(2.50000)') self.assertEqual(fieldFormatter.representValue(layer, 2, config, None, 'NULL'), '(NULL)') # Tests with fallback display for null in different types of fields self.assertEqual(fieldFormatter.representValue(layer, 3, config, None, None), '(NULL)') self.assertEqual(fieldFormatter.representValue(layer, 4, config, None, None), '(NULL)') self.assertEqual(fieldFormatter.representValue(layer, 5, config, None, None), '(NULL)') QgsProject.instance().removeAllMapLayers()
def testInteger64WriteTabfile(self): """Check writing Integer64 fields to an MapInfo tabfile (which does not support that type).""" ml = QgsVectorLayer(("Point?crs=epsg:4326&field=int8:int8"), "test", "memory") self.assertIsNotNone(ml, "Provider not initialized") self.assertTrue(ml.isValid(), "Source layer not valid") provider = ml.dataProvider() self.assertIsNotNone(provider) ft = QgsFeature() ft.setAttributes([2123456789]) res, features = provider.addFeatures([ft]) self.assertTrue(res) self.assertTrue(features) dest_file_name = os.path.join(str(QDir.tempPath()), "integer64.tab") crs = QgsCoordinateReferenceSystem() crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId) write_result = QgsVectorFileWriter.writeAsVectorFormat(ml, dest_file_name, "utf-8", crs, "MapInfo File") self.assertEqual(write_result, QgsVectorFileWriter.NoError) # Open result and check created_layer = QgsVectorLayer("{}|layerid=0".format(dest_file_name), "test", "ogr") fields = created_layer.dataProvider().fields() self.assertEqual(fields.at(fields.indexFromName("int8")).type(), QVariant.Double) f = next(created_layer.getFeatures(QgsFeatureRequest())) int8_idx = created_layer.fields().lookupField("int8") self.assertEqual(f.attributes()[int8_idx], 2123456789)
def test_ExpressionFieldEllipsoidLengthCalculation(self): #create a temporary layer temp_layer = QgsVectorLayer("LineString?crs=epsg:3111&field=pk:int", "vl", "memory") self.assertTrue(temp_layer.isValid()) f1 = QgsFeature(temp_layer.dataProvider().fields(), 1) f1.setAttribute("pk", 1) f1.setGeometry(QgsGeometry.fromPolyline([QgsPoint(2484588, 2425722), QgsPoint(2482767, 2398853)])) temp_layer.dataProvider().addFeatures([f1]) # set project CRS and ellipsoid srs = QgsCoordinateReferenceSystem(3111, QgsCoordinateReferenceSystem.EpsgCrsId) QgsProject.instance().writeEntry("SpatialRefSys", "/ProjectCRSProj4String", srs.toProj4()) QgsProject.instance().writeEntry("SpatialRefSys", "/ProjectCRSID", srs.srsid()) QgsProject.instance().writeEntry("SpatialRefSys", "/ProjectCrs", srs.authid()) QgsProject.instance().writeEntry("Measure", "/Ellipsoid", "WGS84") QgsProject.instance().writeEntry("Measurement", "/DistanceUnits", QgsUnitTypes.encodeUnit(QGis.Meters)) idx = temp_layer.addExpressionField('$length', QgsField('length', QVariant.Double)) # NOQA # check value f = temp_layer.getFeatures().next() expected = 26932.156 self.assertAlmostEqual(f['length'], expected, 3) # change project length unit, check calculation respects unit QgsProject.instance().writeEntry("Measurement", "/DistanceUnits", QgsUnitTypes.encodeUnit(QGis.Feet)) f = temp_layer.getFeatures().next() expected = 88360.0918635 self.assertAlmostEqual(f['length'], expected, 3)
def test_ExpressionFieldEllipsoidAreaCalculation(self): #create a temporary layer temp_layer = QgsVectorLayer("Polygon?crs=epsg:3111&field=pk:int", "vl", "memory") self.assertTrue(temp_layer.isValid()) f1 = QgsFeature(temp_layer.dataProvider().fields(), 1) f1.setAttribute("pk", 1) f1.setGeometry(QgsGeometry.fromPolygon([[QgsPoint(2484588, 2425722), QgsPoint(2482767, 2398853), QgsPoint(2520109, 2397715), QgsPoint(2520792, 2425494), QgsPoint(2484588, 2425722)]])) temp_layer.dataProvider().addFeatures([f1]) # set project CRS and ellipsoid srs = QgsCoordinateReferenceSystem(3111, QgsCoordinateReferenceSystem.EpsgCrsId) QgsProject.instance().writeEntry("SpatialRefSys", "/ProjectCRSProj4String", srs.toProj4()) QgsProject.instance().writeEntry("SpatialRefSys", "/ProjectCRSID", srs.srsid()) QgsProject.instance().writeEntry("SpatialRefSys", "/ProjectCrs", srs.authid()) QgsProject.instance().writeEntry("Measure", "/Ellipsoid", "WGS84") QgsProject.instance().writeEntry("Measurement", "/AreaUnits", QgsUnitTypes.encodeUnit(QgsUnitTypes.SquareMeters)) idx = temp_layer.addExpressionField('$area', QgsField('area', QVariant.Double)) # NOQA # check value f = temp_layer.getFeatures().next() expected = 1009089817.0 self.assertAlmostEqual(f['area'], expected, delta=1.0) # change project area unit, check calculation respects unit QgsProject.instance().writeEntry("Measurement", "/AreaUnits", QgsUnitTypes.encodeUnit(QgsUnitTypes.SquareMiles)) f = temp_layer.getFeatures().next() expected = 389.6117565069 self.assertAlmostEqual(f['area'], expected, 3)
def _create_points(self): """Create points for testing""" point_layer = QgsVectorLayer('Point?crs=EPSG:4326', 'points', 'memory') point_provider = point_layer.dataProvider() point_provider.addAttributes([QgsField('X', QVariant.Double)]) point_provider.addAttributes([QgsField('Y', QVariant.Double)]) x_index = point_provider.fieldNameIndex('X') y_index = point_provider.fieldNameIndex('Y') point_layer.startEditing() for x in [10.0, 20.0, 30.0]: for y in [10.0, 20.0, 30.0]: feature = QgsFeature() feature.initAttributes(2) feature.setAttribute(x_index, x) feature.setAttribute(y_index, y) # noinspection PyCallByClass geom = QgsGeometry.fromPoint(QgsPoint(x, y)) feature.setGeometry(geom) _ = point_layer.dataProvider().addFeatures([feature]) point_layer.commitChanges() return point_layer
def test_create_layer(self): """Test create layer work""" # Lines line_layer = QgsVectorLayer( self.line_before + '.shp', 'test', 'ogr') new_layer = create_layer(line_layer) self.assertEquals(new_layer.geometryType(), line_layer.geometryType()) self.assertEquals(new_layer.crs(), line_layer.crs()) fields = line_layer.dataProvider().fields() new_fields = new_layer.dataProvider().fields() self.assertEquals(new_fields.toList(), fields.toList()) # Polygon polygon_layer = QgsVectorLayer( self.polygon_base + '.shp', 'test', 'ogr') new_layer = create_layer(polygon_layer) self.assertEquals( new_layer.geometryType(), polygon_layer.geometryType() ) self.assertEquals(new_layer.crs(), polygon_layer.crs()) fields = polygon_layer.dataProvider().fields() new_fields = new_layer.dataProvider().fields() self.assertEquals(new_fields.toList(), fields.toList())
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 testNotNullConstraint(self): """ test detection of not null constraint on OGR layer """ tmpfile = os.path.join(self.basetestpath, 'testNotNullConstraint.sqlite') ds = ogr.GetDriverByName('SQLite').CreateDataSource(tmpfile) lyr = ds.CreateLayer('test', geom_type=ogr.wkbPoint, options=['FID=fid']) lyr.CreateField(ogr.FieldDefn('field1', ogr.OFTInteger)) fld2 = ogr.FieldDefn('field2', ogr.OFTInteger) fld2.SetNullable(False) lyr.CreateField(fld2) ds = None vl = QgsVectorLayer('{}'.format(tmpfile), 'test', 'ogr') self.assertTrue(vl.isValid()) # test some bad indexes self.assertEqual(vl.dataProvider().fieldConstraints(-1), QgsFieldConstraints.Constraints()) self.assertEqual(vl.dataProvider().fieldConstraints(1001), QgsFieldConstraints.Constraints()) self.assertFalse(vl.dataProvider().fieldConstraints(0) & QgsFieldConstraints.ConstraintNotNull) self.assertFalse(vl.dataProvider().fieldConstraints(1) & QgsFieldConstraints.ConstraintNotNull) self.assertTrue(vl.dataProvider().fieldConstraints(2) & QgsFieldConstraints.ConstraintNotNull) # test that constraints have been saved to fields correctly fields = vl.fields() self.assertFalse(fields.at(0).constraints().constraints() & QgsFieldConstraints.ConstraintNotNull) self.assertFalse(fields.at(1).constraints().constraints() & QgsFieldConstraints.ConstraintNotNull) self.assertTrue(fields.at(2).constraints().constraints() & QgsFieldConstraints.ConstraintNotNull) self.assertEqual(fields.at(2).constraints().constraintOrigin(QgsFieldConstraints.ConstraintNotNull), QgsFieldConstraints.ConstraintOriginProvider)
def testEditGeoJsonAddFieldAndThenAddFeatures(self): """ Test bugfix of https://issues.qgis.org/issues/18596 (adding a new field)""" datasource = os.path.join(self.basetestpath, 'testEditGeoJsonAddField.json') with open(datasource, 'wt') as f: f.write("""{ "type": "FeatureCollection", "features": [ { "type": "Feature", "properties": { "x": 1 }, "geometry": { "type": "Point", "coordinates": [ 0, 0 ] } } ] }""") vl = QgsVectorLayer(datasource, 'test', 'ogr') self.assertTrue(vl.isValid()) self.assertTrue(vl.startEditing()) self.assertTrue(vl.addAttribute(QgsField('strfield', QVariant.String))) self.assertTrue(vl.commitChanges()) self.assertEqual(len(vl.dataProvider().fields()), 1 + 1) self.assertEqual([f.name() for f in vl.dataProvider().fields()], ['x', 'strfield']) f = QgsFeature() self.assertTrue(vl.getFeatures(QgsFeatureRequest()).nextFeature(f)) self.assertIsNone(f['strfield']) self.assertEqual([field.name() for field in f.fields()], ['x', 'strfield']) self.assertTrue(vl.startEditing()) vl.changeAttributeValue(f.id(), 1, 'x') self.assertTrue(vl.commitChanges()) f = QgsFeature() self.assertTrue(vl.getFeatures(QgsFeatureRequest()).nextFeature(f)) self.assertEqual(f['strfield'], 'x') self.assertEqual([field.name() for field in f.fields()], ['x', 'strfield']) # Completely reload file vl = QgsVectorLayer(datasource, 'test', 'ogr') self.assertEqual(len(vl.fields()), 2)
def test_geometryTypes(self): geo = [(1, "POINT", "(0 0)"), (2, "LINESTRING", "(0 0,1 0)"), (3, "POLYGON", "((0 0,1 0,1 1,0 0))"), (4, "MULTIPOINT", "((1 1))"), (5, "MULTILINESTRING", "((0 0,1 0),(0 1,1 1))"), (6, "MULTIPOLYGON", "(((0 0,1 0,1 1,0 0)),((2 2,3 0,3 3,2 2)))")] for wkb_type, wkt_type, wkt in geo: l = QgsVectorLayer("%s?crs=epsg:4326" % wkt_type, "m1", "memory", False) self.assertEqual(l.isValid(), True) QgsProject.instance().addMapLayer(l) f1 = QgsFeature(1) g = QgsGeometry.fromWkt(wkt_type + wkt) self.assertEqual(g is None, False) f1.setGeometry(g) l.dataProvider().addFeatures([f1]) l2 = QgsVectorLayer("?layer_ref=%s" % l.id(), "vtab", "virtual", False) self.assertEqual(l2.isValid(), True) self.assertEqual(l2.dataProvider().featureCount(), 1) self.assertEqual(l2.dataProvider().wkbType(), wkb_type) QgsProject.instance().removeMapLayer(l.id())
def testNotNullConstraint(self): vl = QgsVectorLayer("dbname=%s table=test_constraints key='id'" % self.dbname, "test_constraints", "spatialite") self.assertTrue(vl.isValid()) self.assertEqual(len(vl.fields()), 5) # test some bad field indexes self.assertEqual(vl.dataProvider().fieldConstraints(-1), QgsFieldConstraints.Constraints()) self.assertEqual(vl.dataProvider().fieldConstraints(1001), QgsFieldConstraints.Constraints()) self.assertTrue(vl.dataProvider().fieldConstraints(0) & QgsFieldConstraints.ConstraintNotNull) self.assertTrue(vl.dataProvider().fieldConstraints(1) & QgsFieldConstraints.ConstraintNotNull) self.assertFalse(vl.dataProvider().fieldConstraints(2) & QgsFieldConstraints.ConstraintNotNull) self.assertFalse(vl.dataProvider().fieldConstraints(3) & QgsFieldConstraints.ConstraintNotNull) self.assertTrue(vl.dataProvider().fieldConstraints(4) & QgsFieldConstraints.ConstraintNotNull) # test that constraints have been saved to fields correctly fields = vl.fields() self.assertTrue(fields.at(0).constraints().constraints() & QgsFieldConstraints.ConstraintNotNull) self.assertEqual(fields.at(0).constraints().constraintOrigin(QgsFieldConstraints.ConstraintNotNull), QgsFieldConstraints.ConstraintOriginProvider) self.assertTrue(fields.at(1).constraints().constraints() & QgsFieldConstraints.ConstraintNotNull) self.assertEqual(fields.at(1).constraints().constraintOrigin(QgsFieldConstraints.ConstraintNotNull), QgsFieldConstraints.ConstraintOriginProvider) self.assertFalse(fields.at(2).constraints().constraints() & QgsFieldConstraints.ConstraintNotNull) self.assertFalse(fields.at(3).constraints().constraints() & QgsFieldConstraints.ConstraintNotNull) self.assertTrue(fields.at(4).constraints().constraints() & QgsFieldConstraints.ConstraintNotNull) self.assertEqual(fields.at(4).constraints().constraintOrigin(QgsFieldConstraints.ConstraintNotNull), QgsFieldConstraints.ConstraintOriginProvider)
def test_case(self): """Test case sensitivity issues""" l = QgsVectorLayer("dbname=%s table='test_n' (geometry) key='id'" % self.dbname, "test_n1", "spatialite") self.assertTrue(l.isValid()) self.assertEqual(l.dataProvider().fields().count(), 2) fields = [f.name() for f in l.dataProvider().fields()] self.assertTrue('Geometry' not in fields)
def testSkipConstraintCheck(self): vl = QgsVectorLayer("dbname=%s table=test_autoincrement" % self.dbname, "test_autoincrement", "spatialite") self.assertTrue(vl.isValid()) self.assertTrue(vl.dataProvider().skipConstraintCheck(0, QgsFieldConstraints.ConstraintUnique, str("Autogenerate"))) self.assertFalse(vl.dataProvider().skipConstraintCheck(0, QgsFieldConstraints.ConstraintUnique, 123))
def testCreateAttributeIndex(self): vl = QgsVectorLayer("dbname=%s table='test_defaults' key='id'" % self.dbname, "test_defaults", "spatialite") self.assertTrue(vl.dataProvider().capabilities() & QgsVectorDataProvider.CreateAttributeIndex) self.assertFalse(vl.dataProvider().createAttributeIndex(-1)) self.assertFalse(vl.dataProvider().createAttributeIndex(100)) self.assertTrue(vl.dataProvider().createAttributeIndex(1)) con = spatialite_connect(self.dbname, isolation_level=None) cur = con.cursor() rs = cur.execute("SELECT * FROM sqlite_master WHERE type='index' AND tbl_name='test_defaults'") res = [row for row in rs] self.assertEqual(len(res), 1) index_name = res[0][1] rs = cur.execute("PRAGMA index_info({})".format(index_name)) res = [row for row in rs] self.assertEqual(len(res), 1) self.assertEqual(res[0][2], 'name') # second index self.assertTrue(vl.dataProvider().createAttributeIndex(2)) rs = cur.execute("SELECT * FROM sqlite_master WHERE type='index' AND tbl_name='test_defaults'") res = [row for row in rs] self.assertEqual(len(res), 2) indexed_columns = [] for row in res: index_name = row[1] rs = cur.execute("PRAGMA index_info({})".format(index_name)) res = [row for row in rs] self.assertEqual(len(res), 1) indexed_columns.append(res[0][2]) self.assertEqual(set(indexed_columns), set(['name', 'number'])) con.close()
def testNotify(self): vl0 = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'pk\' srid=4326 type=POLYGON table="qgis_test"."some_poly_data" (geom) sql=', 'test', 'postgres') vl0.dataProvider().setListening(True) class Notified(QObject): def __init__(self): super(Notified, self).__init__() self.received = "" def receive(self, msg): self.received = msg notified = Notified() vl0.dataProvider().notify.connect(notified.receive) vl0.dataProvider().setListening(True) cur = self.con.cursor() ok = False start = time.time() while True: cur.execute("NOTIFY qgis, 'my message'") self.con.commit() QGISAPP.processEvents() if notified.received == "my message": ok = True break if (time.time() - start) > 5: # timeout break vl0.dataProvider().notify.disconnect(notified.receive) vl0.dataProvider().setListening(False) self.assertTrue(ok)
def add_flooded_field(self, shapefile_path): """Create the layer from the local shp adding the flooded field. .. versionadded:: 3.3 Use this method to add a calculated field to a shapefile. The shapefile should have a field called 'count' containing the number of flood reports for the field. The field values will be set to 0 if the count field is < 1, otherwise it will be set to 1. :param shapefile_path: Path to the shapefile that will have the flooded field added. :type shapefile_path: basestring :return: A vector layer with the flooded field added. :rtype: QgsVectorLayer """ layer = QgsVectorLayer( shapefile_path, self.tr('Jakarta Floods'), 'ogr') # Add a calculated field indicating if a poly is flooded or not # from PyQt4.QtCore import QVariant layer.startEditing() field = QgsField('flooded', QVariant.Int) layer.dataProvider().addAttributes([field]) layer.commitChanges() layer.startEditing() idx = layer.fieldNameIndex('flooded') expression = QgsExpression('state > 0') expression.prepare(layer.pendingFields()) for feature in layer.getFeatures(): feature[idx] = expression.evaluate(feature) layer.updateFeature(feature) layer.commitChanges() return layer
def testUpdatedFields(self): """Test when referenced layer update its fields https://issues.qgis.org/issues/20893 """ ml = QgsVectorLayer("Point?srid=EPSG:4326&field=a:int", "mem", "memory") self.assertEqual(ml.isValid(), True) QgsProject.instance().addMapLayer(ml) ml.startEditing() f1 = QgsFeature(ml.fields()) f1.setGeometry(QgsGeometry.fromWkt('POINT(2 3)')) ml.addFeatures([f1]) ml.commitChanges() vl = QgsVectorLayer("?query=select a, geometry from mem", "vl", "virtual") self.assertEqual(vl.isValid(), True) # add one more field ml.dataProvider().addAttributes([QgsField('newfield', QVariant.Int)]) ml.updateFields() self.assertEqual(ml.featureCount(), vl.featureCount()) self.assertEqual(vl.fields().count(), 1) geometry = next(vl.getFeatures()).geometry() self.assertTrue(geometry) point = geometry.asPoint() self.assertEqual(point.x(), 2) self.assertEqual(point.y(), 3) QgsProject.instance().removeMapLayer(ml)
def testUniqueConstraint(self): vl = QgsVectorLayer('%s table="qgis_test"."constraints" sql=' % (self.dbconn), "constraints", "postgres") self.assertTrue(vl.isValid()) self.assertEqual(len(vl.fields()), 4) # test some bad field indexes self.assertEqual(vl.dataProvider().fieldConstraints(-1), QgsFieldConstraints.Constraints()) self.assertEqual(vl.dataProvider().fieldConstraints(1001), QgsFieldConstraints.Constraints()) self.assertTrue(vl.dataProvider().fieldConstraints(0) & QgsFieldConstraints.ConstraintUnique) self.assertTrue(vl.dataProvider().fieldConstraints(1) & QgsFieldConstraints.ConstraintUnique) self.assertTrue(vl.dataProvider().fieldConstraints(2) & QgsFieldConstraints.ConstraintUnique) self.assertFalse(vl.dataProvider().fieldConstraints(3) & QgsFieldConstraints.ConstraintUnique) # test that constraints have been saved to fields correctly fields = vl.fields() self.assertTrue(fields.at(0).constraints().constraints() & QgsFieldConstraints.ConstraintUnique) self.assertEqual( fields.at(0).constraints().constraintOrigin(QgsFieldConstraints.ConstraintUnique), QgsFieldConstraints.ConstraintOriginProvider, ) self.assertTrue(fields.at(1).constraints().constraints() & QgsFieldConstraints.ConstraintUnique) self.assertEqual( fields.at(1).constraints().constraintOrigin(QgsFieldConstraints.ConstraintUnique), QgsFieldConstraints.ConstraintOriginProvider, ) self.assertTrue(fields.at(2).constraints().constraints() & QgsFieldConstraints.ConstraintUnique) self.assertEqual( fields.at(2).constraints().constraintOrigin(QgsFieldConstraints.ConstraintUnique), QgsFieldConstraints.ConstraintOriginProvider, ) self.assertFalse(fields.at(3).constraints().constraints() & QgsFieldConstraints.ConstraintUnique)
def testSubSetStringEditable_bug17795_but_with_modified_behavior(self): """Test that a layer is editable after setting a subset""" tmpfile = os.path.join(self.basetestpath, 'testSubSetStringEditable_bug17795.gpkg') shutil.copy(TEST_DATA_DIR + '/' + 'provider/bug_17795.gpkg', tmpfile) isEditable = QgsVectorDataProvider.ChangeAttributeValues testPath = tmpfile + '|layername=bug_17795' vl = QgsVectorLayer(testPath, 'subset_test', 'ogr') self.assertTrue(vl.isValid()) self.assertTrue(vl.dataProvider().capabilities() & isEditable) vl = QgsVectorLayer(testPath, 'subset_test', 'ogr') vl.setSubsetString('') self.assertTrue(vl.isValid()) self.assertTrue(vl.dataProvider().capabilities() & isEditable) vl = QgsVectorLayer(testPath, 'subset_test', 'ogr') vl.setSubsetString('"category" = \'one\'') self.assertTrue(vl.isValid()) self.assertTrue(vl.dataProvider().capabilities() & isEditable) vl.setSubsetString('') self.assertTrue(vl.dataProvider().capabilities() & isEditable)
def newmemorylayer(): uri = "point?crs=epsg:4326&field=id:integer" layer = QgsVectorLayer(uri, "testlayer", "memory") print QgsProviderRegistry.instance().pluginList() print layer.dataProvider() print layer.dataProvider().errors() return layer
def getSource(self): # create temporary table for edit tests self.execSQLCommand('DROP TABLE IF EXISTS qgis_test.edit_data') self.execSQLCommand( """CREATE TABLE qgis_test.edit_data (pk INTEGER PRIMARY KEY,cnt integer, name nvarchar(max), name2 nvarchar(max), num_char nvarchar(max), geom geometry)""") vl = QgsVectorLayer( self.dbconn + ' sslmode=disable key=\'pk\' srid=4326 type=POINT table="qgis_test"."edit_data" (geom) sql=', 'test', 'mssql') self.assertTrue(vl.isValid(), vl.dataProvider().error().message()) f1 = QgsFeature() f1.setAttributes([5, -200, NULL, 'NuLl', '5']) f1.setGeometry(QgsGeometry.fromWkt('Point (-71.123 78.23)')) f2 = QgsFeature() f2.setAttributes([3, 300, 'Pear', 'PEaR', '3']) f3 = QgsFeature() f3.setAttributes([1, 100, 'Orange', 'oranGe', '1']) f3.setGeometry(QgsGeometry.fromWkt('Point (-70.332 66.33)')) f4 = QgsFeature() f4.setAttributes([2, 200, 'Apple', 'Apple', '2']) f4.setGeometry(QgsGeometry.fromWkt('Point (-68.2 70.8)')) f5 = QgsFeature() f5.setAttributes([4, 400, 'Honey', 'Honey', '4']) f5.setGeometry(QgsGeometry.fromWkt('Point (-65.32 78.3)')) self.assertTrue(vl.dataProvider().addFeatures([f1, f2, f3, f4, f5])) return vl
def pixels_to_points( raster, threshold_min=0.0, threshold_max=float('inf'), field_name='value'): """ Convert raster to points. Areas (pixels) with threshold_min < pixel_values < threshold_max will be converted to point layer. :param raster: Raster layer :type raster: QgsRasterLayer :param threshold_min: Value that splits raster to flooded or not flooded. :type threshold_min: float :param threshold_max: Value that splits raster to flooded or not flooded. :type threshold_max: float :param field_name: Field name to store pixel value. :type field_name: string :returns: Point layer of pixels :rtype: QgsVectorLayer """ if raster.bandCount() != 1: msg = "Current version allows using of one-band raster only" raise NotImplementedError(msg) extent = raster.extent() width, height = raster.width(), raster.height() provider = raster.dataProvider() block = provider.block(1, extent, width, height) # Create points crs = raster.crs().toWkt() point_layer = QgsVectorLayer('Point?crs=' + crs, 'pixels', 'memory') point_provider = point_layer.dataProvider() point_provider.addAttributes([QgsField(field_name, QVariant.Double)]) field_index = point_provider.fieldNameIndex(field_name) attribute_count = 1 point_layer.startEditing() for row in range(height): for col in range(width): value = block.value(row, col) x, y = _get_pixel_coordinates(extent, width, height, row, col) # noinspection PyCallByClass,PyTypeChecker,PyArgumentList geom = QgsGeometry.fromPoint(QgsPoint(x, y)) if threshold_min < value < threshold_max: feature = QgsFeature() feature.initAttributes(attribute_count) feature.setAttribute(field_index, value) feature.setGeometry(geom) _ = point_layer.dataProvider().addFeatures([feature]) point_layer.commitChanges() return point_layer
def testDateTimeWriteShapefile(self): """Check writing date and time fields to an ESRI shapefile.""" ml = QgsVectorLayer( ('Point?crs=epsg:4326&field=id:int&' 'field=date_f:date&field=time_f:time&field=dt_f:datetime'), 'test', 'memory') self.assertTrue(ml.isValid()) provider = ml.dataProvider() self.assertIsNotNone(provider) ft = QgsFeature() ft.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10, 10))) ft.setAttributes([ 1, QDate(2014, 3, 5), QTime(13, 45, 22), QDateTime(QDate(2014, 3, 5), QTime(13, 45, 22)) ]) res, features = provider.addFeatures([ft]) self.assertTrue(res) self.assertTrue(features) dest_file_name = os.path.join(str(QDir.tempPath()), 'datetime.shp') crs = QgsCoordinateReferenceSystem() crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId) write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( ml, dest_file_name, 'utf-8', crs, 'ESRI Shapefile') self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) # Open result and check created_layer = QgsVectorLayer('{}|layerid=0'.format(dest_file_name), 'test', 'ogr') fields = created_layer.dataProvider().fields() self.assertEqual( fields.at(fields.indexFromName('date_f')).type(), QVariant.Date) # shapefiles do not support time types, result should be string self.assertEqual( fields.at(fields.indexFromName('time_f')).type(), QVariant.String) # shapefiles do not support datetime types, result should be string self.assertEqual( fields.at(fields.indexFromName('dt_f')).type(), QVariant.String) f = next(created_layer.getFeatures(QgsFeatureRequest())) date_idx = created_layer.fields().lookupField('date_f') self.assertIsInstance(f.attributes()[date_idx], QDate) self.assertEqual(f.attributes()[date_idx], QDate(2014, 3, 5)) time_idx = created_layer.fields().lookupField('time_f') # shapefiles do not support time types self.assertIsInstance(f.attributes()[time_idx], str) self.assertEqual(f.attributes()[time_idx], '13:45:22') # shapefiles do not support datetime types datetime_idx = created_layer.fields().lookupField('dt_f') self.assertIsInstance(f.attributes()[datetime_idx], str) self.assertEqual( f.attributes()[datetime_idx], QDateTime(QDate(2014, 3, 5), QTime(13, 45, 22)).toString("yyyy/MM/dd hh:mm:ss.zzz"))
def testWriteShapefileWithAttributeSubsets(self): """Tests writing subsets of attributes to files.""" ml = QgsVectorLayer(( 'Point?crs=epsg:4326&field=id:int&field=field1:int&field=field2:int&field=field3:int' ), 'test', 'memory') self.assertIsNotNone(ml, 'Provider not initialized') self.assertTrue(ml.isValid(), 'Source layer not valid') provider = ml.dataProvider() self.assertIsNotNone(provider) ft = QgsFeature() ft.setGeometry(QgsGeometry.fromWkt('Point (1 2)')) ft.setAttributes([1, 11, 12, 13]) res, features = provider.addFeatures([ft]) self.assertTrue(res) self.assertTrue(features) # first write out with all attributes dest_file_name = os.path.join(str(QDir.tempPath()), 'all_attributes.shp') crs = QgsCoordinateReferenceSystem() crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId) write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( ml, dest_file_name, 'utf-8', crs, 'ESRI Shapefile', attributes=[]) self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) # Open result and check created_layer = QgsVectorLayer('{}|layerid=0'.format(dest_file_name), 'test', 'ogr') self.assertEqual(created_layer.fields().count(), 4) f = next(created_layer.getFeatures(QgsFeatureRequest())) self.assertEqual(f['id'], 1) self.assertEqual(f['field1'], 11) self.assertEqual(f['field2'], 12) self.assertEqual(f['field3'], 13) # now test writing out only a subset of attributes dest_file_name = os.path.join(str(QDir.tempPath()), 'subset_attributes.shp') write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( ml, dest_file_name, 'utf-8', crs, 'ESRI Shapefile', attributes=[1, 3]) self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) # Open result and check created_layer = QgsVectorLayer('{}|layerid=0'.format(dest_file_name), 'test', 'ogr') self.assertEqual(created_layer.fields().count(), 2) f = next(created_layer.getFeatures(QgsFeatureRequest())) self.assertEqual(f['field1'], 11) self.assertEqual(f['field3'], 13) # finally test writing no attributes dest_file_name = os.path.join(str(QDir.tempPath()), 'no_attributes.shp') write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( ml, dest_file_name, 'utf-8', crs, 'ESRI Shapefile', skipAttributeCreation=True) self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) # Open result and check created_layer = QgsVectorLayer('{}|layerid=0'.format(dest_file_name), 'test', 'ogr') # expect only a default 'FID' field for shapefiles self.assertEqual(created_layer.fields().count(), 1) self.assertEqual(created_layer.fields()[0].name(), 'FID') # in this case we also check that the geometry exists, to make sure feature has been correctly written # even without attributes f = next(created_layer.getFeatures(QgsFeatureRequest())) g = f.geometry() wkt = g.asWkt() expWkt = 'Point (1 2)' self.assertTrue( compareWkt(expWkt, wkt), "geometry not saved correctly when saving without attributes : mismatch Expected:\n%s\nGot:\n%s\n" % (expWkt, wkt)) self.assertEqual(f['FID'], 0)
def testWriteShapefileWithZ(self): """Check writing geometries with Z dimension to an ESRI shapefile.""" # start by saving a memory layer and forcing z ml = QgsVectorLayer(('Point?crs=epsg:4326&field=id:int'), 'test', 'memory') self.assertIsNotNone(ml, 'Provider not initialized') self.assertTrue(ml.isValid(), 'Source layer not valid') provider = ml.dataProvider() self.assertIsNotNone(provider) ft = QgsFeature() ft.setGeometry(QgsGeometry.fromWkt('PointZ (1 2 3)')) ft.setAttributes([1]) res, features = provider.addFeatures([ft]) self.assertTrue(res) self.assertTrue(features) # check with both a standard PointZ and 25d style Point25D type for t in [QgsWkbTypes.PointZ, QgsWkbTypes.Point25D]: dest_file_name = os.path.join( str(QDir.tempPath()), 'point_{}.shp'.format(QgsWkbTypes.displayString(t))) crs = QgsCoordinateReferenceSystem() crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId) write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( ml, dest_file_name, 'utf-8', crs, 'ESRI Shapefile', overrideGeometryType=t) self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) # Open result and check created_layer = QgsVectorLayer( '{}|layerid=0'.format(dest_file_name), 'test', 'ogr') f = next(created_layer.getFeatures(QgsFeatureRequest())) g = f.geometry() wkt = g.asWkt() expWkt = 'PointZ (1 2 3)' self.assertTrue( compareWkt(expWkt, wkt), "saving geometry with Z failed: mismatch Expected:\n%s\nGot:\n%s\n" % (expWkt, wkt)) # also try saving out the shapefile version again, as an extra test # this tests that saving a layer with z WITHOUT explicitly telling the writer to keep z values, # will stay retain the z values dest_file_name = os.path.join( str(QDir.tempPath()), 'point_{}_copy.shp'.format(QgsWkbTypes.displayString(t))) crs = QgsCoordinateReferenceSystem() crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId) write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( created_layer, dest_file_name, 'utf-8', crs, 'ESRI Shapefile') self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) # Open result and check created_layer_from_shp = QgsVectorLayer( '{}|layerid=0'.format(dest_file_name), 'test', 'ogr') f = next(created_layer_from_shp.getFeatures(QgsFeatureRequest())) g = f.geometry() wkt = g.asWkt() self.assertTrue( compareWkt(expWkt, wkt), "saving geometry with Z failed: mismatch Expected:\n%s\nGot:\n%s\n" % (expWkt, wkt))
def writeTmpLayer(layer, restrictToExtent, iface, extent): if layer.wkbType() == QgsWkbTypes.NoGeometry: return fields = layer.fields() usedFields = [] for count, field in enumerate(fields): fieldIndex = fields.indexFromName(field.name()) editorWidget = layer.editorWidgetSetup(fieldIndex).type() addField = False try: if layer.renderer().classAttribute() == field.name(): addField = True except Exception: pass if layer.customProperty("labeling/fieldName") == field.name(): addField = True if (editorWidget != 'Hidden'): addField = True if addField: usedFields.append(count) uri = TYPE_MAP[layer.wkbType()] crs = layer.crs() if crs.isValid(): uri += '?crs=' + crs.authid() for field in usedFields: fieldIndex = layer.fields().indexFromName( layer.fields().field(field).name()) editorWidget = layer.editorWidgetSetup(fieldIndex).type() fieldType = layer.fields().field(field).type() fieldName = layer.fields().field(field).name() if (editorWidget == 'Hidden'): fieldName = "q2wHide_" + fieldName if fieldType == QVariant.Double or fieldType == QVariant.Int: fieldType = "double" else: fieldType = "string" uri += '&field=' + fieldName + ":" + fieldType newlayer = QgsVectorLayer(uri, layer.name(), 'memory') writer = newlayer.dataProvider() outFeat = QgsFeature() if restrictToExtent and extent == "Canvas extent": canvas = iface.mapCanvas() extent = canvas.extent() canvasCRS = canvas.mapSettings().destinationCrs() layerCRS = layer.crs() try: transform = QgsCoordinateTransform(canvasCRS, layerCRS, QgsProject.instance()) except Exception: transform = QgsCoordinateTransform(canvasCRS, layerCRS) projectedExtent = transform.transformBoundingBox(extent) request = QgsFeatureRequest(projectedExtent) request.setFlags(QgsFeatureRequest.ExactIntersect) features = layer.getFeatures(request) else: features = layer.getFeatures() for feature in features: if feature.geometry() is not None: outFeat.setGeometry(feature.geometry()) attrs = [feature[f] for f in usedFields] if attrs: outFeat.setAttributes(attrs) writer.addFeatures([outFeat]) return newlayer
class TestQgsVectorFileWriter(unittest.TestCase): mMemoryLayer = None def testWrite(self): """Check we can write a vector file.""" self.mMemoryLayer = QgsVectorLayer( ('Point?crs=epsg:4326&field=name:string(20)&' 'field=age:integer&field=size:double&index=yes'), 'test', 'memory') self.assertIsNotNone(self.mMemoryLayer, 'Provider not initialized') myProvider = self.mMemoryLayer.dataProvider() self.assertIsNotNone(myProvider) ft = QgsFeature() ft.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10, 10))) ft.setAttributes(['Johny', 20, 0.3]) myResult, myFeatures = myProvider.addFeatures([ft]) self.assertTrue(myResult) self.assertTrue(myFeatures) writeShape(self.mMemoryLayer, 'writetest.shp') 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) del vl os.unlink(filename + '.gpkg') 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 testDateTimeWriteShapefile(self): """Check writing date and time fields to an ESRI shapefile.""" ml = QgsVectorLayer( ('Point?crs=epsg:4326&field=id:int&' 'field=date_f:date&field=time_f:time&field=dt_f:datetime'), 'test', 'memory') self.assertTrue(ml.isValid()) provider = ml.dataProvider() self.assertIsNotNone(provider) ft = QgsFeature() ft.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10, 10))) ft.setAttributes([ 1, QDate(2014, 3, 5), QTime(13, 45, 22), QDateTime(QDate(2014, 3, 5), QTime(13, 45, 22)) ]) res, features = provider.addFeatures([ft]) self.assertTrue(res) self.assertTrue(features) dest_file_name = os.path.join(str(QDir.tempPath()), 'datetime.shp') crs = QgsCoordinateReferenceSystem() crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId) write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( ml, dest_file_name, 'utf-8', crs, 'ESRI Shapefile') self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) # Open result and check created_layer = QgsVectorLayer('{}|layerid=0'.format(dest_file_name), 'test', 'ogr') fields = created_layer.dataProvider().fields() self.assertEqual( fields.at(fields.indexFromName('date_f')).type(), QVariant.Date) # shapefiles do not support time types, result should be string self.assertEqual( fields.at(fields.indexFromName('time_f')).type(), QVariant.String) # shapefiles do not support datetime types, result should be string self.assertEqual( fields.at(fields.indexFromName('dt_f')).type(), QVariant.String) f = next(created_layer.getFeatures(QgsFeatureRequest())) date_idx = created_layer.fields().lookupField('date_f') self.assertIsInstance(f.attributes()[date_idx], QDate) self.assertEqual(f.attributes()[date_idx], QDate(2014, 3, 5)) time_idx = created_layer.fields().lookupField('time_f') # shapefiles do not support time types self.assertIsInstance(f.attributes()[time_idx], str) self.assertEqual(f.attributes()[time_idx], '13:45:22') # shapefiles do not support datetime types datetime_idx = created_layer.fields().lookupField('dt_f') self.assertIsInstance(f.attributes()[datetime_idx], str) self.assertEqual( f.attributes()[datetime_idx], QDateTime(QDate(2014, 3, 5), QTime(13, 45, 22)).toString("yyyy/MM/dd hh:mm:ss.zzz")) def testWriterWithExtent(self): """Check writing using extent filter.""" source_file = os.path.join(TEST_DATA_DIR, 'points.shp') source_layer = QgsVectorLayer(source_file, 'Points', 'ogr') self.assertTrue(source_layer.isValid()) options = QgsVectorFileWriter.SaveVectorOptions() options.driverName = 'ESRI Shapefile' options.filterExtent = QgsRectangle(-111, 26, -96, 38) dest_file_name = os.path.join(str(QDir.tempPath()), 'extent_no_transform.shp') write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( source_layer, dest_file_name, options) self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) # Open result and check created_layer = QgsVectorLayer('{}|layerid=0'.format(dest_file_name), 'test', 'ogr') features = [f for f in created_layer.getFeatures()] self.assertEqual(len(features), 5) for f in features: self.assertTrue(f.geometry().intersects(options.filterExtent)) def testWriterWithExtentAndReprojection(self): """Check writing using extent filter with reprojection.""" source_file = os.path.join(TEST_DATA_DIR, 'points.shp') source_layer = QgsVectorLayer(source_file, 'Points', 'ogr') self.assertTrue(source_layer.isValid()) options = QgsVectorFileWriter.SaveVectorOptions() options.driverName = 'ESRI Shapefile' options.filterExtent = QgsRectangle(-12511460, 3045157, -10646621, 4683497) options.ct = QgsCoordinateTransform( source_layer.crs(), QgsCoordinateReferenceSystem.fromEpsgId(3785), QgsProject.instance()) dest_file_name = os.path.join(str(QDir.tempPath()), 'extent_transform.shp') write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( source_layer, dest_file_name, options) self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) # Open result and check created_layer = QgsVectorLayer('{}|layerid=0'.format(dest_file_name), 'test', 'ogr') features = [f for f in created_layer.getFeatures()] self.assertEqual(len(features), 5) for f in features: self.assertTrue(f.geometry().intersects(options.filterExtent)) def testDateTimeWriteTabfile(self): """Check writing date and time fields to an MapInfo tabfile.""" ml = QgsVectorLayer( ('Point?crs=epsg:4326&field=id:int&' 'field=date_f:date&field=time_f:time&field=dt_f:datetime'), 'test', 'memory') self.assertIsNotNone(ml, 'Provider not initialized') self.assertTrue(ml.isValid(), 'Source layer not valid') provider = ml.dataProvider() self.assertIsNotNone(provider) ft = QgsFeature() ft.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10, 10))) ft.setAttributes([ 1, QDate(2014, 3, 5), QTime(13, 45, 22), QDateTime(QDate(2014, 3, 5), QTime(13, 45, 22)) ]) res, features = provider.addFeatures([ft]) self.assertTrue(res) self.assertTrue(features) dest_file_name = os.path.join(str(QDir.tempPath()), 'datetime.tab') crs = QgsCoordinateReferenceSystem() crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId) write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( ml, dest_file_name, 'utf-8', crs, 'MapInfo File') self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) # Open result and check created_layer = QgsVectorLayer('{}|layerid=0'.format(dest_file_name), 'test', 'ogr') fields = created_layer.dataProvider().fields() self.assertEqual( fields.at(fields.indexFromName('date_f')).type(), QVariant.Date) self.assertEqual( fields.at(fields.indexFromName('time_f')).type(), QVariant.Time) self.assertEqual( fields.at(fields.indexFromName('dt_f')).type(), QVariant.DateTime) f = next(created_layer.getFeatures(QgsFeatureRequest())) date_idx = created_layer.fields().lookupField('date_f') self.assertIsInstance(f.attributes()[date_idx], QDate) self.assertEqual(f.attributes()[date_idx], QDate(2014, 3, 5)) time_idx = created_layer.fields().lookupField('time_f') self.assertIsInstance(f.attributes()[time_idx], QTime) self.assertEqual(f.attributes()[time_idx], QTime(13, 45, 22)) datetime_idx = created_layer.fields().lookupField('dt_f') self.assertIsInstance(f.attributes()[datetime_idx], QDateTime) self.assertEqual(f.attributes()[datetime_idx], QDateTime(QDate(2014, 3, 5), QTime(13, 45, 22))) def testWriteShapefileWithZ(self): """Check writing geometries with Z dimension to an ESRI shapefile.""" # start by saving a memory layer and forcing z ml = QgsVectorLayer(('Point?crs=epsg:4326&field=id:int'), 'test', 'memory') self.assertIsNotNone(ml, 'Provider not initialized') self.assertTrue(ml.isValid(), 'Source layer not valid') provider = ml.dataProvider() self.assertIsNotNone(provider) ft = QgsFeature() ft.setGeometry(QgsGeometry.fromWkt('PointZ (1 2 3)')) ft.setAttributes([1]) res, features = provider.addFeatures([ft]) self.assertTrue(res) self.assertTrue(features) # check with both a standard PointZ and 25d style Point25D type for t in [QgsWkbTypes.PointZ, QgsWkbTypes.Point25D]: dest_file_name = os.path.join( str(QDir.tempPath()), 'point_{}.shp'.format(QgsWkbTypes.displayString(t))) crs = QgsCoordinateReferenceSystem() crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId) write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( ml, dest_file_name, 'utf-8', crs, 'ESRI Shapefile', overrideGeometryType=t) self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) # Open result and check created_layer = QgsVectorLayer( '{}|layerid=0'.format(dest_file_name), 'test', 'ogr') f = next(created_layer.getFeatures(QgsFeatureRequest())) g = f.geometry() wkt = g.asWkt() expWkt = 'PointZ (1 2 3)' self.assertTrue( compareWkt(expWkt, wkt), "saving geometry with Z failed: mismatch Expected:\n%s\nGot:\n%s\n" % (expWkt, wkt)) # also try saving out the shapefile version again, as an extra test # this tests that saving a layer with z WITHOUT explicitly telling the writer to keep z values, # will stay retain the z values dest_file_name = os.path.join( str(QDir.tempPath()), 'point_{}_copy.shp'.format(QgsWkbTypes.displayString(t))) crs = QgsCoordinateReferenceSystem() crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId) write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( created_layer, dest_file_name, 'utf-8', crs, 'ESRI Shapefile') self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) # Open result and check created_layer_from_shp = QgsVectorLayer( '{}|layerid=0'.format(dest_file_name), 'test', 'ogr') f = next(created_layer_from_shp.getFeatures(QgsFeatureRequest())) g = f.geometry() wkt = g.asWkt() self.assertTrue( compareWkt(expWkt, wkt), "saving geometry with Z failed: mismatch Expected:\n%s\nGot:\n%s\n" % (expWkt, wkt)) def testWriteShapefileWithMultiConversion(self): """Check writing geometries to an ESRI shapefile with conversion to multi.""" ml = QgsVectorLayer(('Point?crs=epsg:4326&field=id:int'), 'test', 'memory') self.assertIsNotNone(ml, 'Provider not initialized') self.assertTrue(ml.isValid(), 'Source layer not valid') provider = ml.dataProvider() self.assertIsNotNone(provider) ft = QgsFeature() ft.setGeometry(QgsGeometry.fromWkt('Point (1 2)')) ft.setAttributes([1]) res, features = provider.addFeatures([ft]) self.assertTrue(res) self.assertTrue(features) dest_file_name = os.path.join(str(QDir.tempPath()), 'to_multi.shp') crs = QgsCoordinateReferenceSystem() crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId) write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( ml, dest_file_name, 'utf-8', crs, 'ESRI Shapefile', forceMulti=True) self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) # Open result and check created_layer = QgsVectorLayer('{}|layerid=0'.format(dest_file_name), 'test', 'ogr') f = next(created_layer.getFeatures(QgsFeatureRequest())) g = f.geometry() wkt = g.asWkt() expWkt = 'MultiPoint ((1 2))' self.assertTrue( compareWkt(expWkt, wkt), "saving geometry with multi conversion failed: mismatch Expected:\n%s\nGot:\n%s\n" % (expWkt, wkt)) def testWriteShapefileWithAttributeSubsets(self): """Tests writing subsets of attributes to files.""" ml = QgsVectorLayer(( 'Point?crs=epsg:4326&field=id:int&field=field1:int&field=field2:int&field=field3:int' ), 'test', 'memory') self.assertIsNotNone(ml, 'Provider not initialized') self.assertTrue(ml.isValid(), 'Source layer not valid') provider = ml.dataProvider() self.assertIsNotNone(provider) ft = QgsFeature() ft.setGeometry(QgsGeometry.fromWkt('Point (1 2)')) ft.setAttributes([1, 11, 12, 13]) res, features = provider.addFeatures([ft]) self.assertTrue(res) self.assertTrue(features) # first write out with all attributes dest_file_name = os.path.join(str(QDir.tempPath()), 'all_attributes.shp') crs = QgsCoordinateReferenceSystem() crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId) write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( ml, dest_file_name, 'utf-8', crs, 'ESRI Shapefile', attributes=[]) self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) # Open result and check created_layer = QgsVectorLayer('{}|layerid=0'.format(dest_file_name), 'test', 'ogr') self.assertEqual(created_layer.fields().count(), 4) f = next(created_layer.getFeatures(QgsFeatureRequest())) self.assertEqual(f['id'], 1) self.assertEqual(f['field1'], 11) self.assertEqual(f['field2'], 12) self.assertEqual(f['field3'], 13) # now test writing out only a subset of attributes dest_file_name = os.path.join(str(QDir.tempPath()), 'subset_attributes.shp') write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( ml, dest_file_name, 'utf-8', crs, 'ESRI Shapefile', attributes=[1, 3]) self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) # Open result and check created_layer = QgsVectorLayer('{}|layerid=0'.format(dest_file_name), 'test', 'ogr') self.assertEqual(created_layer.fields().count(), 2) f = next(created_layer.getFeatures(QgsFeatureRequest())) self.assertEqual(f['field1'], 11) self.assertEqual(f['field3'], 13) # finally test writing no attributes dest_file_name = os.path.join(str(QDir.tempPath()), 'no_attributes.shp') write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( ml, dest_file_name, 'utf-8', crs, 'ESRI Shapefile', skipAttributeCreation=True) self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) # Open result and check created_layer = QgsVectorLayer('{}|layerid=0'.format(dest_file_name), 'test', 'ogr') # expect only a default 'FID' field for shapefiles self.assertEqual(created_layer.fields().count(), 1) self.assertEqual(created_layer.fields()[0].name(), 'FID') # in this case we also check that the geometry exists, to make sure feature has been correctly written # even without attributes f = next(created_layer.getFeatures(QgsFeatureRequest())) g = f.geometry() wkt = g.asWkt() expWkt = 'Point (1 2)' self.assertTrue( compareWkt(expWkt, wkt), "geometry not saved correctly when saving without attributes : mismatch Expected:\n%s\nGot:\n%s\n" % (expWkt, wkt)) self.assertEqual(f['FID'], 0) def testValueConverter(self): """Tests writing a layer with a field value converter.""" ml = QgsVectorLayer( ('Point?field=nonconv:int&field=ignored:string&field=converted:int' ), 'test', 'memory') self.assertIsNotNone(ml, 'Provider not initialized') self.assertTrue(ml.isValid(), 'Source layer not valid') provider = ml.dataProvider() self.assertIsNotNone(provider) self.assertEqual(ml.fields().count(), 3) ft = QgsFeature() ft.setAttributes([1, 'ignored', 3]) res, features = provider.addFeatures([ft]) self.assertTrue(res) self.assertTrue(features) dest_file_name = os.path.join(str(QDir.tempPath()), 'value_converter.shp') converter = TestFieldValueConverter(ml) write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( ml, dest_file_name, 'utf-8', QgsCoordinateReferenceSystem(), 'ESRI Shapefile', attributes=[0, 2], fieldValueConverter=converter) self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) # Open result and check created_layer = QgsVectorLayer('{}|layerid=0'.format(dest_file_name), 'test', 'ogr') self.assertEqual(created_layer.fields().count(), 2) f = next(created_layer.getFeatures(QgsFeatureRequest())) self.assertEqual(f['nonconv'], 1) self.assertEqual(f['conv_attr'], 'converted_val') def testInteger64WriteTabfile(self): """Check writing Integer64 fields to an MapInfo tabfile (which does not support that type).""" ml = QgsVectorLayer(('Point?crs=epsg:4326&field=int8:int8'), 'test', 'memory') self.assertIsNotNone(ml, 'Provider not initialized') self.assertTrue(ml.isValid(), 'Source layer not valid') provider = ml.dataProvider() self.assertIsNotNone(provider) ft = QgsFeature() ft.setAttributes([2123456789]) res, features = provider.addFeatures([ft]) self.assertTrue(res) self.assertTrue(features) dest_file_name = os.path.join(str(QDir.tempPath()), 'integer64.tab') crs = QgsCoordinateReferenceSystem() crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId) write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( ml, dest_file_name, 'utf-8', crs, 'MapInfo File') self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) # Open result and check created_layer = QgsVectorLayer('{}|layerid=0'.format(dest_file_name), 'test', 'ogr') fields = created_layer.dataProvider().fields() self.assertEqual( fields.at(fields.indexFromName('int8')).type(), QVariant.Double) f = next(created_layer.getFeatures(QgsFeatureRequest())) int8_idx = created_layer.fields().lookupField('int8') self.assertEqual(f.attributes()[int8_idx], 2123456789) def testDefaultDatasetOptions(self): """ Test retrieving default dataset options for a format """ # NOTE - feel free to adapt these if the defaults change! options = QgsVectorFileWriter.defaultDatasetOptions('not a format') self.assertEqual(options, []) options = QgsVectorFileWriter.defaultDatasetOptions('ESRI Shapefile') self.assertEqual(options, []) options = QgsVectorFileWriter.defaultDatasetOptions('GML') # just test a few self.assertTrue('GML3_LONGSRS=YES' in options) self.assertTrue('STRIP_PREFIX=NO' in options) def testDefaultLayerOptions(self): """ Test retrieving default layer options for a format """ # NOTE - feel free to adapt these if the defaults change! options = QgsVectorFileWriter.defaultLayerOptions('not a format') self.assertEqual(options, []) options = QgsVectorFileWriter.defaultLayerOptions('ESRI Shapefile') self.assertEqual(options, ['RESIZE=NO']) options = QgsVectorFileWriter.defaultLayerOptions('GML') self.assertEqual(options, []) def testOverwriteLayer(self): """Tests writing a layer with a field value converter.""" ml = QgsVectorLayer('Point?field=firstfield:int', 'test', 'memory') provider = ml.dataProvider() ft = QgsFeature() ft.setAttributes([1]) provider.addFeatures([ft]) options = QgsVectorFileWriter.SaveVectorOptions() options.driverName = 'GPKG' options.layerName = 'test' filename = '/vsimem/out.gpkg' write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( ml, filename, options) self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) ds = ogr.Open(filename, update=1) lyr = ds.GetLayerByName('test') self.assertIsNotNone(lyr) f = lyr.GetNextFeature() self.assertEqual(f['firstfield'], 1) ds.CreateLayer('another_layer') del f del lyr del ds caps = QgsVectorFileWriter.editionCapabilities(filename) self.assertTrue((caps & QgsVectorFileWriter.CanAddNewLayer)) self.assertTrue((caps & QgsVectorFileWriter.CanAppendToExistingLayer)) self.assertTrue( (caps & QgsVectorFileWriter.CanAddNewFieldsToExistingLayer)) self.assertTrue((caps & QgsVectorFileWriter.CanDeleteLayer)) self.assertTrue(QgsVectorFileWriter.targetLayerExists( filename, 'test')) self.assertFalse( QgsVectorFileWriter.areThereNewFieldsToCreate( filename, 'test', ml, [0])) # Test CreateOrOverwriteLayer ml = QgsVectorLayer('Point?field=firstfield:int', 'test', 'memory') provider = ml.dataProvider() ft = QgsFeature() ft.setAttributes([2]) provider.addFeatures([ft]) options = QgsVectorFileWriter.SaveVectorOptions() options.driverName = 'GPKG' options.layerName = 'test' options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteLayer filename = '/vsimem/out.gpkg' write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( ml, filename, options) self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) ds = ogr.Open(filename) lyr = ds.GetLayerByName('test') self.assertIsNotNone(lyr) f = lyr.GetNextFeature() self.assertEqual(f['firstfield'], 2) # another_layer should still exist self.assertIsNotNone(ds.GetLayerByName('another_layer')) del f del lyr del ds # Test CreateOrOverwriteFile ml = QgsVectorLayer('Point?field=firstfield:int', 'test', 'memory') provider = ml.dataProvider() ft = QgsFeature() ft.setAttributes([3]) provider.addFeatures([ft]) options = QgsVectorFileWriter.SaveVectorOptions() options.driverName = 'GPKG' options.layerName = 'test' filename = '/vsimem/out.gpkg' write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( ml, filename, options) self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) ds = ogr.Open(filename) lyr = ds.GetLayerByName('test') self.assertIsNotNone(lyr) f = lyr.GetNextFeature() self.assertEqual(f['firstfield'], 3) # another_layer should no longer exist self.assertIsNone(ds.GetLayerByName('another_layer')) del f del lyr del ds # Test AppendToLayerNoNewFields ml = QgsVectorLayer('Point?field=firstfield:int&field=secondfield:int', 'test', 'memory') provider = ml.dataProvider() ft = QgsFeature() ft.setAttributes([4, -10]) provider.addFeatures([ft]) self.assertTrue( QgsVectorFileWriter.areThereNewFieldsToCreate( filename, 'test', ml, [0, 1])) options = QgsVectorFileWriter.SaveVectorOptions() options.driverName = 'GPKG' options.layerName = 'test' options.actionOnExistingFile = QgsVectorFileWriter.AppendToLayerNoNewFields filename = '/vsimem/out.gpkg' write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( ml, filename, options) self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) ds = ogr.Open(filename) lyr = ds.GetLayerByName('test') self.assertEqual(lyr.GetLayerDefn().GetFieldCount(), 1) self.assertIsNotNone(lyr) f = lyr.GetNextFeature() self.assertEqual(f['firstfield'], 3) f = lyr.GetNextFeature() self.assertEqual(f['firstfield'], 4) del f del lyr del ds # Test AppendToLayerAddFields ml = QgsVectorLayer('Point?field=firstfield:int&field=secondfield:int', 'test', 'memory') provider = ml.dataProvider() ft = QgsFeature() ft.setAttributes([5, -1]) provider.addFeatures([ft]) self.assertTrue( QgsVectorFileWriter.areThereNewFieldsToCreate( filename, 'test', ml, [0, 1])) options = QgsVectorFileWriter.SaveVectorOptions() options.driverName = 'GPKG' options.layerName = 'test' options.actionOnExistingFile = QgsVectorFileWriter.AppendToLayerAddFields filename = '/vsimem/out.gpkg' write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( ml, filename, options) self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) ds = ogr.Open(filename) lyr = ds.GetLayerByName('test') self.assertEqual(lyr.GetLayerDefn().GetFieldCount(), 2) self.assertIsNotNone(lyr) f = lyr.GetNextFeature() self.assertEqual(f['firstfield'], 3) if hasattr(f, "IsFieldSetAndNotNull"): # GDAL >= 2.2 self.assertFalse(f.IsFieldSetAndNotNull('secondfield')) else: self.assertFalse(f.IsFieldSet('secondfield')) f = lyr.GetNextFeature() self.assertEqual(f['firstfield'], 4) if hasattr(f, "IsFieldSetAndNotNull"): self.assertFalse(f.IsFieldSetAndNotNull('secondfield')) else: self.assertFalse(f.IsFieldSet('secondfield')) f = lyr.GetNextFeature() self.assertEqual(f['firstfield'], 5) self.assertEqual(f['secondfield'], -1) del f del lyr del ds gdal.Unlink(filename) def testSupportedFiltersAndFormat(self): # test with formats in recommended order formats = QgsVectorFileWriter.supportedFiltersAndFormats( QgsVectorFileWriter.SortRecommended) self.assertEqual(formats[0].filterString, 'GeoPackage (*.gpkg *.GPKG)') self.assertEqual(formats[0].driverName, 'GPKG') self.assertEqual(formats[0].globs, ['*.gpkg']) self.assertEqual(formats[1].filterString, 'ESRI Shapefile (*.shp *.SHP)') self.assertEqual(formats[1].driverName, 'ESRI Shapefile') self.assertEqual(formats[1].globs, ['*.shp']) self.assertTrue('ODS' in [f.driverName for f in formats]) interlis_format = [f for f in formats if f.driverName == 'Interlis 2'][0] self.assertEqual(interlis_format.globs, ['*.xtf', '*.xml', '*.ili']) # alphabetical sorting formats2 = QgsVectorFileWriter.supportedFiltersAndFormats( QgsVectorFileWriter.VectorFormatOptions()) self.assertTrue(formats2[0].driverName < formats2[1].driverName) self.assertCountEqual([f.driverName for f in formats], [f.driverName for f in formats2]) self.assertNotEqual(formats2[0].driverName, 'GeoPackage') # skip non-spatial formats = QgsVectorFileWriter.supportedFiltersAndFormats( QgsVectorFileWriter.SkipNonSpatialFormats) self.assertFalse('ODS' in [f.driverName for f in formats]) def testOgrDriverList(self): # test with drivers in recommended order drivers = QgsVectorFileWriter.ogrDriverList( QgsVectorFileWriter.SortRecommended) self.assertEqual(drivers[0].longName, 'GeoPackage') self.assertEqual(drivers[0].driverName, 'GPKG') self.assertEqual(drivers[1].longName, 'ESRI Shapefile') self.assertEqual(drivers[1].driverName, 'ESRI Shapefile') self.assertTrue('ODS' in [f.driverName for f in drivers]) # ensure that XLSX comes before SQLite, because we should sort on longName, not driverName! ms_xlsx_index = next(i for i, v in enumerate(drivers) if v.driverName == 'XLSX') sqlite_index = next(i for i, v in enumerate(drivers) if v.driverName == 'SQLite') self.assertLess(ms_xlsx_index, sqlite_index) self.assertIn('[XLSX]', drivers[ms_xlsx_index].longName) # alphabetical sorting drivers2 = QgsVectorFileWriter.ogrDriverList( QgsVectorFileWriter.VectorFormatOptions()) self.assertTrue(drivers2[0].longName < drivers2[1].longName) self.assertCountEqual([d.driverName for d in drivers], [d.driverName for d in drivers2]) self.assertNotEqual(drivers2[0].driverName, 'GPKG') # skip non-spatial formats = QgsVectorFileWriter.ogrDriverList( QgsVectorFileWriter.SkipNonSpatialFormats) self.assertFalse('ODS' in [f.driverName for f in formats]) def testSupportedFormatExtensions(self): formats = QgsVectorFileWriter.supportedFormatExtensions() self.assertTrue('gpkg' in formats) self.assertFalse('exe' in formats) self.assertEqual(formats[0], 'gpkg') self.assertEqual(formats[1], 'shp') self.assertTrue('ods' in formats) self.assertTrue('xtf' in formats) self.assertTrue('ili' in formats) for i in range(2, len(formats) - 1): self.assertLess(formats[i].lower(), formats[i + 1].lower()) # alphabetical sorting formats2 = QgsVectorFileWriter.supportedFormatExtensions( QgsVectorFileWriter.VectorFormatOptions()) self.assertTrue(formats2[0] < formats2[1]) self.assertCountEqual(formats, formats2) self.assertNotEqual(formats2[0], 'gpkg') for i in range(0, len(formats2) - 1): self.assertLess(formats2[i].lower(), formats2[i + 1].lower()) formats = QgsVectorFileWriter.supportedFormatExtensions( QgsVectorFileWriter.SkipNonSpatialFormats) self.assertFalse('ods' in formats) def testFileFilterString(self): formats = QgsVectorFileWriter.fileFilterString() self.assertTrue('gpkg' in formats) self.assertTrue('shp' in formats) self.assertLess(formats.index('gpkg'), formats.index('shp')) self.assertTrue('ods' in formats) parts = formats.split(';;') for i in range(2, len(parts) - 1): self.assertLess(parts[i].lower(), parts[i + 1].lower()) # alphabetical sorting formats2 = QgsVectorFileWriter.fileFilterString( QgsVectorFileWriter.VectorFormatOptions()) self.assertNotEqual(formats.index('gpkg'), formats2.index('gpkg')) parts = formats2.split(';;') for i in range(len(parts) - 1): self.assertLess(parts[i].lower(), parts[i + 1].lower()) # hide non spatial formats = QgsVectorFileWriter.fileFilterString( QgsVectorFileWriter.SkipNonSpatialFormats) self.assertFalse('ods' in formats) def testDriverForExtension(self): self.assertEqual(QgsVectorFileWriter.driverForExtension('shp'), 'ESRI Shapefile') self.assertEqual(QgsVectorFileWriter.driverForExtension('SHP'), 'ESRI Shapefile') self.assertEqual(QgsVectorFileWriter.driverForExtension('sHp'), 'ESRI Shapefile') self.assertEqual(QgsVectorFileWriter.driverForExtension('.shp'), 'ESRI Shapefile') self.assertEqual(QgsVectorFileWriter.driverForExtension('tab'), 'MapInfo File') self.assertEqual(QgsVectorFileWriter.driverForExtension('.GML'), 'GML') self.assertEqual( QgsVectorFileWriter.driverForExtension('not a format'), '') self.assertEqual(QgsVectorFileWriter.driverForExtension(''), '') def testSupportsFeatureStyles(self): self.assertFalse( QgsVectorFileWriter.supportsFeatureStyles('ESRI Shapefile')) self.assertFalse( QgsVectorFileWriter.supportsFeatureStyles('not a driver')) self.assertTrue(QgsVectorFileWriter.supportsFeatureStyles('DXF')) self.assertTrue(QgsVectorFileWriter.supportsFeatureStyles('KML')) self.assertTrue( QgsVectorFileWriter.supportsFeatureStyles('MapInfo File')) self.assertTrue( QgsVectorFileWriter.supportsFeatureStyles('MapInfo MIF')) def testOverwriteGPKG(self): """Test that overwriting the same origin GPKG file works only if the layername is different""" # Prepare test data ml = QgsVectorLayer('Point?field=firstfield:int&field=secondfield:int', 'test', 'memory') provider = ml.dataProvider() ft = QgsFeature() ft.setAttributes([4, -10]) provider.addFeatures([ft]) filehandle, filename = tempfile.mkstemp('.gpkg') options = QgsVectorFileWriter.SaveVectorOptions() options.driverName = 'GPKG' options.layerName = 'test' write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( ml, filename, options) self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) # Real test vl = QgsVectorLayer("%s|layername=test" % filename, 'src_test', 'ogr') self.assertTrue(vl.isValid()) self.assertEqual(vl.featureCount(), 1) # This must fail write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( vl, filename, options) self.assertEqual(write_result, QgsVectorFileWriter.ErrCreateDataSource) self.assertEqual(error_message, 'Cannot overwrite a OGR layer in place') options.layerName = 'test2' write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( vl, filename, options) self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) def testCreateDGN(self): ml = QgsVectorLayer('Point?crs=epsg:4326', 'test', 'memory') provider = ml.dataProvider() feat = QgsFeature() feat.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10, 10))) provider.addFeatures([feat]) filename = os.path.join(str(QDir.tempPath()), 'testCreateDGN.dgn') crs = QgsCoordinateReferenceSystem() crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId) rc, errmsg = QgsVectorFileWriter.writeAsVectorFormat( ml, filename, 'utf-8', crs, 'DGN') # open the resulting file vl = QgsVectorLayer(filename, '', 'ogr') self.assertTrue(vl.isValid()) self.assertEqual(vl.featureCount(), 1) del vl # append options = QgsVectorFileWriter.SaveVectorOptions() options.driverName = 'DGN' options.layerName = 'test' options.actionOnExistingFile = QgsVectorFileWriter.AppendToLayerNoNewFields write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( ml, filename, options) self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) # open the resulting file vl = QgsVectorLayer(filename, '', 'ogr') self.assertTrue(vl.isValid()) self.assertEqual(vl.featureCount(), 2) del vl os.unlink(filename) def testAddZ(self): """Check adding z values to non z input.""" input = QgsVectorLayer('Point?crs=epsg:4326&field=name:string(20)', 'test', 'memory') self.assertTrue(input.isValid(), 'Provider not initialized') ft = QgsFeature() ft.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10, 10))) myResult, myFeatures = input.dataProvider().addFeatures([ft]) self.assertTrue(myResult) self.assertTrue(myFeatures) dest_file_name = os.path.join(str(QDir.tempPath()), 'add_z.geojson') options = QgsVectorFileWriter.SaveVectorOptions() options.overrideGeometryType = QgsWkbTypes.PointZ options.driverName = 'GeoJSON' write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( input, dest_file_name, options) self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) # Open result and check created_layer = QgsVectorLayer(dest_file_name, 'test', 'ogr') self.assertTrue(created_layer.isValid()) f = next(created_layer.getFeatures(QgsFeatureRequest())) self.assertEqual(f.geometry().asWkt(), 'PointZ (10 10 0)') def testDropZ(self): """Check dropping z values input.""" input = QgsVectorLayer('PointZ?crs=epsg:4326&field=name:string(20)', 'test', 'memory') self.assertTrue(input.isValid(), 'Provider not initialized') ft = QgsFeature() ft.setGeometry(QgsGeometry.fromWkt('PointM(10 10 2)')) myResult, myFeatures = input.dataProvider().addFeatures([ft]) self.assertTrue(myResult) self.assertTrue(myFeatures) dest_file_name = os.path.join(str(QDir.tempPath()), 'drop_z.geojson') options = QgsVectorFileWriter.SaveVectorOptions() options.overrideGeometryType = QgsWkbTypes.PointM options.driverName = 'GeoJSON' write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( input, dest_file_name, options) self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) # Open result and check created_layer = QgsVectorLayer(dest_file_name, 'test', 'ogr') self.assertTrue(created_layer.isValid()) f = next(created_layer.getFeatures(QgsFeatureRequest())) self.assertEqual(f.geometry().asWkt(), 'Point (10 10)') 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 testMapTheme(self): canvas = QgsMapCanvas() canvas.setDestinationCrs(QgsCoordinateReferenceSystem(4326)) canvas.setFrameStyle(0) canvas.resize(600, 400) self.assertEqual(canvas.width(), 600) self.assertEqual(canvas.height(), 400) layer = QgsVectorLayer("Polygon?crs=epsg:4326&field=fldtxt:string", "layer", "memory") # add a polygon to layer f = QgsFeature() f.setGeometry(QgsGeometry.fromRect(QgsRectangle(5, 25, 25, 45))) self.assertTrue(layer.dataProvider().addFeatures([f])) # create a style sym1 = QgsFillSymbol.createSimple({'color': '#ffb200'}) renderer = QgsSingleSymbolRenderer(sym1) layer.setRenderer(renderer) canvas.setLayers([layer]) canvas.setExtent(QgsRectangle(10, 30, 20, 35)) canvas.show() # need to wait until first redraw can occur (note that we first need to wait till drawing starts!) while not canvas.isDrawing(): app.processEvents() canvas.waitWhileRendering() self.assertTrue(self.canvasImageCheck('theme1', 'theme1', canvas)) # add some styles layer.styleManager().addStyleFromLayer('style1') sym2 = QgsFillSymbol.createSimple({'color': '#00b2ff'}) renderer2 = QgsSingleSymbolRenderer(sym2) layer.setRenderer(renderer2) layer.styleManager().addStyleFromLayer('style2') canvas.refresh() canvas.waitWhileRendering() self.assertTrue(self.canvasImageCheck('theme2', 'theme2', canvas)) layer.styleManager().setCurrentStyle('style1') canvas.refresh() canvas.waitWhileRendering() self.assertTrue(self.canvasImageCheck('theme1', 'theme1', canvas)) # OK, so all good with setting/rendering map styles # try setting canvas to a particular theme # make some themes... theme1 = QgsMapThemeCollection.MapThemeRecord() record1 = QgsMapThemeCollection.MapThemeLayerRecord(layer) record1.currentStyle = 'style1' record1.usingCurrentStyle = True theme1.setLayerRecords([record1]) theme2 = QgsMapThemeCollection.MapThemeRecord() record2 = QgsMapThemeCollection.MapThemeLayerRecord(layer) record2.currentStyle = 'style2' record2.usingCurrentStyle = True theme2.setLayerRecords([record2]) QgsProject.instance().mapThemeCollection().insert('theme1', theme1) QgsProject.instance().mapThemeCollection().insert('theme2', theme2) canvas.setTheme('theme2') canvas.refresh() canvas.waitWhileRendering() self.assertTrue(self.canvasImageCheck('theme2', 'theme2', canvas)) canvas.setTheme('theme1') canvas.refresh() canvas.waitWhileRendering() self.assertTrue(self.canvasImageCheck('theme1', 'theme1', canvas)) # add another layer layer2 = QgsVectorLayer("Polygon?crs=epsg:4326&field=fldtxt:string", "layer2", "memory") f = QgsFeature() f.setGeometry(QgsGeometry.fromRect(QgsRectangle(5, 25, 25, 45))) self.assertTrue(layer2.dataProvider().addFeatures([f])) # create a style sym1 = QgsFillSymbol.createSimple({'color': '#b2ff00'}) renderer = QgsSingleSymbolRenderer(sym1) layer2.setRenderer(renderer) # rerender canvas - should NOT show new layer canvas.refresh() canvas.waitWhileRendering() self.assertTrue(self.canvasImageCheck('theme1', 'theme1', canvas)) # test again - this time refresh all layers canvas.refreshAllLayers() canvas.waitWhileRendering() self.assertTrue(self.canvasImageCheck('theme1', 'theme1', canvas)) # add layer 2 to theme1 record3 = QgsMapThemeCollection.MapThemeLayerRecord(layer2) theme1.setLayerRecords([record3]) QgsProject.instance().mapThemeCollection().update('theme1', theme1) canvas.refresh() canvas.waitWhileRendering() self.assertTrue(self.canvasImageCheck('theme3', 'theme3', canvas)) # change the appearance of an active style layer2.styleManager().addStyleFromLayer('original') layer2.styleManager().addStyleFromLayer('style4') record3.currentStyle = 'style4' record3.usingCurrentStyle = True theme1.setLayerRecords([record3]) QgsProject.instance().mapThemeCollection().update('theme1', theme1) canvas.refresh() canvas.waitWhileRendering() self.assertTrue(self.canvasImageCheck('theme3', 'theme3', canvas)) layer2.styleManager().setCurrentStyle('style4') sym3 = QgsFillSymbol.createSimple({'color': '#b200b2'}) layer2.renderer().setSymbol(sym3) canvas.refresh() canvas.waitWhileRendering() self.assertTrue(self.canvasImageCheck('theme4', 'theme4', canvas)) # try setting layers while a theme is in place canvas.setLayers([layer]) canvas.refresh() # should be no change... setLayers should be ignored if canvas is following a theme! canvas.waitWhileRendering() self.assertTrue(self.canvasImageCheck('theme4', 'theme4', canvas)) # setLayerStyleOverrides while theme is in place canvas.setLayerStyleOverrides({layer2.id(): 'original'}) # should be no change... setLayerStyleOverrides should be ignored if canvas is following a theme! canvas.refresh() canvas.waitWhileRendering() self.assertTrue(self.canvasImageCheck('theme4', 'theme4', canvas)) # clear theme canvas.setTheme('') canvas.refresh() canvas.waitWhileRendering() # should be different - we should now render project layers self.assertFalse(self.canvasImageCheck('theme4', 'theme4', canvas))
def test_invalidGeometryFilter(self): layer = QgsVectorLayer("Polygon?field=x:string", "joinlayer", "memory") # add some features, one has invalid geometry pr = layer.dataProvider() f1 = QgsFeature(1) f1.setAttributes(["a"]) f1.setGeometry( QgsGeometry.fromWkt('Polygon((0 0, 1 0, 1 1, 0 1, 0 0))')) # valid f2 = QgsFeature(2) f2.setAttributes(["b"]) f2.setGeometry( QgsGeometry.fromWkt( 'Polygon((0 0, 1 0, 0 1, 1 1, 0 0))')) # invalid f3 = QgsFeature(3) f3.setAttributes(["c"]) f3.setGeometry( QgsGeometry.fromWkt('Polygon((0 0, 1 0, 1 1, 0 1, 0 0))')) # valid self.assertTrue(pr.addFeatures([f1, f2, f3])) res = [ f['x'] for f in layer.getFeatures(QgsFeatureRequest( ).setInvalidGeometryCheck(QgsFeatureRequest.GeometryNoCheck)) ] self.assertEqual(res, ['a', 'b', 'c']) res = [ f['x'] for f in layer.getFeatures(QgsFeatureRequest( ).setInvalidGeometryCheck(QgsFeatureRequest.GeometrySkipInvalid)) ] self.assertEqual(res, ['a', 'c']) res = [ f['x'] for f in layer.getFeatures( QgsFeatureRequest().setInvalidGeometryCheck( QgsFeatureRequest.GeometryAbortOnInvalid)) ] self.assertEqual(res, ['a']) # with callback self.callback_feature_val = None def callback(feature): self.callback_feature_val = feature['x'] res = [ f['x'] for f in layer.getFeatures(QgsFeatureRequest( ).setInvalidGeometryCheck(QgsFeatureRequest.GeometryAbortOnInvalid ).setInvalidGeometryCallback(callback)) ] self.assertEqual(res, ['a']) self.assertEqual(self.callback_feature_val, 'b') # clear callback res = [ f['x'] for f in layer.getFeatures(QgsFeatureRequest( ).setInvalidGeometryCheck(QgsFeatureRequest.GeometryAbortOnInvalid ).setInvalidGeometryCallback(None)) ] self.assertEqual(res, ['a']) # check with filter fids res = [ f['x'] for f in layer.getFeatures(QgsFeatureRequest().setFilterFid(f2.id( )).setInvalidGeometryCheck(QgsFeatureRequest.GeometryNoCheck)) ] self.assertEqual(res, ['b']) res = [ f['x'] for f in layer.getFeatures(QgsFeatureRequest().setFilterFid(f2.id( )).setInvalidGeometryCheck(QgsFeatureRequest.GeometrySkipInvalid)) ] self.assertEqual(res, []) res = [ f['x'] for f in layer.getFeatures(QgsFeatureRequest().setFilterFid( f2.id()).setInvalidGeometryCheck( QgsFeatureRequest.GeometryAbortOnInvalid)) ] self.assertEqual(res, []) f4 = QgsFeature(4) f4.setAttributes(["d"]) f4.setGeometry( QgsGeometry.fromWkt( 'Polygon((0 0, 1 0, 0 1, 1 1, 0 0))')) # invalid # check with added features layer.startEditing() self.assertTrue(layer.addFeatures([f4])) res = [ f['x'] for f in layer.getFeatures(QgsFeatureRequest( ).setInvalidGeometryCheck(QgsFeatureRequest.GeometryNoCheck)) ] self.assertEqual(set(res), {'a', 'b', 'c', 'd'}) res = [ f['x'] for f in layer.getFeatures(QgsFeatureRequest( ).setInvalidGeometryCheck(QgsFeatureRequest.GeometrySkipInvalid)) ] self.assertEqual(set(res), {'a', 'c'}) res = [ f['x'] for f in layer.getFeatures( QgsFeatureRequest().setInvalidGeometryCheck( QgsFeatureRequest.GeometryAbortOnInvalid)) ] self.assertEqual(res, ['a']) # check with features with changed geometry layer.rollBack() layer.startEditing() layer.changeGeometry( 2, QgsGeometry.fromWkt('Polygon((0 0, 1 0, 1 1, 0 1, 0 0))')) # valid layer.changeGeometry( 3, QgsGeometry.fromWkt( 'Polygon((0 0, 1 0, 0 1, 1 1, 0 0))')) # invalid res = [ f['x'] for f in layer.getFeatures(QgsFeatureRequest( ).setInvalidGeometryCheck(QgsFeatureRequest.GeometryNoCheck)) ] self.assertEqual(set(res), {'a', 'b', 'c'}) res = [ f['x'] for f in layer.getFeatures(QgsFeatureRequest( ).setInvalidGeometryCheck(QgsFeatureRequest.GeometrySkipInvalid)) ] self.assertEqual(set(res), {'a', 'b'}) res = [ f['x'] for f in layer.getFeatures( QgsFeatureRequest().setInvalidGeometryCheck( QgsFeatureRequest.GeometryAbortOnInvalid)) ] self.assertEqual(res, ['a', 'b']) layer.rollBack()
def test_Query(self): l1 = QgsVectorLayer(os.path.join(self.testDataDir, "france_parts.shp"), "france_parts", "ogr", QgsVectorLayer.LayerOptions(False)) self.assertEqual(l1.isValid(), True) QgsProject.instance().addMapLayer(l1) ref_sum = sum(f.attributes()[0] for f in l1.getFeatures()) query = toPercent("SELECT * FROM vtab1") l2 = QgsVectorLayer( "?layer_ref=%s&geometry=geometry:3:4326&query=%s&uid=OBJECTID" % (l1.id(), query), "vtab", "virtual", QgsVectorLayer.LayerOptions(False)) self.assertEqual(l2.isValid(), True) self.assertEqual(l2.dataProvider().wkbType(), 3) ref_sum2 = sum(f.attributes()[0] for f in l2.getFeatures()) ref_sum3 = sum(f.id() for f in l2.getFeatures()) # check we have the same rows self.assertEqual(ref_sum, ref_sum2) # check the id is OK self.assertEqual(ref_sum, ref_sum3) # the same, without specifying the geometry column name l2 = QgsVectorLayer( "?layer_ref=%s&query=%s&uid=OBJECTID" % (l1.id(), query), "vtab", "virtual", QgsVectorLayer.LayerOptions(False)) self.assertEqual(l2.isValid(), True) self.assertEqual(l2.dataProvider().wkbType(), 6) ref_sum2 = sum(f.attributes()[0] for f in l2.getFeatures()) ref_sum3 = sum(f.id() for f in l2.getFeatures()) # check we have the same rows self.assertEqual(ref_sum, ref_sum2) # check the id is OK self.assertEqual(ref_sum, ref_sum3) # with two geometry columns query = toPercent("SELECT *,geometry as geom FROM vtab1") l2 = QgsVectorLayer( "?layer_ref=%s&query=%s&uid=OBJECTID&geometry=geom:3:4326" % (l1.id(), query), "vtab", "virtual", QgsVectorLayer.LayerOptions(False)) self.assertEqual(l2.isValid(), True) self.assertEqual(l2.dataProvider().wkbType(), 3) ref_sum2 = sum(f.attributes()[0] for f in l2.getFeatures()) ref_sum3 = sum(f.id() for f in l2.getFeatures()) # check we have the same rows self.assertEqual(ref_sum, ref_sum2) # check the id is OK self.assertEqual(ref_sum, ref_sum3) # with two geometry columns, but no geometry column specified (will take the first) l2 = QgsVectorLayer( "?layer_ref=%s&query=%s&uid=OBJECTID" % (l1.id(), query), "vtab", "virtual", QgsVectorLayer.LayerOptions(False)) self.assertEqual(l2.isValid(), True) self.assertEqual(l2.dataProvider().wkbType(), 6) ref_sum2 = sum(f.attributes()[0] for f in l2.getFeatures()) ref_sum3 = sum(f.id() for f in l2.getFeatures()) # check we have the same rows self.assertEqual(ref_sum, ref_sum2) # check the id is OK self.assertEqual(ref_sum, ref_sum3) # the same, without geometry query = toPercent("SELECT * FROM ww") l2 = QgsVectorLayer( "?layer_ref=%s:ww&query=%s&uid=ObJeCtId&nogeometry" % (l1.id(), query), "vtab", "virtual", QgsVectorLayer.LayerOptions(False)) self.assertEqual(l2.isValid(), True) self.assertEqual(l2.dataProvider().wkbType(), 100) # NoGeometry ref_sum2 = sum(f.attributes()[0] for f in l2.getFeatures()) ref_sum3 = sum(f.id() for f in l2.getFeatures()) self.assertEqual(ref_sum, ref_sum2) self.assertEqual(ref_sum, ref_sum3) # check that it fails when a query has a wrong geometry column l2 = QgsVectorLayer( "?layer_ref=%s&query=%s&geometry=geo" % (l1.id(), query), "vtab", "virtual", QgsVectorLayer.LayerOptions(False)) self.assertEqual(l2.isValid(), False) QgsProject.instance().removeMapLayer(l1.id())
class TestQgsRangeWidget(unittest.TestCase): @classmethod def setUpClass(cls): QgsGui.editorWidgetRegistry().initEditors() def setUp(self): """ create a layer with one feature """ self.layer = QgsVectorLayer( "Point?crs=EPSG:21781&field=fldtxt:string&field=fldint:integer", "addfeat", "memory") pr = self.layer.dataProvider() # NOQA f = QgsFeature() f.setAttributes(["Hello World", 123]) f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(600000, 200000))) def __createRangeWidget(self, allownull=False): """ create a range widget """ reg = QgsGui.editorWidgetRegistry() configWdg = reg.createConfigWidget('Range', self.layer, 1, None) config = configWdg.config() config["Min"] = 0 # if null shall be allowed if allownull: config["AllowNull"] = allownull rangewidget = reg.create('Range', self.layer, 1, config, None, None) return rangewidget def test_range_widget_numbers(self): """ are the numbers being returned correctly """ rangewidget = self.__createRangeWidget() rangewidget.setValue(1) assert rangewidget.value() == 1 rangewidget.setValue(0) assert rangewidget.value() == 0 def test_range_widget_no_null(self): """ are None and NULL being returned as expected """ rangewidget = self.__createRangeWidget() rangewidget.setValue(NULL) assert rangewidget.value() == 0 rangewidget.setValue(None) assert rangewidget.value() == 0 def test_range_widget_null_allowed(self): """ are None and NULL being returned as expected """ rangewidget = self.__createRangeWidget(True) rangewidget.setValue(NULL) self.assertEqual(rangewidget.value(), NULL) rangewidget.setValue(None) self.assertEqual(rangewidget.value(), NULL) rangewidget.setValue(0) self.assertEqual(rangewidget.value(), 0)
def test_sql_field_types(self): query = toPercent( "SELECT 42 as t, 'ok'||'ok' as t2, GeomFromText('') as t3, 3.14*2 as t4" ) l4 = QgsVectorLayer("?query=%s" % query, "tt", "virtual", QgsVectorLayer.LayerOptions(False)) self.assertEqual(l4.isValid(), True) self.assertEqual(l4.dataProvider().fields().at(0).name(), "t") self.assertEqual(l4.dataProvider().fields().at(0).type(), QVariant.Int) self.assertEqual(l4.dataProvider().fields().at(1).name(), "t2") self.assertEqual(l4.dataProvider().fields().at(1).type(), QVariant.String) self.assertEqual(l4.dataProvider().fields().at(2).name(), "t3") self.assertEqual(l4.dataProvider().fields().at(2).type(), QVariant.String) self.assertEqual(l4.dataProvider().fields().at(3).name(), "t4") self.assertEqual(l4.dataProvider().fields().at(3).type(), QVariant.Double) # with type annotations query = toPercent( "SELECT '42.0' as t /*:real*/, 3 as t2/*:text */, GeomFromText('') as t3 /*:multiPoInT:4326 */, 3.14*2 as t4/*:int*/" ) l4 = QgsVectorLayer("?query=%s" % query, "tt", "virtual", QgsVectorLayer.LayerOptions(False)) self.assertEqual(l4.isValid(), True) self.assertEqual(l4.dataProvider().fields().at(0).name(), "t") self.assertEqual(l4.dataProvider().fields().at(0).type(), QVariant.Double) self.assertEqual(l4.dataProvider().fields().at(1).name(), "t2") self.assertEqual(l4.dataProvider().fields().at(1).type(), QVariant.String) self.assertEqual(l4.dataProvider().fields().at(2).name(), "t4") self.assertEqual(l4.dataProvider().fields().at(2).type(), QVariant.Int) self.assertEqual(l4.dataProvider().wkbType(), 4) # multipoint # test value types (!= from declared column types) for f in l4.getFeatures(): self.assertEqual(f.attributes()[0], "42.0") self.assertEqual(f.attributes()[1], 3) self.assertEqual(f.attributes()[2], 6.28) # with type annotations and url options query = toPercent( "SELECT 1 as id /*:int*/, geomfromtext('point(0 0)',4326) as geometry/*:point:4326*/" ) l4 = QgsVectorLayer("?query=%s&geometry=geometry" % query, "tt", "virtual", QgsVectorLayer.LayerOptions(False)) self.assertEqual(l4.isValid(), True) self.assertEqual(l4.dataProvider().wkbType(), 1) # point # with type annotations and url options (2) query = toPercent( "SELECT 1 as id /*:int*/, 3.14 as f, geomfromtext('point(0 0)',4326) as geometry/*:point:4326*/" ) l4 = QgsVectorLayer( "?query=%s&geometry=geometry&field=id:text" % query, "tt", "virtual", QgsVectorLayer.LayerOptions(False)) self.assertEqual(l4.isValid(), True) self.assertEqual(l4.dataProvider().fields().at(0).name(), "id") self.assertEqual(l4.dataProvider().fields().at(0).type(), QVariant.String) self.assertEqual(l4.dataProvider().fields().at(1).name(), "f") self.assertEqual(l4.dataProvider().fields().at(1).type(), QVariant.Double) self.assertEqual(l4.dataProvider().wkbType(), 1) # point
def test_sql2(self): l2 = QgsVectorLayer(os.path.join(self.testDataDir, "france_parts.shp"), "france_parts", "ogr", QgsVectorLayer.LayerOptions(False)) self.assertEqual(l2.isValid(), True) QgsProject.instance().addMapLayer(l2) query = toPercent("SELECT * FROM france_parts") l4 = QgsVectorLayer("?query=%s&uid=ObjectId" % query, "tt", "virtual") self.assertEqual(l4.isValid(), True) self.assertEqual(l4.dataProvider().wkbType(), 6) self.assertEqual(l4.dataProvider().crs().postgisSrid(), 4326) n = 0 r = QgsFeatureRequest(QgsRectangle(-1.677, 49.624, -0.816, 49.086)) for f in l4.getFeatures(r): self.assertEqual(f.geometry() is not None, True) self.assertEqual(f.attributes()[0], 2661) n += 1 self.assertEqual(n, 1) # use uid query = toPercent("SELECT * FROM france_parts") l5 = QgsVectorLayer( "?query=%s&geometry=geometry:polygon:4326&uid=ObjectId" % query, "tt", "virtual") self.assertEqual(l5.isValid(), True) idSum = sum(f.id() for f in l5.getFeatures()) self.assertEqual(idSum, 10659) r = QgsFeatureRequest(2661) idSum2 = sum(f.id() for f in l5.getFeatures(r)) self.assertEqual(idSum2, 2661) r = QgsFeatureRequest() r.setFilterFids([2661, 2664]) self.assertEqual(sum(f.id() for f in l5.getFeatures(r)), 2661 + 2664) # test attribute subset r = QgsFeatureRequest() r.setFlags(QgsFeatureRequest.SubsetOfAttributes) r.setSubsetOfAttributes([1]) s = [(f.id(), f.attributes()[1]) for f in l5.getFeatures(r)] self.assertEqual(sum([x[0] for x in s]), 10659) self.assertEqual(sum([x[1] for x in s]), 3064.0) # test NoGeometry # by request flag r = QgsFeatureRequest() r.setFlags(QgsFeatureRequest.NoGeometry) self.assertEqual(all([not f.hasGeometry() for f in l5.getFeatures(r)]), True) # test subset self.assertEqual(l5.dataProvider().featureCount(), 4) l5.setSubsetString("ObjectId = 2661") idSum2 = sum(f.id() for f in l5.getFeatures(r)) self.assertEqual(idSum2, 2661) self.assertEqual(l5.dataProvider().featureCount(), 1)
def testFidSupport(self): # We do not use @unittest.expectedFailure since the test might actually succeed # on Linux 64bit with GDAL 1.11, where "long" is 64 bit... # GDAL 2.0 is guaranteed to properly support it on all platforms version_num = int(gdal.VersionInfo('VERSION_NUM')) if version_num < GDAL_COMPUTE_VERSION(2, 0, 0): return tmpfile = os.path.join(self.basetestpath, 'testFidSupport.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)) f = ogr.Feature(lyr.GetLayerDefn()) f.SetFID(12) f.SetField(0, 'foo') f.SetField(1, 123) lyr.CreateFeature(f) f = None ds = None vl = QgsVectorLayer('{}'.format(tmpfile), 'test', 'ogr') self.assertEqual(len(vl.fields()), 3) got = [(f.attribute('fid'), f.attribute('strfield'), f.attribute('intfield')) for f in vl.getFeatures()] self.assertEqual(got, [(12, 'foo', 123)]) got = [(f.attribute('fid'), f.attribute('strfield')) for f in vl.getFeatures(QgsFeatureRequest().setFilterExpression( "strfield = 'foo'"))] self.assertEqual(got, [(12, 'foo')]) got = [(f.attribute('fid'), f.attribute('strfield')) for f in vl.getFeatures(QgsFeatureRequest().setFilterExpression( "fid = 12"))] self.assertEqual(got, [(12, 'foo')]) result = [ f['strfield'] for f in vl.dataProvider().getFeatures(QgsFeatureRequest( ).setSubsetOfAttributes(['strfield'], vl.dataProvider().fields())) ] self.assertEqual(result, ['foo']) result = [ f['fid'] for f in vl.dataProvider().getFeatures(QgsFeatureRequest( ).setSubsetOfAttributes(['fid'], vl.dataProvider().fields())) ] self.assertEqual(result, [12]) # Test that when the 'fid' field is not set, regular insertion is done f = QgsFeature() f.setFields(vl.fields()) f.setAttributes([None, 'automatic_id']) (res, out_f) = vl.dataProvider().addFeatures([f]) self.assertEqual(out_f[0].id(), 13) self.assertEqual(out_f[0].attribute('fid'), 13) self.assertEqual(out_f[0].attribute('strfield'), 'automatic_id') # Test that when the 'fid' field is set, it is really used to set the id f = QgsFeature() f.setFields(vl.fields()) f.setAttributes([9876543210, 'bar']) (res, out_f) = vl.dataProvider().addFeatures([f]) self.assertEqual(out_f[0].id(), 9876543210) self.assertEqual(out_f[0].attribute('fid'), 9876543210) self.assertEqual(out_f[0].attribute('strfield'), 'bar') got = [(f.attribute('fid'), f.attribute('strfield')) for f in vl.getFeatures(QgsFeatureRequest().setFilterExpression( "fid = 9876543210"))] self.assertEqual(got, [(9876543210, 'bar')]) self.assertTrue(vl.dataProvider().changeAttributeValues( {9876543210: { 1: 'baz' }})) got = [(f.attribute('fid'), f.attribute('strfield')) for f in vl.getFeatures(QgsFeatureRequest().setFilterExpression( "fid = 9876543210"))] self.assertEqual(got, [(9876543210, 'baz')]) self.assertTrue(vl.dataProvider().changeAttributeValues( {9876543210: { 0: 9876543210, 1: 'baw' }})) got = [(f.attribute('fid'), f.attribute('strfield')) for f in vl.getFeatures(QgsFeatureRequest().setFilterExpression( "fid = 9876543210"))] self.assertEqual(got, [(9876543210, 'baw')]) # Not allowed: changing the fid regular field self.assertTrue(vl.dataProvider().changeAttributeValues( {9876543210: { 0: 12, 1: 'baw' }})) got = [(f.attribute('fid'), f.attribute('strfield')) for f in vl.getFeatures(QgsFeatureRequest().setFilterExpression( "fid = 9876543210"))] self.assertEqual(got, [(9876543210, 'baw')]) # Cannot delete fid self.assertFalse(vl.dataProvider().deleteAttributes([0])) # Delete first "genuine" attribute self.assertTrue(vl.dataProvider().deleteAttributes([1])) got = [(f.attribute('fid'), f.attribute('intfield')) for f in vl.dataProvider().getFeatures( QgsFeatureRequest().setFilterExpression("fid = 12"))] self.assertEqual(got, [(12, 123)])
def _test_operations(self, md, conn): """Common tests""" capabilities = conn.capabilities() # Schema operations if (capabilities & QgsAbstractDatabaseProviderConnection.CreateSchema and capabilities & QgsAbstractDatabaseProviderConnection.Schemas and capabilities & QgsAbstractDatabaseProviderConnection.DropSchema): myNewSchema = self.getUniqueSchemaName('myNewSchema') # Start clean if myNewSchema in conn.schemas(): conn.dropSchema(myNewSchema, True) # Create conn.createSchema(myNewSchema) schemas = conn.schemas() self.assertTrue(myNewSchema in schemas) # Create again with self.assertRaises(QgsProviderConnectionException) as ex: conn.createSchema(myNewSchema) # Test rename if capabilities & QgsAbstractDatabaseProviderConnection.RenameSchema: # Rename myVeryNewSchema = self.getUniqueSchemaName('myVeryNewSchema') conn.renameSchema(myNewSchema, myVeryNewSchema) schemas = conn.schemas() self.assertTrue(myVeryNewSchema in schemas) self.assertFalse(myNewSchema in schemas) conn.renameSchema(myVeryNewSchema, myNewSchema) schemas = conn.schemas() self.assertFalse(myVeryNewSchema in schemas) self.assertTrue(myNewSchema in schemas) # Drop conn.dropSchema(myNewSchema) schemas = conn.schemas() self.assertFalse(myNewSchema in schemas) # UTF8 schema myUtf8NewSchema = self.getUniqueSchemaName('myUtf8\U0001f604NewSchema') conn.createSchema(myUtf8NewSchema) schemas = conn.schemas() conn.dropSchema(myUtf8NewSchema) schemas = conn.schemas() self.assertFalse(myUtf8NewSchema in schemas) # Table operations schema = None if (capabilities & QgsAbstractDatabaseProviderConnection.CreateVectorTable and capabilities & QgsAbstractDatabaseProviderConnection.Tables and capabilities & QgsAbstractDatabaseProviderConnection.DropVectorTable): if capabilities & QgsAbstractDatabaseProviderConnection.CreateSchema: schema = self.getUniqueSchemaName('myNewSchema') conn.createSchema(schema) elif capabilities & QgsAbstractDatabaseProviderConnection.Schemas: schema = self.getUniqueSchemaName(self.defaultSchema) # Start clean if self.myNewTable in self._table_names(conn.tables(schema)): conn.dropVectorTable(schema, self.myNewTable) fields = QgsFields() fields.append(QgsField("string_t", QVariant.String)) fields.append(QgsField("long_t", QVariant.LongLong)) fields.append(QgsField("double_t", QVariant.Double)) fields.append(QgsField("integer_t", QVariant.Int)) fields.append(QgsField("date_t", QVariant.Date)) fields.append(QgsField("datetime_t", QVariant.DateTime)) fields.append(QgsField("time_t", QVariant.Time)) options = {} crs = QgsCoordinateReferenceSystem.fromEpsgId(3857) typ = QgsWkbTypes.LineString # Create conn.createVectorTable(schema, self.myNewTable, fields, typ, crs, True, options) table_names = self._table_names(conn.tables(schema)) self.assertTrue(self.myNewTable in table_names) # Create UTF8 table conn.createVectorTable(schema, self.myUtf8Table, fields, typ, crs, True, options) table_names = self._table_names(conn.tables(schema)) self.assertTrue(self.myNewTable in table_names) self.assertTrue(self.myUtf8Table in table_names) conn.dropVectorTable(schema, self.myUtf8Table) table_names = self._table_names(conn.tables(schema)) self.assertFalse(self.myUtf8Table in table_names) self.assertTrue(self.myNewTable in table_names) # insert something, because otherwise some databases cannot guess if self.providerKey in ['hana', 'mssql', 'oracle']: f = QgsFeature(fields) f.setGeometry(QgsGeometry.fromWkt('LineString (-72.345 71.987, -80 80)')) vl = QgsVectorLayer(conn.tableUri(schema, self.myNewTable), 'vl', self.providerKey) vl.dataProvider().addFeatures([f]) # Check table information table_properties = conn.tables(schema) table_property = self._table_by_name(table_properties, self.myNewTable) self.assertEqual(table_property.maxCoordinateDimensions(), 2) self.assertIsNotNone(table_property) self.assertEqual(table_property.tableName(), self.myNewTable) self.assertEqual(table_property.geometryColumnCount(), 1) self.assertEqual(table_property.geometryColumnTypes()[0].wkbType, QgsWkbTypes.LineString) cols = table_property.geometryColumnTypes() self.assertEqual(cols[0].crs, QgsCoordinateReferenceSystem.fromEpsgId(3857)) self.assertEqual(table_property.defaultName(), self.myNewTable) # Check aspatial tables conn.createVectorTable(schema, 'myNewAspatialTable', fields, QgsWkbTypes.NoGeometry, crs, True, options) table_properties = conn.tables(schema, QgsAbstractDatabaseProviderConnection.Aspatial) table_property = self._table_by_name(table_properties, 'myNewAspatialTable') self.assertIsNotNone(table_property) self.assertEqual(table_property.maxCoordinateDimensions(), 0) self.assertEqual(table_property.tableName(), 'myNewAspatialTable') self.assertEqual(table_property.geometryColumnCount(), 0) self.assertEqual(table_property.geometryColumn(), '') self.assertEqual(table_property.defaultName(), 'myNewAspatialTable') cols = table_property.geometryColumnTypes() # We always return geom col types, even when there is no geometry self.assertEqual(cols[0].wkbType, QgsWkbTypes.NoGeometry) self.assertFalse(cols[0].crs.isValid()) self.assertFalse(table_property.flags() & QgsAbstractDatabaseProviderConnection.Raster) self.assertFalse(table_property.flags() & QgsAbstractDatabaseProviderConnection.Vector) self.assertTrue(table_property.flags() & QgsAbstractDatabaseProviderConnection.Aspatial) # Check executeSql if capabilities & QgsAbstractDatabaseProviderConnection.ExecuteSql: if schema: table = "\"%s\".\"myNewAspatialTable\"" % schema else: table = 'myNewAspatialTable' # MSSQL literal syntax for UTF8 requires 'N' prefix # Oracle date time definition needs some prefix sql = "INSERT INTO %s (\"string_t\", \"long_t\", \"double_t\", \"integer_t\", \"date_t\", \"datetime_t\", \"time_t\") VALUES (%s'QGIS Rocks - \U0001f604', 666, 1.234, 1234, %s '2019-07-08', %s, '12:00:13.00')" % ( table, 'N' if self.providerKey == 'mssql' else '', "DATE" if self.providerKey == 'oracle' else '', "TIMESTAMP '2019-07-08 12:00:12'" if self.providerKey == 'oracle' else "'2019-07-08T12:00:12'" ) res = conn.executeSql(sql) self.assertEqual(res, []) sql = "SELECT \"string_t\", \"long_t\", \"double_t\", \"integer_t\", \"date_t\", \"datetime_t\" FROM %s" % table res = conn.executeSql(sql) expected_date = QtCore.QDate(2019, 7, 8) # GPKG and spatialite have no type for time if self.treat_date_as_string(): expected_date = '2019-07-08' # Oracle DATE type contains date and time and so returns a QDateTime object elif self.providerKey == 'oracle': expected_date = QtCore.QDateTime(QtCore.QDate(2019, 7, 8)) self.assertEqual(res, [['QGIS Rocks - \U0001f604', 666, 1.234, 1234, expected_date, QtCore.QDateTime(2019, 7, 8, 12, 0, 12)]]) # Test column names res = conn.execSql(sql) row_count = res.rowCount() # Some providers do not support rowCount and return -1 if row_count != -1: self.assertEqual(row_count, 1) rows = res.rows() self.assertEqual(rows, [['QGIS Rocks - \U0001f604', 666, 1.234, 1234, expected_date, QtCore.QDateTime(2019, 7, 8, 12, 0, 12)]]) self.assertEqual(res.columns(), ['string_t', 'long_t', 'double_t', 'integer_t', 'date_t', 'datetime_t']) self.assertEqual(res.fetchedRowCount(), 1) # Test iterator old_rows = rows res = conn.execSql(sql) rows = [] self.assertTrue(res.hasNextRow()) for row in res: rows.append(row) self.assertEqual(rows, old_rows) # Java style res = conn.execSql(sql) rows = [] self.assertTrue(res.hasNextRow()) while res.hasNextRow(): rows.append(res.nextRow()) self.assertFalse(res.hasNextRow()) # Test time_t sql = "SELECT \"time_t\" FROM %s" % table res = conn.executeSql(sql) # This does not work in MSSQL and returns a QByteArray, we have no way to know that it is a time # value and there is no way we can convert it. if self.providerKey != 'mssql': self.assertIn(res, ([[QtCore.QTime(12, 0, 13)]], [['12:00:13.00']])) sql = "DELETE FROM %s WHERE \"string_t\" = %s'QGIS Rocks - \U0001f604'" % ( table, 'N' if self.providerKey == 'mssql' else '') res = conn.executeSql(sql) self.assertEqual(res, []) sql = "SELECT \"string_t\", \"integer_t\" FROM %s" % table res = conn.executeSql(sql) self.assertEqual(res, []) # Check that we do NOT get the aspatial table when querying for vectors table_names = self._table_names(conn.tables(schema, QgsAbstractDatabaseProviderConnection.Vector)) self.assertTrue(self.myNewTable in table_names) self.assertFalse('myNewAspatialTable' in table_names) # Query for rasters (in qgis_test schema or no schema for GPKG, spatialite has no support) if self.providerKey not in ('spatialite', 'mssql', 'hana', 'oracle'): table_properties = conn.tables('qgis_test', QgsAbstractDatabaseProviderConnection.Raster) # At least one raster should be there (except for spatialite) self.assertTrue(len(table_properties) >= 1) table_property = table_properties[0] self.assertTrue(table_property.flags() & QgsAbstractDatabaseProviderConnection.Raster) self.assertFalse(table_property.flags() & QgsAbstractDatabaseProviderConnection.Vector) self.assertFalse(table_property.flags() & QgsAbstractDatabaseProviderConnection.Aspatial) if capabilities & QgsAbstractDatabaseProviderConnection.RenameVectorTable: # Rename conn.renameVectorTable(schema, self.myNewTable, self.myVeryNewTable) tables = self._table_names(conn.tables(schema)) self.assertFalse(self.myNewTable in tables) self.assertTrue(self.myVeryNewTable in tables) # Rename it back conn.renameVectorTable(schema, self.myVeryNewTable, self.myNewTable) tables = self._table_names(conn.tables(schema)) self.assertTrue(self.myNewTable in tables) self.assertFalse(self.myVeryNewTable in tables) # Vacuum if capabilities & QgsAbstractDatabaseProviderConnection.Vacuum: conn.vacuum(schema, self.myNewTable) # Spatial index spatial_index_exists = False # we don't initially know if a spatial index exists -- some formats may create them by default, others don't if capabilities & QgsAbstractDatabaseProviderConnection.SpatialIndexExists: spatial_index_exists = conn.spatialIndexExists(schema, self.myNewTable, self.geometryColumnName) if capabilities & QgsAbstractDatabaseProviderConnection.DeleteSpatialIndex: if spatial_index_exists: conn.deleteSpatialIndex(schema, self.myNewTable, self.geometryColumnName) if capabilities & QgsAbstractDatabaseProviderConnection.SpatialIndexExists: self.assertFalse(conn.spatialIndexExists(schema, self.myNewTable, self.geometryColumnName)) if capabilities & (QgsAbstractDatabaseProviderConnection.CreateSpatialIndex | QgsAbstractDatabaseProviderConnection.SpatialIndexExists): options = QgsAbstractDatabaseProviderConnection.SpatialIndexOptions() options.geometryColumnName = self.geometryColumnName if not conn.spatialIndexExists(schema, self.myNewTable, options.geometryColumnName): conn.createSpatialIndex(schema, self.myNewTable, options) self.assertTrue(conn.spatialIndexExists(schema, self.myNewTable, self.geometryColumnName)) # now we know for certain a spatial index exists, let's retry dropping it if capabilities & QgsAbstractDatabaseProviderConnection.DeleteSpatialIndex: conn.deleteSpatialIndex(schema, self.myNewTable, self.geometryColumnName) if capabilities & QgsAbstractDatabaseProviderConnection.SpatialIndexExists: self.assertFalse(conn.spatialIndexExists(schema, self.myNewTable, self.geometryColumnName)) if capabilities & QgsAbstractDatabaseProviderConnection.DropSchema: # Drop schema (should fail) with self.assertRaises(QgsProviderConnectionException) as ex: conn.dropSchema(schema) # Check some column types operations table = self._table_by_name(conn.tables(schema), self.myNewTable) self.assertEqual(len(table.geometryColumnTypes()), 1) ct = table.geometryColumnTypes()[0] self.assertEqual(ct.crs, QgsCoordinateReferenceSystem.fromEpsgId(3857)) self.assertEqual(ct.wkbType, QgsWkbTypes.LineString) # Add a new (existing type) table.addGeometryColumnType(QgsWkbTypes.LineString, QgsCoordinateReferenceSystem.fromEpsgId(3857)) self.assertEqual(len(table.geometryColumnTypes()), 1) ct = table.geometryColumnTypes()[0] self.assertEqual(ct.crs, QgsCoordinateReferenceSystem.fromEpsgId(3857)) self.assertEqual(ct.wkbType, QgsWkbTypes.LineString) # Add a new one table.addGeometryColumnType(QgsWkbTypes.LineString, QgsCoordinateReferenceSystem.fromEpsgId(4326)) self.assertEqual(len(table.geometryColumnTypes()), 2) ct = table.geometryColumnTypes()[0] self.assertEqual(ct.crs, QgsCoordinateReferenceSystem.fromEpsgId(3857)) self.assertEqual(ct.wkbType, QgsWkbTypes.LineString) ct = table.geometryColumnTypes()[1] self.assertEqual(ct.crs, QgsCoordinateReferenceSystem.fromEpsgId(4326)) self.assertEqual(ct.wkbType, QgsWkbTypes.LineString) # Check fields fields = conn.fields(schema, self.myNewTable) for f in ['string_t', 'long_t', 'double_t', 'integer_t', 'date_t', 'datetime_t', 'time_t']: self.assertTrue(f in fields.names()) if capabilities & QgsAbstractDatabaseProviderConnection.AddField: field = QgsField('short_lived_field', QVariant.Int, 'integer') conn.addField(field, schema, self.myNewTable) fields = conn.fields(schema, self.myNewTable) self.assertTrue('short_lived_field' in fields.names()) if capabilities & QgsAbstractDatabaseProviderConnection.DeleteField: conn.deleteField('short_lived_field', schema, self.myNewTable) # This fails on Travis for spatialite, for no particular reason if self.providerKey == 'spatialite' and not os.environ.get('TRAVIS', False): fields = conn.fields(schema, self.myNewTable) self.assertFalse('short_lived_field' in fields.names()) # Drop table conn.dropVectorTable(schema, self.myNewTable) conn.dropVectorTable(schema, 'myNewAspatialTable') table_names = self._table_names(conn.tables(schema)) self.assertFalse(self.myNewTable in table_names) if capabilities & QgsAbstractDatabaseProviderConnection.DropSchema: # Drop schema conn.dropSchema(schema) self.assertFalse(schema in conn.schemas()) conns = md.connections() self.assertTrue(isinstance(list(conns.values())[0], QgsAbstractDatabaseProviderConnection)) # Remove connection spy_deleted = QSignalSpy(md.connectionDeleted) md.deleteConnection('qgis_test1') self.assertEqual(list(md.connections().values()), []) self.assertEqual(len(spy_deleted), 1)
def testUpdateMode(self): """ Test that on-the-fly re-opening in update/read-only mode works """ tmpdir = tempfile.mkdtemp() self.dirs_to_cleanup.append(tmpdir) srcpath = os.path.join(TEST_DATA_DIR, 'provider') for file in glob.glob(os.path.join(srcpath, 'shapefile.*')): shutil.copy(os.path.join(srcpath, file), tmpdir) datasource = os.path.join(tmpdir, 'shapefile.shp') vl = QgsVectorLayer('{}|layerid=0'.format(datasource), 'test', 'ogr') caps = vl.dataProvider().capabilities() self.assertTrue(caps & QgsVectorDataProvider.AddFeatures) self.assertTrue(caps & QgsVectorDataProvider.DeleteFeatures) self.assertTrue(caps & QgsVectorDataProvider.ChangeAttributeValues) self.assertTrue(caps & QgsVectorDataProvider.AddAttributes) self.assertTrue(caps & QgsVectorDataProvider.DeleteAttributes) self.assertTrue(caps & QgsVectorDataProvider.CreateSpatialIndex) self.assertTrue(caps & QgsVectorDataProvider.SelectAtId) self.assertTrue(caps & QgsVectorDataProvider.ChangeGeometries) # self.assertTrue(caps & QgsVectorDataProvider.ChangeFeatures) # We should be really opened in read-only mode even if write capabilities are declared self.assertEqual(vl.dataProvider().property("_debug_open_mode"), "read-only") # Unbalanced call to leaveUpdateMode() self.assertFalse(vl.dataProvider().leaveUpdateMode()) # Test that startEditing() / commitChanges() plays with enterUpdateMode() / leaveUpdateMode() self.assertTrue(vl.startEditing()) self.assertEqual(vl.dataProvider().property("_debug_open_mode"), "read-write") self.assertTrue(vl.dataProvider().isValid()) self.assertTrue(vl.commitChanges()) self.assertEqual(vl.dataProvider().property("_debug_open_mode"), "read-only") self.assertTrue(vl.dataProvider().isValid()) # Manual enterUpdateMode() / leaveUpdateMode() with 2 depths self.assertTrue(vl.dataProvider().enterUpdateMode()) self.assertEqual(vl.dataProvider().property("_debug_open_mode"), "read-write") caps = vl.dataProvider().capabilities() self.assertTrue(caps & QgsVectorDataProvider.AddFeatures) f = QgsFeature() f.setAttributes([200]) f.setGeometry(QgsGeometry.fromWkt('Point (2 49)')) (ret, feature_list) = vl.dataProvider().addFeatures([f]) self.assertTrue(ret) fid = feature_list[0].id() features = [ f_iter for f_iter in vl.getFeatures(QgsFeatureRequest().setFilterFid(fid)) ] values = [f_iter['pk'] for f_iter in features] self.assertEqual(values, [200]) got_geom = [f_iter.geometry() for f_iter in features][0].constGet() self.assertEqual((got_geom.x(), got_geom.y()), (2.0, 49.0)) self.assertTrue(vl.dataProvider().changeGeometryValues( {fid: QgsGeometry.fromWkt('Point (3 50)')})) self.assertTrue(vl.dataProvider().changeAttributeValues( {fid: { 0: 100 }})) features = [ f_iter for f_iter in vl.getFeatures(QgsFeatureRequest().setFilterFid(fid)) ] values = [f_iter['pk'] for f_iter in features] got_geom = [f_iter.geometry() for f_iter in features][0].constGet() self.assertEqual((got_geom.x(), got_geom.y()), (3.0, 50.0)) self.assertTrue(vl.dataProvider().deleteFeatures([fid])) # Check that it has really disappeared osgeo.gdal.PushErrorHandler('CPLQuietErrorHandler') features = [ f_iter for f_iter in vl.getFeatures(QgsFeatureRequest().setFilterFid(fid)) ] osgeo.gdal.PopErrorHandler() self.assertEqual(features, []) self.assertTrue(vl.dataProvider().addAttributes( [QgsField("new_field", QVariant.Int, "integer")])) self.assertTrue(vl.dataProvider().deleteAttributes( [len(vl.dataProvider().fields()) - 1])) self.assertTrue(vl.startEditing()) self.assertEqual(vl.dataProvider().property("_debug_open_mode"), "read-write") self.assertTrue(vl.commitChanges()) self.assertEqual(vl.dataProvider().property("_debug_open_mode"), "read-write") self.assertTrue(vl.dataProvider().enterUpdateMode()) self.assertEqual(vl.dataProvider().property("_debug_open_mode"), "read-write") self.assertTrue(vl.dataProvider().leaveUpdateMode()) self.assertEqual(vl.dataProvider().property("_debug_open_mode"), "read-write") self.assertTrue(vl.dataProvider().leaveUpdateMode()) self.assertEqual(vl.dataProvider().property("_debug_open_mode"), "read-only") # Test that update mode will be implictly enabled if doing an action # that requires update mode (ret, _) = vl.dataProvider().addFeatures([QgsFeature()]) self.assertTrue(ret) self.assertEqual(vl.dataProvider().property("_debug_open_mode"), "read-write")
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 testCreateExpression(self): """ Test creating an expression using the widget""" layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", "test", "memory") # setup value relation parent_layer = QgsVectorLayer("Point?field=stringkey:string&field=intkey:integer&field=display:string", "parent", "memory") f1 = QgsFeature(parent_layer.fields(), 1) f1.setAttributes(['a', 1, 'value a']) f2 = QgsFeature(parent_layer.fields(), 2) f2.setAttributes(['b', 2, 'value b']) f3 = QgsFeature(parent_layer.fields(), 3) f3.setAttributes(['c', 3, 'value c']) parent_layer.dataProvider().addFeatures([f1, f2, f3]) QgsProject.instance().addMapLayers([layer, parent_layer]) config = {"Layer": parent_layer.id(), "Key": 'stringkey', "Value": 'display'} w = QgsValueRelationSearchWidgetWrapper(layer, 0) w.setConfig(config) c = w.widget() # first, set it to the "select value" item c.setCurrentIndex(0) self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.IsNull), '"fldtxt" IS NULL') self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.IsNotNull), '"fldtxt" IS NOT NULL') self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.EqualTo), '') self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.NotEqualTo), '') c.setCurrentIndex(1) self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.IsNull), '"fldtxt" IS NULL') self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.IsNotNull), '"fldtxt" IS NOT NULL') self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.EqualTo), '"fldtxt"=\'a\'') self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.NotEqualTo), '"fldtxt"<>\'a\'') c.setCurrentIndex(2) self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.IsNull), '"fldtxt" IS NULL') self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.IsNotNull), '"fldtxt" IS NOT NULL') self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.EqualTo), '"fldtxt"=\'b\'') self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.NotEqualTo), '"fldtxt"<>\'b\'') # try with numeric field w = QgsValueRelationSearchWidgetWrapper(layer, 1) config['Key'] = 'intkey' w.setConfig(config) c = w.widget() c.setCurrentIndex(c.findText('value c')) self.assertEqual(c.currentIndex(), 3) self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.IsNull), '"fldint" IS NULL') self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.IsNotNull), '"fldint" IS NOT NULL') self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.EqualTo), '"fldint"=3') self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.NotEqualTo), '"fldint"<>3') # try with allow null set w = QgsValueRelationSearchWidgetWrapper(layer, 1) config['AllowNull'] = True w.setConfig(config) c = w.widget() c.setCurrentIndex(c.findText('value c')) self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.IsNull), '"fldint" IS NULL') self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.IsNotNull), '"fldint" IS NOT NULL') self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.EqualTo), '"fldint"=3') self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.NotEqualTo), '"fldint"<>3') # try with line edit w = QgsValueRelationSearchWidgetWrapper(layer, 1) config['UseCompleter'] = True w.setConfig(config) l = w.widget() l.setText('value b') self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.IsNull), '"fldint" IS NULL') self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.IsNotNull), '"fldint" IS NOT NULL') self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.EqualTo), '"fldint"=2') self.assertEqual(w.createExpression(QgsSearchWidgetWrapper.NotEqualTo), '"fldint"<>2')
def testRefreshOnTimer(self): """ test that map canvas refreshes with auto refreshing layers """ canvas = QgsMapCanvas() canvas.setDestinationCrs(QgsCoordinateReferenceSystem(4326)) canvas.setFrameStyle(0) canvas.resize(600, 400) self.assertEqual(canvas.width(), 600) self.assertEqual(canvas.height(), 400) layer = QgsVectorLayer("Polygon?crs=epsg:4326&field=fldtxt:string", "layer", "memory") canvas.setLayers([layer]) canvas.setExtent(QgsRectangle(10, 30, 20, 35)) canvas.show() # need to wait until first redraw can occur (note that we first need to wait till drawing starts!) while not canvas.isDrawing(): app.processEvents() canvas.waitWhileRendering() self.assertTrue( self.canvasImageCheck('empty_canvas', 'empty_canvas', canvas)) # add polygon to layer f = QgsFeature() f.setGeometry(QgsGeometry.fromRect(QgsRectangle(5, 25, 25, 45))) self.assertTrue(layer.dataProvider().addFeatures([f])) # set auto refresh on layer layer.setAutoRefreshInterval(100) layer.setAutoRefreshEnabled(True) timeout = time.time() + 1 # expect canvas to auto refresh... while not canvas.isDrawing(): app.processEvents() self.assertTrue(time.time() < timeout) while canvas.isDrawing(): app.processEvents() self.assertTrue(time.time() < timeout) # add a polygon to layer f = QgsFeature() f.setGeometry(QgsGeometry.fromRect(QgsRectangle(5, 25, 25, 45))) self.assertTrue(layer.dataProvider().addFeatures([f])) # wait for canvas auto refresh while not canvas.isDrawing(): app.processEvents() self.assertTrue(time.time() < timeout) while canvas.isDrawing(): app.processEvents() self.assertTrue(time.time() < timeout) # now canvas should look different... self.assertFalse( self.canvasImageCheck('empty_canvas', 'empty_canvas', canvas)) # switch off auto refresh layer.setAutoRefreshEnabled(False) timeout = time.time() + 0.5 while time.time() < timeout: # messy, but only way to check that canvas redraw doesn't occur self.assertFalse(canvas.isDrawing())
def legend_test(self): self.atlas_map.setAtlasDriven(True) self.atlas_map.setAtlasScalingMode(QgsLayoutItemMap.Auto) self.atlas_map.setAtlasMargin(0.10) # add a point layer ptLayer = QgsVectorLayer( "Point?crs=epsg:4326&field=attr:int(1)&field=label:string(20)", "points", "memory") pr = ptLayer.dataProvider() f1 = QgsFeature(1) f1.initAttributes(2) f1.setAttribute(0, 1) f1.setAttribute(1, "Test label 1") f1.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(-0.638, 48.954))) f2 = QgsFeature(2) f2.initAttributes(2) f2.setAttribute(0, 2) f2.setAttribute(1, "Test label 2") f2.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(-1.682, 48.550))) pr.addFeatures([f1, f2]) # categorized symbology r = QgsCategorizedSymbolRenderer("attr", [ QgsRendererCategory( 1, QgsMarkerSymbol.createSimple({ "color": "255,0,0", 'outline_color': 'black' }), "red"), QgsRendererCategory( 2, QgsMarkerSymbol.createSimple({ "color": "0,0,255", 'outline_color': 'black' }), "blue") ]) ptLayer.setRenderer(r) QgsProject.instance().addMapLayer(ptLayer) # add the point layer to the map settings layers = self.layers layers = [ptLayer] + layers self.atlas_map.setLayers(layers) self.overview.setLayers(layers) # add a legend legend = QgsLayoutItemLegend(self.layout) legend.attemptMove(QgsLayoutPoint(200, 100)) # sets the legend filter parameter legend.setLinkedMap(self.atlas_map) legend.setLegendFilterOutAtlas(True) self.layout.addLayoutItem(legend) self.atlas.beginRender() self.atlas.seekTo(0) self.mLabel1.adjustSizeToText() checker = QgsLayoutChecker('atlas_legend', self.layout) myTestResult, myMessage = checker.testLayout() self.report += checker.report() self.assertTrue(myTestResult, myMessage) self.atlas.endRender() # restore state self.atlas_map.setLayers([layers[1]]) self.layout.removeLayoutItem(legend) QgsProject.instance().removeMapLayer(ptLayer.id())
def testRenderer(self): """ Test that renderer is correctly acquired from provider """ endpoint = self.basetestpath + '/renderer_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","geometryType":"esriGeometryPoint","copyrightText":"not copyright","parentLayer":{"id":2,"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":"OBJECTID","type":"esriFieldTypeOID","alias":"OBJECTID","domain":null}], "relationships":[],"canModifyLayer":false,"canScaleSymbols":false,"hasLabels":false, "capabilities":"Map,Query,Data","maxRecordCount":1000,"supportsStatistics":true, "supportsAdvancedQueries":true,"supportedQueryFormats":"JSON, AMF", "drawingInfo":{"renderer": { "type": "uniqueValue", "field1": "COUNTRY", "uniqueValueInfos": [ { "value": "US", "symbol": { "color": [ 253, 127, 111, 255 ], "size": 12.75, "angle": 0, "xoffset": 0, "yoffset": 0, "type": "esriSMS", "style": "esriSMSCircle", "outline": { "color": [ 26, 26, 26, 255 ], "width": 0.75, "type": "esriSLS", "style": "esriSLSSolid" } }, "label": "US" }, { "value": "Canada", "symbol": { "color": [ 126, 176, 213, 255 ], "size": 12.75, "angle": 0, "xoffset": 0, "yoffset": 0, "type": "esriSMS", "style": "esriSMSCircle", "outline": { "color": [ 26, 26, 26, 255 ], "width": 0.75, "type": "esriSLS", "style": "esriSLSSolid" } }, "label": "Canada" }]}}, "ownershipBasedAccessControlForFeatures":{"allowOthersToQuery":true},"useStandardizedQueries":true}""" .encode('UTF-8')) with open( sanitize( endpoint, '/query?f=json_where=OBJECTID=OBJECTID_returnIdsOnly=true' ), 'wb') as f: f.write(""" { "objectIdFieldName": "OBJECTID", "objectIds": [ 1 ] } """.encode('UTF-8')) # Create test layer vl = QgsVectorLayer("url='http://" + endpoint + "' crs='epsg:4326'", 'test', 'arcgisfeatureserver') self.assertTrue(vl.isValid()) self.assertIsNotNone(vl.dataProvider().createRenderer()) self.assertIsInstance(vl.renderer(), QgsCategorizedSymbolRenderer) self.assertEqual(len(vl.renderer().categories()), 2) self.assertEqual(vl.renderer().categories()[0].value(), 'US') self.assertEqual(vl.renderer().categories()[1].value(), 'Canada')
def testOverwriteLayer(self): """Tests writing a layer with a field value converter.""" ml = QgsVectorLayer('Point?field=firstfield:int', 'test', 'memory') provider = ml.dataProvider() ft = QgsFeature() ft.setAttributes([1]) provider.addFeatures([ft]) options = QgsVectorFileWriter.SaveVectorOptions() options.driverName = 'GPKG' options.layerName = 'test' filename = '/vsimem/out.gpkg' write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( ml, filename, options) self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) ds = ogr.Open(filename, update=1) lyr = ds.GetLayerByName('test') self.assertIsNotNone(lyr) f = lyr.GetNextFeature() self.assertEqual(f['firstfield'], 1) ds.CreateLayer('another_layer') del f del lyr del ds caps = QgsVectorFileWriter.editionCapabilities(filename) self.assertTrue((caps & QgsVectorFileWriter.CanAddNewLayer)) self.assertTrue((caps & QgsVectorFileWriter.CanAppendToExistingLayer)) self.assertTrue( (caps & QgsVectorFileWriter.CanAddNewFieldsToExistingLayer)) self.assertTrue((caps & QgsVectorFileWriter.CanDeleteLayer)) self.assertTrue(QgsVectorFileWriter.targetLayerExists( filename, 'test')) self.assertFalse( QgsVectorFileWriter.areThereNewFieldsToCreate( filename, 'test', ml, [0])) # Test CreateOrOverwriteLayer ml = QgsVectorLayer('Point?field=firstfield:int', 'test', 'memory') provider = ml.dataProvider() ft = QgsFeature() ft.setAttributes([2]) provider.addFeatures([ft]) options = QgsVectorFileWriter.SaveVectorOptions() options.driverName = 'GPKG' options.layerName = 'test' options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteLayer filename = '/vsimem/out.gpkg' write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( ml, filename, options) self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) ds = ogr.Open(filename) lyr = ds.GetLayerByName('test') self.assertIsNotNone(lyr) f = lyr.GetNextFeature() self.assertEqual(f['firstfield'], 2) # another_layer should still exist self.assertIsNotNone(ds.GetLayerByName('another_layer')) del f del lyr del ds # Test CreateOrOverwriteFile ml = QgsVectorLayer('Point?field=firstfield:int', 'test', 'memory') provider = ml.dataProvider() ft = QgsFeature() ft.setAttributes([3]) provider.addFeatures([ft]) options = QgsVectorFileWriter.SaveVectorOptions() options.driverName = 'GPKG' options.layerName = 'test' filename = '/vsimem/out.gpkg' write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( ml, filename, options) self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) ds = ogr.Open(filename) lyr = ds.GetLayerByName('test') self.assertIsNotNone(lyr) f = lyr.GetNextFeature() self.assertEqual(f['firstfield'], 3) # another_layer should no longer exist self.assertIsNone(ds.GetLayerByName('another_layer')) del f del lyr del ds # Test AppendToLayerNoNewFields ml = QgsVectorLayer('Point?field=firstfield:int&field=secondfield:int', 'test', 'memory') provider = ml.dataProvider() ft = QgsFeature() ft.setAttributes([4, -10]) provider.addFeatures([ft]) self.assertTrue( QgsVectorFileWriter.areThereNewFieldsToCreate( filename, 'test', ml, [0, 1])) options = QgsVectorFileWriter.SaveVectorOptions() options.driverName = 'GPKG' options.layerName = 'test' options.actionOnExistingFile = QgsVectorFileWriter.AppendToLayerNoNewFields filename = '/vsimem/out.gpkg' write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( ml, filename, options) self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) ds = ogr.Open(filename) lyr = ds.GetLayerByName('test') self.assertEqual(lyr.GetLayerDefn().GetFieldCount(), 1) self.assertIsNotNone(lyr) f = lyr.GetNextFeature() self.assertEqual(f['firstfield'], 3) f = lyr.GetNextFeature() self.assertEqual(f['firstfield'], 4) del f del lyr del ds # Test AppendToLayerAddFields ml = QgsVectorLayer('Point?field=firstfield:int&field=secondfield:int', 'test', 'memory') provider = ml.dataProvider() ft = QgsFeature() ft.setAttributes([5, -1]) provider.addFeatures([ft]) self.assertTrue( QgsVectorFileWriter.areThereNewFieldsToCreate( filename, 'test', ml, [0, 1])) options = QgsVectorFileWriter.SaveVectorOptions() options.driverName = 'GPKG' options.layerName = 'test' options.actionOnExistingFile = QgsVectorFileWriter.AppendToLayerAddFields filename = '/vsimem/out.gpkg' write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( ml, filename, options) self.assertEqual(write_result, QgsVectorFileWriter.NoError, error_message) ds = ogr.Open(filename) lyr = ds.GetLayerByName('test') self.assertEqual(lyr.GetLayerDefn().GetFieldCount(), 2) self.assertIsNotNone(lyr) f = lyr.GetNextFeature() self.assertEqual(f['firstfield'], 3) if hasattr(f, "IsFieldSetAndNotNull"): # GDAL >= 2.2 self.assertFalse(f.IsFieldSetAndNotNull('secondfield')) else: self.assertFalse(f.IsFieldSet('secondfield')) f = lyr.GetNextFeature() self.assertEqual(f['firstfield'], 4) if hasattr(f, "IsFieldSetAndNotNull"): self.assertFalse(f.IsFieldSetAndNotNull('secondfield')) else: self.assertFalse(f.IsFieldSet('secondfield')) f = lyr.GetNextFeature() self.assertEqual(f['firstfield'], 5) self.assertEqual(f['secondfield'], -1) del f del lyr del ds gdal.Unlink(filename)
def testDuplicateFeature(self): """ test duplicating a feature """ project = QgsProject().instance() # LAYERS # - add first layer (parent) layer1 = QgsVectorLayer("Point?field=fldtxt:string&field=pkid:integer", "parentlayer", "memory") # > check first layer (parent) self.assertTrue(layer1.isValid()) # - set the value for the copy layer1.setDefaultValueDefinition(1, QgsDefaultValue("rand(1000,2000)")) # > check first layer (parent) self.assertTrue(layer1.isValid()) # - add second layer (child) layer2 = QgsVectorLayer( "Point?field=fldtxt:string&field=id:integer&field=foreign_key:integer", "childlayer", "memory") # > check second layer (child) self.assertTrue(layer2.isValid()) # - add layers project.addMapLayers([layer1, layer2]) # FEATURES # - add 2 features on layer1 (parent) l1f1orig = QgsFeature() l1f1orig.setFields(layer1.fields()) l1f1orig.setAttributes(["F_l1f1", 100]) l1f2orig = QgsFeature() l1f2orig.setFields(layer1.fields()) l1f2orig.setAttributes(["F_l1f2", 101]) # > check by adding features self.assertTrue(layer1.dataProvider().addFeatures([l1f1orig, l1f2orig])) # add 4 features on layer2 (child) l2f1orig = QgsFeature() l2f1orig.setFields(layer2.fields()) l2f1orig.setAttributes(["F_l2f1", 201, 100]) l2f2orig = QgsFeature() l2f2orig.setFields(layer2.fields()) l2f2orig.setAttributes(["F_l2f2", 202, 100]) l2f3orig = QgsFeature() l2f3orig.setFields(layer2.fields()) l2f3orig.setAttributes(["F_l2f3", 203, 100]) l2f4orig = QgsFeature() l2f4orig.setFields(layer2.fields()) l2f4orig.setAttributes(["F_l2f4", 204, 101]) # > check by adding features self.assertTrue(layer2.dataProvider().addFeatures( [l2f1orig, l2f2orig, l2f3orig, l2f4orig])) # RELATION # - create the relationmanager relMgr = project.relationManager() # - create the relation rel = QgsRelation() rel.setId('rel1') rel.setName('childrel') rel.setReferencingLayer(layer2.id()) rel.setReferencedLayer(layer1.id()) rel.addFieldPair('foreign_key', 'pkid') rel.setStrength(QgsRelation.Composition) # > check relation self.assertTrue(rel.isValid()) # - add relation relMgr.addRelation(rel) # > check if referencedLayer is layer1 self.assertEqual(rel.referencedLayer(), layer1) # > check if referencingLayer is layer2 self.assertEqual(rel.referencingLayer(), layer2) # > check if the layers are correct in relation when loading from relationManager relations = project.relationManager().relations() relation = relations[list(relations.keys())[0]] # > check if referencedLayer is layer1 self.assertEqual(relation.referencedLayer(), layer1) # > check if referencingLayer is layer2 self.assertEqual(relation.referencingLayer(), layer2) # > check the relatedfeatures ''' # testoutput 1 print( "\nAll Features and relations") featit=layer1.getFeatures() f=QgsFeature() while featit.nextFeature(f): print( f.attributes()) childFeature = QgsFeature() relfeatit=rel.getRelatedFeatures(f) while relfeatit.nextFeature(childFeature): print( childFeature.attributes() ) print( "\n--------------------------") print( "\nFeatures on layer1") for f in layer1.getFeatures(): print( f.attributes() ) print( "\nFeatures on layer2") for f in layer2.getFeatures(): print( f.attributes() ) ''' # DUPLICATION # - duplicate feature l1f1orig with children layer1.startEditing() results = QgsVectorLayerUtils.duplicateFeature(layer1, l1f1orig, project, 0) # > check if name is name of duplicated (pk is different) result_feature = results[0] self.assertEqual(result_feature.attribute('fldtxt'), l1f1orig.attribute('fldtxt')) # > check duplicated child layer result_layer = results[1].layers()[0] self.assertEqual(result_layer, layer2) # > check duplicated child features self.assertTrue(results[1].duplicatedFeatures(result_layer)) ''' # testoutput 2 print( "\nFeatures on layer1 (after duplication)") for f in layer1.getFeatures(): print( f.attributes() ) print( "\nFeatures on layer2 (after duplication)") for f in layer2.getFeatures(): print( f.attributes() ) print( "\nAll Features and relations") featit=layer1.getFeatures() f=QgsFeature() while featit.nextFeature(f): print( f.attributes()) childFeature = QgsFeature() relfeatit=rel.getRelatedFeatures(f) while relfeatit.nextFeature(childFeature): print( childFeature.attributes() ) ''' # > compare text of parent feature self.assertEqual(result_feature.attribute('fldtxt'), l1f1orig.attribute('fldtxt')) # - create copyValueList childFeature = QgsFeature() relfeatit = rel.getRelatedFeatures(result_feature) copyValueList = [] while relfeatit.nextFeature(childFeature): copyValueList.append(childFeature.attribute('fldtxt')) # - create origValueList childFeature = QgsFeature() relfeatit = rel.getRelatedFeatures(l1f1orig) origValueList = [] while relfeatit.nextFeature(childFeature): origValueList.append(childFeature.attribute('fldtxt')) # - check if the ids are still the same self.assertEqual(copyValueList, origValueList)
def testSetOutputCrs(self): w = qgis.gui.QgsExtentGroupBox() w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:4326')) w.setCurrentExtent(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem('epsg:4326')) w.setOutputExtentFromCurrent() self.assertEqual(w.outputExtent(), QgsRectangle(1, 2, 3, 4)) # with reprojection w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:3785')) self.assertEqual( w.outputExtent().toString(4), QgsRectangle(111319.4908, 222684.2085, 333958.4724, 445640.1097).toString(4)) # change CRS back w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:4326')) # extent should be back to current - not a reprojection of the reprojected bounds self.assertEqual(w.outputExtent().toString(20), QgsRectangle(1, 2, 3, 4).toString(20)) # repeat, this time using original extents w = qgis.gui.QgsExtentGroupBox() w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:4326')) w.setOriginalExtent(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem('epsg:4326')) w.setOutputExtentFromOriginal() self.assertEqual(w.outputExtent(), QgsRectangle(1, 2, 3, 4)) # with reprojection w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:3785')) self.assertEqual( w.outputExtent().toString(4), QgsRectangle(111319.4908, 222684.2085, 333958.4724, 445640.1097).toString(4)) # change CRS back w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:4326')) # extent should be back to original - not a reprojection of the reprojected bounds self.assertEqual(w.outputExtent().toString(20), QgsRectangle(1, 2, 3, 4).toString(20)) # repeat, this time using layer extent layer = QgsVectorLayer("Polygon?crs=4326", 'memory', 'memory') self.assertTrue(layer.isValid()) f = QgsFeature() f.setGeometry( QgsGeometry.fromWkt('Polygon((1 2, 3 2, 3 4, 1 4, 1 2))')) layer.dataProvider().addFeatures([f]) QgsProject.instance().addMapLayer(layer) w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:4326')) w.setOutputExtentFromLayer(layer) self.assertEqual(w.outputExtent(), QgsRectangle(1, 2, 3, 4)) w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:3785')) self.assertEqual( w.outputExtent().toString(4), QgsRectangle(111319.4908, 222684.2085, 333958.4724, 445640.1097).toString(4)) # change CRS back w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:4326')) # extent should be back to original - not a reprojection of the reprojected bounds self.assertEqual(w.outputExtent().toString(20), QgsRectangle(1, 2, 3, 4).toString(20)) # custom extent w = qgis.gui.QgsExtentGroupBox() w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:4326')) w.setOutputExtentFromUser(QgsRectangle(1, 2, 3, 4), QgsCoordinateReferenceSystem('epsg:4326')) self.assertEqual(w.outputExtent(), QgsRectangle(1, 2, 3, 4)) # with reprojection w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:3785')) self.assertEqual( w.outputExtent().toString(4), QgsRectangle(111319.4908, 222684.2085, 333958.4724, 445640.1097).toString(4)) # change CRS back w.setOutputCrs(QgsCoordinateReferenceSystem('epsg:4326')) # in this case we can't retrieve the original user extent in 4326, so we have a reprojection of the reprojected bounds # just test this by restricting the test to 4 decimals self.assertEqual(w.outputExtent().toString(4), QgsRectangle(1, 2, 3, 4).toString(4))
def testStyle(self): # First test with invalid URI vl = QgsVectorLayer('/idont/exist.gpkg', 'test', 'ogr') self.assertFalse( vl.dataProvider().isSaveAndLoadStyleToDatabaseSupported()) related_count, idlist, namelist, desclist, errmsg = vl.listStylesInDatabase( ) self.assertEqual(related_count, -1) self.assertEqual(idlist, []) self.assertEqual(namelist, []) self.assertEqual(desclist, []) self.assertNotEqual(errmsg, "") qml, errmsg = vl.getStyleFromDatabase("1") self.assertEqual(qml, "") self.assertNotEqual(errmsg, "") qml, success = vl.loadNamedStyle('/idont/exist.gpkg') self.assertFalse(success) errorMsg = vl.saveStyleToDatabase("name", "description", False, "") self.assertNotEqual(errorMsg, "") # Now with valid URI tmpfile = os.path.join(self.basetestpath, 'testStyle.gpkg') ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) lyr = ds.CreateLayer('test', geom_type=ogr.wkbMultiPolygon) lyr.CreateField(ogr.FieldDefn('foo', ogr.OFTString)) f = ogr.Feature(lyr.GetLayerDefn()) f['foo'] = 'bar' lyr.CreateFeature(f) f = None lyr = ds.CreateLayer('test2', geom_type=ogr.wkbMultiPolygon) lyr.CreateField(ogr.FieldDefn('foo', ogr.OFTString)) f = ogr.Feature(lyr.GetLayerDefn()) f['foo'] = 'bar' lyr.CreateFeature(f) f = None ds = None vl = QgsVectorLayer('{}|layername=test'.format(tmpfile), 'test', 'ogr') self.assertTrue(vl.isValid()) vl2 = QgsVectorLayer('{}|layername=test2'.format(tmpfile), 'test2', 'ogr') self.assertTrue(vl2.isValid()) self.assertTrue( vl.dataProvider().isSaveAndLoadStyleToDatabaseSupported()) related_count, idlist, namelist, desclist, errmsg = vl.listStylesInDatabase( ) self.assertEqual(related_count, 0) self.assertEqual(idlist, []) self.assertEqual(namelist, []) self.assertEqual(desclist, []) self.assertNotEqual(errmsg, "") qml, errmsg = vl.getStyleFromDatabase("not_existing") self.assertEqual(qml, "") self.assertNotEqual(errmsg, "") qml, success = vl.loadNamedStyle('{}|layerid=0'.format(tmpfile)) self.assertFalse(success) errorMsg = vl.saveStyleToDatabase("name", "description", False, "") self.assertEqual(errorMsg, "") qml, errmsg = vl.getStyleFromDatabase("not_existing") self.assertEqual(qml, "") self.assertNotEqual(errmsg, "") related_count, idlist, namelist, desclist, errmsg = vl.listStylesInDatabase( ) self.assertEqual(related_count, 1) self.assertEqual(errmsg, "") self.assertEqual(idlist, ['1']) self.assertEqual(namelist, ['name']) self.assertEqual(desclist, ['description']) qml, errmsg = vl.getStyleFromDatabase("100") self.assertEqual(qml, "") self.assertNotEqual(errmsg, "") qml, errmsg = vl.getStyleFromDatabase("1") self.assertTrue(qml.startswith('<!DOCTYPE qgis'), qml) self.assertEqual(errmsg, "") # Try overwrite it but simulate answer no settings = QgsSettings() settings.setValue("/qgis/overwriteStyle", False) errorMsg = vl.saveStyleToDatabase("name", "description_bis", False, "") self.assertNotEqual(errorMsg, "") related_count, idlist, namelist, desclist, errmsg = vl.listStylesInDatabase( ) self.assertEqual(related_count, 1) self.assertEqual(errmsg, "") self.assertEqual(idlist, ['1']) self.assertEqual(namelist, ['name']) self.assertEqual(desclist, ['description']) # Try overwrite it and simulate answer yes settings = QgsSettings() settings.setValue("/qgis/overwriteStyle", True) errorMsg = vl.saveStyleToDatabase("name", "description_bis", False, "") self.assertEqual(errorMsg, "") related_count, idlist, namelist, desclist, errmsg = vl.listStylesInDatabase( ) self.assertEqual(related_count, 1) self.assertEqual(errmsg, "") self.assertEqual(idlist, ['1']) self.assertEqual(namelist, ['name']) self.assertEqual(desclist, ['description_bis']) errorMsg = vl2.saveStyleToDatabase("name_test2", "description_test2", True, "") self.assertEqual(errorMsg, "") errorMsg = vl.saveStyleToDatabase("name2", "description2", True, "") self.assertEqual(errorMsg, "") errorMsg = vl.saveStyleToDatabase("name3", "description3", True, "") self.assertEqual(errorMsg, "") related_count, idlist, namelist, desclist, errmsg = vl.listStylesInDatabase( ) self.assertEqual(related_count, 3) self.assertEqual(errmsg, "") self.assertEqual(idlist, ['1', '3', '4', '2']) self.assertEqual(namelist, ['name', 'name2', 'name3', 'name_test2']) self.assertEqual( desclist, ['description_bis', 'description2', 'description3', 'name_test2']) # Check that layers_style table is not list in subLayers() vl = QgsVectorLayer(tmpfile, 'test', 'ogr') sublayers = vl.dataProvider().subLayers() self.assertEqual(len(sublayers), 2, sublayers)
def testExportFeatureRelations(self): """ Test exporting a feature with relations """ #parent layer parent = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer&field=foreignkey:integer", "parent", "memory") pr = parent.dataProvider() pf1 = QgsFeature() pf1.setFields(parent.fields()) pf1.setAttributes(["test1", 67, 123]) pf2 = QgsFeature() pf2.setFields(parent.fields()) pf2.setAttributes(["test2", 68, 124]) assert pr.addFeatures([pf1, pf2]) #child layer child = QgsVectorLayer( "Point?field=x:string&field=y:integer&field=z:integer", "referencedlayer", "memory") pr = child.dataProvider() f1 = QgsFeature() f1.setFields(child.fields()) f1.setAttributes(["foo", 123, 321]) f2 = QgsFeature() f2.setFields(child.fields()) f2.setAttributes(["bar", 123, 654]) f3 = QgsFeature() f3.setFields(child.fields()) f3.setAttributes(["foobar", 124, 554]) assert pr.addFeatures([f1, f2, f3]) QgsMapLayerRegistry.instance().addMapLayers([child, parent]) rel = QgsRelation() rel.setRelationId('rel1') rel.setRelationName('relation one') rel.setReferencingLayer(child.id()) rel.setReferencedLayer(parent.id()) rel.addFieldPair('y', 'foreignkey') QgsProject.instance().relationManager().addRelation(rel) exporter = QgsJSONExporter() exporter.setVectorLayer(parent) self.assertEqual(exporter.vectorLayer(), parent) exporter.setIncludeRelated(True) self.assertEqual(exporter.includeRelated(), True) expected = """{ "type":"Feature", "id":0, "geometry":null, "properties":{ "fldtxt":"test1", "fldint":67, "foreignkey":123, "relation one":[{"x":"foo", "y":123, "z":321}, {"x":"bar", "y":123, "z":654}] } }""" self.assertEqual(exporter.exportFeature(pf1), expected) expected = """{ "type":"Feature", "id":0, "geometry":null, "properties":{ "fldtxt":"test2", "fldint":68, "foreignkey":124, "relation one":[{"x":"foobar", "y":124, "z":554}] } }""" self.assertEqual(exporter.exportFeature(pf2), expected) # test excluding related attributes exporter.setIncludeRelated(False) self.assertEqual(exporter.includeRelated(), False) expected = """{ "type":"Feature", "id":0, "geometry":null, "properties":{ "fldtxt":"test2", "fldint":68, "foreignkey":124 } }""" self.assertEqual(exporter.exportFeature(pf2), expected) # test without vector layer set exporter.setIncludeRelated(True) exporter.setVectorLayer(None) expected = """{ "type":"Feature", "id":0, "geometry":null, "properties":{ "fldtxt":"test2", "fldint":68, "foreignkey":124 } }""" self.assertEqual(exporter.exportFeature(pf2), expected)
def testNumeric(self): """ Test calculation of aggregates on numeric fields""" layer = QgsVectorLayer("Point?field=fldint:integer&field=flddbl:double", "layer", "memory") pr = layer.dataProvider() # must be same length: int_values = [4, 2, 3, 2, 5, None, 8] dbl_values = [5.5, 3.5, 7.5, 5, 9, None, 7] self.assertEqual(len(int_values), len(dbl_values)) features = [] for i in range(len(int_values)): f = QgsFeature() f.setFields(layer.fields()) f.setAttributes([int_values[i], dbl_values[i]]) features.append(f) assert pr.addFeatures(features) tests = [[QgsAggregateCalculator.Count, 'fldint', 6], [QgsAggregateCalculator.Count, 'flddbl', 6], [QgsAggregateCalculator.Sum, 'fldint', 24], [QgsAggregateCalculator.Sum, 'flddbl', 37.5], [QgsAggregateCalculator.Mean, 'fldint', 4], [QgsAggregateCalculator.Mean, 'flddbl', 6.25], [QgsAggregateCalculator.StDev, 'fldint', 2.0816], [QgsAggregateCalculator.StDev, 'flddbl', 1.7969], [QgsAggregateCalculator.StDevSample, 'fldint', 2.2803], [QgsAggregateCalculator.StDevSample, 'flddbl', 1.9685], [QgsAggregateCalculator.Min, 'fldint', 2], [QgsAggregateCalculator.Min, 'flddbl', 3.5], [QgsAggregateCalculator.Max, 'fldint', 8], [QgsAggregateCalculator.Max, 'flddbl', 9], [QgsAggregateCalculator.Range, 'fldint', 6], [QgsAggregateCalculator.Range, 'flddbl', 5.5], [QgsAggregateCalculator.Median, 'fldint', 3.5], [QgsAggregateCalculator.Median, 'flddbl', 6.25], [QgsAggregateCalculator.CountDistinct, 'fldint', 5], [QgsAggregateCalculator.CountDistinct, 'flddbl', 6], [QgsAggregateCalculator.CountMissing, 'fldint', 1], [QgsAggregateCalculator.CountMissing, 'flddbl', 1], [QgsAggregateCalculator.FirstQuartile, 'fldint', 2], [QgsAggregateCalculator.FirstQuartile, 'flddbl', 5.0], [QgsAggregateCalculator.ThirdQuartile, 'fldint', 5.0], [QgsAggregateCalculator.ThirdQuartile, 'flddbl', 7.5], [QgsAggregateCalculator.InterQuartileRange, 'fldint', 3.0], [QgsAggregateCalculator.InterQuartileRange, 'flddbl', 2.5], ] agg = QgsAggregateCalculator(layer) for t in tests: val, ok = agg.calculate(t[0], t[1]) self.assertTrue(ok) if isinstance(t[2], int): self.assertEqual(val, t[2]) else: self.assertAlmostEqual(val, t[2], 3) # bad tests - the following stats should not be calculatable for numeric fields for t in [QgsAggregateCalculator.StringMinimumLength, QgsAggregateCalculator.StringMaximumLength]: val, ok = agg.calculate(t, 'fldint') self.assertFalse(ok) val, ok = agg.calculate(t, 'flddbl') self.assertFalse(ok)
def testCreateFeature(self): """ test creating a feature respecting defaults and constraints """ layer = QgsVectorLayer( "Point?field=fldtxt:string&field=fldint:integer&field=flddbl:double", "addfeat", "memory") # add a bunch of features f = QgsFeature() f.setAttributes(["test", 123, 1.0]) f1 = QgsFeature(2) f1.setAttributes(["test_1", 124, 1.1]) f2 = QgsFeature(3) f2.setAttributes(["test_2", 125, 2.4]) f3 = QgsFeature(4) f3.setAttributes(["test_3", 126, 1.7]) f4 = QgsFeature(5) f4.setAttributes(["superpig", 127, 0.8]) self.assertTrue(layer.dataProvider().addFeatures([f, f1, f2, f3, f4])) # no layer self.assertFalse(QgsVectorLayerUtils.createFeature(None).isValid()) # basic tests f = QgsVectorLayerUtils.createFeature(layer) self.assertTrue(f.isValid()) self.assertEqual(f.fields(), layer.fields()) self.assertFalse(f.hasGeometry()) self.assertEqual(f.attributes(), [NULL, NULL, NULL]) # set geometry g = QgsGeometry.fromPointXY(QgsPointXY(100, 200)) f = QgsVectorLayerUtils.createFeature(layer, g) self.assertTrue(f.hasGeometry()) self.assertEqual(f.geometry().asWkt(), g.asWkt()) # using attribute map f = QgsVectorLayerUtils.createFeature(layer, attributes={ 0: 'a', 2: 6.0 }) self.assertEqual(f.attributes(), ['a', NULL, 6.0]) # layer with default value expression layer.setDefaultValueDefinition(2, QgsDefaultValue('3*4')) f = QgsVectorLayerUtils.createFeature(layer) self.assertEqual(f.attributes(), [NULL, NULL, 12]) # we do not expect the default value expression to take precedence over the attribute map f = QgsVectorLayerUtils.createFeature(layer, attributes={ 0: 'a', 2: 6.0 }) self.assertEqual(f.attributes(), ['a', NULL, 6.0]) # default value takes precedence if it's apply on update layer.setDefaultValueDefinition(2, QgsDefaultValue('3*4', True)) f = QgsVectorLayerUtils.createFeature(layer, attributes={ 0: 'a', 2: 6.0 }) self.assertEqual(f.attributes(), ['a', NULL, 12.0]) # layer with default value expression based on geometry layer.setDefaultValueDefinition(2, QgsDefaultValue('3*$x')) f = QgsVectorLayerUtils.createFeature(layer, g) # adjusted so that input value and output feature are the same self.assertEqual(f.attributes(), [NULL, NULL, 300.0]) layer.setDefaultValueDefinition(2, QgsDefaultValue(None)) # test with violated unique constraints layer.setFieldConstraint(1, QgsFieldConstraints.ConstraintUnique) f = QgsVectorLayerUtils.createFeature(layer, attributes={ 0: 'test_1', 1: 123 }) # since field 1 has Unique Constraint, it ignores value 123 that already has been set and sets to 128 self.assertEqual(f.attributes(), ['test_1', 128, NULL]) layer.setFieldConstraint(0, QgsFieldConstraints.ConstraintUnique) # since field 0 and 1 already have values test_1 and 123, the output must be a new unique value f = QgsVectorLayerUtils.createFeature(layer, attributes={ 0: 'test_1', 1: 123 }) self.assertEqual(f.attributes(), ['test_4', 128, NULL]) # test with violated unique constraints and default value expression providing unique value layer.setDefaultValueDefinition(1, QgsDefaultValue('130')) f = QgsVectorLayerUtils.createFeature(layer, attributes={ 0: 'test_1', 1: 123 }) # since field 1 has Unique Constraint, it ignores value 123 that already has been set and adds the default value self.assertEqual(f.attributes(), ['test_4', 130, NULL]) # fallback: test with violated unique constraints and default value expression providing already existing value # add the feature with the default value: self.assertTrue(layer.dataProvider().addFeatures([f])) f = QgsVectorLayerUtils.createFeature(layer, attributes={ 0: 'test_1', 1: 123 }) # since field 1 has Unique Constraint, it ignores value 123 that already has been set and adds the default value # and since the default value providing an already existing value (130) it generates a unique value (next int: 131) self.assertEqual(f.attributes(), ['test_5', 131, NULL]) layer.setDefaultValueDefinition(1, QgsDefaultValue(None)) # test with manually correct unique constraint f = QgsVectorLayerUtils.createFeature(layer, attributes={ 0: 'test_1', 1: 132 }) self.assertEqual(f.attributes(), ['test_5', 132, NULL]) """ test creating a feature respecting unique values of postgres provider """ layer = QgsVectorLayer( "Point?field=fldtxt:string&field=fldint:integer&field=flddbl:double", "addfeat", "memory") # init connection string dbconn = 'service=qgis_test' if 'QGIS_PGTEST_DB' in os.environ: dbconn = os.environ['QGIS_PGTEST_DB'] # create a vector layer pg_layer = QgsVectorLayer( '{} table="qgis_test"."authors" sql='.format(dbconn), "authors", "postgres") self.assertTrue(pg_layer.isValid()) # check the default clause default_clause = 'nextval(\'qgis_test.authors_pk_seq\'::regclass)' self.assertEqual(pg_layer.dataProvider().defaultValueClause(0), default_clause) # though default_clause is after the first create not unique (until save), it should fill up all the features with it pg_layer.startEditing() f = QgsVectorLayerUtils.createFeature(pg_layer) self.assertEqual(f.attributes(), [default_clause, NULL]) self.assertTrue(pg_layer.addFeatures([f])) self.assertTrue( QgsVectorLayerUtils.valueExists(pg_layer, 0, default_clause)) f = QgsVectorLayerUtils.createFeature(pg_layer) self.assertEqual(f.attributes(), [default_clause, NULL]) self.assertTrue(pg_layer.addFeatures([f])) f = QgsVectorLayerUtils.createFeature(pg_layer) self.assertEqual(f.attributes(), [default_clause, NULL]) self.assertTrue(pg_layer.addFeatures([f])) # if a unique value is passed, use it f = QgsVectorLayerUtils.createFeature(pg_layer, attributes={ 0: 40, 1: NULL }) self.assertEqual(f.attributes(), [40, NULL]) # and if a default value is configured use it as well pg_layer.setDefaultValueDefinition(0, QgsDefaultValue('11*4')) f = QgsVectorLayerUtils.createFeature(pg_layer) self.assertEqual(f.attributes(), [44, NULL]) pg_layer.rollBack()
def delimitedTextData(self, testname, filename, requests, verbose, **params): # Retrieve the data for a delimited text url # Create a layer for the specified file and query parameters # and return the data for the layer (fields, data) filepath = os.path.join(unitTestDataPath("delimitedtext"), filename) url = MyUrl.fromLocalFile(filepath) if not requests: requests = [{}] for k in list(params.keys()): url.addQueryItem(k, params[k]) urlstr = url.toString() log = [] with MessageLogger('DelimitedText') as logger: if verbose: print(testname) layer = QgsVectorLayer(urlstr, 'test', 'delimitedtext') uri = layer.dataProvider().dataSourceUri() if verbose: print(uri) basename = os.path.basename(filepath) if not basename.startswith('test'): basename = 'file' uri = re.sub(r'^file\:\/\/[^\?]*', 'file://' + basename, uri) fields = [] fieldTypes = [] data = {} if layer.isValid(): for nr, r in enumerate(requests): if verbose: print(("Processing request", nr + 1, repr(r))) if isinstance(r, collections.Callable): r(layer) if verbose: print("Request function executed") if isinstance(r, collections.Callable): continue rfields, rtypes, rdata = self.layerData( layer, r, nr * 1000) if len(rfields) > len(fields): fields = rfields fieldTypes = rtypes data.update(rdata) if not rdata: log.append("Request " + str(nr) + " did not return any data") if verbose: print(("Request returned", len(list(rdata.keys())), "features")) for msg in logger.messages(): filelogname = 'temp_file' if 'tmp' in filename.lower( ) else filename msg = re.sub(r'file\s+.*' + re.escape(filename), 'file ' + filelogname, msg) msg = msg.replace(filepath, filelogname) log.append(msg) return dict(fields=fields, fieldTypes=fieldTypes, data=data, log=log, uri=uri, geometryType=layer.geometryType())
def testUpdateModeFailedReopening(self): ''' Test that methods on provider don't crash after a failed reopening ''' # Windows doesn't like removing files opened by OGR, whatever # their open mode, so that makes it hard to test if sys.platform == 'win32': return tmpdir = tempfile.mkdtemp() self.dirs_to_cleanup.append(tmpdir) srcpath = os.path.join(TEST_DATA_DIR, 'provider') for file in glob.glob(os.path.join(srcpath, 'shapefile.*')): shutil.copy(os.path.join(srcpath, file), tmpdir) datasource = os.path.join(tmpdir, 'shapefile.shp') vl = QgsVectorLayer('{}|layerid=0'.format(datasource), 'test', 'ogr') os.unlink(datasource) self.assertFalse(vl.dataProvider().enterUpdateMode()) self.assertFalse(vl.dataProvider().enterUpdateMode()) self.assertEqual(vl.dataProvider().property("_debug_open_mode"), "invalid") self.assertFalse(vl.dataProvider().isValid()) self.assertEqual(len([f for f in vl.dataProvider().getFeatures()]), 0) self.assertEqual(len(vl.dataProvider().subLayers()), 0) self.assertFalse(vl.dataProvider().setSubsetString('TRUE')) (ret, _) = vl.dataProvider().addFeatures([QgsFeature()]) self.assertFalse(ret) self.assertFalse(vl.dataProvider().deleteFeatures([1])) self.assertFalse(vl.dataProvider().addAttributes([QgsField()])) self.assertFalse(vl.dataProvider().deleteAttributes([1])) self.assertFalse(vl.dataProvider().changeGeometryValues( {0: QgsGeometry.fromWkt('Point (3 50)')})) self.assertFalse(vl.dataProvider().changeAttributeValues({0: {0: 0}})) self.assertFalse(vl.dataProvider().createSpatialIndex()) self.assertFalse(vl.dataProvider().createAttributeIndex(0))
def test_representValue(self): first_layer = QgsVectorLayer("none?field=foreign_key:integer", "first_layer", "memory") self.assertTrue(first_layer.isValid()) second_layer = QgsVectorLayer( "none?field=pkid:integer&field=decoded:string", "second_layer", "memory") self.assertTrue(second_layer.isValid()) QgsProject.instance().addMapLayer(second_layer) f = QgsFeature() f.setAttributes([123]) first_layer.dataProvider().addFeatures([f]) f = QgsFeature() f.setAttributes([123, 'decoded_val']) second_layer.dataProvider().addFeatures([f]) fieldFormatter = QgsValueRelationFieldFormatter() # Everything valid config = { 'Layer': second_layer.id(), 'Key': 'pkid', 'Value': 'decoded' } self.assertEqual( fieldFormatter.representValue(first_layer, 0, config, None, '123'), 'decoded_val') # Code not find match in foreign layer config = { 'Layer': second_layer.id(), 'Key': 'pkid', 'Value': 'decoded' } self.assertEqual( fieldFormatter.representValue(first_layer, 0, config, None, '456'), '(456)') # Missing Layer config = {'Key': 'pkid', 'Value': 'decoded'} self.assertEqual( fieldFormatter.representValue(first_layer, 0, config, None, '456'), '(456)') # Invalid Layer config = {'Layer': 'invalid', 'Key': 'pkid', 'Value': 'decoded'} self.assertEqual( fieldFormatter.representValue(first_layer, 0, config, None, '456'), '(456)') # Invalid Key config = { 'Layer': second_layer.id(), 'Key': 'invalid', 'Value': 'decoded' } self.assertEqual( fieldFormatter.representValue(first_layer, 0, config, None, '456'), '(456)') # Invalid Value config = { 'Layer': second_layer.id(), 'Key': 'pkid', 'Value': 'invalid' } self.assertEqual( fieldFormatter.representValue(first_layer, 0, config, None, '456'), '(456)') QgsProject.instance().removeMapLayer(second_layer.id())
class TestQgsVectorLayer(unittest.TestCase): mMemoryLayer = None def testWrite(self): """Check we can write a vector file.""" self.mMemoryLayer = QgsVectorLayer( ('Point?crs=epsg:4326&field=name:string(20)&' 'field=age:integer&field=size:double&index=yes'), 'test', 'memory') assert self.mMemoryLayer is not None, 'Provider not initialized' myProvider = self.mMemoryLayer.dataProvider() assert myProvider is not None ft = QgsFeature() ft.setGeometry(QgsGeometry.fromPoint(QgsPoint(10, 10))) ft.setAttributes(['Johny', 20, 0.3]) myResult, myFeatures = myProvider.addFeatures([ft]) assert myResult assert len(myFeatures) > 0 writeShape(self.mMemoryLayer, 'writetest.shp') def testDateTimeWriteShapefile(self): """Check writing date and time fields to an ESRI shapefile.""" ml = QgsVectorLayer( ('Point?crs=epsg:4326&field=id:int&' 'field=date_f:date&field=time_f:time&field=dt_f:datetime'), 'test', 'memory') assert ml is not None, 'Provider not initialized' assert ml.isValid(), 'Source layer not valid' provider = ml.dataProvider() assert provider is not None ft = QgsFeature() ft.setGeometry(QgsGeometry.fromPoint(QgsPoint(10, 10))) ft.setAttributes([ 1, QDate(2014, 3, 5), QTime(13, 45, 22), QDateTime(QDate(2014, 3, 5), QTime(13, 45, 22)) ]) res, features = provider.addFeatures([ft]) assert res assert len(features) > 0 dest_file_name = os.path.join(str(QDir.tempPath()), 'datetime.shp') crs = QgsCoordinateReferenceSystem() crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId) write_result = QgsVectorFileWriter.writeAsVectorFormat( ml, dest_file_name, 'utf-8', crs, 'ESRI Shapefile') self.assertEqual(write_result, QgsVectorFileWriter.NoError) # Open result and check created_layer = QgsVectorLayer(u'{}|layerid=0'.format(dest_file_name), u'test', u'ogr') fields = created_layer.dataProvider().fields() self.assertEqual( fields.at(fields.indexFromName('date_f')).type(), QVariant.Date) #shapefiles do not support time types, result should be string self.assertEqual( fields.at(fields.indexFromName('time_f')).type(), QVariant.String) #shapefiles do not support datetime types, result should be string self.assertEqual( fields.at(fields.indexFromName('dt_f')).type(), QVariant.String) f = next(created_layer.getFeatures(QgsFeatureRequest())) date_idx = created_layer.fieldNameIndex('date_f') assert isinstance(f.attributes()[date_idx], QDate) self.assertEqual(f.attributes()[date_idx], QDate(2014, 3, 5)) time_idx = created_layer.fieldNameIndex('time_f') #shapefiles do not support time types assert isinstance(f.attributes()[time_idx], basestring) self.assertEqual(f.attributes()[time_idx], '13:45:22') #shapefiles do not support datetime types datetime_idx = created_layer.fieldNameIndex('dt_f') assert isinstance(f.attributes()[datetime_idx], basestring) self.assertEqual( f.attributes()[datetime_idx], QDateTime(QDate(2014, 3, 5), QTime(13, 45, 22)).toString("yyyy/MM/dd hh:mm:ss.zzz")) def testDateTimeWriteTabfile(self): """Check writing date and time fields to an MapInfo tabfile.""" ml = QgsVectorLayer( ('Point?crs=epsg:4326&field=id:int&' 'field=date_f:date&field=time_f:time&field=dt_f:datetime'), 'test', 'memory') assert ml is not None, 'Provider not initialized' assert ml.isValid(), 'Source layer not valid' provider = ml.dataProvider() assert provider is not None ft = QgsFeature() ft.setGeometry(QgsGeometry.fromPoint(QgsPoint(10, 10))) ft.setAttributes([ 1, QDate(2014, 3, 5), QTime(13, 45, 22), QDateTime(QDate(2014, 3, 5), QTime(13, 45, 22)) ]) res, features = provider.addFeatures([ft]) assert res assert len(features) > 0 dest_file_name = os.path.join(str(QDir.tempPath()), 'datetime.tab') crs = QgsCoordinateReferenceSystem() crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId) write_result = QgsVectorFileWriter.writeAsVectorFormat( ml, dest_file_name, 'utf-8', crs, 'MapInfo File') self.assertEqual(write_result, QgsVectorFileWriter.NoError) # Open result and check created_layer = QgsVectorLayer(u'{}|layerid=0'.format(dest_file_name), u'test', u'ogr') fields = created_layer.dataProvider().fields() self.assertEqual( fields.at(fields.indexFromName('date_f')).type(), QVariant.Date) self.assertEqual( fields.at(fields.indexFromName('time_f')).type(), QVariant.Time) self.assertEqual( fields.at(fields.indexFromName('dt_f')).type(), QVariant.DateTime) f = next(created_layer.getFeatures(QgsFeatureRequest())) date_idx = created_layer.fieldNameIndex('date_f') assert isinstance(f.attributes()[date_idx], QDate) self.assertEqual(f.attributes()[date_idx], QDate(2014, 3, 5)) time_idx = created_layer.fieldNameIndex('time_f') assert isinstance(f.attributes()[time_idx], QTime) self.assertEqual(f.attributes()[time_idx], QTime(13, 45, 22)) datetime_idx = created_layer.fieldNameIndex('dt_f') assert isinstance(f.attributes()[datetime_idx], QDateTime) self.assertEqual(f.attributes()[datetime_idx], QDateTime(QDate(2014, 3, 5), QTime(13, 45, 22))) def testWriteShapefileWithZ(self): """Check writing geometries with Z dimension to an ESRI shapefile.""" #start by saving a memory layer and forcing z ml = QgsVectorLayer(('Point?crs=epsg:4326&field=id:int'), 'test', 'memory') assert ml is not None, 'Provider not initialized' assert ml.isValid(), 'Source layer not valid' provider = ml.dataProvider() assert provider is not None ft = QgsFeature() ft.setGeometry(QgsGeometry.fromWkt('PointZ (1 2 3)')) ft.setAttributes([1]) res, features = provider.addFeatures([ft]) assert res assert len(features) > 0 # check with both a standard PointZ and 25d style Point25D type for t in [QgsWKBTypes.PointZ, QgsWKBTypes.Point25D]: dest_file_name = os.path.join( str(QDir.tempPath()), 'point_{}.shp'.format(QgsWKBTypes.displayString(t))) crs = QgsCoordinateReferenceSystem() crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId) write_result = QgsVectorFileWriter.writeAsVectorFormat( ml, dest_file_name, 'utf-8', crs, 'ESRI Shapefile', overrideGeometryType=t) self.assertEqual(write_result, QgsVectorFileWriter.NoError) # Open result and check created_layer = QgsVectorLayer( u'{}|layerid=0'.format(dest_file_name), u'test', u'ogr') f = next(created_layer.getFeatures(QgsFeatureRequest())) g = f.geometry() wkt = g.exportToWkt() expWkt = 'PointZ (1 2 3)' assert compareWkt( expWkt, wkt ), "saving geometry with Z failed: mismatch Expected:\n%s\nGot:\n%s\n" % ( expWkt, wkt) #also try saving out the shapefile version again, as an extra test #this tests that saving a layer with z WITHOUT explicitly telling the writer to keep z values, #will stay retain the z values dest_file_name = os.path.join( str(QDir.tempPath()), 'point_{}_copy.shp'.format(QgsWKBTypes.displayString(t))) crs = QgsCoordinateReferenceSystem() crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId) write_result = QgsVectorFileWriter.writeAsVectorFormat( created_layer, dest_file_name, 'utf-8', crs, 'ESRI Shapefile') self.assertEqual(write_result, QgsVectorFileWriter.NoError) # Open result and check created_layer_from_shp = QgsVectorLayer( u'{}|layerid=0'.format(dest_file_name), u'test', u'ogr') f = next(created_layer_from_shp.getFeatures(QgsFeatureRequest())) g = f.geometry() wkt = g.exportToWkt() assert compareWkt( expWkt, wkt ), "saving geometry with Z failed: mismatch Expected:\n%s\nGot:\n%s\n" % ( expWkt, wkt) def testWriteShapefileWithMultiConversion(self): """Check writing geometries to an ESRI shapefile with conversion to multi.""" ml = QgsVectorLayer(('Point?crs=epsg:4326&field=id:int'), 'test', 'memory') assert ml is not None, 'Provider not initialized' assert ml.isValid(), 'Source layer not valid' provider = ml.dataProvider() assert provider is not None ft = QgsFeature() ft.setGeometry(QgsGeometry.fromWkt('Point (1 2)')) ft.setAttributes([1]) res, features = provider.addFeatures([ft]) assert res assert len(features) > 0 dest_file_name = os.path.join(str(QDir.tempPath()), 'to_multi.shp') crs = QgsCoordinateReferenceSystem() crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId) write_result = QgsVectorFileWriter.writeAsVectorFormat( ml, dest_file_name, 'utf-8', crs, 'ESRI Shapefile', forceMulti=True) self.assertEqual(write_result, QgsVectorFileWriter.NoError) # Open result and check created_layer = QgsVectorLayer(u'{}|layerid=0'.format(dest_file_name), u'test', u'ogr') f = next(created_layer.getFeatures(QgsFeatureRequest())) g = f.geometry() wkt = g.exportToWkt() expWkt = 'MultiPoint ((1 2))' assert compareWkt( expWkt, wkt ), "saving geometry with multi conversion failed: mismatch Expected:\n%s\nGot:\n%s\n" % ( expWkt, wkt) def testWriteShapefileWithAttributeSubsets(self): """Tests writing subsets of attributes to files.""" ml = QgsVectorLayer(( 'Point?crs=epsg:4326&field=id:int&field=field1:int&field=field2:int&field=field3:int' ), 'test', 'memory') assert ml is not None, 'Provider not initialized' assert ml.isValid(), 'Source layer not valid' provider = ml.dataProvider() assert provider is not None ft = QgsFeature() ft.setGeometry(QgsGeometry.fromWkt('Point (1 2)')) ft.setAttributes([1, 11, 12, 13]) res, features = provider.addFeatures([ft]) assert res assert len(features) > 0 #first write out with all attributes dest_file_name = os.path.join(str(QDir.tempPath()), 'all_attributes.shp') crs = QgsCoordinateReferenceSystem() crs.createFromId(4326, QgsCoordinateReferenceSystem.EpsgCrsId) write_result = QgsVectorFileWriter.writeAsVectorFormat( ml, dest_file_name, 'utf-8', crs, 'ESRI Shapefile', attributes=[]) self.assertEqual(write_result, QgsVectorFileWriter.NoError) # Open result and check created_layer = QgsVectorLayer(u'{}|layerid=0'.format(dest_file_name), u'test', u'ogr') self.assertEqual(created_layer.fields().count(), 4) f = next(created_layer.getFeatures(QgsFeatureRequest())) self.assertEqual(f['id'], 1) self.assertEqual(f['field1'], 11) self.assertEqual(f['field2'], 12) self.assertEqual(f['field3'], 13) #now test writing out only a subset of attributes dest_file_name = os.path.join(str(QDir.tempPath()), 'subset_attributes.shp') write_result = QgsVectorFileWriter.writeAsVectorFormat( ml, dest_file_name, 'utf-8', crs, 'ESRI Shapefile', attributes=[1, 3]) self.assertEqual(write_result, QgsVectorFileWriter.NoError) # Open result and check created_layer = QgsVectorLayer(u'{}|layerid=0'.format(dest_file_name), u'test', u'ogr') self.assertEqual(created_layer.fields().count(), 2) f = next(created_layer.getFeatures(QgsFeatureRequest())) self.assertEqual(f['field1'], 11) self.assertEqual(f['field3'], 13) #finally test writing no attributes dest_file_name = os.path.join(str(QDir.tempPath()), 'no_attributes.shp') write_result = QgsVectorFileWriter.writeAsVectorFormat( ml, dest_file_name, 'utf-8', crs, 'ESRI Shapefile', skipAttributeCreation=True) self.assertEqual(write_result, QgsVectorFileWriter.NoError) # Open result and check created_layer = QgsVectorLayer(u'{}|layerid=0'.format(dest_file_name), u'test', u'ogr') # expect only a default 'FID' field for shapefiles self.assertEqual(created_layer.fields().count(), 1) self.assertEqual(created_layer.fields()[0].name(), 'FID') # in this case we also check that the geometry exists, to make sure feature has been correctly written # even without attributes f = next(created_layer.getFeatures(QgsFeatureRequest())) g = f.geometry() wkt = g.exportToWkt() expWkt = 'Point (1 2)' assert compareWkt( expWkt, wkt ), "geometry not saved correctly when saving without attributes : mismatch Expected:\n%s\nGot:\n%s\n" % ( expWkt, wkt) self.assertEqual(f['FID'], 0)
def testInsertPolygonInMultiPolygon(self): layer = QgsVectorLayer("MultiPolygon?crs=epsg:4326&field=id:integer", "addfeat", "memory") pr = layer.dataProvider() f = QgsFeature() f.setAttributes([1]) f.setGeometry(QgsGeometry.fromWkt('MultiPolygon(((0 0, 1 0, 1 1, 0 1, 0 0)),((10 0, 11 0, 11 1, 10 1, 10 0)))')) pr.addFeatures([f]) uri = '{} table="qgis_test"."new_table_multipolygon" sql='.format(self.dbconn) error, message = QgsVectorLayerExporter.exportLayer(layer, uri, 'mssql', QgsCoordinateReferenceSystem('EPSG:4326')) self.assertEqual(error, QgsVectorLayerExporter.NoError) new_layer = QgsVectorLayer(uri, 'new', 'mssql') self.assertTrue(new_layer.isValid()) self.assertEqual(new_layer.wkbType(), QgsWkbTypes.MultiPolygon) geom = [f.geometry().asWkt() for f in new_layer.getFeatures()] self.assertEqual(geom, ['MultiPolygon (((0 0, 1 0, 1 1, 0 1, 0 0)),((10 0, 11 0, 11 1, 10 1, 10 0)))']) # add single part f2 = QgsFeature() f2.setAttributes([2]) f2.setGeometry(QgsGeometry.fromWkt('Polygon((30 0, 31 0, 31 1, 30 1, 30 0))')) self.assertTrue(new_layer.dataProvider().addFeatures([f2])) # should become multipart geom = [f.geometry().asWkt() for f in new_layer.getFeatures()] self.assertEqual(geom, ['MultiPolygon (((0 0, 1 0, 1 1, 0 1, 0 0)),((10 0, 11 0, 11 1, 10 1, 10 0)))', 'MultiPolygon (((30 0, 31 0, 31 1, 30 1, 30 0)))'])