def testThemeChanged(self): """ Test that the mapTheme(s)Changed signals are correctly emitted in all relevant situations """ project = QgsProject() collection = QgsMapThemeCollection(project) record = QgsMapThemeCollection.MapThemeRecord() theme_changed_spy = QSignalSpy(collection.mapThemeChanged) themes_changed_spy = QSignalSpy(collection.mapThemesChanged) collection.insert('theme1', record) self.assertEqual(len(theme_changed_spy), 1) self.assertEqual(theme_changed_spy[-1][0], 'theme1') self.assertEqual(len(themes_changed_spy), 1) # reinsert collection.insert('theme1', record) self.assertEqual(len(theme_changed_spy), 2) self.assertEqual(theme_changed_spy[-1][0], 'theme1') self.assertEqual(len(themes_changed_spy), 2) # update collection.update('theme1', record) self.assertEqual(len(theme_changed_spy), 3) self.assertEqual(theme_changed_spy[-1][0], 'theme1') self.assertEqual(len(themes_changed_spy), 3) # remove invalid collection.removeMapTheme( 'i wish i was a slave to an age old trade... like riding around on rail cars and working long days' ) self.assertEqual(len(theme_changed_spy), 3) self.assertEqual(len(themes_changed_spy), 3) # remove valid collection.removeMapTheme('theme1') self.assertEqual(len(theme_changed_spy), 3) # not changed - removed! self.assertEqual(len(themes_changed_spy), 4) # reinsert collection.insert('theme1', record) self.assertEqual(len(theme_changed_spy), 4) self.assertEqual(len(themes_changed_spy), 5) # clear collection.clear() self.assertEqual(len(theme_changed_spy), 4) # not changed - removed! self.assertEqual(len(themes_changed_spy), 6) # check that mapThemeChanged is emitted if layer is removed layer = QgsVectorLayer("Point?field=fldtxt:string", "layer1", "memory") layer2 = QgsVectorLayer("Point?field=fldtxt:string", "layer2", "memory") project.addMapLayers([layer, layer2]) # record for layer1 record.addLayerRecord(QgsMapThemeCollection.MapThemeLayerRecord(layer)) collection.insert('theme1', record) self.assertEqual(len(theme_changed_spy), 5) self.assertEqual(len(themes_changed_spy), 7) # now kill layer 2 project.removeMapLayer(layer2) self.assertEqual( len(theme_changed_spy), 5) # signal should not be emitted - layer is not in record # now kill layer 1 project.removeMapLayer(layer) app.processEvents() self.assertEqual(len(theme_changed_spy), 6) # signal should be emitted - layer is in record
def testDirtyBlocker(self): # first test manual QgsProjectDirtyBlocker construction p = QgsProject() dirty_spy = QSignalSpy(p.isDirtyChanged) # ^ will do *whatever* it takes to discover the enemy's secret plans! # simple checks p.setDirty(True) self.assertTrue(p.isDirty()) self.assertEqual(len(dirty_spy), 1) self.assertEqual(dirty_spy[-1], [True]) p.setDirty(True) # already dirty self.assertTrue(p.isDirty()) self.assertEqual(len(dirty_spy), 1) p.setDirty(False) self.assertFalse(p.isDirty()) self.assertEqual(len(dirty_spy), 2) self.assertEqual(dirty_spy[-1], [False]) p.setDirty(True) self.assertTrue(p.isDirty()) self.assertEqual(len(dirty_spy), 3) self.assertEqual(dirty_spy[-1], [True]) # with a blocker blocker = QgsProjectDirtyBlocker(p) # blockers will allow cleaning projects p.setDirty(False) self.assertFalse(p.isDirty()) self.assertEqual(len(dirty_spy), 4) self.assertEqual(dirty_spy[-1], [False]) # but not dirtying! p.setDirty(True) self.assertFalse(p.isDirty()) self.assertEqual(len(dirty_spy), 4) self.assertEqual(dirty_spy[-1], [False]) # nested block blocker2 = QgsProjectDirtyBlocker(p) p.setDirty(True) self.assertFalse(p.isDirty()) self.assertEqual(len(dirty_spy), 4) self.assertEqual(dirty_spy[-1], [False]) del blocker2 p.setDirty(True) self.assertFalse(p.isDirty()) self.assertEqual(len(dirty_spy), 4) self.assertEqual(dirty_spy[-1], [False]) del blocker p.setDirty(True) self.assertTrue(p.isDirty()) self.assertEqual(len(dirty_spy), 5) self.assertEqual(dirty_spy[-1], [True]) # using python context manager with QgsProject.blockDirtying(p): # cleaning allowed p.setDirty(False) self.assertFalse(p.isDirty()) self.assertEqual(len(dirty_spy), 6) self.assertEqual(dirty_spy[-1], [False]) # but not dirtying! p.setDirty(True) self.assertFalse(p.isDirty()) self.assertEqual(len(dirty_spy), 6) self.assertEqual(dirty_spy[-1], [False]) # unblocked p.setDirty(True) self.assertTrue(p.isDirty()) self.assertEqual(len(dirty_spy), 7) self.assertEqual(dirty_spy[-1], [True])
def test_geocode(self): geocoder = TestGeocoder() canvas = QgsMapCanvas() filter = QgsGeocoderLocatorFilter('testgeocoder', 'my geocoder', 'pref', geocoder, canvas, QgsRectangle(-1, -1, 1, 1)) self.assertEqual(filter.name(), 'testgeocoder') self.assertEqual(filter.displayName(), 'my geocoder') self.assertEqual(filter.prefix(), 'pref') self.assertEqual(filter.geocoder(), geocoder) self.assertEqual(filter.boundingBox(), QgsRectangle(-1, -1, 1, 1)) spy = QSignalSpy(filter.resultFetched) context = QgsLocatorContext() feedback = QgsFeedback() # no results filter.fetchResults('cvxbcvb', context, feedback) self.assertEqual(len(spy), 0) # one result filter.fetchResults('a', context, feedback) self.assertEqual(len(spy), 1) res = spy[-1][0] self.assertEqual(res.displayString, 'res 1') # some sip weirdness here -- if we directly access the QgsLocatorResult object here then we get segfaults! # so instead convert back to QgsGeocoderResult. This makes the test more robust anyway... geocode_result = filter.locatorResultToGeocoderResult(res) self.assertEqual(geocode_result.identifier(), 'res 1') self.assertEqual(geocode_result.geometry().asWkt(), 'Point (1 2)') self.assertEqual(geocode_result.crs().authid(), 'EPSG:4326') self.assertEqual(geocode_result.additionalAttributes(), { 'b': 123, 'c': 'xyz' }) self.assertTrue(geocode_result.viewport().isNull()) self.assertFalse(geocode_result.description()) self.assertFalse(geocode_result.group()) # two possible results filter.fetchResults('b', context, feedback) self.assertEqual(len(spy), 3) res1 = spy[-2][0] res2 = spy[-1][0] self.assertEqual(res1.displayString, 'res 1') geocode_result = filter.locatorResultToGeocoderResult(res1) self.assertEqual(geocode_result.identifier(), 'res 1') self.assertEqual(geocode_result.geometry().asWkt(), 'Point (11 12)') self.assertEqual(geocode_result.crs().authid(), 'EPSG:4326') self.assertEqual(geocode_result.additionalAttributes(), { 'b': 123, 'c': 'xyz' }) self.assertTrue(geocode_result.viewport().isNull()) self.assertEqual(geocode_result.description(), 'desc') self.assertEqual(geocode_result.group(), 'group') self.assertEqual(res2.displayString, 'res 2') geocode_result = filter.locatorResultToGeocoderResult(res2) self.assertEqual(geocode_result.identifier(), 'res 2') self.assertEqual(geocode_result.geometry().asWkt(), 'Point (13 14)') self.assertEqual(geocode_result.crs().authid(), 'EPSG:3857') self.assertEqual(geocode_result.additionalAttributes(), {'d': 456}) self.assertEqual(geocode_result.viewport(), QgsRectangle(1, 2, 3, 4)) self.assertFalse(geocode_result.description()) self.assertFalse(geocode_result.group())
def test_ring_vertex_count(self): # valid ring g = QgsGeometry.fromWkt("Polygon ((0 0, 10 0, 10 10, 0 0))") validator = QgsGeometryValidator(g) spy = QSignalSpy(validator.errorFound) validator.run() self.assertEqual(len(spy), 0) # not enough vertices g = QgsGeometry.fromWkt("Polygon ((0 0, 10 0, 10 10))") validator = QgsGeometryValidator(g) spy = QSignalSpy(validator.errorFound) validator.run() self.assertEqual(len(spy), 1) self.assertEqual(spy[0][0].where(), QgsPointXY()) self.assertEqual(spy[0][0].what(), 'ring 0 with less than four points') g = QgsGeometry.fromWkt("Polygon ((0 0, 10 0, 0 0))") validator = QgsGeometryValidator(g) spy = QSignalSpy(validator.errorFound) validator.run() self.assertEqual(len(spy), 1) self.assertEqual(spy[0][0].where(), QgsPointXY()) self.assertEqual(spy[0][0].what(), 'ring 0 with less than four points') g = QgsGeometry.fromWkt("Polygon ((0 0, 10 0))") validator = QgsGeometryValidator(g) spy = QSignalSpy(validator.errorFound) validator.run() self.assertEqual(len(spy), 1) self.assertEqual(spy[0][0].where(), QgsPointXY()) self.assertEqual(spy[0][0].what(), 'ring 0 with less than four points') g = QgsGeometry.fromWkt("Polygon ((0 0))") validator = QgsGeometryValidator(g) spy = QSignalSpy(validator.errorFound) validator.run() self.assertEqual(len(spy), 1) self.assertEqual(spy[0][0].where(), QgsPointXY()) self.assertEqual(spy[0][0].what(), 'ring 0 with less than four points') g = QgsGeometry.fromWkt("Polygon (())") validator = QgsGeometryValidator(g) spy = QSignalSpy(validator.errorFound) validator.run() self.assertEqual(len(spy), 0) g = QgsGeometry.fromWkt( "Polygon ((0 0, 10 0, 10 10, 0 0),(1 1, 2 1, 2 2))") validator = QgsGeometryValidator(g) spy = QSignalSpy(validator.errorFound) validator.run() self.assertEqual(len(spy), 1) self.assertEqual(spy[0][0].where(), QgsPointXY()) self.assertEqual(spy[0][0].what(), 'ring 1 with less than four points') g = QgsGeometry.fromWkt( "Polygon ((0 0, 10 0, 10 10, 0 0),(1 1, 2 1, 2 2, 1 1))") validator = QgsGeometryValidator(g) spy = QSignalSpy(validator.errorFound) validator.run() self.assertEqual(len(spy), 0) g = QgsGeometry.fromWkt( "Polygon ((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 2 1, 2 2, 1 1),(3 3, 3 4, 4 4))" ) validator = QgsGeometryValidator(g) spy = QSignalSpy(validator.errorFound) validator.run() self.assertEqual(len(spy), 1) self.assertEqual(spy[0][0].where(), QgsPointXY()) self.assertEqual(spy[0][0].what(), 'ring 2 with less than four points')
def testHomePath(self): p = QgsProject() path_changed_spy = QSignalSpy(p.homePathChanged) self.assertFalse(p.homePath()) self.assertFalse(p.presetHomePath()) # simulate save file tmp_dir = QTemporaryDir() tmp_file = "{}/project.qgs".format(tmp_dir.path()) with open(tmp_file, 'w') as f: pass p.setFileName(tmp_file) # home path should be file path self.assertEqual(p.homePath(), tmp_dir.path()) self.assertFalse(p.presetHomePath()) self.assertEqual(len(path_changed_spy), 1) # manually override home path p.setPresetHomePath('/tmp/my_path') self.assertEqual(p.homePath(), '/tmp/my_path') self.assertEqual(p.presetHomePath(), '/tmp/my_path') self.assertEqual(len(path_changed_spy), 2) # check project scope scope = QgsExpressionContextUtils.projectScope(p) self.assertEqual(scope.variable('project_home'), '/tmp/my_path') # no extra signal if path is unchanged p.setPresetHomePath('/tmp/my_path') self.assertEqual(p.homePath(), '/tmp/my_path') self.assertEqual(p.presetHomePath(), '/tmp/my_path') self.assertEqual(len(path_changed_spy), 2) # setting file name should not affect home path is manually set tmp_file_2 = "{}/project/project2.qgs".format(tmp_dir.path()) os.mkdir(tmp_dir.path() + '/project') with open(tmp_file_2, 'w') as f: pass p.setFileName(tmp_file_2) self.assertEqual(p.homePath(), '/tmp/my_path') self.assertEqual(p.presetHomePath(), '/tmp/my_path') self.assertEqual(len(path_changed_spy), 2) scope = QgsExpressionContextUtils.projectScope(p) self.assertEqual(scope.variable('project_home'), '/tmp/my_path') # clear manual path p.setPresetHomePath('') self.assertEqual(p.homePath(), tmp_dir.path() + '/project') self.assertFalse(p.presetHomePath()) self.assertEqual(len(path_changed_spy), 3) scope = QgsExpressionContextUtils.projectScope(p) self.assertEqual(scope.variable('project_home'), tmp_dir.path() + '/project') # relative path p.setPresetHomePath('../home') self.assertEqual(p.homePath(), tmp_dir.path() + '/home') self.assertEqual(p.presetHomePath(), '../home') self.assertEqual(len(path_changed_spy), 4) scope = QgsExpressionContextUtils.projectScope(p) self.assertEqual(scope.variable('project_home'), tmp_dir.path() + '/home') # relative path, no filename p.setFileName('') self.assertEqual(p.homePath(), '../home') self.assertEqual(p.presetHomePath(), '../home') scope = QgsExpressionContextUtils.projectScope(p) self.assertEqual(scope.variable('project_home'), '../home')
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): # 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 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 conn.createSchema('myUtf8\U0001f604NewSchema') schemas = conn.schemas() conn.dropSchema('myUtf8\U0001f604NewSchema') schemas = conn.schemas() self.assertFalse('myUtf8\U0001f604NewSchema' in schemas) # Table operations if (capabilities & QgsAbstractDatabaseProviderConnection.CreateVectorTable and capabilities & QgsAbstractDatabaseProviderConnection.Tables and capabilities & QgsAbstractDatabaseProviderConnection.DropVectorTable): if capabilities & QgsAbstractDatabaseProviderConnection.CreateSchema: schema = 'myNewSchema' conn.createSchema('myNewSchema') else: schema = 'public' # Start clean if 'myNewTable' in self._table_names(conn.tables(schema)): conn.dropVectorTable(schema, '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, 'myNewTable', fields, typ, crs, True, options) table_names = self._table_names(conn.tables(schema)) self.assertTrue('myNewTable' in table_names) # Create UTF8 table conn.createVectorTable(schema, 'myUtf8\U0001f604Table', fields, typ, crs, True, options) table_names = self._table_names(conn.tables(schema)) self.assertTrue('myNewTable' in table_names) self.assertTrue('myUtf8\U0001f604Table' in table_names) conn.dropVectorTable(schema, 'myUtf8\U0001f604Table') table_names = self._table_names(conn.tables(schema)) self.assertFalse('myUtf8\U0001f604Table' in table_names) self.assertTrue('myNewTable' in table_names) # insert something, because otherwise MSSQL cannot guess if self.providerKey == 'mssql': f = QgsFeature(fields) f.setGeometry(QgsGeometry.fromWkt('LineString (-72.345 71.987, -80 80)')) vl = QgsVectorLayer(conn.tableUri('myNewSchema', 'myNewTable'), 'vl', 'mssql') vl.dataProvider().addFeatures([f]) # Check table information table_properties = conn.tables(schema) table_property = self._table_by_name(table_properties, 'myNewTable') self.assertEqual(table_property.maxCoordinateDimensions(), 2) self.assertIsNotNone(table_property) self.assertEqual(table_property.tableName(), '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(), '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 has_schema = capabilities & QgsAbstractDatabaseProviderConnection.Schemas if capabilities & QgsAbstractDatabaseProviderConnection.ExecuteSql: if has_schema: table = "\"%s\".\"myNewAspatialTable\"" % schema else: table = 'myNewAspatialTable' # MSSQL literal syntax for UTF8 requires 'N' 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, '2019-07-08', '2019-07-08T12:00:12', '12:00:13.00')" % ( table, 'N' if self.providerKey == 'mssql' else '') 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) # GPKG and spatialite have no type for time self.assertEqual(res, [['QGIS Rocks - \U0001f604', 666, 1.234, 1234, QtCore.QDate(2019, 7, 8) if not self.treat_date_as_string() else '2019-07-08', QtCore.QDateTime(2019, 7, 8, 12, 0, 12)]]) # Test column names res = conn.execSql(sql) self.assertEqual(res.rows(), [['QGIS Rocks - \U0001f604', 666, 1.234, 1234, QtCore.QDate(2019, 7, 8) if not self.treat_date_as_string() else '2019-07-08', QtCore.QDateTime(2019, 7, 8, 12, 0, 12)]]) self.assertEqual(res.columns(), ['string_t', 'long_t', 'double_t', 'integer_t', 'date_t', 'datetime_t']) # Test iterator old_rows = res.rows() res = conn.execSql(sql) rows = [] self.assertTrue(res.hasNextRow()) for row in res: rows.append(row) self.assertEqual(rows, old_rows) self.assertEqual(rows, res.rows()) # Java style res = conn.execSql(sql) rows = [] self.assertTrue(res.hasNextRow()) while res.hasNextRow(): rows.append(res.nextRow()) self.assertFalse(res.hasNextRow()) # But we still have access to rows: self.assertEqual(rows, res.rows()) 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('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'): 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, 'myNewTable', 'myVeryNewTable') tables = self._table_names(conn.tables(schema)) self.assertFalse('myNewTable' in tables) self.assertTrue('myVeryNewTable' in tables) # Rename it back conn.renameVectorTable(schema, 'myVeryNewTable', 'myNewTable') tables = self._table_names(conn.tables(schema)) self.assertTrue('myNewTable' in tables) self.assertFalse('myVeryNewTable' in tables) # Vacuum if capabilities & QgsAbstractDatabaseProviderConnection.Vacuum: conn.vacuum('myNewSchema', '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 not if capabilities & QgsAbstractDatabaseProviderConnection.SpatialIndexExists: spatial_index_exists = conn.spatialIndexExists('myNewSchema', 'myNewTable', 'geom') if capabilities & QgsAbstractDatabaseProviderConnection.DeleteSpatialIndex: if spatial_index_exists: conn.deleteSpatialIndex('myNewSchema', 'myNewTable', 'geom') if capabilities & QgsAbstractDatabaseProviderConnection.SpatialIndexExists: self.assertFalse(conn.spatialIndexExists('myNewSchema', 'myNewTable', 'geom')) if capabilities & (QgsAbstractDatabaseProviderConnection.CreateSpatialIndex | QgsAbstractDatabaseProviderConnection.SpatialIndexExists): options = QgsAbstractDatabaseProviderConnection.SpatialIndexOptions() options.geometryColumnName = 'geom' if not conn.spatialIndexExists('myNewSchema', 'myNewTable', options.geometryColumnName): conn.createSpatialIndex('myNewSchema', 'myNewTable', options) self.assertTrue(conn.spatialIndexExists('myNewSchema', 'myNewTable', 'geom')) # now we know for certain a spatial index exists, let's retry dropping it if capabilities & QgsAbstractDatabaseProviderConnection.DeleteSpatialIndex: conn.deleteSpatialIndex('myNewSchema', 'myNewTable', 'geom') if capabilities & QgsAbstractDatabaseProviderConnection.SpatialIndexExists: self.assertFalse(conn.spatialIndexExists('myNewSchema', 'myNewTable', 'geom')) if capabilities & QgsAbstractDatabaseProviderConnection.DropSchema: # Drop schema (should fail) with self.assertRaises(QgsProviderConnectionException) as ex: conn.dropSchema('myNewSchema') # Check some column types operations table = self._table_by_name(conn.tables(schema), '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('myNewSchema', '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, 'myNewSchema', 'myNewTable') fields = conn.fields('myNewSchema', 'myNewTable') self.assertTrue('short_lived_field' in fields.names()) if capabilities & QgsAbstractDatabaseProviderConnection.DeleteField: conn.deleteField('short_lived_field', 'myNewSchema', '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('myNewSchema', 'myNewTable') self.assertFalse('short_lived_field' in fields.names()) # Drop table conn.dropVectorTable(schema, 'myNewTable') conn.dropVectorTable(schema, 'myNewAspatialTable') table_names = self._table_names(conn.tables(schema)) self.assertFalse('myNewTable' in table_names) if capabilities & QgsAbstractDatabaseProviderConnection.DropSchema: # Drop schema conn.dropSchema('myNewSchema') self.assertFalse('myNewSchema' 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 testValues(self): w = QgsRangeSlider() w.setRangeLimits(0, 10) w.setUpperValue(7) spy = QSignalSpy(w.rangeChanged) w.setLowerValue(5) self.assertEqual(w.lowerValue(), 5) self.assertEqual(len(spy), 1) self.assertEqual(spy[-1], [5, 7]) w.setLowerValue(5) self.assertEqual(w.lowerValue(), 5) self.assertEqual(len(spy), 1) w.setUpperValue(8) self.assertEqual(w.lowerValue(), 5) self.assertEqual(w.upperValue(), 8) self.assertEqual(len(spy), 2) self.assertEqual(spy[-1], [5, 8]) w.setUpperValue(8) self.assertEqual(w.lowerValue(), 5) self.assertEqual(w.upperValue(), 8) self.assertEqual(len(spy), 2) w.setRange(3, 7) self.assertEqual(w.lowerValue(), 3) self.assertEqual(w.upperValue(), 7) self.assertEqual(len(spy), 3) self.assertEqual(spy[-1], [3, 7]) w.setRange(3, 7) self.assertEqual(w.lowerValue(), 3) self.assertEqual(w.upperValue(), 7) self.assertEqual(len(spy), 3) w.setRange(3, 8) self.assertEqual(w.lowerValue(), 3) self.assertEqual(w.upperValue(), 8) self.assertEqual(len(spy), 4) self.assertEqual(spy[-1], [3, 8]) w.setRange(4, 8) self.assertEqual(w.lowerValue(), 4) self.assertEqual(w.upperValue(), 8) self.assertEqual(len(spy), 5) self.assertEqual(spy[-1], [4, 8]) # set min > max, max should be raised w.setLowerValue(9) self.assertEqual(w.lowerValue(), 9) self.assertEqual(w.upperValue(), 9) self.assertEqual(len(spy), 6) self.assertEqual(spy[-1], [9, 9]) w.setRange(4, 8) self.assertEqual(len(spy), 7) # set max < min, min should be lowered w.setUpperValue(3) self.assertEqual(w.lowerValue(), 3) self.assertEqual(w.upperValue(), 3) self.assertEqual(len(spy), 8) self.assertEqual(spy[-1], [3, 3]) # set to values outside limit, should be clamped w.setUpperValue(12) self.assertEqual(w.lowerValue(), 3) self.assertEqual(w.upperValue(), 10) self.assertEqual(len(spy), 9) self.assertEqual(spy[-1], [3, 10]) w.setLowerValue(-2) self.assertEqual(w.lowerValue(), 0) self.assertEqual(w.upperValue(), 10) self.assertEqual(len(spy), 10) self.assertEqual(spy[-1], [0, 10]) w.setUpperValue(-3) self.assertEqual(w.lowerValue(), 0) self.assertEqual(w.upperValue(), 0) self.assertEqual(len(spy), 11) self.assertEqual(spy[-1], [0, 0]) w.setLowerValue(13) self.assertEqual(w.lowerValue(), 10) self.assertEqual(w.upperValue(), 10) self.assertEqual(len(spy), 12) self.assertEqual(spy[-1], [10, 10]) w.setRange(-2, 3) self.assertEqual(w.lowerValue(), 0) self.assertEqual(w.upperValue(), 3) self.assertEqual(len(spy), 13) self.assertEqual(spy[-1], [0, 3]) w.setRange(3, 13) self.assertEqual(w.lowerValue(), 3) self.assertEqual(w.upperValue(), 10) self.assertEqual(len(spy), 14) self.assertEqual(spy[-1], [3, 10]) w.setRange(-3, -2) self.assertEqual(w.lowerValue(), 0) self.assertEqual(w.upperValue(), 0) self.assertEqual(len(spy), 15) self.assertEqual(spy[-1], [0, 0]) w.setRange(12, 13) self.assertEqual(w.lowerValue(), 10) self.assertEqual(w.upperValue(), 10) self.assertEqual(len(spy), 16) self.assertEqual(spy[-1], [10, 10]) # flipped ranges w.setRange(7, 4) self.assertEqual(w.lowerValue(), 4) self.assertEqual(w.upperValue(), 7) self.assertEqual(len(spy), 17) self.assertEqual(spy[-1], [4, 7])
def testOperations(self): w = QgsCoordinateOperationWidget() self.assertFalse(w.hasSelection()) spy = QSignalSpy(w.operationChanged) w.setSourceCrs(QgsCoordinateReferenceSystem('EPSG:26745')) self.assertEqual(len(spy), 0) w.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3857')) self.assertEqual(len(spy), 1) self.assertTrue(w.hasSelection()) self.assertGreaterEqual(len(w.availableOperations()), 6) self.assertEqual( w.defaultOperation().proj, '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=159 +z=175 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84' ) self.assertEqual( w.selectedOperation().proj, '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=159 +z=175 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84' ) self.assertTrue(w.selectedOperation().isAvailable) op = QgsCoordinateOperationWidget.OperationDetails() op.proj = '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84' op.allowFallback = True w.setSelectedOperation(op) self.assertEqual( w.selectedOperation().proj, '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84' ) self.assertTrue(w.selectedOperation().allowFallback) self.assertEqual(len(spy), 2) w.setSelectedOperation(op) self.assertEqual( w.selectedOperation().proj, '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84' ) self.assertTrue(w.selectedOperation().allowFallback) self.assertEqual(len(spy), 2) op.proj = '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=159 +z=175 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84' op.allowFallback = False w.setSelectedOperation(op) self.assertEqual( w.selectedOperation().proj, '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=159 +z=175 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84' ) self.assertFalse(w.selectedOperation().allowFallback) self.assertEqual(len(spy), 3) op.allowFallback = True w.setSelectedOperation(op) self.assertEqual( w.selectedOperation().proj, '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=159 +z=175 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84' ) self.assertTrue(w.selectedOperation().allowFallback) self.assertEqual(len(spy), 4) context = QgsCoordinateTransformContext() op.proj = '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84' w.setSelectedOperation(op) w.setSelectedOperationUsingContext(context) # should go to default, because there's nothing in the context matching these crs self.assertEqual( w.selectedOperation().proj, '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=159 +z=175 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84' ) self.assertEqual(len(spy), 6) # put something in the context context.addCoordinateOperation( w.sourceCrs(), w.destinationCrs(), '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84' ) w.setSelectedOperationUsingContext(context) self.assertEqual( w.selectedOperation().proj, '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84' ) self.assertTrue(w.selectedOperation().allowFallback) self.assertEqual(len(spy), 7) context.addCoordinateOperation( w.sourceCrs(), w.destinationCrs(), '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84', False) w.setSelectedOperationUsingContext(context) self.assertEqual( w.selectedOperation().proj, '+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84' ) self.assertFalse(w.selectedOperation().allowFallback) self.assertEqual(len(spy), 8)
def testSelection(self): layer = QgsVectorTileLayer( 'type=vtpk&url={}'.format(unitTestDataPath() + '/testvtpk.vtpk'), 'tiles') self.assertTrue(layer.isValid()) self.assertFalse(layer.selectedFeatures()) spy = QSignalSpy(layer.selectionChanged) # select by polygon selection_geometry = QgsGeometry.fromWkt( 'Polygon ((-12225020.2316580843180418 6030602.60334861185401678, -13521860.30317855626344681 5526975.39110779482871294, -12976264.15658413991332054 4821897.29397048708051443, -12019372.45332629978656769 4884850.69550053123384714, -11650045.83101624809205532 4754746.99900492746382952, -11469579.41329662501811981 5535369.17797833122313023, -11792740.20781794004142284 6110343.57862004917114973, -12225020.2316580843180418 6030602.60334861185401678))' ) context = QgsSelectionContext() context.setScale(17991708) layer.selectByGeometry(selection_geometry, context, Qgis.SelectBehavior.SetSelection, Qgis.SelectGeometryRelationship.Intersect) self.assertEqual(layer.selectedFeatureCount(), 8) self.assertCountEqual( set(f.id() for f in layer.selectedFeatures()), { 3320043274240, 3320026497024, 2220498092032, 2224826613760, 3320043274243, 2220514869248, 3324338241541, 3324338241536 }) self.assertCountEqual( set(f.geometry().asWkt(-3) for f in layer.selectedFeatures()), { 'Polygon ((-13222000 4970000, -13203000 5004000, -13189000 5073000, -13164000 5127000, -13145000 5205000, -13106000 5239000, -13047000 5274000, -12964000 5269000, -12910000 5195000, -12885000 5185000, -12846000 5185000, -12802000 5151000, -12758000 5093000, -12685000 5093000, -12611000 5107000, -12484000 5103000, -12484000 4970000, -13222000 4970000))', 'MultiPolygon (((-12157000 5694000, -12132000 5738000, -12093000 5782000, -12039000 5817000, -11956000 5836000, -11853000 5836000, -11795000 5792000, -11785000 5763000, -11760000 5738000, -11736000 5621000, -11716000 5587000, -11653000 5528000, -11643000 5503000, -11643000 5366000, -11653000 5337000, -11692000 5278000, -11731000 5249000, -11741000 5239000, -11839000 5205000, -11863000 5220000, -11927000 5288000, -11941000 5440000, -11951000 5450000, -12005000 5450000, -12020000 5450000, -12029000 5435000, -12054000 5435000, -12093000 5450000, -12132000 5503000, -12157000 5518000, -12166000 5543000, -12166000 5650000, -12157000 5694000),(-11995000 5680000, -12015000 5626000, -12005000 5582000, -11990000 5562000, -11927000 5547000, -11907000 5528000, -11883000 5479000, -11863000 5469000, -11829000 5469000, -11809000 5489000, -11814000 5577000, -11863000 5626000, -11912000 5704000, -11966000 5704000, -11995000 5680000)),((-11521000 5773000, -11496000 5851000, -11413000 5900000, -11389000 5890000, -11325000 5787000, -11320000 5724000, -11364000 5645000, -11418000 5640000, -11462000 5655000, -11491000 5699000, -11506000 5709000, -11521000 5773000)))', 'Polygon ((-12563000 5105000, -12470000 5102000, -12411000 4990000, -12411000 4970000, -12563000 4970000, -12563000 5105000))', 'Polygon ((-11868000 4750000, -11809000 4882000, -11702000 4956000, -11638000 4956000, -11609000 4916000, -11574000 4892000, -11452000 4882000, -11354000 4833000, -11325000 4794000, -11291000 4765000, -11212000 4638000, -11217000 4579000, -11261000 4486000, -11266000 4432000, -11281000 4393000, -11296000 4383000, -11310000 4339000, -11398000 4300000, -11501000 4305000, -11530000 4320000, -11579000 4359000, -11633000 4427000, -11687000 4466000, -11790000 4515000, -11834000 4569000, -11873000 4652000, -11868000 4750000))', 'Polygon ((-13228000 4960000, -13203000 5004000, -13194000 5049000, -12484000 5049000, -12484000 4869000, -12587000 4814000, -12631000 4765000, -12641000 4716000, -12680000 4652000, -12714000 4618000, -12837000 4589000, -12900000 4589000, -12944000 4608000, -12949000 4618000, -13027000 4623000, -13062000 4647000, -13135000 4662000, -13189000 4691000, -13228000 4779000, -13238000 4819000, -13238000 4907000, -13228000 4960000))', 'MultiLineString ((-11662000 5797000, -11633000 5704000, -11589000 5640000, -11398000 5518000, -11325000 5420000, -11276000 5127000, -11247000 5053000, -11208000 4990000, -11207000 4970000),(-11305000 5337000, -11261000 5381000, -11227000 5459000, -11178000 5518000, -11105000 5562000, -11051000 5670000, -10997000 5724000, -10953000 5812000))', 'Polygon ((-12442000 5049000, -12411000 4990000, -12411000 4956000, -12426000 4916000, -12450000 4887000, -12563000 4827000, -12563000 5049000, -12442000 5049000))', 'Point (-12714000 5220000)' }) self.assertEqual(len(spy), 1) self.assertNotEqual( layer.selectedFeatures()[0].fields().lookupField('tile_zoom'), -1) self.assertNotEqual( layer.selectedFeatures()[0].fields().lookupField('tile_layer'), -1) self.assertEqual(layer.selectedFeatures()[0]['tile_zoom'], 4) self.assertCountEqual( [f['tile_layer'] for f in layer.selectedFeatures()], [ 'polys', 'polys', 'polys', 'lines', 'points', 'polys', 'polys', 'polys' ]) # select same again, should be no new signal layer.selectByGeometry(selection_geometry, context, Qgis.SelectBehavior.SetSelection, Qgis.SelectGeometryRelationship.Intersect) self.assertEqual(len(spy), 1) # select within layer.selectByGeometry(selection_geometry, context, Qgis.SelectBehavior.SetSelection, Qgis.SelectGeometryRelationship.Within) self.assertEqual(len(spy), 2) self.assertCountEqual(set(f.id() for f in layer.selectedFeatures()), {2220498092032, 3320043274243}) self.assertCountEqual( set(f.geometry().asWkt(-3) for f in layer.selectedFeatures()), { 'Point (-12714000 5220000)', 'Polygon ((-12563000 5105000, -12470000 5102000, -12411000 4990000, -12411000 4970000, -12563000 4970000, -12563000 5105000))' }) # add to selection selection_geometry = QgsGeometry.fromWkt( 'Polygon ((-11104449.68442200869321823 6041094.83693683333694935, -11461185.62642602622509003 5822856.37829908169806004, -11054086.96319791302084923 5419954.60850630886852741, -10793879.57020674645900726 5835447.05860510468482971, -11104449.68442200869321823 6041094.83693683333694935))' ) layer.selectByGeometry(selection_geometry, context, Qgis.SelectBehavior.AddToSelection, Qgis.SelectGeometryRelationship.Intersect) self.assertEqual(len(spy), 3) self.assertCountEqual( set(f.id() for f in layer.selectedFeatures()), {2220498092032, 3320043274243, 3320043274240, 3320026497024}) self.assertCountEqual( set(f.geometry().asWkt(-3) for f in layer.selectedFeatures()), { 'Polygon ((-12563000 5105000, -12470000 5102000, -12411000 4990000, -12411000 4970000, -12563000 4970000, -12563000 5105000))', 'MultiLineString ((-11662000 5797000, -11633000 5704000, -11589000 5640000, -11398000 5518000, -11325000 5420000, -11276000 5127000, -11247000 5053000, -11208000 4990000, -11207000 4970000),(-11305000 5337000, -11261000 5381000, -11227000 5459000, -11178000 5518000, -11105000 5562000, -11051000 5670000, -10997000 5724000, -10953000 5812000))', 'Point (-12714000 5220000)', 'MultiPolygon (((-12157000 5694000, -12132000 5738000, -12093000 5782000, -12039000 5817000, -11956000 5836000, -11853000 5836000, -11795000 5792000, -11785000 5763000, -11760000 5738000, -11736000 5621000, -11716000 5587000, -11653000 5528000, -11643000 5503000, -11643000 5366000, -11653000 5337000, -11692000 5278000, -11731000 5249000, -11741000 5239000, -11839000 5205000, -11863000 5220000, -11927000 5288000, -11941000 5440000, -11951000 5450000, -12005000 5450000, -12020000 5450000, -12029000 5435000, -12054000 5435000, -12093000 5450000, -12132000 5503000, -12157000 5518000, -12166000 5543000, -12166000 5650000, -12157000 5694000),(-11995000 5680000, -12015000 5626000, -12005000 5582000, -11990000 5562000, -11927000 5547000, -11907000 5528000, -11883000 5479000, -11863000 5469000, -11829000 5469000, -11809000 5489000, -11814000 5577000, -11863000 5626000, -11912000 5704000, -11966000 5704000, -11995000 5680000)),((-11521000 5773000, -11496000 5851000, -11413000 5900000, -11389000 5890000, -11325000 5787000, -11320000 5724000, -11364000 5645000, -11418000 5640000, -11462000 5655000, -11491000 5699000, -11506000 5709000, -11521000 5773000)))' }) # remove from selection layer.selectByGeometry(selection_geometry, context, Qgis.SelectBehavior.RemoveFromSelection, Qgis.SelectGeometryRelationship.Intersect) self.assertEqual(len(spy), 4) self.assertCountEqual(set(f.id() for f in layer.selectedFeatures()), {2220498092032, 3320043274243}) self.assertCountEqual( set(f.geometry().asWkt(-3) for f in layer.selectedFeatures()), { 'Point (-12714000 5220000)', 'Polygon ((-12563000 5105000, -12470000 5102000, -12411000 4990000, -12411000 4970000, -12563000 4970000, -12563000 5105000))' }) # intersect selection selection_geometry = QgsGeometry.fromWkt( 'Polygon ((-12632118.89488627389073372 5457726.64942438062280416, -12862948.03383005037903786 5310835.37918743211776018, -12850357.35352402552962303 5046431.09276092518121004, -12716056.76359310187399387 4987674.58466614596545696, -12434864.90342522785067558 5113581.38772638700902462, -12632118.89488627389073372 5457726.64942438062280416))' ) layer.selectByGeometry(selection_geometry, context, Qgis.SelectBehavior.IntersectSelection, Qgis.SelectGeometryRelationship.Within) self.assertEqual(len(spy), 5) self.assertCountEqual(set(f.id() for f in layer.selectedFeatures()), {2220498092032}) self.assertCountEqual( set(f.geometry().asWkt(-3) for f in layer.selectedFeatures()), {'Point (-12714000 5220000)'}) layer.removeSelection() self.assertFalse(layer.selectedFeatures()) self.assertEqual(len(spy), 6) layer.removeSelection() self.assertFalse(layer.selectedFeatures()) self.assertEqual(len(spy), 6) # selection should depend on tile scale selection_geometry = QgsGeometry.fromWkt( 'Polygon ((-12225020.2316580843180418 6030602.60334861185401678, -13521860.30317855626344681 5526975.39110779482871294, -12976264.15658413991332054 4821897.29397048708051443, -12019372.45332629978656769 4884850.69550053123384714, -11650045.83101624809205532 4754746.99900492746382952, -11469579.41329662501811981 5535369.17797833122313023, -11792740.20781794004142284 6110343.57862004917114973, -12225020.2316580843180418 6030602.60334861185401678))' ) context = QgsSelectionContext() context.setScale(137882080) layer.selectByGeometry(selection_geometry, context, Qgis.SelectBehavior.SetSelection, Qgis.SelectGeometryRelationship.Intersect) self.assertEqual(len(layer.selectedFeatures()), 5) self.assertCountEqual(set(f.id() for f in layer.selectedFeatures()), {33554432, 16777216, 0, 33554433, 33554438}) self.assertCountEqual( set(f.geometry().asWkt(-3) for f in layer.selectedFeatures()), { 'MultiPolygon (((-12152000 5694000, -12132000 5733000, -12093000 5792000, -12034000 5812000, -11956000 5831000, -11858000 5831000, -11799000 5792000, -11780000 5773000, -11760000 5733000, -11741000 5616000, -11721000 5596000, -11662000 5538000, -11643000 5499000, -11643000 5362000, -11662000 5342000, -11682000 5283000, -11721000 5244000, -11741000 5244000, -11839000 5205000, -11858000 5225000, -11917000 5283000, -11936000 5440000, -11956000 5459000, -11995000 5459000, -12015000 5459000, -12034000 5440000, -12054000 5440000, -12093000 5459000, -12132000 5499000, -12152000 5518000, -12171000 5538000, -12171000 5655000, -12152000 5694000),(-11995000 5675000, -12015000 5636000, -11995000 5577000, -11995000 5557000, -11917000 5557000, -11917000 5538000, -11878000 5479000, -11858000 5479000, -11839000 5479000, -11799000 5499000, -11819000 5577000, -11858000 5636000, -11917000 5714000, -11956000 5714000, -11995000 5675000)),((-11525000 5773000, -11486000 5851000, -11408000 5909000, -11389000 5890000, -11330000 5792000, -11310000 5733000, -11369000 5655000, -11408000 5636000, -11467000 5655000, -11486000 5694000, -11506000 5714000, -11525000 5773000)))', 'MultiPoint ((-13052000 4471000),(-9275000 4016000),(-12201000 4261000),(-10885000 4143000),(-9828000 3992000),(-9534000 4711000),(-10371000 4965000),(-11403000 5049000),(-12499000 4775000),(-11501000 2607000),(-11452000 3703000),(-11085000 4951000),(-10493000 5919000),(-12714000 5220000),(-12607000 4290000),(-12249000 3703000),(-11687000 3331000))', 'MultiLineString ((-13091000 4188000, -13032000 4207000, -12974000 4285000, -12915000 4364000, -12778000 4442000, -12621000 4501000, -12445000 4481000, -12367000 4461000, -12328000 4461000, -12191000 4403000, -12113000 4344000, -11995000 4285000, -11858000 4285000, -11760000 4246000, -11467000 4227000, -11291000 4227000, -11173000 4285000, -11134000 4305000, -11017000 4305000, -10821000 4246000, -10645000 4246000, -10508000 4285000, -10430000 4344000, -10351000 4422000, -10195000 4520000, -10058000 4559000, -10058000 4579000, -9960000 4559000, -9921000 4540000, -9843000 4520000, -9745000 4461000, -9706000 4442000, -9549000 4422000, -9353000 4442000, -9236000 4520000, -9197000 4520000),(-12347000 4461000, -12367000 4403000, -12406000 4325000, -12426000 4305000, -12445000 4266000, -12465000 4207000, -12504000 4148000, -12621000 4109000, -12758000 4109000, -12797000 4090000, -12817000 4051000, -12856000 3992000, -12856000 3914000, -12856000 3816000, -12837000 3796000, -12797000 3777000),(-11662000 5792000, -11623000 5714000, -11584000 5636000, -11408000 5518000, -11330000 5420000, -11271000 5127000, -11252000 5049000, -11212000 4990000, -11193000 4872000, -11193000 4833000, -11193000 4814000, -11154000 4775000, -11056000 4696000, -11036000 4638000, -11075000 4559000, -11115000 4520000, -11134000 4442000, -11134000 4422000, -11056000 4227000, -11075000 4168000, -11095000 4148000, -11134000 4090000, -11134000 4031000, -11173000 3992000, -11212000 3914000, -11212000 3816000, -11193000 3757000, -11115000 3659000, -11075000 3542000, -11017000 3503000, -10978000 3444000, -10899000 3366000, -10860000 3327000, -10684000 3190000, -10664000 3150000, -10645000 3131000, -10645000 3053000, -10704000 2974000, -10723000 2955000, -10723000 2896000, -10704000 2818000, -10606000 2700000, -10528000 2661000),(-11310000 5342000, -11252000 5381000, -11232000 5459000, -11173000 5518000, -11115000 5557000, -11056000 5675000, -10997000 5733000, -10958000 5812000),(-10273000 4461000, -10254000 4364000, -10234000 4364000, -10214000 4344000, -10175000 4305000, -10097000 4305000, -10058000 4285000, -10038000 4227000, -10019000 4129000, -10019000 4109000, -9999000 4070000, -9921000 3953000, -9901000 3953000, -9804000 3933000, -9745000 3914000, -9706000 3835000, -9686000 3816000, -9627000 3796000, -9549000 3777000, -9530000 3757000, -9432000 3698000, -9353000 3679000, -9314000 3600000, -9256000 3561000),(-9843000 4520000, -9843000 4579000, -9823000 4598000, -9725000 4716000, -9725000 4735000, -9706000 4814000, -9647000 4912000, -9549000 5029000, -9530000 5146000, -9393000 5440000, -9314000 5479000, -9158000 5499000))', 'Polygon ((-11858000 4755000, -11799000 4892000, -11702000 4951000, -11643000 4951000, -11604000 4912000, -11565000 4892000, -11447000 4892000, -11349000 4833000, -11330000 4794000, -11291000 4775000, -11212000 4638000, -11212000 4579000, -11252000 4481000, -11271000 4442000, -11271000 4403000, -11291000 4383000, -11310000 4344000, -11408000 4305000, -11506000 4305000, -11525000 4325000, -11584000 4364000, -11623000 4422000, -11682000 4461000, -11780000 4520000, -11839000 4579000, -11878000 4657000, -11858000 4755000))', 'Polygon ((-13228000 4970000, -13208000 5009000, -13189000 5068000, -13169000 5127000, -13150000 5205000, -13110000 5244000, -13052000 5283000, -12954000 5264000, -12915000 5205000, -12876000 5185000, -12856000 5185000, -12797000 5146000, -12758000 5088000, -12680000 5088000, -12602000 5107000, -12465000 5107000, -12406000 4990000, -12406000 4951000, -12426000 4912000, -12445000 4892000, -12582000 4814000, -12621000 4775000, -12641000 4716000, -12680000 4657000, -12719000 4618000, -12837000 4598000, -12895000 4598000, -12934000 4618000, -12954000 4618000, -13032000 4618000, -13052000 4657000, -13130000 4657000, -13189000 4696000, -13228000 4775000, -13228000 4814000, -13228000 4912000, -13228000 4970000))' }) self.assertEqual(len(spy), 7) # removing features should NOT depend on the scale context.setScale(237882080) layer.selectByGeometry(selection_geometry, context, Qgis.SelectBehavior.RemoveFromSelection, Qgis.SelectGeometryRelationship.Intersect) self.assertFalse(layer.selectedFeatures()) self.assertEqual(len(spy), 8) # single feature selection selection_geometry = QgsGeometry.fromWkt( 'Polygon ((-10486370.9139375202357769 3807467.1023839432746172, -10528246.57568679377436638 3799853.34570225700736046, -10490177.79227836430072784 3735136.41390792420133948, -10486370.9139375202357769 3807467.1023839432746172))' ) layer.selectByGeometry( selection_geometry, context, Qgis.SelectBehavior.SetSelection, Qgis.SelectGeometryRelationship.Intersect, Qgis.SelectionFlags(Qgis.SelectionFlag.SingleFeatureSelection)) self.assertEqual(len(layer.selectedFeatures()), 1) self.assertCountEqual(set(f.id() for f in layer.selectedFeatures()), {33554436}) self.assertCountEqual( set(f.geometry().asWkt(-3) for f in layer.selectedFeatures()), { 'Polygon ((-10958000 3835000, -10958000 3796000, -10919000 3835000, -10841000 3874000, -10684000 3992000, -10567000 4031000, -10410000 4031000, -10332000 3992000, -10254000 3914000, -10136000 3914000, -10058000 3874000, -10019000 3796000, -10019000 3757000, -10058000 3718000, -10097000 3718000, -10254000 3796000, -10332000 3796000, -10371000 3757000, -10371000 3718000, -10371000 3679000, -10332000 3640000, -10332000 3561000, -10410000 3483000, -10449000 3405000, -10488000 3366000, -10645000 3327000, -10723000 3366000, -10762000 3405000, -10801000 3444000, -10762000 3483000, -10801000 3522000, -10841000 3561000, -10919000 3561000, -10958000 3600000, -10958000 3640000, -10958000 3679000, -10958000 3718000, -10997000 3796000, -10958000 3835000))' }) self.assertEqual(len(spy), 9) # select again layer.selectByGeometry( selection_geometry, context, Qgis.SelectBehavior.SetSelection, Qgis.SelectGeometryRelationship.Intersect, Qgis.SelectionFlags(Qgis.SelectionFlag.SingleFeatureSelection)) self.assertEqual(len(layer.selectedFeatures()), 1) self.assertCountEqual(set(f.id() for f in layer.selectedFeatures()), {33554436}) self.assertCountEqual( set(f.geometry().asWkt(-3) for f in layer.selectedFeatures()), { 'Polygon ((-10958000 3835000, -10958000 3796000, -10919000 3835000, -10841000 3874000, -10684000 3992000, -10567000 4031000, -10410000 4031000, -10332000 3992000, -10254000 3914000, -10136000 3914000, -10058000 3874000, -10019000 3796000, -10019000 3757000, -10058000 3718000, -10097000 3718000, -10254000 3796000, -10332000 3796000, -10371000 3757000, -10371000 3718000, -10371000 3679000, -10332000 3640000, -10332000 3561000, -10410000 3483000, -10449000 3405000, -10488000 3366000, -10645000 3327000, -10723000 3366000, -10762000 3405000, -10801000 3444000, -10762000 3483000, -10801000 3522000, -10841000 3561000, -10919000 3561000, -10958000 3600000, -10958000 3640000, -10958000 3679000, -10958000 3718000, -10997000 3796000, -10958000 3835000))' }) self.assertEqual(len(spy), 9) # with toggle mode layer.selectByGeometry( selection_geometry, context, Qgis.SelectBehavior.SetSelection, Qgis.SelectGeometryRelationship.Intersect, Qgis.SelectionFlags(Qgis.SelectionFlag.SingleFeatureSelection | Qgis.SelectionFlag.ToggleSelection)) self.assertFalse(layer.selectedFeatures()) self.assertEqual(len(spy), 10) layer.selectByGeometry( selection_geometry, context, Qgis.SelectBehavior.SetSelection, Qgis.SelectGeometryRelationship.Intersect, Qgis.SelectionFlags(Qgis.SelectionFlag.SingleFeatureSelection | Qgis.SelectionFlag.ToggleSelection)) self.assertEqual(len(layer.selectedFeatures()), 1) self.assertCountEqual(set(f.id() for f in layer.selectedFeatures()), {33554436}) self.assertCountEqual( set(f.geometry().asWkt(-3) for f in layer.selectedFeatures()), { 'Polygon ((-10958000 3835000, -10958000 3796000, -10919000 3835000, -10841000 3874000, -10684000 3992000, -10567000 4031000, -10410000 4031000, -10332000 3992000, -10254000 3914000, -10136000 3914000, -10058000 3874000, -10019000 3796000, -10019000 3757000, -10058000 3718000, -10097000 3718000, -10254000 3796000, -10332000 3796000, -10371000 3757000, -10371000 3718000, -10371000 3679000, -10332000 3640000, -10332000 3561000, -10410000 3483000, -10449000 3405000, -10488000 3366000, -10645000 3327000, -10723000 3366000, -10762000 3405000, -10801000 3444000, -10762000 3483000, -10801000 3522000, -10841000 3561000, -10919000 3561000, -10958000 3600000, -10958000 3640000, -10958000 3679000, -10958000 3718000, -10997000 3796000, -10958000 3835000))' }) self.assertEqual(len(spy), 11)
def testTreeWidgetDeferredLoad(self): """ Test that crs setting made before widget is initialized is respected """ w = QgsProjectionSelectionTreeWidget() spy = QSignalSpy(w.crsSelected) self.assertFalse(w.hasValidSelection()) w.setCrs(QgsCoordinateReferenceSystem('EPSG:3111')) self.assertEqual(len(spy), 1) self.assertTrue(w.hasValidSelection()) self.assertEqual(w.crs().authid(), 'EPSG:3111') self.assertEqual(len(spy), 1) w = QgsProjectionSelectionTreeWidget() spy = QSignalSpy(w.crsSelected) self.assertFalse(w.hasValidSelection()) w.setCrs(QgsCoordinateReferenceSystem()) self.assertEqual(len(spy), 1) self.assertTrue(w.hasValidSelection()) self.assertFalse(w.crs().isValid()) self.assertEqual(len(spy), 1) w.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) self.assertEqual(len(spy), 2) # expect same behavior if we show w = QgsProjectionSelectionTreeWidget() spy = QSignalSpy(w.crsSelected) self.assertFalse(w.hasValidSelection()) w.setCrs(QgsCoordinateReferenceSystem('EPSG:3111')) self.assertEqual(len(spy), 1) w.show() self.assertTrue(w.hasValidSelection()) self.assertEqual(w.crs().authid(), 'EPSG:3111') self.assertEqual(len(spy), 1) w = QgsProjectionSelectionTreeWidget() spy = QSignalSpy(w.crsSelected) self.assertFalse(w.hasValidSelection()) w.setCrs(QgsCoordinateReferenceSystem()) self.assertEqual(len(spy), 1) w.show() self.assertTrue(w.hasValidSelection()) self.assertFalse(w.crs().isValid()) self.assertEqual(len(spy), 1) # no double signals if same crs set w = QgsProjectionSelectionTreeWidget() spy = QSignalSpy(w.crsSelected) self.assertFalse(w.hasValidSelection()) w.setCrs(QgsCoordinateReferenceSystem('EPSG:3111')) w.setCrs(QgsCoordinateReferenceSystem('EPSG:3111')) self.assertEqual(len(spy), 1) # no double signals if same crs set w = QgsProjectionSelectionTreeWidget() spy = QSignalSpy(w.crsSelected) self.assertFalse(w.hasValidSelection()) w.setCrs(QgsCoordinateReferenceSystem('EPSG:3111')) w.setCrs(QgsCoordinateReferenceSystem('EPSG:3111')) w.show() w.setCrs(QgsCoordinateReferenceSystem('EPSG:3111')) self.assertEqual(len(spy), 1) w.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) self.assertEqual(len(spy), 2)
def testOperationsCruftyProj(self): w = QgsCoordinateOperationWidget() self.assertFalse(w.hasSelection()) spy = QSignalSpy(w.operationChanged) w.setSourceCrs(QgsCoordinateReferenceSystem('EPSG:4283')) self.assertEqual(len(spy), 0) w.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:7844')) self.assertEqual(len(spy), 1) self.assertTrue(w.hasSelection()) self.assertEqual(len(w.availableOperations()), 2) self.assertEqual( QgsDatumTransform.datumTransformToProj( w.defaultOperation().sourceTransformId), '+nadgrids=GDA94_GDA2020_conformal_and_distortion.gsb') self.assertEqual(w.defaultOperation().destinationTransformId, -1) self.assertEqual( QgsDatumTransform.datumTransformToProj( w.selectedOperation().sourceTransformId), '+nadgrids=GDA94_GDA2020_conformal_and_distortion.gsb') self.assertEqual(w.selectedOperation().destinationTransformId, -1) self.assertEqual( QgsDatumTransform.datumTransformToProj( w.availableOperations()[1].sourceTransformId), '+nadgrids=GDA94_GDA2020_conformal.gsb') self.assertEqual(w.availableOperations()[1].destinationTransformId, -1) op = QgsCoordinateOperationWidget.OperationDetails() op.sourceTransformId = w.availableOperations()[1].sourceTransformId w.setSelectedOperation(op) self.assertEqual( QgsDatumTransform.datumTransformToProj( w.selectedOperation().sourceTransformId), '+nadgrids=GDA94_GDA2020_conformal.gsb') self.assertEqual(len(spy), 2) w.setSelectedOperation(op) self.assertEqual( QgsDatumTransform.datumTransformToProj( w.selectedOperation().sourceTransformId), '+nadgrids=GDA94_GDA2020_conformal.gsb') self.assertEqual(len(spy), 2) op.sourceTransformId = w.availableOperations()[0].sourceTransformId op.destinationTransformId = -1 w.setSelectedOperation(op) self.assertEqual( QgsDatumTransform.datumTransformToProj( w.selectedOperation().sourceTransformId), '+nadgrids=GDA94_GDA2020_conformal_and_distortion.gsb') self.assertEqual(len(spy), 3) op.destinationTransformId = w.availableOperations( )[1].sourceTransformId op.sourceTransformId = -1 w.setSelectedOperation(op) self.assertEqual( QgsDatumTransform.datumTransformToProj( w.selectedOperation().sourceTransformId), '+nadgrids=GDA94_GDA2020_conformal.gsb') self.assertEqual(len(spy), 4) op.destinationTransformId = w.availableOperations( )[0].sourceTransformId op.sourceTransformId = -1 w.setSelectedOperation(op) self.assertEqual( QgsDatumTransform.datumTransformToProj( w.selectedOperation().sourceTransformId), '+nadgrids=GDA94_GDA2020_conformal_and_distortion.gsb') self.assertEqual(len(spy), 5)
def _test(autoTransaction): """Test buffer methods within and without transactions - create a feature - save - retrieve the feature - change geom and attrs - test changes are seen in the buffer """ def _check_feature(wkt): f = next(layer_a.getFeatures()) self.assertEqual(f.geometry().asWkt().upper(), wkt) f = list(buffer.addedFeatures().values())[0] self.assertEqual(f.geometry().asWkt().upper(), wkt) ml = QgsVectorLayer( 'Point?crs=epsg:4326&field=int:integer&field=int2:integer', 'test', 'memory') self.assertTrue(ml.isValid()) d = QTemporaryDir() options = QgsVectorFileWriter.SaveVectorOptions() options.driverName = 'GPKG' options.layerName = 'layer_a' err, msg, newFileName, newLayer = QgsVectorFileWriter.writeAsVectorFormatV3( ml, os.path.join(d.path(), 'transaction_test.gpkg'), QgsCoordinateTransformContext(), options) self.assertEqual(err, QgsVectorFileWriter.NoError) self.assertTrue(os.path.isfile(newFileName)) layer_a = QgsVectorLayer(newFileName + '|layername=layer_a') self.assertTrue(layer_a.isValid()) project = QgsProject() project.setAutoTransaction(autoTransaction) project.addMapLayers([layer_a]) ########################################### # Tests with a new feature self.assertTrue(layer_a.startEditing()) buffer = layer_a.editBuffer() f = QgsFeature(layer_a.fields()) f.setAttribute('int', 123) f.setGeometry(QgsGeometry.fromWkt('point(7 45)')) self.assertTrue(layer_a.addFeatures([f])) _check_feature('POINT (7 45)') # Need to fetch the feature because its ID is NULL (-9223372036854775808) f = next(layer_a.getFeatures()) self.assertEqual(len(buffer.addedFeatures()), 1) layer_a.undoStack().undo() self.assertEqual(len(buffer.addedFeatures()), 0) layer_a.undoStack().redo() self.assertEqual(len(buffer.addedFeatures()), 1) f = list(buffer.addedFeatures().values())[0] self.assertEqual(f.attribute('int'), 123) # Now change attribute self.assertEqual(buffer.changedAttributeValues(), {}) spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.changeAttributeValue(f.id(), 1, 321) self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 1, 321]) self.assertEqual(len(buffer.addedFeatures()), 1) # This is surprising: because it was a new feature it has been changed directly self.assertEqual(buffer.changedAttributeValues(), {}) f = list(buffer.addedFeatures().values())[0] self.assertEqual(f.attribute('int'), 321) spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.undoStack().undo() self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 1, 123]) self.assertEqual(buffer.changedAttributeValues(), {}) f = list(buffer.addedFeatures().values())[0] self.assertEqual(f.attribute('int'), 123) f = next(layer_a.getFeatures()) self.assertEqual(f.attribute('int'), 123) # Change multiple attributes spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.changeAttributeValues(f.id(), {1: 321, 2: 456}) self.assertEqual(len(spy_attribute_changed), 2) self.assertEqual(spy_attribute_changed[0], [f.id(), 1, 321]) self.assertEqual(spy_attribute_changed[1], [f.id(), 2, 456]) buffer = layer_a.editBuffer() # This is surprising: because it was a new feature it has been changed directly self.assertEqual(buffer.changedAttributeValues(), {}) spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.undoStack().undo() # This is because QgsVectorLayerUndoCommandChangeAttribute plural if not autoTransaction: layer_a.undoStack().undo() f = next(layer_a.getFeatures()) self.assertEqual(f.attribute('int'), 123) self.assertEqual(f.attribute('int2'), None) self.assertEqual(len(spy_attribute_changed), 2) self.assertEqual( spy_attribute_changed[1 if autoTransaction else 0], [f.id(), 2, None]) self.assertEqual( spy_attribute_changed[0 if autoTransaction else 1], [f.id(), 1, 123]) # Change geometry f = next(layer_a.getFeatures()) spy_geometry_changed = QSignalSpy(layer_a.geometryChanged) self.assertTrue( layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(9 43)'))) self.assertTrue(len(spy_geometry_changed), 1) self.assertEqual(spy_geometry_changed[0][0], f.id()) self.assertEqual(spy_geometry_changed[0][1].asWkt(), QgsGeometry.fromWkt('point(9 43)').asWkt()) _check_feature('POINT (9 43)') self.assertEqual(buffer.changedGeometries(), {}) layer_a.undoStack().undo() _check_feature('POINT (7 45)') self.assertEqual(buffer.changedGeometries(), {}) self.assertTrue( layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(9 43)'))) _check_feature('POINT (9 43)') self.assertTrue( layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(10 44)'))) _check_feature('POINT (10 44)') # This is another surprise: geometry edits get collapsed into a single # one because they have the same hardcoded id layer_a.undoStack().undo() _check_feature('POINT (7 45)') self.assertTrue(layer_a.commitChanges()) ########################################### # Tests with the existing feature # Get the feature f = next(layer_a.getFeatures()) self.assertTrue(f.isValid()) self.assertEqual(f.attribute('int'), 123) self.assertEqual(f.geometry().asWkt().upper(), 'POINT (7 45)') # Change single attribute self.assertTrue(layer_a.startEditing()) spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.changeAttributeValue(f.id(), 1, 321) self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 1, 321]) buffer = layer_a.editBuffer() self.assertEqual(buffer.changedAttributeValues(), {1: {1: 321}}) f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(1), 321) spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.undoStack().undo() f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(1), 123) self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 1, 123]) self.assertEqual(buffer.changedAttributeValues(), {}) # Change attributes spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.changeAttributeValues(f.id(), {1: 111, 2: 654}) self.assertEqual(len(spy_attribute_changed), 2) self.assertEqual(spy_attribute_changed[0], [1, 1, 111]) self.assertEqual(spy_attribute_changed[1], [1, 2, 654]) f = next(layer_a.getFeatures()) self.assertEqual(f.attributes(), [1, 111, 654]) self.assertEqual(buffer.changedAttributeValues(), {1: { 1: 111, 2: 654 }}) spy_attribute_changed = QSignalSpy(layer_a.attributeValueChanged) layer_a.undoStack().undo() # This is because QgsVectorLayerUndoCommandChangeAttribute plural if not autoTransaction: layer_a.undoStack().undo() self.assertEqual(len(spy_attribute_changed), 2) self.assertEqual( spy_attribute_changed[0 if autoTransaction else 1], [1, 1, 123]) self.assertEqual( spy_attribute_changed[1 if autoTransaction else 0], [1, 2, None]) f = next(layer_a.getFeatures()) self.assertEqual(f.attributes(), [1, 123, None]) self.assertEqual(buffer.changedAttributeValues(), {}) # Change geometry spy_geometry_changed = QSignalSpy(layer_a.geometryChanged) self.assertTrue( layer_a.changeGeometry(f.id(), QgsGeometry.fromWkt('point(9 43)'))) self.assertEqual(spy_geometry_changed[0][0], 1) self.assertEqual(spy_geometry_changed[0][1].asWkt(), QgsGeometry.fromWkt('point(9 43)').asWkt()) f = next(layer_a.getFeatures()) self.assertEqual(f.geometry().asWkt().upper(), 'POINT (9 43)') self.assertEqual(buffer.changedGeometries()[1].asWkt().upper(), 'POINT (9 43)') spy_geometry_changed = QSignalSpy(layer_a.geometryChanged) layer_a.undoStack().undo() self.assertEqual(spy_geometry_changed[0][0], 1) self.assertEqual(spy_geometry_changed[0][1].asWkt(), QgsGeometry.fromWkt('point(7 45)').asWkt()) self.assertEqual(buffer.changedGeometries(), {}) f = next(layer_a.getFeatures()) self.assertEqual(f.geometry().asWkt().upper(), 'POINT (7 45)') self.assertEqual(buffer.changedGeometries(), {}) # Delete an existing feature self.assertTrue(layer_a.deleteFeature(f.id())) with self.assertRaises(StopIteration): next(layer_a.getFeatures()) self.assertEqual(buffer.deletedFeatureIds(), [f.id()]) layer_a.undoStack().undo() self.assertTrue(layer_a.getFeature(f.id()).isValid()) self.assertEqual(buffer.deletedFeatureIds(), []) ########################################### # Test delete # Delete a new feature f = QgsFeature(layer_a.fields()) f.setAttribute('int', 555) f.setGeometry(QgsGeometry.fromWkt('point(8 46)')) self.assertTrue(layer_a.addFeatures([f])) f = [ f for f in layer_a.getFeatures() if f.attribute('int') == 555 ][0] self.assertTrue(f.id() in buffer.addedFeatures()) self.assertTrue(layer_a.deleteFeature(f.id())) self.assertFalse(f.id() in buffer.addedFeatures()) self.assertFalse(f.id() in buffer.deletedFeatureIds()) layer_a.undoStack().undo() self.assertTrue(f.id() in buffer.addedFeatures()) ########################################### # Add attribute field = QgsField('attr1', QVariant.String) self.assertTrue(layer_a.addAttribute(field)) self.assertNotEqual(layer_a.fields().lookupField(field.name()), -1) self.assertEqual(buffer.addedAttributes(), [field]) layer_a.undoStack().undo() self.assertEqual(layer_a.fields().lookupField(field.name()), -1) self.assertEqual(buffer.addedAttributes(), []) layer_a.undoStack().redo() self.assertNotEqual(layer_a.fields().lookupField(field.name()), -1) self.assertEqual(buffer.addedAttributes(), [field]) self.assertTrue(layer_a.commitChanges()) ########################################### # Remove attribute self.assertTrue(layer_a.startEditing()) buffer = layer_a.editBuffer() attr_idx = layer_a.fields().lookupField(field.name()) self.assertNotEqual(attr_idx, -1) self.assertTrue(layer_a.deleteAttribute(attr_idx)) self.assertEqual(buffer.deletedAttributeIds(), [attr_idx]) self.assertEqual(layer_a.fields().lookupField(field.name()), -1) layer_a.undoStack().undo() self.assertEqual(buffer.deletedAttributeIds(), []) self.assertEqual(layer_a.fields().lookupField(field.name()), attr_idx) # This is totally broken at least on OGR/GPKG: the rollback # does not restore the original fields if False: layer_a.undoStack().redo() self.assertEqual(buffer.deletedAttributeIds(), [attr_idx]) self.assertEqual(layer_a.fields().lookupField(field.name()), -1) # Rollback! self.assertTrue(layer_a.rollBack()) self.assertIn('attr1', layer_a.dataProvider().fields().names()) self.assertIn('attr1', layer_a.fields().names()) self.assertEqual(layer_a.fields().names(), layer_a.dataProvider().fields().names()) attr_idx = layer_a.fields().lookupField(field.name()) self.assertNotEqual(attr_idx, -1) self.assertTrue(layer_a.startEditing()) attr_idx = layer_a.fields().lookupField(field.name()) self.assertNotEqual(attr_idx, -1) ########################################### # Rename attribute attr_idx = layer_a.fields().lookupField(field.name()) self.assertEqual(layer_a.fields().lookupField('new_name'), -1) self.assertTrue(layer_a.renameAttribute(attr_idx, 'new_name')) self.assertEqual(layer_a.fields().lookupField('new_name'), attr_idx) layer_a.undoStack().undo() self.assertEqual(layer_a.fields().lookupField(field.name()), attr_idx) self.assertEqual(layer_a.fields().lookupField('new_name'), -1) layer_a.undoStack().redo() self.assertEqual(layer_a.fields().lookupField('new_name'), attr_idx) self.assertEqual(layer_a.fields().lookupField(field.name()), -1) ############################################# # Try hard to make this fail for transactions if autoTransaction: self.assertTrue(layer_a.commitChanges()) self.assertTrue(layer_a.startEditing()) f = next(layer_a.getFeatures()) # Do for i in range(10): spy_attribute_changed = QSignalSpy( layer_a.attributeValueChanged) layer_a.changeAttributeValue(f.id(), 2, i) self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 2, i]) buffer = layer_a.editBuffer() self.assertEqual(buffer.changedAttributeValues(), {f.id(): { 2: i }}) f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(2), i) # Undo/redo for i in range(9): # Undo spy_attribute_changed = QSignalSpy( layer_a.attributeValueChanged) layer_a.undoStack().undo() f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(2), 8 - i) self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 2, 8 - i]) buffer = layer_a.editBuffer() self.assertEqual(buffer.changedAttributeValues(), {f.id(): { 2: 8 - i }}) # Redo spy_attribute_changed = QSignalSpy( layer_a.attributeValueChanged) layer_a.undoStack().redo() f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(2), 9 - i) self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 2, 9 - i]) # Undo again spy_attribute_changed = QSignalSpy( layer_a.attributeValueChanged) layer_a.undoStack().undo() f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(2), 8 - i) self.assertEqual(len(spy_attribute_changed), 1) self.assertEqual(spy_attribute_changed[0], [f.id(), 2, 8 - i]) buffer = layer_a.editBuffer() self.assertEqual(buffer.changedAttributeValues(), {f.id(): { 2: 8 - i }}) # Last check f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(2), 8 - i) self.assertEqual(buffer.changedAttributeValues(), {f.id(): { 2: 0 }}) layer_a.undoStack().undo() buffer = layer_a.editBuffer() self.assertEqual(buffer.changedAttributeValues(), {}) f = next(layer_a.getFeatures()) self.assertEqual(f.attribute(2), None)
def testInvalidLayer(self): layer = QgsRasterLayer('blah', 'blah') self.assertTrue(layer) self.assertFalse(layer.isValid()) combo = QgsRasterBandComboBox() combo.setLayer(layer) self.assertEqual(combo.count(), 0) self.assertTrue(combo.isEditable()) signal_spy = QSignalSpy(combo.bandChanged) combo.setBand(11111) self.assertEqual(len(signal_spy), 1) self.assertEqual(signal_spy[-1][0], 11111) self.assertEqual(combo.currentBand(), 11111) combo.setBand(-11111) self.assertEqual(combo.currentBand(), -1) self.assertEqual(len(signal_spy), 2) self.assertEqual(signal_spy[-1][0], -1) # replace with valid layer path = os.path.join(unitTestDataPath('raster'), 'band3_float32_noct_epsg4326.tif') info = QFileInfo(path) base_name = info.baseName() layer2 = QgsRasterLayer(path, base_name) self.assertTrue(layer2.isValid()) combo.setBand(2) self.assertEqual(combo.currentBand(), 2) self.assertEqual(len(signal_spy), 3) self.assertEqual(signal_spy[-1][0], 2) combo.setLayer(layer2) self.assertEqual(combo.count(), 3) self.assertFalse(combo.isEditable()) self.assertEqual(combo.currentBand(), 2) self.assertEqual(len(signal_spy), 3) # back to invalid combo.setLayer(layer) self.assertEqual(combo.count(), 0) self.assertTrue(combo.isEditable()) self.assertEqual(combo.currentBand(), 2) self.assertEqual(len(signal_spy), 3) # with not set option combo.setShowNotSetOption(True) combo.setBand(-1) self.assertEqual(combo.currentBand(), -1) self.assertEqual(len(signal_spy), 4) self.assertEqual(signal_spy[-1][0], -1) combo.setBand(3) self.assertEqual(combo.currentBand(), 3) self.assertEqual(len(signal_spy), 5) self.assertEqual(signal_spy[-1][0], 3) combo.setBand(-1) self.assertEqual(combo.currentBand(), -1) self.assertEqual(len(signal_spy), 6) self.assertEqual(signal_spy[-1][0], -1) combo.setLayer(layer2) self.assertEqual(combo.currentBand(), -1) self.assertEqual(len(signal_spy), 6) combo.setLayer(layer) combo.setCurrentText('bad') self.assertEqual(combo.currentBand(), -1) self.assertEqual(len(signal_spy), 6) self.assertEqual(signal_spy[-1][0], -1) combo.setCurrentText('5') self.assertEqual(combo.currentBand(), 5) self.assertEqual(len(signal_spy), 7) self.assertEqual(signal_spy[-1][0], 5) combo.setCurrentText('6.5') self.assertEqual(combo.currentBand(), -1) self.assertEqual(len(signal_spy), 8) self.assertEqual(signal_spy[-1][0], -1) combo.setCurrentText('5') self.assertEqual(combo.currentBand(), 5) self.assertEqual(len(signal_spy), 9) self.assertEqual(signal_spy[-1][0], 5) combo.setCurrentText('Not set') self.assertEqual(combo.currentBand(), -1) self.assertEqual(len(signal_spy), 10) self.assertEqual(signal_spy[-1][0], -1)
def testLimits(self): w = QgsRangeSlider() spy = QSignalSpy(w.rangeLimitsChanged) w.setMaximum(50) self.assertEqual(w.minimum(), 0) self.assertEqual(w.maximum(), 50) self.assertEqual(len(spy), 1) self.assertEqual(spy[-1], [0, 50]) w.setMaximum(50) self.assertEqual(len(spy), 1) w.setMinimum(40) self.assertEqual(w.minimum(), 40) self.assertEqual(w.maximum(), 50) self.assertEqual(len(spy), 2) self.assertEqual(spy[-1], [40, 50]) w.setMinimum(40) self.assertEqual(len(spy), 2) w.setRangeLimits(40, 50) self.assertEqual(w.minimum(), 40) self.assertEqual(w.maximum(), 50) self.assertEqual(len(spy), 2) w.setRangeLimits(40, 60) self.assertEqual(w.minimum(), 40) self.assertEqual(w.maximum(), 60) self.assertEqual(len(spy), 3) self.assertEqual(spy[-1], [40, 60]) w.setRangeLimits(45, 60) self.assertEqual(w.minimum(), 45) self.assertEqual(w.maximum(), 60) self.assertEqual(len(spy), 4) self.assertEqual(spy[-1], [45, 60]) w.setRangeLimits(30, 70) self.assertEqual(w.minimum(), 30) self.assertEqual(w.maximum(), 70) self.assertEqual(len(spy), 5) self.assertEqual(spy[-1], [30, 70]) # inconsistent ranges w.setMinimum(80) self.assertEqual(w.minimum(), 80) self.assertEqual(w.maximum(), 80) self.assertEqual(len(spy), 6) self.assertEqual(spy[-1], [80, 80]) w.setRangeLimits(10, 20) self.assertEqual(len(spy), 7) w.setMaximum(8) self.assertEqual(w.minimum(), 8) self.assertEqual(w.maximum(), 8) self.assertEqual(len(spy), 8) self.assertEqual(spy[-1], [8, 8]) w.setRangeLimits(20, 10) self.assertEqual(w.minimum(), 10) self.assertEqual(w.maximum(), 20) self.assertEqual(len(spy), 9) self.assertEqual(spy[-1], [10, 20]) w.setRangeLimits(20, 10) self.assertEqual(w.minimum(), 10) self.assertEqual(w.maximum(), 20) self.assertEqual(len(spy), 9)
def testIteration(self): p = QgsProject() vectorFileInfo = QFileInfo(unitTestDataPath() + "/france_parts.shp") vector_layer = QgsVectorLayer(vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr") self.assertTrue(vector_layer.isValid()) p.addMapLayer(vector_layer) l = QgsPrintLayout(p) atlas = l.atlas() atlas.setEnabled(True) atlas.setCoverageLayer(vector_layer) atlas_feature_changed_spy = QSignalSpy(atlas.featureChanged) context_changed_spy = QSignalSpy(l.reportContext().changed) self.assertTrue(atlas.beginRender()) self.assertTrue(atlas.first()) self.assertEqual(len(atlas_feature_changed_spy), 1) self.assertEqual(len(context_changed_spy), 1) self.assertEqual(atlas.currentFeatureNumber(), 0) self.assertEqual(l.reportContext().feature()[4], 'Basse-Normandie') self.assertEqual(l.reportContext().layer(), vector_layer) f1 = l.reportContext().feature() self.assertTrue(atlas.next()) self.assertEqual(len(atlas_feature_changed_spy), 2) self.assertEqual(len(context_changed_spy), 2) self.assertEqual(atlas.currentFeatureNumber(), 1) self.assertEqual(l.reportContext().feature()[4], 'Bretagne') f2 = l.reportContext().feature() self.assertTrue(atlas.next()) self.assertEqual(len(atlas_feature_changed_spy), 3) self.assertEqual(len(context_changed_spy), 3) self.assertEqual(atlas.currentFeatureNumber(), 2) self.assertEqual(l.reportContext().feature()[4], 'Pays de la Loire') f3 = l.reportContext().feature() self.assertTrue(atlas.next()) self.assertEqual(len(atlas_feature_changed_spy), 4) self.assertEqual(len(context_changed_spy), 4) self.assertEqual(atlas.currentFeatureNumber(), 3) self.assertEqual(l.reportContext().feature()[4], 'Centre') f4 = l.reportContext().feature() self.assertFalse(atlas.next()) self.assertTrue(atlas.seekTo(2)) self.assertEqual(len(atlas_feature_changed_spy), 5) self.assertEqual(len(context_changed_spy), 5) self.assertEqual(atlas.currentFeatureNumber(), 2) self.assertEqual(l.reportContext().feature()[4], 'Pays de la Loire') self.assertTrue(atlas.last()) self.assertEqual(len(atlas_feature_changed_spy), 6) self.assertEqual(len(context_changed_spy), 6) self.assertEqual(atlas.currentFeatureNumber(), 3) self.assertEqual(l.reportContext().feature()[4], 'Centre') self.assertTrue(atlas.previous()) self.assertEqual(len(atlas_feature_changed_spy), 7) self.assertEqual(len(context_changed_spy), 7) self.assertEqual(atlas.currentFeatureNumber(), 2) self.assertEqual(l.reportContext().feature()[4], 'Pays de la Loire') self.assertTrue(atlas.previous()) self.assertTrue(atlas.previous()) self.assertEqual(len(atlas_feature_changed_spy), 9) self.assertFalse(atlas.previous()) self.assertEqual(len(atlas_feature_changed_spy), 9) self.assertTrue(atlas.endRender()) self.assertEqual(len(atlas_feature_changed_spy), 10) self.assertTrue(atlas.seekTo(f1)) self.assertEqual(l.reportContext().feature()[4], 'Basse-Normandie') self.assertTrue(atlas.seekTo(f4)) self.assertEqual(l.reportContext().feature()[4], 'Centre') self.assertTrue(atlas.seekTo(f3)) self.assertEqual(l.reportContext().feature()[4], 'Pays de la Loire') self.assertTrue(atlas.seekTo(f2)) self.assertEqual(l.reportContext().feature()[4], 'Bretagne') self.assertFalse(atlas.seekTo(QgsFeature(5)))
def testCombo(self): project = QgsProject() layout = QgsPrintLayout(project) combo = QgsLayoutItemComboBox(None) spy = QSignalSpy(combo.itemChanged) self.assertEqual(combo.count(), 0) self.assertIsNone(combo.currentLayout()) self.assertIsNone(combo.currentItem()) self.assertIsNone(combo.item(0)) self.assertIsNone(combo.item(-1)) self.assertIsNone(combo.item(1)) combo.setItem(None) self.assertIsNone(combo.currentItem()) self.assertEqual(combo.currentIndex(), -1) self.assertEqual(len(spy), 0) combo.setCurrentLayout(layout) self.assertEqual(combo.currentIndex(), -1) self.assertEqual(len(spy), 0) self.assertEqual(combo.currentLayout(), layout) self.assertEqual(combo.count(), 0) self.assertIsNone(combo.currentItem()) self.assertIsNone(combo.item(0)) self.assertIsNone(combo.item(-1)) self.assertIsNone(combo.item(1)) combo.setItem(None) self.assertIsNone(combo.currentItem()) self.assertEqual(len(spy), 0) combo.setAllowEmptyItem(True) self.assertEqual(combo.currentIndex(), 0) self.assertEqual(combo.count(), 1) self.assertEqual(len(spy), 2) self.assertEqual(combo.currentLayout(), layout) self.assertIsNone(combo.currentItem()) self.assertIsNone(combo.item(0)) self.assertIsNone(combo.item(-1)) self.assertIsNone(combo.item(1)) combo.setItem(None) self.assertIsNone(combo.currentItem()) self.assertEqual(len(spy), 2) self.assertEqual(combo.currentIndex(), 0) self.assertEqual(combo.itemText(0), '') combo.setAllowEmptyItem(False) self.assertEqual(combo.currentIndex(), -1) self.assertEqual(combo.count(), 0) self.assertEqual(len(spy), 4) self.assertEqual(combo.currentLayout(), layout) self.assertIsNone(combo.currentItem()) self.assertIsNone(combo.item(0)) self.assertIsNone(combo.item(-1)) self.assertIsNone(combo.item(1)) combo.setItem(None) self.assertIsNone(combo.currentItem()) self.assertEqual(len(spy), 4) self.assertEqual(combo.currentIndex(), -1) label1 = QgsLayoutItemLabel(layout) label1.setId('llll') # don't add to layout yet! combo.setItem(label1) self.assertIsNone(combo.currentItem()) self.assertEqual(len(spy), 4) self.assertEqual(combo.currentIndex(), -1) combo.setAllowEmptyItem(True) combo.setItem(label1) self.assertIsNone(combo.currentItem()) self.assertEqual(len(spy), 6) self.assertEqual(combo.currentIndex(), 0) combo.setAllowEmptyItem(False) layout.addLayoutItem(label1) self.assertEqual(combo.currentIndex(), 0) self.assertEqual(combo.count(), 1) self.assertEqual(combo.itemText(0), 'llll') self.assertEqual(len(spy), 10) self.assertEqual(combo.currentLayout(), layout) self.assertEqual(combo.currentItem(), label1) self.assertEqual(combo.item(0), label1) self.assertIsNone(combo.item(-1)) self.assertIsNone(combo.item(1)) combo.setItem(None) self.assertIsNone(combo.currentItem()) self.assertEqual(len(spy), 11) self.assertEqual(combo.currentIndex(), -1) combo.setItem(label1) self.assertEqual(combo.currentItem(), label1) self.assertEqual(len(spy), 12) self.assertEqual(combo.currentIndex(), 0) combo.setAllowEmptyItem(True) self.assertEqual(combo.currentIndex(), 1) self.assertEqual(combo.count(), 2) self.assertEqual(combo.itemText(0), '') self.assertEqual(combo.itemText(1), 'llll') self.assertEqual(len(spy), 13) self.assertEqual(combo.currentLayout(), layout) self.assertEqual(combo.currentItem(), label1) self.assertIsNone(combo.item(0)) self.assertEqual(combo.item(1), label1) self.assertIsNone(combo.item(-1)) self.assertIsNone(combo.item(2)) combo.setItem(None) self.assertIsNone(combo.currentItem()) self.assertEqual(len(spy), 14) self.assertEqual(combo.currentIndex(), 0) combo.setItem(label1) self.assertEqual(combo.currentItem(), label1) self.assertEqual(len(spy), 15) self.assertEqual(combo.currentIndex(), 1) label2 = QgsLayoutItemLabel(layout) label2.setId('mmmm') layout.addLayoutItem(label2) self.assertEqual(combo.currentIndex(), 1) self.assertEqual(combo.count(), 3) self.assertEqual(combo.itemText(0), '') self.assertEqual(combo.itemText(1), 'llll') self.assertEqual(combo.itemText(2), 'mmmm') self.assertEqual(len(spy), 15) self.assertEqual(combo.currentLayout(), layout) self.assertEqual(combo.currentItem(), label1) self.assertIsNone(combo.item(0)) self.assertEqual(combo.item(1), label1) self.assertEqual(combo.item(2), label2) self.assertIsNone(combo.item(-1)) self.assertIsNone(combo.item(3)) combo.setItem(None) self.assertIsNone(combo.currentItem()) self.assertEqual(len(spy), 16) self.assertEqual(combo.currentIndex(), 0) combo.setItem(label1) self.assertEqual(combo.currentItem(), label1) self.assertEqual(len(spy), 17) self.assertEqual(combo.currentIndex(), 1) label1.setId('nnnn') self.assertEqual(combo.itemText(0), '') self.assertEqual(combo.itemText(1), 'mmmm') self.assertEqual(combo.itemText(2), 'nnnn') self.assertIsNone(combo.item(0)) self.assertEqual(combo.item(1), label2) self.assertEqual(combo.item(2), label1) self.assertEqual(combo.currentItem(), label1) combo.setAllowEmptyItem(False) self.assertEqual(combo.itemText(0), 'mmmm') self.assertEqual(combo.itemText(1), 'nnnn') self.assertEqual(combo.item(0), label2) self.assertEqual(combo.item(1), label1) self.assertEqual(combo.currentItem(), label1) combo.setItem(label2) label2.setId('oooo') self.assertEqual(combo.itemText(0), 'nnnn') self.assertEqual(combo.itemText(1), 'oooo') self.assertEqual(combo.item(0), label1) self.assertEqual(combo.item(1), label2) self.assertEqual(combo.currentItem(), label2) combo.setAllowEmptyItem(True) layout.removeLayoutItem(label1) self.assertEqual(combo.itemText(0), '') self.assertEqual(combo.itemText(1), 'oooo') self.assertIsNone(combo.item(0)) self.assertEqual(combo.item(1), label2) self.assertEqual(combo.currentItem(), label2) map = QgsLayoutItemMap(layout) layout.addLayoutItem(map) map.setId('pppp') self.assertEqual(combo.itemText(0), '') self.assertEqual(combo.itemText(1), 'oooo') self.assertEqual(combo.itemText(2), 'pppp') self.assertIsNone(combo.item(0)) self.assertEqual(combo.item(1), label2) self.assertEqual(combo.item(2), map) self.assertEqual(combo.currentItem(), label2) combo.setItemType(QgsLayoutItemRegistry.LayoutMap) self.assertEqual(combo.itemText(0), '') self.assertEqual(combo.itemText(1), 'pppp') self.assertIsNone(combo.item(0)) self.assertEqual(combo.item(1), map) self.assertIsNone(combo.currentItem()) combo.setItemType(QgsLayoutItemRegistry.LayoutLabel) self.assertEqual(combo.itemText(0), '') self.assertEqual(combo.itemText(1), 'oooo') self.assertIsNone(combo.item(0)) self.assertEqual(combo.item(1), label2) self.assertIsNone(combo.currentItem()) combo.setItemType(QgsLayoutItemRegistry.LayoutAttributeTable) self.assertEqual(combo.itemText(0), '') self.assertIsNone(combo.item(0)) self.assertIsNone(combo.currentItem()) combo.setAllowEmptyItem(False) self.assertEqual(combo.count(), 0) self.assertIsNone(combo.currentItem()) self.assertEqual(combo.currentIndex(), -1)
def test_addRemoveLayersSignals(self): """ test that signals are correctly emitted when removing map layers""" store = QgsMapLayerStore() layers_will_be_removed_spy = QSignalSpy(store.layersWillBeRemoved) layer_will_be_removed_spy_str = QSignalSpy( store.layerWillBeRemoved[str]) layer_will_be_removed_spy_layer = QSignalSpy( store.layerWillBeRemoved[QgsMapLayer]) layers_removed_spy = QSignalSpy(store.layersRemoved) layer_removed_spy = QSignalSpy(store.layerRemoved) remove_all_spy = QSignalSpy(store.allLayersRemoved) l1 = createLayer('l1') l2 = createLayer('l2') l3 = createLayer('l3') l4 = createLayer('l4') store.addMapLayers([l1, l2, l3, l4]) # remove 1 layer store.removeMapLayer(l1) # can't seem to actually test the data which was emitted, so best we can do is test # the signal count self.assertEqual(len(layers_will_be_removed_spy), 1) self.assertEqual(len(layer_will_be_removed_spy_str), 1) self.assertEqual(len(layer_will_be_removed_spy_layer), 1) self.assertEqual(len(layers_removed_spy), 1) self.assertEqual(len(layer_removed_spy), 1) self.assertEqual(len(remove_all_spy), 0) self.assertEqual(store.count(), 3) # remove 2 layers at once store.removeMapLayersById([l2.id(), l3.id()]) self.assertEqual(len(layers_will_be_removed_spy), 2) self.assertEqual(len(layer_will_be_removed_spy_str), 3) self.assertEqual(len(layer_will_be_removed_spy_layer), 3) self.assertEqual(len(layers_removed_spy), 2) self.assertEqual(len(layer_removed_spy), 3) self.assertEqual(len(remove_all_spy), 0) self.assertEqual(store.count(), 1) # remove all store.removeAllMapLayers() self.assertEqual(len(layers_will_be_removed_spy), 3) self.assertEqual(len(layer_will_be_removed_spy_str), 4) self.assertEqual(len(layer_will_be_removed_spy_layer), 4) self.assertEqual(len(layers_removed_spy), 3) self.assertEqual(len(layer_removed_spy), 4) self.assertEqual(len(remove_all_spy), 1) #remove some layers which aren't in the store store.removeMapLayersById(['asdasd']) self.assertEqual(len(layers_will_be_removed_spy), 3) self.assertEqual(len(layer_will_be_removed_spy_str), 4) self.assertEqual(len(layer_will_be_removed_spy_layer), 4) self.assertEqual(len(layers_removed_spy), 3) self.assertEqual(len(layer_removed_spy), 4) self.assertEqual(len(remove_all_spy), 1) l5 = createLayer('test5') store.removeMapLayer(l5) self.assertEqual(len(layers_will_be_removed_spy), 3) self.assertEqual(len(layer_will_be_removed_spy_str), 4) self.assertEqual(len(layer_will_be_removed_spy_layer), 4) self.assertEqual(len(layers_removed_spy), 3) self.assertEqual(len(layer_removed_spy), 4) self.assertEqual(len(remove_all_spy), 1)
def testSubsetString(self): if not self.source.supportsSubsetString(): print('Provider does not support subset strings') return changed_spy = QSignalSpy(self.source.dataChanged) subset = self.getSubsetString() self.source.setSubsetString(subset) self.assertEqual(self.source.subsetString(), subset) self.assertEqual(len(changed_spy), 1) # No signal should be emitted if the subset string is not modified self.source.setSubsetString(subset) self.assertEqual(len(changed_spy), 1) result = set([f['pk'] for f in self.source.getFeatures()]) all_valid = (all(f.isValid() for f in self.source.getFeatures())) self.source.setSubsetString(None) expected = set([2, 3, 4]) assert set( expected ) == result, 'Expected {} and got {} when testing subset string {}'.format( set(expected), result, subset) self.assertTrue(all_valid) # Subset string AND filter rect self.source.setSubsetString(subset) extent = QgsRectangle(-70, 70, -60, 75) request = QgsFeatureRequest().setFilterRect(extent) result = set([f['pk'] for f in self.source.getFeatures(request)]) all_valid = (all(f.isValid() for f in self.source.getFeatures(request))) self.source.setSubsetString(None) expected = set([2]) assert set( expected ) == result, 'Expected {} and got {} when testing subset string {}'.format( set(expected), result, subset) self.assertTrue(all_valid) # Subset string AND filter rect, version 2 self.source.setSubsetString(subset) extent = QgsRectangle(-71, 65, -60, 80) result = set([ f['pk'] for f in self.source.getFeatures( QgsFeatureRequest().setFilterRect(extent)) ]) self.source.setSubsetString(None) expected = set([2, 4]) assert set( expected ) == result, 'Expected {} and got {} when testing subset string {}'.format( set(expected), result, subset) # Subset string AND expression self.source.setSubsetString(subset) request = QgsFeatureRequest().setFilterExpression('length("name")=5') result = set([f['pk'] for f in self.source.getFeatures(request)]) all_valid = (all(f.isValid() for f in self.source.getFeatures(request))) self.source.setSubsetString(None) expected = set([2, 4]) assert set( expected ) == result, 'Expected {} and got {} when testing subset string {}'.format( set(expected), result, subset) self.assertTrue(all_valid)
def testSelectNextByZOrder(self): p = QgsProject() l = QgsLayout(p) # add some items item1 = QgsLayoutItemPicture(l) l.addItem(item1) item2 = QgsLayoutItemPicture(l) l.addItem(item2) item3 = QgsLayoutItemPicture(l) item3.setLocked(True) l.addItem(item3) view = QgsLayoutView() # no layout, no crash view.selectNextItemAbove() view.selectNextItemBelow() view.setCurrentLayout(l) focused_item_spy = QSignalSpy(view.itemFocused) # no selection view.selectNextItemAbove() view.selectNextItemBelow() self.assertEqual(len(focused_item_spy), 0) l.setSelectedItem(item1) self.assertEqual(len(focused_item_spy), 1) # already bottom most view.selectNextItemBelow() self.assertTrue(item1.isSelected()) self.assertFalse(item2.isSelected()) self.assertFalse(item3.isSelected()) self.assertEqual(len(focused_item_spy), 1) view.selectNextItemAbove() self.assertFalse(item1.isSelected()) self.assertTrue(item2.isSelected()) self.assertFalse(item3.isSelected()) self.assertEqual(len(focused_item_spy), 2) view.selectNextItemAbove() self.assertFalse(item1.isSelected()) self.assertFalse(item2.isSelected()) self.assertTrue(item3.isSelected()) self.assertEqual(len(focused_item_spy), 3) view.selectNextItemAbove() # already top most self.assertFalse(item1.isSelected()) self.assertFalse(item2.isSelected()) self.assertTrue(item3.isSelected()) self.assertEqual(len(focused_item_spy), 3) view.selectNextItemBelow() self.assertFalse(item1.isSelected()) self.assertTrue(item2.isSelected()) self.assertFalse(item3.isSelected()) self.assertEqual(len(focused_item_spy), 4) view.selectNextItemBelow() self.assertTrue(item1.isSelected()) self.assertFalse(item2.isSelected()) self.assertFalse(item3.isSelected()) self.assertEqual(len(focused_item_spy), 5) view.selectNextItemBelow() # back to bottom most self.assertTrue(item1.isSelected()) self.assertFalse(item2.isSelected()) self.assertFalse(item3.isSelected()) self.assertEqual(len(focused_item_spy), 5)
def testCombo(self): """ test combobox functionality """ md = QgsProviderRegistry.instance().providerMetadata('postgres') conn = md.createConnection(self.uri, {}) md.saveConnection(conn, 'mycon') m = QgsDatabaseTableComboBox('postgres', 'mycon') self.assertGreaterEqual(m.comboBox().count(), 3) text = [m.comboBox().itemText(i) for i in range(m.comboBox().count())] self.assertIn('information_schema.attributes', text) self.assertIn('qgis_test.some_poly_data', text) self.assertLess(text.index('information_schema.attributes'), text.index('qgis_test.some_poly_data')) self.assertTrue(m.currentSchema()) self.assertTrue(m.currentTable()) m.setSchema('information_schema') m.setTable('attributes') spy = QSignalSpy(m.tableChanged) m.setSchema('qgis_test') text = [m.comboBox().itemText(i) for i in range(m.comboBox().count())] self.assertNotIn('information_schema.attributes', text) self.assertNotIn('attributes', text) self.assertIn('some_poly_data', text) self.assertEqual(m.currentTable(), '') self.assertEqual(m.currentSchema(), '') self.assertEqual(len(spy), 1) self.assertFalse(spy[-1][0]) m.setTable('') self.assertEqual(m.currentTable(), '') self.assertEqual(m.currentSchema(), '') self.assertEqual(len(spy), 1) self.assertFalse(spy[-1][0]) m.setTable('someData') self.assertEqual(len(spy), 2) self.assertEqual(m.currentSchema(), 'qgis_test') self.assertEqual(m.currentTable(), 'someData') self.assertEqual(spy[-1][0], 'someData') self.assertEqual(spy[-1][1], 'qgis_test') fields = QgsFields() fields.append(QgsField('test', QVariant.String)) conn.createVectorTable('qgis_test', 'myNewTable', fields, QgsWkbTypes.Point, QgsCoordinateReferenceSystem('EPSG:3857'), False, {}) text2 = [m.comboBox().itemText(i) for i in range(m.comboBox().count())] # tables are not automatically refreshed self.assertEqual(text2, text) # but setting a new connection should fix this! md = QgsProviderRegistry.instance().providerMetadata('postgres') conn2 = md.createConnection(self.uri, {}) md.saveConnection(conn2, 'another') m.setConnectionName('another', 'postgres') # ideally there'd be no extra signal here, but it's a minor issue... self.assertEqual(len(spy), 3) self.assertEqual(m.currentTable(), 'someData') self.assertEqual(m.currentSchema(), 'qgis_test') self.assertEqual(spy[-1][0], 'someData') self.assertEqual(spy[-1][1], 'qgis_test') text2 = [m.comboBox().itemText(i) for i in range(m.comboBox().count())] self.assertNotEqual(text2, text) self.assertIn('myNewTable', text2) m.setTable('myNewTable') self.assertEqual(len(spy), 4) self.assertEqual(m.currentTable(), 'myNewTable') self.assertEqual(m.currentSchema(), 'qgis_test') self.assertEqual(spy[-1][0], 'myNewTable') self.assertEqual(spy[-1][1], 'qgis_test') # no auto drop conn.dropVectorTable('qgis_test', 'myNewTable') self.assertEqual(len(spy), 4) self.assertEqual(m.currentTable(), 'myNewTable') self.assertEqual(m.currentSchema(), 'qgis_test') self.assertEqual(spy[-1][0], 'myNewTable') self.assertEqual(spy[-1][1], 'qgis_test') m.refreshTables() text2 = [m.comboBox().itemText(i) for i in range(m.comboBox().count())] self.assertNotIn('myNewTable', text2) self.assertEqual(len(spy), 5) self.assertFalse(m.currentSchema()) self.assertFalse(spy[-1][0])